SNARKeling Treasure Hunt

First Flight #59
Beginner FriendlyGameFiFoundry
100 EXP
View results
Submission Details
Severity: medium
Valid

Bypass of Intended flow -> Missing msg.value() check in constructor

Root + Impact

Description

  • The contract explicitly states that on deployment, the contract should be funded (line 74 )

  • It can be bypassed and deployed with no funds, potentially breaking the contract for time being for future users

constructor(address _verifier) payable {
if (_verifier == address(0)) revert InvalidVerifier();
//@> missing require statement here
owner = msg.sender;
verifier = IVerifier(_verifier);
paused = false;
// Owner should fund 100 ETH at deployment (10 treasures × 10 ETH).
}

Risk

Likelihood:

  • This may occur during deployment

  • Impact:

    ->At the very least, some of the users gas could get wasted, due to broken logic, because it will be missing requirements the contract is designed for.

Proof of Concept

I updated the source code, so that it could successfully compile, and be deployed without the need of missing files

pragma solidity ^0.8.27;
import {Test} from "../lib/forge-std/src/Test.sol";
import {console} from "../lib/forge-std/src/console.sol";
import {TreasureHunt} from "../src/TreasureHunt.sol";
contract DeploymentWithoutFunds is Test {
// contract owner
address owner = makeAddr("owner");
// contract
TreasureHunt contractObject;
function setUp() external {
// fund owner address
vm.deal(owner, 1005 wei);
}
function test_Deploy() external {
// try to deploy contract below 100 ether
contractObject = new TreasureHunt{value: 1000 wei}();
// read funds
console.log("funds of contract at:", contractObject.getContractBalance());
// check condition
assertLt(contractObject.getContractBalance(), 100 ether);
}
}

Recommended Mitigation

+ require(msg.value >= 100 ether)
Updates

Lead Judging Commences

s3mvl4d Lead Judge 18 days ago
Submission Judgement Published
Validated
Assigned finding tags:

liquidity enforcement issues

The liquidity-enforcement issue arises because the protocol assumes the hunt will be funded with enough ETH to cover all rewards, but the contract itself does not actively enforce that invariant at deployment time. The constructor accepts arbitrary `msg.value` and only validates the verifier address, even though the contract hardcodes a reward of 10 ether and a maximum of 10 treasures, implying an expected full funding target of 100 ether; the README likewise states that the contract is expected to be funded with enough ETH to cover all rewards and notes that the default deployment flow uses 100 ether. Although the deployment script sets `DEFAULT_INITIAL_FUNDING = 100 ether`, it also allows that amount to be overridden via `vm.envOr("INITIAL_FUNDING", DEFAULT_INITIAL_FUNDING)`, and the only post-deployment balance check is that the contract balance equals the chosen `initialFunding`, not that the chosen amount is actually sufficient to fund the full hunt. As a result, the system can be deployed in an underfunded state after which otherwise valid claims will begin reverting with `NotEnoughFunds()` once the balance drops below a single reward payment.

Support

FAQs

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

Give us feedback!