buySnow branches on an exact equality between msg.value and the fee. When msg.value does not match exactly, it pulls the full fee in WETH but never refunds the ETH the caller sent, and never requires msg.value to be zero on the WETH path. The stranded ETH is later swept to the collector.
Likelihood:
Likelihood: s_buyFee is pre-multiplied by PRECISION in the constructor, so the exact ETH amount required is large and unintuitive, making the double-charge branch the common outcome for any caller who attaches ETH while intending to pay in WETH.
Impact: A caller who sends a non-zero msg.value that is not exactly the fee pays twice (WETH fee taken plus ETH retained) and permanently loses that ETH to the collector, with no refund.
Self-contained Foundry test (inline WETH mock). The buyer funds and approves the full WETH fee, then attaches 1 ETH while calling buySnow. Because msg.value does not equal the fee, the else branch pulls the full WETH fee and keeps the ETH, so the buyer pays twice for one token.
Result: [PASS] testStrandedEthAndDoubleCharge().
Make the payment path explicit. On the WETH branch, require msg.value to be zero (or refund any ETH sent), so a caller can never be charged in both ETH and WETH for the same purchase.
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.