Normally, users are expected to sign an EIP-712 message containing their address and the amount of Snow
tokens they hold, then call claimSnowman()
to verify their signature and claim their Snowman NFT. The contract uses the getMessageHash()
function to compute the digest for signature validation using the caller's current token balance.
Normally, users are expected to sign an EIP-712 message containing their address and the amount of Snow
tokens they hold, then call claimSnowman()
to verify their signature and claim their Snowman NFT. The contract uses the getMessageHash()
function to compute the digest for signature validation using the caller's current token balance.
Likelihood: Medium
Very likely to occur in production where user balances fluctuate due to regular transfers or protocol activity.
Especially problematic if users pre-sign messages and claim later via scripts, UIs, or relayers.
Impact: Medium
Users will be unable to claim their airdrop despite having a valid Merkle proof and valid signature at time of signing.
Results in failed claims, poor UX, and loss of trust in the airdrop process.
This PoC simulates a real-world failure scenario. Alice signs a message when she has 1,000 SNOW tokens. After signing, she transfers 500 tokens to another user. When she later attempts to claim using her signature, the contract recalculates her current balance (now 500) and uses it in getMessageHash()
, producing a different digest than what she signed. As a result, the ECDSA verification fails and the claim is rejected
The root cause of the issue is that getMessageHash(address)
uses the user's current SNOW
balance to compute the EIP-712 digest. However, signatures are typically created off-chain using static values. If a user's balance changes between signing and claiming, the digest will mismatch, causing signature verification to fail.
To fix this, make the amount
part of the input to claimSnowman()
and use this static value when computing the message hash. This ensures the digest used for verification matches what the user actually signed.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.