TempleGold

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

Vulnerability in `TempleGoldStaking.sol`: Manipulation of Reward Calculations through Unrestricted `getReward` Function

Summary

The TempleGoldStaking.sol contract contains a vulnerability where the getReward function, being external and callable by anyone, can be abused to manipulate the reward calculations for any staker. This can lead to unintended alterations in future reward calculations and can flood the blockchain with unnecessary transactions.

Vulnerability Details

The getReward function in the TempleGoldStaking.sol contract is defined as follows:

function getReward(address staker, uint256 index) external override updateReward(staker, index) {
_getReward(staker, staker, index);
}

This function allows anyone to claim rewards on behalf of any staker. While this might seem harmless at first, the use of the updateReward modifier introduces a critical issue.

The updateReward modifier is defined as:

modifier updateReward(address _account, uint256 _index) {
rewardData.rewardPerTokenStored = uint216(_rewardPerToken());
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;
}
_;
}

This modifier updates the reward data for the staker each time the getReward function is called. Since anyone can call this function for any staker, it can lead to frequent and unnecessary updates to the reward data, potentially disrupting future reward calculations.

Additionally, the _getReward function called within getReward does not revert when the claim amount is zero:

function _getReward(address staker, address rewardsToAddress, uint256 index) internal {
uint256 amount = claimableRewards[staker][index];
if (amount > 0) {
claimableRewards[staker][index] = 0;
rewardToken.safeTransfer(rewardsToAddress, amount);
emit RewardPaid(staker, rewardsToAddress, index, amount);
}
}

This means an attacker can repeatedly call getReward, even when there are no rewards to claim, causing unnecessary reward updates and bloating the blockchain with meaningless transactions.

Impact

  1. Reward Calculation Manipulation: The frequent and unnecessary updates to the reward data can alter the intended reward calculations for stakers, leading to potential inaccuracies and unfair distributions.

  2. Blockchain Bloat: By allowing calls to getReward with no claimable rewards, the contract is vulnerable to spam attacks that can flood the blockchain with meaningless transactions, increasing gas costs and reducing overall efficiency.

Tools Used

  • Code editor/IDE

Recommendations

  1. Access Control: Implement access control on the getReward function to restrict who can call it. This can be done by introducing a whitelist or limiting calls to the staker themselves.

  2. Revert on Zero Amount: Modify the _getReward function to revert when the claim amount is zero, preventing unnecessary reward updates and transactions:

    function _getReward(address staker, address rewardsToAddress, uint256 index) internal {
    uint256 amount = claimableRewards[staker][index];
    require(amount > 0, "No rewards to claim");
    claimableRewards[staker][index] = 0;
    rewardToken.safeTransfer(rewardsToAddress, amount);
    emit RewardPaid(staker, rewardsToAddress, index, amount);
    }
Updates

Lead Judging Commences

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.