Summary
ClaimCut
is meant to be called upto 90 days from the time, contest is created. Although lack of time check allows users to claim it any time i.e. after 90 days as well breaks the protocol intended behaviour.
Vulnerability Details
2024-08-MyCut/src/Pot.sol at main · Cyfrin/2024-08-MyCut (github.com)
function claimCut() public {
address player = msg.sender;
uint256 reward = playersToRewards[player];
if (reward <= 0) {
revert Pot__RewardNotFound();
}
playersToRewards[player] = 0;
remainingRewards -= reward;
claimants.push(player);
_transferReward(player, reward);
}
ClaimCut allows eligible users to claim there cut upto 90 days once contest is created. As afterwards remaining funds are meant to distributed as follows:
1) 10% to owner
2) 90% split among all claimants who claimed on time equally.
However, due to lack of check, users can claim the assigned rewards without the 90 days restriction breaking the protocol design.
POC
Add following test in existing test suite:
function testCanClaimCutAfter90Days() public mintAndApproveTokens {
vm.startPrank(user);
contest = ContestManager(conMan).createContest(
players,
rewards,
IERC20(ERC20Mock(weth)),
4
);
ContestManager(conMan).fundContest(0);
vm.stopPrank();
uint256 balanceBefore = ERC20Mock(weth).balanceOf(player1);
vm.warp(block.timestamp + 91 days);
vm.startPrank(player1);
Pot(contest).claimCut();
console.log("user has claimed after 90 days successfully");
vm.stopPrank();
uint256 balanceAfter = ERC20Mock(weth).balanceOf(player1);
assert(balanceAfter > balanceBefore);
}
then run forge test --mt testCanClaimCutAfter90Days -vv
in the terminal, it will show following output:
[⠊] Compiling...
[⠘] Compiling 1 files with Solc 0.8.20
[⠃] Solc 0.8.20 finished in 1.75s
Compiler run successful!
Ran 1 test for test/TestMyCut.t.sol:TestMyCut
[PASS] testCanClaimCutAfter90Days() (gas: 833511)
Logs:
User Address: 0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D
Contest Manager Address 1: 0x7BD1119CEC127eeCDBa5DCA7d1Bd59986f6d7353
Minting tokens to: 0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D
Approved tokens to: 0x7BD1119CEC127eeCDBa5DCA7d1Bd59986f6d7353
user has claimed after 90 days successfully
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.32ms (437.08µs CPU time)
Impact
breaks protocol design
Tools Used
Manual Review
Recommendations
Add a strict time period, as per design, given below:
+ error Pot__ClaimIsClosed();
function claimCut() public {
+ if (block.timestamp - i_deployedAt > 90 days) {
+ revert Pot__ClaimIsClosed();
+ }
address player = msg.sender;
uint256 reward = playersToRewards[player];
if (reward <= 0) {
revert Pot__RewardNotFound();
}
playersToRewards[player] = 0;
remainingRewards -= reward;
claimants.push(player);
_transferReward(player, reward);
}