Vanguard

First Flight #56
Beginner FriendlyDeFiFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

Deployment Script Uses Wrong Flags Causing Hook To Be Unusable

Deployment Script Uses Wrong Flags Causing Hook To Be Unusable

Description

Uniswap V4 hooks encode their required permissions as flags in the hook's contract address. The BaseHook constructor validates that the address flags match the permissions returned by getHookPermissions(). If they do not match, deployment reverts with HookAddressNotValid.

The deployment script uses BEFORE_INITIALIZE_FLAG but the hook's getHookPermissions() returns beforeInitialize: false and afterInitialize: true. This mismatch causes the hook deployment to always revert.

// script/deployLaunchHook.s.sol
function run() public {
// hook contracts must have specific flags encoded in the address
@> 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,
@> afterInitialize: true,
// ...
beforeSwap: true,
// ...
});
}

Risk

Likelihood: High

  • This occurs very time the deployment script is executed

  • The mismatch is hardcoded - there is no conditiona logic that could avoid it

Impact: High

  • The hook cannot be deployed using the provided deployment script

  • Any automated deployment pipelines using the script will fail

Proof Of Concept

The following test case provides a proof of concept

function test_flagMismatch() public {
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
);
uint160 correctFlags = uint160(Hooks.AFTER_INITIALIZE_FLAG | Hooks.BEFORE_SWAP_FLAG);
(address hookAddress, bytes32 salt) =
HookMiner.find(address(this), correctFlags, type(TokenLaunchHook).creationCode, constructorArgs);
uint160 scriptFlags = uint160(Hooks.BEFORE_SWAP_FLAG | Hooks.BEFORE_INITIALIZE_FLAG);
(address hookAddressWithScriptFlags, bytes32 saltWithScriptFlags) =
HookMiner.find(address(this), scriptFlags, type(TokenLaunchHook).creationCode, constructorArgs);
// Assert different address is produced
assertNotEq(hookAddress, hookAddressWithScriptFlags, "Hook addresses with different flags match");
// Try deployment with script's flags
vm.expectRevert();
TokenLaunchHook hook = new TokenLaunchHook{salt: saltWithScriptFlags}(
manager,
PHASE1_DURATION,
PHASE2_DURATION,
PHASE1_LIMIT_BPS,
PHASE2_LIMIT_BPS,
PHASE1_COOLDOWN,
PHASE2_COOLDOWN,
PHASE1_PENALTY_BPS,
PHASE2_PENALTY_BPS
);
}

Recommended Mitigation

A fix to deployment script should be made:

function run() public {
// hook contracts must have specific flags encoded in the address
- uint160 flags = uint160(Hooks.BEFORE_SWAP_FLAG | Hooks.BEFORE_INITIALIZE_FLAG);
+ uint160 flags = uint160(Hooks.BEFORE_SWAP_FLAG | Hooks.AFTER_INITIALIZE_FLAG);
Updates

Appeal created

chaossr Lead Judge 17 days ago
Submission Judgement Published
Validated
Assigned finding tags:

Deploy Script Uses Wrong Hook Flag

Support

FAQs

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

Give us feedback!