Pot.closePot() is the protocol's finalization step: after the 90-day window the owner takes a 10% manager cut and distributes the remainder. But it never finalizes the Pot's state - remainingRewards is read and never set to 0, and there is no closed flag or guard preventing a second call:
Because remainingRewards keeps its pre-close value, every later closePot() call still passes the time check and re-runs the entire distribution: the manager takes another 10% cut and claimants are paid again, draining the Pot until its token balance is insufficient and transfers revert. getRemainingRewards() also permanently reports a stale, incorrect value.
Likelihood: Low - requires the Owner/Manager (marked Trusted) to call closePot() more than once; no external actor can trigger it.
Impact: High - repeated manager cuts and re-distributions drain pot funds and corrupt accounting; getRemainingRewards() no longer reflects reality.
2 players each entitled to 500 (pool = 1000). No one claims in time, so claimants is empty and remainingRewards stays 1000. The owner closes twice and collects the 10% cut both times:
Run forge test --mt test_PoC_closePotNotFinalized -vv; it passes, proving the manager is paid twice and remainingRewards is never updated.
Finalize the Pot: zero remainingRewards after distribution and/or add an explicit closed guard.
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.