← ClaudeAtlas

v4-hook-permission-flags-mismatchlisted

Detect Uniswap V4 hooks whose address-encoded permission flags don't match the callbacks the hook actually implements. In V4 the hook's permissions live in the low bits of its deployed address (mined via CREATE2 salt) and must agree with getHookPermissions(); a callback the hook implements but whose flag bit is unset is never invoked, and a flag set without a real implementation makes pool initialization revert in Hooks.validateHookPermissions. Activate on any BaseHook/IHooks contract, getHookPermissions overrides, or hook address mining.
iktok90-design/ai-smart-contract-auditor · ★ 36 · AI & Automation · score 80
Install: claude install-skill iktok90-design/ai-smart-contract-auditor
# Uniswap V4 hook permission-flag mismatch detection ## When this applies Trigger on any of: - Contracts inheriting `BaseHook` / implementing `IHooks` - An overridden `getHookPermissions()` returning a `Hooks.Permissions` struct - Implemented callbacks: `beforeSwap`, `afterSwap`, `beforeAddLiquidity`, `afterAddLiquidity`, `beforeRemoveLiquidity`, `afterRemoveLiquidity`, `beforeInitialize`, `afterInitialize`, `beforeDonate`, `afterDonate` - `*ReturnDelta` permission flags (`afterSwapReturnDelta`, `beforeSwapReturnDelta`, etc.) - CREATE2 / `HookMiner.find` salt mining to encode flags into the hook address - Pool initialization that passes the hook address to `PoolManager.initialize` ## Detection patterns ### Implemented callback whose flag bit is unset (HIGH) ```solidity function getHookPermissions() public pure override returns (Hooks.Permissions memory) { return Hooks.Permissions({ beforeSwap: true, afterSwap: false, /* ...all else false */ }); } function afterSwap(...) external override returns (bytes4, int128) { _accrueFees(...); // ← real logic, but afterSwap flag is FALSE return (this.afterSwap.selector, 0); } ``` The pool reads permissions from the hook *address bits*, not from the function table. With the `AFTER_SWAP` bit unset, the PoolManager never calls `afterSwap`; `_accrueFees` silently never runs. **Signal:** a callback is implemented (non-reverting body) but its corresponding permission is `false` / the address bit is unmined. ### Flag