How it works

Permissions live in the address

In Uniswap v4, a hook can't decide later which moments it runs at. Those permissions are fixed by the hook's address: the lowest 14 bits are 14 on/off switches. That's why hook builders "mine" addresses until the bits match the code.

So Fathom doesn't need to call the contract to know what a hook may do. It reads the last four characters of the address. For example, an address ending in 0080 has only bit 7 on: before swaps.

bits = parseInt(address.slice(-4), 16) & 0x3fff
beforeInitialize      bit 13      beforeSwap               bit 7
afterInitialize       bit 12      afterSwap                bit 6
beforeAddLiquidity    bit 11      beforeDonate             bit 5
afterAddLiquidity     bit 10      afterDonate              bit 4
beforeRemoveLiquidity bit 9       beforeSwapReturnDelta    bit 3
afterRemoveLiquidity  bit 8       afterSwapReturnDelta     bit 2
                                  afterAddLiquidityReturnDelta    bit 1
                                  afterRemoveLiquidityReturnDelta bit 0

This part works on real addresses.

Valid combinations

The four "return delta" switches let a hook change amounts. Each only works together with its base switch, and v4 rejects a hook address that has one without the other:

  • Rewrites swap amounts needs before swaps.
  • Takes from swap output needs after swaps.
  • Changes deposit amounts needs after deposits.
  • Takes from withdrawals needs after withdrawals.

A hook with no switches at all only makes sense on a pool with dynamic fees.

The score

Every hook starts at 100 and loses points for each power it has. The biggest costs are the ones that touch your money:

  • Takes from withdrawals: −28
  • Rewrites swap amounts: −22
  • Before withdrawals (can refuse them): −20
  • Takes from swap output: −18
  • Changes deposit amounts: −12
  • Before swaps (can refuse swaps or set fees): −8
  • Before deposits (can gate who joins): −5
  • Watch-only permissions: −1 or −2

80 and up is deep water, 50 to 79 is shoals, under 50 is reef.

Contract checks

  • Source code not verified: −15
  • Code can be replaced at any time: −18, or −8 behind a timelock
  • Owner is a single wallet: −15; a multisig: −6; a timelock: −3
  • Owner can change the fee on a hook that charges one: −8

For now these are simulated from the address. A live version would read them from the chain and the explorer.

API

With the Node server running:

  • GET /api/inspect?hook=0x… — the full report.
  • GET /api/hooks — the hook chart.
  • GET /api/flags — all 14 permissions with their bits.

What Fathom can't do yet

  • It doesn't read Robinhood Chain. Owners, upgradeability, verification, pools and names are made up, but stay the same for the same address.
  • A score reads what a hook is allowed to do. It isn't an audit of how well the code does it.