veRAACToken holders are entitled to part of the fees collected. The fees are distributed using _processDistributions() function of the fee collector, where totalDistributed variable is incremented.
Later holders can call claimRewards() to claim their rewards. However, the function incorrectly sets userRewards to totalDistributed instead of pendingReward.
Assume a scenario where total voting power is 1000, user's voting power is 100, while totalDistributed is also 100. _calculatePendingRewards will calculated user's rewards in the following way.
share will be equal to 10, and as userRewards currently is 0, the function will return 10. After that userRewards will be set to totalDistributed, which is 100. Now let's say totalDistributed got incremented to 110. If claimRewards is called again, logically user's share should be calculated as 110 * 100 / 1000 = 11, and the final value to receive is 11 minus 10 of already claimed rewards, so the final result of new rewards should be 1. However, because userRewards is currently equal to 100, the return value of the _calculatePendingRewards() will be 0, since share is lesser than userRewards, while userRewards will yet again be set to totalDistributed which is now equal to 110. As a result, after the first claim user has no way of claiming new rewards.
After user has claimed his rewards from feeCollector for the first time, he is now unable to claim any subsequent rewards. Rewards belonging to users will remain locked in the feeCollector without a way to claim them.
Set userRewards to pendingReward instead of 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.