Skip to main content
You need to execute a large swap but are concerned about price impact eating into your profits. Traditional AMMs cause significant slippage on large orders, but DLMM’s concentrated liquidity lets you trade across multiple price bins with minimal impact.

What You’ll Achieve

Execute swaps of any size while:
  • Keeping price impact under 1%
  • Getting better rates than traditional AMMs
  • Maintaining transaction reliability
  • Optimizing gas usage

When to Use This Guide

  • You’re executing swaps larger than $10,000
  • Current slippage is eating 2%+ of your profits
  • You need atomic execution across multiple trades
  • Your users complain about poor swap rates
  • You want the best available prices on Solana

How DLMM Solves Large Swap Problems

Traditional AMMs force you to trade against a single liquidity pool, causing exponential price impact. DLMM automatically routes your swap across multiple price bins, each containing concentrated liquidity at specific price ranges. Example: A 10 SOL → USDC swap:
  • Traditional AMM: 3.2% price impact, poor execution
  • DLMM: 0.8% price impact, distributed across 15 bins

Your Swap Execution Process

  1. Get optimal quote - DLMM calculates best route across bins
  2. Apply slippage protection - Set maximum acceptable price movement
  3. Execute atomically - All bin swaps happen in one transaction
  4. Collect optimal output - Better rates than any single pool

Execute Your First Large Swap

For a 100 USDC → SOL swap with minimal slippage:
import { LiquidityBookServices, MODE, GetTokenOutputResponse } from '@saros-finance/dlmm-sdk';
import { Connection, PublicKey, Keypair, Transaction } from '@solana/web3.js';

export class OptimalSwapExecutor {
  private dlmmService: LiquidityBookServices;
  private poolAddress: PublicKey;

  constructor(poolAddress: PublicKey, rpcUrl?: string) {
    this.poolAddress = poolAddress;
    this.dlmmService = new LiquidityBookServices({
      mode: MODE.MAINNET, // or MODE.DEVNET
      options: {
        rpcUrl: rpcUrl || "https://api.mainnet-beta.solana.com"
      }
    });
  }

  /**
   * Step 1: Get the best available quote
   */
  async getSwapQuote({
    amount,
    swapForY = true,
    slippage = 0.5
  }: {
    amount: number;
    swapForY?: boolean;
    slippage?: number;
  }) {

    try {
      // First get pool metadata
      const metadata = await this.dlmmService.fetchPoolMetadata(this.poolAddress.toString());
      
      // Get quote using correct SDK method
      const quoteResult: GetTokenOutputResponse = await this.dlmmService.quote({
        amount: amount, // Amount in smallest units (e.g., 1_000_000 for 1 USDC)
        metadata,
        optional: {
          isExactInput: true,
          swapForY,
          slippage
        }
      });

      return {
        amountIn: amount,
        amountOut: quoteResult.amountOut,
        priceImpact: quoteResult.priceImpact,
        fee: quoteResult.fee,
        minimumAmountOut: quoteResult.minAmountOut
      };

    } catch (error) {
      throw new Error(`Unable to get quote: ${error}`);
    }
  }

  /**
   * Step 2: Execute your swap with protection
   */
  async executeSwap({
    user,
    fromToken,
    toToken,
    amountIn,
    minAmountOut,
    swapYtoX = false,
    slippage = 0.005 // 0.5% slippage tolerance
  }: {
    user: Keypair;
    fromToken: PublicKey;
    toToken: PublicKey;
    amountIn: number;
    minAmountOut: number;
    swapYtoX?: boolean;
    slippage?: number;
  }) {
    try {
      // Get fresh quote before execution
      const quote = await this.getSwapQuote({
        fromToken,
        toToken,
        amount: amountIn,
        swapYtoX
      });

      // Apply slippage protection - use the stricter limit
      const slippageAdjustedMinOut = Math.max(
        minAmountOut,
        quote.amountOut * (1 - slippage)
      );

      // Execute the swap across multiple bins atomically
      const swapAmount = new BN(amountIn * Math.pow(10, swapYtoX ? 9 : 6));
      const minOutAmount = new BN(slippageAdjustedMinOut * Math.pow(10, swapYtoX ? 6 : 9));

      const swapInstruction = await this.dlmmPool.swap({
        user: user.publicKey,
        amountIn: swapAmount,
        minAmountOut: minOutAmount,
        swapYtoX
      });

      const transaction = new Transaction().add(swapInstruction);
      const signature = await this.connection.sendTransaction(transaction, [user]);
      
      const confirmation = await this.connection.confirmTransaction(signature, 'confirmed');
      
      if (confirmation.value.err) {
        throw new Error(`Swap failed: ${confirmation.value.err}`);
      }

      const swapResult = await this.parseSwapResult(signature);
      
      return {
        signature,
        amountIn,
        amountOut: swapResult.amountOut,
        priceImpact: quote.priceImpact,
        executionPrice: swapResult.amountOut / amountIn
      };

    } catch (error) {
      throw new Error(`Swap execution failed: ${error}`);
    }
  }

