MyCut

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

claimCut() has no claim deadline, so a player can claim their full original cut after the pot has already been closed and redistributed

Root + Impact

The protocol gives claimants 90 days to claim; after that the pot is closed and the remainder is redistributed. But claimCut() contains no time check at all and closePot() does not clear the unclaimed entries in playersToRewards. A player who ignored the deadline can therefore call claimCut() after the pot has been closed and still withdraw their full original reward, paid out of whatever balance remains in the pot (leftovers from the closing distribution). This breaks the core incentive of the design: waiting past the deadline is never punished, the late player double-dips into funds that were already reassigned to the manager and the timely claimants, and their late claim additionally pushes them into the claimants array, polluting any subsequent distribution.

Description

function claimCut() public {
address player = msg.sender;
uint256 reward = playersToRewards[player];
if (reward <= 0) {
revert Pot__RewardNotFound();
}
// @> // no check that block.timestamp <= i_deployedAt + 90 days
// @> // no check that the pot has not been closed already
playersToRewards[player] = 0;
remainingRewards -= reward;
claimants.push(player);
_transferReward(player, reward);
}

Risk

Likelihood: High - any authorized player can do it at any time after the deadline, including after closing; nothing in the code path resists it, and leftover balances for it to draw from are the norm.
Impact: Medium - the late claimant takes a full original cut (25 of a 100-token pot in the PoC) out of funds already redistributed to others, so the timely claimants' and manager's closing payouts are effectively clawed back on a first-come basis; the deadline the whole product is built around ("90 days to claim") is unenforceable.

Proof of Concept

Verified with Foundry (test passes). Player 1 claims in time; players 2 to 4 do not. After 91 days the owner closes the pot and the remainder is distributed. Player 2 then calls claimCut() and still receives their full 25-token original cut.

// after closePot() has run:
vm.prank(p2);
Pot(potAddr).claimCut();
assertEq(token.balanceOf(p2), 25e18); // full cut, paid after closing

Recommended Mitigation

Enforce the claim window in claimCut and refuse claims once the pot is closed:

function claimCut() public {
+ if (block.timestamp - i_deployedAt >= 90 days) {
+ revert Pot__ClaimPeriodOver();
+ }
...
}
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 3 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!