Puppy Raffle

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

Strict balance equality in withdrawFees can be broken by forced ETH

Root + Impact

Description

function withdrawFees() external {
@> require(address(this).balance == uint256(totalFees), "PuppyRaffle: There are currently players active!");
...
}

Risk

Likelihood: Low — requires an attacker to selfdestruct a contract sending ETH to this address, spending funds with no direct gain (griefing).

Impact: Low — the strict equality in withdrawFees() stops matching, so the owner can no longer withdraw accrued fees.

Proof of Concept

A minimal attacker contract holding some ETH and calling selfdestruct(payable(address(puppyRaffle))) forces ETH into the raffle. After that, address(this).balance exceeds totalFees, and the strict-equality require in withdrawFees() reverts on every call, permanently locking the fees. This mirrors the EtherGame selfdestruct example: a contract without receive/fallback can still be forced to hold ETH.

​

Recommended Mitigation

Avoid strict equality on address(this).balance. Use >= instead, or better,
track fees with internal accounting that does not depend on the contract's
actual balance. This also addresses the truncation issue reported separately.

- require(address(this).balance == uint256(totalFees), "...");
+ require(address(this).balance >= uint256(totalFees), "...");
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 2 hours 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!