Core Contracts

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

[H] Incorrect Reward Assignment in `claimRewards` Function in `FeeCollector`

Summary

The claimRewards function in the FeeCollector contract incorrectly assigns the totalDistributed value to the userRewards mapping for a single user. This is incorrect and can lead to inaccurate reward calculations for other users.

Vulnerability Details

The current claimRewards function in the FeeCollector contract is:

function claimRewards(address user) external override nonReentrant whenNotPaused returns (uint256) {
if (user == address(0)) revert InvalidAddress();
uint256 pendingReward = _calculatePendingRewards(user);
if (pendingReward == 0) revert InsufficientBalance();
// Reset user rewards before transfer
>> userRewards[user] = totalDistributed;
// Transfer rewards
raacToken.safeTransfer(user, pendingReward);
emit RewardClaimed(user, pendingReward);
return pendingReward;
}

The line userRewards[user] = totalDistributed; incorrectly assigns the totalDistributed value to the userRewards mapping for a single user.

Impact

When the user tries to claim rewards again for the next batch, the _calculatePendingRewards function calculates the remaining amount of shares the user has to claim. If userRewards is greater than share, the user gets zero rewards.

The _calculatePendingRewards function is:

function _calculatePendingRewards(address user) internal view returns (uint256) {
uint256 userVotingPower = veRAACToken.getVotingPower(user);
if (userVotingPower == 0) return 0;
uint256 totalVotingPower = veRAACToken.getTotalVotingPower();
if (totalVotingPower == 0) return 0;
uint256 share = (totalDistributed * userVotingPower) / totalVotingPower;
return share > userRewards[user] ? share - userRewards[user] : 0;
}

If userRewards[user] is greater than share, the user gets zero rewards.

Link to the issue:

  1. https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/collectors/FeeCollector.sol#L206

Tools Used

Manual code review.

Recommendations

Update the claimRewards function to correctly assign the pending reward to the userRewards mapping for the user. The corrected function should be:

function claimRewards(address user) external override nonReentrant whenNotPaused returns (uint256) {
if (user == address(0)) revert InvalidAddress();
uint256 pendingReward = _calculatePendingRewards(user);
if (pendingReward == 0) revert InsufficientBalance();
// Reset user rewards before transfer
>> userRewards[user] += pendingReward;
// Transfer rewards
raacToken.safeTransfer(user, pendingReward);
emit RewardClaimed(user, pendingReward);
return pendingReward;
}

This ensures that the rewards are correctly assigned to the user without affecting the reward calculations for other users.


Updates

Lead Judging Commences

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

FeeCollector::claimRewards sets `userRewards[user]` to `totalDistributed` seriously grieving users from rewards

Support

FAQs

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

Give us feedback!