Pre-launch. RC4 code-frozen for external audit (rc4-audit-candidate, aca5fcd). Report pending. Status, updated 2026-10-08
GENESpecimen 001

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 with launch(), metabolize() and REGENERATION's buyback (GeneHook.sol:40-43).
  • Donations are not blocked. With the donate bits clear, v4's donate works on the pool; a donated amount accrues as fees to in-range positions, which are the hook's, and is collected when a later metabolize() 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, and beforeSwap returns fee override 0 (GeneHook.sol:26-27, GeneHook.sol:365; invariants FEE1 and FEE2).
  • REQUIRED_FLAGS() returns 0x2AC0 on chain (GeneHook.sol:148-149). GeneHook has no getHookPermissions() function; the tests assert address & ALL_HOOK_MASK == 0x2AC0, the prefix rule and REQUIRED_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 match

The 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).