Snowman Merkle Airdrop

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

Gas-Inefficient Event Emission in Loop

Root + Impact

Description

The mintSnowman() function emits an event inside a loop for each NFT minted. This is gas-inefficient and can lead to very high gas costs when minting large amounts of NFTs. For users claiming significant amounts, this could make the transaction prohibitively expensive or even cause it to exceed block gas limits.

Each event emission costs additional gas, and when multiplied by potentially hundreds or thousands of iterations, the total cost becomes significant.

// src/Snowman.sol:36-44
function mintSnowman(address receiver, uint256 amount) external {
for (uint256 i = 0; i < amount; i++) {
_safeMint(receiver, s_TokenCounter);
emit SnowmanMinted(receiver, s_TokenCounter); // @> Emitted in loop - gas inefficient
s_TokenCounter++;
}
}

Risk

Likelihood:

  • Every mint operation triggers this inefficiency

  • Users claiming large amounts will definitely hit this

  • No way to avoid this in current implementation

Impact:

  • High gas costs for users claiming many NFTs

  • Potential DOS if amount is very large (gas limit exceeded)

  • Poor user experience

  • Makes large claims economically unviable

Proof of Concept

function testGasInefficiency() public {
// Mint 100 NFTs with current implementation
uint256 gasBefore = gasleft();
snowman.mintSnowman(alice, 100);
uint256 gasUsed = gasBefore - gasleft();
// Gas breakdown:
// - 100 _safeMint calls
// - 100 event emissions ← Extra cost
// - 100 counter increments
// With optimized version (single event):
// - 100 _safeMint calls
// - 1 event emission ← Much cheaper
// - 100 counter increments
// Gas savings: ~2,000 gas per event * 100 = ~200,000 gas saved
// For 1000 NFTs: ~2,000,000 gas saved
// At 50 gwei: ~0.1 ETH saved
}

Recommended Mitigation

- event SnowmanMinted(address indexed receiver, uint256 indexed numberOfSnowman);
+ event SnowmanMinted(address indexed receiver, uint256 indexed startTokenId, uint256 amount);
function mintSnowman(address receiver, uint256 amount) external {
+ uint256 startTokenId = s_TokenCounter;
+
for (uint256 i = 0; i < amount; i++) {
_safeMint(receiver, s_TokenCounter);
- emit SnowmanMinted(receiver, s_TokenCounter);
s_TokenCounter++;
}
+
+ emit SnowmanMinted(receiver, startTokenId, amount);
}
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!