When closeContest function in the ContestManager contract is called, pot sends the owner's cut to the ContestManager itself, with no mechanism to withdraw these funds.
Relevant code -
Pot
ContestManager
The vulnerability stems from current ownership implementation between the Pot and ContestManager contracts, leading to funds being irretrievably locked in the ContestManager contract.
Ownership Assignment:
When a Pot contract is created, it assigns msg.sender as its owner:
Contract Creation Context:
The ContestManager contract creates new Pot instances through its createContest function:
In this context, msg.sender for the new Pot is the ContestManager contract itself, not the external owner who called createContest.
Unintended Ownership:
As a result, the ContestManager becomes the owner of each Pot contract it creates, rather than the intended external owner.
Fund Lock-up:
When closeContest is called (after the 90-day contest period), it triggers the closePot function:
The closePot function sends the owner's cut to its caller. Since the caller is ContestManager, these funds are sent to and locked within the ContestManager contract.
Lack of Withdrawal Mechanism:
The ContestManager contract does not include any functionality to withdraw or redistribute these locked funds, rendering them permanently inaccessible.
This ownership misalignment and the absence of a fund recovery mechanism result in a critical vulnerability where contest rewards become permanently trapped in the ContestManager contract.
In existing test suite, add following test
run forge test --mt testOwnerCutStuckInContestManager -vv in the terminal and it will return following output:
Loss of funds for the protocol / owner
Manual Review, Foundry
Add a claimERC20 function ContestManager to solve this issue.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.