Documentation · Reference
Permissions and PoolKey
The 14 Uniswap v4 hook flag bits and which ones GeneHook's address sets, what each implemented callback does, and how the PoolKey and poolId are formed.
In Uniswap v4, a hook's permissions are encoded in the low 14 bits of its address, and the PoolManager calls only the callbacks whose bits are set (Uniswap v4: Hooks). GeneHook's address must have those 14 bits equal to exactly 0x2AC0. The constructor enforces this, so no GeneHook can exist at any other address shape (GeneHook.sol:225-226).
#Hook flag bits
Bit positions and names are from the vendored v4-core Hooks.sol (Hooks.sol:27-47). 0x2AC0 sets bits 13, 11, 9, 7 and 6.
| Bit | Mask | Flag | In 0x2AC0 |
GeneHook behaviour | Source |
|---|---|---|---|---|---|
| 13 | 0x2000 |
BEFORE_INITIALIZE |
set | Always reverts Forbidden(). Skipped when the hook itself initializes, so only launch() can open the pool and no other pool can name this hook |
GeneHook.sol:332-334 |
| 12 | 0x1000 |
AFTER_INITIALIZE |
clear | Not implemented | GeneHook.sol:43-45 |
| 11 | 0x0800 |
BEFORE_ADD_LIQUIDITY |
set | Always reverts Forbidden(). Skipped for the hook's own adds, so only the hook can provide liquidity |
GeneHook.sol:337-343 |
| 10 | 0x0400 |
AFTER_ADD_LIQUIDITY |
clear | Not implemented | GeneHook.sol:43-45 |
| 9 | 0x0200 |
BEFORE_REMOVE_LIQUIDITY |
set | Always reverts Forbidden(). The hook has no remove path of its own |
GeneHook.sol:346-352, GeneHook.sol:594-608 |
| 8 | 0x0100 |
AFTER_REMOVE_LIQUIDITY |
clear | Not implemented | GeneHook.sol:43-45 |
| 7 | 0x0080 |
BEFORE_SWAP |
set | PoolManager-only; checks the key fields; on a block's first swap runs the block-start update; returns zero delta and fee override 0 | GeneHook.sol:355-366 |
| 6 | 0x0040 |
AFTER_SWAP |
set | PoolManager-only; accumulates net curve GENE, block ETH volume and buy-side revenue; returns delta 0 | GeneHook.sol:368-390 |
| 5 | 0x0020 |
BEFORE_DONATE |
clear | Not implemented | GeneHook.sol:43-45 |
| 4 | 0x0010 |
AFTER_DONATE |
clear | Not implemented | GeneHook.sol:43-45 |
| 3 | 0x0008 |
BEFORE_SWAP_RETURNS_DELTA |
clear | No return delta | GeneHook.sol:365 |
| 2 | 0x0004 |
AFTER_SWAP_RETURNS_DELTA |
clear | No return delta | GeneHook.sol:389 |
| 1 | 0x0002 |
AFTER_ADD_LIQUIDITY_RETURNS_DELTA |
clear | No return delta | GeneHook.sol:40-45 |
| 0 | 0x0001 |
AFTER_REMOVE_LIQUIDITY_RETURNS_DELTA |
clear | No return delta | GeneHook.sol:40-45 |
Notes:
- Self-calls are skipped. v4 does not call a hook's initialize and liquidity callbacks when the hook is the caller (
noSelfCall, Hooks.sol:171-175), and returns early from the swap callbacks for the hook's own swaps (Hooks.sol:253, Hooks.sol:293). This is what lets the always-reverting callbacks coexist withlaunch(),metabolize()and REGENERATION's buyback (GeneHook.sol:40-43). - Donations are not blocked. With the donate bits clear, v4's
donateworks on the pool; a donated amount accrues as fees to in-range positions, which are the hook's, and is collected when a latermetabolize()pokes or tops up that position (GeneHook.sol:554-559, GeneHook.sol:671-689). - No dynamic fee and no hook fee. The fee is static in the PoolKey, nothing in GeneHook calls
updateDynamicLPFee, andbeforeSwapreturns fee override 0 (GeneHook.sol:26-27, GeneHook.sol:365; invariants FEE1 and FEE2). REQUIRED_FLAGS()returns0x2AC0on chain (GeneHook.sol:148-149). GeneHook has nogetHookPermissions()function; the tests assertaddress & ALL_HOOK_MASK == 0x2AC0, the prefix rule andREQUIRED_FLAGS() == 0x2AC0(SecurityGates.t.sol:272-273, SecurityGates.t.sol:292; invariant ADDR).
#Address prefix rule
The constructor also reverts if the address's top byte is 0x91 (GeneHook.sol:227-228). The source states the reason: the Uniswap routing auto-allowlist excludes addresses starting with 0x91 (GeneHook.sol:227; GeneSaltMiner.sol:6-9). Routing policy is an off-chain rule outside GENE's control. The deploy script mines a CREATE2 salt through the Arachnid deterministic deployer to satisfy both rules (Deploy.s.sol:31-33; GeneSaltMiner.sol:6-11).
#PoolKey
The constructor builds the key once and poolKey() rebuilds the same value (GeneHook.sol:236-242, GeneHook.sol:965-973). Field definitions are Uniswap's (Uniswap v4: create a pool; PoolKey.sol:11-22).
| Field | Type | GENE value | Source |
|---|---|---|---|
currency0 |
Currency (address) |
address(0): native ETH |
GeneHook.sol:237 |
currency1 |
Currency (address) |
The GeneToken address | GeneHook.sol:238 |
fee |
uint24 |
LP_FEE, in pips; static (the dynamic-fee flag is not set) | GeneHook.sol:239; Genome.sol:16 |
tickSpacing |
int24 |
TICK_SPACING | GeneHook.sol:240; Genome.sol:17 |
hooks |
IHooks (address) |
The GeneHook itself | GeneHook.sol:241 |
currency0 < currency1 always holds because currency0 is address(0).
Price orientation. currency0 is ETH, so the pool price is GENE per ETH: a higher tick means cheaper GENE, and a buy of GENE (zeroForOne = true) moves the tick down (GeneHook.sol:103-104).
#poolId derivation
poolId = keccak256(abi.encode(poolKey)): the keccak-256 of the five 32-byte words of the key (PoolId.sol:9-16). GeneHook computes it in the constructor and stores it as the immutable poolId() (GeneHook.sol:243-244).
To recompute it after deployment:
HOOK=0x... # from /docs/reference/addresses/ after deployment
# poolKey() returns a static struct, so its raw return data is exactly abi.encode(poolKey)
KEY=$(cast call $HOOK "poolKey()" --rpc-url $RPC)
cast keccak $KEY
cast call $HOOK "poolId()(bytes32)" --rpc-url $RPC # must matchThe full verification procedure is on Verify the deployment.
Sources (18)
- src/GeneHook.sol:40-45
- src/GeneHook.sol:148-149
- src/GeneHook.sol:224-244
- src/GeneHook.sol:332-390
- src/GeneHook.sol:965-973
- src/Genome.sol:16-17
- script/GeneSaltMiner.sol:6-11
- script/Deploy.s.sol:31-33
- lib/v4-core/src/libraries/Hooks.sol:27-47
- lib/v4-core/src/libraries/Hooks.sol:171-175
- lib/v4-core/src/libraries/Hooks.sol:253
- lib/v4-core/src/libraries/Hooks.sol:293
- lib/v4-core/src/types/PoolKey.sol:11-22
- lib/v4-core/src/types/PoolId.sol:9-16
- test/unit/SecurityGates.t.sol:272-273
- test/unit/SecurityGates.t.sol:292
- src/GeneHook.sol:554-559
- src/GeneHook.sol:671-689
Paths are relative to the GENE repository at tag rc4-audit-candidate (aca5fcd).