MyCut

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

closePot does not reset remainingRewards, breaking accounting state

Root + Impact

Description

  • After closePot() distributes the manager cut and claimant bonuses, remainingRewards is never set to 0. The state variable retains its pre-close value even though tokens have been transferred out.

  • While closePot is onlyOwner and unlikely to be called twice, the stale remainingRewards value is exposed via the public getRemainingRewards() getter, providing incorrect information to any external system querying the Pot's state.

// Pot.sol::closePot()
function closePot() external onlyOwner {
// ... distributes tokens ...
@> // remainingRewards never set to 0
}

Risk

Likelihood:

  • Every call to closePot() leaves remainingRewards at a stale non-zero value.

Impact:

  • getRemainingRewards() returns an incorrect value after pot closure.

  • ContestManager.getContestRemainingRewards() reports wrong data to frontends/integrators.

  • No direct fund loss, but misleading state could cause incorrect decisions by off-chain systems.

Proof of Concept

The following test shows that after closePot() distributes tokens, the getRemainingRewards() getter still returns the pre-close value instead of 0, providing incorrect data to any external system or frontend querying the Pot's state.

function testStaleRemainingRewards() public {
// Setup and close pot...
vm.warp(block.timestamp + 91 days);
pot.closePot();
// remainingRewards still shows pre-close value
assertGt(pot.getRemainingRewards(), 0); // should be 0 after close
}

Recommended Mitigation

Add remainingRewards = 0 at the end of the closePot() function after all distributions are complete. This ensures the public getter returns an accurate value and prevents any downstream logic from using stale accounting data.

function closePot() external onlyOwner {
if (block.timestamp - i_deployedAt < 90 days) {
revert Pot__StillOpenForClaim();
}
if (remainingRewards > 0) {
uint256 managerCut = remainingRewards / managerCutPercent;
i_token.transfer(msg.sender, managerCut);
uint256 claimantCut = (remainingRewards - managerCut) / claimants.length;
for (uint256 i = 0; i < claimants.length; i++) {
_transferReward(claimants[i], claimantCut);
}
+ remainingRewards = 0;
}
}
Updates

Lead Judging Commences

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