Skip to main content

Documentation Index

Fetch the complete documentation index at: https://continuum-ec12e897.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

mint_paired(collateral_amount) is the canonical user-facing entry. It deposits cUSDC, mints L and S to the user’s ATAs, and sends fees to the configured fee recipient.

Math

fee         = collateral_amount × mint_fee_bps / 10_000
half_value  = (collateral_amount - fee) / 2
qty_L       = half_value / L_NAV
qty_S       = half_value / S_NAV

L_NAV       = market.user_twap_price (or initial_l_price if TWAP == 0)
S_NAV       = (initial_l × initial_s) / L_NAV
In Normal risk state with no confidence markup, qty_L × L_NAV + qty_S × S_NAV = collateral_amount - fee. Trivially.

Accounts required

AccountNotes
marketMarket PDA
user (signer)Pays collateral_amount
user_collateralUser’s cUSDC ATA (must exist; create via getAssociatedTokenAddressSync + ATA program if missing)
user_longUser’s L ATA (created if missing)
user_shortUser’s S ATA (created if missing)
long_mintFrom market.long_mint
short_mintFrom market.short_mint
collateral_vaultFrom market.collateral_vault
dev_token_accountFee recipient’s cUSDC ATA
oracle_addressFrom market.oracle_address
token_programSPL Token program
The frontend’s useMint() hook resolves all of this from the symbol. For a copy-pasteable script see Build → Mint and redeem example.

TypeScript

import { Program, BN } from "@coral-xyz/anchor";
import { PublicKey } from "@solana/web3.js";
import {
  getAssociatedTokenAddressSync,
  TOKEN_PROGRAM_ID,
  ASSOCIATED_TOKEN_PROGRAM_ID,
  createAssociatedTokenAccountInstruction,
} from "@solana/spl-token";
import idl from "./mint_redeem.json";

const program = new Program(idl, provider);
const symbol = "QQQ";

// Derive market PDA
const [marketPDA] = PublicKey.findProgramAddressSync(
  [Buffer.from("market"), Buffer.from(symbol)],
  program.programId,
);

// Fetch market for child accounts
const market = await program.account.market.fetch(marketPDA);

// User ATAs
const userCusdc = getAssociatedTokenAddressSync(market.collateralMint, wallet.publicKey);
const userLong  = getAssociatedTokenAddressSync(market.longMint, wallet.publicKey);
const userShort = getAssociatedTokenAddressSync(market.shortMint, wallet.publicKey);
const devCusdc  = getAssociatedTokenAddressSync(market.collateralMint, market.feeRecipient);

// Build the tx
const amount = new BN(100_000_000); // 100 cUSDC

const ix = await program.methods
  .mintPaired(amount)
  .accounts({
    market: marketPDA,
    user: wallet.publicKey,
    userCollateral: userCusdc,
    userLong: userLong,
    userShort: userShort,
    longMint: market.longMint,
    shortMint: market.shortMint,
    collateralVault: market.collateralVault,
    devTokenAccount: devCusdc,
    oracleAddress: market.oracleAddress,
    tokenProgram: TOKEN_PROGRAM_ID,
  })
  .instruction();

// You may need to prepend ATA creation instructions if longATA/shortATA don't exist yet:
const preIxs = [];
const longInfo = await connection.getAccountInfo(userLong);
if (!longInfo) {
  preIxs.push(
    createAssociatedTokenAccountInstruction(
      wallet.publicKey,
      userLong,
      wallet.publicKey,
      market.longMint,
    ),
  );
}
// (do the same for userShort)

const tx = new Transaction().add(...preIxs, ix);
const sig = await provider.sendAndConfirm(tx);

Minimum mint size

Enforced by the program: 10 cUSDC (10_000_000 lamports). Below this, you get BelowMinimum. This exists to keep the post-fee residual computable without precision issues - at 1 cUSDC mint, the 0.1% fee rounds to lamport boundaries that produce zero L/S in some markets.

Errors

ErrorCause
MarketNotActivemarket.is_active = false
InvalidAmountcollateral_amount = 0
BelowMinimumLess than 10 cUSDC
InsufficientCollateralUser’s cUSDC ATA balance < collateral_amount
OraclePriceUnavailableOracle account stale or paused
MintNotAllowedInStressRisk state is Stress
ExceedsStressMintCapRisk state is ProxyMode / Recovery and amount exceeds the throttled cap
OICapExceededtotal_l_supply + l_to_mint > oi_cap
MathOverflowShould be unreachable; report if you see this
Full error catalog

Behavior across risk states

Risk stateBehavior
NormalMint at NAV, no markup, no size throttle.
ProxyModeMint with 2× confidence markup, size-throttled.
StressMint rejected.
RecoveryMint at NAV, size-throttled.
Risk states

Optional: mint_paired_with_waiver

A variant that consumes a fee-waiver against the user’s FeeWaiver PDA, if active. Saves the mint fee but only works when the user has previously called donate_to_vault to acquire a waiver and the market vault is over-collateralized (>102%). This is an advanced flow used by power users. Most integrations stick with mint_paired.

What you receive

After a successful mint:
User cUSDC ATA: -collateral_amount
Vault cUSDC:    +(collateral_amount - fee)
Dev cUSDC ATA:  +fee
User L ATA:     +qty_L
User S ATA:     +qty_S

market.total_l_supply: += qty_L
market.total_s_supply: += qty_S
market.total_collateral: += (collateral_amount - fee)
The L and S tokens are SPL tokens. They are transferable, depositable into Meteora pools, usable in CPI by other programs. There’s no special locking, lockup, or hold period.

See also

Redeem

The inverse: burn paired tokens, receive cUSDC at NAV.

End-to-end TypeScript example

Copy-pasteable script with wallet setup, IDL load, mint, verify.