Summary
In Pot.sol, there is no checking for totalRewards and array of rewards. If the totalRewards more higher than total array of rewards, it will cause the protocol has a rest of rewards. also if the totalRewards more lower than total array of rewards, it will cause the last player can not take the reward because rewardsRemaining unsufficient.
Vulnerability Details
Let's se the following codebase below :
constructor(address[] memory players, uint256[] memory rewards, IERC20 token, uint256 totalRewards) {
i_players = players;
i_rewards = rewards;
i_token = token;
i_totalRewards = totalRewards;
remainingRewards = totalRewards;
i_deployedAt = block.timestamp;
for (uint256 i = 0; i < i_players.length; i++) {
playersToRewards[i_players[i]] = i_rewards[i];
}
}
There isn't any checking for totalRewards and total array of rewards. There is not guarantee if totalRewards and total of array rewards is exactly same. There is PoC below this :
function testForTotalRewardsLessThanArrayOfRewardMakeOverOrUnderFlow() public {
address[] memory playerss = new address[](2);
playerss[0] = makeAddr("p0");
playerss[1] = makeAddr("p1");
uint256[] memory rewardss = new uint256[](2);
rewardss[0] = 10;
rewardss[1] = 20;
uint256 totalRewardss = 20;
vm.startPrank(user);
contest = ContestManager(conMan).createContest(playerss, rewardss, IERC20(ERC20Mock(weth)), totalRewardss);
ContestManager(conMan).fundContest(0);
vm.stopPrank();
vm.prank(playerss[0]);
Pot(contest).claimCut();
vm.prank(playerss[1]);
vm.expectRevert();
Pot(contest).claimCut();
}
Impact
The impact that willl occur either the protocol still have a rest of rewards whereas all of players claimed their rewards or the player who take claim in last will not occurs because rewards remaining unsufficient to charge the player.
Tools Used
Manual review ~ Foundry
Recommendations
Add checking for Pot.sol constructor following this :
constructor(address[] memory players, uint256[] memory rewards, IERC20 token, uint256 totalRewards) {
i_players = players;
i_rewards = rewards;
i_token = token;
i_totalRewards = totalRewards;
remainingRewards = totalRewards;
i_deployedAt = block.timestamp;
// i_token.transfer(address(this), i_totalRewards);
+ uint256 totalRewardsManual;
+ for (uint256 i = 0; i < rewards.length; i++) {
+ totalRewardsManual += rewards[i];
+ }
+ require(totalRewardsManual == totalRewards);
for (uint256 i = 0; i < i_players.length; i++) {
playersToRewards[i_players[i]] = i_rewards[i];
}
}