SecondaryHook
Owns the token↔$LP24 pool for every graduated token on V4-family chains. Deliberately minimal: one pool per token, a flat fee taken in the token and burned, permanently locked liquidity, and nothing else.
Singleton — one per chain, on Base, BSC, Polygon and Robinhood. No owner, no admin keys, no upgrade path. Not deployed on Gnosis.
SecondaryHook reads PrimaryHook.tokenInfo() to verify a token graduated. PrimaryHook needs nothing back — it pushes funds at graduation and never interacts again. Even the $LP24 acquisition swap is an ordinary fee-paying swap, so there is no fee-exemption path between the two contracts.
Pool Creation
notifyReserved(token: address) external payablePrimaryHook only. Delivers and earmarks this token's native share during graduation. The token side arrives via a separate ERC-20 transfer in the same transaction.
Because only the PrimaryHook can credit nativeEarmark, the earmark cannot be forged — which is what makes createSecondary's per-token accounting sound.
"Only PRIMARY_HOOK""Wrong native amount"— must equalSECONDARY_NATIVE_RAWexactly"No secondary for PROTOCOL_TOKEN"
SecondaryFunded(token, nativeAmount)
createSecondary(token: address) externalCreate the token↔$LP24 pool using funds this contract already custodies. Anyone can call — a keeper, a bot, the deployer. Not payable: the caller brings nothing and pays only gas.
Swaps the earmarked native for $LP24 on the primary $LP24 pool, initializes the pool at the resulting ratio, and mints a full-range position owned by this contract.
token != $LP24- Token registered in PrimaryHook (deployer non-zero)
- No secondary already exists
- Contract holds at least 40,000,000 × 10⁹ (40M)
nativeEarmark[token] >= SECONDARY_NATIVE_RAW— consumed on success- The $LP24 pool exists and is initialized
"No secondary for PROTOCOL_TOKEN""Token not registered in PrimaryHook""Secondary exists""Token funds not received""No native earmark for token"
SecondaryCreated(token, poolId, protocolTokenAmount, tokenAmount, positionId, tokenIsCurrency0)
A revert costs only gas. The earmark is consumed up front, but any later failure in the same call rolls it back along with everything else — so on failure the custodied funds and the earmark both survive for a later attempt, and on success the earmark is spent exactly once.
Fee Behaviour
A flat 60 bps (0.6%) is taken in the launched token, in both directions, and burned to 0x…dEaD. There are no tiers, no reinvestment, and no deployer or protocol share.
| Case | Callback | Taken from |
|---|---|---|
| Token is the input | beforeSwap | The specified input amount |
| Token is the output | afterSwap | The token output delta |
| $LP24 side | — | Never taxed |
take() sends the fee directly to the dead address. It debits the caller — this hook — regardless of recipient, which clears the delta the callback returns, so one call both burns the tokens and settles the pool. Each burn emits SecondaryTokenBurn(token, amount).
Dispatch is by pool id: tokenOfPool[poolId] returns the zero address for any pool that is not one of ours, and the callbacks no-op. indexOfPool[poolId] records which currency slot the launched token occupies — its default of 0 is indistinguishable from "token is currency0", so tokenOfPool must always be checked first.
View Functions
| Function | Returns |
|---|---|
hasSecondary(token) -> bool | Whether a secondary pool exists |
secondaryPoolIdOf(token) -> bytes32 | Pool id, or zero if none exists |
nativeEarmark(token) -> uint256 | Native reserved but not yet consumed |
tokenOfPool(poolId) -> address | Reverse lookup, zero for foreign pools |
indexOfPool(poolId) -> uint8 | 0 if the token is currency0, 1 if currency1 |
getHookPermissions() -> uint256 | Permission bitmap for the venue |
Constants
| Constant | Base | BSC | Polygon | Robinhood |
|---|---|---|---|---|
SECONDARY_FEE_BPS | 60 bps (0.6%) | |||
SWAP_SLIPPAGE_BPS | 200 bps (2%) | |||
SECONDARY_TOKEN_RAW | 40,000,000 × 10⁹ (40M) | |||
SECONDARY_NATIVE_RAW | 0.4 ETH | 1.2 BNB | 9,600 POL | 0.4 ETH |
TICK_SPACING | 200 | |||
POOL_FEE | 0 — fees taken by the hook | |||