Core Contracts

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

Unclaimable Rewards in Fee Distribution

Summary

The current reward distribution mechanism in FeeCollector.sol results in unclaimable rewards accumulating over time due to the decaying nature of userVotingPower. While rewards are allocated based on totalDistributed, users’ voting power decreases over time, preventing them from fully claiming their share. The issue stems from using dynamically changing userVotingPower instead of a checkpointed voting power at the time of distribution. This results in a portion of rewards being permanently locked in the contract, requiring governance intervention through emergencyWithdraw().

Vulnerability Details

  • Incorrect Reward Calculation Logic:

FeeCollector.sol#L474-L488

/**
* @dev Calculates pending rewards for a user using time-weighted average
* @param user Address of the user
* @return pendingAmount Amount of pending rewards
*/
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;
}
  • Problem: userVotingPower decays over time, while totalVotingPower (based on totalSupply()) only updates during lock(), increase(), extend() and withdraw() in veRAACToken.sol.

  • Issue: Users cannot claim their full share if they wait too long, as their voting power is lower at claim time compared to distribution time.

  • Unclaimable Rewards Accumulate Over Time:

    • Even if all users claim their rewards, a portion will always remain unclaimable due to the mismatch between decaying voting power and totalSupply updates.

    • The longer a user delays claiming, the more rewards become inaccessible.

    • The only way to recover these lost rewards is through emergencyWithdraw(), which grants governance control over excess rewards, centralizing their redistribution.

Impact

  • Users lose a portion of their allocated rewards if they do not claim early.

  • The system does not ensure full reward distribution, favoring early claimers.

  • Unclaimed rewards accumulate, leading to centralized decision-making on redistribution.

  • Users may lose confidence in the reward system due to inaccessible rewards.

Tools Used

Manual

Recommendations

  1. Implement Voting Power Checkpointing at Distribution

    • Store userVotingPower at the time of reward distribution instead of dynamically using the decaying power.

    • Use PowerCheckpoint.sol to fetch historical voting power when rewards were assigned.

  2. Modify _calculatePendingRewards() to Use Checkpoints

    • Replace userVotingPower with the stored voting power from the time of distribution.

    • Ensure totalVotingPower also references the checkpointed value instead of totalSupply().

  3. Implement Periodic Redistribution of Unclaimed Rewards

    • If rewards remain unclaimed for an extended period, redistribute them among active veRAAC holders instead of relying on emergencyWithdraw().

  4. Require Automatic Reward Claims Before Withdrawals

    • Before allowing users to call withdraw(), enforce an automatic reward claim to prevent loss.

    • This ensures users do not lose their accumulated rewards due to voting power decay.

Updates

Lead Judging Commences

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

veRAACToken::getTotalVotingPower returns non-decaying totalSupply while individual voting powers decay, causing impossible governance quorums and stuck rewards in FeeCollector

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

veRAACToken::getTotalVotingPower returns non-decaying totalSupply while individual voting powers decay, causing impossible governance quorums and stuck rewards in FeeCollector

Support

FAQs

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

Give us feedback!