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.
Capability notes
Section titled “Capability notes”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.
Profile warnings
Section titled “Profile warnings”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.
Example
Section titled “Example”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.
A checklist
Section titled “A checklist”Before swapping through a hooked pool:
GET /v1/pools/:poolId: checkhook.capabilitiesandstate.lpFee.GET /v1/hooks/:address: checkwarningsandcode.proxy.POST /v1/quote: the quote runs the hook. CompareexecutionPriceto the pool’s spotprice.POST /v1/swap/buildwith 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).
