SNARKeling Treasure Hunt

First Flight #59
Beginner FriendlyGameFiFoundry
100 EXP
Submission Details
Impact: high
Likelihood: high

Title Uninitialized immutable variable _treasureHash causes compilation failure or broken logic

Author Revealed upon completion

Root + Impact

Description

  • Normal Behavior: Variables declared with the immutable keyword in Solidity must be explicitly initialized exactly once. This initialization must occur either at the time of their declaration or within the constructor of the contract. This ensures the value is hardcoded into the contract's deployed bytecode, optimizing gas costs.

  • Specific Issue: The _treasureHash variable is declared as immutable at the state level but is completely omitted from the constructor logic. The developer intended to use the treasureHash passed as a parameter in the claim function, but mistakenly referenced the uninitialized state variable _treasureHash in the claimed mapping check. In Solidity versions 0.8.21 and above, failing to initialize an immutable variable results in a strict compiler error (TypeError: Immutable variable has not been initialized). If deployed using a misconfigured environment that ignores this, the variable defaults to bytes32(0), which permanently breaks the core verification logic within the claim function, as every user will unknowingly check the claim status of the zero hash instead of their actual treasure hash.

bytes32 private immutable _treasureHash;
constructor(address _verifier) payable {
if (_verifier == address(0)) revert InvalidVerifier();
owner = msg.sender;
verifier = IVerifier(_verifier);
paused = false;
// @> Root cause: _treasureHash is declared as immutable but never initialized.
}

Risk

Likelihood:

  • This will occur 100% of the time upon attempting to compile the contract with a standard modern Solidity compiler.

Impact:

  • Complete failure to deploy the smart contract due to compilation errors.

  • If bypassed, the claim function will validate claimed[bytes32(0)] instead of the actual treasure hash, permanently bricking the game logic and locking user rewards.

Proof of Concept

The following steps demonstrate the failure:

  1. Setup a standard Foundry or Hardhat environment using solc version ^0.8.27.

  2. Attempt to compile TreasureHunt.sol using forge build or npx hardhat compile.

  3. The compiler strictly halts the process and throws the following error, preventing deployment:

// Compilation output proving the failure:
TypeError: Immutable variable "_treasureHash" has not been initialized.
--> src/TreasureHunt.sol:24:5:
|
24 | bytes32 private immutable _treasureHash;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Recommended Mitigation

Explanation of the fix: The state variable _treasureHash is entirely unnecessary for the contract's logic. The claim function receives the specific treasureHash directly as a parameter from the user. The mitigation removes the unused state variable and corrects the typo in the claim function to use the provided parameter.

- bytes32 private immutable _treasureHash;
function claim(bytes calldata proof, bytes32 treasureHash, address payable recipient) external nonReentrant() {
if (paused) revert ContractPaused();
if (address(this).balance < REWARD) revert NotEnoughFunds();
if (recipient == address(0) || recipient == address(this) || recipient == owner || recipient == msg.sender) revert InvalidRecipient();
if (claimsCount >= MAX_TREASURES) revert AllTreasuresClaimed();
- if (claimed[_treasureHash]) revert AlreadyClaimed(treasureHash);
+ if (claimed[treasureHash]) revert AlreadyClaimed(treasureHash);

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!