TempleGold

TempleDAO
Foundry
25,000 USDC
View results
Submission Details
Severity: high
Valid

User can claim more reward than they should in `TempleGoldStaking`

Vulnerability Details

Function _earned():

function _earned(
StakeInfo memory _stakeInfo,
address _account,
uint256 _index
) internal view returns (uint256) {
uint256 vestingRate = _getVestingRate(_stakeInfo);
if (vestingRate == 0) {
return 0;
}
uint256 _perTokenReward;
if (vestingRate == 1e18) {
_perTokenReward = _rewardPerToken();
} else {
_perTokenReward = _rewardPerToken() * vestingRate / 1e18;
}
return
(_stakeInfo.amount * (_perTokenReward - userRewardPerTokenPaid[_account][_index])) / 1e18 +
claimableRewards[_account][_index];
}

It can be seen that total earned reward is calculated as (_stakeInfo.amount * (_perTokenReward - userRewardPerTokenPaid[_account][_index])) / 1e18 + claimableRewards[_account][_index];

The problem at here is userRewardPerTokenPaid[_account][_index]is only updated after reward is calculated:

modifier updateReward(address _account, uint256 _index) {
{
// stack too deep
rewardData.rewardPerTokenStored = uint216(_rewardPerToken()); //@auditn spam dc cho cái này = 0 (như uniswap - ít nhất cũng là low)
rewardData.lastUpdateTime = uint40(_lastTimeRewardApplicable(rewardData.periodFinish));
if (_account != address(0)) {
StakeInfo memory _stakeInfo = _stakeInfos[_account][_index];
uint256 vestingRate = _getVestingRate(_stakeInfo);
claimableRewards[_account][_index] = _earned(_stakeInfo, _account, _index);
userRewardPerTokenPaid[_account][_index] = vestingRate * uint256(rewardData.rewardPerTokenStored) / 1e18; // <---
}
}
_;
}

Which mean at the first time a account is called in that index, userRewardPerTokenPaid[_account][_index]will equal to 0. Which open scenario that attacker will flashloan to stake and withdraw to able to claim reward

Impact

User without any contribution can get reward

Tools Used

MAnual review

Recommendations

Updates

Lead Judging Commences

inallhonesty Lead Judge
11 months ago
inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Future stakers are paid with rewards that have been accrued from the past due to miscalculation in userRewardPerTokenPaid and _perTokenReward

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.