Snowman Merkle Airdrop

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

Snow.collectFee calls ERC20.transfer without checking return value — non-standard tokens silently fail

Snow.collectFee calls ERC20.transfer without checking return value

Impact

Low Impact

Likelihood

Low Likelihood

Root + Impact

Description

  • Snow.collectFee is responsible for sweeping accumulated WETH and ETH fees to the collector address.

  • The WETH transfer uses i_weth.transfer(s_collector, collection) — a raw ERC20 transfer call whose boolean return value is not checked. Although SafeERC20 is already imported in the project (used in SnowmanAirdrop), it is not used in Snow. Non-standard ERC20 tokens (notably USDT on some networks) return false on failure instead of reverting; an unchecked transfer will silently succeed while no tokens move.

// src/Snow.sol
function collectFee() external onlyCollector {
uint256 collection = i_weth.balanceOf(address(this));
@> i_weth.transfer(s_collector, collection); // return value not checked
(bool success,) = payable(s_collector).call{value: address(this).balance}("");
if (!success) revert S__TransferFailed();
}

Risk

Likelihood:

  • Only manifests if the token used as i_weth does not revert on failure — standard WETH always reverts, so current risk is low.

Impact:

  • Fee collection silently fails; WETH remains in the contract while the collector believes fees were paid.

Proof of Concept

1) Deploy Snow with a mock ERC20 that returns false on transfer
2) Collector calls collectFee()
3) i_weth.transfer returns false — no revert — no tokens moved
4) Contract WETH balance unchanged; collector receives nothing

Recommended Mitigation

+ using SafeERC20 for IERC20;
function collectFee() external onlyCollector {
uint256 collection = i_weth.balanceOf(address(this));
- i_weth.transfer(s_collector, collection);
+ i_weth.safeTransfer(s_collector, collection);
(bool success,) = payable(s_collector).call{value: address(this).balance}("");
if (!success) revert S__TransferFailed();
}
Updates

Lead Judging Commences

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