Skip to main content

Rust SDK

The legend-client crate is a typed HTTP client for the Legend Prime API. It’s the same SDK that powers the legend-cli binary.

Installation

# Cargo.toml
[dependencies]
legend-client = "0.1"
tokio = { version = "1", features = ["full"] }

Client Setup

use legend_client::{LegendPrime, Config};

let client = LegendPrime::new(Config {
    query_key: std::env::var("LEGEND_QUERY_KEY").unwrap(),
    base_url: None, // defaults to https://prime-api.legend.xyz
});

Accounts

use legend_client::CreateAccountParams;

// List accounts
let accounts = client.accounts.list().await?;

// Get a specific account
let account = client.accounts.get("acc_xxx").await?;

// Create an EOA account
let account = client.accounts.create(&CreateAccountParams {
    signer_type: "eoa".into(),
    ethereum_signer_address: Some("0x742d...".into()),
    ..Default::default()
}).await?;

// Create a Turnkey P256 account
let account = client.accounts.create(&CreateAccountParams {
    signer_type: "turnkey_p256".into(),
    p256_public_key: Some("0x02abc...".into()),
    ..Default::default()
}).await?;

Plans

use legend_client::{EarnParams, SwapParams, ExecuteParams};

// Create an earn plan
let plan = client.plan.earn("acc_xxx", &EarnParams {
    amount: "1000000".into(),
    asset: "USDC".into(),
    network: "base".into(),
    protocol: "compound".into(),
    market: None,
}).await?;

// Extract the digest for signing
let digest = plan.digest().expect("Plan missing digest");

// Create a swap plan
let plan = client.plan.swap("acc_xxx", &SwapParams {
    sell_asset: "USDC".into(),
    buy_asset: "WETH".into(),
    sell_amount: Some("1000000".into()),
    buy_amount: None,
    network: "base".into(),
}).await?;

// Execute with a signature
let result = client.plan.execute("acc_xxx", &ExecuteParams {
    plan_id: plan.plan_id.clone(),
    signature: "0xdef456...".into(),
}).await?;
All 14 plan types are supported: earn, withdraw, swap, transfer, borrow, repay, claim_rewards, loop_long, unloop_long, add_backing, withdraw_backing, migrate, swap_and_supply, reinvest_rewards.

Portfolio and Activities

use legend_client::FolioOpts;

let folio = client.accounts.folio("acc_xxx", &FolioOpts::default()).await?;
let activities = client.accounts.activities("acc_xxx").await?;
let activity = client.accounts.activity("acc_xxx", 42).await?;

Reference Data

let networks = client.networks().await?;
let assets = client.assets().await?;
let prime_account = client.prime_account().await?;

Error Handling

use legend_client::LegendPrimeError;

match client.accounts.get("acc_nonexistent").await {
    Ok(account) => println!("Found: {}", account.account_id),
    Err(LegendPrimeError::Api { code, message, status }) => {
        eprintln!("API error ({status}): [{code}] {message}");
    }
    Err(e) => eprintln!("Other error: {e}"),
}

Signing with legend-signer

The companion legend-signer crate handles P256 key management and Turnkey signing:
use legend_signer::{FileSigner, TurnkeyClient, TurnkeyConfig, Signer};

// Generate a P256 key
let signer = FileSigner::generate(Path::new("key.pem"))?;
println!("Public key: {}", signer.public_key_hex());

// Sign a digest via Turnkey
let turnkey = TurnkeyClient::new(TurnkeyConfig {
    signer: Box::new(signer),
    sub_org_id: "sub_org_xxx".into(),
    ethereum_signer_address: "0x742d...".into(),
    api_base_url: None,
});

let signature = turnkey.sign_digest("0xabc123...").await?;
On macOS, use SecureEnclaveSigner for hardware-protected keys:
#[cfg(target_os = "macos")]
use legend_signer::SecureEnclaveSigner;

let signer = SecureEnclaveSigner::generate("com.legend.prime.default")?;