Snowman Merkle Airdrop

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

`collectFee` Uses Unchecked `transfer()` Instead of `safeTransfer()` for WETH, Risking Silent Fee Loss

Root + Impact

Description

  • The Snow contract imports SafeERC20 and applies using SafeERC20 for IERC20 for safe ERC20 interactions. The buySnow() function correctly uses safeTransferFrom() on line 83.

  • The collectFee() function calls i_weth.transfer() directly (line 103) instead of i_weth.safeTransfer(). The transfer() function returns a boolean that is not checked. If the WETH implementation returns false on failure rather than reverting, fees are silently lost.

// src/Snow.sol
using SafeERC20 for IERC20; // Line 19 — SafeERC20 imported
function buySnow(uint256 amount) external payable canFarmSnow {
// ...
i_weth.safeTransferFrom(...); // Line 83 — CORRECT usage
}
function collectFee() external onlyCollector {
uint256 collection = i_weth.balanceOf(address(this));
i_weth.transfer(s_collector, collection); // @> Line 103 — UNSAFE, unchecked return
(bool collected,) = payable(s_collector).call{value: address(this).balance}("");
require(collected, "Fee collection failed!!!");
}

Risk

Likelihood:

  • Standard WETH implementations revert on failure, so this vulnerability is unlikely to manifest with canonical WETH contracts. It becomes exploitable with non-standard ERC20 tokens that return false on failure.

Impact:

  • If WETH transfer silently fails, the function proceeds to send native ETH. WETH fees accumulate permanently in the contract with no recovery path, while the collector only receives native ETH.

Proof of Concept

This is a code-review finding confirmed by comparing the SafeERC20 usage across the contract. Line 83 uses safeTransferFrom (correct), while line 103 uses transfer (inconsistent and unsafe).

function test_SAST006_UnsafeTransfer() public {
// Code review confirmation:
// Line 19: using SafeERC20 for IERC20
// Line 83: i_weth.safeTransferFrom() — CORRECT
// Line 103: i_weth.transfer() — UNSAFE, unchecked return
}

Recommended Mitigation

Replace transfer() with safeTransfer() for consistency and safety.

function collectFee() external onlyCollector {
uint256 collection = i_weth.balanceOf(address(this));
- i_weth.transfer(s_collector, collection);
+ i_weth.safeTransfer(s_collector, collection);
(bool collected,) = payable(s_collector).call{value: address(this).balance}("");
require(collected, "Fee collection failed!!!");
}
Updates

Lead Judging Commences

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