monaco-sdk 0.8.1

Typed Rust client for the Monaco REST API — generated from the OpenAPI specification
Documentation

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

[dependencies]
monaco-sdk = "0.5"
tokio = { version = "1", features = ["full"] }
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = monaco_sdk::Client::new("https://develop.apimonaco.xyz");
    let pairs = client.list_trading_pairs(None, Some(true), None, None, None, None).await?.into_inner();
    println!("{:?}", pairs.data);
    Ok(())
}

Authentication

Authenticated endpoints require a Bearer JWT from the challenge/verify flow:

use monaco_sdk::types::{ChallengeRequest, VerifyRequest};

let client = monaco_sdk::Client::new("https://develop.apimonaco.xyz");

// 1. Request a challenge
let challenge = client
    .create_challenge(&ChallengeRequest {
        address: "0xYourAddress".parse().unwrap(),
        chain_id: None,
        client_id: None,
    })
    .await?
    .into_inner();

// 2. Sign the challenge message and verify
let verify = client
    .verify_signature(&VerifyRequest {
        address: "0xYourAddress".parse().unwrap(),
        chain_id: None,
        client_id: None,
        nonce: challenge.nonce.unwrap().parse().unwrap(),
        signature: "<signed-message>".parse().unwrap(),
    })
    .await?
    .into_inner();

// 3. Use the JWT for authenticated requests
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION};

let mut headers = HeaderMap::new();
let token = format!("Bearer {}", verify.access_token.unwrap());
headers.insert(AUTHORIZATION, HeaderValue::from_str(&token).unwrap());
let http = reqwest::ClientBuilder::new().default_headers(headers).build().unwrap();
let authed = monaco_sdk::Client::new_with_client("https://develop.apimonaco.xyz", http);

API Coverage

Category Methods
Market data list_trading_pairs, get_trading_pair_by_id, get_market_metadata, get_candles
Orderbook get_orderbook_snapshot
Trades get_trades
Orders create_order, replace_order, cancel_order, get_orders, get_order_by_id
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
Sub-accounts list_sub_accounts_with_balances, create_sub_account_limit, get_sub_account_limits, update_sub_account_limit, delete_sub_account_limit
Auth create_challenge, verify_signature, refresh_token, 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. To update, refresh the vendored openapi.yaml from the repo-level docs artifact before publishing.
  • No runtime codegen: The spec is included via include! from OUT_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)
cargo test -p monaco-sdk

# Full live suite against an environment
API_BASE_URL=https://develop.apimonaco.xyz \
PRIVATE_KEY=0x...your_funded_test_key \
cargo test -p monaco-sdk -- --include-ignored --test-threads=1

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.