Skip to main content
LaunchFactory.createLaunch is the one call that brings a token into existence. It reads the currency from the registry, converts the configured dollar depth into the launch currency at the oracle rate, deploys the token and a minimal-proxy curve, seeds the curve with the whole supply and, when asked, executes the creator’s first buy in the same transaction. Source: contracts/src/launch/LaunchFactory.sol (Ownable2Step, ReentrancyGuard) and contracts/src/launch/LaunchToken.sol. Addresses: Addresses.

Structs

Deployed configuration

With these numbers every curve starts at a 6,000 USD virtual depth and graduates after raising 12,000 USD in its currency (virtualQuoteUsd * curveSupply / virtualToken). See Units for a worked example.

createLaunch

1

Resolve the currency

registry.requireEnabled(p.code) returns the CurrencyConfig or reverts (UnknownCurrency, CurrencyDisabled).
2

Push the price and size the curve

priceUpdate is forwarded to the registry’s oracle with exactly oracle.updateFee(priceUpdate) of msg.value; less reverts InsufficientFee, more is refunded (RefundFailed if the refund fails). With the keeper oracle pass [] and no value. Then oracle.peekRate(p.code) (no age check, so a launch can be created while the FX market is closed) gives r, and virtualQuote = virtualQuoteUsd * r / 1e18 in 18-decimal quote units.
3

Deploy

Clones.clone(curveImplementation) creates the curve; new LaunchToken(name, symbol, curve, totalSupply) mints the whole supply to it; curve.initialize(Init{...}) copies the config, the quote asset, the code and msg.sender as creator. The curve computes its own graduationQuote.
4

Record and emit

The Launch is appended (index = launchCount() before the call), indexOfToken[token] and indexOfCurve[curve] are set to index + 1, and LaunchCreated then LaunchMetadata are emitted.
5

Optional first buy

When p.initialIn > 0: if payInUsdc and the quote asset is not the dollar, the currency must be tier 2 (UseQuoteAsset otherwise); the factory pulls initialIn dollars, mints the synthetic through the vault with minSynthOut = 0 and an empty price update, and buys with the minted amount. Otherwise it pulls initialIn of the quote asset directly. The buy goes to msg.sender with p.minTokensOut as the floor (Slippage from the curve); any quote the curve did not take (the last buy is capped at graduation) is returned to the creator in the quote asset.
Approvals before calling: initialIn of the dollar to the factory when payInUsdc, else initialIn of the quote asset (EURC for a EUR launch, the synthetic for a tier-2 launch paid in kind). USD launches always pay in the dollar; payInUsdc is irrelevant for them. A launch can be created by any account; there is no allowlist and no creation fee beyond gas. Names and symbols are not validated on chain (the app limits them to 64 and 11 characters).

Views

Curves read poolManager, positionManager, permit2, locker, feeCollector, poolFee and tickSpacing from the factory at graduation and fee-sweep time (ILaunchFactoryView), so those values apply to every launch, including ones created earlier, at the moment it graduates.

Owner functions

The same bounds are enforced again by BondingCurve.initialize. The owner cannot touch a live curve’s fees, supply, price or reserve.

LaunchToken

A plain OpenZeppelin ERC-20 with 18 decimals whose entire supply is minted to the curve in the constructor. No owner, no mint, no burn hook, no transfer tax, no blocklist, no pause. Holdings of the curve, the Uniswap PoolManager and the burn address are excluded from the indexer’s holder counts.

Events

virtualQuote in LaunchCreated is in 18-decimal quote units. The indexer creates its launch row from these two events and starts following the new curve and token addresses (see Launches query).

Errors

Reverts from the registry (UnknownCurrency, CurrencyDisabled), the vault (Slippage, LiabilityCapExceeded, StalePrice, paused) and the curve (Slippage) bubble up unchanged.

Metadata

metadataURI is opaque to the contracts. The app encodes { name, description, image } as data:application/json;base64,..., with the image itself a small WebP data URL (at most 20 KB after client-side cropping), so a launch’s artwork lives on chain with no external host. Integrators may store any URI (IPFS, HTTPS); the app resolves ipfs:// through a public gateway and treats anything it cannot parse as absent.