Core Contracts

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

Reward distribution inaccuracy in FeeCollector contract

Summary

The FeeCollector contract contains an issue in its reward distribution mechanism where users may lose their entitled rewards due to improper tracking of claimed rewards. This occurs because the contract resets user rewards to the total distributed amount instead of properly accumulating them.

Vulnerability Details

The issue exists in the claimRewards function where userRewards[user] is set to totalDistributed:

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; // @audit-issue: Incorrect reward tracking
// Transfer rewards
raacToken.safeTransfer(user, pendingReward);
emit RewardClaimed(user, pendingReward);
return pendingReward;
}

The reward calculation in _calculatePendingRewards:

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

Impact

Users lose rewards when claiming during active distribution periods
Incorrect reward distribution affects the fairness of the protocol's incentive mechanism
Financial loss for users who don't receive their full share of rewards

Tools Used

Manual Review

Recommendations

  1. Modify the reward tracking mechanism to properly accumulate rewards:

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();
// Update user's accumulated rewards
userRewards[user] += pendingReward;
// Transfer rewards
raacToken.safeTransfer(user, pendingReward);
emit RewardClaimed(user, pendingReward);
return pendingReward;
}
  1. Implement period-based reward tracking to ensure accurate distribution across multiple periods.

  2. Add proper documentation for the reward calculation and distribution mechanism.

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!