ARTICLESX
Feb 2, 2025#TECH· 14 min

Uniswap v4 ships — pools become programmable

One singleton PoolManager + hooks: arbitrary logic at every swap, mint and burn. Dynamic fees, onchain oracles, MEV capture — a whole design space opened overnight.

v3 was a fixed AMM: concentrated liquidity, a handful of fee tiers, one contract per pool. v4 keeps concentrated liquidity but changes the *architecture* in two ways that matter enormously: a singleton and hooks.

One contract to hold them all

Every v4 pool lives inside a single PoolManager contract. Creating a pool is a state entry, not a deploy. Combined with flash accounting (balances net out within one unlock callback, settle once at the end), multi-hop swaps stop paying for token transfers at every step. Cheaper, and composable.

Hooks: logic at the lifecycle points

A pool can attach a hook — a contract the PoolManager calls at lifecycle points: before/after initialize, add/remove liquidity, swap, donate. That's where the design space explodes.

swap() ─→ PoolManager
            │  beforeSwap()  ─→ hook  (override fee? gate? custom curve?)
            │  ── core swap math ──
            │  afterSwap()   ─→ hook  (oracle write? skim a fee?)
            ↓
        result
A swap passing through a hook

Dynamic fees that react to volatility, an onchain TWAP oracle baked into the pool, KYC'd pools, anti-snipe launches, MEV capture — all ~100 lines bolted onto a pool instead of a whole protocol.

The address gotcha

Flash accounting, briefly

The singleton pairs with flash accounting: inside one unlock callback you can run many operations, and the PoolManager only tracks the *net* balance you owe or are owed, settling once at the end. A multi-hop swap that used to transfer tokens at every pool now nets to a single settlement — big gas savings and clean composition.

Hooks cut both ways

The same power that lets a hook add a TWAP oracle or a dynamic fee also lets a malicious or buggy hook block your withdrawal, skim more than advertised, or revert at the worst moment. A pool is only as trustworthy as its hook — which is the whole reason I built tooling around *reading* a hook before you ever provide liquidity to it.

  • beforeSwap — gate, re-price, or run a custom curve before the trade.
  • afterSwap — write an oracle, skim a fee, settle a delta.
  • before/afterAddLiquidity — enforce ranges, allowlists, anti-snipe rules.
  • Permissions are public (encoded in the address) — so they're auditable, if you know to look.

A hook's enabled callbacks are encoded in the low 14 bits of its address, so you can't deploy it just anywhere — you mine a CREATE2 salt for an address with the right bits. (I went deep here: a hooks kit, a permission inspector, and a hook simulator — all on this site.)