StrataDocs

Public Contract

Strata's agent contract is deliberately compact, versioned, and strict. Clients discover the current capability catalog at runtime rather than guessing what production supports.

Stability model

Dynamic product state and contract releases are separate:

  • A market becoming available or paused is reflected through live discovery.
  • A capability may be enabled or disabled by Strata's public policy.
  • A change to request or response meaning requires a coordinated contract release.

Official TypeScript, Rust, CLI, MCP, documentation, and live-service releases are verified against one reviewed contract fingerprint.

Money and time

  • Token amounts are unsigned base-10 strings in atomic units.
  • Display prices are decimal strings and are not signing bounds.
  • Every quote includes server time and expiry.
  • amount_out_atoms is the user-net output after output_fee_atoms.
  • Gross pre-fee output is exactly amount_out_atoms + output_fee_atoms;

all-in user comparisons use amount_out_atoms.

  • minimum_output_atoms is the canonical lower bound returned for the quote.
  • maximum_tolerance_bps is the caller's choice: the most they accept below

the quoted output, 0 by default, applied in minimum_output_atoms and echoed back on the quote.

  • price_impact_pct is measured from the book: how far the quoted fills'

average price sits from reference_price. It is not a setting and is unrelated to maximum_tolerance_bps — a quote can show 0 impact with 25 bps of tolerance, or 40 bps of impact with 0 tolerance.

  • Input-side and output-side fees are labelled separately.
  • A market quote fixes exactly one amount. Exact input (amount_in_atoms):

spend that much and receive at least minimum_output_atoms. Exact output (amount_out_atoms, "buy 1 SOL"): Strata inverts its best route at quote time and returns the input that delivers the requested output as amount_in_atoms — no cushion of its own. maximum_tolerance_bps keeps its one meaning: minimum_output_atoms is the requested amount lowered by it, zero by default. Both forms execute through the same quote handle.

Opaque quote handles

A quote handle identifies a short-lived economic snapshot. It is opaque, is not a reservation, cannot move funds, and must not be decoded or used to infer execution details.

Book and market data

books.read gates the versioned HTTP and WebSocket surface. HTTP exposes the Strata book, market status, fee schedule, and recent anonymized trades by opaque market ID. The WebSocket stream begins with a snapshot, then publishes strict previous-sequence changes, trade events, and heartbeats. A zero size removes a price. Clients must replace local state from a fresh snapshot after any gap. A status event removes stale local state until a fresh snapshot arrives.

The book contains only price and size. It does not identify how Strata produced a level. Book prices exclude additional Strata trading fees; a fresh quote returns the exact execution economics and remains the authority for signing.

market_data.candles.read returns at most 5,000 time-ordered OHLC rows. Prices remain decimal strings, and the official clients reject malformed bounds. market_data.marks.read returns an atomic price per whole base unit, quote decimals, age, and stale state. Both adapters resolve opaque market IDs inside Strata and deliberately omit private execution and construction details.

Signed account state

account.read exposes only the owner's sanitized open orders and fills. The HTTP authorization signature binds the opaque market ID, wallet address, request time, and fill limit. The WebSocket sends an expiring challenge before it sends private data, and the owner-configured signer signs that challenge externally. Strata never accepts its private key.

The account stream begins with a complete signed snapshot, then emits strictly sequenced order snapshots, fill or settlement updates, and heartbeats. The official clients fail closed on a gap and replace state from a newly signed snapshot after reconnecting. Public order and fill IDs are opaque. Responses are limited to the owner's order state, fill economics, fees, settlement, timestamps, transaction reference, and realized profit or loss.

Execution contract

Preparation and submission are separate, independently controlled capabilities. A session authorization binds the market, side, input, account sequence, expiry, and minimum_output_atoms. Preparation may refuse an execution, but it cannot weaken that minimum. The account sequence may be omitted from any execution or order challenge: Strata then resolves the next sequence from the Vault's confirmed market account when it issues the challenge and seals it into the authorization, and the official SDKs read that sealed value back rather than guess. A supplied sequence is bound exactly. In one order batch, every place-like operation must either supply its sequence or omit it; omitted sequences are consecutive in request order.

Prepared transactions are signed locally, and one signature is enough: the operation itself (a quote binding, an order command, a TWAP action) may be sent straight to prepare and the session then signs only the returned transaction; the two-step path — authorization bytes signed first — remains available. The SDK never accepts private key material, and a transaction verifier runs before the session signer: the SDK's built-in verifier decodes the transaction and requires it to be exactly the requested operation for that market, with the session co-signing only delegated instructions and never paying, and an owner may substitute a stricter one. Submit accepts only the exact prepared transaction and is idempotent. The public execution response contains the transaction signature and status; it does not describe how Sonar produced the result.

