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

Documentation · Reference

Events

Every event GeneHook and GeneToken emit, with full signature, indexed fields, topic0, when it fires and where in the code.

GeneHook emits nine events; GeneLens emits none; GeneToken emits the two standard ERC-20 events. topic0 values were produced by forge inspect at commit aca5fcd3bbc9ecb1026de58bea431d406d8ecfff and re-hashed over the canonical signatures (see Selectors). In canonical signatures a struct is a tuple, the enum State is uint8 and PoolId is bytes32.

Index only logs whose emitting address is the GeneHook (or GeneToken) address from Addresses: any contract can emit a log with the same topic.

#GeneHook events

Event Indexed Emitted when Declared Emitted at
Genesis genomeHash Constructor GeneHook.sol:131 GeneHook.sol:247
Launched poolId End of launch() GeneHook.sol:132 GeneHook.sol:272
EpochClosed epoch First touch after an epoch boundary GeneHook.sol:133 GeneHook.sol:757
FlowBudgets epoch A closing epoch creates a non-zero net-flow budget GeneHook.sol:135 GeneHook.sol:868, GeneHook.sol:871
GeneTransition gene, epoch Every gene state change GeneHook.sol:136 GeneHook.sol:271, GeneHook.sol:908, GeneHook.sol:915, GeneHook.sol:928, GeneHook.sol:931, GeneHook.sol:945-946
FeesHarvested none Every metabolize() harvest GeneHook.sol:137 GeneHook.sol:688
MassAdded kind Genesis band and every placement GeneHook.sol:141 GeneHook.sol:433, GeneHook.sol:626
PlacementSkipped kind A placement exceeding v4's per-tick liquidity ceiling GeneHook.sol:144 GeneHook.sol:620
Regenerated none A REGENERATION buyback that reached the swap GeneHook.sol:145 GeneHook.sol:589

#Genesis

event Genesis(bytes32 indexed genomeHash, address token, PoolId poolId);
  • topic0: 0xe1b51be66a2ef6be7dcd41a89830cfd13b149b5b2a8414acff3ae3732823b944 (Genesis(bytes32,address,bytes32)).
  • Emitted once, in the constructor, after the token is deployed and the poolId and genomeHash are set (GeneHook.sol:233-247).
  • genomeHash is keccak256(Genome.encode()); token is the GeneToken address; poolId is the canonical pool's id.

#Launched

event Launched(PoolId indexed poolId, int24 tickLower, int24 tickUpper, uint128 liquidity, uint256 geneSeeded, uint256 dustBurned);
  • topic0: 0x91e0e355c54aa11c2da9794288faa5736a5c94771a77469ca23177a9b732e8ac (Launched(bytes32,int24,int24,uint128,uint256,uint256)).
  • Emitted once, as the last action of launch() (GeneHook.sol:272).
  • tickLower / tickUpper are the genesis band (GENESIS_TICK_LOWER, GENESIS_TICK_UPPER); liquidity is the band's liquidity units; geneSeeded is the GENE settled into the pool; dustBurned is the GENE left in the hook and burned (GeneHook.sol:260-263, GeneHook.sol:426).

#EpochClosed

event EpochClosed(uint32 indexed epoch, EpochRecord record, int256 netGene, int24 maxTick, int24 minTick);
  • topic0: 0xb16b0e10b517ac061f1c0df34b8573fea184e51931288d06ad20fce4958cb732 (EpochClosed(uint32,(uint96,uint32,uint32,uint88,bool),int256,int24,int24)).
  • Emitted in _newBlock when the block's epoch differs from the last touched epoch, that is on the first swap, metabolize(), regenerate() or evolve() after a boundary (GeneHook.sol:747-757).
  • epoch is the last touched epoch, whose record is written in the same step. An epoch with no touch gets no record and no event (GeneHook.sol:748-756, GeneHook.sol:880).
  • record is the stored EpochRecord: revenue (wei), activeBlocks, pathTicks, ethCommitted (cumulative, wei), closed (GeneHook.sol:75-81, GeneHook.sol:749-755).
  • netGene is the epoch's net curve GENE in wei (netGeneMicro x 1e12); positive means net buying (GeneHook.sol:113, GeneHook.sol:757).
  • maxTick / minTick are the epoch's highest and lowest block-start ticks (GeneHook.sol:101-102, GeneHook.sol:757).

