The FeeCollector contract presents a vulnerability in its reward calculation mechanism. The _calculatePendingRewards function improperly utilizes the current veRAAC voting power of users instead of considering their historical voting power during the specific distribution periods.
The vulnerability resides within the _calculatePendingRewards function, which is used by claimRewards to determine the amount of unclaimed rewards for a user:
The core issue is the use of veRAACToken.getVotingPower() and veRAACToken.getTotalVotingPower(). These functions retrieve the current voting power of the user and the current total voting power, respectively. The reward calculation should be based on the user's voting power during the period in which the rewards were accrued, not their current voting power.
Steps:
Distribute Fees: The protocol distributes 1000 tokens when the total veRAAC supply is 1000 (1 token per veRAAC).
User A Claims: User A, with 500 veRAAC, claims 500 tokens (correct).
User A Withdraws: User A withdraws all veRAAC, reducing their voting power to 0.
Second Distribution: The Protocol distributes another 1000 tokens. Total veRAAC is now 500 (2 tokens per veRAAC).
User A Deposits: User A quickly deposits 500 veRAAC, making the total supply 1000.
User A Claims Again: Current code calculates: (2000 * 500 / 1000) - 500 = 500 tokens. The correct total should be 0 (User A had 0 veRAAC during the second distribution), but they receive 500 extra tokens.
A user's veRAAC voting power can change over time due to:
Locking more RAAC: Increases voting power.
Extending the lock duration: Increases voting power.
Lock expiring: Voting power decreases linearly as the lock approaches expiry.
Critical Severity: This vulnerability allows for significant and unfair reward extraction.
Fund Drainage: Malicious users can drain the FeeCollector's reward pool by claiming rewards they are not entitled to.
Unfair Distribution: Honest users who maintain a consistent veRAAC balance over time will receive fewer rewards than those who exploit the vulnerability.
Loss of Trust: The vulnerability undermines the integrity of the reward distribution system and erodes user trust in the protocol.
Manual Review
The fundamental solution is to use historical snapshots of voting power for reward calculations. The contract needs to track the total voting power and each user's voting power at the time of each reward distribution.
Here's a detailed breakdown of the recommended changes:
Modify FeeCollector:
Modify distributeCollectedFees: Before distributing rewards, take a snapshot of the current total voting power and each user's voting power.
Modify _calculatePendingRewards: Use the snapshot values instead of the current voting power.
Modify claimRewards: Correctly update userRewards[user] by adding the pendingReward, not assigning totalDistributed.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.