Overview

dKit’s routing engine intelligently finds the most efficient path for your swaps, whether direct or through multiple hops. The system considers factors like liquidity, fees, slippage, and execution time to optimize your trades.

Route Types

Direct Routes

Single-hop swaps within one provider: Characteristics:
  • Single transaction
  • Lower complexity
  • Predictable fees
  • Faster execution
Example:
{
  "providers": ["THORCHAIN"],
  "legs": [], // No intermediate legs for direct routes
  "estimatedTime": {
    "total": 600 // ~10 minutes
  }
}

Multi-Leg Routes

Swaps requiring multiple steps within a provider: Characteristics:
  • Multiple swaps in one transaction
  • Optimized routing through liquidity pools
  • Higher gas costs on EVM chains
  • Better rates for illiquid pairs

DEX Aggregation Routes

Cross-provider routes combining different protocols: Characteristics:
  • Multiple transactions across chains
  • Combines strengths of different providers
  • Enables otherwise impossible swaps
  • Requires careful tracking

Route Discovery Process

1. Asset Analysis

The routing engine first analyzes the assets:
const analyzeAssets = (sellAsset, buyAsset) => {
  return {
    sellChain: sellAsset.split('.')[0],
    buyChain: buyAsset.split('.')[0],
    isCrossChain: sellChain !== buyChain,
    isNativeToNative: !sellAsset.includes('-') && !buyAsset.includes('-'),
    requiresWrapping: needsWrapping(sellAsset, buyAsset)
  };
};

2. Provider Selection

Based on asset analysis, relevant providers are identified:
const selectProviders = (analysis) => {
  const providers = [];
  
  if (analysis.isCrossChain) {
    // Cross-chain providers
    providers.push('THORCHAIN', 'CHAINFLIP', 'MAYACHAIN');
  }
  
  if (analysis.sellChain === 'SOL') {
    providers.push('JUPITER');
  }
  
  if (isEVMChain(analysis.sellChain)) {
    providers.push('ONEINCH');
  }
  
  return providers;
};

3. Route Calculation

Each provider calculates possible routes:
  • Liquidity depth at each hop
  • Price impact based on swap size
  • Fee structure (network, protocol, LP fees)
  • Execution time estimates

4. Route Optimization

Routes are ranked by:
  1. Output amount (after all fees)
  2. Execution speed
  3. Route complexity
  4. Security considerations

Route Metadata

Each route includes rich metadata for decision-making:

Price Impact

{
  "meta": {
    "priceImpact": 0.15, // 0.15% price impact
    "tags": ["BEST", "LOW_IMPACT"]
  }
}
Thresholds:
  • < 0.1% - Negligible impact
  • 0.1% - 1% - Low impact
  • 1% - 3% - Moderate impact
  • 3% - 5% - High impact
  • > 5% - Very high impact

Route Tags

Routes are tagged for easy identification:
TagDescription
FASTESTQuickest execution time
CHEAPESTLowest fees
BESTBest overall value
RECOMMENDEDPlatform recommendation

Time Estimates

{
  "estimatedTime": {
    "inbound": 600,   // Time for source chain confirmation
    "swap": 10,       // Time for swap execution
    "outbound": 180,  // Time for destination delivery
    "total": 790      // Total seconds (~13 minutes)
  }
}

Complex Routing Examples

Cross-Chain Token to Token

Swapping USDC on Ethereum to USDC on Solana: Route Structure:
{
  "providers": ["THORCHAIN", "JUPITER"],
  "legs": [
    {
      "provider": "THORCHAIN",
      "sellAsset": "ETH.USDC",
      "buyAsset": "SOL.SOL"
    },
    {
      "provider": "JUPITER",
      "sellAsset": "SOL.SOL",
      "buyAsset": "SOL.USDC"
    }
  ]
}

Arbitrage Routes

Finding profitable paths between assets:
// Triangular arbitrage detection
const findArbitrageRoute = async (startAsset, amount) => {
  // Path 1: Asset A → B → C → A
  const path1 = await getQuote({
    sellAsset: startAsset,
    buyAsset: 'ETH.USDC',
    sellAmount: amount
  });
  
  const path2 = await getQuote({
    sellAsset: 'ETH.USDC',
    buyAsset: 'ETH.WBTC',
    sellAmount: path1.routes[0].expectedBuyAmount
  });
  
  const path3 = await getQuote({
    sellAsset: 'ETH.WBTC',
    buyAsset: startAsset,
    sellAmount: path2.routes[0].expectedBuyAmount
  });
  
  const profit = BigInt(path3.routes[0].expectedBuyAmount) - BigInt(amount);
  
  return {
    profitable: profit > 0,
    profitAmount: profit.toString(),
    route: [path1, path2, path3]
  };
};

