Documentation · Reference
Errors
Every custom error GENE contracts can raise, with its selector and the exact condition that throws it.
Selectors were produced by forge inspect at commit aca5fcd3bbc9ecb1026de58bea431d406d8ecfff (see Selectors). GeneLens defines no custom errors. Errors raised inside the PoolManager or inside OpenZeppelin ERC20 during a GENE call carry their own selectors.
#GeneHook errors
| Error | Selector | Declared | Thrown at |
|---|---|---|---|
| NotPoolManager() | 0xae18210a |
GeneHook.sol:52 | GeneHook.sol:359, GeneHook.sol:372, GeneHook.sol:396 |
| NotLauncher() | 0x9e6ff739 |
GeneHook.sol:53 | GeneHook.sol:253 |
| AlreadyLaunched() | 0xcfa6d878 |
GeneHook.sol:54 | GeneHook.sol:254 |
| NotLaunched() | 0x8dda39df |
GeneHook.sol:55 | GeneHook.sol:1000 |
| Forbidden() | 0xee90c468 |
GeneHook.sol:56 | GeneHook.sol:333, GeneHook.sol:342, GeneHook.sol:351 |
| WrongPool() | 0xd3c913ea |
GeneHook.sol:57 | GeneHook.sol:363 |
| UnexpectedCallback() | 0xdab1e993 |
GeneHook.sol:58 | GeneHook.sol:403 |
| HookAddressInvalid() | 0xf0dd0d55 |
GeneHook.sol:59 | GeneHook.sol:226, GeneHook.sol:228, GeneHook.sol:229 |
| GeneNotExpressed(uint8) | 0x2abc0a56 |
GeneHook.sol:60 | GeneHook.sol:283, GeneHook.sol:298 |
| Cooldown(uint256) | 0xff658a1c |
GeneHook.sol:61 | GeneHook.sol:285, GeneHook.sol:300 |
| InvariantBroken() | 0xb2151907 |
GeneHook.sol:62 | GeneHook.sol:425, GeneHook.sol:660, GeneHook.sol:694 |
#NotPoolManager
error NotPoolManager(), selector 0xae18210a. Thrown when msg.sender is not the PoolManager in beforeSwap (GeneHook.sol:359), afterSwap (GeneHook.sol:372) or unlockCallback (GeneHook.sol:396).
#NotLauncher
error NotLauncher(), selector 0x9e6ff739. Thrown by launch() when msg.sender != launcher (GeneHook.sol:253).
#AlreadyLaunched
error AlreadyLaunched(), selector 0xcfa6d878. Thrown by launch() when launched is already true, so a second launch always reverts (GeneHook.sol:254).
#NotLaunched
error NotLaunched(), selector 0x8dda39df. Thrown by _requireLaunched() (GeneHook.sol:999-1001), which metabolize(), regenerate() and evolve() call first (GeneHook.sol:282, GeneHook.sol:297, GeneHook.sol:313).
#Forbidden
error Forbidden(), selector 0xee90c468. beforeInitialize, beforeAddLiquidity and beforeRemoveLiquidity always throw it (GeneHook.sol:332-352). The PoolManager calls them for every initialize or liquidity change on a pool naming this hook, except when the hook itself is the caller.
A caller sees it wrapped: v4's callHook reverts with WrappedError(address target, bytes4 selector, bytes reason, bytes details) (selector 0x90bfb865), where target is the hook, selector is the callback's selector, reason holds Forbidden() and details holds HookCallFailed() (selector 0xa9e35b2f) (v4 Hooks.sol:74, Hooks.sol:131-137, CustomRevert.sol:11, CustomRevert.sol:83-115).
#WrongPool
error WrongPool(), selector 0xd3c913ea. Thrown by beforeSwap when the key passed by the PoolManager differs from the canonical key in currency0, currency1, fee or tickSpacing (GeneHook.sol:360-363). afterSwap has no key check.
#UnexpectedCallback
error UnexpectedCallback(), selector 0xdab1e993. Thrown by unlockCallback when the transient ACTION_SLOT is zero or differs from the action decoded from the callback data (GeneHook.sol:397-403). The slot is set only by the hook's own _unlock (GeneHook.sol:409-418).
#HookAddressInvalid
error HookAddressInvalid(), selector 0xf0dd0d55. Thrown by the constructor when:
- the low 14 bits of the hook address are not exactly
REQUIRED_FLAGS(0x2AC0) (GeneHook.sol:226); - the top byte of the address is
0x91(GeneHook.sol:228); - the PoolManager address has no code, or the launcher is
address(0)(GeneHook.sol:229).
#GeneNotExpressed
error GeneNotExpressed(uint8 gene), selector 0x2abc0a56. Thrown with gene = 1 by metabolize() while METABOLISM is not EXPRESSED (GeneHook.sol:283), and with gene = 2 by regenerate() while REGENERATION is not EXPRESSED (GeneHook.sol:298). After launch the first metabolize() therefore needs METABOLISM to have been expressed by an earlier evolve().
#Cooldown
error Cooldown(uint256 readyAtBlock), selector 0xff658a1c. Thrown when the stored last block is non-zero and block.number < last + COOLDOWN_BLOCKS (COOLDOWN_BLOCKS); readyAtBlock is last + COOLDOWN_BLOCKS.
| Function | Stored block | Written when | Source |
|---|---|---|---|
metabolize() |
lastMetabolizeBlock |
At the start of every call that passes the checks | GeneHook.sol:284-286 |
regenerate() |
lastRegenerateBlock |
Only after a call that spent its whole allotment | GeneHook.sol:299-307 |
#InvariantBroken
error InvariantBroken(), selector 0xb2151907. Thrown when a liquidity operation returns a principal that the code does not allow:
| Where | Condition | Source |
|---|---|---|
launch() genesis add |
The genesis band required any ETH | GeneHook.sol:425 |
_addMass (every placement) |
An ETH placement required GENE, or an ask required ETH | GeneHook.sol:654-660 |
_poke (harvest) |
A zero-liquidity poke returned any principal | GeneHook.sol:691-694 |
A revert rolls back the whole call, including its harvest and its cooldown write (GeneHook.sol:284-286). An ETH placement requires GENE when the pool price is at or beyond the band's lower tick. Audit scope note: metabolize() reverting InvariantBroken while the price sits at or beyond the METABOLISM or churn bid band (see Security).
#GeneLens revert
positionAt(hook, i) reverts with the string "index" (Error(string)) when i >= positionCount(hook) (GeneLens.sol:93-94). GeneLens has no other revert of its own.
#GeneToken errors
GeneToken defines no custom errors. It raises the OpenZeppelin ERC-6093 errors below (declared in draft-IERC6093.sol). OZ is lib/v4-core/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol.
| Error | Selector | Thrown when | Source |
|---|---|---|---|
ERC20InsufficientBalance(address,uint256,uint256) |
0xe450d38c |
A transfer, transferFrom or burn exceeds the sender's balance |
draft-IERC6093.sol:16; OZ:195 |
ERC20InvalidSender(address) |
0x96c6fd1e |
A transfer or burn from address(0) |
draft-IERC6093.sol:22; OZ:173, OZ:243 |
ERC20InvalidReceiver(address) |
0xec442f05 |
A transfer or mint to address(0) |
draft-IERC6093.sol:28; OZ:176, OZ:228 |
ERC20InsufficientAllowance(address,uint256,uint256) |
0xfb8f41b2 |
transferFrom exceeds the allowance |
draft-IERC6093.sol:36; OZ:309 |
ERC20InvalidApprover(address) |
0xe602df05 |
An approval from address(0) |
draft-IERC6093.sol:42; OZ:286 |
ERC20InvalidSpender(address) |
0x94280d62 |
An approval for address(0) |
draft-IERC6093.sol:48; OZ:289 |
Sources (20)
- src/GeneHook.sol:52-62
- src/GeneHook.sol:224-229
- src/GeneHook.sol:252-254
- src/GeneHook.sol:281-300
- src/GeneHook.sol:312-313
- src/GeneHook.sol:332-372
- src/GeneHook.sol:395-403
- src/GeneHook.sol:420-426
- src/GeneHook.sol:484
- src/GeneHook.sol:516-518
- src/GeneHook.sol:654-697
- src/GeneHook.sol:999-1001
- src/GeneLens.sol:93-94
- src/GeneToken.sol:20-23
- lib/v4-core/src/libraries/Hooks.sol:74
- lib/v4-core/src/libraries/Hooks.sol:131-137
- lib/v4-core/src/libraries/CustomRevert.sol:11
- lib/v4-core/src/libraries/CustomRevert.sol:83-115
- lib/v4-core/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol:16-48
- lib/v4-core/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol:171-310
Paths are relative to the GENE repository at tag rc4-audit-candidate (aca5fcd).