Skip to main content
Drift protocol supports two types of markets: Spot Markets for token trading and Perpetual Markets for leveraged futures trading. Each market has an associated oracle for price feeds.

Market Types

MarketId

Markets are identified using the MarketId type:
pub struct MarketId {
    index: u16,
    kind: MarketType,
}

pub enum MarketType {
    Spot,
    Perp,
}
Create market identifiers:
// Perpetual market 0 (SOL-PERP)
let sol_perp = MarketId::perp(0);

// Spot market 0 (USDC)
let usdc = MarketId::spot(0);
let usdc_alt = MarketId::QUOTE_SPOT;  // constant for USDC

// Decompose
let (index, kind) = sol_perp.to_parts();
let is_perp = sol_perp.is_perp();
let is_spot = sol_perp.is_spot();

Spot Markets

SpotMarket Structure

Spot markets represent token trading pairs:
pub struct SpotMarket {
    pub market_index: u16,
    pub oracle: Pubkey,
    pub oracle_source: OracleSource,
    pub mint: Pubkey,
    pub vault: Pubkey,
    
    // Price/quantity precision
    pub order_tick_size: u64,      // Minimum price increment
    pub order_step_size: u64,      // Minimum quantity increment
    pub min_order_size: u64,       // Minimum order size
    
    // Token program
    pub token_program_flag: u8,
    
    // Market state
    pub status: MarketStatus,
    pub decimals: u32,
    
    // ... additional fields
}

Accessing Spot Markets

// Get spot market by index
let usdc_market = client.get_spot_market_account(0).await?;

println!("Market: {}", usdc_market.market_index);
println!("Oracle: {}", usdc_market.oracle);
println!("Mint: {}", usdc_market.mint);
println!("Decimals: {}", usdc_market.decimals);

// Get with slot information
let market_with_slot = client.get_spot_market_account_and_slot(0).await?;
println!("Data from slot: {}", market_with_slot.slot);

// Try cached (requires subscription)
let market = client.try_get_spot_market_account(0)?;

Spot Market Helpers

use drift_sdk::types::MarketPrecision;

let spot_market = client.get_spot_market_account(1).await?;

// Get price tick (minimum price increment)
let price_tick = spot_market.price_tick();

// Get quantity tick (minimum quantity increment)  
let quantity_tick = spot_market.quantity_tick();

// Get minimum order size
let min_size = spot_market.min_order_size();

// Check token program
let is_token_2022 = spot_market.is_token_2022_program();
let has_transfer_hook = spot_market.has_transfer_hook();
let token_program = spot_market.token_program();

Iterating Spot Markets

// Get all active spot market IDs
let spot_markets = client.get_all_spot_market_ids();

for market_id in spot_markets {
    let market = client.get_spot_market_account(market_id.index()).await?;
    let config = client.program_data()
        .spot_market_config(market_id.index());
    
    println!("Market {}: {}", market.market_index, config.symbol());
}

Perpetual Markets

PerpMarket Structure

Perp markets represent leveraged futures contracts:
pub struct PerpMarket {
    pub market_index: u16,
    pub status: MarketStatus,
    pub contract_type: ContractType,
    pub contract_tier: ContractTier,
    
    // AMM configuration
    pub amm: AMM,
    
    // Margin requirements
    pub margin_ratio_initial: u32,
    pub margin_ratio_maintenance: u32,
    
    // Funding
    pub funding_period: i64,
    
    // Insurance
    pub insurance_claim: InsuranceClaim,
    pub unrealized_pnl_max_imbalance: u64,
    
    // ... additional fields
}

pub struct AMM {
    pub oracle: Pubkey,
    pub oracle_source: OracleSource,
    
    // Pricing
    pub base_asset_reserve: u128,
    pub quote_asset_reserve: u128,
    pub sqrt_k: u128,
    
    // Order constraints
    pub order_tick_size: u64,
    pub order_step_size: u64,
    pub min_order_size: u64,
    
    // ... additional AMM fields
}

Accessing Perp Markets

// Get perp market by index
let sol_perp = client.get_perp_market_account(0).await?;

println!("Market: {}", sol_perp.market_index);
println!("Oracle: {}", sol_perp.amm.oracle);
println!("Contract Type: {:?}", sol_perp.contract_type);

// Access AMM data
let amm = &sol_perp.amm;
println!("Base Reserve: {}", amm.base_asset_reserve);
println!("Quote Reserve: {}", amm.quote_asset_reserve);

// Get market precision
let price_tick = sol_perp.price_tick();
let quantity_tick = sol_perp.quantity_tick();
let min_size = sol_perp.min_order_size();

Iterating Perp Markets

// Get all active perp market IDs
let perp_markets = client.get_all_perp_market_ids();

for market_id in perp_markets {
    let market = client.get_perp_market_account(market_id.index()).await?;
    let config = client.program_data()
        .perp_market_config(market_id.index());
    
    println!("Market {}: {}", market.market_index, config.symbol());
}

Market Status

Markets can be in different states:
pub enum MarketStatus {
    Initialized,
    Active,
    FundingPaused,
    AmmPaused,
    FillPaused,
    WithdrawPaused,
    ReduceOnly,
    Settlement,
    Delisted,
}

// Check market status
let market = client.get_perp_market_account(0).await?;
match market.status {
    MarketStatus::Active => println!("Market is active"),
    MarketStatus::ReduceOnly => println!("Reduce-only mode"),
    MarketStatus::Settlement => println!("In settlement"),
    _ => println!("Other status: {:?}", market.status),
}
The SDK filters out Delisted and Settlement markets from get_all_*_market_ids() methods by default.

