Snowman Merkle Airdrop

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

ETH Can Be Trapped in Contract Forever in `Snow.sol::buySnow()`

[Low] ETH Can Be Trapped in Contract Forever in Snow.sol::buySnow()


Description

The Snow.sol contract is declared payable, which means it can receive native ETH. However, there is no explicit receive() or fallback() function defined to handle incoming ETH. While buySnow can accept msg.value, if users accidentally send ETH directly to the contract address (i.e., not through buySnow), or if ETH is sent in an amount not expected by the buySnow logic (as discussed in H-2), that ETH will be irrevocably trapped within the contract. There is no refund mechanism or a function for the owner to withdraw this unintentionally sent ETH.


Risk

Users can permanently lose funds if they mistakenly send ETH directly to the contract. The contract's ETH balance will accumulate these untraceable and unrecoverable funds, which cannot be utilized or returned.


Proof of Concept

The provided testETHTrappedInFallback() function in SnowTest.t.sol demonstrates this scenario:

function testETHTrappedInFallback() public {
vm.deal(jerry, 1 ether);
vm.prank(jerry);
(bool sent,) = address(snow).call{value: 0.1 ether}(""); // Direct ETH transfer to the contract
require(sent, "ETH send failed");
assertEq(address(snow).balance, 0.1 ether); // The ETH is now trapped in the contract
}

Recommended Mitigation

Implement a receive() function. For a contract that is not intended to hold arbitrary ETH, the safest and clearest approach is to make this function revert, explicitly rejecting any unexpected ETH transfers. If the contract is designed to receive ETH for other purposes, then a specific handling logic (e.g., wrapping to WETH, forwarding to an owner/treasury) should be implemented.

+ receive() external payable {
+ revert("Snow: ETH not accepted directly. Use buySnow with correct value.");
+ }
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.