Skip to main content
This comprehensive tutorial walks you through building your first high-performance DEX using the DLMM Rust SDK.

Getting Started

use dlmm_rust_sdk::{
    DlmmPool, PoolConfig, SwapQuote, LiquidityOperation,
    error::DlmmError,
};
use solana_sdk::{
    pubkey::Pubkey,
    signature::{Keypair, Signer},
    transaction::Transaction,
};
use std::collections::HashMap;

#[derive(Debug)]
pub struct SimpleDex {
    pools: HashMap<String, DlmmPool>,
    config: DexConfig,
}

#[derive(Debug, Clone)]
pub struct DexConfig {
    pub default_slippage: f64,
    pub max_hops: u8,
    pub fee_tier: u16,
}

impl SimpleDex {
    pub fn new(config: DexConfig) -> Self {
        Self {
            pools: HashMap::new(),
            config,
        }
    }

    /// Initialize a new DLMM pool
    pub async fn create_pool(
        &mut self,
        token_a: Pubkey,
        token_b: Pubkey,
        bin_step: u16,
        initial_price: f64,
    ) -> Result<Pubkey, DlmmError> {
        let pool_config = PoolConfig {
            token_a,
            token_b,
            bin_step,
            base_fee_rate: self.config.fee_tier,
            filter_period: 30,
            decay_period: 600,
            reduction_factor: 5000,
            variable_fee_control: 40000,
            max_volatility_accumulator: 350000,
            min_bin_id: -443636,
            max_bin_id: 443636,
        };

        let pool = DlmmPool::create_pool(pool_config, initial_price).await?;
        let pool_key = format!("{}-{}", token_a, token_b);
        
        self.pools.insert(pool_key.clone(), pool);
        
        Ok(pool.get_address())
    }

    /// Execute a token swap
    pub async fn swap(
        &self,
        pool_address: &Pubkey,
        amount_in: u64,
        token_in: Pubkey,
        minimum_amount_out: u64,
        payer: &Keypair,
    ) -> Result<u64, DlmmError> {
        // Find the pool
        let pool = self.find_pool_by_address(pool_address)
            .ok_or(DlmmError::PoolNotFound)?;

        // Get swap quote
        let quote = pool.get_swap_quote(
            amount_in,
            token_in == pool.token_x(),
            self.config.default_slippage,
        ).await?;

        // Validate minimum output
        if quote.amount_out < minimum_amount_out {
            return Err(DlmmError::SlippageExceeded);
        }

        // Execute the swap
        let swap_result = pool.swap(
            amount_in,
            token_in == pool.token_x(),
            minimum_amount_out,
            payer,
        ).await?;

        Ok(swap_result.amount_out)
    }

    /// Add concentrated liquidity to a pool
    pub async fn add_liquidity(
        &self,
        pool_address: &Pubkey,
        amount_x: u64,
        amount_y: u64,
        active_bin_id: i32,
        width: u16,
        payer: &Keypair,
    ) -> Result<Vec<u64>, DlmmError> {
        let pool = self.find_pool_by_address(pool_address)
            .ok_or(DlmmError::PoolNotFound)?;

        // Calculate liquidity distribution
        let liquidity_params = pool.calculate_liquidity_distribution(
            amount_x,
            amount_y,
            active_bin_id,
            width,
        )?;

        // Add liquidity to the pool
        let add_result = pool.add_liquidity(
            liquidity_params,
            payer,
        ).await?;

        Ok(add_result.position_ids)
    }

    /// Get current pool state and pricing
    pub async fn get_pool_info(&self, pool_address: &Pubkey) -> Result<PoolInfo, DlmmError> {
        let pool = self.find_pool_by_address(pool_address)
            .ok_or(DlmmError::PoolNotFound)?;

        let state = pool.get_pool_state().await?;
        
        Ok(PoolInfo {
            address: *pool_address,
            token_x: pool.token_x(),
            token_y: pool.token_y(),
            active_bin_id: state.active_id,
            current_price: state.get_price(),
            total_liquidity: state.total_liquidity,
            volume_24h: state.volume_24h,
            fees_24h: state.fees_24h,
        })
    }

    fn find_pool_by_address(&self, address: &Pubkey) -> Option<&DlmmPool> {
        self.pools.values()
            .find(|pool| pool.get_address() == *address)
    }
}

#[derive(Debug)]
pub struct PoolInfo {
    pub address: Pubkey,
    pub token_x: Pubkey,
    pub token_y: Pubkey,
    pub active_bin_id: i32,
    pub current_price: f64,
    pub total_liquidity: u128,
    pub volume_24h: u64,
    pub fees_24h: u64,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize the DEX
    let config = DexConfig {
        default_slippage: 0.005, // 0.5%
        max_hops: 3,
        fee_tier: 100, // 0.01%
    };
    
    let mut dex = SimpleDex::new(config);
    
    // Example token addresses (replace with actual)
    let usdc = Pubkey::new_unique();
    let sol = Pubkey::new_unique();
    
    // Create a new pool
    let pool_address = dex.create_pool(
        usdc,
        sol,
        100, // 1% bin step
        50.0, // Initial price
    ).await?;
    
    println!("Created pool: {}", pool_address);
    
    // Get pool information
    let pool_info = dex.get_pool_info(&pool_address).await?;
    println!("Pool info: {:?}", pool_info);
    
    Ok(())
}

Key Features

Pool Management

  • Dynamic Liquidity: Concentrated liquidity with customizable ranges
  • Fee Optimization: Variable fees based on market volatility
  • Multi-Asset Support: Support for any SPL token pair

Advanced Features

  • Zero-Copy Parsing: Ultra-fast account data processing
  • Optimized Math: SIMD-accelerated price calculations
  • Batch Operations: Process multiple swaps efficiently

Error Handling

use dlmm_rust_sdk::error::DlmmError;

match dex.swap(pool_address, amount, token_in, min_out, payer).await {
    Ok(amount_out) => println!("Swap successful: {} tokens received", amount_out),
    Err(DlmmError::SlippageExceeded) => {
        println!("Swap failed: Price moved too much");
    },
    Err(DlmmError::InsufficientLiquidity) => {
        println!("Swap failed: Not enough liquidity");
    },
    Err(e) => println!("Swap failed: {:?}", e),
}

Performance Considerations

  1. Memory Efficiency: Uses zero-copy deserialization
  2. CPU Optimization: SIMD instructions for math operations
  3. Network Efficiency: Batched RPC calls
  4. Concurrency: Lock-free data structures for multi-threading