Route Selection Strategies

Optimizing for Speed

const getFastestRoute = (routes) => {
  return routes
    .filter(r => r.estimatedTime)
    .sort((a, b) => a.estimatedTime.total - b.estimatedTime.total)[0];
};

Optimizing for Output

const getBestOutput = (routes) => {
  return routes
    .sort((a, b) => 
      BigInt(b.expectedBuyAmount) - BigInt(a.expectedBuyAmount)
    )[0];
};

Balanced Optimization

const getBalancedRoute = (routes) => {
  // Score each route
  const scored = routes.map(route => {
    const outputScore = calculateOutputScore(route);
    const timeScore = calculateTimeScore(route);
    const feeScore = calculateFeeScore(route);
    
    return {
      route,
      score: outputScore * 0.5 + timeScore * 0.3 + feeScore * 0.2
    };
  });
  
  return scored.sort((a, b) => b.score - a.score)[0].route;
};

Streaming Routes

For large swaps, THORChain automatically creates streaming routes:
{
  "meta": {
    "streamingInterval": 10,     // Blocks between swaps
    "maxStreamingQuantity": 100,  // Number of sub-swaps
    "tags": ["STREAMING", "LOW_IMPACT"]
  }
}
Benefits:
  • Reduced price impact
  • Better execution price
  • Protection against manipulation
Trade-offs:
  • Longer execution time
  • Multiple transactions
  • Complex tracking

Route Warnings

Routes may include warnings about potential issues:
{
  "warnings": [
    {
      "code": "HIGH_PRICE_IMPACT",
      "display": "High price impact",
      "tooltip": "This swap will move the market price by >3%"
    },
    {
      "code": "LOW_LIQUIDITY",
      "display": "Low liquidity",
      "tooltip": "Limited liquidity may result in partial fills"
    }
  ]
}
Common warning codes:
  • HIGH_PRICE_IMPACT - Significant market impact
  • LOW_LIQUIDITY - Shallow pools
  • LONG_EXECUTION - Extended completion time
  • REQUIRES_APPROVAL - Token approval needed
  • EXPERIMENTAL_ROUTE - New or untested path

Route Execution

Pre-execution Checks

const validateRoute = (route) => {
  const checks = {
    hasInboundAddress: !!route.inboundAddress || !!route.targetAddress,
    hasValidMemo: route.memo && route.memo.length > 0,
    withinExpiration: !route.expiration || Date.now() < route.expiration,
    acceptableSlippage: route.totalSlippageBps < 500 // 5%
  };
  
  return Object.values(checks).every(check => check);
};

Transaction Building

Different routes require different transaction formats:
// Native cross-chain (THORChain)
const nativeTx = {
  to: route.inboundAddress,
  value: sellAmount,
  memo: route.memo
};

// EVM contract interaction
const evmTx = {
  to: route.tx.to,
  from: userAddress,
  value: route.tx.value,
  data: route.tx.data,
  gasLimit: estimateGas(route.tx)
};

// Solana transaction
const solanaTx = {
  instructions: route.tx.instructions,
  signers: [userWallet],
  feePayer: userWallet.publicKey
};

Route Monitoring

Track multi-leg route progress:
const trackMultiLegRoute = async (quoteId, routeIndex) => {
  let completed = false;
  
  while (!completed) {
    const status = await fetch('/track', {
      body: JSON.stringify({
        hash: currentTxHash,
        chainId: currentChainId,
        quoteId,
        routeIndex
      })
    });
    
    if (status.data.isDexAgg) {
      const { currentLeg, totalLegs, legs } = status.data.dexAggProgress;
      
      console.log(`Leg ${currentLeg}/${totalLegs}`);
      
      // Check if we need to execute next leg
      if (currentLeg < totalLegs && legs[currentLeg].status === 'waiting_user_action') {
        // Execute next leg transaction
        await executeNextLeg(legs[currentLeg]);
      }
    }
    
    completed = status.data.trackingStatus === 'completed';
    await sleep(5000);
  }
};

Best Practices

  1. Always check route validity before execution
  2. Monitor expiration times for time-sensitive routes
  3. Implement fallback routes for critical swaps
  4. Cache route calculations for repeated queries
  5. Use appropriate slippage based on route complexity
  6. Track all legs of multi-hop routes
  7. Handle partial fills gracefully