closePot() distributes the remaining reward pool among claimants who acted within 90 days. The intended invariant is that any player who did not call claimCut() before closure forfeits their allocation.
closePot() does not set any closed-state flag and does not zero the playersToRewards entries of non-claiming players. After closure, those players still have non-zero mapping entries and can call claimCut(). If any token balance remains in the pot (truncation dust from M6, a direct transfer, or intentional re-funding), the post-close claimCut call succeeds — violating the 90-day claim window.
Likelihood:
A post-close balance in the pot is uncommon but achievable — truncation dust always exists after closePot (per M6), and anyone can send tokens directly to a contract address.
A player who intentionally waited past the deadline can observe the pot's token balance on-chain and claim if it is non-zero, gaming the deadline by monitoring for a post-close deposit.
Impact:
The 90-day claim window ceases to be a hard deadline. Players who forfeited their allocation by not claiming in time can reclaim it post-closure if the contract holds any residual balance, undermining the contest's finality guarantees.
Place this test in test/ and run forge test --match-test testPostCloseClaimSucceeds. The test demonstrates that players can successfully call claimCut() after closePot() has already been executed, withdrawing tokens from a pot that has officially closed.
Add a boolean state variable isClosed and set it to true inside closePot(). Then check it at the top of claimCut() so the function reverts once the distribution cycle has ended.
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.