The claimRewards() function incorrectly resets the user's reward tracking state to totalDistributed in FeeCollector.sol, causing all future calls to claimRewards() to return 0 pendingReward. As a result, users are unable to claim any newly distributed rewards, leading to a complete lockout from further earnings.
This bug arises due to the incorrect update of the userRewards[user] state variable, which tracks the user's claimed rewards improperly and prevents correct calculation of pending rewards.
In the claimRewards() function of the FeeCollector contract:
The issue is triggered by this line:
And, before hand, the _calculatePendingRewards() function computes the user’s pending reward as:
On the first claim, userRewards[user] is 0, and the user correctly receives their initial pending rewards. However, after the first claim, userRewards[user] == totalDistributed. This causes future calls to claimRewards() to almost always return 0 pendingReward because share < userRewards[user].
Example Walkthrough:
Step 1. Initial State
totalDistributed = 1000 tokens
The user’s voting power entitles them to 200 tokens.
Step 2. First Call to claimRewards()
_calculatePendingRewards() correctly calculates:
pendingReward = (1000 * userVotingPower) / totalVotingPower = 200 tokens
The user receives 200 tokens, and userRewards[user] is updated:
userRewards[user] = totalDistributed; // 1000
Step 3. Future Calls (After More Rewards Distributed and Assuming the Same Ratio of userVotingPower / totalVotingPower)
Suppose totalDistributed = 1500, but _calculatePendingRewards() calculates:
share = (1500 * userVotingPower) / totalVotingPower = 300 tokens
Since userRewards[user] == 1000, 300 < 1000, making the returned pendingReward == 0.
The user is locked out of future rewards despite new distributions.
Complete Lockout from Future Rewards:
Users will be unable to claim any additional rewards after their first claim, resulting in financial loss for stakeholders and a breakdown of the rewards distribution system.
Stakeholder Trust and Reputation Risk:
As rewards remain locked, users may lose confidence in the protocol, and the protocol could face reputational damage if the issue is not quickly addressed.
Potential Accumulation of Unclaimed Rewards:
Since users cannot claim new rewards, unclaimed rewards will accumulate within the contract, potentially leading to large protocol-wide imbalances and manual interventions.
Manual
Consider the following refactoring:
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.