SNARKeling Treasure Hunt

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

Nine custom errors defined but never thrown — contract uses costly require strings instead

Author Revealed upon completion

Root + Impact

Description

  • The contract defines 9 custom errors at the top but never uses them. All admin functions use require() with string literals instead. Custom errors are significantly cheaper than string reverts because strings are stored and returned as ABI-encoded data while custom errors use only a 4-byte selector. The errors are already written — they are simply never called.

// @> defined but never thrown
error HuntNotOver();
error NoFundsToWithdraw();
error OnlyOwnerCanFund();
error OnlyOwnerCanPause();
error OnlyOwnerCanUnpause();
error OwnerCannotBeRecipient();
error TheContractMustBePaused();
error OnlyOwnerCanUpdateVerifier();
error OnlyOwnerCanEmergencyWithdraw();
error InvalidAmount();
// @> expensive string literals used instead throughout
function withdraw() external {
require(claimsCount >= MAX_TREASURES, "HUNT_NOT_OVER");
require(balance > 0, "NO_FUNDS_TO_WITHDRAW");
}
function fund() external payable {
require(msg.sender == owner, "ONLY_OWNER_CAN_FUND");
}

Risk

Impact:

  • ~50 gas wasted per revert across all admin functions.

  • Dead code bloat — 9 errors declared and never referenced.

  • Inconsistent style — claim() and constructor use revert CustomError() correctly, admin functions do not.


Recommended Mitigation

function withdraw() external {
- require(claimsCount >= MAX_TREASURES, "HUNT_NOT_OVER");
+ if (claimsCount < MAX_TREASURES) revert HuntNotOver();
- require(balance > 0, "NO_FUNDS_TO_WITHDRAW");
+ if (balance == 0) revert NoFundsToWithdraw();
}
function fund() external payable {
- require(msg.sender == owner, "ONLY_OWNER_CAN_FUND");
+ if (msg.sender != owner) revert OnlyOwnerCanFund();
}

Support

FAQs

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

Give us feedback!