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.