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?)
↓
resultDynamic 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.)