Skip to main content

Crate lightcone

Crate lightcone 

Source
Expand description

§Lightcone SDK

Rust SDK for the Lightcone impact market protocol on Solana.

§Table of Contents

§Installation

Add to your Cargo.toml:

[dependencies]
lightcone = { version = "0.4.1", features = ["native"] }

For browser/WASM targets:

[dependencies]
lightcone = { version = "0.4.1", features = ["wasm"] }

§Feature Flags

FeatureWhat it enablesUse case
nativehttp + native-auth + ws-native + solana-rpcMarket makers, bots, CLI tools
wasmhttp + ws-wasmBrowser applications

§Quick Start

use lightcone::prelude::*;
use lightcone::auth::native::sign_login_message;
use solana_keypair::Keypair;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = LightconeClient::builder()
        .rpc_url("https://api.devnet.solana.com")
        .deposit_source(DepositSource::Market)
        .build()?;
    let keypair = Keypair::new();

    // 1. Authenticate
    let nonce = client.auth().get_nonce().await?;
    let signed = sign_login_message(&keypair, &nonce);
    let user = client.auth().login_with_message(
        &signed.message,
        &signed.signature_bs58,
        &signed.pubkey_bytes,
        None,
    ).await?;

    // 2. Find a market
    let market = client.markets().get(None, Some(1)).await?.markets.into_iter().next().unwrap();
    let orderbook = &market.orderbook_pairs[0];

    // 3. Deposit collateral to the global pool
    let deposit_mint = market.deposit_assets[0].pubkey().to_pubkey()?;
    let deposit_ix = client.positions().deposit().await
        .user(keypair.pubkey())
        .mint(deposit_mint)
        .amount(1_000_000)
        .build_ix()
        .await?;

    // 4. Build, sign, and submit a limit order
    let request = client.orders().limit_order().await
        .maker(keypair.pubkey())
        .bid()
        .price("0.55")
        .size("100")
        .sign(&keypair, &orderbook)?;

    let response = client.orders().submit(&request).await?;
    println!("Order submitted: {:?}", response);

    // 5. Withdraw from the global pool
    let withdraw_ix = client.positions().withdraw().await
        .user(keypair.pubkey())
        .mint(deposit_mint)
        .amount(1_000_000)
        .build_ix()
        .await?;

    // 6. Stream real-time updates
    let mut ws = client.ws_native();
    ws.connect().await?;
    ws.subscribe(SubscribeParams::Books {
        orderbook_ids: vec![orderbook.orderbook_id.clone()],
    })?;

    Ok(())
}

§Start Trading

use lightcone::prelude::*;
use solana_keypair::read_keypair_file;
use solana_signer::Signer;

let client = LightconeClient::builder()
    .rpc_url("https://api.devnet.solana.com")
    .deposit_source(DepositSource::Market)
    .build()?;
let keypair = read_keypair_file("~/.config/solana/id.json")?;

§Step 1: Find a Market

let market = client.markets().get(None, Some(1)).await?.markets.into_iter().next().unwrap();
let orderbook = market
    .orderbook_pairs
    .iter()
    .find(|pair| pair.active)
    .or_else(|| market.orderbook_pairs.first())
    .expect("market has no orderbooks");

§Step 2: Deposit Collateral

let deposit_mint = market.deposit_assets[0].pubkey().to_pubkey()?;
let deposit_ix = client.positions().deposit().await
    .user(keypair.pubkey())
    .mint(deposit_mint)
    .amount(1_000_000)
    .build_ix()
    .await?;

§Step 3: Place an Order

let request = client.orders().limit_order().await
    .maker(keypair.pubkey())
    .bid()
    .price("0.55")
    .size("1")
    .sign(&keypair, &orderbook)?;
let order = client.orders().submit(&request).await?;

§Step 4: Monitor

let open = client
    .orders()
    .get_user_orders(&keypair.pubkey().to_string(), Some(50), None)
    .await?;
let mut ws = client.ws_native();
ws.connect().await?;
ws.subscribe(SubscribeParams::Books {
    orderbook_ids: vec![orderbook.orderbook_id.clone()],
})?;
ws.subscribe(SubscribeParams::User {
    wallet_address: keypair.pubkey().into(),
})?;

§Step 5: Cancel an Order

let cancel = CancelBody::signed(order.order_hash.clone(), keypair.pubkey().into(), &keypair);
client.orders().cancel(&cancel).await?;

§Step 6: Exit a Position

// sign_and_submit builds the tx, signs it using the client's signing strategy, and submits
let tx_hash = client.positions().merge()
    .user(keypair.pubkey())
    .market(&market)
    .mint(deposit_mint)
    .amount(1_000_000)
    .sign_and_submit()
    .await?;

