Snowman Merkle Airdrop

First Flight #42
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Impact: high
Likelihood: medium
Invalid

Payment Logic Flaw in buySnow of Snow.sol

Root + Impact

Description

  • Normal Behavior: The buySnow function should mint Snow tokens after verifying correct ETH or WETH payment, ensuring protocol revenue.

  • Specific Issue: The function’s payment logic allows incorrect ETH amounts to trigger WETH transfers without explicit validation, leading to reverts if WETH transfers fail (e.g., insufficient balance/allowance).

// Root cause in the codebase with @> marks to highlight the relevant section
function buySnow(uint256 amount) external payable canFarmSnow {// @> No amount validation
if (msg.value == (s_buyFee * amount)) {
_mint(msg.sender, amount);
} else {
i_weth.safeTransferFrom(msg.sender, address(this), (s_buyFee * amount));// @> Fails if no WETH
_mint(msg.sender, amount);
}
s_earnTimer = block.timestamp;
emit SnowBought(msg.sender, amount);// @> Emits for zero amount
}

Risk

Likelihood:

  • Occurs when users send incorrect ETH and lack WETH balance/allowance, causing reverts.

  • Zero amount calls are processed, emitting SnowBought(0) events, common in user errors or bot interactions.

Impact:

  • Transaction failures confuse users, degrading experience and trust.

  • Zero-amount transactions waste gas and mislead analytics, potentially affecting economic models.

Proof of Concept

Snow snow = Snow(snowAddress);
snow.buySnow{value: 1}(1000);// Reverts if WETH transfer fails
snow.buySnow{value: s_buyFee * 0}(0);// Wastes gas, emits SnowBought(0)

Recommended Mitigation

+ error S__InvalidAmount();
+ error S__InvalidPayment();
- function buySnow(uint256 amount) external payable canFarmSnow {
+ function buySnowWithETH(uint256 amount) external payable canFarmSnow {
+ if (amount == 0) revert S__InvalidAmount();
+ if (msg.value != s_buyFee * amount) revert S__InvalidPayment();
_mint(msg.sender, amount);
- } else {
- i_weth.safeTransferFrom(msg.sender, address(this), (s_buyFee * amount));
- _mint(msg.sender, amount);
- }
- s_earnTimer = block.timestamp;
+ s_userEarnTimer[msg.sender] = block.timestamp;
emit SnowBought(msg.sender, amount);
+ }
+ function buySnowWithWETH(uint256 amount) external canFarmSnow {
+ if (amount == 0) revert S__InvalidAmount();
+ if (msg.value != 0) revert S__InvalidPayment();
+ i_weth.safeTransferFrom(msg.sender, address(this), s_buyFee * amount);
+ _mint(msg.sender, amount);
+ s_userEarnTimer[msg.sender] = block.timestamp;
+ emit SnowBought(msg.sender, amount);
}
Updates

Lead Judging Commences

yeahchibyke Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.