Launching a coin
Two wallet prompts. The first publishes your coin; the second opens its pool, seeds it with the whole float, locks the position and records the launch. If the second fails, none of it happened — and the coin from the first is still in your wallet, ready to try again.
What you choose
| what it is | bounds | |
|---|---|---|
| name / symbol | written into the coin's Currency in Sui's coin registry, permanently | name 1–32 characters, symbol 1–10 printable ASCII |
| description / logo | also permanent; the logo is an https link, pinned to IPFS by the interface | description up to 280 characters |
| links | website and socials, stored on the launch record as a small JSON document | at most 1,024 bytes; never read on-chain |
| pair asset | what your coin trades against | anything the launchpad does not refuse — see Pair assets |
| fee tier | the pool fee on every trade | 1% (tick spacing 200) or 2% (tick spacing 220) |
| creator premine | share of supply sent straight to you | 0 by default, hard-capped at 20% |
| dev buy | pair asset spent buying your own coin as the pool's opening trade | from a few base units up to just short of the whole float |
| fee routing | what happens to your share of fees — see Fees | keep it, or buy back and burn; changeable later |
| fee recipient | where your share goes | defaults to the launching wallet; changeable later |
What you do not choose:
- Supply is 1,000,000,000 coins at 9 decimals, for every coin. It is a constant in the template, not a field, so no two coins launched here differ in anything but their four strings.
- The top of the range is always the last usable tick. There is no ceiling to set.
- The opening valuation is the same for every launch in the interface: a $4,000 market cap, converted into the pair asset at its live price. The contract takes a tick and would accept any; the interface fixes the number because it is denominated in the pair asset, and a figure typed against USDC and the same figure typed against CETUS are orders of magnitude apart.
The launch fee is 2 SUI, paid to the treasury in the second transaction. The contract caps it
at 100 SUI (MAX_LAUNCH_FEE), so it can never quietly become a tax, and returns whatever you send
above it.
The two prompts
1 — publish. Nothing is compiled per coin. The interface takes the template's checked-in bytecode,
renames its module and one-time witness after your symbol ($WAVE becomes …::wave::WAVE), swaps
your strings in for the placeholders with @mysten/move-bytecode-template, and asks your wallet to
publish it and call 0x2::package::make_immutable on the resulting UpgradeCap. When it lands you hold the entire
supply, and the coin's Currency<T> is waiting in the registry for its final registration.
2 — launch. One programmable transaction:
coin_registry::finalize_registration<T> if the Currency is still pending
<Cetus aggregator swap: SUI → pair asset> if you pay for the dev buy in SUI
launchpad::launch_as_a<T, Q> / launch_as_b<T, Q>
finalize_registration is permissionless, so somebody else may have done it already; the interface
checks rather than assumes. The swap, when present, carries a 1% slippage bound, and its output
becomes the seed — so there is no moment at which you hold the pair asset and the launch has not
happened.
The dev buy
The seed you pass is the dev buy, computed on-chain along the position's own curve — see What it is. Before it moves the price, two things come off it:
- The protocol's share of the pool fee the computed trade does not pay:
seed × fee rate × (1 − creator share), which is 0.2% of the seed at the 1% tier. - A rounding margin of
seed / 1000 + 10base units, held back from the price computation because Cetus rounds the first deposit's pair-asset requirement up. Whatever is not needed comes back to you in the same transaction.
min_coins_out is the least the dev buy may return. It is not protection from other traders —
nobody can trade before this, because the pool does not exist yet. It guards against the chain and
the interface disagreeing: the launchpad's creator share changing between preview and signing, or
the aggregator swap delivering less than planned. The interface's preview replays the contract's
arithmetic exactly (previewLaunch in the SDK), so it sets the bound 2% under the preview rather than
guessing at slippage.
A launch with no dev buy still needs a seed: the few base units that open the pool inside the range. They buy you a sliver of coin, which is correct — that is what they would buy.
Which side of the pair
Cetus requires a pool's coin A to sort above coin B by type name, and your coin's type name starts with its freshly published package address. So which function the launch calls is read off the chain after the first prompt, not chosen:
factory::is_right_order<T, Q>() | the call | pool | price reads as |
|---|---|---|---|
| true | launch_as_a | Pool<T, Q> | pair asset per coin; buys move it up |
| false | launch_as_b | Pool<Q, T> | coin per pair asset; buys move it down |
Against SUI it is always launch_as_a. The boundary tick flips with the side — the bottom of the
range for coin A, the top for coin B — and the SDK's boundaryTick and previewLaunch handle both,
including pair assets that do not have 9 decimals. USDC has 6 and BLUB has 2; a tick is a ratio of
raw units, so getting that correction wrong by hand opens a launch orders of magnitude off.
What can go wrong
A launch aborts with one of the launchpad's errors, named in the wallet and the explorer:
| abort | what happened |
|---|---|
EPaused | the owner has paused launches (set_paused); fee collection is unaffected |
EQuoteNotAllowed | the launchpad's registry refuses this pair asset |
ETickSpacingNotAllowed | that fee tier is not offered |
ECreatorShareTooHigh | premine above 20% |
EBadFeeRoute | a fee route other than 0 (wallet) or 1 (buyback-burn) |
EMetadataTooLong | links above 1,024 bytes |
EAlreadyLaunched | this coin already has a launch — against any pair asset, at any tier |
EWrongSide | launch_as_a for a coin that sorts below its pair asset, or the reverse |
EInsufficientLaunchFee | the fee coin is below the launch fee, which may have changed since the page loaded |
ETickNotAligned | the boundary tick is not a multiple of the tick spacing |
ETickOutOfRange | the boundary tick leaves no room for a range before the edge of the pool |
EZeroSupply | the supply coin is empty |
ESeedTooSmall | the seed cannot move the price off the boundary, or is not larger than its own rounding margin |
ESeedTooLarge | the seed would buy the entire float |
EDevBuyBelowMinimum | the dev buy would return less than min_coins_out |
EWrongVersion | the Launchpad object and the package disagree on version — an upgrade without migrate |
And a few can come from Cetus inside the same call:
| Cetus abort | what happened |
|---|---|
config::EPackageVersionDeprecate | Cetus retired the version the launchpad links against, or paused itself; the launchpad needs an upgrade (see Contracts) |
factory::EPoolAlreadyExist | a pool for this coin, pair asset and tier already exists. Opening one takes some of the coin, which only you hold — unless you have sent some away |
factory::ECoinTypeNotAllowed | Cetus has put the coin or the pair asset on its deny list for new pools |
None of these cost more than gas. Every abort undoes the whole second transaction: the supply, the seed and the fee stay in your wallet, and the coin can still be launched.

