MyCut

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

Pot Can Be Closed Multiple Times Resulting in Duplicate Reward Distribution.

Root + Impact

Description

Function https://github.com/CodeHawks-Contests/ai-mycut/blob/819134663950999ca5ab29a91eeceddb80274743/src/Pot.sol#L49 contains no state variable indicating that the pot has already been finalized.
​
function can therefore be called repeatedly.
​
Each execution performs:
​
manager fee transfer
redistribution to all claimants
​
using the same remainingRewards value.
​
Since remainingRewards is never updated after redistribution, every subsequent call attempts to distribute the same rewards again.
// Root cause in the codebase with @> marks to highlight the relevant section

Risk

Likelihood:


Impact:

If sufficient tokens exist inside the contract (accidental transfers, fee-on-transfer behavior, or malicious deposits), claimants can repeatedly receive redistribution rewards.
​
The function violates the protocol invariant that a contest should only be finalized once.

Proof of Concept

remainingRewards = 1000
​
claimants = [Alice, Bob]
​
Owner calls
​
closePot()
​
Alice and Bob receive redistribution.
​
Owner calls
​
closePot()
​
again.
​
Alice and Bob receive redistribution again.
​
The contract has no protection against repeated execution.
function test_closePotTwice() public {
address contests;
uint256 player2BalB4 = weth.balanceOf(player2);
console.log("Player 2 Initial Balance:", player2BalB4);
​
vm.startPrank(owner);
contests = _contestManager.createContest(players, rewards, IERC20(ERC20Mock(weth)), 4);
_contestManager.fundContest(0);
vm.stopPrank();
​
vm.warp(100 days);
​
vm.startPrank(player2);
Pot(contests).claimCut();
vm.stopPrank();
​
vm.startPrank(owner);
_contestManager.closeContest(contests);
vm.stopPrank();
​
vm.startPrank(owner);
_contestManager.closeContest(contests);
vm.stopPrank();
​
​
uint256 player2BalAF = weth.balanceOf(player2);
console.log("Player2 Balancing After Pot closed:", player2BalAF);
assertGt(player2BalAF, player2BalB4);
​
​
}
​

Recommended Mitigation

Introduce a finalized flag, before performing any transfers.
bool public closed; + add this code
​
require(!closed); + add this code
​
closed = true; + add this code
​
Updates

Lead Judging Commences

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