Snowman Merkle Airdrop

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

No Token Transfer to Airdrop Contract

Root + Impact

Description

  • For an airdrop to function, the airdrop contract must hold sufficient tokens to distribute to claimants.

    Users earn Snow tokens to their own addresses, but these tokens are never transferred to the SnowmanAirdrop contract, leaving it with zero balance to distribute.

// Root cause in the codebase with @> marks to highlight the relevant section
// Helper.sol
function helper() public returns (SnowmanAirdrop, Snow, Snowman, MockWETH) {
(airdrop, snow, nft) = deployer.deploySnowmanAirdrop();
vm.prank(alice);
snow.earnSnow(); // @> Tokens go to Alice's address
aliceSB = snow.balanceOf(alice);
// @> No transfer to airdrop contract - it has 0 balance!
}

Risk

Likelihood:

  • No code exists to transfer tokens to the airdrop contract

  • The helper function completes without funding the airdrop

Impact:

  • All claim transactions will revert due to insufficient balance

  • Airdrop is non-functional even with valid proofs

Proof of Concept

After running Helper.helper(), check snow.balanceOf(address(airdrop)) which equals 0 - when Alice attempts to claim her 1 token using valid proof from output.json, the transfer will fail because the airdrop contract has no tokens to distribute.

function testNoTokensInAirdrop() public {
Helper helper = new Helper();
(SnowmanAirdrop airdrop, Snow snow,,) = helper.helper();
// Check airdrop contract balance
uint256 airdropBalance = snow.balanceOf(address(airdrop));
assertEq(airdropBalance, 0); // Airdrop has no tokens to distribute!
// Total tokens that should be in airdrop
uint256 totalNeeded = helper.aliceSB() + helper.bobSB() + helper.claraSB()
+ helper.danSB() + helper.eliSB(); // = 5 tokens total
// Try to claim - will fail due to insufficient balance
bytes32[] memory proof = new bytes32[](3);
proof[0] = 0xf99782cec890699d4947528f9884acaca174602bb028a66d0870534acf241c52;
proof[1] = 0xbc5a8a0aad4a65155abf53bb707aa6d66b11b220ecb672f7832c05613dba82af;
proof[2] = 0x971653456742d62534a5d7594745c292dda6a75c69c43a6a6249523f26e0cac1;
vm.prank(alice);
vm.expectRevert(); // Fails: airdrop contract has 0 tokens
airdrop.claim(alice, 1, proof);
}

Recommended Mitigation

Calculate total airdrop amount (aliceSB + bobSB + claraSB + danSB + eliSB = 5 tokens) and mint/transfer tokens to the airdrop contract address before deployment completes.

- remove this code
+ add this code
// In Helper.sol
+ uint256 totalAirdrop = aliceSB + bobSB + claraSB + danSB + eliSB;
+ snow.transfer(address(airdrop), totalAirdrop); // or snow.mint(address(airdrop), totalAirdrop)
Updates

Lead Judging Commences

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