Skip to main content
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,
}
price
i64
Oracle price with PRICE_PRECISION (1e6) decimals
confidence
u64
Confidence interval (1 standard deviation) with PRICE_PRECISION decimals
delay
i64
Seconds since the last oracle update
has_sufficient_number_of_data_points
bool
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

Build docs developers (and LLMs) love