Snowman Merkle Airdrop

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

Airdrop minting uses token balance in wei, causing massive loops and OOG errors

Root + Impact

The SnowmanAirdrop.claimSnowman function calculates the amount of NFTs to mint based on the user's Snow token balance retrieved via i_snow.balanceOf(receiver). Since Snow is an ERC20 token with 18 decimals, balanceOf returns values in wei. For a user holding just 1 Snow token, the balance is 1 * 10^18. The SnowmanAirdrop contract passes this raw 10^18 value to i_snowman.mintSnowman, which then attempts to loop 10^18 times to mint individual NFTs.

Description

This creates two critical issues:

  1. Denial of Service (DoS): Executing a loop of 10^18 iterations is computationally impossible on any current blockchain. The transaction will consume all available gas and eventually revert (OutOfGas), preventing any legitimate user with a non-trivial balance from ever claiming their NFTs.

  2. Economic Exploitation: A user with a microscopic balance (e.g., 1000 wei, or 0.000000000000001 tokens) could successfully mint 1000 NFTs within gas limits for virtually zero cost, as the contract treats "1 wei" as "1 NFT".

// src/SnowmanAirdrop.sol
@> uint256 amount = i_snow.balanceOf(receiver);
// ...
@> i_snowman.mintSnowman(receiver, amount);
// src/Snowman.sol
function mintSnowman(address receiver, uint256 amount) external {
@> for (uint256 i = 0; i < amount; i++) {
_safeMint(receiver, s_TokenCounter);
// ...
}
}

Risk

Likelihood: High

  • Any user who has interacted with the protocol normally (owning 1 or more tokens) will trigger this logic.

  • It is a systematic failure of the minting logic's scale.

Impact: High

  • Permanent loss of access to airdrop rewards for all eligible users.

  • Potential sybil attack where users buy tiny amounts of tokens to mint vast quantities of NFTs for cheap.

Proof of Concept

The PoC illustrates the numerical impossibility of the code. It calculates that if a user owns just 1 Snow token, the mintSnowman function will try to loop 1,000,000,000,000,000,000 times. In Foundry, this results in an immediate OutOfGas error or a massive hang, demonstrating that the function is unusable in production.

function test_poc_MintingLoopDescription() public {
// 1. A user holds exactly 1 Snow token
uint256 balanceInWei = 1e18; // 1.000000000000000000 Snow
// 2. The airdrop contract would call:
// nft.mintSnowman(user, 1e18);
// 3. The Snowman contract would attempt:
// for (uint256 i = 0; i < 1e18; i++) { _safeMint(...) }
console2.log("Loop iterations attempted:", balanceInWei);
console2.log("Conclusion: Transaction will always fail due to gas limits.");
}

Recommended Mitigation

The amount should be scaled down from the token's precision (wei) to the intended NFT unit. If the rule is "1 Snow token = 1 Snowman NFT", the balance must be divided by the token's decimals (10^18).

// src/SnowmanAirdrop.sol
- uint256 amount = i_snow.balanceOf(receiver);
+ uint256 amount = i_snow.balanceOf(receiver) / 10**18;
Updates

Lead Judging Commences

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