Documentation
Launching a token
There are two ways in, and they differ only in whether the creator buys in the same transaction.
factory.launchToken | launchAndBuy.launchAndBuy | |
|---|---|---|
| Opening buy | none | required, quoteIn must be non-zero |
Native HYPE msg.value | exactly launchFee() | launchFee() + quoteIn |
| ERC-20 quote | msg.value is the fee | msg.value is the fee; approve the router for quoteIn |
| Returns | token | (token, tokensOut) |
Use launchAndBuy if the creator wants tokens at all. A separate buy afterwards is a race against
everyone watching the chain, on a pool that opens at its lowest price.
launchAndBuy needs the router to be the factory's launchForwarder. It can be switched off in an
emergency, so check GET /v1/protocol → launchAndBuy.enabled before offering it. Plain
launchToken keeps working either way.
TokenParams#
| Field | Rule |
|---|---|
name | 1 to 31 bytes, no NUL byte. Immutable |
symbol | [A-Z0-9], 1 to 6 characters, unique across Tartarus. Immutable |
logo | At most 512 bytes. A URL, not image data |
description | At most 2,048 bytes |
socials | twitter, telegram, discord, website, farcaster; each at most 256 bytes, may be empty |
creatorFeeRecipient | Zero means the caller. HOLDER_REWARDS means the token's holders. Anything else is used as given |
creatorFeeBps | Your tranche in basis points, inside the hook's bounds: 50 to 950 today |
expectedEconomics | From previewLaunchEconomics. Zero waives the check |
salt | A random 32 bytes. See below |
All limits are in UTF-8 bytes, not characters, so an emoji in a name costs four.
creatorFeeBps has no default worth relying on. Leaving it at zero is outside the bounds and reverts
CreatorFeeOutOfBounds, so a launch can never land on a rate nobody chose.
The ticker#
Symbols are unique because HyperCore tickers are. Whoever lands first owns the ticker for good. These
are reserved and can never be used: HYPE, USDC, USDT, USDE, USDH, PURR, BTC, ETH,
SOL, UBTC, UETH, USOL, HFUN. The owner can reserve more.
Check before you show a form:
const free = await client.readContract({
address: FACTORY, abi: factoryAbi, functionName: "isSymbolAvailable", args: ["MINE"],
});GET /v1/launch/symbol?symbol=MINE gives the same answer with a reason: ok, invalid, reserved
or taken.
The salt and the token address#
The token address is CREATE2, salted with
keccak256(abi.encode(deployer, salt, creatorFeeRecipient, creatorFeeBps, launchConfigId)), and the
metadata is part of the creation code. So:
- your salts are your own, and nobody can land a launch at an address derived from your account;
- an address commits to exact terms, so a vanity salt only works for the recipient, tranche, config and metadata it was mined for.
Do not compute the address by hand. Call deployer.predictLaunchAddress, or POST /v1/launch/predict
with a session, which also returns the pool key and floor price so you can draw the token before it
exists.
For a holder-rewards launch, use a fresh salt every time. A distributor's address depends only on
creator, salt and quote, so reusing one reverts HolderRewardsDistributorTaken.
expectedEconomics#
The digest is:
keccak256(abi.encode(quoteToken, startingTick, tickSpacing,
protocolFeeBps, creatorFeeBps, maxInternalPriceImpactBps, launchFee))previewLaunchEconomics(configId, creatorFeeBps) computes it. If any input moves between your read
and your transaction, the launch reverts with LaunchEconomicsMismatch(expected, actual).
Metadata cannot be fixed later#
Everything on the token is permanent. The contract has no setter, and the name and symbol must never change because Elysium's bridge keys a token's mirror on them. Check spelling, the ticker and the logo before you sign.
What can change is creatorFeeRecipient: the current recipient can hand it on with
factory.transferCreatorFeeRecipient(token, newRecipient). The creator tranche itself is frozen.
Common reverts#
| Error | Meaning |
|---|---|
NotWhitelisted / NotApprovedLauncher | Launching is closed and you are not whitelisted |
IncorrectLaunchFee / WrongValue | msg.value is not exactly right. Re-read launchFee() |
LaunchConfigDisabled / InvalidLaunchConfigId | That config is off or does not exist |
QuoteTokenNotApproved | The config's quote is no longer approved |
InvalidName / InvalidSymbol / MetadataTooLong | A TokenParams rule above |
SymbolReserved / SymbolTaken(address) | The ticker is unavailable |
CreatorFeeOutOfBounds(bps, min, max) | Your tranche is outside the bounds |
LaunchEconomicsMismatch(expected, actual) | Terms moved. Re-read and show the user the new ones |
RewardsFactoryNotSet | HOLDER_REWARDS used before the rewards factory was wired |
HolderRewardsDistributorTaken(address) | Salt reused for holder rewards. Use a new one |
ZeroBuy | launchAndBuy with quoteIn of zero. Use launchToken |
CreatorFeeOutOfBounds comes from the hook, so a client holding only the factory ABI sees the raw
selector 0x87ab5572. Decode with the combined tartarus.json from the ABI page,
or look any selector up on the Errors page.