Puppy Raffle

AI First Flight #1
Beginner FriendlyFoundrySolidityNFT
EXP
View results
Submission Details
Impact: medium
Likelihood: medium
Invalid

Slightly increasing puppyraffle's contract balance will render `withdrawFees` function useless, permanently locking fees

Description

The intended behavior is that the feeAddress can withdraw the accumulated protocol fees via withdrawFees.

The specific issue is that withdrawFees requires the contract's ENTIRE ETH balance to be exactly equal to totalFees. Anyone can permanently break this by force-sending even 1 wei to the contract, after which the strict equality can never hold again and the fees are locked forever.

function withdrawFees() external {
require(address(this).balance == uint256(totalFees), "PuppyRaffle: There are currently players active!"); // @> strict ==
uint256 feesToWithdraw = totalFees;
totalFees = 0;
(bool success,) = feeAddress.call{value: feesToWithdraw}("");
require(success, "PuppyRaffle: Failed to withdraw fees");
}

address(this).balance can be increased unconditionally via selfdestruct (force-send), which bypasses any receive/fallback. Once the balance exceeds totalFees, balance == totalFees is never true again, so withdrawFees reverts forever.

Risk

Likelihood: Medium

  • Any address can selfdestruct a tiny contract to force ETH into PuppyRaffle; it is cheap and irreversible.

Impact: Medium

  • The protocol's fees become permanently un-withdrawable: feeAddress can never collect the fees it is owed. A griefer bricks fee withdrawal for the life of the contract.

Proof of Concept

// contract Kill { constructor() payable {} function go(address t) external { selfdestruct(payable(t)); } }
// Kill.go(puppyRaffle) force-sends 1 wei -> address(this).balance = totalFees + 1.
// withdrawFees: require(balance == totalFees) is now always false -> fees locked forever.

Recommended Mitigation

Do not tie withdrawal to the whole contract balance. Withdraw the tracked totalFees directly: uint256 amt = totalFees; totalFees = 0; feeAddress.call{value: amt}("");.

Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 8 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!