§Step 7: Withdraw

let withdraw_ix = client.positions().withdraw().await
    .user(keypair.pubkey())
    .mint(deposit_mint)
    .amount(1_000_000)
    .build_ix()
    .await?;

§Authentication

Authentication is only required for user-specific endpoints. Authentication is session-based using ED25519 signed messages. The flow is: request a nonce, sign it with your wallet, and exchange it for a session token.

§Examples

All examples are runnable with cargo run --example <name> --features native. Set environment variables in a .env file - see .env.example for the template.

§Setup & Authentication

ExampleDescription
loginFull auth lifecycle: sign message, login, check session, logout

§Market Discovery & Data

ExampleDescription
marketsFeatured markets, paginated listing, fetch by pubkey, search
orderbookFetch orderbook depth (bids/asks) and decimal precision metadata
tradesRecent trade history with cursor-based pagination
price_historyHistorical candlestick data (OHLCV) at various resolutions
positionsUser positions across all markets and per-market

§Placing Orders

ExampleDescription
submit_orderLimit order via client.orders().limit_order() with human-readable price/size, auto-scaling, and fill tracking

§Cancelling Orders

ExampleDescription
cancel_orderCancel a single order by hash and cancel all orders in an orderbook
user_ordersFetch open orders for an authenticated user

§On-Chain Operations

ExampleDescription
read_onchainRead exchange state, market state, user nonce, and PDA derivations via RPC
onchain_transactionsBuild, sign, and submit mint/merge complete set and increment nonce on-chain
global_deposit_withdrawalInit position tokens, deposit to global pool, move capital into a market, extend an existing ALT, and withdraw from global

§WebSocket Streaming

ExampleDescription
ws_book_and_tradesLive orderbook depth with OrderbookSnapshot state + rolling TradeHistory buffer
ws_ticker_and_pricesBest bid/ask ticker + price history candles with PriceHistoryState
ws_user_and_marketAuthenticated user stream (orders, balances) + market lifecycle events

§Error Handling

All SDK operations return Result<T, SdkError>:

VariantWhen
SdkError::Http(HttpError)REST request failures
SdkError::Ws(WsError)WebSocket connection/protocol errors
SdkError::Auth(AuthError)Authentication failures
SdkError::Validation(String)Domain type conversion failures
SdkError::Serde(serde_json::Error)Serialization errors
SdkError::MissingMarketContext(string)Market context not provided for operation requiring DepositSource::Market
SdkError::Signing(String)Signing operation failures
SdkError::UserCancelledUser cancelled wallet signing prompt
SdkError::Program(program::SdkError)On-chain program errors (RPC, account parsing)
SdkError::Other(String)Catch-all

HttpError variants:

VariantMeaning
Reqwest(reqwest::Error)Network/transport failure
ServerError { status, body }Non-2xx response from the backend
RateLimited { retry_after_ms }429 - back off and retry
Unauthorized401 - session expired or missing
NotFound(String)404 - resource not found
BadRequest(String)400 - invalid request
TimeoutRequest timed out
MaxRetriesExceeded { attempts, last_error }All retry attempts exhausted

§Retry Strategy

  • GET requests: RetryPolicy::Idempotent - retries on transport failures and 502/503/504, backs off on 429 with exponential backoff + jitter.
  • POST requests (order submit, cancel, auth): RetryPolicy::None - no automatic retry. Non-idempotent actions are never retried to prevent duplicate side effects.
  • Customizable per-call with RetryPolicy::Custom(RetryConfig { .. }).

Modules§

auth
Authentication: message generation, credentials, login/logout.
client
LightconeClient — the primary entry point. High-level client — LightconeClient with nested sub-client accessors.
domain
Domain modules (vertical slices): types, wire types, conversions, state. Domain modules organized as vertical slices.
error
Unified SDK error types. Unified SDK error types.
http
HTTP client with retry policies. HTTP client layer — LightconeHttp with per-endpoint retry policies.
network
Network URL constants. Network URL constants for the Lightcone SDK.
prelude
privy
Privy embedded wallet RPC operations. Privy sub-client — embedded wallet RPC operations.
program
On-chain program interaction: instructions, orders, PDAs, accounts.
rpc
RPC sub-client: PDA helpers, account fetchers, blockhash access. RPC sub-client — exchange-level on-chain fetchers, global deposit helpers, and blockhash access.
shared
Shared newtypes used across all domains. Shared newtypes and utilities used across all domain modules.
ws
WebSocket client: messages, subscriptions, events.