s_buyFee is multiplied by PRECISION (1e18) in the constructor, and buySnow multiplies it by an amount that is already in 18-decimal base units without dividing the precision back out, so the price is scaled twice.
Snow can be purchased with ETH or WETH. A buyer pays the buy fee for the amount of Snow they want.
The constructor stores s_buyFee = _buyFee * PRECISION, and buySnow charges s_buyFee * amount. Because Snow is a standard 18-decimal ERC20, one whole Snow is 1e18 base units, so amount already carries a factor of 1e18. Multiplying the two scaled values gives a cost with the 1e18 factor counted twice. Since the constructor rejects _buyFee == 0, the cheapest possible configuration is _buyFee = 1, which gives s_buyFee = 1e18 wei per base unit (1 ETH for 0.000000000000000001 Snow) and 1e36 wei for one whole Snow.
Likelihood: High
Every deployment is affected. The constructor blocks a zero fee, so no valid _buyFee can make the price reasonable, and any wallet or frontend that sends one whole token (1e18) triggers it.
Impact: Medium
Buying whole tokens is impossible: at the minimum fee, one whole Snow costs 1e36 wei (1e18 ETH), far more than all ETH in existence.
The only purchases that can succeed are tiny base-unit amounts at a price of at least 1 ETH per 1e-18 Snow, so the paid path of the protocol, and the fees the collector is meant to gather, is effectively unusable.
Add SnowFeePoC.t.sol to your test/ folder and run:
Output:
The first test shows a buyer paying 1 ETH for a single base unit (1e-18 Snow) at the lowest possible fee. The second shows one whole Snow requires 1e36 wei, more than the ETH supply, so even a 1,000 ETH payment reverts.
Divide the precision back out so the fee means "price of one whole Snow in wei", and use one cost value in both branches:
If the intended design was instead to price each base unit directly, remove the * PRECISION from the constructor (s_buyFee = _buyFee;).
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.