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