In the FeeCollector contract, the claimRewards function incorrectly sets userRewards[user] to totalDistributed instead of the user's proportional share, causing all subsequent reward claims to fail as the calculated pending rewards will always be zero.
The issue lies in how reward tracking and claiming is implemented. Let's break down the flow:
The contract tracks total distributed rewards in totalDistributed, which accumulates all rewards allocated to veRAAC holders over time.
When calculating pending rewards, it uses the formula share = (totalDistributed * userVotingPower) / totalVotingPower which is the right one for calculating the rewards share for the user:
However, in claimRewards, during the first successful claim:
During the upcoming claims, it always reverts;
pendingReward after the first claim, will be zero always because in _calculatePendingRewards, return share > userRewards[user] ? share - userRewards[user] : 0; will evaluate to zero since share will always be smaller than userRewards[user] = totalDistributed.
Therefore setting userRewards[user] as totalDistributed is incorrect because totalDistributed represents ALL rewards ever distributed to ALL users, not just this user's share. This effectively makes it impossible for users to claim rewards after their first claim, as their recorded rewards will always be higher than their actual share.
Alice has 10% of total veRAAC voting power
Contract distributes 1000 RAAC tokens (totalDistributed = 1000)
Alice claims rewards for first time:
Calculated share = 1000 * 10% = 100 RAAC
Alice receives 100 RAAC
userRewards[Alice] is set to 1000
Contract distributes another 1000 RAAC (totalDistributed = 2000)
Alice tries to claim again:
Calculated share = 2000 * 10% = 200
200 is not > 1000 (userRewards[Alice])
Returns 0
Transaction reverts with InsufficientBalance
Complete denial of service for the reward claiming functionality after first claim, permanently locking user rewards in the contract.
Manual review
Fix the tracking of claimed rewards by storing the user's proportional share instead of total distributed:
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.