TempleGold

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

periodFinish variable updated on every staking reward distribution leads to users being able to claim more rewards than they earned

Summary

In the function TempleGoldStaking::_notifyReward(), which is called every time the contract is distributing rewards to users, the state variable rewardData.periodFinish is updated further in the future, leading to wrong reward calculation overall, and allowing for malicious users to gain more TempleGold than the TempleDAO team intends.

Vulnerability Details

Every time the _notifyReward function is executed, the rewardData.periodFinish is updated.

rewardData.periodFinish = uint40(block.timestamp + rewardDuration)

This leads to the end of the reward epoch being moved forward in the future with every call of distributeRewards(). In this function, the values for therewardData.rewardRate and nextRewardAmount are set. As the periodFinish will be larger than is intended, so will rewardRate and nextRewardAmount, leading to higher rewards being paid out to users than intended.

modifier updateRewardis called where we adjust the user's claimableRewardsby calling _earned() . However, earned() calls _rewardPerToken() which takes the period finish into account, so the calculation of user rewards will be wrong.

Impact

The distribution of TempleGold rewards will not be as intended or documented. Users who know about this weakness can exploit it to receive more rewards than they have earned.

Tools Used

Manual review, Foundry

Recommendations

To ensure appropriate rewards calculation and distribution, periodFinish should stay constant for the duration of the rewards epoch. The line in question should be inside the if (block.timestamp >= rewardData.periodFinish)block. Change the _notifyReward function as follows:

function _notifyReward(uint256 amount) private {
if (block.timestamp >= rewardData.periodFinish) {
rewardData.rewardRate = uint216(amount / rewardDuration);
rewardData.periodFinish = uint40(block.timestamp+rewardDuration);
// collect dust
nextRewardAmount = amount - (rewardData.rewardRate * rewardDuration);
} else {
uint256 remaining = uint256(rewardData.periodFinish) - block.timestamp;
uint256 leftover = remaining * rewardData.rewardRate;
rewardData.rewardRate = uint216((amount + leftover) / rewardDuration);
// collect dust
nextRewardAmount = (amount + leftover) - (rewardData.rewardRate * rewardDuration);
}
rewardData.lastUpdateTime = uint40(block.timestamp);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Appeal created

tutkata Submitter
about 1 year ago
tutkata Submitter
about 1 year ago
inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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