The permission bits
The fourteen bits at the end of every hook address, what each one lets a hook do, and how to read them yourself.
A v4 hook's permissions are the last 14 bits of its address. The deployer mines the address (with CREATE2 and a chosen salt) until those bits match the callbacks the hook implements. The PoolManager reads the bits on every action and calls only what they switch on.
The fourteen bits
| Bit | Mask | Permission | What it lets the hook do |
|---|---|---|---|
| 13 | 0x2000 |
beforeInitialize | Run once, when a pool is created. |
| 12 | 0x1000 |
afterInitialize | Run once, right after a pool is created. |
| 11 | 0x0800 |
beforeAddLiquidity | Run before each deposit. Can refuse deposits, or admit only some addresses. |
| 10 | 0x0400 |
afterAddLiquidity | Run after each deposit. |
| 9 | 0x0200 |
beforeRemoveLiquidity | Run before each withdrawal. Can refuse a withdrawal. |
| 8 | 0x0100 |
afterRemoveLiquidity | Run after each withdrawal. |
| 7 | 0x0080 |
beforeSwap | Run before every swap. On a dynamic-fee pool, can set the fee for each swap. |
| 6 | 0x0040 |
afterSwap | Run after every swap. |
| 5 | 0x0020 |
beforeDonate | Run before a donation to LPs. |
| 4 | 0x0010 |
afterDonate | Run after a donation to LPs. |
| 3 | 0x0008 |
beforeSwapReturnDelta | Take part of what you put into a swap, or change how much is swapped. |
| 2 | 0x0004 |
afterSwapReturnDelta | Take part of what you get out of a swap. |
| 1 | 0x0002 |
afterAddLiquidityReturnDelta | Charge LPs on the way in. |
| 0 | 0x0001 |
afterRemoveLiquidityReturnDelta | Take part of what LPs withdraw. |
The four return-delta permissions have no function of their own. Each rides on a callback: beforeSwapReturnDelta on beforeSwap, afterSwapReturnDelta on afterSwap, and the two liquidity ones on afterAddLiquidity and afterRemoveLiquidity. The PoolManager rejects a hook address that switches on a return delta without its callback.
Each return-delta permission can also add rather than take: a hook can pay a rebate the same way it charges a tax.
Reading an address by hand
Take the last four hex digits of the address and keep the low 14 bits (AND with 0x3FFF). Then split the result into the masks above.
An address ending in …20CC:
0x20CC & 0x3FFF = 0x20CC
0x20CC = 0x2000 + 0x0080 + 0x0040 + 0x0008 + 0x0004
= beforeInitialize + beforeSwap + afterSwap
+ beforeSwapReturnDelta + afterSwapReturnDelta
This is the shape of a launch-tax hook: it sets something up when the pool is created, runs around every swap, and may take from both the input and the output. Whether it actually takes, and how much, is a question the address cannot answer; the probe does.
An address ending in …0080 has beforeSwap alone. It can run code before each swap, refuse a swap, and set the fee if its pools are dynamic-fee pools, but it cannot take tokens through a delta.
What the bits guarantee, and what they do not
A bit that is off is a guarantee. The PoolManager will never call that callback, whatever the code contains. A hook whose four return-delta bits are off cannot take from a swap or from an LP through a delta, and a hook whose beforeRemoveLiquidity and afterRemoveLiquidity bits are off cannot refuse a withdrawal (the tokens themselves are another matter). One exception to keep in mind: on a dynamic-fee pool, a hook with no return delta can still raise the pool fee, and in a pool closed to outside LPs the fee goes to liquidity the hook controls. That is why check 04 judges the fee's level, and fails it above 10%.
A bit that is on is only a possibility. The hook is allowed to act there; it may do nothing. A hook can switch on a return delta and leave it at zero.
Any callback that is on can revert. A revert refuses the action the callback wraps. That is why the scan measures swaps and withdrawals instead of inferring them from the bits: afterSwap alone cannot take, but it can refuse.
How the scan uses them
The permission register on a report shows all fourteen bits. Check 01, Permissions that touch your money, is a caution when any of the four return deltas or beforeRemoveLiquidity is on, and a pass otherwise. It is a caution, never a fail: it says the hook may take or block, and 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.
The bits also decide which callbacks the callback access test knocks on: every callback whose bit is on, and only those.