Core Contracts

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

Any user that stakes at least 1 wei in the BaseGauge contract will get undue rewards.

Summary

Whenever a user stakes tokens in the BaseGauge with the stake function, updateReward modifier will update the user's rewards:

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);
}
}

The problem arises because the state.rewards value is independent from the staked amount and will be calculated as follows:

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

This will return a non zero value, depending on the weight of the gauge and the voting power of the user (boost).

After that, user is able to call getRewards, also protected by the updateReward modifier:

function getReward() external virtual nonReentrant whenNotPaused updateReward(msg.sender) {
if (block.timestamp - lastClaimTime[msg.sender] < MIN_CLAIM_INTERVAL) {
revert ClaimTooFrequent();
}
lastClaimTime[msg.sender] = block.timestamp;
UserState storage state = userStates[msg.sender];
uint256 reward = state.rewards;
if (reward > 0) {
state.rewards = 0;
uint256 balance = rewardToken.balanceOf(address(this));
if (reward > balance) {
revert InsufficientBalance();
}
rewardToken.safeTransfer(msg.sender, reward);
emit RewardPaid(msg.sender, reward);
}
}

This means users will get rewards like if they owned all the staked tokens of the gauge. There is no ponderation mechanism to distribute rewards depending on the staked amount. This is a serious issue as it will lead to first users claiming too much rewards and last users not being able to claim rewards at all.

Impact

The impact of this issue is high as it leads to incorrect computation of rewards for users.

Tools Used

Manual review.

Recommendations

Make sure to take into account the staked amount in the reward computation, so that users cannot claim more rewards than they should.

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

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

Support

FAQs

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

Give us feedback!