A successful claim sets s_hasClaimedSnowman[receiver] = true, but that mapping is never read inside claimSnowman to block a repeat claim; it is only exposed through the getClaimStatus getter. Separately, the signed EIP-712 message commits only to (receiver, amount) with no nonce and no deadline, and the signature is never consumed on use. So a single signature stays valid and can be replayed to mint again whenever the receiver holds the committed amount.
Today a same-state double claim is blocked only incidentally, because the full balance is transferred out. Once M-01 is fixed to transfer a fixed amount, that side effect disappears and any receiver who re-acquires the committed amount can replay the same signature; the message has no nonce or deadline, so a captured signature never expires.
Impact: The one-claim-per-eligible-entry invariant is not enforced, allowing repeated mints and Snowman supply inflation. A leaked or replayed signature drives additional mints without fresh consent from the receiver.
Self-contained Foundry test. A single-leaf tree commits alice to a snapshot amount of 1. Alice signs one claim; it is then replayed after she re-acquires the committed amount, minting a second NFT from the same signature. This proves both defects at once: the claim guard is never checked, and the signature has no nonce so its digest is unchanged.
Result: [PASS] testOneSignatureMintsTwice().
Enforce the existing claim guard at the start of claimSnowman, and add a per-account nonce and a deadline to the signed message so each authorization can be used only once and only before it expires. Extend SnowmanClaim and MESSAGE_TYPEHASH with uint256 nonce and uint256 deadline, include them in the digest, and increment the nonce on each successful claim.
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.