Snowman Merkle Airdrop

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

[M-01] Unchecked Return Value of i_weth.transfer in Snow::collectFee Leads to Potential Loss of Protocol Fees

Root + Impact

Description

  • Normal Behavior: When the collectFee function is called, the contract should transfer all accumulated WETH fees to the s_collector address and ensure the transaction was successful before proceeding with any state changes.

  • Specific Issue: The contract executes i_weth.transfer(s_collector, collection) but does not check the boolean return value. Many ERC20 implementations (including some versions of WETH on different chains) return false instead of reverting if a transfer fails. This leads to a "Silent Failure" where the contract assumes the fees were sent when they were not.

function collectFee() external {
uint256 collection = i_weth.balanceOf(address(this));
// @> VULNERABILITY: The return value of transfer is ignored.
// If the transfer returns 'false', the function continues execution.
i_weth.transfer(s_collector, collection);
// Potential state resets here would happen even on failed transfers.
}

Risk

Likelihood

  • Reason 1: Certain ERC20 token implementations are known for returning false on failure (e.g., USDT or older WETH versions on specific sidechains), which is a common pitfall in smart contract development.

  • Reason 2: If the s_collector address is a contract that is blacklisted (in certain token types) or cannot receive tokens due to logic errors, the transfer will fail silently.

Impact:

  • Impact 1 (Financial Loss): The protocol loses its accumulated fees because the contract logic proceeds as if the funds were successfully moved to the collector.

  • Impact 2 (Accounting Errors): Internal accounting or events emitted after the call will report a successful collection, creating a discrepancy between the on-chain data and the actual balance in the collector's wallet.

Proof of Concept

Scenario: The Snow contract has accumulated 10 WETH in fees.

  • Trigger: An admin calls collectFee().

  • Failure: Due to a non-standard WETH implementation or an issue at the recipient's end, the transfer call fails and returns false.

  • Silent Continuation: Because there is no require() or check on the return value, the EVM does not revert the transaction.

  • Outcome: The collectFee() execution completes "successfully" in the eyes of the blockchain, but the 10 WETH remains in the Snow contract, and the s_collector receives nothing.

Scenario: The Snow contract has accumulated 10 WETH in fees.
Trigger: An admin calls collectFee().
Failure: Due to a non-standard WETH implementation or an issue at the recipient's end, the transfer call fails and returns false.
Silent Continuation: Because there is no require() or check on the return value, the EVM does not revert the transaction.
Outcome: The collectFee() execution completes "successfully" in the eyes of the blockchain, but the 10 WETH remains in the Snow contract, and the s_collector receives nothing.

Recommended Mitigation

Implementation

The most secure way to handle ERC20 transfers is using OpenZeppelin's SafeERC20 library, or at minimum, wrapping the call in a require statement.

+ import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
// ...
function collectFee() external {
uint256 collection = i_weth.balanceOf(address(this));
- i_weth.transfer(s_collector, collection);
+ bool success = i_weth.transfer(s_collector, collection);
+ if (!success) revert TransferFailed(); // Or use SafeERC20.safeTransfer
}

Explanation
By checking the return value, we ensure that the entire transaction reverts if the transfer does not succeed. This guarantees atomicity: either the collector gets the money and the state updates, or nothing happens at all. This prevents the protocol from losing track of its funds.

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!