Uniswap V4 hooks are the most powerful primitive ever shipped in AMM design — and the most dangerous. One misconfigured hook can drain an entire pool in a single transaction, and with over $1B in TVL migrated from V3 within weeks of launch, there's a lot of money sitting behind code most people haven't audited.
I've gone through the V4 architecture, the PoolManager contract, and a stack of early hook implementations. The vulnerability surface isn't just new — it's fundamentally different from anything that came before.
How Hooks Change the V4 Security Model
Uniswap V4 moves all pools into a single singleton contract called PoolManager. Instead of deploying a new pair contract per token pair (V2/V3 style), every pool lives in one contract and is identified by a PoolKey struct. Lower gas, but a bug in one pool's hook now has implications for shared singleton state.
Hooks are external contracts that PoolManager calls at defined lifecycle points:
-
beforeInitialize/afterInitialize -
beforeAddLiquidity/afterAddLiquidity -
beforeRemoveLiquidity/afterRemoveLiquidity -
beforeSwap/afterSwap -
beforeDonate/afterDonate
The hook's address determines which callbacks it implements — encoded in the address via CREATE2 mining. Clever design. But it introduces a critical trust assumption: the hook is trusted by the pool unconditionally. PoolManager calls your hook contract and expects it to behave. There is no sandbox.
The Four Real Attack Vectors
Everyone focuses on reentrancy because it's the classic AMM boogeyman. Fair — but the real killers in V4 are subtler.
1. Hook-Level Reentrancy via Delta Accounting
V4 uses a flash accounting model — balances are tracked as deltas, settled by end of transaction. The lock mechanism in PoolManager is meant to prevent reentrant calls. But if your hook calls back into PoolManager through a different code path during a callback, you can manipulate intermediate state before deltas settle.
Reentrancy-adjacent vulnerabilities have drained over $2.3B from DeFi protocols since 2020 (Rekt News). V4's accounting model doesn't eliminate this class — it reshapes it.
2. Malicious Hooks as Backdoors
This one targets traders and LPs directly. If you're interacting with a V4 pool, you are implicitly trusting its hook. A malicious afterSwap hook can redirect funds, inflate prices, or call back into your wallet if approvals exist. Venom Protocol used exactly this social engineering pattern against NFT traders in 2022 — embedding malicious logic in what looked like a standard marketplace contract, draining $1.8M. V4 hooks create the same attack surface with a technical wrapper that looks legitimate.
3. Missing Access Control on Admin Functions
Access control failures account for 3x more total DeFi losses than reentrancy — and almost nobody builds their hook audit checklist around it. Most hook developers add admin functions for fee updates, oracle configs, or whitelist management. If those aren't properly gated, you've shipped a god-mode backdoor.
4. Price Oracle Manipulation Through Hook Logic
Hooks that read or write price data mid-swap create new TWAP manipulation surfaces. If your hook reads slot0 (spot price, not TWAP) during a beforeSwap callback — say, for a dynamic fee calculation — an attacker can sandwich that logic with a flash loan. Mango Markets lost $117M to oracle price manipulation. V4 hooks give attackers a new insertion point for the same playbook.
What a Vulnerable Hook Looks Like
Here's a realistic dynamic fee hook with two critical vulnerabilities. This pattern shows up constantly in early implementations.
// ❌ VULNERABLE PATTERN
contract VulnerableFeeHook is BaseHook {
uint24 public dynamicFee;
// ❌ No access control — anyone can call this
function setFee(uint24 newFee) external {
dynamicFee = newFee;
}
// ❌ Reads slot0 (spot price) — flash loan bait
function beforeSwap(
address,
PoolKey calldata key,
IPoolManager.SwapParams calldata params,
bytes calldata
) external override returns (bytes4, BeforeSwapDelta, uint24) {
(uint160 sqrtPriceX96,,,) = poolManager.getSlot0(key.toId());
uint24 fee = sqrtPriceX96 > 1e18 ? 500 : dynamicFee;
return (BaseHook.beforeSwap.selector, BeforeSwapDeltaLibrary.ZERO_DELTA, fee);
}
}
Two problems: setFee has zero access control — any wallet can set the fee to the maximum, bricking the pool or extracting value from traders. And reading slot0 in beforeSwap to drive fee logic means a flash loan attacker can manipulate that price in the same block.
The fix requires two changes: gate admin functions behind ownership, and replace spot price reads with TWAP data that can't be manipulated within a single block.
// ✅ SECURE PATTERN
contract SecureFeeHook is BaseHook, Ownable {
uint24 public dynamicFee;
// ✅ Only owner can update fee
function setFee(uint24 newFee) external onlyOwner {
require(newFee <= 100_000, "Fee too high");
dynamicFee = newFee;
emit FeeUpdated(newFee);
}
// ✅ Use TWAP — not spot price — for fee decisions
function beforeSwap(
address,
PoolKey calldata key,
IPoolManager.SwapParams calldata params,
bytes calldata
) external override returns (bytes4, BeforeSwapDelta, uint24) {
// Reference TWAP oracle instead of slot0
uint24 fee = _getTWAPBasedFee(key);
return (BaseHook.beforeSwap.selector, BeforeSwapDeltaLibrary.ZERO_DELTA, fee);
}
}
Pre-Deployment Checklist
Before you touch a V4 pool — as a developer or an LP — run through this:
-
Access control: Every admin function gated. No unprotected
setFee,setOracle, or whitelist functions -
Oracle source: TWAP over multiple blocks, never
slot0for decision logic - Reentrancy: Trace every external call inside hook callbacks; check for cross-function reentrance paths through the delta accounting system
- Hook trust model: If you're an LP or trader, verify the hook's source code is published and audited — the pool's safety is entirely dependent on it
-
Singleton implications: Understand that any hook interacting with shared
PoolManagerstate can have cross-pool effects - Delta settlement: Ensure all currency deltas are properly settled before transaction end; unsettled deltas are a vector for fund extraction
The V4 architecture is a genuine leap forward in AMM design. The hooks primitive enables things that simply weren't possible before — dynamic fees, custom order types, on-chain limit orders, protocol-owned liquidity management. But every one of
Top comments (0)