Slippage Protection

Set minimum output amounts to protect swaps from price movements between quote and execution. Essential for safe trading in volatile markets.

What is Slippage?

Slippage occurs when:

  • Price moves between quote and execution

  • Other trades consume liquidity

  • Network delays cause stale quotes

Protection ensures you receive at least a minimum amount.

Basic Implementation

// Calculate minimum output with slippage tolerance
function calculateMinimumOutput(
  expectedOutput: bigint,
  slippagePercent: number = 0.5 // 0.5% default
): bigint {
  const slippageFactor = 10000 - Math.floor(slippagePercent * 100);
  return (expectedOutput * BigInt(slippageFactor)) / 10000n;
}

// Usage
const expectedOut = await calculateSwapOutput(pair, amountIn, xtoy);
const minimumOut = calculateMinimumOutput(expectedOut, 1.0); // 1% slippage

Protected Swap Pattern

async function swapWithProtection(
  pair: LBPair,
  amountIn: bigint,
  xtoy: boolean,
  slippagePercent: number = 0.5
) {
  // 1. Calculate expected output
  const expectedOutput = await calculateSwapOutput(pair, amountIn, xtoy);
  
  // 2. Set minimum acceptable
  const minOutput = calculateMinimumOutput(expectedOutput, slippagePercent);
  
  // 3. Build transaction with protection
  const tx = new Transaction();
  
  // Add swap
  const [_, coinXOut, coinYOut] = await sdk.Pair.prepareSwap(
    pair,
    { amount: amountIn, xtoy },
    tx
  );
  
  // Add minimum check (pseudo-code - actual implementation varies)
  const outputCoin = xtoy ? coinYOut : coinXOut;
  tx.moveCall({
    target: "0x2::coin::value",
    arguments: [outputCoin],
    // Assert minimum amount
  });
  
  return tx;
}

Dynamic Slippage

// Adjust slippage based on conditions
function getDynamicSlippage(
  pair: LBPair,
  tradeSize: bigint,
  volatility: number
): number {
  // Base slippage
  let slippage = 0.3;
  
  // Increase for large trades
  const avgTradeSize = getAverageTradeSize(pair);
  if (tradeSize > avgTradeSize * 10n) {
    slippage += 0.5;
  }
  
  // Increase for volatile pairs
  if (volatility > 0.05) { // 5% daily volatility
    slippage += 0.5;
  }
  
  // Cap at reasonable maximum
  return Math.min(slippage, 3.0);
}

Slippage by Asset Type

const SLIPPAGE_PRESETS = {
  stable: 0.1,      // USDC/USDT: 0.1%
  bluechip: 0.5,    // ETH/USDC: 0.5%
  volatile: 2.0,    // MEME/USDC: 2%
  illiquid: 5.0     // Low liquidity: 5%
};

function getRecommendedSlippage(
  tokenX: string,
  tokenY: string
): number {
  if (isStablePair(tokenX, tokenY)) return SLIPPAGE_PRESETS.stable;
  if (isBluechipPair(tokenX, tokenY)) return SLIPPAGE_PRESETS.bluechip;
  if (hasLowLiquidity(tokenX, tokenY)) return SLIPPAGE_PRESETS.illiquid;
  return SLIPPAGE_PRESETS.volatile;
}

User-Friendly Display

interface SlippageSettings {
  percent: number;
  minOutput: bigint;
  maxSlippage: bigint;
}

function calculateSlippageInfo(
  expectedOutput: bigint,
  slippagePercent: number
): SlippageSettings {
  const minOutput = calculateMinimumOutput(expectedOutput, slippagePercent);
  const maxSlippage = expectedOutput - minOutput;
  
  return {
    percent: slippagePercent,
    minOutput,
    maxSlippage
  };
}

// Display to user
const info = calculateSlippageInfo(expectedOut, 1.0);
console.log(`Minimum received: ${formatUnits(info.minOutput, decimals)}`);
console.log(`Max slippage: ${formatUnits(info.maxSlippage, decimals)}`);

MEV Protection

// Tight slippage for MEV protection
function getMEVProtectedSlippage(
  normalSlippage: number,
  isMEVProne: boolean
): number {
  if (isMEVProne) {
    // Tighter tolerance for sandwich protection
    return Math.min(normalSlippage * 0.5, 0.3);
  }
  return normalSlippage;
}

// High-value trades need extra protection
const needsMEVProtection = tradeValueUSD > 10000;
const slippage = getMEVProtectedSlippage(1.0, needsMEVProtection);

Handling Failures

async function swapWithRetry(
  pair: LBPair,
  amountIn: bigint,
  xtoy: boolean,
  maxRetries: number = 3
) {
  let slippage = 0.5;
  
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await swapWithProtection(pair, amountIn, xtoy, slippage);
    } catch (error) {
      if (error.message.includes("Slippage exceeded")) {
        // Increase tolerance and retry
        slippage = Math.min(slippage * 1.5, 5.0);
        console.log(`Retry with ${slippage}% slippage`);
      } else {
        throw error;
      }
    }
  }
  
  throw new Error("Max retries exceeded");
}

Best Practices

  1. Default Settings

    • 0.5% for normal conditions

    • 0.1% for stable pairs

    • 2-5% for volatile assets

  2. User Control

    • Allow manual adjustment

    • Show impact clearly

    • Warn on high settings

  3. Auto-adjust

    • Monitor recent volatility

    • Check liquidity depth

    • Consider trade size

Last updated