Skip to main content
Continuum trades L and S tokens on its own venues in the CLP program. Which one fills depends on whether the market’s price is live: Since 11 Oct 2026, open-hours trading is committed orders only. pool_swap fails with PoolClosedWhileLive whenever the market’s price is live. The CLP’s instant oracle swap, clp_swap, is retired: the instruction keeps its accounts and arguments, but every call fails with SwapDisabled. Committed orders work on every live market. The app places every trade from your trading account. While the market is open it uses committed orders, at any size, so every in-hours fill is priced by a price push that happens after you commit. While the market is closed or its price updates are paused, no price push would arrive to settle a committed order, so the app shows the bin book’s quotes, which fill instantly up to its capped size, and traders’ orders on the order book, where size is limited only by who is on the other side, as one book. A market order takes the cheapest offers first when you buy and the highest bids first when you sell, from either, in one transaction. When the keeper has pulled one side of the bin book because outside markets moved, the app warns anyone about to trade into the side that still prices the close.
Mint and redeem open and close a paired position (see Mint and Redeem). The venues on this page buy or sell one leg.

Bin books

pool_swap trades against a native bin book. Each market has two, one per leg: QQQ’s long book and QQQ’s short book are separate Pool accounts. A book lives inline in its Pool account, with up to 16 bins and no rent per bin. asks[i] holds tokens of the leg for sale above the centre price base_price_1e6, and bids[i] holds cUSDC below it. The keeper sets the centre from NAV, shifted by the CLP’s inventory, and reshapes the book as the price moves. Off-hours it posts a demand-sized free-float book, and a guard lets it pull bins only on the stale side. See Book management. Bins use two step sizes: a fine core step (step_bps) for the first core_bins bins on each side, then a wider wing step (wing_step_bps). Ask bin i, counting from 0, sits i + 1 steps above the centre and bid bin i sits i + 1 steps below it. Each step up multiplies the price by 1 + step / 10_000, and each step down divides by it. On 10 Oct 2026 each QQQ book had 12 bins: 3 core bins 20 bps apart, then 300 bps wing steps. A swap walks the bins outward from the centre. If the book runs out, the swap fills what it can and charges only for that, and min_out still applies. pool_swap charges no swap fee; you pay the distance from the centre. It fills only while the market floats: the market’s risk state must not be Normal, and its last price push must be more than 300 s old, the same age at which mint and redeem freeze. In any other case it fails with PoolClosedWhileLive, and you trade with a committed order instead. While the market floats, the book must also have been posted by the keeper after the float began: pool.shape_updated_at must be more than 300 s after twap_updated_at, or the swap fails with PoolShapePredatesFloat (6052). Only a book the keeper posted for the float can trade. Every devnet market runs in ProxyMode, so on devnet a book opens 300 s after the last push and closes again at the next one. There is no pool-level kill switch. A new pool stays disabled until the keeper posts its first shape, and after that nothing disables or freezes it: no instruction sets pool.frozen, and set_pool_shape always re-enables the pool. Freezing the CLP’s swap guards stops committed orders but not pool_swap. The keeper can still empty a book by posting all-zero bins, and the rolling-window cap can pause it.

Accounts

pool_swap takes PoolSwapParams { direction, amount_in, min_out }. direction is 0 to buy the leg with cUSDC and 1 to sell it for cUSDC. amount_in is cUSDC on a buy and tokens of the leg on a sell, both with 6 decimals. When the market is capped (Clp.oi_cap above 0), add four read-only remaining accounts after market: the pool long synth vault, the pool short synth vault, the CLP’s long token account and the CLP’s short token account. Without them pool_swap fails with ExposureAccountsMissing. An uncapped market ignores them. See Exposure cap. A trade through swap_pool on your trading account passes its remaining accounts on to pool_swap.

Setup

Both samples on this page start from this setup.

Quote and swap

Against an unchanged book, quote.out is exactly what the swap returns. On Saturday 10 Oct 2026, with the market closed, it quoted 0.132577 QQQL for 100 cUSDC on the QQQ long book, and a simulated pool_swap returned the same. Standing depth is small on purpose. It is sized to demand rather than TVL, because the losses to informed traders grow with the depth deployed. On Saturday 10 Oct 2026 the QQQ long book held 5,000 cUSDC of bids and 10.13 QQQL (about 7,600 cUSDC) of asks. The single-stock books held 1,000 to 1,250 cUSDC a side. Depth has since been resized to demand, at least 500 cUSDC a side. Larger orders belong in a committed order once the market opens, or on the order book.

Rolling-window cap

