Location: contracts/src/TreasureHunt.sol:35, 83, 88, 104
The TreasureHunt.claim function is supposed to stop a user from claiming the same treasure twice, but the duplicate check reads the wrong storage key. It reads claimed[_treasureHash], where _treasureHash is an immutable that is never assigned in the constructor, so its value is always the type default bytes32(0).
Every call reads claimed[bytes32(0)], which is always false. The "already claimed" guard never triggers. Meanwhile, _markClaimed(treasureHash) correctly writes the real hash into the mapping, but that slot is never consulted during claim.
Likelihood: High. Anyone with a single valid proof (i.e. any treasure finder) can trigger this. There is no edge case, no race condition, no precondition beyond having one valid claim tuple.
Impact: High . A participant with one valid proof can call claim up to MAX_TREASURES = 10 times with the same (proof, treasureHash, recipient). Each call sends REWARD = 10 ether to the recipient. One valid proof therefore drains the full 100 ETH prize pool to a single address. The rest of the finders get nothing.
Put the following test :
Run:
Expected output:
Use the function parameter treasureHash in the duplicate check. Delete the unused _treasureHash immutable.
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.