MyCut

AI First Flight #8
Beginner FriendlyFoundry
EXP
View results
Submission Details
Impact: medium
Likelihood: high
Invalid

Players can claim rewards after the 90-day claim period has expired

Root + Impact

Description

The intended behavior is that authorized players have 90 days to claim their rewards from a pot. After the 90-day claim period has elapsed, the owner/admin should be able to close the pot, take the manager cut from the remaining unclaimed rewards, and distribute the remainder only to players who claimed in time.

The issue is that Pot.claimCut() does not check whether the 90-day claim period has expired. Because of this missing deadline validation, an eligible player can still claim their original reward after the claim window has ended.

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);
// @> Reward is transferred without checking whether the 90-day claim period has expired.
_transferReward(player, reward);
}

Risk

Likelihood:

  • This occurs whenever an eligible player calls claimCut() after the 90-day claim period has elapsed.

  • The function is public and does not validate block.timestamp against i_deployedAt + 90 days.

Impact:

  • Late claimants can withdraw rewards that should have remained in the unclaimed reward pool.

  • This reduces the remaining rewards available for the manager cut and for redistribution to players who claimed within the intended period.

Proof of Concept

Add the following test to test/TestMyCut.t.sol:

function testPoCPlayerCanClaimAfterClaimPeriodExpired() public mintAndApproveTokens {
vm.startPrank(user);
contest = ContestManager(conMan).createContest(players, rewards, IERC20(ERC20Mock(weth)), totalRewards);
ContestManager(conMan).fundContest(0);
vm.stopPrank();
vm.warp(91 days);
uint256 balanceBefore = ERC20Mock(weth).balanceOf(player1);
vm.startPrank(player1);
Pot(contest).claimCut();
vm.stopPrank();
uint256 balanceAfter = ERC20Mock(weth).balanceOf(player1);
assertEq(balanceAfter - balanceBefore, rewards[0]);
}

Run the test:

forge test --match-test testPoCPlayerCanClaimAfterClaimPeriodExpired -vv

The test passes:

[PASS] testPoCPlayerCanClaimAfterClaimPeriodExpired()
1 passed; 0 failed

This proves that player1 can still claim their reward after 91 days, even though the intended claim period is only 90 days.

Recommended Mitigation

Add a deadline check to claimCut() so claims revert once the 90-day claim period has elapsed.

+ error Pot__ClaimPeriodEnded();
function claimCut() public {
+ if (block.timestamp - i_deployedAt >= 90 days) {
+ revert Pot__ClaimPeriodEnded();
+ }
+
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);
}
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 12 hours ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!