buySnow When Exact Fee Condition FailsSeverity: Medium-High
Impact: Users who send ETH to buySnow and fail to meet the exact msg.value requirement will permanently lose their ETH with no mechanism for refund, even though the transaction proceeds (or reverts due to WETH allowance). In the current fee configuration, the ETH payment path is virtually impossible, guaranteeing that any ETH sent is lost.
Affected Contract: Snow.sol
The buySnow function allows users to purchase Snow tokens using either native ETH or WETH. If a user sends ETH, the function checks whether msg.value == (s_buyFee * amount). If this condition fails (which it almost always will, due to a separate scaling error that makes the required ETH amount astronomical), the function does not refund the sent ETH. Instead, it attempts to transfer WETH from the caller, ignoring the already‑sent ETH. The ETH remains permanently locked in the contract, accessible only by the collector via collectFee. A user attempting to pay with ETH will therefore lose their funds.
The relevant code in Snow.sol:
When the caller attaches ETH (msg.value > 0) and the exact amount condition fails, the code falls into the else branch.
The else branch does not use msg.value at all; it only pulls WETH. The attached ETH is not refunded.
The contract has no function to refund stray ETH to users. The only ETH retrieval mechanism is collectFee, which sends all ETH to the collector. Thus, the user’s ETH is irretrievably lost.
This issue is exacerbated by the fact that s_buyFee is incorrectly scaled (multiplied by 1e18 in the constructor), making the required msg.value astronomically large for any reasonable amount. Consequently, the condition is never satisfied, and any ETH sent to buySnow is immediately lost.
Run this test: it passes, showing that the user lost both ETH and WETH for a single purchase. The ETH is trapped.
Direct financial loss: Users who send ETH expecting to buy tokens will lose that ETH, effectively paying double (ETH + WETH) if the WETH transfer succeeds, or losing the ETH if the transaction partially fails (though a revert would refund, a successful WETH transfer causes permanent loss).
No recovery mechanism: The contract provides no way for users to reclaim mistakenly sent ETH.
Exacerbated by scaling bug: The broken fee calculation ensures that the ETH payment condition is practically unreachable, making any ETH sent always lost.
Refund excess ETH when the condition is not met, or revert if msg.value > 0 and the condition fails. For example:
Fix the fee scaling by removing the unnecessary multiplication by PRECISION in s_buyFee, so the condition becomes usable.
Add a refund function restricted to the owner, but better to prevent the loss entirely.
Implementing these changes ensures that users cannot accidentally lose ETH and that the ETH payment path functions as intended.
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.