v4-hook-permission-flags-mismatchlisted
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