Normal behavior: A user buying Snow with native ETH should pay exactly s_buyFee * amount and receive amount Snow; anything sent above the price should be refunded or the call should revert, never silently absorbed.
The issue: buySnow picks the payment rail by exact equality: only when msg.value == s_buyFee * amount does it take the ETH path. If a user attaches ETH but the value is not exactly the price (an overpay, a rounding error, a gas-cost miscalculation, or sending ETH while WETH is also approved), execution falls into the WETH branch: the full WETH price is pulled from the user via safeTransferFrom and the attached ETH stays in the contract. The only way ETH ever leaves the contract is collectFee(), which sends the entire balance to the fee collector — the overpaying user never gets their ETH back.
Likelihood:
Reason 1 — The loss happens when a user sends ETH whose value is not exactly the computed price while WETH is also approved; this requires a user-side mistake or rounding rather than an active attacker.
Reason 2 — The scenario is nevertheless realistic (users commonly attach cost + buffer, and integrators miscalculate exact fee amounts), and when it occurs the funds are permanently unrecoverable by the user.
Impact:
Impact 1 — The user pays in both assets: the full WETH price is transferred and the attached ETH is forfeited.
Impact 2 — The stranded ETH silently accrues to the fee collector via collectFee() instead of being refunded.
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.