Skip to main content
The DriftClient is the main entry point for interacting with the Drift protocol. This guide covers how to initialize the client, configure network contexts, and set up RPC connections.

Prerequisites

Add drift-rs to your Cargo.toml:
[dependencies]
drift-rs = "1.0"
solana-sdk = "2.0"
tokio = { version = "1.0", features = ["full"] }

Basic Setup

Creating a Wallet

First, you’ll need a wallet for signing transactions:
use drift_rs::Wallet;

// From a keypair file or environment variable
let wallet: Wallet = drift_rs::utils::load_keypair_multi_format(
    &std::env::var("PRIVATE_KEY").expect("PRIVATE_KEY environment variable set"),
)
.unwrap()
.into();

// Or create a read-only wallet (for queries only)
use solana_sdk::pubkey;
let read_only_wallet = Wallet::read_only(
    pubkey!("11111111111111111111111111111111")
);

Initializing DriftClient

MainNet Connection

use drift_rs::{Context, DriftClient, RpcClient};

let context = Context::MainNet;
let rpc_url = "https://api.mainnet-beta.solana.com".to_string();

let drift_client = DriftClient::new(
    context,
    RpcClient::new(rpc_url),
    wallet.clone(),
)
.await
.expect("Failed to initialize DriftClient");

DevNet Connection

let context = Context::DevNet;
let rpc_url = "https://api.devnet.solana.com".to_string();

let drift_client = DriftClient::new(
    context,
    RpcClient::new(rpc_url),
    wallet.clone(),
)
.await
.expect("Failed to initialize DriftClient");

Custom WebSocket URL

If your RPC provider uses a different WebSocket URL, you can specify it explicitly:
let drift_client = DriftClient::new_with_ws_url(
    context,
    RpcClient::new("https://my-rpc.example.com".to_string()),
    wallet.clone(),
    "wss://my-ws.example.com", // Custom WebSocket URL
)
.await
.expect("Failed to initialize DriftClient");
The SDK automatically converts HTTP RPC URLs to WebSocket URLs by default. Only use new_with_ws_url if your provider uses non-standard WebSocket endpoints.

Accessing Client Resources

RPC Client

Access the underlying RPC client for custom queries:
let rpc = drift_client.rpc();
let slot = rpc.get_slot().await.expect("Failed to get slot");
println!("Current slot: {}", slot);

WebSocket Client

Access the WebSocket client for subscriptions:
let ws = drift_client.ws();
// Use ws for custom account subscriptions

Program Data

Access on-chain program metadata (market configs, etc.):
let program_data = drift_client.program_data();

// Get all spot market configurations
let spot_markets = program_data.spot_market_configs();
for market in spot_markets {
    println!("Spot market {}: {}", market.market_index, market.symbol());
}

// Get all perp market configurations
let perp_markets = program_data.perp_market_configs();
for market in perp_markets {
    println!("Perp market {}: {}", market.market_index, market.symbol());
}

Working with Sub-Accounts

Drift supports multiple sub-accounts per authority:
// Get the default sub-account (index 0)
let default_subaccount = wallet.default_sub_account();

// Get a specific sub-account by index
let subaccount_3 = wallet.sub_account(3);

// Derive sub-account address from authority
use drift_rs::Wallet;
let authority = wallet.authority();
let derived_subaccount = Wallet::derive_user_account(authority, 0);

Complete Example

Here’s a complete example that initializes the client and queries basic information:
use drift_rs::{Context, DriftClient, RpcClient, Wallet};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Load environment variables
    dotenv::dotenv().ok();
    
    // Create wallet
    let wallet: Wallet = drift_rs::utils::load_keypair_multi_format(
        &std::env::var("PRIVATE_KEY")?,
    )?
    .into();
    
    // Select network
    let context = if std::env::var("MAINNET").is_ok() {
        Context::MainNet
    } else {
        Context::DevNet
    };
    
    let rpc_url = std::env::var("RPC_URL")
        .unwrap_or_else(|_| "https://api.mainnet-beta.solana.com".to_string());
    
    // Initialize client
    let drift = DriftClient::new(context, RpcClient::new(rpc_url), wallet.clone())
        .await?;
    
    println!("Connected to Drift Protocol on {}", context.name());
    
    // Query current slot
    let slot = drift.rpc().get_slot().await?;
    println!("Current slot: {}", slot);
    
    // Get program data
    let program_data = drift.program_data();
    println!("Active perp markets: {}", 
        drift.get_all_perp_market_ids().len());
    println!("Active spot markets: {}", 
        drift.get_all_spot_market_ids().len());
    
    Ok(())
}

Context Configuration

The Context enum determines which network and program IDs to use:
  • Context::MainNet - Production Solana mainnet
  • Context::DevNet - Solana devnet for testing
The context automatically configures:
  • Program IDs
  • Lookup table addresses
  • Network-specific endpoints

Best Practices

The DriftClient is cheaply clonable. It’s recommended to clone the client rather than creating multiple instances with ::new(), as this reuses underlying resources like network connections and memory allocations.
// ✅ Good: Clone the client
let drift_clone = drift_client.clone();

// ❌ Avoid: Creating multiple instances
let drift2 = DriftClient::new(context, RpcClient::new(rpc_url), wallet)
    .await?;
Store your RPC URL and private key in environment variables or a .env file for security and flexibility.

Next Steps

Build docs developers (and LLMs) love