claimSnowman sets s_hasClaimedSnowman but never checks it, and the signature has no nonce or deadline, so one valid proof + signature can be replayed for repeated claims.
claimSnowman sets s_hasClaimedSnowman[receiver] = true but never reads the flag. The EIP-712 signature binds only (receiver, amount) — no nonce and no deadline.
Likelihood: Medium
Impact: After a successful claim, a user can re-acquire the exact same Snow balance (earn/buy/transfer back) and call claimSnowman again with the identical Merkle proof and signature to mint another batch of Snowman NFTs. This can be repeated to drain the intended 1-claim-per-user design.
User U claims successfully with proof + signature for (U, A); s_hasClaimedSnowman[U] becomes true but is never enforced.
U re-acquires exactly A Snow (earn/buy/transfer).
U calls claimSnowman again with the SAME proof and SAME signature.
The call succeeds and mints a second batch of Snowman NFTs; repeatable indefinitely.
Add require(!s_hasClaimedSnowman[receiver]) at the start of claimSnowman, and include a nonce/deadline in the signed digest as defense in depth.
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.