Onboarding is one owner signature: vault.setup registers an external session key from the wallet and key (policy fields are optional). Supplying replace_session_public_key revokes that old key in the same atomic transaction, or the first vault.deposit that names the session key registers it inside the same transaction. One session then trades every market. Owner actions — Vault setup, deposit, withdrawal, session change, withdrawal policy, pause — are prepared by Strata with Strata as the sponsored fee payer whenever the owner's sponsorship budget allows: sponsored is true, Strata pre-funds any account the action creates, and the owner needs no SOL and no RPC. The owner signs the exact prepared transaction and returns it with its preparation_id to vault.relay; Strata verifies the bytes, adds only its own fee-payer signature, broadcasts, and records a durable outcome readable by preparation_id. Submission is idempotent. Owners holding at least 0.01 SOL pay their own network fee (sponsored: false; the flow is otherwise identical); below that Strata pays and recovers exactly what it spent from the owner's deposits, in the deposit asset, inside the same deposit transaction — disclosed as network_cost_atoms, capped at 1% of the deposit, remainder carried forward. First setup is sponsored for an empty wallet too, so a user can register a session before holding SOL. Rent for a first withdrawal policy is sponsored when the wallet already holds about $10 of supported assets. A global daily circuit breaker is the only other limit; when it trips the owner wallet is the fee payer for that action.

A Vault needs no per-market onboarding. Its first resting order, TWAP, or internally filled execution in a market creates the Vault's market account inside that same transaction, with Strata sponsoring the rent, so the first trade in a new market is the same one call as every later trade. A verifier may therefore see one sponsored rent transfer from the fee payer to the Vault's market account ahead of the order on that first transaction only.

execution.status.read recovers prepared state or a confirmed receipt by opaque market and execution ID. Confirmed execution IDs, signatures, and settlement timestamps are journalled in the existing market store and survive a service restart. Reading status never resubmits a transaction.

execution.stream is the sequenced WebSocket form of that receipt for one market: the client opens the socket, sends a watch frame naming the opaque execution handles it prepared, and receives one executions_snapshot for those handles, then execution_update when a watched execution is prepared or confirmed on chain, execution_expired when an unconfirmed preparation lapses, execution_unknown for handles this market never issued or no longer remembers, and heartbeats. Later watch frames add handles on the same stream. Every event carries the stream identity, sequence, and previous sequence, and the official SDKs fail closed on any gap.

algos.twap.read projects the existing on-chain and durable TWAP index into opaque schedule and fill IDs. It exposes cadence, bounds, exact progress, labelled fees, and transaction receipts while omitting maker identity and private execution metadata. Wallet and vault-owned schedules are returned together; this is sanitized public chain state and does not grant authority to place or cancel a schedule.

algos.twap.stream delivers the same sanitized rows as a sequenced WebSocket per market: one twaps_snapshot, then a twap_update carrying the complete schedule whenever it is created, executes a slice, or reaches a terminal state, plus heartbeats. Every event carries the stream identity, sequence, and previous sequence; a recovery snapshot advances the sequence on the same identity and the official SDKs fail closed on any gap, so an agent never has to poll for progress or reconstruct a schedule from partial fills.

When algos.twap.place or algos.twap.cancel is live, the action uses the same external-session boundary as immediate execution and resting orders. A place authorization binds the owner, session, side, total atomic size, slice count, maximum tolerance, interval, exact tick-aligned price bound, schedule identity, block lifetime, and expiry. A cancellation binds one active owner-controlled opaque TWAP ID. The backend builds the canonical transaction from the action itself (one signature) or from a signed challenge; the official SDK verifies it — built-in verifier or the owner's own — before asking the session signer for the one transaction signature. Submission is idempotent and restart durable. The public contract never accepts a private key or exposes transaction construction details.

Account and community contract

portfolio.read is the whole account in one public read, by wallet address: GET /v2/account/{wallet} (also /v2/account/{wallet}/portfolio). No signature, no session key, no market selection. It returns, across every live market, exact per-asset balances as total, available, and locked atoms with USD values, per-market positions, every open order, recent fills (newest first, bounded), and USD totals with the observed chain slot. Assets without holdings and markets without a position are omitted. USD totals are null whenever any held asset lacks a fresh public mark, and the response lists which assets are unpriced; a partial valuation is never presented as complete. unavailable_market_ids names any market that did not report orders and fills for that snapshot; balances stay complete. The response describes only Strata product identities; it never reveals where or how liquidity is sourced. The per-market signed reads (account.read, account.stream) remain for owners who want a signed, per-market view; they are never a prerequisite for trading.

portfolio.history.read returns only genuine stored equity samples for the requested wallet and time window. Values are exact USD micros, a response says when collection is still starting, and missing earlier samples are never invented.

points.read is the agent-facing source of truth for fleet-wide Points. One rate-limit-efficient response contains the current Season and epoch windows, weekly budget, named Volume/Maker/Bugs/Referrals weights, immutable owner balance and lane breakdown, rank, bounded standings, and the earliest allocation finalization time. Eligible activity across every live market is captured automatically. Public balances and ranks contain closed immutable epochs only; current-week activity remains provisional until finalization.