  /**
   * Alternative: Buy exact amount (when you need specific output)
   */
  async buyExactAmount({
    user,
    fromToken,
    toToken,
    exactAmountOut,
    maxAmountIn,
    swapYtoX = false
  }: {
    user: Keypair;
    fromToken: PublicKey;
    toToken: PublicKey;
    exactAmountOut: number;
    maxAmountIn: number;
    swapYtoX?: boolean;
  }) {
    const exactOutAmount = new BN(exactAmountOut * Math.pow(10, swapYtoX ? 6 : 9));
    
    const reverseQuote = await this.dlmmPool.getQuoteExactOut({
      amountOut: exactOutAmount,
      swapYtoX
    });

    const requiredInput = reverseQuote.amountIn.toNumber() / Math.pow(10, swapYtoX ? 9 : 6);
    
    if (requiredInput > maxAmountIn) {
      throw new Error(`Need ${requiredInput} but max is ${maxAmountIn}`);
    }

    const swapInstruction = await this.dlmmPool.swapExactOut({
      user: user.publicKey,
      amountOut: exactOutAmount,
      maxAmountIn: new BN(maxAmountIn * Math.pow(10, swapYtoX ? 9 : 6)),
      swapYtoX
    });

    const transaction = new Transaction().add(swapInstruction);
    const signature = await this.connection.sendTransaction(transaction, [user]);
    
    await this.connection.confirmTransaction(signature, 'confirmed');
    
    return {
      signature,
      amountIn: requiredInput,
      amountOut: exactAmountOut
    };
  }

  /**
   * Advanced: Route through multiple pools for better rates
   */
  async routeThroughMultiplePools({
    user,
    route,
    amountIn,
    minAmountOut
  }: {
    user: Keypair;
    route: { pool: PublicKey; swapYtoX: boolean }[];
    amountIn: number;
    minAmountOut: number;
  }) {

    let currentAmount = amountIn;
    const swapInstructions = [];
    
    // Build instructions for each pool in route
    for (let i = 0; i < route.length; i++) {
      const hop = route[i];
      const hopPool = new DLMM(this.connection, hop.pool);
      
      const hopQuote = await hopPool.getQuote({
        amountIn: new BN(currentAmount * Math.pow(10, hop.swapYtoX ? 9 : 6)),
        swapYtoX: hop.swapYtoX
      });
      
      const minOut = i === route.length - 1 ? 
        new BN(minAmountOut * Math.pow(10, hop.swapYtoX ? 6 : 9)) :
        new BN(0);
      
      const swapInstruction = await hopPool.swap({
        user: user.publicKey,
        amountIn: new BN(currentAmount * Math.pow(10, hop.swapYtoX ? 9 : 6)),
        minAmountOut: minOut,
        swapYtoX: hop.swapYtoX
      });
      
      swapInstructions.push(swapInstruction);
      currentAmount = hopQuote.amountOut.toNumber() / Math.pow(10, hop.swapYtoX ? 6 : 9);
    }
    
    // Execute all hops atomically
    const transaction = new Transaction().add(...swapInstructions);
    const signature = await this.connection.sendTransaction(transaction, [user]);
    
    await this.connection.confirmTransaction(signature, 'confirmed');
    
    return {
      signature,
      amountIn,
      amountOut: currentAmount,
      hops: route.length
    };
  }

