Snowman Merkle Airdrop

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

Unbounded Loop in mintSnowman Can Cause DoS

Root + Impact

The mintSnowman function has no upper limit on the amount parameter, allowing extremely large mint requests that exceed block gas limits and cause transaction failures.

Description

The mintSnowman function should safely mint NFTs without risk of transaction failure due to gas limits. Large minting requests should be handled gracefully.

The function uses an unbounded loop that iterates amount times. If amount is very large, the transaction will exceed block gas limits and revert, potentially blocking legitimate large claims.

// Snowman.sol
function mintSnowman(address receiver, uint256 amount) external {
// @> No upper bound check on amount
for (uint256 i = 0; i < amount; i++) {
_safeMint(receiver, s_TokenCounter);
emit SnowmanMinted(receiver, s_TokenCounter);
s_TokenCounter++;
}
}

Risk

Likelihood:MEDIUM

  • Reason 1: Users with large Snow token holdings will trigger large mint amounts

  • Reason 2: Whales or accumulated holdings over time lead to large claims

Impact:MEDIUM

  • Impact 1:Users with significant holdings cannot claim their NFTs

  • Impact 2:Potential permanent lockout for high-value participants

Proof of Concept

This test shows that when a whale with 100,000 tokens attempts to claim their NFTs, the transaction runs out of gas due to the unbounded loop. The user is left unable to claim despite being a legitimate airdrop recipient with verified Merkle proof.

function testLargeMintFails() public {
address whale = makeAddr("whale");
uint256 largeAmount = 100000;
vm.prank(address(airdrop));
uint256 gasStart = gasleft();
vm.expectRevert(); // Out of gas
snowman.mintSnowman(whale, largeAmount);
}

Recommended Mitigation:

Add a maximum mint limit per transaction. Users with allocations exceeding this limit can claim in multiple transactions. This ensures all users can claim their NFTs regardless of allocation size.

+ uint256 public constant MAX_MINT_PER_TX = 100;
+ error SM__ExceedsMaxMint();
function mintSnowman(address receiver, uint256 amount) external {
+ if (amount > MAX_MINT_PER_TX) {
+ revert SM__ExceedsMaxMint();
+ }
for (uint256 i = 0; i < amount; i++) {
_safeMint(receiver, s_TokenCounter);
emit SnowmanMinted(receiver, s_TokenCounter);
s_TokenCounter++;
}
}
Updates

Lead Judging Commences

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