V4 Hooks Architecture
Uniswap V4 introduces hook contracts — permissionless plugins that execute custom logic at every step of a swap lifecycle. Hooks can modify swap behavior, implement limit orders, charge dynamic fees, or create entirely new AMM primitives without changing the core pool contract.
🔄 Hook Lifecycle — Execution Order
Every V4 swap passes through a deterministic sequence of hook callbacks. The diagram below shows which hooks fire and in what order for a complete swap cycle.
🎣 Hook Type 1: Limit Order Hook
A limit order hook listens for beforeSwap and only allows the swap if the price is
at or beyond a specified boundary. The afterSwap callback is where the actual
fill is recorded and the order is updated.
🌊 Hook Type 2: TWAMM (Time-Weighted AMM)
TWAMM amortizes large orders over time as a series of micro-swaps. The hook intercepts
beforeSwap to record the order, then afterSwap to execute the
time-fraction and accumulate the result.
🌐 Hook Type 3: Dutch Auction Hook
A Dutch auction hook starts with a high price and decreases it linearly over time. Used for
ICOs, token sales, or protocol treasury liquidation. The getFee callback
dynamically returns the current auction price.
🔗 Hook Type 4: Dynamic Fee Hook
Rather than a static fee tier, the getFee hook can implement any fee-setting
logic: volatility-based fees, momentum fees, cross-asset fees, or governance-controlled fees.
The fee is computed per-swap, not per-pool.
🧩 Interactive: Build a Custom Hook
Toggle different hook capabilities to see how the pool behavior changes. Each toggle enables or disables a specific callback behavior:
How V4 singleton architecture works
V3 uses a separate contract for each pool (deploy per pair, deploy per fee tier). V4 uses a single PoolManager contract that holds all pools, with pool identity determined by the PoolKey tuple (token0, token1, fee, tickSpacing, hooks). The hook address is part of the PoolKey and is baked into the pool's CREATE2 address — once deployed, the hook for a pool can never be changed, which protects LPs from rug-pull fee changes.
Because all pools share one contract, cross-pool operations like multi-hop swaps in a single transaction become gas-cheaper and simpler to coordinate. The native ETH token is used for gas instead of separate Wrapped ETH deposits, further reducing overhead. Anyone can deploy a new hook contract and create a pool referencing that hook — V4 permissionlessly extends the AMM without Uniswap Labs' involvement.
Key concepts
- PoolKey
- A struct encoding (token0, token1, fee, tickSpacing, hooks). The hook address is a parameter in the PoolKey, so the pool's CREATE2 address is a function of the hook — once deployed, the hook cannot be swapped out, protecting LPs from post-deployment hook changes.
- Hook permissions bitmap
- A 248-bit bitmap in the hook contract that declares which callback functions the hook implements. The PoolManager checks this bitmap before calling any hook to avoid unnecessary calls. A hook can implement any subset of the 7 callbacks.
- beforeSwap / afterSwap
- Called immediately before and after the core swap math (x·y=k with dynamic fee from getFee). beforeSwap can revert the swap or modify swap parameters; afterSwap can record the result, update state, or emit custom events.
- getFee
- The most powerful hook primitive. Called inside the swap math and expected to return a fee numerator — not a basis-point amount but a fraction of the input. A hook returning 300 = 0.03% (matching the 0.30% tier) is equivalent to the standard pool fee, but arbitrary values like 150 (0.015%) or 500 (0.05%) can be returned based on any on-chain logic.
- CREATE2 and hook immutability
- V4 pools are deployed using CREATE2 with a salt derived from the PoolKey, so anyone can compute a pool's address before it exists. The hook address in the PoolKey means that a malicious operator cannot deploy a pool with a legitimate-looking hook address — LPs can verify pool authenticity by checking the CREATE2 address independently.
- Flash accounting
- V4 nets all token transfers in a transaction using internal balance accounting instead of actual ERC-20 transfers per pool. This means a multi-hop swap through ETH/USDC → USDC/DAI routes efficiently without multiple token transfer events, dramatically reducing gas for complex routing.