Summary
In FeeCollector.sol
function claimRewards(address user) external override nonReentrant whenNotPaused returns (uint256) {
if (user == address(0)) revert InvalidAddress();
uint256 pendingReward = _calculatePendingRewards(user);
if (pendingReward == 0) revert InsufficientBalance();
userRewards[user] = totalDistributed;
raacToken.safeTransfer(user, pendingReward);
emit RewardClaimed(user, pendingReward);
return pendingReward;
}
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;
}
In the claimRewards() function, set totalDistributed in userRewards[user].
On the next fee distribution, totalDistributed will increase.
However, when calculating pending rewards in the _calculatePendingRewards() function, the user's share may be smaller than userRewards[user]. This is because totalDistributed was initially set in userRewards[user] during the first claim.
As a result, the user may either not receive reward on their second claim or receive smaller amount than expected.
Impact
The issue arises from the incorrect resetting of the userRewards[user] value during the reward claim process.
As a result, the user may not receive reward on next claim or receive smaller amount.
Tools Used
Manual
Recommendations
Need to set pendingReward in userRewards[user]
function claimRewards(address user) external override nonReentrant whenNotPaused returns (uint256) {\
if (user == address(0)) revert InvalidAddress();
uint256 pendingReward = _calculatePendingRewards(user);
if (pendingReward == 0) revert InsufficientBalance();
--- userRewards[user] = totalDistributed;
+++ userRewards[user] += pendingReward;
raacToken.safeTransfer(user, pendingReward);
emit RewardClaimed(user, pendingReward);
return pendingReward;
}