MyCut

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

[Low] Missing deadline check in claimCut allows claims after 90-day claim period

Root + Impact

Description

  • According to the protocol design, users should only be able to claim rewards within the 90-day claim window after a contest is created.
    After the claim period ends, the manager closes the pot, takes the manager cut from unclaimed rewards, and the remaining amount is redistributed to eligible claimants.

  • Pot.claimCut() does not enforce the 90-day deadline, so a user can still claim after the claim window has expired as long as closePot() has not been executed yet.
    This causes reward distribution to deviate from the documented policy, because late claimants can receive rewards that should have remained in the unclaimed pool for manager/claimant post-close distribution.

// Root cause in the codebase with @> marks to highlight the relevant section
function claimCut() public {
// @> Vulnerability: missing 90-day deadline check.
// @> Users can still claim after claim window expiry if closePot() has not been called yet.
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);
}

Risk

Likelihood:

  • when claim window expiry if closePot() has not been called yet.

Impact:

  • Late claims are possible after 90 days before the pot is closed, which deviates from the documented claim policy.
    This does not always lead to direct loss, but it can alter expected reward accounting and produce unfair distribution relative to the intended 90-day cutoff.

Proof of Concept

The following test demonstrates that a player can still successfully claim rewards after the documented 90-day claim period has elapsed.

  1. Create and fund a contest with two players and fixed rewards (500, 500).

  2. Advance time by more than 90 days using vm.warp(block.timestamp + 91 days).

  3. Let player1 call Pot(contest).claimCut().

  4. Compare player1 token balance before and after the call.

Expected behavior (per README): claims should no longer be allowed after 90 days.
Actual behavior: claimCut() succeeds and player1 receives tokens, proving that late claims are still possible until closePot() is executed.

function test_Poc_claimCutOver90days() public mintAndApproveTokens {
vm.startPrank(user);
rewards = [500, 500];
totalRewards = 1000;
contest = ContestManager(conMan).createContest(players, rewards, IERC20(ERC20Mock(weth)), totalRewards);
ContestManager(conMan).fundContest(0);
vm.stopPrank();
//
vm.warp(block.timestamp + 91 days);
uint256 player1BalanceBefore = ERC20Mock(weth).balanceOf(player1);
vm.startPrank(player1);
Pot(contest).claimCut();
vm.stopPrank();
uint256 player1BalanceAfter = ERC20Mock(weth).balanceOf(player1);
assert(player1BalanceAfter > player1BalanceBefore);
}

Recommended Mitigation

Enforce the 90-day claim deadline directly in claimCut() so expired claims always revert, regardless of whether closePot() has been called.

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