Snowman Merkle Airdrop

First Flight #42
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: low
Valid

Missing Claim Status Check Allows Repeated NFT Claims

Root + Impact

Description

  • Normally, each user is only allowed to claim the Snowman NFT once using a valid Merkle proof, ECDSA signature, and sufficient Snow token balance.

  • However, the claimSnowman function does not check whether the caller has already claimed. As a result, any eligible user can repeatedly invoke the function and mint multiple NFTs.

function claimSnowman(...) external nonReentrant {
if (receiver == address(0)) {
revert SA__ZeroAddress();
}
if (i_snow.balanceOf(receiver) == 0) {
revert SA__ZeroAmount();
}
if (!_isValidSignature(receiver, getMessageHash(receiver), v, r, s)) {
revert SA__InvalidSignature();
}
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();
}
// @> Missing check for s_hasClaimedSnowman[receiver]
i_snow.safeTransferFrom(receiver, address(this), amount);
s_hasClaimedSnowman[receiver] = true; // set after already processing logic
emit SnowmanClaimedSuccessfully(receiver, amount);
i_snowman.mintSnowman(receiver, amount);
}

Risk

Likelihood:

  • This will happen whenever an eligible user (with a correct proof and signature) repeatedly calls the claimSnowman function.

Impact:

  • A single user can mint unlimited Snowman NFTs by calling the function multiple times.

  • It could result in total airdrop over-distribution and damage project tokenomics and fairness.

Recommended Mitigation

Add the following check:

function claimSnowman(...) external nonReentrant {
+ if (s_hasClaimedSnowman[receiver]) {
+ revert AlreadyClaimed();
+ }
if (receiver == address(0)) {
revert SA__ZeroAddress();
}
if (i_snow.balanceOf(receiver) == 0) {
revert SA__ZeroAmount();
}
//.....
}

also define the custom error error AlreadyClaimed(); to match existing style.

Updates

Lead Judging Commences

yeahchibyke Lead Judge 4 days ago
Submission Judgement Published
Validated
Assigned finding tags:

Lack of claim check

The claim function of the Snowman Airdrop contract doesn't check that a recipient has already claimed a Snowman. This poses no significant risk as is as farming period must have been long concluded before snapshot, creation of merkle script, and finally claiming.

Support

FAQs

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