Snowman Merkle Airdrop

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

Merkle leaf hash generation mismatch renders airdrop system completely non-functional

Description:

The SnowMerkle script and SnowmanAirdrop contract use incompatible methods for generating Merkle tree leaf hashes, creating a critical incompatibility that prevents users from claiming their airdrop rewards.

In SnowMerkle.s.sol the leaf hash is generated using:

leafs[i] = keccak256(bytes.concat(keccak256(ltrim64(abi.encode(data)))));

Where data is a bytes32[] array containing the address (converted to bytes32) and amount.

However, in SnowmanAirdrop.sol the leaf hash is expected to be:

bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(receiver, amount))));

Where receiver and amount are directly encoded as address and uint256 types respectively.

The key differences are:

  1. SnowMerkle uses ltrim64() to remove array metadata, while SnowmanAirdrop does not

  2. SnowMerkle encodes a bytes32[] array, while SnowmanAirdrop encodes individual typed parameters

  3. The data structure and encoding methods are fundamentally different

Attack path:

  1. Protocol administrators run SnowMerkle script to generate Merkle proofs for airdrop participants

  2. Users attempt to claim their airdrop by calling claimSnowman() with the generated proof

  3. The MerkleProof.verify() function fails because the leaf hash computed in SnowmanAirdrop doesn't match any leaf in the Merkle tree

  4. Transaction reverts with SA__InvalidProof() error

  5. No user can successfully claim their airdrop, regardless of their eligibility

Impact:

The entire airdrop mechanism becomes non-functional

Users cannot claim their entitled Snowman NFTs despite having valid Snow token balances

Recommended Mitigation:

Align the leaf hash generation method in SnowMerkle.s.sol to match SnowmanAirdrop.sol

In SnowMerkle.s.sol:

function run() public {
// ...
- leafs[i] = keccak256(bytes.concat(keccak256(ltrim64(abi.encode(data)))));
+ address receiver = address(uint160(uint256(data[0])));
+ uint256 amount = uint256(data[1]);
+ leafs[i] = keccak256(bytes.concat(keccak256(abi.encode(receiver, amount))));
//...
}
Updates

Lead Judging Commences

yeahchibyke Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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