Snowman Merkle Airdrop

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

DoS of mintSnowman leading to users Unable to Claim Their NFT

Root + Impact

Description

  • The mintSnowman function performs a for loop that mints one NFT per iteration, based on the provided amount.

  • This loop is unbounded, and if the amount is too large (e.g., 8001+), the transaction exceeds the block gas limit and reverts, preventing users from claiming their NFTs.

function mintSnowman(address receiver, uint256 amount) external {
@> for (uint256 i = 0; i < amount; i++) { //@audit how if there is many snow to mint???
_safeMint(receiver, s_TokenCounter);
emit SnowmanMinted(receiver, s_TokenCounter);
s_TokenCounter++;
}
}

Risk

Likelihood:

  • Since token accumulation is a core part of the protocol’s airdrop design, high balances are expected and realistic to encounter this issue.

Impact:

  • High balance users (=8001 + snow ) are permanently unable to claim their NFTs due to out-of-gas limit reverts.

Proof of Concept

Attempting to mint a large number of NFTs (e.g., 8001+) leads to an out-of-gas revert due to block gas limits.
This becomes a denial-of-service vector for users with high Snow token balances, especially in the airdrop claim flow where mintSnowman() is called after tokens are transferred to the contract.

function testFindFailingMintAmount() public {
uint256 amount = 1;
while (true) {
try nft.mintSnowman(bob, amount) {
amount += 1000;
} catch {
console2.log("Failed at amount:", amount);
break;
}
}
}

Recommended Mitigation

Restrict the maximum number of NFTs that can be minted in a single call by adding a reasonable upper bound to the amount parameter in mintSnowman().

+ error ExceedsMaxMintLimit();
+ uint256 public constant MAX_MINT = 500; // adjust as needed
function mintSnowman(address receiver, uint256 amount) external {
+ if (amount > MAX_MINT) {
+ revert ExceedsMaxMintLimit();
+}
for (uint256 i = 0; i < amount; i++) {
_safeMint(receiver, s_TokenCounter);
emit SnowmanMinted(receiver, s_TokenCounter);
s_TokenCounter++;
}
}
Updates

Lead Judging Commences

yeahchibyke Lead Judge
3 months ago
yeahchibyke Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.