Snowman Merkle Airdrop

AI First Flight #10
Beginner FriendlyFoundrySolidityNFT
EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

Snow.buySnow() ETH/WETH Path Logic Flaw — Trapped ETH & Silent Fallthrough

Root + Impact

Description

  • buySnow() uses an if/else: if msg.value exactly equals the fee, it mints via ETH. Otherwise it falls through to the WETH path regardless of what msg.value was sent. A user sending some ETH that doesn't match the exact fee pays both ETH (now trapped forever) and WETH. Additionally, calling with msg.value = 0 and amount = 0 passes the == check (both 0), mints nothing, but resets the global timer

function buySnow(uint256 amount) external payable canFarmSnow {
>if (msg.value == (s_buyFee * amount)) {
_mint(msg.sender, amount);
>} else {
i_weth.safeTransferFrom(msg.sender, address(this), (s_buyFee * amount));
> _mint(msg.sender, amount);
}
s_earnTimer = block.timestamp;
emit SnowBought(msg.sender, amount);
}

Risk

Likelihood:

  • Any user who miscalculates the exact ETH amount, or sends ETH while intending the WETH path, will lose their ETH permanently. Common user error scenario.

Impact:

  • Permanent loss of user ETH with no recovery mechanism. The contract has no receive()/fallback() and no withdrawal function for mistakenly sent ETH (though collectFee() sends address(this).balance).

Proof of Concept

function buySnow(uint256 amount) external payable canFarmSnow {
if (msg.value == (s_buyFee * amount)) { // only exact match
_mint(msg.sender, amount);
} else { // ANY other msg.value falls here — including partial ETH
i_weth.safeTransferFrom(msg.sender, address(this), (s_buyFee * amount));
_mint(msg.sender, amount); // user pays WETH AND loses sent ETH
}

Recommended Mitigation

- if (msg.value == (s_buyFee * amount)) {
- _mint(msg.sender, amount);
- } else {
- i_weth.safeTransferFrom(msg.sender, address(this), (s_buyFee * amount));
- _mint(msg.sender, amount);
- }
-
- s_earnTimer = block.timestamp;
-
- emit SnowBought(msg.sender, amount);
+ if (msg.value > 0) {
+ require(msg.value == s_buyFee * amount, "Incorrect ETH amount");
+ _mint(msg.sender, amount);
+ } else {
+ i_weth.safeTransferFrom(msg.sender, address(this), s_buyFee * amount);
+ _mint(msg.sender, amount);
+ }
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 3 hours ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!