The eight checks
What each check reads or measures, the exact thresholds, and its weight in the score.
Every hook gets the same eight checks. Each ends in one of four statuses: pass, caution, fail, or n/a when there was nothing to check. Each comes with one sentence of evidence on the report.
| # | Check | How it is decided | Weight |
|---|---|---|---|
| 01 | Permissions that touch your money | Read from the address | 10 |
| 02 | What it takes from a swap | Measured | 25 |
| 03 | LPs can get out | Measured | 15 |
| 04 | The fee is the fee | Read from the pool key and the pool's stored fee | 5 |
| 05 | No one holds the switch | Read from the bytecode and owner() |
15 |
| 06 | The code cannot change | Read from the bytecode and proxy slots | 15 |
| 07 | Only the PoolManager can call it | Called from a stranger | 10 |
| 08 | Track record | Read from the index of pools | 5 |
The weights add up to 100. How they become a score and a verdict is on Score and verdict.
01 Permissions that touch your money
Reads the hook's permission bits.
- Caution if any of the four return-delta permissions (
beforeSwapReturnDelta,afterSwapReturnDelta,afterAddLiquidityReturnDelta,afterRemoveLiquidityReturnDelta) orbeforeRemoveLiquidityis on. - Pass otherwise.
This check says the hook may take from swaps or LPs, or block a withdrawal. It never fails, because being allowed is not doing; checks 02 and 03 measure whether it does. It is still enough to keep the verdict from safe, since safe means nothing that may take.
02 What it takes from a swap
Measures a small swap in each direction through up to two of the hook's pools, with the probe. The take is what is missing beyond the fee stored in the pool. The level of that fee is judged separately, in 04.
- Pass if the hook takes at most 1% beyond the pool fee.
- Caution if it takes more than 1% and at most 10%.
- Fail if it takes more than 10%.
- Fail if a swap is refused in one direction while the other direction works: you may be able to buy and not sell.
- Fail if swaps are refused and none goes through: only an approved router, or an approved sender, may get through.
- n/a if there was no pool, or no swap could be measured because the pools were too thin.
Only a swap that reverts counts as refused. A swap that goes through but consumes nothing is thin, not refused: the pool's liquidity ends at the current price on that side ("no liquidity below the price" or "above the price"), which is common on launch pools nobody has traded yet. A thin direction is not measured and does not count against the hook.
The worst measured direction decides. A take of 1% or less passes: a hook may charge a small fee by design, and the report still shows the exact figure.
03 LPs can get out
Measures a liquidity round trip: a little liquidity added around the current price and removed in the same call.
- Pass if it comes back whole (a loss of 0.1% or less).
- Caution if the loss is more than 0.1% and at most 5%.
- Fail if the loss is above 5%, or if the withdrawal is refused.
- n/a if deposits are refused (the pool is closed to outside LPs), or if there was no pool to try.
A closed pool is not a fail. An outside LP cannot enter, so there is nobody outside to trap. It does mean the only liquidity is the hook's own.
04 The fee is the fee
Reads the level of the pool fee: the highest fee among the measured pools. For a fixed-fee pool that is the fee written in the pool key. For a dynamic-fee pool (fee field 0x800000) it is the LP fee the hook has currently stored in the pool.
- Fail if the fee is above 10%, fixed or dynamic.
- Caution if the pool uses a dynamic fee, at any level up to 10%. The hook sets it, it stands at the reported level now, and it can change; with
beforeSwapthe hook can set it before every swap. - Caution if the fee is fixed and above 1%.
- Pass if the fee is fixed and at most 1%.
- n/a if the hook has no pool yet.
The fee and the take are two halves of what a swap costs, and they are judged in two checks: the fee level here, the hook's extra take in 02. A trader pays both. One hook on Robinhood Chain, attached to 15,300 pools at the time of writing, has dynamic-fee pools standing at a 10% fee and takes 2% on top: its report shows a caution on 04 (10% is not above 10%) and a caution on 02, and together they cost close to 12% of each swap.
05 No one holds the switch
Reads owner() and the names of the hook's functions.
- Pass if there is no owner and no owner-style function.
- Caution if
owner()returns an address, or if functions with owner-style names are found (set…,update…,withdraw…,pause,blacklist…,mint…,upgrade…and the like). The report names the owner and the functions.
This check never fails. An owner can be there for ordinary reasons, such as setting a fee recipient or collecting fees. But whoever holds the switch can change what 02 and 03 measured, and that is worth knowing before you rely on them. A caution here is enough to make the verdict caution.
06 The code cannot change
Reads the EIP-1967 proxy slots, checks for an EIP-1167 clone, and walks the bytecode.
- Fail if the hook is an upgradeable proxy: the code that runs lives at another address and can be replaced. The report shows the implementation and, if set, the admin.
- Caution if the bytecode contains DELEGATECALL or SELFDESTRUCT.
- Pass otherwise.
A scan is a reading of the code at one block. If the code can be swapped, the reading can be made obsolete in a single transaction, which is why this is one of the two checks that can fail on structure alone.
07 Only the PoolManager can call it
Calls each callback the address switches on, directly, from a stranger address, with a harmless pool key.
- Pass if every callback refuses.
- Fail if any callback accepts the call. The report lists which ones.
- n/a if the address switches no callback on.
Guarding callbacks with an onlyPoolManager check is one line, and every standard base contract does it. A hook that skips it lets anyone run its callbacks with made-up arguments, and any state those callbacks write can then be written by anyone.
08 Track record
Reads the index of every pool created on the PoolManager.
- Pass if the hook is used by at least 3 pools and its first pool is at least 7 days old.
- Caution otherwise, including a hook that is not in the index yet.
Age is not safety, but a hook from this morning has proven nothing. The weight is small on purpose.