pool_swap is held to one notional cap per market, kept in the market’s Clp account. Each fill adds its cUSDC amount to swap_window_used, and a fill that would take it past window_cap_usd reverts with WindowCapExceeded. The count resets once window_secs have passed since the window opened. As of 11 Oct 2026, QQQ, SPY and XAU are capped at 1,000,000 cUSDC per 3,600 s. The other 11 markets have no cap set, and 0 means uncapped. Committed orders don’t count toward the cap.

Committed orders

You put your input in escrow under an order account, and the order fills at a keeper price push after your commit, at NAV ± the commit spread:
NAV is the leg’s NAV at the settling push: P for the long leg and K / P * γ for the short leg (see Mint). The keeper posts commit_spread_bps as clamp(half-spread, 10, 500) from its volatility model. As of 10 Oct 2026 it was 18 bps on QQQ, 15 on SPY and 18 on XAU. The price is set after you commit, so nobody can trade against a stale quote. That is why committed orders have no size cap of their own and skip the rolling window. They are bounded by the price checks at settle, the collateral floor, the CLP’s inventory and the market’s exposure cap. Committed orders need the market’s swap guards (Clp.swap_guards, set with configure_swap) to be enabled and not frozen. Since 11 Oct 2026 they are on for all 13 live markets, with the same settings: Their spread (spread_bps) and window cap were left unchanged. spread_bps priced the retired clp_swap, and no live instruction reads it.
1

Commit

commit_swap(side, direction, amount_in, min_out, nonce) moves your input (cUSDC on a buy, tokens of the leg on a sell) into an escrow token account owned by the order PDA. It needs the market active (MarketInactive) and its swap guards enabled (SwapDisabled) and not frozen (SwapFrozen). Your payout account must already exist. The program checks it at commit, so settlement can’t fail on a missing account.
2

Settle (keeper only)

settle_swap becomes valid once market.twap_updated_at is later than the commit, in a later second. It stays valid until expires_at. Only the keeper can send it: the signer must be clp.authority or market.keeper_authority (SettleKeeperOnly, 6047). The keeper settles at the first push it sees after the commit, so you can’t choose which price fills your order.
  • If the output misses min_out, the order is refunded in full and closed.
  • If the market’s exposure cap has room for only part of the order, the part that fits fills and the rest is refunded with the escrow (see Exposure cap).
  • If the market is below its collateral floor (a 100% collateral ratio at the settle price), or the price fails the checks above, settle reverts. The order stays pending and fills at a later push, if one passes before it expires.
  • If the CLP lacks inventory, settle reverts and the order stays pending while the keeper provisions it.
  • If a payout or refund can’t reach your account, settle still succeeds and the order is held (see Held orders).
While the underlying market is closed the keeper normally withholds pushes, so an order committed then can’t settle and expires.
3

Refund (after the TTL)

An order expires 180 s after the commit. After that, anyone can send cancel_swap. It returns the escrow to the owner’s token account and the rent to the owner, and needs neither of their signatures. Before expiry nobody can cancel (OrderNotExpired). Cancel checks nothing else (no price, keeper, freeze or market state), so escrowed funds can always be recovered after expiry. The keeper refunds every expired order about 5 s after expiry, and the app shows a Refund now button if an order is still open 60 s after it.
Settling, refunding and cancelling all close the order and escrow accounts and return their rent to you, unless the order is held.

Held orders

An order records three accounts when you commit: your payout account (user_out), your input account (user_in) and the claim payer. If the payout or refund can’t be delivered, because the recorded account is closed, owned by someone else, frozen or the wrong mint, settle and cancel still succeed. The funds wait instead: a payout in a claim account, a refund in the escrow. The order’s status becomes 1, “held”, the log line reads settle_swap HELD for claim, and OrderHeld is emitted. claim releases a held order. It is permissionless, and every token goes to an account owned by the order’s owner, so it can’t be redirected. The keeper cranks it and creates the owner’s token account first if it is missing. The keeper also fronts the claim account’s rent when it settles, and gets it back at claim. claim returns the escrow and order rent to the owner and emits OrderClaimed. A claim on an order with nothing held fails with OrderNotClaimable (6049), and one to an account that isn’t the owner’s live, unfrozen account for that mint fails with ClaimDestinationInvalid (6050).
On devnet the fill price (market.user_twap_price) and the freshness check (market.twap_updated_at) both come from keeper pushes, so a committed order trusts the keeper’s price.

Order account

