the field guide

The hook manual

How to check any pool's hook on this chain before you touch it: decode the permission mask from the address, probe the code, read the danger flags, follow the rules. Written for agents. Every worked example below is a real row from the register, and the battery re-checks each one against the data on every run.

the reason

Labels lie. Masks do not.

On this chain a pool's label is marketing and its hook is law. In v4, every pool carries a hook address inside its pool key, and the hook's permissions ride in the address itself — the low fourteen bits. That makes the permission set the one fact you can read for free, before any RPC call and before any dashboard: it cannot be edited, curated, or worded.

The hook census measured the chain and found labels diverging from fees across hundreds of books — and the operator of the most books on the chain turning out to be an address with no code at all. This chapter is the check an agent runs before it touches any hooked book. The census it reads lives in the manual as open data.

the primitive

What a hook is on this fork

A v4 pool's rules live at one address. When a pool initializes on the fork PoolManager — pinned at 0x8366a39CC670B4001A1121B8F6A443A643e40951 — its pool key carries that hook address, and every swap, mint, burn, and donate on the pool passes through it. The fork reads the hook's low fourteen bits as the permission mask: each bit arms one callback. The decode is arithmetic, free, and permanent.

bitsarmscallbacks
13, 12initializebeforeInitialize, afterInitialize
11, 10add liquiditybeforeAddLiquidity, afterAddLiquidity
9, 8remove liquiditybeforeRemoveLiquidity, afterRemoveLiquidity
7, 6swapbeforeSwap, afterSwap
5, 4donatebeforeDonate, afterDonate
3, 2swap returns deltabeforeSwapReturnsDelta, afterSwapReturnsDelta
1, 0unobservednever assume them — the census records them as unknown

The mask window is 0x3fff — fourteen bits, (1 << 14) − 1. Anything above bit 13 in an address is just where the deployer landed.

the surfaces

Where to check

Three files carry the census. Read them before you read the chain — they are the chain, measured.

The register — 5,558 hooks, one row each: the decoded permissions, the five danger flags, the pool coverage in books, code presence, the classes (PAYS-LPS, HOOK-MONETIZED, DEAD), the label tier, and a null name until an alias is curated. The register reports a null name, and so does this page.

The per-pool sidecar — 402 pools mapped poolId to hook, mask, flags, and code presence: the lookup for a pool you already hold.

The fleet feed — the measured fee screen: what each book charges and what it pays, from the same measurement pass that powers the fleet surface.

How the register was built, as a receipt: one full pass over the fork PoolManager's Initialize logs — 961,768 logs mined over keyless RPC slices — then 1,154 hooks probed with eth_getCode. A probe that fails records unprobed. Codelessness is a measurement, never an inference. As of the fixture head, no register row reports deployable code — and a coded hook can arrive tomorrow, so every row is measured the same way.

For live state, read the pinned StateView at 0x0284Cb0bcbaa8B87A8AA409D0e41afA7a76355F2 — its slot0 read carries the pool's live fee. A slot0 read is a measurement of now, never a promise about the next swap.

the decode

How to read a mask

The five danger flags are groups of permission bits with consequences. The register computes them per row; here is what each one means for money.

flagbitswindowwhat it means
returnsDeltas3, 20x0cthe hook can move swap money in-pool — a swap that pays in can pay out something other than the quoted figure
touchesLiquidityRemoval9, 80x300the hook runs on removal — your withdrawal can be seen, gated, or taxed
setsDynamicFee70x80the hook sets the pool fee per swap — yesterday's fee is not today's
touchesAddLiquidity11, 100xc00the hook runs on entry — your mint can be gated or sized
donate5, 40x30donations route through the hook

Two masks recur enough to carry names in the census. mask 0x14c0 — nineteen hooks — arms afterInitialize, afterAddLiquidity, beforeSwap, and afterSwap, and nothing that returns deltas: these hooks cannot skim swap value inside the pool; any payout must arrive as a separate transfer. mask 0x28cc — sixteen hooks — arms beforeInitialize, beforeAddLiquidity, beforeSwap, afterSwap, and both swap-returns-delta bits: these hooks can take or give tokens inside the swap itself. Treat every quoted output on a 0x28cc book as unverified until you re-derive it.

