buySnow() decides how the caller pays by comparing msg.value to the expected price, and silently falls back to WETH when the comparison fails.
The else branch runs whenever msg.value is not exactly the required amount, including when the caller did send ETH but sent slightly too little. In that case the caller is charged twice:
The ETH they sent stays in the Snow contract, where collectFee() later forwards the whole balance to the collector.
The full WETH price is pulled on top of it.
There is no refund and no revert, so the caller cannot tell from the return value that anything went wrong. A user paying with ETH who miscomputes the price by one wei loses both the ETH and the WETH.
Likelihood: Medium. The branch triggers on any inexact msg.value, which is the normal outcome of a UI computing the price from a stale or rounded quote. No attacker is needed.
Impact: Medium. Direct, silent loss of the caller's ETH. The amount lost is the full purchase price, and the WETH is charged as well, so the user pays twice for one purchase and loses the ETH to the collector.
The test funds an account with both ETH and WETH, sends one wei less than the required ETH price, and shows that the ETH is retained by the contract while the full WETH amount is also transferred.
Make the two payment paths explicit. Revert when a caller sends ETH that does not exactly cover the price, and only use the WETH path when no ETH was sent.
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.