#FlowBudgets

event FlowBudgets(uint32 indexed epoch, uint256 bidBudget, uint256 immBudget, int24 pLowTick);
  • topic0: 0xe8e65271f07193dfb398d3d3644cc35404e121f1e199e65d6518ed82c83e26f3 (FlowBudgets(uint32,uint256,uint256,int24)).
  • Emitted by _closeFlowBudgets right after EpochClosed, only when the closing epoch's net flow funds a non-zero amount against the cumulative water marks (GeneHook.sol:837-858, GeneHook.sol:866-872).
  • Exactly one of bidBudget (net buying) and immBudget (net selling) is non-zero. Both are ETH (wei), spent in epoch epoch + 1 (GeneHook.sol:199-204, GeneHook.sol:866-872).
  • pLowTick is the epoch's cheapest price: the highest of its block-start ticks and its closing tick (GeneHook.sol:758-761).

#GeneTransition

event GeneTransition(uint8 indexed gene, State from, State to, uint32 indexed epoch, bytes32 evidenceHash);
  • topic0: 0x12df5d9409e23faf7d1a247f463a53b569c8612910e1992bd14f27bf273ef34d (GeneTransition(uint8,uint8,uint8,uint32,bytes32)).
  • gene: 0 GENESIS, 1 METABOLISM, 2 REGENERATION, 3 IMMUNITY (Genome.sol:57-60). State: 0 DORMANT, 1 OBSERVING, 2 EXPRESSIBLE, 3 EXPRESSED (GeneHook.sol:65-70).
Transition When evidenceHash Emitted at
GENESIS DORMANT to EXPRESSED, epoch 0 launch() keccak256(abi.encode(uint8(0), genomeHash, launchBlock)) GeneHook.sol:270-271
DORMANT to OBSERVING First pressure epoch while eligible zero GeneHook.sol:908, GeneHook.sol:928
OBSERVING to DORMANT METABOLISM / REGENERATION: a processed epoch without pressure. IMMUNITY: no stressed epoch left in the window zero GeneHook.sol:915, GeneHook.sol:931
current state to EXPRESSIBLE, then EXPRESSIBLE to EXPRESSED Expression; two events in the same call with the same epoch and hash keccak256(abi.encode(g, first, last, EpochRecord[first..last])) GeneHook.sol:945-946

epoch is the processed closed epoch, not the block's epoch. EXPRESSIBLE is never stored at rest (GeneHook.sol:937-947).

#FeesHarvested

event FeesHarvested(uint256 eth, uint256 gene, uint256 positionsPoked);
  • topic0: 0x68d793b46909dd71f01302cc73514e67391ab192095cf26aec99f08ccca271e2 (FeesHarvested(uint256,uint256,uint256)).
  • Emitted once per metabolize() after the harvest pokes (GeneHook.sol:671-689).
  • eth / gene are the LP fees collected from the poked positions; positionsPoked counts the genesis position plus the registry positions poked. Fees auto-collected later in the same call when adding to an existing band are credited to reserves but are not included in this event (GeneHook.sol:554-559).

#MassAdded

event MassAdded(uint8 indexed kind, int24 tickLower, int24 tickUpper, uint128 liquidity, uint256 amount, int24 spotTick, int24 anchorTick);
  • topic0: 0x4a3afe13ff7bf157ccf7a73bdbdee5453c57a3bebf8d96bb80f101315b1717fa (MassAdded(uint8,int24,int24,uint128,uint256,int24,int24)).
  • Emitted for the genesis band in launch() and for every placement in metabolize() that was not skipped (GeneHook.sol:433, GeneHook.sol:623-626).
  • liquidity is the liquidity units added; amount is the principal actually used (ETH for kinds 1, 2, 4; GENE for kinds 0 and 3); spotTick is the pool tick at the start of the call (GeneHook.sol:453, GeneHook.sol:661).
