Normal: After players refund, selectWinner() should calculate the prize pool based on actual remaining players, not the original count.
Bug: prizePool is calculated as (players.length * entranceFee * 80) / 100. But players.length never decreases after refunds (players are set to address(0), not removed). The contract holds less ETH than the calculated prize pool, so the winner.call{value: prizePool} always reverts.
This is distinct from H-01 (which focuses on gas waste and zero-address winner). Here the issue is that even if a valid non-zero address is selected as winner, the contract doesn't have enough ETH to pay the prize.
Likelihood:
Any refund creates the condition — only 1 refund needed to cause revert
No attacker needed — normal protocol usage triggers the bug
Users who are unhappy with their odds naturally refund, making this inevitable
Impact:
selectWinner() permanently reverts after any refund occurs
Raffle is bricked — no winner selected, no NFT minted
Players can still refund (lucky), but the protocol's core function is destroyed
Run with:
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.