Summary
In the Pot::closePot()
function, the remaining rewards are not entirely distributed, and thus, tokens are burnt.
Vulnerability Details
LoC responsible for the vulnerability:
https://github.com/Cyfrin/2024-08-MyCut/blob/946231db0fe717039429a11706717be568d03b54/src/Pot.sol#L57
The claimantCut
is calculated by dividing the difference between the remainingRewards
and the managerCut
by the length of the players array. This leads to an inaccurate distribution of rewards, and thus, the tokens are left in the contract and essentially, burnt.
The following test function can prove the bug:
function testRemainingRewardsNotDistributed() public {
vm.startPrank(user);
rewards = [10,10];
contest = ContestManager(conMan).createContest(players, rewards, IERC20(ERC20Mock(weth)), 20);
ContestManager(conMan).fundContest(0);
vm.stopPrank();
uint256 p1BalanceBefore = ERC20Mock(weth).balanceOf(player1);
vm.prank(player1);
Pot(contest).claimCut();
uint256 conManBalanceBefore = ERC20Mock(weth).balanceOf(address(conMan));
vm.prank(address(conMan));
vm.warp(91 days);
Pot(contest).closePot();
uint256 p1BalanceAfter = ERC20Mock(weth).balanceOf(player1);
uint256 conManBalanceAfter = ERC20Mock(weth).balanceOf(address(conMan));
uint256 receivedRewards = (p1BalanceAfter - p1BalanceBefore) + (conManBalanceAfter - conManBalanceBefore);
console.log("Total rewards claimed + distributed after closing Pot: ",receivedRewards);
assert(receivedRewards < ContestManager(conMan).getContestTotalRewards(contest));
}
Impact
Tokens are lost/burnt as no one can retrieve them from the Pot contract after the existing pot is closed.
Tools Used
Manual Review
Recommendations
Make the following changes in your code:
- uint256 claimantCut = (remainingRewards - managerCut) / i_players.length;
+ uint256 claimantCut = (remainingRewards - managerCut) / claimants.length;