Snowman Merkle Airdrop

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

M-5 — Unbounded mint loop makes large claims unexecutable

Root + Impact

claimSnowman passes the receiver's full balance to mintSnowman, which mints one NFT per iteration. There is no cap, so a large Snow balance makes the claim exceed the block gas limit and revert permanently.

Description

// src/SnowmanAirdrop.sol
@>84: uint256 amount = i_snow.balanceOf(receiver);
...
@>98: i_snowman.mintSnowman(receiver, amount);
​
// src/Snowman.sol
@>37: for (uint256 i = 0; i < amount; i++) {
38: _safeMint(receiver, s_TokenCounter);
42: s_TokenCounter++;
43: }

Risk

Likelihood: Medium — a holder accumulates a large balance (buy/earn) or is griefed with tokens.

Impact: Medium — the claim is permanently unexecutable (gas-limit DoS); the holder cannot redeem.

Proof of Concept

function test_PoC6_MintGasUnbounded() public {
_deploy();
address r = makeAddr("r");
​
uint256 g0 = gasleft();
nft.mintSnowman(r, 1);
uint256 one = g0 - gasleft();
​
uint256 g1 = gasleft();
nft.mintSnowman(r, 500);
uint256 fiveHundred = g1 - gasleft();
​
emit log_named_uint("gas mint(1)", one); // ~79,878
emit log_named_uint("gas mint(500)", fiveHundred); // ~16,556,978
assertGt(fiveHundred, one * 100);
}

~33k gas per NFT; ~900 mints exceeds a 30M block gas limit.

Recommended Mitigation

Bound the per-call mint and/or use a batch mint implementation.

// src/Snowman.sol
+ uint256 public constant MAX_PER_CALL = 50;
function mintSnowman(address receiver, uint256 amount) external {
+ if (amount > MAX_PER_CALL) revert SM__NotAllowed();
for (uint256 i = 0; i < amount; i++) {

Alternatively, allow the claimant to mint in bounded batches and track the remaining entitlement.


Updates

Lead Judging Commences

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