Moxie API, RPC, and settlement reference.
The full reference surface for teams wiring production market infrastructure: clearing primitives, auth profiles, agent envelopes, JSON-RPC methods, settlement receipts, realtime streams, SDK install paths, pagination, errors, and amount utilities.
Clearing, settlement, and market primitives
This page carries the detailed protocol material behind the SDK calls: settlement jobs, compliance preflight, portfolio margin, parimutuel and continuous clearing, receipt proofs, release/recovery, and certified hot-market deltas. The terminal runtime primitive is AdmissibleObligationTransition; ClaimGraph and ClaimCompiler are the target source-language layer for contract-shaped products.
1. Event-atomic settlement
A settlement job resolves the oracle event, pays winners, mints assets, burns tickets, and nets cross-position margin under one terminal receipt. Small jobs fit in one block; large cohorts chunk in deterministic order and expose no final participant state until the settlement_batch_root is finalized. NativeTx::SettlementBatch now has consensus type coverage and an executor path that validates cheap invariants, stages non-terminal chunks under settlement_batch_staging, records payout metadata, and applies terminal chunk effects under one root. NativeTx::PayoutReturned closes the bank-return leg: the authorized return debits the recorded recipient USDC, credits custody, records the return code, and emits TxReceiptEvent::PayoutReturned committed through eventsRoot. Two RPC methods round-trip batch admission: moxie_estimateSettlementBatch returns a deterministic manifest_root, gas estimate, and validation envelope, while moxie_submitSettlementBatch dispatches the signed write under the same security envelope as moxie_submitSigned. Successful terminal receipts surface settlementBatchRoot and events[] on RpcReceipt; inclusion proofs mirror settlementBatchRoot and eventsRoot on RpcMerkleReceipt.digestInput. See docs/architecture/SETTLEMENT_JOB.md for the moat #1 spec.
import { Client } from "@moxie/sdk";
const moxie = new Client();
// Brand list + token price
const brands = await moxie.getBrands();
const fightToken = brands[0]?.token_id ?? "0x<64-hex-token>";
const price = await moxie.getTokenPrice(fightToken);
// AMM swap — constant-product pool
const tx = await moxie.ammSwap({
key: "0x<64-hex>",
pool_id: "0x<64-hex-pool>",
token_in: "USDC",
token_out: fightToken,
amount_in: "1000000000000000000000",
min_amount_out: "950000000000000000000",
});
2. Prediction and parimutuel markets
Binary, multi-outcome, and parimutuel-style markets resolve before trades execute in the settlement block. A sports card, HKJC-style racing pool, bracket market, or live micro-bet can pay many winners from one resolved event. Prediction signals may influence related spot or AMM markets; AMM state never feeds back into the prediction payoff.
const eventId = "0x<64-hex-event>";
const mint = await moxie.predictionMint({
key: "0x<64-hex>",
prediction_id: "0x<64-hex-prediction>",
event_id: eventId,
outcome_index: 0, // McGregor
amount: "500000000000000000000",
});
const odds = await moxie.getPredictionOdds(eventId);
console.log(odds);
// { outcomes: [...], probabilities: [...] }
// Settled in Phase 1 at resolution block — atomic
// with spot repricing through the PW-AMM coupling.
3. AMM/CLOB hybrid orderbook
Markets progress through five stages: BondingCurve → EquilibriumAmm → HybridAmmClob → FullClob → CrossListed. The orderbook merges synthetic AMM levels with resting CLOB orders. Spot orders, conditional orders, and contingent orders share a unified clearinghouse; cross-margined positions offset correlated exposure.
const marketId = "0x<64-hex-market>";
const book = await moxie.getOrderBook(marketId);
console.log(book);
// { bids: [...], asks: [...], stage: "HybridAmmClob" }
const order = await moxie.spotOrder({
key: "0x<64-hex>",
market_id: marketId,
is_buy: true,
quantity: "1000000000000000000000",
price: "2450000000000000000",
});
4. Continuous markets with LP fee accrual
Use a continuous market when the outcome is a range rather than a fixed list: item resale price, auction clearing price, implied probability, finishing time, weather, vote share, or any bounded numeric result. Under the hood this is Continuous-CPCAM over [omega_lo, omega_hi], discretised on a grid_size_code ∈ {N8, N16, N32, N64, N128, N256}, paired with a convex entropy generator. LPs provide shape-weighted range liquidity; swap_fee_bps of every Buy accrues back to LP positions prorated by liquidity_budget.
import { Client, ShapeCode } from "@moxie/sdk";
const moxie = new Client();
const provide = await moxie.provideContinuousLiquidity({
key: "0x<64-hex>",
position_id: "0x<64-hex>",
market_id: "0x<64-hex>",
omega_lo: "100000000000000000",
omega_hi: "500000000000000000",
shape_code: ShapeCode.Gaussian,
shape_param_a: "300000000000000000",
shape_param_b: "50000000000000000",
liquidity_budget: "100000000000000000000",
});
// Observe: pending clearings + LP positions by market
const pending = await moxie.getPendingClearings({});
const lps = await moxie.getContinuousLpPositionsByMarket({
market_id: "0x<64-hex>",
});
// Withdraw principal + accrued fees
const withdraw = await moxie.withdrawContinuousLiquidity({
key: "0x<64-hex>",
position_id: "0x<64-hex>",
});
Four auth profiles — the same RPC surface
Every Moxie call resolves to one of four auth profiles. All four share the same underlying RPC surface: an AI agent holding a scoped agent credential is indistinguishable from a human developer backend at the RPC layer.
1. Developer backend (server-to-server)
Credential: mxk_sk_<env>_<kid>_<random> (secret, backend-only), optional mxk_pk_* publishable key (origin-pinned via Referer / Origin allowlist, scope-locked to reads). Exchange into short-lived mxat_<blake3> bearers via OAuth 2.0 Client Credentials at the mounted gateway or ops route POST /oauth/token. Postgres + Redis token store is the production target.
token = await http.post(
"/oauth/token",
json={
"grant_type": "client_credentials",
"client_id": "mxk_sk_prod_acme_kid42",
"private_key_jwt": sign_jwt("acme", priv),
"scope": "markets:read personas:write",
},
)
access_token = token["access_token"]
2. Wallet-native player (SIWE)
EIP-4361 Sign-In-With-Ethereum remains the player-session target surface, implemented by gateways rather than the node JSON-RPC module. Subject is the wallet address, not email. Wallet default: MPC with passkey for new players (self-hosted threshold under Moxie ops, no permanent third-party custody); ML-DSA-65 post-quantum seed provisioned alongside; hardware upgrade (Ledger EIP-1193) on by default.
const nonceRes = await fetch("/v1/auth/siwe/nonce", {
method: "POST",
body: JSON.stringify({ address, domain: "moxie.inc" }),
});
const { nonce } = await nonceRes.json();
const msg = buildSiweMessage({
address, nonce, chainId, /* ... */
});
const sig = await wallet.signMessage(msg);
const sessionRes = await fetch("/v1/auth/siwe/verify", {
method: "POST",
body: JSON.stringify({ message: msg, signature: sig }),
});
const session = await sessionRes.json();
3. Delegated session key (macaroon-attenuated)
On top of SIWE, the gateway can mint a secondary secp256k1 session key bound on-chain as a restricted signer; this is not a shipped @moxie/sdk namespace. Biscuit/macaroon caveats (max_spend, persona, device, ttl) ride as first-party predicates on the signed-envelope params. Depth cap 8; attenuate-only; TTL-bounded. ERC-4337 account abstraction lives here: player smart-accounts are SimpleAccount behind a developer-funded Paymaster with per-player budgets.
const keyRes = await fetch("/v1/auth/session-keys", {
method: "POST",
headers: { Authorization: `Bearer ${session.token}` },
body: JSON.stringify({
scope: ["native:transfer", "moxie_submitSigned"],
caveats: [
{ max_spend: "10000000000000000000" },
{ device: "ios-abc" },
],
ttl_seconds: 3600,
}),
});
const sessionKey = await keyRes.json();
4. Admin (HSM-backed, m-of-n)
Static X-Admin-Key is retired. Every admin* RPC is a signed envelope from an HSM-rotatable admin signer (YubiHSM or CloudHSM), countersigned by a second admin via m-of-n matching the mez-recovery kill-switch ceremony signer set. Admin sessions require staff login plus WebAuthn step-up plus HSM-backed signing with role-based approval. Regulators get read-only auditor sessions via a separate OAuth client class; validators get node certificates + validator-key attestation, not admin credentials.
{
"method": "admin_emergencyHalt",
"envelope": {
"signer_hsm_id": "yubi-01",
"cosigner_hsm_id": "yubi-02",
"cryptographic_epoch": 3,
"composite_signature": "ed25519 ‖ ml_dsa_65 ‖ slh_dsa",
"ceremony_id": "cer_01HX..."
}
}
AI agents call Moxie the same way developers do
An AI agent can attach an AgentInvocation envelope to state-mutating SDK calls that opt into agent context. Depth-bounded delegation (≤ 8) under HARNESS-I, biscuit/macaroon attenuate-only scopes, composite ed25519 + ML-DSA-65 + SLH-DSA signatures, F22 chain verifier, F21 hash-chained audit record closing the loop (directive → prompt → model → plan → Moxie call → outcome). The MCP tool surface ships as @moxie/sdk-mcp — every continuous-market tool has a matching MCP binding.
MCP tool surface — @moxie/sdk-mcp
The MCP surface maps onto Continuous-CPCAM create, quote, swap, provide liquidity, withdraw, resolve, prune, market reads, LP reads, LP lists by market/owner, pending clearings, and resolved-market lookup. Each tool validates input via Zod against the same schemas the TypeScript SDK exposes. Agents that depend on the tool surface inherit the conformance corpus checks.
$ npm install @moxie/sdk-mcp
// Agent-enabled gateways attach this envelope before submission.
const agentContext = {
invocation_id: crypto.randomUUID(),
agent_id: "did:moxie:agent:treasury-autopilot@v4",
principal_chain: [
"alice",
"planner@v11",
"treasury-autopilot@v4",
],
delegation: {
delegation_id: "b6...1f",
scope: [
["OpInstance", "moxie:swap:usdc:moxie:le50k"],
["RuntimeBound", "per_tx_usd", 25000],
],
ttl_ms: 120000,
depth: 3, // cap ≤ 8
revocable: true,
},
cryptographic_epoch: 3,
composite_signature: "ed25519 | ml_dsa_65 | slh_dsa",
};
Introduction
Moxie is a programmable exchange for contract markets. A contract market can be as simple as an in-game item resale market or as complex as a racing pool, parlay, royalty-linked asset, insurance payout, coupon, or cross-market portfolio. The developer surface is ordinary SDK + JSON-RPC: create the market, quote the trade, submit the order, read the receipt, and subscribe to updates.
Under the hood, Moxie owns price discovery, clearing, settlement, liquidity, receipts, release/recovery, and reliance export. Mass supplies the institutional admissibility plane. The terminal runtime primitive is AdmissibleObligationTransition; event-contingent settlement, brand/IP, securities, insurance, parimutuels, coupons, payouts, non-event trading, and agent actions are TemplatePack/AOT lanes over the same kernel. ClaimGraph and ClaimCompiler are the typed source-IR/lowering layer for contracts and claims; the lowered AOT remains consensus truth.
The API is JSON-RPC 2.0 over HTTPS plus staged REST surfaces. The registered moxie_* catalog includes moxie_getBrandExperiences, moxie_merchOrder, the PTJC moxie_racing* surface, the settlement-job pair moxie_estimateSettlementBatch + moxie_submitSettlementBatch, and the terminal-kernel surface moxie_getTerminalKernelState, moxie_getTerminalTemplatePacks, moxie_getTerminalRelianceInstruments, moxie_getTerminalHotMarketStatus, moxie_lowerClaimGraph, and moxie_buildTransaction { method: "terminalKernel" }. The @moxie/sdk TypeScript client exposes flat named methods, SDK-owned wire types, typed errors, and the webapp compatibility facade; moxie-sdk (Rust, Python) are the Tier 1 counterparts. The SDK can call the mounted compliance preflight route today; signed native writes can echo a preflight binding into moxie_submitSigned, and racing writes also require idempotency plus a chain-bound chain_binding.settlement_batch. PTJC production wagering remains gated by the Thai legal opinion and deployment smoke witness. REST parity gating currently covers OAuth, corridor, webhooks, audit-chain, regulator, portfolio, app-install, agent-invocations, and revenue REST surfaces.
Base URLs
Content Type
All requests and responses use application/json.
SDK Method Families
health(), getBrands(), getBrandExperiences(), getLeaderboardPage(), getPools(), merchOrder(), ammSwap(), spotOrder(), getPerpMarkets(), and getCalibration().
createContinuousMarket(), getContinuousMarket(), quoteContinuous(), swapContinuous(), LP reads/writes, pending clearings, and resolved-market pruning.
moxie_getStateRoot(block_height_hex) exposes retained block state roots with source: "block" and falls back to the bounded state_root_history ring after full block payloads are pruned. Heights beyond both windows return the canonical -32004 envelope with requested_height, chain_oldest_height, chain_newest_height, and pruned_count.
moxie_getLeaderboard is a current-node legacy offset surface accepting brand_id/brandId, window, metric, offset, and limit. Expanded entries include rank, address, points, score, tier, score_components (token, experience, prediction, cultural, community), display_name, avatar_url, brand_id, rank_delta, and country_code. Legacy page envelopes include items, has_more, offset, limit, and stats with participant counts, tier counts, scoring weights, as_of_block, prediction_count, window, metric, and optional brand_id.
client.terminal() / client.terminal exposes terminal roots, full AOT state, ProductLegalProfile + TemplatePack registries, recognized reliance instruments, certified hot-market replay status, deterministic moxie_lowerClaimGraph, unsigned terminalKernel transaction building, and preflight-bound moxie_submitSigned submission.
getTickets(), ticketCreate(), ticketPurchase(), and ticketRedeem() are native SDK/RPC methods. Ticket-create payloads still carry metadataHash for the native transaction envelope; ticket read models do not persist or return that field. Reads return ticketId, eventId, brandId, creator, tier, price, totalSupply, sold, section and seat fields, event and venue labels, timing fields, cardLabel, ticketImage, venueImage, and compatibility venue_image.
getMerchandise(), merchOrder(), purchaseMerch(), and merchFulfill() are shipped SDK/RPC methods. moxie_merchOrder returns a typed receipt with order_id, item_id, brand_id, buyer, quantity, unit_points, total_points, payment_token, status, created_at_block, optional escrow_tx_hash, optional estimated_delivery, and fulfillment_status.
racing() / client.racing over 21 registered moxie_racing* JSON-RPC methods: race-day, race, pool, dividend, bet, jockey, leaderboard, settlement-receipt, and racing epoch-commitment reads; bettor preview/place; and strict-admin race-card, pool lifecycle, result, void, settlement, and treasury-ledger writes. Racing writes enforce compliance commitment, idempotency replay semantics, and chain_binding.settlement_batch lowering through the generic settlement/AOT receipt path; successful writes return PENDING_CHAIN_RECEIPT until the canonical receipt lands. Production wagering remains blocked until legal and deployment witnesses close.
client.brands() including experiences(...) and merch_order(...), markets(), events(), drops(), personas(), accounts(), positions(), swaps(), chain(), governance(), perps(), predictions(), vault(), calibration(), compliance(), racing(), terminal(), arb(), and raw().
client.accounts, brands including get_brand_experiences(...) and merch_order(...), drops, ephemeral, governance, markets, personas, staking, trading, racing, terminal, raw, and rpc().
client.call<T>(), Rust client.call<T>()/client.raw(), and Python client.rpc() cover the full registered method catalog when a typed wrapper lags.
import { Client } from "@moxie/sdk";
const moxie = new Client({
apiKey: "mxat_...",
baseUrl: "https://api.moxie.xyz",
});
$ curl https://api.moxie.xyz \
-H "Authorization: Bearer mxat_..." \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"moxie_health","params":[]}'
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"status": "healthy",
"synced": true,
"block": 847293,
"peers": 12,
"highestBlock": 847293,
"chainId": 1337
}
}
Authentication
The API uses Bearer token authentication. Four credential classes are issued in distinct forms: secret developer keys are prefixed mxk_sk_<env>_<kid>_, publishable developer keys mxk_pk_<env>_<kid>_, OAuth-exchanged bearer tokens mxat_, SIWE player sessions mxs_player_<addr>_, and short-lived Mass-app-install tokens miat_ (TTL ≤ 900s). Exchange a secret key into a bearer via the mounted gateway or ops route POST /oauth/token; pass the bearer as Authorization: Bearer on every request.
The SDK accepts the token via the apiKey constructor option. For client-side signing, pass a signer with addressFromPrivateKey() and signTransactionHash(). For admin routes, submit signed envelopes from an HSM-rotatable admin signer; see the Authentication overview above for the four auth profiles.
const moxie = new Client({
apiKey: "mxat_...",
});
import { Client } from "@moxie/sdk";
const moxie = new Client({
signer: {
addressFromPrivateKey: deriveAddress,
signTransactionHash: signHash,
},
});
Mutating Calls
Writes use explicit idempotency, validation, and confirmation discipline. callMutation()-backed methods generate an Idempotency-Key from the registered RPC method when the caller does not provide one; racing JSON-RPC writes enforce same-key/same-body replay and same-key/different-body mismatch semantics, while broader mutation replay enforcement remains route-specific. SDK validators reject malformed event windows, amounts above MAX_TRANSFER_AMOUNT / MAX_STAKE_AMOUNT / MAX_ORDER_SIZE, reserved addresses, and oversized serialized transactions before transport. Signer-backed native helpers map SDK aliases such as ammSwap, spotOrder, and createContinuousMarket to their moxie_* RPC names for idempotency, then build, sign, submit through moxie_submitSigned, and wait for receipt confirmation by default. Pass waitForReceipt: false only when the caller owns polling.
Compliance preflight is available on supported NativeMutationOptions surfaces and on direct signed submissions through the preflight binding object accepted by moxie_submitSigned. When Mass compliance write admission is enabled, enhanced mutating calls fail closed unless the binding matches sender, purpose, entity ids, as-of block, TTL, jurisdiction, and commitment. A blocked verdict raises MoxieComplianceBlockedError with the server verdict preserved in error metadata.
Write Headers
-_.:; racing JSON-RPC writes and idempotent REST mutation routes enforce replay on the server.
const gate = await moxie.preflightCompliance({
entity_ids: [accountEntityId],
purpose: "TerminalKernel",
jurisdiction: "USA",
});
const txHash = await moxie.terminal().submitSigned(signedEnvelope, {
idempotencyKey: "terminal-aot-2026-04-30-001",
preflight: {
commitment: gate.commitment,
asof_block: gate.asof_block,
ttl_ms: gate.ttl_ms,
entity_ids: [accountEntityId],
purpose: "TerminalKernel",
jurisdiction: "USA",
},
});
// sendRawTransaction has already waited for a successful receipt.
console.log(txHash);
Errors
The API returns standard JSON-RPC wire errors as { code, message, data? }. The TypeScript SDK maps those and HTTP failures into subclasses of MoxieSdkError: MoxieRateLimitError, MoxieTimeoutError, MoxieNetworkError, MoxieJsonRpcError, MoxieComplianceBlockedError, MoxieAuthError, and MoxieInvalidInputError. Each preserves available JSON-RPC code, HTTP status, backend error code, request ID, retry-after value, and retryability metadata.
Server errors (5xx), rate-limit responses, JSON-RPC -32005, timeouts, and retryable network failures are automatically retried with exponential backoff up to maxRetries (default 3). Rate limit responses may include Retry-After and X-RateLimit-Remaining headers when the node or gateway provides them.
HTTP Status Codes
Retry-After when present and retries with exponential backoff.
import {
MoxieJsonRpcError,
MoxieRateLimitError,
MoxieSdkError
} from "@moxie/sdk";
try {
await moxie.call("moxie_unknown", []);
} catch (err) {
if (err instanceof MoxieRateLimitError) {
console.log(`Retry in ${err.retryAfter ?? 1}s`);
} else if (err instanceof MoxieJsonRpcError) {
console.log(err.code, err.requestId);
} else if (err instanceof MoxieSdkError) {
console.log(err.kind, err.status);
}
}
Pagination
Canonical pagination follows the Moxie PLATONIC I-9 cursor-only contract: clients pass opaque cursors through unchanged, never decode them, and treat null / absent cursor as the first page. Current-node legacy JSON-RPC list handlers still accept limit and offset on explicitly documented surfaces and cap limit at 200.
Do not inspect or derive meaning from pagination tokens. Cursor surfaces advance with the backend-provided cursor. Current-node legacy offset surfaces advance by the number of returned items until the handler migrates to the cursor envelope.
Response Fields
import { Client, RpcLeaderboardEntry } from "@moxie/sdk";
type LeaderboardPage = {
items: RpcLeaderboardEntry[];
has_more: boolean;
offset: number;
limit: number;
};
const client = new Client();
let offset = 0;
let hasMore = true;
do {
const page = await client.call<LeaderboardPage>("moxie_getLeaderboard", [{
brand_id: "0x<brand>",
window: "weekly",
metric: "points",
limit: 20,
offset,
}]);
page.items.forEach(row => console.log(row.rank, row.address, row.points));
offset += page.items.length;
hasMore = page.has_more;
} while (hasMore);
Amounts
All monetary values on the wire are raw 18-decimal strings. "1000000000000000000" equals 1.0 USDC (the primary settlement currency). Never use parseFloat() on raw amounts: they exceed JavaScript’s safe integer range.
The SDK exports wire-safe helpers directly from @moxie/sdk.
Utilities
"1000.5" to wire format "1000500000000000000000".
import {
coerceFixedPointString,
formatFixedPointRaw,
parseFixedPointDecimal
} from "@moxie/sdk";
parseFixedPointDecimal("100");
// "100000000000000000000"
formatFixedPointRaw("1000000000000000000");
// "1"
coerceFixedPointString("1500000000000000000000");
// "1500000000000000000000"
Brands
A Brand represents an IP-linked derivative on the clearing network: a sports league, entertainment property, or cultural franchise whose token price is coupled to real-world event outcomes. Each brand has a token, a market stage, a temperature regime (Cold/Warm/Hot regulatory graduation), and a revenue pool that accumulates fees from trading, licensing, drops, and auctions.
Lists all brands. The current JSON-RPC handler is moxie_getBrands; the REST route returns the same RpcBrand[] wire objects without pagination metadata.
Scheduled brand experiences are exposed by moxie_getBrandExperiences with an optional brand ID filter. The Tier 1 SDK names are TypeScript getBrandExperiences(brandId?), Rust client.brands().experiences(Some(brand_id)), and Python client.brands.get_brand_experiences(brand_id). Each experience carries id, brand_id, title, subtitle, category, starts_at, location, points_cost, capacity fields, tier requirement, featured flag, and status.
Merchandise is exposed by moxie_getMerchandise, moxie_purchaseMerch, moxie_merchOrder, and moxie_merchFulfill. The typed order path is TypeScript merchOrder(params), Rust client.brands().merch_order(params), and Python client.brands.merch_order(...); it returns the RpcMerchOrderReceipt fields documented in the method-family summary.
REST Notes
price, ticker, and reserve fields.
moxie.search() for cross-resource search; /api/v1/brands itself is a list route.
Brand Object
FIGHT, CITY, PLAY
const brands = await moxie.getBrands();
brands.forEach((brand) => {
console.log(brand.ticker, brand.price);
});
[
{
"brand_id": "0x<64-hex-brand>",
"token_id": "0x<64-hex-token>",
"ticker": "FIGHT",
"name": "UFC",
"price": "2470000000000000000",
"reserve_brand": "1000000000000000000000",
"reserve_moxie": "2470000000000000000000"
}
]
const tokenId = brands[0]?.token_id;
if (tokenId) {
const [price, volumes, stages] = await Promise.all([
moxie.getTokenPrice(tokenId),
moxie.getPoolVolume(),
moxie.getMarketStages(),
]);
}
Markets
Markets represent trading venues for brand tokens. Each market progresses through five stages: BondingCurve, EquilibriumAmm, HybridAmmClob, FullClob, and CrossListed. The orderbook merges synthetic AMM levels with resting CLOB orders.
Lists all markets through JSON-RPC. Filter client-side by brand, regime, volume, spread, or price.
Retrieves candle data for a market. Single-market summary reads use SDK/JSON-RPC helpers.
Returns L2 orderbook depth. Bids and asks include price, quantity, and order count at each level.
Market Object
const book = await moxie.getOrderBook(
"0x<64-hex-market>"
);
book.bids.forEach(level => {
console.log(level.price, level.quantity, level.order_count);
});
{
"market_id": "0x<64-hex-market>",
"bids": [
{ "price": "2450000000000000000", "quantity": "500000000000000000000", "order_count": 3 },
{ "price": "2440000000000000000", "quantity": "1200000000000000000000", "order_count": 7 }
],
"asks": [
{ "price": "2480000000000000000", "quantity": "300000000000000000000", "order_count": 2 }
],
"bid_count": 10,
"ask_count": 8
}
Swaps
AMM swaps execute against constant-product pools with Probability-Weighted AMM coupling. The pool price adjusts based on prediction market outcomes through a bounded geometric function.
Lists all AMM pools with reserves, fees, and 24h volume.
Returns the token-side quote fixture exposed by the REST node. For executable slippage protection, compute and pass min_amount_out to the SDK mutation.
Executes an AMM swap. SDK write helpers return a transaction hash and wait for a successful receipt by default; use waitForReceipt(txHash) only when polling manually.
Body Parameters
USDC/MOXIE aliases or 32-byte token IDs for the swap direction.
parseFixedPointDecimal() for human decimal conversion.
import { parseFixedPointDecimal } from "@moxie/sdk";
const txHash = await moxie.ammSwap({
key: "0x<64-hex>",
pool_id: "0x<64-hex-pool>",
token_in: "USDC",
token_out: "0x<64-hex-token>",
amount_in: parseFixedPointDecimal("1000.0"),
min_amount_out: parseFixedPointDecimal("950.0"),
});
// ammSwap has already waited for a successful receipt.
console.log(txHash);
Continuous-CPCAM
Continuous-outcome AMM over an interval [omega_lo, omega_hi], discretised on a grid, paired with a convex entropy generator. Three creator choices are integer-coded on the wire: grid_size_code ∈ 0..=5 (N8, N16, N32, N64, N128, N256), generator_code ∈ 0..=4 (Quadratic, Entropy, Logarithmic, PowerMean2, ExponentialKernel), and an optional swap_fee_bps ∈ 0..=10000 (basis points of every Buy accruing to LP positions prorated by liquidity_budget). LPs provide range liquidity with a shape (shape_code ∈ 0..=2: PiecewiseConstant, Gaussian, Exponential); withdraw returns principal plus accrued fees. Quotes may defer when the integrator has not converged; a deferred quote returns pending_id and the caller polls getPendingClearings.
Creates a continuous market. Body fields: key (64-hex transaction key), market_id (64-hex), omega_lo / omega_hi (18-decimal FixedPoint wire strings), grid_size_code, generator_code, initial_mu (array of FixedPoint; size matches the grid), and optional swap_fee_bps.
Reads market state by market_id: generator, grid, current mu, total liquidity budget, fee accumulator.
Returns { deferred, post_mu, state_prices, total_payout, iterations_used, pending_id, last_iterate }. A non-deferred quote is directly executable; a deferred quote means the integrator needs more iterations than the per-block budget permits. Poll moxie_getPendingClearings until the pending id resolves.
Submits a continuous swap. Body: { key, market_id, omega_a, omega_b, delta_amount, direction_code } where direction_code is 0 (Buy) or 1 (Sell). Returns a transaction hash.
Commits a range [omega_lo, omega_hi] with a weighting shape_code (and shape_param_a, optional shape_param_b) and a liquidity_budget. The caller’s swap_fee_bps share accrues to the position prorated by liquidity_budget across all LP positions in range for the duration of residency.
Closes an LP position and returns principal plus accrued fees.
Terminates an active market. Only the creator may resolve. Every open ContinuousLpPosition for market_id is paid out (liquidity_budget + accrued_fees from custody back to owner) and removed; subsequent swapContinuous and provideContinuousLiquidity calls against the market return InvalidParameter. The market entry remains in state for historical queries until pruned.
Lifecycle close: removes resolved markets whose resolution block is older than CONTINUOUS_MARKET_RESOLUTION_RETENTION_BLOCKS = 10_000. Wall-clock duration depends on node cadence: about 5.56h at the default 2,000ms block time and 2.22h at the chained 800ms target. Open access: any nonce-holding account may submit once the retention threshold has elapsed.
Reads a single LP position by position_id: range, shape, liquidity budget, accrued fees since last withdraw.
Observability read: all LP positions in a market. Supports dashboards and fee-accrual monitoring.
Paginated read of every LP position held by an owner across all continuous markets. Capped at 200 positions per call; callers page through larger inventories. Backs LP-dashboard workflows where a provider tracks accrued fees and ranges across concurrent markets.
Returns the block number at which a given market_id was resolved, or indicates the market is not yet resolved. Backs audit tooling and the retention-window check before pruneResolvedContinuousMarkets.
Lists deferred quotes awaiting further integrator iterations. Each entry carries pending_id, last_iterate, and estimated blocks-to-completion.
Enum codes (wire)
N8, N16, N32, N64, N128, N256. Wider grids are higher resolution at the cost of per-swap integrator budget.
Quadratic, Entropy, Logarithmic, PowerMean2, ExponentialKernel. The generator sets the curvature of the cost function and the shape of the state-price response.
Buy (0), Sell (1).
PiecewiseConstant, Gaussian, Exponential. Determines how LP liquidity is weighted across the provided range.
liquidity_budget. Omit for a fee-less market.
import {
Client, GridSizeCode, GeneratorCode,
DirectionCode, ShapeCode,
} from "@moxie/sdk";
const moxie = new Client();
// 1. Creator opens a continuous market
await moxie.createContinuousMarket({
key: KEY, market_id: MKT,
omega_lo: "0",
omega_hi: "1000000000000000000",
grid_size_code: GridSizeCode.N64,
generator_code: GeneratorCode.Entropy,
initial_mu: ["500000000000000000"],
swap_fee_bps: 30,
});
// 2. LP provisions a Gaussian range
await moxie.provideContinuousLiquidity({
key: KEY, position_id: POS, market_id: MKT,
omega_lo: "100000000000000000",
omega_hi: "500000000000000000",
shape_code: ShapeCode.Gaussian,
shape_param_a: "300000000000000000",
shape_param_b: "50000000000000000",
liquidity_budget: "100000000000000000000",
});
// 3. Trader quotes + swaps (Buy direction pays fee)
const q = await moxie.quoteContinuous({
market_id: MKT,
omega_a: "100000000000000000",
omega_b: "200000000000000000",
delta_amount: "10000000000000000000",
direction_code: DirectionCode.Buy,
});
if (!q.deferred) {
await moxie.swapContinuous({
key: KEY, market_id: MKT,
omega_a: "100000000000000000",
omega_b: "200000000000000000",
delta_amount: "10000000000000000000",
direction_code: DirectionCode.Buy,
});
}
// 4. LP withdraws principal + accrued fees
await moxie.withdrawContinuousLiquidity({
key: KEY, position_id: POS,
});
$ curl -X POST http://localhost:8545 \
-H "content-type: application/json" \
-d '{"jsonrpc":"2.0","id":1,
"method":"moxie_getContinuousLpPositionsByMarket",
"params":[{"market_id":"0x..."}]}'
$ curl -X POST http://localhost:8545 \
-H "content-type: application/json" \
-d '{"jsonrpc":"2.0","id":2,
"method":"moxie_getPendingClearings","params":[]}'
Predictions
Prediction events are binary or multi-outcome markets tied to real-world outcomes, settled in USDC. Events resolve in Phase 1 of each block, before any trades execute: this is event-atomic settlement, where prediction resolution and spot repricing happen in a single block. Resolution reprices the coupled brand token through the PW-AMM.
Lists prediction events. Filter by brand, status (Open, Closed, Resolved, Settled).
Retrieves prediction odds for a single event through JSON-RPC.
Creates a new prediction event through the signed native SDK path.
Mints outcome shares for a prediction position. Specify prediction ID, event ID, outcome index, and amount.
Trades prediction shares through the signed native SDK path.
Event Object
["McGregor KO", "Decision", "Opponent"]
Open → Closed → Resolved → Settled
// Create event
const eventId = "0x<64-hex-event>";
const marketId = "0x<64-hex-market>";
const createTx = await moxie.createEvent({
key: "0x<64-hex>",
event_id: eventId,
market_id: marketId,
opens_at: 1743724800,
closes_at: 1743811200,
brand_id: "0x<64-hex-brand>",
title: "McGregor vs Chandler",
});
// Mint YES shares
const mintTx = await moxie.predictionMint({
key: "0x<64-hex>",
prediction_id: "0x<64-hex-prediction>",
event_id: eventId,
outcome_index: 0,
amount: "500000000000000000000",
});
// Check probabilities
const live = await moxie.getPredictionOdds(eventId);
console.log(live.yes_pct, live.no_pct);
// ["0.62...", "0.38..."]
Drops
VRF-based reward distributions. A creator funds a pool, sets a weight function and duration. At the designated block, the on-chain VRF selects winners weighted by stake. Winners claim rewards before the deadline.
Lists drops. Filter by brand or status (Upcoming, Active, Revealing, Completed).
Creates a new drop with reward pool, weight function, execution block, and claim deadline.
Claims winnings for a completed drop. Only callable by winners.
Weight Functions
const dropId = "0x<64-hex-drop>";
const dropTx = await moxie.dropCreate({
key: "0x<64-hex>",
drop_id: dropId,
brand_id: "0x<64-hex-brand>",
reward_pool: "10000000000000000000000",
weight_function: "sqrt",
execution_block: 900000,
claim_deadline_block: 901000,
});
// Later: claim winnings
const claimTx = await moxie.dropClaim({
key: "0x<64-hex>",
drop_id: dropId,
});
const drops = await moxie.getDrops();
const active = drops.filter((drop) => drop.status === "Active");
Personas
Belief-weighted character tokens tied to a parent brand. Each persona has an LMSR belief state coupled to the brand’s prediction markets. Shares trade on a bonding curve until graduation to a full brand token.
Lists persona tokens. Filter by brand.
Retrieves a single persona with belief weight, supply, price, and holder count.
Buys persona shares. Cost determined by the bonding curve.
Sells persona shares. Proceeds determined by the bonding curve.
Persona Object
// List personas for UFC
const brandId = "0x<64-hex-brand>";
const personaId = "0x<64-hex-persona>";
const personas = await moxie.getPersonas(brandId);
// [{ name: "McGregor", price: "0.85..." },
// { name: "Chandler", price: "0.42..." }]
// Buy shares
const quote = await moxie.personaBuyCost(personaId, "100000000000000000000");
const buyTx = await moxie.personaBuy({
key: "0x<64-hex>",
brand_id: brandId,
persona_id: personaId,
delta_shares: "100000000000000000000",
max_cost: quote.net_cost,
});
// Sell shares
const sellTx = await moxie.personaSell({
key: "0x<64-hex>",
brand_id: brandId,
persona_id: personaId,
delta_shares: "50000000000000000000",
});
Accounts
Query account state: balances across all tokens, transaction history, staking positions, and KYC tier. Transfer tokens, stake to validators, and unstake.
Lists all token balances for an account. Each entry includes token symbol, balance, and current price.
Paginated transaction history. Each transaction includes type, block, success status, and error message if failed.
Transfers and staking are native signed SDK mutations, not REST account routes.
KYC Tiers
const address = "0x<40-hex-address>";
const [balance, nonce, kyc] = await Promise.all([
moxie.getBalance(address),
moxie.getNonce(address),
moxie.getKycLevel(address),
]);
console.log(balance, nonce, kyc.kycLevel);
const balances = await moxie.getTokenBalances(address);
balances.forEach(b => {
console.log(b.token_id, b.balance);
});
const txHash = await moxie.transfer({
key: "0x<64-hex>",
to: "0x<40-hex-address>",
amount: "500000000000000000000",
token: "0x<64-hex-token>",
});
console.log(txHash);
Positions
Cross-margined clearinghouse positions. A single USDC-denominated margin pool backs spot, prediction, perpetual, and liquidity positions. Diversified portfolios require less capital because the clearinghouse understands brand correlation and offsets hedged exposure.
Lists positions for an account. Filter client-side by market or kind (BrandSpot, BrandPrediction, Standalone).
Position Object
const positions = await moxie.getPositionsDetailed(
"0x<40-hex-address>"
);
positions
.filter((p) => p.kind === "BrandSpot")
.forEach(p => {
console.log(
p.marketId,
p.size,
p.marginRequirement
);
});
Governance
On-chain governance through ve$MOXIE vote-escrowed tokens. Proposals progress through Pending, Active, Passed, Rejected, and Executed states. Voting power is proportional to locked MOXIE amount and lock duration.
Lists governance proposals. Filter by status or proposer.
Submits a new governance proposal with title, description, and executable actions.
Casts a vote on a proposal. Pass support: true/false and optional amount to weight.
// Submit proposal
const prop = await moxie.governanceSubmit({
proposer: "0x<40-hex-address>",
title: "Reduce pool fees to 20bps",
description: "...",
actions: [{ type: "SetPoolFee", fee: 20 }],
});
// Vote
const vote = await moxie.governanceCastVote({
voter: "0x<40-hex-address>",
proposalId,
support: true,
});
IP Graph
The IP licensing relationship graph. Nodes represent entities (brands, licensors, distributors). Edges represent licensing agreements, revenue splits, and IP transfer relationships with weights.
Returns the current IP graph as { nodes, edges, totalNodes, totalEdges }. Filter client-side by brand, entity, or relationship.
const graph = await moxie.getIpGraph();
const brandId = "0x<64-hex-brand>";
const nodes = graph.nodes.filter((n) => n.brandId === brandId);
const edges = graph.edges.filter(
(e) => e.fromBrand === brandId || e.toBrand === brandId
);
edges.forEach(e => {
console.log(e.fromBrand, "->", e.toBrand, e.relationship);
});
Chain
Chain-level queries: node health, block retrieval, transaction receipts, and historical state-root proofs. Blocks execute in three deterministic phases. The default block-time constant is 2,000ms; chained execution targets 800ms, while consensus tests still exercise the 600ms centerline.
Returns chain ID, current block number, sync status, peer count, and pending transaction count.
Retrieves a block by number. Use latest for the most recent block.
Returns a transaction receipt when present; a missing receipt serializes as null. The SDK’s signed mutation helpers poll via waitForReceipt(txHash) by default.
Returns the historical block-header state root at a hex block height plus the current retained chain window. Heights older than retained history fail closed with JSON-RPC code -32004 and a pruned history unavailable envelope carrying requested_height, chain_oldest_height, chain_newest_height, and pruned_count.
Returns the current bare receipt by tx hash. The Tier 1 SDK method is getTransactionReceipt(txHash); signed mutation helpers call the same receipt path through waitForReceipt(txHash). RpcReceipt carries optional camelCase settlementBatchRoot: string | null and events: RpcReceiptEvent[]. Terminal or single-chunk SettlementBatch receipts populate settlementBatchRoot; NativeTx::PayoutReturned receipts include a PayoutReturned event with payoutId, recipient, amount, and returnCode. A23 proof methods (moxie_getReceipt with includeProof and moxie_getReceiptsForBlock) are publicly registered; their RpcMerkleReceipt.digestInput mirrors settlementBatchRoot and commits receipt events through eventsRoot.
Per-tx gas estimation. EvmCall paths reserve the declared gas_limit at admission, reject underpriced max_fee_per_gas/max_priority_fee_per_gas caps against the current base fee, execute at the effective EIP-1559 gas price, and reconcile block gas to revm-metered receipt.gas_used after execution. Non-EVM variants still use their static consensus tiers.
Settlement-job dry-run for the moat #1 primitive. Single named param { payload: SettlementBatchPayload }. Returns { gas_estimate: u64, manifest_root: 0x-prefixed 32-byte hex, validation: { ok: bool, errors: string[] }, chunked_mode: bool, is_terminal_chunk: bool, staging_complete: bool }. Per invariant I-12, dev-input failures return HTTP 200 with validation.ok = false rather than a JSON-RPC envelope error; reserved 4xx / Internal envelopes are transport-only. Public read class — no auth required. The gas heuristic constants are pub-exported in crates/moxie-rpc/src/types.rs: BASE_GAS = 21,000, GAS_PER_PAYOUT = 5,000, GAS_PER_MINT = 5,000, GAS_PER_BURN = 5,000, GAS_PER_ORACLE = 3,000, GAS_PER_MARGIN = 3,000, GAS_PER_CHUNK = 1,000.
Settlement-job write for the moat #1 primitive. Auth class: AuthWrite (mirrors moxie_submitSigned rate-limiting and auth). Mandatory Idempotency-Key header on every request (I-3). Bi-modal envelope: trusted-gateway auth-only mode { payload }, or client-side ECDSA signed mode { payload, signature: 0x-prefixed-hex, signer: 0x-prefixed-20-byte-hex, cryptographic_epoch?: number }. Half-pair envelopes (signature without signer or vice versa) return RpcErr::InvalidParams. The handler re-runs payload.validate_cheap_checks() and payload.compute_manifest_root() before mempool dispatch and rejects manifest-root mismatch. Dispatches via the same submit_signed_transaction() path as moxie_submitSigned: HEAL A1 active-suite verification plus the downgrade gate. Returns { tx_hash: 0x-prefixed 32-byte hex }; clients then call waitForReceipt(txHash) and read settlementBatchRoot on the terminal receipt. Returned payouts are submitted as signed NativeTx::PayoutReturned transactions and observed through receipt.events.
Returns the live { baseFeePerGas, maxPriorityFeePerGas } envelope. Base-fee adjusts per block via the canonical Roughgarden 2021 update rule (±12.5% bound, denominator δ = 8, 1-wei wake-up bump, MIN_BASE_FEE_PER_GAS floor). maxPriorityFeePerGas is the nonzero deterministic suggestion; EvmCall mempool ordering derives its cleartext priority byte from the paid priority-fee cap.
Returns the terminal clearing-kernel snapshot: root registry, role-scoped authority grants and action nonces, ProductLegalProfile and TemplatePack registries, RiskGeneratorV1 snapshots, executable-depth certificates and consumed keys, release/recovery authorizations, recognized reliance instruments and envelopes, admitted AOT ledger, certified hot-market deltas/status, and bounded CPCAM adapter certificates. Sibling reads expose narrower views: moxie_getTerminalKernelRoot, moxie_getTerminalTemplatePacks, moxie_getTerminalRelianceInstruments, and moxie_getTerminalHotMarketStatus.
Deterministic source-layer preflight for product compilers. Single named param { program: ClaimProgramDefinition, graph: ClaimGraph, context: ClaimLoweringContext }. The node validates the program, graph, evidence, risk, reliance, and lowering context, then returns { program_id, graph_id, graph_root, compiler_version, aot } without mutating chain state. Consensus truth remains the lowered AdmissibleObligationTransition.
const info = await moxie.health();
console.log(info.block, info.status);
// 847293 "healthy"
const block = await moxie.getBlock("latest");
console.log(block.transactionCount, block.hash, block.receiptsRoot);
const receipt = await moxie.getTransactionReceipt(txHash);
console.log(receipt.success);
const root = await moxie.call<{
block_height: string;
state_root: string;
source: "block" | "state_root_history";
chain_newest_height: string;
}>("moxie_getStateRoot", ["0x1234"]);
console.log(root.state_root);
// A23 proof APIs are registered: moxie_getReceipt(includeProof) and moxie_getReceiptsForBlock.
// Use getTransactionReceipt(txHash) when the current bare receipt is enough.
// EIP-1559 gas surface (B7) — dynamic base-fee plus paid priority suggestion
const fee = await moxie.gasFeeData();
console.log(fee.baseFeePerGas, fee.maxPriorityFeePerGas);
const est = await moxie.estimateGas(unsignedTx);
console.log(est.gasLimit, est.maxFeePerGas);
const terminal = await moxie.terminal().root();
console.log(terminal.terminal_kernel_root);
// Moat #1 — settlement-job dry-run + signed submit
const dryRun = await moxie.call<{
gas_estimate: number;
manifest_root: string;
validation: { ok: boolean; errors: string[] };
chunked_mode: boolean;
is_terminal_chunk: boolean;
staging_complete: boolean;
}>("moxie_estimateSettlementBatch", { payload: settlementPayload });
if (!dryRun.validation.ok) throw new Error(dryRun.validation.errors.join(", "));
// Auth-only trusted-gateway mode
const submitted = await moxie.call<{ tx_hash: string }>(
"moxie_submitSettlementBatch",
{ payload: settlementPayload },
{ idempotencyKey: "settle-2026-04-27-001" },
);
const rcpt = await moxie.waitForReceipt(submitted.tx_hash);
console.log(rcpt.success, rcpt.settlementBatchRoot, rcpt.events);
// settlementBatchRoot is populated for terminal/single-chunk SettlementBatch.
// PayoutReturned receipts expose the committed return event in rcpt.events.
Perpetuals
Perpetual contracts on IP-linked tokens. Open long or short positions, receive periodic funding payments, and close at any time. Funding rates are computed from mark-index price divergence and exposed on the perp market read model; the exact wall-clock interval follows configured block cadence.
Lists perpetual markets with funding rates, mark/index prices, open interest, and funding interval. Opening and closing positions are signed SDK mutations.
Body Parameters
true for long, false for short.
Reads a specific perpetual position. Closing positions is the signed perpClose() SDK mutation.
Body Parameters
Funding is visible on each PerpMarket; perpFunding() submits the funding-settlement native transaction when an operator needs to crystallize funding.
Funding Object
// Open a long on a perpetual market
const marketId = "0x<64-hex-market>";
const openTx = await moxie.perpOpen({
key: "0x<64-hex>",
market_id: marketId,
is_long: true,
size: "1000000000000000000000",
collateral_amount: "500000000000000000000",
persona_slug: "mcgregor",
});
console.log(openTx);
// Check funding rate
const markets = await moxie.getPerpMarkets();
const market = markets.find((m) => m.market_id === marketId);
console.log(market?.funding_rate, market?.funding_rate_negative);
// Close the position
const closeTx = await moxie.perpClose({
key: "0x<64-hex>",
market_id: marketId,
size: "1000000000000000000000",
is_long: true,
});
console.log(closeTx);
Contingent Orders
Event-contingent order state is exposed as a read model per account. The current TypeScript write helper is conditionalOrder() for price-triggered orders with optional event context; stop-event and parlay state appear in the pending-order read model as the native executor matures.
Lists pending contingent, stop-event, and parlay orders for a 20-byte account address.
Body Parameters
Submits a signed conditional order through the SDK/native transaction path.
Body Parameters
Reads all pending contingent-order families for the account; clients filter by type.
Body Parameters
contingent, stop_event, or parlay.
Lists all active contingent, stop-event, and parlay orders for the supplied account.
// Place a signed conditional order
const txHash = await moxie.conditionalOrder({
key: "0x<64-hex>",
market_id: "0x<64-hex-market>",
trigger_price: "2300000000000000000",
limit_price: "2250000000000000000",
quantity: "500000000000000000000",
is_buy: true,
event_id: "0x<64-hex-event>",
});
// Read pending contingent-family orders
const pending = await moxie.getContingentOrders(
"0x<40-hex-address>"
);
const parlays = pending.filter(
(order) => order.type === "parlay"
);
parlays.forEach((order) => {
console.log(order.order_id, order.market_id, order.condition);
});
Autonomous Events
Self-resolving prediction events are submitted through the signed createAutonomousEvent() SDK helper. The current node does not expose a REST create route; REST observability should be layered on the event read model as parity work.
Creates a signed CreateAutonomousEvent native transaction.
Body Parameters
Event read-side visibility is served through getEvents() and /api/v1/events.
// Self-resolving fight outcome event
const txHash = await moxie.createAutonomousEvent({
key: "0x<64-hex>",
description: "UFC 295 Main Event Winner",
affected_tokens: ["0x<64-hex-token>"],
factor_loadings: ["1000000000000000000"],
resolution_criteria: "ufc.event.295.main.winner != null",
base_probability: "500000000000000000",
lmsr_liquidity_b: "1000000000000000000000",
time_horizon_blocks: 200,
});
console.log(txHash);
// Event resolves automatically when
// oracle posts the fight result
const events = await moxie.getEvents();
console.log(events.length);
Reflexivity
The calibration and risk-reflexivity surfaces expose the reflexivity coefficient ρ (rho): a measure of how strongly prediction market outcomes feed back into the brand token price. When ρ is high, event resolution has outsized price impact; when low, the brand token trades independently of prediction markets.
Returns the current calibration state, including reflexivity diagnostics and OI cap controller state.
ReflexivityResult Object
{ eventId, weight, priceImpact }.
PwAmm, BinaryPayoff, Logit.
Returns the REST reflexivity diagnostic view. Use moxie_getCalibration for the consensus calibration state.
const calibration = await moxie.getCalibration();
const reflexivity = calibration.reflexivity as {
rho?: string;
severity?: string;
};
console.log(
reflexivity.rho,
reflexivity.severity
);
// REST diagnostic view
const risk = await moxie.getRiskReflexivity();
console.log(risk.reflexivity.reflexivity_score);
Circuit Breakers
The CircuitBreakerState endpoint reports node-wide halt state. Circuit breakers trigger on extreme price moves, abnormal reflexivity spikes, or governance action. During a halt, new orders are rejected; existing positions remain open but cannot be modified.
Returns the node-wide current CircuitBreakerState.
CircuitBreakerState Object
PriceMove, ReflexivitySpike, Governance, or null if not halted.
TypeScript SDK JSON-RPC helper for the same state.
const cb = await moxie.getCircuitBreaker();
const halted = Boolean(cb.is_halted ?? cb.halted);
const blocksRemaining = Number(cb.blocks_remaining ?? 0);
if (halted) {
console.log(
`Halted: ${cb.reason}`,
`blocks remaining ${blocksRemaining}`
);
} else {
console.log("Trading active");
}
Coupling Modes
The clearing engine supports three coupling modes that determine how prediction event outcomes affect the brand token price. The active mode is selected automatically based on the reflexivity coefficient ρ and can be overridden by governance.
Returns LMSR calibration for a market; coupling-mode governance remains a consensus-layer concept rather than a dedicated REST route.
CouplingMode Variants
Calibration Object
const calibration = await moxie.getCalibration();
const reflexivity = calibration.reflexivity as { severity?: string };
console.log(reflexivity.severity);
// "Elevated"
console.log(calibration.oi_cap_controller.phi);
// Current OI cap controller output
const lmsr = await moxie.getLmsrCalibration(
"0x<64-hex-market>"
);
console.log(lmsr.calibration.status);
Mutual Information
The MutualInformationEstimator computes the mutual information (MI) between prediction event outcomes and brand token price movements. The MI-derived κ (kappa) parameter controls the coupling strength in the PW-AMM: higher MI means tighter coupling between predictions and price.
Returns recently updated correlation estimates used by the intelligence layer.
MutualInformation Object
Returns top correlations and cohort summary statistics.
const recent = await moxie.getCorrelationsRecent();
recent.correlations.forEach((edge) => {
console.log(edge.event_a, edge.event_b, edge.rho, edge.n);
});
// Aggregate intelligence view
const snapshot = await moxie.getIntelligenceSnapshot();
console.log(snapshot.snapshot.cohort.mean_rho);
Soulbound Status
Non-transferable reputation credentials issued to accounts based on on-chain clearing activity. SoulboundStatus tokens are ERC-5192-style: they live in a wallet permanently and represent earned standing in the clearing network. Badges unlock tier promotions, governance weight boosts, and drop eligibility.
Lists all soulbound badges held by an account.
Returns the participant engagement profile that badge issuance is based on.
Badge Types
SoulboundStatus Object
true. Soulbound tokens cannot be transferred.
const address = "0x<40-hex-address>";
const badgesRes = await fetch(
`/api/v1/participants/${address}/badges`
);
const badges = await badgesRes.json();
badges.badges.forEach(b => {
console.log(b.badge_type, b.earned_at);
});
// "EarlyAdopter" 1024
// "PredictionStreak" 48201
// Pair with participant profile
const profileRes = await fetch(
`/api/v1/participants/${address}/profile`
);
const profile = await profileRes.json();
console.log(profile.composite_score);
Temperature Compliance
The TemperatureComplianceMapping defines regulatory graduation thresholds for brand tokens. Temperature graduation (Cold → Warm → Hot) is the clearing network's regulatory ramp: Cold brands trade with minimal KYC and no leverage; Warm brands unlock perpetuals and higher limits; Hot brands require full accredited-investor attestation and enable maximum leverage. This endpoint exposes the mapping between temperature regimes and required compliance checks, KYC tiers, and position limits.
Returns the current execution regime and compliance requirements for a token.
The TypeScript SDK exposes the same state via getTokenTemperature(tokenId).
TemperatureComplianceMapping Object
Cold, Warm, or Hot.
Contender, Elite, Champion, or Legend.
["AML", "Sanctions", "AccreditedInvestor"].
const tokenId = "0x<64-hex-token>";
const temp = await moxie.getTokenTemperature(tokenId);
console.log(
temp.regime,
temp.required_compliance_domains
);
// "Cold" ["ConsumerProtection", "AML"]
Mass-Moxie Bridge
The bridge has two directions. Inbound: a Mass kernel signs a MassIdentityAttestation { attestor, subject, kyc_level, jurisdiction, expiry_block, signature }; the Moxie chain verifies it against a genesis-pinned Mass public key (updatable only via Moxie governance, never discovered from the attestation itself), and the subject’s KYC tier is upgraded on-chain. Per-subject monotonic issued_at_block blocks downgrade-rollback replay. A ComplianceGatePayload carries {brand_id, target_stage, composed_tensor_hash, verdict, expires_at, authority, nonce} as a consensus-affecting NativeTx: absent or expired Approved gates block market promotion past HybridAmmClob; a Rejected gate at Warm+ demotes the market back to EquilibriumAmm.
Outbound: MassObservationRelay runs under a configured bridge mode and produces signed POST /v1/corpus/observe requests to the Mass kernel (OAuth bearer from MOXIE_BRIDGE_TOKEN, or mTLS). Aggregation emits per-epoch jurisdiction roll-ups, never trade-level data. Revenue distribution flows through Mass with harbor-level withholding computed against the composed compliance tensor; Moxie anchors the returned Merkle root via RevenueDistribute and a claim contract validates Merkle proofs against the stored root.
A universal correlation thread corridor_id = blake3(u32_le(|ik|) ‖ ik ‖ u32_le(|tx|) ‖ tx ‖ entity_32 ‖ u64_le(asof)) threads the five cross-kernel surfaces: ComplianceQuery, ComplianceAssertion, AttestationProof, MassObservation, and the Moxie 3PC operation_envelope. The current REST surface is /api/v1/corridors/id, /status, /preflight, and /trace/{cid}. Every kill path routed through the bridge traces back to an accepted contract version, a triggered policy code, a dispute or safety case, or a compliance verdict; regulator takedowns require an F38 CeremonyOverrideReceipt participating in block commit. No kill-by-Slack-DM.
Submits a Mass identity attestation to the Moxie chain via JSON-RPC. The attestation is a signed credential from a Mass kernel proving that an identity has passed a specific compliance check. Once attested, the Moxie account is upgraded to the corresponding KYC tier.
Body Parameters
Checks whether the target entities are likely to pass the compliance tensor for a specific operation. The chain remains the binding authority at admit time.
Body Parameters
NativeTx::PerpOpen or moxie_submitSigned.
Reads the account KYC level after attestations have been applied.
Preflight Response
moxie.compliance.* codes.
// Bridge a Mass KYC attestation to Moxie
const subject = "0x<40-hex-address>";
const attestTx = await moxie.submitMassAttestation({
key: "0x<64-hex>",
attestor: "0x<64-hex-attestor>",
subject,
kyc_level: "L2",
jurisdiction: "SYC",
expiry_block: 1200000,
signature: "0x<signature>",
});
console.log(attestTx);
// Can this account open a perp?
const gate = await moxie.preflightCompliance({
entity_ids: ["0x<64-hex-entity>"],
purpose: "NativeTx::PerpOpen",
jurisdiction: "SYC",
});
if (gate.allowed) {
console.log("Cleared for perp trading");
} else {
console.log(
"Blocked:",
gate.reasons.map((reason) => reason.code)
);
}
// Read the resulting account tier
const kyc = await moxie.getKycLevel(subject);
console.log(kyc.kycLevel);
WebSockets
Real-time subscriptions over WebSocket. The TypeScript SDK exposes connectBlockSubscription(wsUrl, onBlock) for moxie_subscribe("newBlocks"), including reconnect backoff and decimal/hex block-number parsing. The broader WsClient with authentication and topic routing remains the parity target.
Channels
Connection URL
Pass an explicit node WebSocket URL such as wss://api.moxie.xyz or ws://localhost:8545. The current SDK helper is not derived from baseUrl.
import { connectBlockSubscription } from "@moxie/sdk";
// Stream new blocks through moxie_subscribe("newBlocks")
const ws = connectBlockSubscription(
"wss://api.moxie.xyz",
(block) => {
console.log("Block", block.number, block.hash);
}
);
// Close when the view unmounts.
ws.close();
SDK Installation
The official TypeScript SDK wraps the JSON-RPC surface with SDK-owned wire types, named methods, typed errors, retry logic for HTTP and JSON-RPC rate limits, client-side signer injection, idempotent native mutations, compliance preflight on supported mutation surfaces, A27 validation preflight, receipt polling, getBrandExperiences(), typed merch order receipts, PTJC racing, terminal-kernel resources, expanded leaderboard types, the webapp compatibility facade, and the block-subscription helper used by the webapp. The Rust and Python SDKs expose matching Tier 1 resources for brand experiences, merch order receipts, racing, settlement, gas, and terminal kernel access plus raw RPC escape hatches for the registered catalog; their continuous-market helpers mirror the consensus MAX_ORDER_SIZE cap before transport. For Rust release dry-runs, moxie-types must publish before moxie-sdk because the SDK depends on the pinned protocol type crate. The conformance corpus and parity tooling keep the SDK surface aligned with the node; scripts/sdk-parity-check.mjs covers registered methods, racing methods, and REST surfaces. Full topic-routed WebSockets remain tracked as parity work.
Requirements
Client Options
http://localhost:8545
$ npm install @moxie/sdk@rc # v1.0.0-rc.1
$ cargo publish -p moxie-types --dry-run
$ cargo publish -p moxie-sdk --dry-run # after moxie-types is published at the pinned version
import { Client } from "@moxie/sdk";
const moxie = new Client({
apiKey: "mxat_...",
baseUrl: "https://api.moxie.xyz",
timeoutMs: 15000,
maxRetries: 5,
});
Amount Utilities
The SDK exports fixed-point helpers for converting between human-readable decimal strings and the 18-decimal raw wire format used by the protocol. Always use these instead of manual arithmetic.
Raw wire amounts are strings because they exceed JavaScript’s Number.MAX_SAFE_INTEGER. Mutating SDK methods send raw wire amounts; convert display input before submitting writes.
import {
coerceFixedPointString,
formatFixedPointRaw,
parseFixedPointDecimal,
} from "@moxie/sdk";
// Human → Wire
parseFixedPointDecimal("1000.5");
// "1000500000000000000000"
// Wire → Human
formatFixedPointRaw("2470000000000000000");
// "2.47"
// Validate raw wire value
coerceFixedPointString("184201000000000000000000");
// "184201000000000000000000"