SNARKeling Treasure Hunt

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

M-02 Deployment Script Permits Underfunded Hunt Deployment

Description

The deployment script accepts INITIAL_FUNDING from the environment and forwards it directly into the TreasureHunt constructor without validating that the amount is sufficient to fund all intended rewards.

Because the script does not enforce INITIAL_FUNDING >= REWARD * MAX_TREASURES, it can successfully deploy a hunt that is structurally underfunded from the first block.

Risk

An underfunded deployment can create an unusable or partially unusable hunt:

  • valid claims may revert with NotEnoughFunds

  • the deployed contract may violate the project’s intended economic assumptions

  • operators may believe deployment succeeded while the hunt is not actually solvent

This is primarily a deployment safety and operational integrity issue.

Proof of Concept

The script reads arbitrary funding input here:

uint256 initialFunding = vm.envOr("INITIAL_FUNDING", DEFAULT_INITIAL_FUNDING);

and deploys the contract with that value here:

hunt = new TreasureHunt{value: initialFunding}(address(verifier));

The only post-deployment balance check is:

require(hunt.getContractBalance() == initialFunding, "UNEXPECTED_BALANCE");

That check confirms only that the transfer occurred, not that the amount is economically sufficient.

For example, if INITIAL_FUNDING=5 ether, deployment would still proceed even though the contract’s reward logic expects:

REWARD = 10 ether
MAX_TREASURES = 10

As a result, the first valid claim would already be at risk of reverting due to insufficient funds.

Recommended Mitigation

Validate funding before broadcasting and fail fast unless the deployment is fully funded.

diff --git a/contracts/scripts/Deploy.s.sol b/contracts/scripts/Deploy.s.sol
--- a/contracts/scripts/Deploy.s.sol
+++ b/contracts/scripts/Deploy.s.sol
@@ -44,6 +44,9 @@ contract Deploy is Script {
uint256 deployerKey = vm.envUint("PRIVATE_KEY");
uint256 initialFunding = vm.envOr("INITIAL_FUNDING", DEFAULT_INITIAL_FUNDING);
+
+ require(initialFunding >= TreasureHunt.REWARD() * TreasureHunt.MAX_TREASURES(), "INSUFFICIENT_INITIAL_FUNDING");
address deployer = vm.addr(deployerKey);
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!