Skip to content

Reading a hook's risk profile

A hooked pool runs third-party code inside every swap and liquidity change. HookKit does not audit hooks and does not label them safe or unsafe. It reports what a hook is able to do, from its permission bits and its deployed bytecode, so you can decide what to check next.

There are two layers:

  • capabilities: notes derived from the permission bits. Pure, works for any address. Returned by every decode, hook profile, and pool state.
  • warnings: address-level findings from the chain (proxy, missing code, invalid flags). Returned by the full hook profile, GET /v1/hooks/:address.

Each note has a level, the flag it comes from, and a note. They are ordered from most to least significant.

Level Flag Note
warning beforeSwapReturnDelta Can take over swap pricing (custom curve / custom accounting): output may not follow the pool’s liquidity.
warning afterSwapReturnDelta Can charge or rebate tokens after each swap, e.g. a hook fee on top of the LP fee.
warning liquidityReturnDelta Can take or add tokens when liquidity is added or removed. (Either afterAddLiquidityReturnDelta or afterRemoveLiquidityReturnDelta.)
caution beforeRemoveLiquidity Runs before LP withdrawals and can revert them (lockups, vesting, or a withdrawal block).
info beforeAddLiquidity Can gate who adds liquidity or where.
info beforeSwap Runs before every swap: can revert, or override the LP fee on dynamic-fee pools.
info afterSwap Runs after every swap: oracles, points, limit orders, rebalancing.
info initialize Runs when a pool is created with this hook (can restrict which pools use it). (Either initialize flag.)
info donate Runs on donations to in-range LPs. (Either donate flag.)

How to read the levels:

  • warning: the hook can move tokens in or out of your swap or position beyond what the pool’s curve and LP fee would. Many legitimate designs need this (custom curves, hook fees, launchpads), but the quote is the only reliable number. Always quote through the hook and set a slippage bound.
  • caution: for LPs, the hook can block or delay withdrawals. Read its rules before depositing.
  • info: the hook runs at that point and can revert, but cannot change amounts on its own.

The registry (GET /v1/hooks) summarizes this as warnings: the list of flags whose note is at warning level.

GET /v1/hooks/:address adds findings from the chain:

Warning Meaning
Invalid hook address: ... A *ReturnDelta flag without its base flag. The PoolManager will not initialize a pool with it
No contract code at this address Nothing is deployed there (yet)
Upgradeable proxy: the hook's logic can be changed by its admin after you trade or provide liquidity EIP-1967 proxy. Its permissions are fixed, but what it does with them is not
No permission bits set: only valid on dynamic-fee pools, where the hook can set the LP fee The hook’s only power is the fee

The code object shows the details:

{
"deployed": true,
"codeSize": 25533,
"codeHash": "0xc41a91106002f15bf70ae266824317f3f3ac638ac72ca5253bae395fa47ee631",
"proxy": null
}

When the hook is a proxy, proxy is filled in:

{
"kind": "eip1967",
"implementation": "0x...",
"admin": "0x...",
"upgradeable": true
}

eip1167 minimal proxies (clones) point at a fixed implementation and are reported with upgradeable: false. codeHash lets you check whether two hooks run identical bytecode.

One of the most used hooks on Robinhood Chain, 0x4e34...a544, is attached to tens of thousands of pools:

{
"enabled": ["beforeInitialize", "afterAddLiquidity", "afterRemoveLiquidity", "afterSwap", "afterSwapReturnDelta"],
"capabilities": [
{ "level": "warning", "flag": "afterSwapReturnDelta", "note": "Can charge or rebate tokens after each swap, e.g. a hook fee on top of the LP fee." },
{ "level": "info", "flag": "afterSwap", "note": "Runs after every swap: oracles, points, limit orders, rebalancing." },
{ "level": "info", "flag": "initialize", "note": "Runs when a pool is created with this hook (can restrict which pools use it)." }
],
"code": { "deployed": true, "codeSize": 25533, "proxy": null },
"warnings": []
}

Reading it: it is not a proxy, it cannot block LP withdrawals, and it does not replace swap pricing, but it can take a cut (or pay a rebate) after each swap. So the swap output can differ from the pool’s curve and LP fee alone. Quote through it before swapping.

Before swapping through a hooked pool:

  1. GET /v1/pools/:poolId: check hook.capabilities and state.lpFee.
  2. GET /v1/hooks/:address: check warnings and code.proxy.
  3. POST /v1/quote: the quote runs the hook. Compare executionPrice to the pool’s spot price.
  4. POST /v1/swap/build with a slippage bound you are comfortable with.

Before providing liquidity, also look for beforeRemoveLiquidity (withdrawals can be blocked) and the liquidity ReturnDelta flags (deposits and withdrawals can be charged).