Maelstrom
Launch coin

What it is

Most launchpads price a new coin in the chain's gas token. This one prices it in another coin — SUI if you like, but just as well USDC, a wrapped bitcoin, DEEP, a memecoin or tokenised treasuries: anything with a real market on Sui. A coin that trades against WAL, where every buy is paid in WAL, is a sentence this makes executable.

A launch, step by step

Two wallet prompts.

  1. Your coin is published. A coin type on Sui needs a Move module of its own, so your wallet publishes one: the launchpad's coin template with your name, symbol, description and logo written in. Its init mints 1,000,000,000 coins once, sends all of them to you, and gives up the ability to mint more or change the metadata. The same transaction makes the package immutable.
  2. Its pool is opened and locked. One programmable transaction finishes the coin's entry in Sui's coin registry (coin_registry::finalize_registration, if nobody has yet), swaps SUI into the pair asset through the Cetus aggregator if you are paying for your dev buy in SUI, and calls launchpad::launch_as_a or launch_as_b. That call opens a Cetus pool for (your coin, pair asset), deposits the entire float as one position, locks the position, and sends you your premine and your dev buy.

If any part of the second transaction fails, none of it happened. Between the two, the coin exists and sits in your wallet — nobody else holds any of it, so nobody else can open a pool for it.

Why the pool opens with a sliver of the pair asset

A concentrated-liquidity range that sits entirely on one side of the current price needs only one of the two assets. That would let a launch deposit nothing but the coin. Cetus does not allow a pool to be created that way: pool_creator::create_pool_v3 insists that the opening price is strictly inside the range and that both sides of the first deposit are non-zero.

So the pool opens a hair inside the range, and a small amount of the pair asset — the seed — pays for that hair. The seed can be a handful of base units; the interface works out the smallest one that opens the pool and adds a margin.

The dev buy is the seed

Cetus shares a new pool inside the call that creates it, so nothing later in the same transaction can trade against it. A real first buy would have to be a second transaction — and anyone watching could buy in front of it.

So the launch computes the first trade instead of making it:

  • the position is sized from the float as if the pool opened exactly at the bottom of the range;
  • the seed moves the price along that same curve, exactly as a swap of that size would;
  • the coins that swap would have released are yours;
  • and the pool opens at the post-trade price, holding precisely what it would hold after the trade.

The resulting state is the state a real first buy would leave. Nobody can trade before it, because the pool does not exist until the transaction lands. A test, the_computed_dev_buy_matches_a_real_first_trade, launches one coin with a dev buy and a twin with almost none, buys the twin's pool through Cetus for the same net amount, and requires the two to agree to within a hundredth of a percent.

The one thing a computed trade does not do is pay the pool fee, so the launch charges the protocol's share of it explicitly — see Fees. Buying nothing is allowed: the seed is then just the sliver, and buys you almost nothing.

Why the liquidity can never be pulled

On Sui a Cetus position is an object, cetus_clmm::position::Position, and whoever holds it by value can close it and take the liquidity out. So the question is who holds it.

Nobody does. The launch puts it inside a Locker from vortex_locker::locker, a package made immutable right after it was published. That module has one function that takes a position in (lock) and none that gives it back: the only thing it ever hands out is &Position, an immutable reference. Every Cetus function that moves principal needs the position by value (close_position) or by mutable reference (add_liquidity, remove_liquidity); the two that accept &Position are collect_fee and collect_reward, which pay out what the position earned and cannot touch what it holds. In Move only the module that defines a struct can take it apart, so no other code — including any future version of the launchpad — can reach inside a Locker.

Only the swap fees the position earns can ever be taken out. Contracts states the limits of that sentence plainly: the launchpad package itself stays upgradeable, and Cetus's own administrators keep powers over every Cetus pool.

Which side of the pool you land on

Cetus orders a pool's two coins by their type names, and your coin's type name begins with the address of the package your wallet just published — effectively random. Coin A must sort above coin B. SUI's type name is 0x2 padded with sixty-three zeros, so a freshly published coin sorts above it and a launch against SUI is coin A, for every practical purpose always; against anything else it is a coin toss the chain decides, and the launch reads the answer off rather than choosing.

your coin israngeprice reads asbuying moves the price
coin A (launch_as_a)boundary tick → last usable tickpair asset per coinup
coin B (launch_as_b)first usable tick → boundary tickcoin per pair assetdown

Everything else is identical, and the interface shows both as a price in the pair asset.

Why there is no price ceiling

Your range is literally the set of prices your float is offered at. Stop it early and the coin hits a wall: at the top of the range the last coin is gone, nobody can ever buy again, and the quoted price runs off to the edge of what a pool can express.

So the range always runs to the last usable tick — the far end is not a parameter. It also makes the curve easy to reason about: buying the first half of the float costs almost exactly what the whole float was worth at the opening price, and quadruples the price on the way.

The consequence worth understanding: a new coin's pool holds almost none of the pair asset. Until somebody buys, there is next to nothing on the pair-asset side, so a freshly launched coin can barely be sold before it has been bought. Buyers bring the pair asset as they trade in; the market funds itself.