Snowman Merkle Airdrop

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

ETH/WETH Handling in buySnow

Root + Impact

Description

  • Expected : The buySnow function should enforce strict payment requirements — either ETH or WETH — to ensure liquidity is properly managed and avoid fund loss.

  • Bug : The function checks msg.value == (s_buyFee * amount) but does not validate whether WETH was transferred when msg.value == 0. This creates a discrepancy where users can pay ETH while the contract expects WETH, leading to frozen ETH balances in the contract.


// ❌ Vulnerable Code
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 :

  • Medium : Users may accidentally send ETH instead of WETH, especially if interface instructions are unclear.

  • Medium : Contracts interacting with buySnow may misconfigure payment types, leading to unintended ETH deposits.

Impact :

  • Medium : ETH sent to the contract cannot be processed or withdrawn, locking liquidity.

  • Low : Users lose access to their ETH, but WETH payments remain functional.

Proof of Concept

// Exploit contract demonstrating ETH/WETH handling flaw
contract Exploit {
address public snowContract = 0xDeployedSnowAddress;
function attack() external payable {
// Call buySnow with ETH payment (contract expects WETH)
(bool success,) = snowContract.call{value: 1 ether}(
abi.encodeWithSignature("buySnow(uint256)", 1)
);
require(success, "Buy failed");
}
}

Explanation :
By sending ETH directly to buySnow, the contract accepts the payment (msg.value == s_buyFee * amount) but does not verify if WETH is intended . The ETH remains stuck in the contract, as there is no logic to handle or refund it.

Recommended Mitigation

- function buySnow(uint256 amount) external payable canFarmSnow {
+ function buySnow(uint256 amount, bool isEth) external payable canFarmSnow {
if (isEth) {
require(msg.value == (s_buyFee * amount), "Invalid ETH amount");
_mint(msg.sender, amount);
} else {
require(msg.value == 0, "ETH sent for WETH payment");
i_weth.safeTransferFrom(msg.sender, address(this), (s_buyFee * amount));
_mint(msg.sender, amount);
}
s_earnTimer = block.timestamp;
emit SnowBought(msg.sender, amount);
}

Steps :

Add Payment Type Flag : Introduce a bool isEth parameter to explicitly distinguish between ETH and WETH payments.
Validate ETH/WETH Separately : Ensure msg.value == 0 for WETH payments and reject mismatched transfers.
Rationale :
This prevents accidental ETH deposits when WETH is required, ensuring liquidity is handled correctly and avoiding fund loss.

Updates

Lead Judging Commences

yeahchibyke Lead Judge
about 2 months ago
yeahchibyke Lead Judge about 2 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.