The protocol aims to verify that the total fees collected are equal to the balance of the PuppyRaffle contract before withdrawal. Unfortunately, require conditions dependent on the contract's balance can be manipulated and may block the protocol's functionality indefinitely.
The PuppyRaffle::withdrawFees function sends all of the collected fees to the feeAddress provided to the protocol. Unfortunately, it has the condition at the top: address(this).balance == uint256(totalFees), which checks if the balance of the PuppyRaffle contract is equal to totalFees.
As we are all familiar with the Solidity feature that allows any user to send ether to any contract, even without a fallback or receive function inside the receiving contract (i.e., using selfdestruct).
Using this feature, anyone can send a small amount, such as 1 wei, of ether to the PuppyRaffle contract and disrupt this condition, which would block the withdrawFees function and prevent feeAddress from receiving the collected and future fees.
Create a file Selfdestruct.sol inside the test folder and put this code inside it;
This contract selfdestruct itself on the construction and sent all of its funds to PuppyRaffle contract.
Import this in the PuppyRaffleTest.t.sol file
And the add this code inside the same file;
Fees will stuck forever in the PuppyRaffle contract.
Manual Review
To ensure the withdrawal is only permitted when active players do not exist, the protocol teams can verify the length of the players array. If any active players are found, the withdrawal can be prevented.
Alternatively, consider implementing similar logic to address 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.