Snowman Merkle Airdrop

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

ETH Stuck in Contract When sent more or less than Snow price and Paying With WETH

Root + Impact

Description

  • Normally, users can buy Snow tokens by sending the exact amount of ETH or by paying with WETH. The contract mints the correct amount of Snow tokens and emits an event.

  • However, when a user sends less or more ETH than required and pays with WETH, the contract does not refund the ETH sent. This ETH remains stuck in the contract, as there is no withdrawal or refund logic for this scenario.

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);
// @> No refund for msg.value in this branch <@
}
s_earnTimer = block.timestamp;
emit SnowBought(msg.sender, amount);
}

Risk

Likelihood:

  • This will occur whenever a user sends any ETH (msg.value > 0) that is not exactly equal to the required buy fee and pays with WETH.

  • Users may mistakenly send ETH along with their WETH payment, especially if interacting with the contract directly or via custom interfaces.

Impact:

  • Users can lose ETH by mistake, as it becomes stuck in the contract with no way to retrieve it.

  • The contract accumulates ETH that is not accessible, potentially leading to user frustration or loss of trust.

Proof of Concept

User sends 1 wei ETH and has enough WETH and approval
The contract mints 1 Snow token after taking WETH, but the 1 wei ETH remains stuck in the contract.

// User sends 1 wei ETH and has enough WETH and approval
buySnow{value: 1}(1);
// The contract mints 1 Snow token after taking WETH, but the 1 wei ETH remains stuck in the contract.
assert(address(contract).balance == 1); // ETH is stuck

Recommended Mitigation

Add logic to refund any ETH sent in the WETH payment branch. This ensures that users who accidentally send ETH (either less or more than the required amount) while paying with WETH do not lose their funds.

- i_weth.safeTransferFrom(msg.sender, address(this), (s_buyFee * amount));
- _mint(msg.sender, amount);
+ i_weth.safeTransferFrom(msg.sender, address(this), (s_buyFee * amount));
+ _mint(msg.sender, amount);
+ if (msg.value > 0) {
+ (bool sent, ) = msg.sender.call{value: msg.value}("");
+ require(sent, "Refund failed");
+ }
Updates

Lead Judging Commences

yeahchibyke Lead Judge
3 months ago
yeahchibyke Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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