Contract fails to deliver promised returns, but doesn't lose value
Description
Brief/Intro
Bribe:getRewardForOwner should not revert if there are no bribe rewards. But it should continue looping.
Vulnerability Details
A bribe contract permits a maximum of 16 reward tokens, and anyone wishing to give a bribe can offer any of these tokens as a reward using the notifyRewardAmount function.
Given these 16 tokens, it's unpredictable how many reward tokens get deposited in one epoch. At times, the bribe contract may involve all 16 tokens as rewards, while other times, only a few may be present.
Users who participate in gauge voting can claim their bribe rewards using the Voter::claimBribes function.
functionclaimBribes(address[] memory_bribes,address[][] memory_tokens,uint256_tokenId) external {require(IVotingEscrow(veALCX).isApprovedOrOwner(msg.sender, _tokenId));for (uint256 i =0; i < _bribes.length; i++) {IBribe(_bribes[i]).getRewardForOwner(_tokenId, _tokens[i]); } }
The address[][] memory tokens will typically contain 16 whitelisted tokens due to the confusion discussed previously.
In the getRewardForOwner function, it iterates through all the provided tokens. If it doesn't find a reward, it simply reverts without checking all tokens. Consequently, any remaining token that might have a reward for the user is not accounted for.
functiongetRewardForOwner(uint256 tokenId,address[] memory tokens) externallock {require(msg.sender == voter,"not voter");address _owner =IVotingEscrow(veALCX).ownerOf(tokenId);uint256 length = tokens.length;for (uint256 i =0; i < length; i++) {uint256 _reward =earned(tokens[i], tokenId);require(_reward >0,"no rewards to claim"); //@audit-issue should not revert if there is no reward for token instead should continue require(_reward > 0, "no rewards to claim");
lastEarn[tokens[i]][tokenId] = block.timestamp;_writeCheckpoint(tokenId, balanceOf[tokenId]);IERC20(tokens[i]).safeTransfer(_owner, _reward);emitClaimRewards(_owner, tokens[i], _reward); } }
For reference please have a look at how Velodrome have done it