Core Contracts

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

Protocol users will lose rewards of raacToken in FeeCollector

Summary

A miscalculation in reward tracking will cause a loss of rewards for legitimate users as the protocol incorrectly sets user rewards to total distributed amount instead of claimed amount.

Root Cause

In FeeCollector.sol the reward tracking mechanism incorrectly updates userRewards[user] to totalDistributed instead of adding the claimed amount, causing users to lose their rightful rewards in subsequent distributions.

Vulnerability Details

The _calculatePendingRewards() function calculates rewards as follows:

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

The claim function incorrectly updates the user's reward tracking:

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

Impact

Users will lose portions of their rightful rewards in subsequent distributions. For example:

  1. Initial distribution: totalDistributed = 1e18

  2. User with 10% voting power claims 0.1e18 rewards but userRewards[user] is set to 1e18

  3. Additional distribution increases totalDistributed to 2e18

  4. User's new claim will return 0 since userRewards[user] (1e18) is larger than their share (0.2e18)

Mitigation

Update the reward tracking to add claimed amount instead of setting to total distributed:

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;
+ userRewards[user] += pendingReward;
// Transfer rewards
raacToken.safeTransfer(user, pendingReward);
emit RewardClaimed(user, pendingReward);
return pendingReward;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 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!