Snowman Merkle Airdrop

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

[L-2] `SnowmanAirdrop::claimSnowman` forces users to spend their entire Snow balance on identical NFTs, penalizing higher balances

Description

The SnowmanAirdrop::claimSnowman function reads the receiver's full Snow balance and uses it as both the transfer amount and the number of NFTs to mint. Users cannot choose how many Snow tokens to spend — they are forced to spend all of them.

uint256 amount = i_snow.balanceOf(receiver); // @> takes entire balance
// ...
i_snow.safeTransferFrom(receiver, address(this), amount); // @> transfers all Snow
// ...
i_snowman.mintSnowman(receiver, amount); // @> mints `amount` identical NFTs

Risk

Likelihood:

  • Every user who holds more than 1 Snow token at claim time is affected

  • Users cannot reduce their balance before claiming without invalidating their merkle proof and signature

Impact:

  • A user with 10 Snow pays 10x more than a user with 1 Snow for functionally identical NFTs

  • Users lose all their Snow tokens with no way to partially claim

Proof of Concept

Recommended Mitigation

- function claimSnowman(address receiver, bytes32[] calldata merkleProof, uint8 v, bytes32 r, bytes32 s)
+ function claimSnowman(address receiver, uint256 amount, bytes32[] calldata merkleProof, uint8 v, bytes32 r, bytes32 s)
external
nonReentrant
{
- uint256 amount = i_snow.balanceOf(receiver);
bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(receiver, amount))));
if (!MerkleProof.verify(merkleProof, i_merkleRoot, leaf)) {
revert SA__InvalidProof();
}
i_snow.safeTransferFrom(receiver, address(this), amount);
- i_snowman.mintSnowman(receiver, amount);
+ i_snowman.mintSnowman(receiver, 1);
// ...
}
Updates

Lead Judging Commences

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