Vanguard

First Flight #56
Beginner FriendlyDeFiFoundry
0 EXP
Submission Details
Impact: medium
Likelihood: high

Deployment script mines for incorrect Hook Flags, causing total protocol initialization failure

Author Revealed upon completion

Description

  • Normal Behavior: For a Uniswap V4 pool to be initialized successfully, the hook's address flags (derived from its CREATE2 address prefix) must exactly match the permissions reported by the hook contract's getHookPermissions() function. This is a core security invariant enforced by the PoolManager.

  • Specific Issue: The DeployHookScript.s.sol script mines for a salt that produces an address with the BEFORE_INITIALIZE_FLAG. However, the TokenLaunchHook contract reports beforeInitialize: false and instead implements afterInitialize. This binary mismatch causes an immediate revert during pool creation.

// script/deployLaunchHook.s.sol
function run() public {
// @> Root Cause: Script mines for BEFORE_INITIALIZE
uint160 flags = uint160(Hooks.BEFORE_SWAP_FLAG | Hooks.BEFORE_INITIALIZE_FLAG);
// ...
}
// src/TokenLaunchHook.sol
function getHookPermissions() public pure override returns (Hooks.Permissions memory) {
return Hooks.Permissions({
beforeInitialize: false, // @> Root Cause: Contract does not support BEFORE_INITIALIZE
afterInitialize: true, // @> Contract intends to use AFTER_INITIALIZE
// ...
});
}

Risk

Likelihood:

  • 100% Certainty: This occurs every time the protocol is deployed using the provided official deployment script. The mismatch is hardcoded into the setup logic.

Impact:

  • Critical Launch Blocker: The PoolManager will revert whenever the owner tries to initialize the pool. Because the address flag says "I must be called before initialize" but the contract code says "I do not support being called before initialize," the protocol is rendered un-deployable and non-functional.

Proof of Concept

The Proof of Concept is verified through a technical comparison between the mined address flags and the contract metadata check performed by the Uniswap V4 Hooks library.

1. Reproduction Steps

  1. Locate line 28 in script/deployLaunchHook.s.sol. Note that bit 1 (BEFORE_INITIALIZE) is included in the mining mask.

  2. Locate line 96 in src/TokenLaunchHook.sol. Note that beforeInitialize is returned as false.

  3. Attempting to initialize a pool with the resulting address will trigger a revert in the PoolManager.

2. Technical Validation Logic (PoolManager Failure)

The following pseudocode represents the internal check in the PoolManager (via Hooks.sol) that verifies the mismatch:

// Logic inside Hooks.validateHookPermissions(...)
// @> 1. hookAddress.shouldCallBeforeInitialize() returns TRUE because of the script flags
// @> 2. permissions.beforeInitialize returns FALSE because of the contract bytecode
if (hookAddress.shouldCallBeforeInitialize() && !permissions.beforeInitialize) {
// @> This condition is met, causing the protocol to fail initialization
revert HookAddressAndMissingPermission(hookAddress);
}

Recommended Mitigation

Update the deployment script to mine for the AFTER_INITIALIZE_FLAG instead of BEFORE_INITIALIZE_FLAG.

- uint160 flags = uint160(Hooks.BEFORE_SWAP_FLAG | Hooks.BEFORE_INITIALIZE_FLAG);
+ uint160 flags = uint160(Hooks.BEFORE_SWAP_FLAG | Hooks.AFTER_INITIALIZE_FLAG);

Support

FAQs

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

Give us feedback!