Auction Lifecycle
Every token launch on Runner Protocol follows a structured lifecycle managed by the Launchpad program's state machine. This page describes each phase, the on-chain instructions that trigger transitions, and the terminal states.
State Machine
The Launchpad tracks each launch's progress through a SettlementState enum with 11 variants:
There is no explicit AuctionActive state transition. Once start_slot is reached, the auction implicitly becomes active within the AuctionReady state. The CCA V2 engine enforces start_slot <= current_slot for bid placement.
Phase 1: Creation (3 Transactions)
Launch creation is split across three transactions to stay within Solana's compute and account limits:
Step 1: create_launch_step_1
Creates the LaunchConfig account and a Token-2022 mint with MetadataPointer extension.
- Who can call: Any signer (becomes the creator/authority)
- Validates: Protocol not paused, token allocations sum to 100%, quote mint is whitelisted, all parameters within protocol bounds
- Creates: LaunchConfig PDA, Token-2022 mint with on-chain metadata (name, symbol, URI)
- State after:
Created
The creator defines all auction parameters at this step: total supply, auction/LP/team BPS splits, floor price, max bid price, tick spacing, auction duration, supply schedule steps, and graduation threshold. A SHA-256 hash of the supply steps is stored for integrity verification in step 3.
Step 2: create_launch_step_2
Creates five escrow accounts and distributes the minted token supply.
- Who can call: Creator only
- Creates: Auction escrow, LP escrow, team escrow (Token-2022), proceeds escrow (SPL Token), fee escrow (System account with 0.15 SOL for Raydium pool fee)
- Mints and distributes:
auction_bps,lp_bps,team_bpsportions to respective escrows - State after:
EscrowsInitialized
Step 3: initialize_cca_auction
Calls into CCA V2 via five sequential CPI calls to set up the auction engine.
- Who can call: Creator only
- CPI calls:
initialize_auction,initialize_vaults,initialize_quote_vault,initialize_floor_tick,receive_tokens - Validates: Supply steps hash matches step 1, duration matches, start slot is reasonable
- Transfers: Auction tokens from auction escrow into CCA V2 base vault
- State after:
AuctionReady
Phase 2: Active Auction
Once the current Solana slot reaches start_slot, the auction becomes active. During this phase:
Bidding
Bidders call place_bid on the CCA V2 program directly, depositing quote currency and specifying their max_price. Each bid:
- Transfers quote tokens from bidder to the CCA quote vault
- Computes effective demand:
amount_q96 = raw_amount * Q96 * MPS / mps_remaining - Creates or updates a Tick at the bid's price level
- Creates a Bid PDA tracking the bidder's position
Bids are placed through the CCA V2 program, not the Launchpad.
Checkpoints
At each auction block interval, checkpoints must be created to advance the auction's clearing state. Checkpoint creation is permissionless -- anyone can call create_checkpoint, and the payer covers the account rent.
Checkpoints discover the clearing price by walking the tick linked list (see Price Discovery), update the settlement accumulators, and advance the auction's cumulative MPS counter.
In production, automated keeper bots handle checkpoint creation. There is an economic incentive to keep checkpoints current because it advances the auction state for all participants.
Bid Withdrawal Rules
- In-range bids (
max_price >= clearing_price): Cannot be withdrawn. This prevents strategic manipulation. - Out-of-range bids (
max_price < clearing_price): May be withdrawn by the bidder.
Phase 3: Graduation Check
An auction graduates when the total currency raised meets or exceeds the configured graduation threshold. Graduation is a computed property checked at finalization time:
is_graduated = currency_raised_q96_x7 >= required_currency_raised
The required_currency_raised threshold is set immutably at auction creation. The auction does not stop early when the threshold is met -- it continues running until end_slot to allow continued price discovery.
Phase 4: Settlement Pipeline
After the auction ends and has graduated, settlement proceeds through four sequential, permissionless steps. Each is a separate transaction that anyone can trigger.
1. finalize_auction
Reads the CCA V2 auction's final state and records it into the LaunchConfig.
- Who can call: Anyone (permissionless)
- Requires:
current_slot >= end_slot, auction graduated, settlement not paused - Records:
final_clearing_price,total_tokens_cleared,finalized_at,finalized_slot - State after:
Finalized
2. sweep_to_escrow
Transfers raised currency from CCA V2 vault to Launchpad proceeds escrow via CPI.
- Who can call: Anyone (permissionless)
- CPI: CCA V2
sweep_currency(transfers all quote from CCA vault to proceeds escrow) - Records:
total_proceedsfrom actual escrow balance (authoritative source) - State after:
ProceedsSwept
3. create_raydium_pool
Creates a Raydium CPMM liquidity pool and distributes proceeds.
- Who can call: Anyone (permissionless)
- Proceeds distribution:
total_proceeds
├── protocol_fee = proceeds * protocol_fee_bps / 10000 → treasury
└── remaining = proceeds - protocol_fee
├── lp_proceeds = remaining * lp_proceeds_bps / 10000 → Raydium pool
└── creator_proceeds = remaining - lp_proceeds → creator
- Pool creation: Raydium CPMM
initializevia rawinvoke_signed(typed CPI would overflow SBF stack) - LP token burn: All LP tokens received from pool creation are immediately burned
- State after:
PoolCreated
LP tokens are burned programmatically during pool creation. This makes the liquidity permanent and irremovable. There is no code path or admin function to retain LP tokens.
4. enable_claims
Enables bidder token claims and renounces mint authority.
- Who can call: Anyone (permissionless)
- Actions:
- Transfers team tokens from team escrow to creator's token account
- CPI to CCA V2
set_claim_slot(sets to current slot, enabling claims) - Renounces Token-2022 mint authority (
set_authoritytoNone)
- State after:
Settled(terminal success)
Token claims are intentionally disabled until the liquidity pool is created. This prevents an attack where bidders could claim tokens early and create a competing pool at a manipulated price, undermining the auction-discovered fair price.
Terminal States
| State | Meaning | How Reached |
|---|---|---|
| Settled | Success. Pool created, claims enabled, mint authority renounced. | enable_claims after full settlement pipeline |
| Cancelled | Creator cancelled before auction started. All tokens returned. | cancel_launch from Created or EscrowsInitialized |
| FailedRecovery | Auction did not graduate. Tokens recovered, bidders get full refunds. | recover_failed_auction after auction ends without graduating |
| EmergencyWithdrawn | Settlement stalled past timeout. Emergency escape hatch triggered. | emergency_withdraw after finalized_slot + emergency_timeout_slots |
Cancellation
The creator can cancel a launch at any point before the auction's start_slot:
- Returns all tokens from escrows to creator
- Returns fee escrow lamports
- Closes all escrow accounts (rent recovery)
- Only the creator can cancel; checked via
authority == creator.key()
Failed Auction Recovery
If an auction ends without graduating:
- CPI to CCA V2
sweep_unsold_tokensreturns all base tokens to auction escrow (100% unsold since non-graduated) - All escrow tokens transferred to creator
- Mint authority renounced
- Bidders recover their quote currency directly from CCA V2 via
exit_bid(non-graduated = full refund)
Emergency Withdrawal
A safety valve for when settlement stalls. If any settlement step fails permanently (e.g., external program upgrade breaks CPI compatibility), the timeout ensures funds are never locked forever.
- Trigger:
current_slot > finalized_slot + emergency_timeout_slots - Permissionless: Anyone can trigger. Creator does not need to sign.
- Timeout is immutable: Snapshotted into LaunchConfig at creation time. Admin cannot change it retroactively.
- Mint authority renounced even in the emergency path.
Idempotent Settlement
Settlement instructions are idempotent: if the state is already at or past the target state, they return Ok(()) without error. This means calling finalize_auction on an already-finalized launch is safe and does not revert, simplifying keeper bot implementation.