Snowman Merkle Airdrop

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

Gas Limit DoS via Unbounded Minting

Root + Impact

The claimSnowman() function allows minting a Snowman NFT for every 1e18 fraction of Snow tokens held, creating a critical vulnerability.

Description

Users with even tiny Snow balances (0.0000000001 tokens) may be able to trigger NFT minting. However, the linear minting loop (i_snowman.mintSnowman()) will exceed block gas limits for slightly bigger holdings. Legitimate claims become impossible due to transaction reverts, and the contract effectively bricks itself as claims pile up.

No Thresholds will enable dust amounts (1 wei) to mint

Each _mint costs ~50k gas → 100 tokens would require 5M gas (exceeding limits)

function mintSnowman(address receiver, uint256 amount) external {
@> for (uint256 i = 0; i < amount; i++) {
_safeMint(receiver, s_TokenCounter);
emit SnowmanMinted(receiver, s_TokenCounter);
s_TokenCounter++;
}
}

Risk

Likelihood: HIGH

  • It will happen at any moment for users who have any amount over 1e5.

  • The MerkleTree validation blocks users from claiming in smaller amounts

Impact: HIGH

  • Users will be blocked from claiming Snowmans

Proof of Concept

Recommended Mitigation

Implement a minting threshold. For example:

function snowToNFT(uint256 snowAmount) public pure returns (uint256) {
if (snowAmount >= 100e18) return 10; // 100 tokens → 10 NFTs
if (snowAmount >= 10e18) return 5; // 10 tokens → 5 NFTs
if (snowAmount >= 1e18) return 1; // 1 token → 1 NFT
revert("SA__MinimumNotMet");
}
function claimSnowman(address receiver, bytes32[] calldata merkleProof, uint8 v, bytes32 r, bytes32 s)
external
nonReentrant
{
{...snipet}
+ uint256 nftCount = snowToNFT(amount);
+ i_snowman.mintSnowman(receiver, nftCount);
{...snipet}
Updates

Lead Judging Commences

yeahchibyke Lead Judge 11 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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