  /**
   * Execute multiple swaps in one transaction
   */
  async executeBatchSwaps({
    user,
    swaps
  }: {
    user: Keypair;
    swaps: {
      pool: PublicKey;
      amountIn: number;
      minAmountOut: number;
      swapYtoX: boolean;
    }[];
  }) {
    const swapInstructions = [];
    
    for (const swap of swaps) {
      const pool = new DLMM(this.connection, swap.pool);
      
      const instruction = await pool.swap({
        user: user.publicKey,
        amountIn: new BN(swap.amountIn * Math.pow(10, swap.swapYtoX ? 9 : 6)),
        minAmountOut: new BN(swap.minAmountOut * Math.pow(10, swap.swapYtoX ? 6 : 9)),
        swapYtoX: swap.swapYtoX
      });
      
      swapInstructions.push(instruction);
    }
    
    const transaction = new Transaction().add(...swapInstructions);
    const signature = await this.connection.sendTransaction(transaction, [user]);
    
    await this.connection.confirmTransaction(signature, 'confirmed');
    
    return { signature, swapsExecuted: swaps.length };
  }

  // Helper methods
  private calculatePriceImpact(amountIn: BN, amountOut: BN, swapYtoX: boolean): number {
    // Simplified calculation - in production use DLMM math
    const inputValue = amountIn.toNumber();
    const outputValue = amountOut.toNumber();
    return Math.abs((outputValue - inputValue) / inputValue) * 100;
  }

  private async parseSwapResult(signature: string) {
    // Parse actual transaction results - simplified for example
    return { amountOut: 0.95 };
  }
}

  // Helper methods
  private calculatePriceImpact(amountIn: BN, amountOut: BN, swapYtoX: boolean): number {
    // Simplified calculation - in production use DLMM math
    const inputValue = amountIn.toNumber();
    const outputValue = amountOut.toNumber();
    return Math.abs((outputValue - inputValue) / inputValue) * 100;
  }

  private async parseSwapResult(signature: string) {
    // Parse actual transaction results - simplified for example
    return { amountOut: 0.95 };
  }
}

## Execute Your Swap

```typescript
// Set up your swap
const connection = new Connection('https://api.devnet.solana.com');
const poolAddress = new PublicKey('YourPoolAddress');
const user = Keypair.generate(); // Your wallet keypair

const swapExecutor = new OptimalSwapExecutor(connection, poolAddress);

// 1. Get quote for 100 USDC → SOL
const quote = await swapExecutor.getSwapQuote({
  fromToken: new PublicKey('USDC_MINT'),
  toToken: new PublicKey('SOL_MINT'), 
  amount: 100,
  swapYtoX: false
});

console.log(`Quote: ${quote.amountIn} USDC${quote.amountOut.toFixed(4)} SOL`);
console.log(`Price impact: ${quote.priceImpact.toFixed(2)}%`);
console.log(`Bins crossed: ${quote.binsCrossed}`);

// 2. Execute with 1% slippage protection
const result = await swapExecutor.executeSwap({
  user,
  fromToken: new PublicKey('USDC_MINT'),
  toToken: new PublicKey('SOL_MINT'),
  amountIn: 100,
  minAmountOut: quote.amountOut * 0.99, // 1% slippage tolerance
  swapYtoX: false
});

console.log(`Swap complete: ${result.signature}`);
console.log(`Got ${result.amountOut} SOL (${result.priceImpact.toFixed(2)}% impact)`);

## What You Can Do

**Standard Swaps**: Sell exact amount, get minimum output  
**Exact Output**: Buy exact amount, pay maximum input  
**Multi-Pool Routes**: Automatically find best path across pools  
**Batch Operations**: Execute multiple swaps in one transaction

### Why DLMM Beats Traditional AMMs

- **Concentrated liquidity**: More tokens at your target price
- **Multi-bin routing**: Spreads large swaps across price ranges
- **Dynamic fees**: Lower costs during stable periods
- **Better capital efficiency**: Higher yields for liquidity providers = more liquidity for you

## Handle Common Issues

When your swap fails:

```typescript
try {
  const result = await swapExecutor.executeSwap(params);
} catch (error) {
  if (error.message.includes('Slippage exceeded')) {
    // Increase slippage tolerance
    params.slippage = 0.02; // 2%
    return swapExecutor.executeSwap(params);
  } 
  
  if (error.message.includes('Insufficient liquidity')) {
    // Split large order or try different pool
    return splitLargeOrder(params);
  }
  
  throw error; // Other errors need investigation
}

Optimize Your Swaps

For Better Performance:
  • Cache RPC connections between swaps
  • Batch multiple swaps in one transaction
  • Get fresh quotes right before execution
  • Use WebSocket for real-time price updates
For Better Rates:
  • Check multiple pools for the same pair
  • Consider multi-hop routes for exotic pairs
  • Time swaps during low volatility periods
  • Monitor price impact - split if over 3%