Monaco SDK
Typed Rust client for the Monaco DEX REST API, auto-generated at build time from the vendored OpenAPI spec via progenitor. The build.rs reads rust-sdk/openapi/openapi.yaml, generates typed Rust code, and includes it via include!.
Code Generation
graph LR
YAML[openapi/openapi.yaml] --> BS[build.rs]
BS --> Gen[progenitor::Generator]
Gen --> OUT["$OUT_DIR/api.rs"]
OUT --> Lib["src/lib.rs<br/>include!()"]
Lib --> Client[monaco_sdk::Client]
Quick Start
[]
= "0.5"
= { = "1", = ["full"] }
async
Authentication
Monaco uses noncustodial session-key auth. The client generates a random ed25519 keypair locally and registers the public key through the challenge → wallet-sign → verify flow; the wallet signature authorizes that session public key. Subsequent authenticated requests are signed with the session private key — the server never holds a credential that can impersonate the user.
use ;
let client = new;
// 1. Generate an ed25519 session keypair locally (e.g. via ed25519-dalek) and
// hex-encode the public key.
let session_public_key = "<64-char-lowercase-hex-ed25519-pubkey>".to_string;
// 2. Request a challenge (binds the session public key into the signed message)
let challenge = client
.create_challenge
.await?
.into_inner;
// 3. Sign the challenge message with your wallet and verify
let verify = client
.verify_signature
.await?
.into_inner;
// `verify` returns { expires_at, user } — no tokens.
Authenticated requests must carry per-request signature headers
(X-Monaco-PublicKey, X-Monaco-Timestamp, X-Monaco-Signature) over
METHOD\nPATH_WITH_QUERY\nTIMESTAMP_MS\nSHA256_BODY_HEX, signed with the
session private key. A built-in request-signing layer for this generated client
is a pending follow-up; until then, inject those headers via your own reqwest
layer when calling authenticated endpoints.
API Coverage
The client exposes every operation in the canonical Monaco REST API. The
vendored spec is resynced from that canonical spec by make docs-gen (see
Gotchas), so this surface tracks the API automatically.
| Category | Methods |
|---|---|
| Market data | list_trading_pairs, get_trading_pair_by_id, get_market_metadata, get_candles, get_screener, get_open_interest |
| Perp markets | get_perp_market_config, get_perp_market_summary, get_mark_price, get_index_price, get_funding_state, list_funding_history |
| Orderbook | get_orderbook_snapshot |
| Trades | get_trades, get_trade_by_id, get_user_trades, list_user_trades |
| Orders | create_order, replace_order, cancel_order, get_orders, get_order_by_id |
| Conditional orders | create_conditional_order, cancel_conditional_order, list_conditional_orders |
| Batch orders | batch_create_orders, batch_replace_orders, batch_cancel_orders, batch_cancel_all, batch_cancel_all_by_pair |
| Accounts | get_user_profile, get_user_balances, get_user_balance_by_asset, get_user_movements, list_funding_payments, get_portfolio_stats, get_portfolio_chart |
| Sub-accounts | list_sub_accounts_with_balances, create_sub_account_limit, get_sub_account_limits, update_sub_account_limit, delete_sub_account_limit |
| Margin accounts | list_margin_accounts, get_margin_account_summary, ensure_parent_margin_account, get_margin_account_movements, get_available_collateral, transfer_collateral_to_margin_account, transfer_collateral_from_margin_account, transfer_collateral_to_auto_margin_account, simulate_order_risk, simulate_auto_margin_order_risk |
| Positions | list_positions, get_position, close_position, get_position_risk, add_position_margin, reduce_position_margin, list_position_history, attach_position_tp_sl |
| Delegated agents | upsert_delegated_agent, list_delegated_agents, list_delegated_agent_owners, revoke_delegated_agent, create_delegated_session |
| Applications | get_application_config, get_application_stats, list_application_orders, list_application_users, list_application_movements, list_application_balances |
| Auth | create_challenge, verify_signature, refresh_session, revoke_session, authenticate_backend |
| Fees | simulate_fees |
| Other | submit_whitelist, mint_tokens, health_check |
All request/response types are in monaco_sdk::types.
Gotchas
- Generated code: The entire client is generated at build time. The vendored
openapi/openapi.yamlis not hand-edited — it is regenerated from the canonical spec (docs/src/proto-openapi/api/openapi.yaml) bymake docs-gen, which runsopenapi-postprocess'ssync-rust-sdk-spectransform. CI fails if the committed copy drifts from a fresh regeneration, so a proto/endpoint change reaches this SDK automatically. - No runtime codegen: The spec is included via
include!fromOUT_DIR, so builds require the OpenAPI YAML to be present.
Build & Test
By default cargo test -p monaco-sdk runs only the static packaging_regressions
checks — the rest of the suite requires a live Monaco backend and is gated
behind #[ignore].
# Static checks only (no backend needed)
# Full live suite against an environment
API_BASE_URL=https://develop.apimonaco.xyz \
PRIVATE_KEY=0x...your_funded_test_key \
The live tests are grouped by responsibility and each file can be targeted
individually (--test auth, --test faucet, etc.):
| File | Covers |
|---|---|
public.rs |
Unauthenticated market data: list_trading_pairs, get_orderbook_snapshot, get_candles, get_trades, health_check, … |
auth.rs |
Challenge / verify / refresh round-trip, plus 401 rejection on an unauthenticated profile call |
accounts.rs |
get_user_balances, get_user_movements, simulate_fees |
faucet.rs |
mint_tokens contract (minted entries carry asset IDs, amounts, tx hashes) and rate-limit slot accounting |
sub_accounts.rs |
list_sub_accounts_with_balances + 4xx envelope on an unknown sub-account |
orders.rs |
Full order lifecycle (create / replace / cancel), batch create/cancel |
end_to_end.rs |
Two user-visible journeys: fresh wallet onboarding (challenge → verify → faucet → simulate fees) and funded wallet order lifecycle |
For published-crate smoke testing, the sibling
sdk-release-verify harness consumes
monaco-grpc-sdk from crates.io so it exercises the crate an external
cargo add user would see.