Impact: One reward slot is permanently unclaimable, locking 10 ETH in the contract with no recovery path
Description
Only 9 unique treasures exist. MAX_TREASURES = 10 and REWARD = 10 ether, so the contract is funded with 100 ETH expecting 10 claimable treasures. The duplicate means only 9 can ever be claimed (or the same hash is claimed once and the duplicate slot is wasted).
The last two entries in ALLOWED_TREASURE_HASHES in main.nr are identical:
-961435057317293580094826482786572873533235701183329831124091847635547871092,
-961435057317293580094826482786572873533235701183329831124091847635547871092
Risk
Likelihood:
The duplicate exists at deployment, the 10th reward slot is unreachable from the moment the contract goes live with no action required by any party
The withdraw() function requires claimsCount >= MAX_TREASURES , with only 9 unique treasures this condition cannot be met through normal play, permanently blocking owner fund recovery too
Impact:
Proof of Concept
1. Contract deployed with ALLOWED_TREASURE_HASHES indices [0..9]
2. Indices 8 and 9 share the same hash value
3. Participant claims index 8 — claimsCount = 1, claimed[hash] = true
4. No participant can claim index 9 (same hash, already marked claimed)
5. Maximum claimsCount reachable through unique treasures = 9
6. 10 ETH sits in the contract permanently unreachable
7. withdraw() requires claimsCount >= 10, condition never met legitimately
Recommended Mitigation
global ALLOWED_TREASURE_HASHES: [Field; 10] = [
1505662313093145631275418581390771847921541863527840230091007112166041775502,
-7876059170207639417138377068663245559360606207000570753582208706879316183353,
-5602859741022561807370900516277986970516538128871954257532197637239594541050,
2256689276847399345359792277406644462014723416398290212952821205940959307205,
10311210168613568792124008431580767227982446451742366771285792060556636004770,
-5697637861416433807484703347699404695743570043365849280798663758395067508,
-2009295789879562882359281321158573810642695913475210803991480097462832104806,
8931814952839857299896840311953754931787080333405300398787637512717059406908,
-961435057317293580094826482786572873533235701183329831124091847635547871092,
+ <unique_10th_treasure_hash> // @> replace with a unique hash derived from a unique secret
];