Skip to content

Latest commit

 

History

History
59 lines (41 loc) · 2.45 KB

055.md

File metadata and controls

59 lines (41 loc) · 2.45 KB

Urban Coffee Nuthatch

Medium

Precision Loss in notifyRewardAmount Function Causes Unclaimable RewardToken

Summary

The notifyRewardAmount function suffers from precision loss when calculating the reward rate, leading to some rewards being locked and unclaimable.

Vulnerability Detail

there is a precision loss in the notifyRewardAmount function when calculating scaledRewardRate, which results in some of the reward funds being locked in the contract and not being available for distribution. This leads to economic loss.

function notifyRewardAmount(uint256 _amount) external virtual { if (!isRewardNotifier[msg.sender]) { revert GovernanceStaker__Unauthorized("not notifier", msg.sender); }

// We checkpoint the accumulator without updating the timestamp at which it was updated,
// because that second operation will be done after updating the reward rate.
rewardPerTokenAccumulatedCheckpoint = rewardPerTokenAccumulated();

if (block.timestamp >= rewardEndTime) {
  scaledRewardRate = (_amount * SCALE_FACTOR) / REWARD_DURATION;
} else {
  uint256 _remainingReward = scaledRewardRate * (rewardEndTime - block.timestamp);
  scaledRewardRate = (_remainingReward + _amount * SCALE_FACTOR) / REWARD_DURATION;
}

rewardEndTime = block.timestamp + REWARD_DURATION;
lastCheckpointTime = block.timestamp;

if ((scaledRewardRate / SCALE_FACTOR) == 0) revert GovernanceStaker__InvalidRewardRate();

// This check cannot _guarantee_ sufficient rewards have been transferred to the contract,
// because it cannot isolate the unclaimed rewards owed to stakers left in the balance. While
// this check is useful for preventing degenerate cases, it is not sufficient. Therefore, it is
// critical that only safe reward notifier contracts are approved to call this method by the
// admin.
if (
  (scaledRewardRate * REWARD_DURATION) > (REWARD_TOKEN.balanceOf(address(this)) * SCALE_FACTOR)
) revert GovernanceStaker__InsufficientRewardBalance();

emit RewardNotified(_amount, msg.sender);

}

Impact

notifyRewardAmount function results in a portion of the reward funds being locked in the contract and unavailable for distribution.

Code Snippet

https://github.com/sherlock-audit/2024-11-tally/blob/main/staker/src/GovernanceStaker.sol#L430

Tool used

Manual Review

Recommendation

Add an admin function to extract the reward tokens that remain undistributed due to precision loss.