Snowman Merkle Airdrop

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

[M-1] Incorrect ETH Handling in buySnow() Causes Double Payment

Root + Impact

  • Root: Missing Validation/Refund of msg.value

  • Impact: Loss of Funds

Description

  • The buySnow() function determines the payment method using strict equality.

  • If the user sends an incorrect msg.value, execution falls into the else branch, where WETH is transferred using safeTransferFrom.

  • However, the contract does not:

    • validate incorrect ETH amounts

    • revert the transaction

    • refund any ETH sent

  • As a result, any ETH sent is accepted and retained by the contract, while the user is still charged the full amount in WETH.

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);
}

Risk

Likelihood:**** Medium

  • Reason: Requires the user to send an incorrect ETH amount, which is likely due to UI issues, miscalculations, or user error.

Impact:

  • Users may unintentionally pay both ETH and WETH for a single purchase

  • ETH sent is permanently locked in the contract

  • Results in unintended loss of funds due to incorrect payment handling

Proof of Concept

The following test demonstrates that a user can lose both ETH and WETH when sending an incorrect ETH amount.

Step-by-step:

  1. Setup

    • A user is funded with both ETH and WETH

    • The user approves the contract to spend WETH

  2. Incorrect Payment

    • The user calls buySnow() with an incorrect msg.value (slightly less than required)

  3. Execution Flow

    • The equality check fails (msg.value != required)

    • The contract enters the WETH branch

    • WETH is transferred from the user

  4. ETH Handling

    • The ETH sent with the transaction is not refunded

    • The transaction does not revert

  5. Result

    • The user loses both ETH and WETH

function test_DoublePayment() public {
address user = address(1);
// Fund user
vm.deal(user, 10 ether);
deal(address(weth), user, 10 ether);
// Approve WETH
vm.prank(user);
weth.approve(address(snow), type(uint256).max);
uint256 fee = snow.s_buyFee();
// Send incorrect ETH
vm.prank(user);
snow.buySnow{value: fee - 1}(1);
// ETH was spent
assert(user.balance < 10 ether);
// WETH was also taken
assert(weth.balanceOf(user) < 10 ether);
}

Recommended Mitigation

Validate ETH input and revert on incorrect values:

+ if (msg.value > 0 && msg.value != (s_buyFee * amount)) {
+ revert S__InvalidPayment();
+}
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 4 days 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!