PDA seeds [b"order", user, market, nonce] under clp, with nonce as 8 little-endian bytes. nonce is any u64 you pick; a fresh one per order lets you keep several open at once. Keep it, or the order address, so you can find the order later (see Reading state).
The account is 213 bytes. Orders committed before the upgrade are 117 bytes, with no recorded accounts, and still settle and cancel.

Accounts: commit_swap

Accounts: settle_swap and cancel_swap

settle_swap takes these accounts, in order: cranker (signer, mut, the keeper: clp.authority or market.keeper_authority), user (order.user), order, escrow, clp, clpVault, clpSynth (the CLP’s cUSDC and leg inventory), market, userOut, userIn, tokenProgram, claim (the PDA [b"claim", order]), outMint and systemProgram. The inventory accounts follow. On a 213-byte order, userOut and userIn must be the accounts recorded at commit. When the market is capped it also needs four read-only inventory accounts after those: the pool long synth vault, the pool short synth vault, the CLP’s long token account and the CLP’s short token account. The keeper passes them on every settle. Without them a capped market’s settle fails with ExposureAccountsMissing and the order stays pending. An uncapped market ignores them. cancel_swap takes user (the order’s owner, who receives the rent; not a signer), order, escrow, userIn (the owner’s token account for the escrowed mint, which receives the refund; on a 213-byte order it must be the recorded account) and tokenProgram. All but tokenProgram are mutable. Whoever sends the transaction pays its fee.

Commit and cancel

This sample buys QQQ’s long leg with 10,000 cUSDC, starting from the setup above. It works on any live market while the market’s price is live.
The order emits OrderCommitted, then one of OrderHeld (later OrderClaimed), OrderSettled (with out, nav and base_price), OrderRefunded (a min_out miss, or a market with no room under its exposure cap) or OrderCancelled. A partial fill emits OrderSettled for the part that filled, whose amount_in is only that part, together with OrderCapped. Fills also emit SwapExecuted, whose route is 1 for pool_swap and 2 for a committed settlement. Route 0 belonged to the retired clp_swap.

Exposure cap

Each market limits how far traders can go net long or net short. The cap is Clp.oi_cap, in cUSDC atoms, where 0 means uncapped. It binds traders’ net position E, which is what traders hold long minus what they hold short, at NAV, not counting the CLP’s own inventory. The protocol’s treasury is the other side of that net position. The nightly sizing and the exact rule are in Solvency, and the instruction-level detail is in the CLP reference. The rule in short: a trade is allowed if it leaves E inside the cap, or if it moves E toward zero. A trade never pushes E further past the cap than it already is, and a trade that shrinks E always passes. Buying a long raises E and buying a short lowers it, so each short opens room for one more long, and the reverse. A paired mint never changes E.
  • Committed orders fill up to the room left, measured at the settle price. If the order is bigger, the part that fits fills and the rest returns to you with the escrow. Your min_out scales down to the filled share, so a partial fill is held to the same price as a full one. The settle logs settle_swap PARTIAL filled=X of Y and emits OrderCapped with filled_in, refunded_in, E before the fill and the cap. If less than $1 of room is left the whole order is refunded, and the log reads settle_swap REFUND exposure cap. A market that is full on one side accepts orders on the other.
  • The bin book fills whole or not at all. A pool_swap that would push E past the cap reverts with ExposureCapExceeded (6045).
  • The order book is not affected. Trades between traders on the order book don’t change what traders hold net against the CLP.
  • Redemptions are not capped. Since 14 Oct 2026 they burn a balanced pair, which moves the net position by less than $1. See Redeem.
The app shows how much of a capped market can still be bought (Longs available, or Shorts available), and says “This market is full for new longs. Every short opens room for one.” when under $1 is left. It warns when your order is larger than the room, and it never changes the amount you typed. After a partial fill it shows what filled and what came back because the market reached its limit. An uncapped market shows none of this. The cap is a number the keeper re-posts each night, so read the live Clp.oi_cap from the chain, not a figure copied from a document.

Retired: instant oracle swap

clp_swap(side, direction, amount_in, min_out) filled instantly from CLP inventory at NAV ± spread_bps, with no book and no slippage, on QQQ, SPY and XAU. It filled at the last pushed price, which is a stale quote between pushes, and it was retired on 11 Oct 2026. The instruction keeps its accounts and arguments, so existing clients still decode it, but every call fails with SwapDisabled. Use a committed order instead.

Errors

See the full error catalog.

See also

Reading state

Books, NAV and pending orders, read from chain.

CLP program reference

Every instruction and account.

Book management

How the keeper shapes and re-centres the books.

Peg maintenance

How the keeper keeps book prices close to NAV.