> ## Documentation Index
> Fetch the complete documentation index at: https://continuum-ec12e897.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# mint-redeem

> User-facing mint and redeem at NAV. Keeper-only single-sided instructions. Market lifecycle.

The user-facing entry to Continuum. Holds the `Market` PDA, mints L+S SPL tokens, and exposes the privileged keeper-only single-sided ixns used inside arb cycles.

```
Devnet ID: 5MBjhNUUguLTPNR5WG6YBUUw7vUcxQ14ARw3NsS3rKu4
```

## Accounts

### `Market` PDA

```
seeds = [b"market", asset_symbol_bytes]
```

The central account for one synthetic asset.

| Field                                                                                 | Type    | Purpose                                                                                                                                                                                                                      |
| ------------------------------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `authority`                                                                           | Pubkey  | Admin signer for `update_market`                                                                                                                                                                                             |
| `fee_recipient`                                                                       | Pubkey  | Receives mint/redeem fees (cUSDC ATA)                                                                                                                                                                                        |
| `asset_symbol`                                                                        | string  | Market ticker (e.g., `"QQQ"`)                                                                                                                                                                                                |
| `oracle_address`                                                                      | Pubkey  | Pointer to `OracleConfig` PDA                                                                                                                                                                                                |
| `oracle_type`                                                                         | enum    | `Pyth` / `Hermes` / `Switchboard` / `Manual`                                                                                                                                                                                 |
| `long_mint`                                                                           | Pubkey  | L SPL mint                                                                                                                                                                                                                   |
| `short_mint`                                                                          | Pubkey  | S SPL mint                                                                                                                                                                                                                   |
| `collateral_mint`                                                                     | Pubkey  | cUSDC mint                                                                                                                                                                                                                   |
| `collateral_vault`                                                                    | Pubkey  | Points at the **one unified** cUSDC vault (owned by the `CollateralAuthority` PDA), shared by all markets                                                                                                                    |
| `multi_collateral_enabled`                                                            | bool    | If true, multiple collateral types accepted                                                                                                                                                                                  |
| `mint_fee_bps` / `redeem_fee_bps`                                                     | u16     | Fees in basis points (10 = 0.10%)                                                                                                                                                                                            |
| `total_l_supply` / `total_s_supply`                                                   | u64     | Outstanding supply (6 decimals)                                                                                                                                                                                              |
| `total_collateral`                                                                    | u64     | This market's collateral **ledger** (6 decimals). With the unified vault this scalar (not the live token balance) is the per-market solvency source of truth; per-market isolation = `total_collateral − deployed_to_yield`. |
| `is_active`                                                                           | bool    | If false, all mint/redeem reject                                                                                                                                                                                             |
| `risk_state`                                                                          | enum    | `Normal` / `ProxyMode` / `Stress` / `Recovery`                                                                                                                                                                               |
| `risk_state_updated_at`                                                               | i64     | Last mirror update unix-ts                                                                                                                                                                                                   |
| `user_twap_price`                                                                     | u64     | Source of `L_NAV` (6 decimals)                                                                                                                                                                                               |
| `twap_updated_at`                                                                     | i64     | Last TWAP write unix-ts                                                                                                                                                                                                      |
| `oracle_confidence`                                                                   | u64     | Last published confidence (6 decimals)                                                                                                                                                                                       |
| `keeper_authority`                                                                    | Pubkey  | Privileged signer for fee-free single-sided ops                                                                                                                                                                              |
| `dev_tax_pct`                                                                         | u8      | Slice of the fee routed to fee\_recipient (default 10%)                                                                                                                                                                      |
| `buffer_target_bps`                                                                   | u16     | Keeper-posted dynamic overcollateralization buffer (bps over parity)                                                                                                                                                         |
| `s_gamma_index`                                                                       | u64     | Short-leg volatility-decay scalar, 1e9 fixed (`1e9` = 1.0 = no decay; `0`/unset reads as 1.0). Multiplies `S_NAV`. Ratchet-down only, floored at `0.5`. See [NAV → Volatility decay](/concepts/nav#volatility-decay).        |
| `yield_ceiling_bps` / `deployed_to_yield` / `yield_enabled` / `total_yield_harvested` | various | Collateral-yield management state                                                                                                                                                                                            |

### `UserCollateralPosition` PDA

```
seeds = [b"user_collateral", owner, market]
```

Lazy account for users who opt into multi-collateral mode (where the market accepts more than one collateral type, weighted). Most markets don't use this.

| Field                          | Type   | Purpose                               |
| ------------------------------ | ------ | ------------------------------------- |
| `owner`                        | Pubkey | Position owner                        |
| `market`                       | Pubkey | Bound market                          |
| `long_amount` / `short_amount` | u64    | Outstanding L+S held by this position |
| `collateral_type`              | enum   | Which collateral was used             |
| `collateral_mint`              | Pubkey | Which mint                            |
| `collateral_amount`            | u64    | Total cUSDC-equivalent deposited      |

### `FeeWaiver` PDA

```
seeds = [b"fee_waiver", donor, market]
```

A grant created by `donate_to_vault` that lets the donor mint/redeem fee-free for some duration.

| Field                  | Type   | Purpose                         |
| ---------------------- | ------ | ------------------------------- |
| `donor`                | Pubkey | Waiver owner                    |
| `market`               | Pubkey | Bound market                    |
| `waiver_end_at`        | i64    | Expiry unix-ts                  |
| `total_donated`        | u64    | Cumulative donation             |
| `total_gap_closed_bps` | u64    | Cumulative fee-equivalent saved |

## Fees

Base mint and redeem fees are **10 bps** each. The keeper posts vol-informed updates through the admin-signed `update_market`: `fee = clamp(max(10, fee_mult × q90), 10, 100)` bps, where `q90` is the market's trailing realized move quantile - 10 bps in calm regimes, up to 100 bps in storms. The fee is the at-NAV venue's defense against gap risk; it moves with measured volatility, not a forecast.

The split: `dev_tax_pct` (default 10%) of each fee goes to the `fee_recipient`'s cUSDC account; the remaining \~90% stays in the collateral vault as extra backing. Retained fees are real collateral and count toward `total_collateral`.

## TWAP freshness gate

In any non-Normal risk state (all devnet markets run in `ProxyMode`), pricing comes from the keeper-relayed `market.user_twap_price`. Every ratio- or price-dependent instruction - `mint_paired`, `redeem_paired`, the keeper single-side paths, donations, excess withdrawals, rebalances - rejects with `TwapNotAvailable` when `twap_updated_at` is older than `MAX_TWAP_AGE_SECS = 300` (5 minutes). A delayed keeper can't be quoted against a stale price.

## Instructions

### User-facing (anyone can call)

#### `mint_paired(collateral_amount: u64)`

Deposits `collateral_amount` cUSDC, mints matched L and S to the user's ATAs. Fee `collateral_amount × mint_fee_bps / 10_000`; the dev-tax slice goes to `dev_token_account`, the rest stays in the vault.

→ [Full mint flow](/flows/mint)

#### `redeem_paired(l_amount: u64, s_amount: u64)`

Burns L and S in independent quantities, returns `l_amount × L_NAV + s_amount × S_NAV - fee` cUSDC.

**Solvency haircut.** The gross payout is `nominal × min(1, CR)` where CR is the vault's live collateralization at the same NAV. While the vault is at or above 100% (the normal state) this is a no-op. If a large NAV move ever left it under 100%, every redeemer is scaled by the same factor - no first-mover advantage, no bank-run race, and the ratio is preserved for everyone who stays.

→ [Full redeem flow](/flows/redeem)

#### `mint_paired_with_waiver(collateral_amount: u64)` / `redeem_paired_with_waiver(l_amount: u64, s_amount: u64)`

Same as the above but consume an active `FeeWaiver` to skip the fee. Requires the market vault to be over-collateralized (≥102%) for the waiver to apply.

#### `donate_to_vault(amount: u64)`

Donate cUSDC into the market's collateral vault. Creates or extends a `FeeWaiver` for the donor. Used by power users to earn fee-free mint/redeem in exchange for boosting vault collateralization.

#### `permissionless_burn(is_long: bool, amount: u64)`

Burns L or S from the caller's own token account without any collateral payout, decrementing the supply ledger. Only the token-account owner may burn (delegates are rejected). Per-token collateralization strictly improves. Used for voluntary forfeiture and by the CLP's `clp_burn_excess` CPI to retire asymmetric inventory residue.

### Keeper-privileged (signer = `market.keeper_authority`)

#### `keeper_mint_single(is_long: bool, collateral_amount: u64)`

Fee-free, single-sided mint at NAV. Deposits `collateral_amount` cUSDC, mints only the chosen side's tokens at NAV. Used inside arb cycles.

| Argument          | Effect                                           |
| ----------------- | ------------------------------------------------ |
| `is_long = true`  | Receive `collateral_amount / L_NAV` long tokens  |
| `is_long = false` | Receive `collateral_amount / S_NAV` short tokens |

No mint fee, no worst-case quoting markup. The keeper pays full NAV for one side, so the vault grows by exactly the value of the new tokens - per-token collateralization is preserved at any size. (An absolute stress-floor check on this path was tried and removed; the error variant `SingleSideMintStressFloor` survives in the IDL but is not enforced.)

#### `keeper_redeem_single(is_long: bool, token_amount: u64)`

Fee-free, single-sided redeem at NAV. Burns `token_amount` of the chosen side, returns `token_amount × NAV` cUSDC. Enforces a post-redeem floor of CR ≥ 100% - peg-keeping operates freely while the vault is solvent, and refuses to make an underwater vault worse.

#### `keeper_burn_single(is_long: bool, token_amount: u64)`

Burn only - no cUSDC transfer. Residue cleanup when an arb cycle leaves unsold inventory; the vault keeps the mint-time deposit, the keeper eats the cost.

#### `redeem_single_for_vault(is_long: bool, token_amount: u64)` (CLP CPI only)

Mirror of `keeper_redeem_single` for the CLP's own inventory: burns from CLP-PDA-owned ATAs, pays cUSDC into the per-market `clp_vault`. The signer must be the canonical CLP PDA (`[b"clp", market]` under the CLP program ID), entered via the CLP program's `vault_redeem_single`. Same CR ≥ 100% post-redeem floor.

#### `update_risk_state(new_state, user_twap_price, oracle_confidence)`

The hot path: mirrors oracle health into `risk_state` and writes the TWAP + confidence the whole program prices against. Two hard bounds protect against a compromised keeper key: the TWAP may move at most 25% per call, and `Stress` can only de-escalate through `Recovery` (where the fee multiplier unwinds over an hour) - never jump straight to `Normal`.

#### `set_buffer_target(buffer_target_bps: u16)`

Posts the market's **dynamic overcollateralization buffer** - the per-market solvency target that replaced the static 102%. The keeper sizes it from the volatility regime and live inventory; on-chain it is clamped to \[100, 5000] bps over parity (target ratio 101%-150%), and 0/unset falls back to the 200 bps (102%) default. This target gates donations, fee waivers, excess withdrawals, and cross-market rebalances.

#### `set_s_gamma_index(s_gamma_index: u64)`

Posts the **short-leg volatility-decay scalar** γ (1e9 fixed). The keeper ratchets it down by realized per-cycle variance, marking `S_NAV` down to bank choppiness-convexity as collateral surplus. On-chain it **rejects any value above the current γ** (ratchet-down only — see `GammaMustRatchetDown`) and clamps to a `0.5` floor. Gated off-chain by `CLMM_GAMMA_DECAY_ENABLED` (default off). Does not touch the long leg. See [NAV → Volatility decay](/concepts/nav#volatility-decay).

#### `rebalance_collateral(amount: u64)`

Cross-market collateral move. With the unified vault this is a **scalar-only ledger move** — no cUSDC token transfer happens; it shifts `total_collateral` from an over-collateralized market to an under-collateralized one. The **source floor** is enforced on-chain: the source market must remain at or above its *own* dynamic target after the move, and only its liquid share (`total_collateral − deployed_to_yield`) may move. (The old TWAP-freshness gate was removed — with no token movement the source-CR floor is the real guard, and gating on a closed-market TWAP only produced spurious `OraclePriceUnavailable` reverts.) Both markets must share the keeper authority.

#### `deploy_collateral_to_yield(amount, protocol)` / `recall_collateral_from_yield(amount, protocol)`

Move idle collateral to an external lending venue and back. Deployment is capped at `yield_ceiling_bps` of `total_collateral` (default 60%); the rest stays liquid for redemptions. The keeper composes the actual lending CPI in the same transaction.

#### `harvest_collateral_yield(yield_amount: u64)`

Routes net interest from a yield recall to the CLP vault as protocol revenue. Principal returns via `recall_collateral_from_yield`; this instruction forwards only the earned spread and advances `total_yield_harvested`.

### Admin (signer = `market.authority`)

#### `initialize_market(asset_symbol, oracle_type, initial_l_price, initial_s_price, mint_fee_bps, redeem_fee_bps, keeper_authority)`

Create a new market. Allocates `Market` PDA, creates L and S SPL mints (mint authority = market PDA), creates the collateral vault.

| Argument                              | Type   | Notes                                        |
| ------------------------------------- | ------ | -------------------------------------------- |
| `asset_symbol`                        | String | ≤ 10 chars                                   |
| `oracle_type`                         | enum   | `Pyth` / `Hermes` / `Switchboard` / `Manual` |
| `initial_l_price` / `initial_s_price` | u64    | 6-decimal cUSDC. Constant-product anchor     |
| `mint_fee_bps` / `redeem_fee_bps`     | u16    | Max 1000 (10%)                               |
| `keeper_authority`                    | Pubkey | Initial keeper signer pubkey                 |

#### `update_market(mint_fee_bps?, redeem_fee_bps?, is_active?, dev_tax_pct?)`

Admin updates to fees, the active flag, and the dev-tax slice (≤ 25%). This is also the channel for the keeper's vol-informed fee posting - see [Fees](#fees).

#### `update_keeper_authority(new_keeper)` / `update_market_oracle(oracle_type)` / `update_fee_recipient(new_recipient)`

Rotate the keeper signer, repoint the oracle, or reroute fee flow. Bound to `market.authority`.

#### `withdraw_excess_to_clp(amount: u64)`

Drain collateral *above the market's dynamic target ratio* to the per-market CLP vault - the inverse of `donate_to_vault`. Guards: fresh TWAP required, only liquid (non-yield-deployed) collateral, and the post-withdrawal ratio must stay at or above `target_ratio_bps()`.

#### `configure_yield_ceiling(ceiling_bps?, enabled?)`

Enable collateral-yield management and set the deployable fraction (max 90%).

#### `configure_worst_case_quoting(enabled, normal_mult, proxy_mult, stress_mult)`

Configure per-state confidence multipliers used in mint pricing markup.

#### `configure_risk_fees`

Per-state fee adjustments (rare; defaults are usually fine).

#### `enable_multi_collateral`, `add_collateral_vault`, `update_collateral_vault`

Multi-collateral mode (accept multiple stablecoin/equity tokens as collateral with weights). Off for most markets; enabled per-market by admin if needed.

## Errors

| Code | Name                           | Cause                                                           |
| ---- | ------------------------------ | --------------------------------------------------------------- |
| 6000 | `MarketNotActive`              | `is_active = false`                                             |
| 6001 | `InvalidAmount`                | Zero or negative                                                |
| 6002 | `InsufficientCollateral`       | Vault can't cover redeem                                        |
| 6003 | `InvalidOracle`                | Oracle account mismatch                                         |
| 6004 | `UnsupportedOracleType`        | Bad `oracle_type` value                                         |
| 6005 | `OraclePriceUnavailable`       | Oracle paused or missing                                        |
| 6006 | `MathOverflow`                 | Should be unreachable                                           |
| 6007 | `SymbolTooLong`                | Symbol > 16 chars                                               |
| 6008 | `FeeTooHigh`                   | Fee bps > 1000 (10%)                                            |
| 6009 | `MintNotAllowedInStress`       | Risk state is `Stress`                                          |
| 6010 | `RedeemNotAllowedInStress`     | Reserved (redeem in `Stress` is currently allowed)              |
| 6011 | `ExceedsStressMintCap`         | Risk state is `ProxyMode`/`Recovery` and amount > throttled cap |
| 6012 | `TwapNotAvailable`             | TWAP buffer not yet populated                                   |
| 6013 | `AlreadyEnabled`               | Multi-collateral already on                                     |
| 6014 | `MultiCollateralNotEnabled`    | Tried to add collateral type without enabling                   |
| 6015 | `MaxCollateralTypesExceeded`   | More than 5 collateral types                                    |
| 6016 | `InvalidWeight`                | Multi-collateral weight not in \[1, 10000] bps                  |
| 6017 | `CollateralAlreadyExists`      | Duplicate collateral mint                                       |
| 6018 | `CollateralNotFound`           | Unknown collateral type                                         |
| 6019 | `BelowMinimum`                 | Mint \< 10 cUSDC                                                |
| 6020 | `UnauthorizedKeeper`           | Signer ≠ `market.keeper_authority`                              |
| 6021 | `Unauthorized`                 | Signer ≠ `market.authority`                                     |
| 6022 | `InsufficientLiquidCollateral` | Yield deployed; recall first                                    |
| 6023 | `ExceedsYieldCeiling`          | Deployment > `yield_ceiling_bps`                                |
| 6024 | `YieldManagementDisabled`      | `yield_enabled = false`                                         |
| 6025 | `RecallExceedsDeployed`        | Recall > deployed balance                                       |

→ [Full error catalog](/reference/errors)

## TypeScript

```typescript theme={null}
import { Program, BN } from "@coral-xyz/anchor";
import { PublicKey } from "@solana/web3.js";
import idl from "./mint_redeem.json";

const program = new Program(idl, provider);
const [marketPDA] = PublicKey.findProgramAddressSync(
  [Buffer.from("market"), Buffer.from("QQQ")],
  program.programId,
);

const market = await program.account.market.fetch(marketPDA);
console.log("L mint:", market.longMint.toBase58());
console.log("Risk:", Object.keys(market.riskState)[0]);
```

→ [Full mint+redeem example](/build/example-mint-redeem)

## See also

<CardGroup cols={2}>
  <Card title="Mint flow" icon="circle-plus" href="/flows/mint">
    Step-by-step `mint_paired` walkthrough.
  </Card>

  <Card title="Redeem flow" icon="arrow-rotate-left" href="/flows/redeem">
    Step-by-step `redeem_paired` walkthrough.
  </Card>
</CardGroup>
