The Snow::buySnow function at Snow.sol line 79 is marked payable and uses an if/else branch to decide the payment method. When msg.value equals exactly s_buyFee * amount,
the user pays with ETH. Otherwise, the else branch executes and pulls WETH via safeTransferFrom.
The problem: when a user sends ETH that does not match the exact fee (msg.value != s_buyFee * amount), the function accepts the ETH (because payable), but also pulls the
full WETH amount. The user pays twice — once in ETH, once in WETH — and only receives Snow tokens for one payment. The ETH is permanently trapped inside the contract with
no dedicated withdrawal mechanism for the user.
// Snow.sol, lines 79-89
Likelihood:
Any user who sends ETH with an amount that doesn't perfectly match s_buyFee * amount triggers this path — a rounding mistake, a wrong amount parameter, or simply not
knowing the exact fee triggers double payment.
Wallet UIs and scripts that set msg.value based on estimates rather than the exact on-chain s_buyFee will hit the else branch consistently.
Impact:
The user loses the ETH sent with the transaction — it stays locked in the contract and cannot be recovered by the user.
The user also pays the full WETH fee, effectively paying double for the same Snow tokens.
While collectFee sweeps the contract's ETH balance, this goes to the collector — not back to the overpaying user.
The test demonstrates that a user who sends 1 wei of ETH alongside a WETH purchase loses that ETH permanently while also paying the full WETH fee. The user ends up paying
double — both ETH and WETH — for the same Snow tokens.
How to run: forge test --mt test_ethTrappedWithWethPayment -vvvv
Add a check in the else branch to ensure 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.