Factory
The entry point. Deploys the protocol pair once, then user token + bonding curve pairs with vanity enforcement. Also owns the deployer-token registry and the curve registry that the hooks trust.
Singleton — one per chain. No owner. The only privileged address is system_deployer, which can call deploy_protocol_token exactly once and has no other power.
Deployment Functions
deploy_pair(name: String[64], symbol: String[32], salt: bytes32, packed_socials: bytes32 = empty(bytes32)) -> (address, address) external payableDeploy a token + bonding curve pair. Returns (token, curve). Anyone can call once the protocol token exists.
Must equal the chain's deployment_fee exactly — Base 0.06 ETH, BSC 0.18 BNB, Polygon 1,440 POL, Robinhood 0.06 ETH, Gnosis 144 xDAI. Forwarded in full to the bonding curve.
"Protocol token not yet deployed"—deploy_protocol_tokenhas not run"Incorrect fee"—msg.value != deployment_fee"Invalid name/symbol"— either is empty"Invalid salt"— anchor block is zero"Anchor not mined"—block.number <= anchor_block"Too late"— past the inclusion window"Blockhash unavailable"— anchor more than 256 blocks back"Blockhash mismatch"— salt's committed prefix does not match"Vanity miss"— resulting address does not start0x24
PairDeployed(token, curve, deployer, name, symbol, packed_socials)
deploy_protocol_token(name: String[64], symbol: String[32]) -> (address, address) externalDeploy the protocol token pair. System deployer only, callable once. Uses CREATE rather than CREATE2, so the address depends only on this factory and its internal nonce. No fee, no socials registration; the initial mint goes to the vesting contract.
"Not system deployer""Protocol already deployed"— permanent one-shot lock"Invalid name/symbol"
ProtocolPairDeployed(token, curve, deployer, name, symbol)
Deployer Registry
moveDeployerToken(token: address, old_deployer: address, new_deployer: address) externalMove a token between deployer enumerations on CTO finalization. Callable only by the primary hook / graduation manager. O(1) swap-and-pop on the old owner, append on the new.
"Only hook"— caller is not the registered hook
getDeployerTokens(deployer: address) -> DynArray[address, 1024] viewEvery token an address has ever launched, in any state. Intended for off-chain eth_call — the array can be large.
getDeployerTokenCount(deployer: address) -> uint256 viewNumber of tokens launched by an address.
getDeployerTokenAt(deployer: address, i: uint256) -> address viewPaginated access, so on-chain callers never materialize the full array.
"Index OOB"
Combining getDeployerTokens() with each curve's is_graduated() / is_refund_mode() gives a deployer's graduation success rate without any indexer. The cap is 1,024 tokens per address; storage cost is per token held, not per cap, so the ceiling is effectively free.
View Functions
| Function | Returns |
|---|---|
is_curve(addr) -> bool | True only for curves this factory deployed. The hook gates graduation on it; any interface or indexer should gate token loading on it to reject cloned or self-registered tokens. |
tokensByDeployer(addr) -> DynArray | Public mapping accessor, same data as getDeployerTokens |
protocol_deployed() -> bool | Whether the one-shot protocol deploy has run |
protocol_token() -> address | $LP24 address |
protocol_curve() -> address | $LP24's bonding curve |
get_config() -> (address, address, address) | (token_master, bonding_curve_master, token_socials) |
get_deployment_fee() -> uint256 | Chain deployment fee in wei |
get_token_socials() -> address | TokenSocials address |
get_system_deployer() -> address | The one-shot protocol deployer key |
Constants
| Constant | Base | BSC | Polygon | Robinhood | Gnosis |
|---|---|---|---|---|---|
VANITY_PREFIX | 36 (0x24) | ||||
MAX_DEPLOYER_TOKENS | 1,024 | ||||
deployment_fee | 0.06 ETH | 0.18 BNB | 1,440 POL | 0.06 ETH | 144 xDAI |
INCLUSION_WINDOW | 10 blocks | 44 blocks | 12 blocks | 200 blocks | 5 blocks |