rewards.read remains the backwards-compatible summary for older clients. referrals.read exposes the owner's code, counts, points, and exact accrued, paid, and claimable reward atoms. Public responses omit administrative state.

bugs.read returns opaque report IDs, review state, severity, points, and timestamps; report text and database IDs never cross the public contract. bugs.submit is a two-step externally signed action. The owner signs the exact domain-separated bytes returned by the SDK or MCP tool and submits only the public key, message, and detached signature. Submission creates a pending report and grants no points until human review.

Market-maker contract

mm.status.read and mm.reputation.read are public by wallet address, per market — no signature, like every other read. Status returns the maker's products — resting firm orders, live signed quotes, each Strand and Current with its remaining exposure, expiry, and oracle health, and armed dead-man guards — plus the current slot for reconciliation. Reputation returns the maker's reliability counters, tier, tier progress, and signed-quote eligibility. Neither reveals other makers, takers, or market participants. (A signed request from an older client is still honored, and a wrong signature is still refused.)

mm.fills.stream is the maker WebSocket for one market, public by wallet address. The server still sends a compatibility challenge; the client answers {"type":"open"} (or a signature, for older clients) and receives one maker_snapshot (the maker status projection plus recent maker-side fills tagged with their product: firm order, Strand, or Current), followed by sequenced maker_fill, maker_status (any product, budget, exposure, expiry, or dead-man change), and heartbeat events. Every event carries the stream identity, sequence, and previous sequence; a recovery snapshot advances the sequence on the same identity, and the official SDKs fail closed on any gap.

Persistent order commands

When orders.prepare and orders.submit advertise websocket, agents can open /v2/markets/{market_id}/orders/stream through either official SDK. The socket authenticates the exact opaque market, owner wallet, external session key, and one-time challenge. Client commands and server events have independent contiguous sequences; command results retain the caller's request ID. After the singleton authentication exchange, either direction may coalesce up to 64 independently sequenced items into one transport frame. Official SDKs apply the batching automatically and keep single-command compatibility. Current SDKs also negotiate compact result batches so shared stream metadata is sent once per frame, then restored and validated for every event locally. Unnegotiated clients continue to receive complete event objects.

Placement returns after RPC broadcast. Terminal chain status arrives later on the same stream and remains recoverable through the durable status operation. This keeps chain confirmation out of the placement hot path without turning an ambiguous transport result into a second submission.

Self-trade cancellation is opt-in. An omitted policy is none and leaves the requested control unchanged. When the owner explicitly selects cancel_taker, cancel_maker, cancel_both, or skip_own_liquidity, that policy may transform the canonical signed operation. The matcher and on-chain program still prevent actual self-fills. The returned effective operation is what the official SDK validates and asks the external signer to authorize.

A dead-man ticket is an exact externally verified, pre-signed cancel-all. Its deadline is persisted, restart-recoverable, and extended only by authenticated heartbeats. Losing the agent or dropping its SDK guard stops heartbeats and leaves cancellation armed. An explicit disarm is a separate command.

The TypeScript SDK also emits a machine-readable non-trading load certificate covering authenticated connection latency, command p50/p95/p99, concurrency, and error rate. The production profile requires authentication p99 ≤ 500ms, command p50 ≤ 10ms, p95 ≤ 25ms, p99 ≤ 50ms, and error rate ≤ 0.1%. These are release thresholds, not claims until measured against the deployed service.

Executable action graph

GET /sonar/action-graph returns stable nodes, transitions, required live capabilities, and external signing boundaries. Its authority model is explicit: permission comes from the external agent owner, signing occurs externally, and Strata accepts no private keys. The graph describes how to use Strata; it does not replace the owner's agent policy.

GET /v2/action-graph expands that entry workflow into the complete public product map: entities and their relationships, SDK modules, exact HTTP, WebSocket, and MCP bindings, plus composable workflow subgraphs. Every operation and workflow node carries live availability projected from GET /v2/capabilities. Unavailable package support is visible for planning but is never callable authority, and unlaunched products are absent.

The platform graph binds every published operation to at least one exact workflow node. Official TypeScript and Rust clients reject orphaned operations, operation/capability mismatches, unreachable workflow nodes, and implicit signing boundaries. An agent can therefore traverse the graph from discovery through preparation, external authorization, submission, recovery, and receipt without inferring an undocumented route.

Capability discovery

Each capability declares its stability, risk class, required scope, SDK availability, MCP exposure, and current state. Clients should re-discover capabilities and the action graph, and fail closed when a required capability is unavailable.

Errors

Public errors contain a stable code, a safe message, and a retryable flag. Unknown fields and incompatible contract versions are rejected by the official clients. Private diagnostics never cross the public contract.