kind Placement anchorTick reported (from the code) Emitted at
0 Genesis band GENESIS_TICK_UPPER (also reported as spotTick) GeneHook.sol:433
1 METABOLISM bid atlTick GeneHook.sol:484-485
2 IMMUNITY bid max(spot, atlTick) in ticks GeneHook.sol:498-501
3 Ask (GENE) min(spot, athTick) in ticks GeneHook.sol:544-546
4 Churn-tier bid atlTick GeneHook.sol:516-518

The NatSpec on the event (GeneHook.sol:139-140) describes the bid anchor as "the all-time low or spot if lower"; the table above follows the code, which passes atlTick for kinds 1 and 4.

Only a mined MassAdded with kind == 2 records an IMMUNITY placement. immunityActive() is a signal only (GeneHook.sol:987-989).

#PlacementSkipped

event PlacementSkipped(uint8 indexed kind, int24 tickLower, int24 tickUpper, uint256 liquidity);
  • topic0: 0x8f66a7348a1e8268a4e1a335ac52f8ecef5ff290996535e55038d644ccada7ec (PlacementSkipped(uint8,int24,int24,uint256)).
  • Emitted by _deploy when the computed liquidity, alone or added to either boundary tick's gross liquidity, would exceed v4's per-tick ceiling for tick spacing 60 (MAX_LIQ_PER_TICK) (GeneHook.sol:619-621, GeneHook.sol:629-652).
  • Nothing was committed and no reserve, cap or budget was consumed (GeneHook.sol:142-143). It adds no Mass.

#Regenerated

event Regenerated(uint256 ethSpent, uint256 geneBurned, int24 spotTick, int24 limitTick);
  • topic0: 0x555d7b94fe7b81e06ec0371158979666f0b647c9f1bcb65e1ce53dc4c1667771 (Regenerated(uint256,uint256,int24,int24)).
  • Emitted inside regenerate() after the buyback swap (GeneHook.sol:578-589). A call that returns before the swap (allotment below the minimum, or spot at or beyond the limit) emits nothing (GeneHook.sol:571, GeneHook.sol:577).
  • ethSpent is the ETH paid; geneBurned is the GENE bought, which the call then burns (GeneHook.sol:308); spotTick is the tick before the swap; limitTick is atlTick - REGEN_PREMIUM_TICKS (GeneHook.sol:572-575).

#GeneToken events

Event Indexed topic0 Emitted when Source
Transfer(address,address,uint256) from, to 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef Mint, transfer, burn IERC20.sol:16
Approval(address,address,uint256) approver, spender 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925 approve IERC20.sol:22

#PoolManager events

The PoolManager's Initialize, ModifyLiquidity and Swap events for the GENE pool carry the poolId as topic1 (IPoolManager.sol:60-104). They are Uniswap v4 events, not GENE events; their topics are on Selectors. For ordering and finality guidance see Events and finality.

Sources (13)
  • src/GeneHook.sol:131-145
  • src/GeneHook.sol:247
  • src/GeneHook.sol:271-272
  • src/GeneHook.sol:433
  • src/GeneHook.sol:479-552
  • src/GeneHook.sol:589
  • src/GeneHook.sol:612-627
  • src/GeneHook.sol:688
  • src/GeneHook.sol:747-765
  • src/GeneHook.sol:837-873
  • src/GeneHook.sol:901-947
  • lib/v4-core/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol:16-22
  • lib/v4-core/src/interfaces/IPoolManager.sol:60-107

Paths are relative to the GENE repository at tag rc4-audit-candidate (aca5fcd).