Vanguard

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

Deployment script mines wrong hook flags and blocks deployment

Author Revealed upon completion

Root + Impact

Root Cause: The deployment script mines an address with BEFORE_INITIALIZE_FLAG, while the hook declares afterInitialize: true and beforeInitialize: false. The mismatch triggers Hooks.validateHookPermissions and reverts in the constructor.
Impact: The hook contract cannot be deployed using the provided script, preventing protocol setup and pool initialization.

Description

  • The normal behavior is to mine a hook address whose flags exactly match the permissions returned by getHookPermissions.

  • The script uses BEFORE_INITIALIZE_FLAG, but the hook only implements afterInitialize, so the constructor validation reverts and deployment fails.

// script/deployLaunchHook.s.sol
uint160 flags = uint160(Hooks.BEFORE_SWAP_FLAG | Hooks.BEFORE_INITIALIZE_FLAG); // @> wrong flag
// src/TokenLaunchHook.sol
return Hooks.Permissions({
beforeInitialize: false, // @> does not match BEFORE_INITIALIZE_FLAG
afterInitialize: true, // @> required by the hook
// ...
});

Risk

Likelihood:

  • Occurs on every deployment that uses the current script.

Impact:

  • Deployment fails and the hook is never created, blocking protocol setup.

vulnerability Path

Steps:

  1. Operator runs forge script script/deployLaunchHook.s.sol.

  2. The script mines a hook address with BEFORE_INITIALIZE_FLAG.

  3. The hook constructor validates permissions against address flags.

  4. Validation fails due to flag mismatch.

  5. The constructor reverts with HookAddressNotValid.

  6. Deployment is aborted and the hook is not created.

Proof of Concept

PoC demonstrates constructor failure when using the script’s flags.

// test/PoC_Finding1_DeploymentFlag_Improved.t.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {Test} from "forge-std/Test.sol";
import {TokenLaunchHook} from "../src/TokenLaunchHook.sol";
import {Deployers} from "@uniswap/v4-core/test/utils/Deployers.sol";
import {Hooks} from "v4-core/libraries/Hooks.sol";
import {HookMiner} from "v4-periphery/src/utils/HookMiner.sol";
contract PoC_Finding1_DeploymentFlag_Improved is Test, Deployers {
uint256 constant PHASE1_DURATION = 100;
uint256 constant PHASE2_DURATION = 200;
uint256 constant PHASE1_LIMIT_BPS = 100;
uint256 constant PHASE2_LIMIT_BPS = 300;
uint256 constant PHASE1_COOLDOWN = 5;
uint256 constant PHASE2_COOLDOWN = 3;
uint256 constant PHASE1_PENALTY_BPS = 500;
uint256 constant PHASE2_PENALTY_BPS = 200;
function setUp() public {
// Deploy a fresh pool manager and routers for this test environment
deployFreshManagerAndRouters();
}
function test_DeploymentFailsWithMismatchedFlags() public {
// Prepare creation code and constructor args to match the deployment script
bytes memory creationCode = type(TokenLaunchHook).creationCode;
bytes memory constructorArgs = abi.encode(
manager,
PHASE1_DURATION,
PHASE2_DURATION,
PHASE1_LIMIT_BPS,
PHASE2_LIMIT_BPS,
PHASE1_COOLDOWN,
PHASE2_COOLDOWN,
PHASE1_PENALTY_BPS,
PHASE2_PENALTY_BPS
);
// Mine an address with BEFORE_INITIALIZE instead of AFTER_INITIALIZE (wrong for this hook)
uint160 flags = uint160(Hooks.BEFORE_SWAP_FLAG | Hooks.BEFORE_INITIALIZE_FLAG);
(address hookAddress, bytes32 salt) = HookMiner.find(address(this), flags, creationCode, constructorArgs);
// Deployment must revert in the constructor due to invalid hook address flags
vm.expectRevert(abi.encodeWithSelector(Hooks.HookAddressNotValid.selector, hookAddress));
new TokenLaunchHook{salt: salt}(
manager,
PHASE1_DURATION,
PHASE2_DURATION,
PHASE1_LIMIT_BPS,
PHASE2_LIMIT_BPS,
PHASE1_COOLDOWN,
PHASE2_COOLDOWN,
PHASE1_PENALTY_BPS,
PHASE2_PENALTY_BPS
);
}
}

Test Result

forge test --match-path test/PoC_Finding1_DeploymentFlag_Improved.t.sol -vv
Ran 1 test for test/PoC_Finding1_DeploymentFlag_Improved.t.sol:PoC_Finding1_DeploymentFlag_Improved
[PASS] test_DeploymentFailsWithMismatchedFlags() (gas: 4555555)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 63.47ms (60.99ms CPU time)

Recommended Mitigation

Update script/deployLaunchHook.s.sol to use the correct flags that match the contract's permissions.

- 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!