remainingRewards is meant to track how much of the pot is still unclaimed. It is correctly decremented in claimCut() when a player claims, but it is never decremented in closePot() after the leftover is distributed.
Because closePot() uses remainingRewards to compute both the manager cut and the claimant cut, and does not update it afterward, the variable keeps its old value. If closePot() is called again, the contract re-computes the same cuts from the same stale remainingRewards and pays them out again.
This lets the manager and the claimants drain extra funds from the contract beyond what should be distributed, and the pot still cannot be properly closed.
There is no:
or any other update to remainingRewards after distribution.
In contrast, claimCut() does update it:
So the intent is clearly for remainingRewards to reflect the unclaimed balance. closePot() simply forgets to zero it out.
Likelihood:
Reason 1 // Describe WHEN this will occur (avoid using "if" statements)
Reason 2
Impact:
Each call to closePot() pays the manager cut and the claimant cut again from the same remainingRewards.
The manager receives multiple cuts from the same leftover pool.
Claimants receive multiple payouts from the same leftover pool.
Funds that should stay in the contract until proper accounting are drained early.
The pot can never reach a clean "closed" state because the variable never moves.
Anyone who can trigger closePot() (the owner, since it is onlyOwner) can drain the contract beyond the intended distribution.
Even if the owner is trusted, this is still a correctness bug: the contract's internal accounting is inconsistent with its token balance, and a single accidental double call causes overpayment.
Setup:
players = [player1, player2]
rewards = [500, 500]
totalRewards = 1000
managerCutPercent = 10
player1 claims 500. Now remainingRewards = 500.
After 90 days, owner calls closePot().
managerCut = 500 / 10 = 50
claimantCut = (500 - 50) / 2 = 225
player1 receives 225, manager receives 50.
remainingRewards is still 500.
Owner calls closePot() again.
managerCut = 500 / 10 = 50 again.
claimantCut = 225 again.
player1 receives another 225, manager receives another 50.
remainingRewards is still 500.
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.