Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: high
Valid

User's earned gauge rewards are incorrectly calculated

Summary

User's earned gauge rewards are incorrectly calculated.

Vulnerability Details

A user's gauge rewards are calcualted in earned().

BaseGauge::earned()

function earned(address account) public view returns (uint256) {
return (getUserWeight(account) *
(getRewardPerToken() - userStates[account].rewardPerTokenPaid) / 1e18
) + userStates[account].rewards;
}

getUserWeight() returns the user's current weight including boost and is in basis point (10000), getRewardPerToken() returns the current reward per token, userStates[account].rewardPerTokenPaid is updated in _updateReward() based on the value based on getRewardPerToken(), both getRewardPerToken() and userStates[account].rewardPerTokenPaid are in the reward token's decimal.

BaseGauge::_updateReward()

function _updateReward(address account) internal {
@> rewardPerTokenStored = getRewardPerToken();
lastUpdateTime = lastTimeRewardApplicable();
if (account != address(0)) {
UserState storage state = userStates[account];
state.rewards = earned(account);
@> state.rewardPerTokenPaid = rewardPerTokenStored;
state.lastUpdateTime = block.timestamp;
emit RewardUpdated(account, state.rewards);
}
}

Therefore, the gauge rewards are calculated as user weight * (rewardPerToken - rewardPerTokenPaid) / 1e18, the calculation is wrong:

  1. To apply user's boosted weight, 10000 should be used as a divisor;

  2. User's balance should be mulitplied with reward per token.

Impact

User receives much less rewards than expected.

Tools Used

Manual Review

Recommendations

function earned(address account) public view returns (uint256) {
return (getUserWeight(account) *
- (getRewardPerToken() - userStates[account].rewardPerTokenPaid) / 1e18
+ _balances[msg.sender] * (getRewardPerToken() - userStates[account].rewardPerTokenPaid) / 10000
) + userStates[account].rewards;
}
Updates

Lead Judging Commences

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

BaseGauge::earned calculates rewards using getUserWeight instead of staked balances, potentially allowing users to claim rewards by gaining weight without proper reward checkpoint updates

BaseGauge reward calculations divide by 1e18 despite using 1e4 precision weights, causing all user weights to round down to zero and preventing reward distribution

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

BaseGauge::earned calculates rewards using getUserWeight instead of staked balances, potentially allowing users to claim rewards by gaining weight without proper reward checkpoint updates

BaseGauge reward calculations divide by 1e18 despite using 1e4 precision weights, causing all user weights to round down to zero and preventing reward distribution

Support

FAQs

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

Give us feedback!