One rule above all: masks on codeless addresses are inert labels. A mask on an address with no bytecode arms nothing, taxes nothing, and redirects nothing — but it still advertises. Read the mask for intent; probe the code for power.

the drill

The worked check — four steps, zero keys

Everything runs over the keyless RPC pinned in the skill. No wallet, no approval, no signature — reading is free.

Step 1 — pool to hook. Look the poolId up in the per-pool sidecar, or mine your own: an eth_getLogs pass over the pinned PoolManager's Initialize topic yields poolId, currencies, hook, and fee for every pool since genesis. Window your scans — keyless RPC caps log ranges.

Step 2 — decode the mask. Free, before any call:

mask = int(hook, 16) & 0x3fff   # the low 14 bits are the whole permission set

Step 3 — probe the code:

cast code 0xfffffffffffffffffffffffffffffffffff9a8cc --rpc-url https://rpc.mainnet.chain.robinhood.com

0x back means codeless — the mask is an inert label. A timeout or error means unprobed: record it as unprobed, never codeless.

Step 4 — read the register row. Permissions, danger flags, classes, label tier, books. Three real rows, resolved live from the register by this page's battery:

hookmaskbookscodewhat the row says
0x00000000000000000000000000000000000305a20x5a259,350codelessremoval, dynamic fee, entry, donate armed · classes DEAD and PAYS-LPS · tier LABEL-LIE — the most-covered hook on the chain is a label, and the label lies
0xfffffffffffffffffffffffffffffffffff9a8cc0x28cc42codelessreturnsDeltas armed — the delta cohort; in-pool money movement is on the table
0x00000000000000000000000000000000000314c00x14c043codelessno delta bits — skimming swap value in-pool is structurally off the table; payouts must arrive as separate transfers

The register currently carries 270 rows in the LABEL-LIE tier — hooks whose books charge a fee their label does not declare. The fee receipts page carries the book-level counts and the hand-check receipt.

the rules

Rules of engagement

For any interaction with a hooked book — swap, mint, or exit — the drill above first. Then these:

  1. Never approve a token to a hook. Approvals go to the PoolManager at 0x8366a39CC670B4001A1121B8F6A443A643e40951, and to the position manager for v3 positions. A hook is code the PoolManager calls, not a counterparty you sign to.
  2. Re-derive, never trust. On a returnsDeltas book the quoted output is a hypothesis. Measure what you actually received.
  3. A dynamic-fee book reprices per swap. Quote late, settle fast, and treat a stale fee as unknown.
  4. A hook can revert your swap. That is the pool enforcing its rules, not an outage — read the mask instead of retrying blind.
  5. Hooks compose through executor adapters. The register measures a pool's own hook; anything composed next to it is unmeasured. Treat labels as claims and measurements as measurements.
  6. Know the removal bits before you mint. touchesLiquidityRemoval means your exit can be seen, gated, or taxed — the one check an LP cannot do from a pool label.
  7. Read the measured fee, not the declared one. The fee receipts page lists every book whose charged fee disagrees with its label.
  8. Check code presence first. A mask on a codeless address is a label; a mask on a coded address is law. The register records which, per row, per fixture head.

the doctrine

This book audits hooks. It ships none.

A hook is mutable, permission-carrying code parked next to every swap. Deploying one would recreate the exact advertised-versus-charged gap this census measures — on a protocol whose whole posture is immutable contracts and timelock-gated seams. So the line is drawn where the measurement is: the chain's hooks get probed, tiered, and published; none get shipped.

What an agent does instead is the rest of the manual: provide liquidity directly through the pinned PoolManager under the skill's permission model, quote through the pinned quoter, operate the vault, and read every fee from data. The skill and the registry carry the flows.