TempleGold

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

Lack of Control on `notifyDistribution` Timing leading to manipulation of Reward Distribution

Summary

Vulnerability Details

  1. notifyDistribution Function:

    • This function is called by the TempleGold contract after minting new rewards.

    • It updates nextRewardAmount with the newly minted amount.

      function notifyDistribution(uint256 amount) external {
      if (msg.sender != address(rewardToken)) { revert CommonEventsAndErrors.InvalidAccess(); }
      nextRewardAmount += amount;
      emit GoldDistributionNotified(amount, block.timestamp);
      }
  • distributeRewards Function:

    • This function is responsible for starting a new reward distribution epoch.

    • It checks if the distribution starter is authorized, if the cooldown period has passed, and if there are stakers.

    • It then calls _notifyReward to update the reward rate and period.

      function distributeRewards() updateReward(address(0), 0) external {
      if (distributionStarter != address(0) && msg.sender != distributionStarter)
      { revert CommonEventsAndErrors.InvalidAccess(); }
      if (totalSupply == 0) { revert NoStaker(); }
      if (lastRewardNotificationTimestamp + rewardDistributionCoolDown > block.timestamp)
      { revert CannotDistribute(); }
      _distributeGold();
      uint256 rewardAmount = nextRewardAmount;
      if (rewardAmount < rewardDuration) { revert CommonEventsAndErrors.ExpectedNonZero(); }
      nextRewardAmount = 0;
      _notifyReward(rewardAmount);
      lastRewardNotificationTimestamp = uint32(block.timestamp);
      }

Detailed Step-by-Step Attack by Alice:

  1. Inflating Rewards:

    • Alice calls notifyDistribution with a large amount, say 1,000,000 tokens.

    • This updates nextRewardAmount to 1,000,000 tokens.

    • Alice calls notifyDistribution again with another 1,000,000 tokens.

    • Now, nextRewardAmount is 2,000,000 tokens.

      templeGold.notifyDistribution(1000000 * 10**18); // First call
      templeGold.notifyDistribution(1000000 * 10**18); // Second call
  2. Starting New Reward Epoch:

    • Alice ensures no one else has called distributeRewards yet.

    • She calls distributeRewards, which starts a new epoch with nextRewardAmount as 2,000,000 tokens.

    • The reward rate and period are now based on this inflated amount.

templeGoldStaking.distributeRewards();

Impact

This can lead to rapid depletion of the reward token pool, causing significant financial losses to the staking contract and diminishing the value of the reward tokens for legitimate stakers.

Tools Used

Recommendations

  • Implement a check to ensure notifyDistribution can only be called once within a certain time frame.

uint256 public lastNotifyTimestamp;
uint256 public constant MIN_NOTIFY_INTERVAL = 1 hours;
function notifyDistribution(uint256 amount) external {
if (msg.sender != address(rewardToken)) { revert CommonEventsAndErrors.InvalidAccess(); }
if (block.timestamp < lastNotifyTimestamp + MIN_NOTIFY_INTERVAL) { revert CommonEventsAndErrors.InvalidAccess(); }
nextRewardAmount += amount;
lastNotifyTimestamp = block.timestamp;
emit GoldDistributionNotified(amount, block.timestamp);
}
  • Introduce a cap on the nextRewardAmount to prevent excessive inflation of rewards.

uint256 public constant MAX_REWARD_AMOUNT = 100000 * 10**18;
function notifyDistribution(uint256 amount) external {
if (msg.sender != address(rewardToken)) { revert CommonEventsAndErrors.InvalidAccess(); }
if (amount > MAX_REWARD_AMOUNT) { revert CommonEventsAndErrors.InvalidParam(); }
nextRewardAmount += amount;
emit GoldDistributionNotified(amount, block.timestamp);
}
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.