Snowman Merkle Airdrop

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

Incorrect `MESSAGE_TYPEHASH` Causes Signature Verification to Always Fail

Author Revealed upon completion

Root + Impact

Description

Expected Behavior

The contract should correctly verify EIP-712 signatures using the SnowmanClaim struct (with address and uint256 fields) via _hashTypedDataV4(...).

Actual Behavior

The developer mistakenly typed "addres" instead of "address" in the EIP-712 struct declaration:

bytes32 private constant MESSAGE_TYPEHASH = keccak256("SnowmanClaim(addres receiver, uint256 amount)");

This causes the struct hash to be incorrect. So the digest generated on-chain during _hashTypedDataV4(...) does not match the one signed off-chain, leading to invalid signature errors.

bytes32 private constant MESSAGE_TYPEHASH = keccak256("SnowmanClaim(@>addres<@ receiver, uint256 amount)");

Risk

Likelihood:

This will happen every time signature verification is attempted.

  • The bug is deterministic and does not depend on user input or external calls.

Impact:

  • Signature verification always fails.

  • Claims cannot be processed even if the user signs the correct data.

  • Core contract functionality is broken.

Proof of Concept

address receiver = 0x123...;
uint256 amount = 100;
// Off-chain signer signs: "SnowmanClaim(address receiver, uint256 amount)"
// On-chain code expects: "SnowmanClaim(addres receiver, uint256 amount)"
// => This hash mismatch causes all verifications to fail
(bool success, ) = address(snowmanAirdrop).call(
abi.encodeWithSignature("claimSnowman(address,bytes32[],uint8,bytes32,bytes32)",
receiver, proof, v, r, s)
);
// This will revert with SA__InvalidSignature

Recommended Mitigation

The "addres" should be chnage to "address"
- bytes32 private constant MESSAGE_TYPEHASH = keccak256("SnowmanClaim(addres receiver, uint256 amount)");
+ bytes32 private constant MESSAGE_TYPEHASH = keccak256("SnowmanClaim(address receiver, uint256 amount)");

Support

FAQs

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