Oracle Price Feeds

Oracle Sources

Drift supports multiple oracle sources:
pub enum OracleSource {
    Pyth,
    Switchboard,
    QuoteAsset,
    Pyth1K,
    Pyth1M,
    PythStableCoin,
    PythPull,
    PythLazer,
    PythLazer1M,
    Prelaunch,
}

Accessing Oracle Prices

// Get oracle price (simple)
let price = client.oracle_price(MarketId::perp(0)).await?;
println!("SOL price: {}", price);

// Get full oracle data
let oracle = client.get_oracle_price_data_and_slot(MarketId::perp(0)).await?;
println!("Price: {}", oracle.data.price);
println!("Confidence: {}", oracle.data.confidence);
println!("Slot: {}", oracle.slot);
println!("Delay: {}", oracle.data.delay);
println!("Has sufficient sources: {}", oracle.data.has_sufficient_number_of_data_points);

// Try cached oracle (requires subscription)
let oracle = client.try_get_oracle_price_data_and_slot(MarketId::perp(0))?;

OraclePriceData

Oracle data includes price and metadata:
pub struct OraclePriceData {
    pub price: i64,
    pub confidence: u64,
    pub delay: i64,
    pub has_sufficient_number_of_data_points: bool,n}

Market Maker Oracle

For perp markets, get the AMM oracle price with validity checks:
let current_slot = client.get_slot().await.unwrap();
let mm_oracle = client.try_get_mmoracle_for_perp_market(0, current_slot)?;

println!("MM Oracle Price: {}", mm_oracle.price);

MarketMap

The MarketMap<T> manages cached market data:
pub struct MarketMap<T> {
    marketmap: Arc<DashMap<u16, DataAndSlot<T>>>,
    subscriptions: DashMap<u16, UnsubHandle>,
    latest_slot: Arc<AtomicU64>,
    // ...
}

Market Map Features

  • Type-safe: Separate maps for MarketMap<SpotMarket> and MarketMap<PerpMarket>
  • Thread-safe: Uses DashMap for concurrent access
  • Auto-sync: Automatically syncs on client initialization
  • WebSocket updates: Live updates via subscriptions

Manual Sync

Force a market map resync:
// Sync is normally done automatically on initialization
// You can manually trigger it if needed:
let rpc = client.rpc();
let markets = vec![MarketId::perp(0), MarketId::perp(1)];

// This is internal but shows the concept
// client.backend.perp_market_map.sync(&rpc).await?;

OracleMap

The OracleMap manages oracle price subscriptions:
pub struct OracleMap {
    oraclemap: Arc<DashMap<(Pubkey, u8), Oracle>>,
    oracle_by_market: ReadOnlyView<MarketId, (Pubkey, OracleSource)>,
    shared_oracles: ReadOnlyView<Pubkey, OracleShareMode>,
    // ...
}

pub struct Oracle {
    pub pubkey: Pubkey,
    pub data: OraclePriceData,
    pub source: OracleSource,
    pub slot: u64,
    pub raw: Vec<u8>,
}

Oracle Sharing

Multiple markets can share the same oracle:
// SOL-PERP and wSOL spot market might share the same oracle
let sol_perp_oracle = client.try_get_oracle_price_data_and_slot(MarketId::perp(0))?;
let sol_spot_oracle = client.try_get_oracle_price_data_and_slot(MarketId::spot(1))?;

// Same oracle pubkey, potentially different source
assert_eq!(sol_perp_oracle.pubkey, sol_spot_oracle.pubkey);
The SDK automatically deduplicates oracle subscriptions. If multiple markets share an oracle, only one WebSocket subscription is created.

Mixed Oracle Sources

Some markets use the same oracle with different sources for precision:
// BONK uses PythLazer1M for perp, PythLazer for spot
let bonk_perp = client.get_perp_market_account(4).await?;
let bonk_spot = client.get_spot_market_account(32).await?;

// Same oracle pubkey, different sources
assert_eq!(bonk_perp.amm.oracle, bonk_spot.oracle);
assert_eq!(bonk_perp.amm.oracle_source, OracleSource::PythLazer1M);
assert_eq!(bonk_spot.oracle_source, OracleSource::PythLazer);

Market Configurations

Access market metadata from program data:
let program_data = client.program_data();

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

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

// Get specific market config
let sol_perp_config = program_data.perp_market_config(0);
let symbol = sol_perp_config.symbol();  // "SOL-PERP"

Market Lookup by Symbol

Find markets by their symbol:
// Case-insensitive symbol lookup
let sol_perp = client.market_lookup("SOL-PERP")?;
let btc_perp = client.market_lookup("btc-perp")?;
let usdc = client.market_lookup("USDC")?;

if let Some(market_id) = sol_perp {
    let market = client.get_perp_market_account(market_id.index()).await?;
}
Cache market lookups in your application. Symbol lookups iterate through all market configs.

Best Practices

Subscribe for Hot Data: If you’re frequently querying market or oracle data, subscribe to it for zero-latency cached access.
Check Market Status: Always check market.status before trading. Markets can be in reduce-only, paused, or settlement modes.
Use try_get for Speed: When you know data is subscribed, use try_get_* methods which return cached data instantly without async overhead.

Build docs developers (and LLMs) love