Snowman Merkle Airdrop

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

[M-3] Silent Failure in collectFee Due to Unsafe WETH Transfer

Root + Impact

  • Root: The collectFee function uses i_weth.transfer, ignoring its return value, instead of SafeERC20.safeTransfer;

  • Impact: Silent failure of WETH transfer could leave funds uncollected, risking loss or exploitation.

Description

  • The collectFee function transfers all WETH to s_collector using i_weth.transfer, which does not revert on failure and lacks return value checking. This could result in funds remaining in the contract if the transfer fails (e.g., collector’s balance cap or reentrancy guard), unlike safeTransfer which would revert.

// Root cause in the codebase with @> marks to highlight the relevant section// Root cause in the codebase with @> marks to highlight the relevant section
function collectFee() external onlyCollector {
uint256 collection = i_weth.balanceOf(address(this));
@> i_weth.transfer(s_collector, collection);
//@Audit medium - ignores return value by i_weth.transfer, use ERC20 safeTransfer instead for the function to revert properly.
(bool collected,) = payable(s_collector).call{value: address(this).balance}("");
require(collected, "Fee collection failed!!!");
}

Risk

** Likelihood**:

  • When the collector’s contract rejects WETH transfers or has a balance limit.

  • During fee collection with untrusted collector implementations.

    Impact:

  • Leaves WETH in the contract, reducing collected fees.

  • Medium severity due to potential fund loss.

Proof of Concept

  • Silent Failure Test:

  • Deploy a Snow contract with a mock WETH that reverts on transfer.

  • Call collectFee and verify no revert occurs, with WETH remaining.
    Steps:

  1. Mint 100 WETH to the Snow contract.

  2. Set a mock WETH to fail transfer.

  3. Call collectFee as the collector.

  4. Check that the contract still holds WETH, proving silent failure.

Recommended Mitigation

import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
function collectFee() external onlyCollector {
uint256 collection = i_weth.balanceOf(address(this));
- i_weth.transfer(s_collector, collection);
+ SafeERC20.safeTransfer(i_weth, s_collector, collection); // Use safeTransfer
(bool collected,) = payable(s_collector).call{value: address(this).balance}("");
require(collected, "Fee collection failed!!!");
}
  • Replace transfer with safeTransfer to ensure proper reversion on failure.

Updates

Lead Judging Commences

yeahchibyke Lead Judge about 2 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.