Skip to main content

Units and conventions

Six decimals. 1_000_000n is one dollar. Division truncates toward zero, matching the Rust engine exactly. Parse user text with parseUsdc; never through Number.
barrierMicroBp and takeProfitMicroBp are signed distances from entry, in millionths of a basis point. MICRO_PER_BP is the conversion. Use levels() to turn them into prices rather than doing the arithmetic yourself.
entryFeeBps, exitFeeBps and friends. ONE_HUNDRED_PCT_BPS is 10_000n.
Account maps take 32-byte hex strings. toHex(publicKey) converts in, toBase58(hex) converts out. Everything you read back from a decoded account is hex.
A signed quote’s ageSlots is Clock.slot minus the slot the quote was published in, and its ageMs is that age counted at 400 ms a slot. The program bounds the first by market.maxOracleAgeSlots and the second by market.maxOracleAgeMs. See quotes.

The surface, by area

The price a market settles on is the signed quote’s, in US-dollar units. A chart drawn from one exchange’s spot price is a different fact from the price the program verifies. Ask settlementIdentity(market) which one a market settles on.
llms.txt ships inside the package and is the whole surface, flat, in reading order — generated, so it cannot drift.

Constants a client uses

The take-profit is a floor, not a ladder. Any multiple at or above RUNG_FLOOR_BPS is admitted, up to the payout cap. The presets an interface offers are presetRungsBps(rungCeilingBps(market, config.params)), computed from the live cap; the RUNGS export is not the preset list. See how the product works.
LAUNCH is not a source of truth. It exists so an interface can paint something before its first fetch resolves. Every field in it is governed and can move on chain. Settle nothing, quote nothing and gate nothing against it — read the config account.

Close reasons

voluntary starts with the owner’s request_close, and the settle that completes it may be sent by anyone. userExpiry and tenorExpiry start with a mark_expiry that anyone may send from the deadline. See settling. lastResort carries no quote. It is legal only while no fresh price exists and the oracle is not frozen, and on one of two grounds: the market is dark (no posted price for 24 hours), or the position’s finite frozen tenor plus config.lastResortGraceS has elapsed. It pays a live position its stake back with the exit fee waived. See the no-price close.
FAVOURABLE_CLOSE_REASONS is {voluntary, takeProfit}. It is not the set the minimum hold applies to — a client testing membership in it before offering a close on a user timer will offer one the chain refuses with MinimumHoldNotMet (6103).A session delegate is not a stranger: it is the owner’s own key, and no key outside that pair can take a voluntary close. Every close reason is refused while config.settlesDisabled is set.

Market availability

Never a boolean. A boolean cannot distinguish “closed on its own calendar” from “the oracle died”, and those need opposite handling.
A stale feed at 02:00 on a closed market is correct; the same staleness while the market is open is an outage. availability() consults the session before it is allowed to call anything an oracle failure. closing-soon means opens are refused and forceCloseAt is when open positions end. A market whose feed has stopped answering during an open session reads halted, reason oracle. On a market with trading hours, opensAt comes from the market’s own calendar (Market.sessions), the calendar the program refuses opens against. nextSessionOpenS(market, now) gives the same instant directly, and openTenorS(config, market, now) gives the life an open would be given now — shorter than the venue tenor near the close, since a position ends before its session does. Opens stop before the close: at now + sessionHeadroomS(market, now) − market.sessionBufferS − minSessionTenorS(), the instant openTenorS turns 'too-late'. Chain time. The program judges every deadline against Clock.unix_timestamp and counts every age in slots. Read the chain’s time, never your machine’s: chainNowSeconds(connection), or the Clock sysvar.

The chain seam

Client is a reader over a ChainSource, which is an interface: clock, account bytes, token balances, and a way to send actions. It exists so the same client code runs against different backends without changing.
The source that ships with the package is LocalnetSource, which runs the program’s own logic out of process — no validator, no deploy — and is what the SDK’s test suite drives. Reading a live cluster today is done directly, as shown throughout these pages: derive the PDA, read the account, decode it.

Honesty about coverage

The package states its own boundary rather than implying coverage it does not have. Its settlement arithmetic, account layouts, refusals and instruction encoding are checked against the program itself, by golden vectors emitted from the engine. A handful of runtime concerns — the things only a real validator can exercise — are listed explicitly in the readme shipped inside the package, and that list is the edge of what has been proven.

Session keys

Who signs a trade, and the session-key delegate’s three clocks.

Risk disclosure

What can go wrong, for traders and for the liquidity pool.