Oracle price data represents the current price and confidence interval from oracle sources like Pyth and Switchboard.
OraclePriceData
The main structure for oracle price information:
pub struct OraclePriceData {
pub price: i64,
pub confidence: u64,
pub delay: i64,
pub has_sufficient_number_of_data_points: bool,
}
Oracle price with PRICE_PRECISION (1e6) decimals
Confidence interval (1 standard deviation) with PRICE_PRECISION decimals
Seconds since the last oracle update
has_sufficient_number_of_data_points
Whether the oracle has enough data points to be considered valid
Price Precision
All prices use PRICE_PRECISION = 1_000_000 (1e6):
const PRICE_PRECISION: i64 = 1_000_000;
// Example: SOL at $150.50
let price_raw = oracle.data.price; // 150_500_000
let price_usd = price_raw as f64 / PRICE_PRECISION as f64; // 150.50
Getting Oracle Data
From DriftClient
oracle_price()
Get just the price (most common use case):
let sol_price = client.oracle_price(MarketId::perp(0)).await?;
println!("SOL: ${:.2}", sol_price as f64 / 1e6);
try_get_oracle_price_data_and_slot()
Get full oracle data from cache (subscription required):
if let Some(oracle) = client.try_get_oracle_price_data_and_slot(MarketId::perp(0)) {
println!("Price: {}", oracle.data.price);
println!("Confidence: {}", oracle.data.confidence);
println!("Delay: {} seconds", oracle.data.delay);
println!("Slot: {}", oracle.slot);
}
get_oracle_price_data_and_slot()
Get oracle data with RPC fallback:
let oracle = client.get_oracle_price_data_and_slot(MarketId::perp(0)).await?;
From FFI
The SDK uses FFI to parse oracle account data:
pub fn get_oracle_price(
oracle_source: &OracleSource,
account_data: &[u8],
slot: u64,
) -> Result<OraclePriceData, Box<dyn std::error::Error>>
This is used internally - you typically don’t need to call it directly.
Oracle Sources
Different oracle types provide data in different formats:
pub enum OracleSource {
Pyth, // Standard Pyth oracle
Pyth1K, // Pyth with 1K precision multiplier
Pyth1M, // Pyth with 1M precision multiplier
PythStableCoin, // Pyth stable coin oracle
PythPull, // Pyth pull-based oracle
Switchboard, // Switchboard oracle
QuoteAsset, // Uses quote asset (USDC) as price
PythLazer, // Pyth Lazer low-latency
Prelaunch, // Pre-launch market
}
Pyth Variants
- Pyth: Standard precision, most common
- Pyth1K: Price multiplied by 1,000 for low-value assets
- Pyth1M: Price multiplied by 1,000,000 for very low-value assets
- PythStableCoin: Optimized for stablecoins
Price Validation
Confidence Interval
The confidence represents uncertainty in the price:
let oracle = client.get_oracle_price_data_and_slot(market).await?;
let price = oracle.data.price as f64 / 1e6;
let confidence = oracle.data.confidence as f64 / 1e6;
println!("Price: ${:.2} ± ${:.4}", price, confidence);
// Check if confidence is acceptable
let confidence_pct = (confidence / price) * 100.0;
if confidence_pct > 1.0 {
println!("Warning: High uncertainty ({:.2}%)", confidence_pct);
}
Staleness Check
Check if the oracle data is recent:
let max_age_seconds = 60;
if oracle.data.delay > max_age_seconds {
println!("Warning: Oracle data is {} seconds old", oracle.data.delay);
}
Sufficient Data Points
if !oracle.data.has_sufficient_number_of_data_points {
println!("Warning: Insufficient oracle data points");
}
MMOracle (Market Maker Oracle)
For perpetual markets, you can get oracle data with AMM fallback:
let current_slot = client.get_slot().await.unwrap();
let oracle_data = client.try_get_mmoracle_for_perp_market(
0, // market_index
current_slot,
)?;
println!("Price (with AMM fallback): {}", oracle_data.price);
The MMOracle uses the AMM price if:
- The oracle is stale
- The oracle confidence is too wide
- The oracle doesn’t have sufficient data points
Complete Example
use drift_rs::{DriftClient, Context, MarketId};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = DriftClient::new(
Context::MainNet,
rpc_client,
wallet,
).await?;
// Subscribe to oracle
let market = MarketId::perp(0);
client.subscribe_oracles(&[market]).await?;
loop {
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
// Get oracle data
if let Some(oracle) = client.try_get_oracle_price_data_and_slot(market) {
let price = oracle.data.price as f64 / 1e6;
let confidence = oracle.data.confidence as f64 / 1e6;
let confidence_pct = (confidence / price) * 100.0;
println!("Price: ${:.2}", price);
println!("Confidence: ±${:.4} ({:.2}%)", confidence, confidence_pct);
println!("Age: {} seconds", oracle.data.delay);
println!("Slot: {}", oracle.slot);
println!("Sufficient data: {}",
oracle.data.has_sufficient_number_of_data_points
);
// Validate oracle quality
if oracle.data.delay > 30 {
println!("⚠️ Warning: Stale oracle data");
}
if confidence_pct > 0.5 {
println!("⚠️ Warning: High price uncertainty");
}
if !oracle.data.has_sufficient_number_of_data_points {
println!("⚠️ Warning: Insufficient data points");
}
println!("---");
}
}
}
Precision Constants
Important constants for working with oracle prices:
// Price precision (all prices use 6 decimals)
const PRICE_PRECISION: i64 = 1_000_000;
const PRICE_PRECISION_U64: u64 = 1_000_000;
const PRICE_PRECISION_I64: i64 = 1_000_000;
// For converting between different precisions
const PRICE_PRECISION_EXP: u32 = 6;
// Base asset precision (for amounts)
const BASE_PRECISION: u64 = 1_000_000_000;
const QUOTE_PRECISION: u64 = 1_000_000;
See Also