What You’ll Achieve
- Save users 10-30% on swap costs through optimal routing
- Provide consistent execution even during high volatility
- Build swap interfaces that feel as responsive as centralized exchanges
- Protect users from MEV attacks that steal value
Why Smart Routing Matters for User Retention
Poor swap execution is the #1 reason users leave DeFi apps. When users see better prices elsewhere, they don’t come back. The Main SDK’s intelligent routing ensures your users always get competitive execution:- Multi-hop optimization: Automatically finds the best path across liquidity pools
- Real-time price comparison: Compares direct vs routed swaps in milliseconds
- Gas-optimized execution: Bundles operations to reduce transaction costs
- MEV protection: Guards against front-running and sandwich attacks
Build a Smart Swap Interface
Start with a swap interface that automatically finds the best prices and protects users from common pitfalls:Copy
import { getSwapAmountSaros, swapSaros } from '@saros-finance/sdk';
import { Connection, PublicKey } from '@solana/web3.js';
// Smart swap functionality using actual SDK API
export class SmartSwapInterface {
constructor(connection, userWallet) {
this.connection = connection;
this.wallet = userWallet;
}
// Get swap estimate using actual Saros SDK
async getSwapQuote(fromMint, toMint, fromAmount, slippage = 0.5) {
console.log(`🔍 Getting swap quote for ${fromAmount} tokens`);
try {
// Note: poolParams needs to be configured for your specific pool
const poolParams = {
// Pool configuration specific to the trading pair
// This requires knowledge of the pool structure
};
const swapEstimate = await getSwapAmountSaros(
this.connection,
fromMint, // Token mint address as string
toMint, // Token mint address as string
fromAmount,
slippage,
poolParams
);
return {
amountOut: swapEstimate.amountOut,
priceImpact: swapEstimate.priceImpact || 0,
fee: swapEstimate.fee || 0
};
} catch (error) {
console.error('Swap quote failed:', error);
throw error;
}
}
// Execute swap using actual SDK
async executeSwap(fromMint, toMint, fromAmount, minAmountOut, slippage = 0.5) {
try {
console.log('🔄 Executing swap...');
const swapResult = await swapSaros(
this.connection,
this.wallet,
fromMint,
toMint,
fromAmount,
minAmountOut,
slippage
);
console.log(`✅ Swap successful! Transaction: ${swapResult.signature}`);
return swapResult;
} catch (error) {
console.error('Swap execution failed:', error.message);
throw error;
}
}
// Combined quote and execute flow
async performOptimalSwap(fromMint, toMint, fromAmount, slippage = 0.5) {
// Step 1: Get quote
const quote = await this.getSwapQuote(fromMint, toMint, fromAmount, slippage);
console.log(`📊 Swap Quote:`);
console.log(` Input: ${fromAmount} tokens`);
console.log(` Output: ${quote.amountOut} tokens`);
console.log(` Price Impact: ${quote.priceImpact}%`);
// Step 2: Execute swap
return await this.executeSwap(fromMint, toMint, fromAmount, quote.amountOut, slippage);
}
/// Execute swap with user-friendly progress updates
async executeOptimalSwap(fromToken, toToken, amount, maxSlippage = 0.5) {
const quote = await this.getBestQuote(fromToken, toToken, amount);
// Show user what they're getting
console.log(`\n🎯 Executing optimal swap:`);
console.log(`📊 Input: ${amount.toLocaleString()} ${fromToken}`);
console.log(`📊 Expected output: ${quote.outputAmount.toLocaleString()} ${toToken}`);
console.log(`📊 Max slippage: ${maxSlippage}%`);
console.log(`📊 Estimated fee: ${quote.fee?.toLocaleString() || 'Included in output'}`);
if (quote.potentialSavings > 0) {
console.log(`💡 You're saving ${quote.potentialSavings.toLocaleString()} tokens vs other routes!`);
}
try {
const swapParams = {
fromToken: new PublicKey(fromToken),
toToken: new PublicKey(toToken),
amount,
slippage: maxSlippage,
route: quote.routePath,
wallet: this.wallet,
// Enable MEV protection for larger swaps
mevProtection: amount > 1000
};
console.log('🚀 Executing swap...');
const result = await this.sdk.swaps.executeSwap(swapParams);
console.log('✅ Swap completed successfully!');
console.log(`📝 Transaction: ${result.signature}`);
console.log(`💰 Actual output: ${result.actualOutput?.toLocaleString() || 'Check wallet'} ${toToken}`);
return result;
} catch (error) {
console.error('❌ Swap execution failed:', error.message);
// Provide helpful error context
if (error.message.includes('slippage')) {
console.log('💡 Try increasing slippage tolerance or reducing amount');
} else if (error.message.includes('balance')) {
console.log('💡 Check token balance and allowances');
}
throw error;
}
}
}
/// Handle exotic token pairs that don't have direct liquidity
async swapExoticPair(fromToken, toToken, amount) {
console.log(`🔍 Finding path for exotic pair: ${fromToken} → ${toToken}`);
try {
// Automatically find the best multi-hop route
const routeOptions = await this.sdk.swaps.findOptimalRoutes({
fromToken: new PublicKey(fromToken),
toToken: new PublicKey(toToken),
amount,
maxHops: 3, // Allow up to 3 hops for exotic pairs
prioritize: 'output' // Could be 'speed', 'output', or 'fees'
});
if (routeOptions.length === 0) {
throw new Error(`No liquidity path found for ${fromToken} → ${toToken}`);
}
// Show user the route that will be used
const bestRoute = routeOptions[0];
console.log(`🛤️ Best route: ${bestRoute.path.join(' → ')}`);
console.log(`📊 ${bestRoute.hops} hops, ${bestRoute.totalFeePercent.toFixed(2)}% total fees`);
console.log(`⏱️ Estimated time: ${bestRoute.estimatedTimeSeconds}s`);
return await this.sdk.swaps.executeMultiHopSwap({
fromToken: new PublicKey(fromToken),
toToken: new PublicKey(toToken),
amount,
route: bestRoute,
slippage: 1.5, // Higher slippage for multi-hop
wallet: this.wallet
});
} catch (error) {
console.error('Multi-hop swap failed:', error.message);
if (error.message.includes('No liquidity')) {
console.log('💡 This token pair may not have sufficient liquidity');
console.log('💡 Try a smaller amount or different timing');
}
throw error;
}
}
/// Compare prices across different DEXs to ensure best execution
async compareAcrossDEXs(fromToken, toToken, amount) {
console.log(`📊 Comparing prices across DEXs for ${amount} ${fromToken}`);
const comparisons = await this.sdk.swaps.compareRoutes({
fromToken: new PublicKey(fromToken),
toToken: new PublicKey(toToken),
amount,
includeDEXs: ['saros', 'raydium', 'orca', 'jupiter'] // Compare major DEXs
});
console.log('\n🏆 Price Comparison:');
comparisons.forEach((comp, index) => {
const icon = index === 0 ? '🥇' : index === 1 ? '🥈' : index === 2 ? '🥉' : '📊';
console.log(`${icon} ${comp.dex}: ${comp.outputAmount.toLocaleString()} ${toToken} (${comp.priceImpact.toFixed(3)}% impact)`);
});
return comparisons[0]; // Return the best option
}
}
Example: Complete Swap Application
Here’s how to build a complete swap interface that gives users the best possible experience:Copy
// Example usage of the SmartSwapInterface
async function demonstrateSmartSwapping() {
const swapInterface = new SmartSwapInterface(connection, userWallet);
try {
// Scenario 1: Standard swap with optimal routing
console.log('=== Scenario 1: USDC → SOL Swap ===');
await swapInterface.executeOptimalSwap(
'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC
'So11111111111111111111111111111111111111112', // SOL
1000 * 1e6, // 1000 USDC
0.5 // 0.5% max slippage
);
// Scenario 2: Exotic pair that requires multi-hop routing
console.log('\n=== Scenario 2: Exotic Token Swap ===');
await swapInterface.swapExoticPair(
'TOKEN_A_MINT', // Some less liquid token
'TOKEN_B_MINT', // Another less liquid token
500 * 1e9 // 500 tokens
);
// Scenario 3: Price comparison for large trades
console.log('\n=== Scenario 3: Large Trade Price Shopping ===');
const bestDEX = await swapInterface.compareAcrossDEXs(
'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC
'So11111111111111111111111111111111111111112', // SOL
50000 * 1e6 // $50k USDC - large enough to care about routing
);
console.log(`\n💰 Best execution venue: ${bestDEX.dex}`);
console.log(`💰 You'll receive: ${bestDEX.outputAmount.toLocaleString()} SOL`);
} catch (error) {
console.error('Demo failed:', error);
}
}
User Experience Best Practices
Slippage Protection
Copy
// Automatically adjust slippage based on market conditions
function getRecommendedSlippage(amount, tokenPair, marketVolatility) {
let baseSlippage = 0.5; // 0.5% base
// Increase for large trades
if (amount > 10000) baseSlippage *= 1.5;
// Increase during high volatility
if (marketVolatility > 0.15) baseSlippage *= 2;
// Cap at reasonable maximum
return Math.min(baseSlippage, 3.0);
}
Price Impact Warnings
Copy
// Warn users about high price impact before they swap
function shouldWarnUser(quote) {
if (quote.priceImpact > 0.05) { // >5% impact
console.log('⚠️ HIGH PRICE IMPACT WARNING');
console.log(`This swap will move the price by ${(quote.priceImpact * 100).toFixed(1)}%`);
console.log('💡 Consider splitting into smaller trades');
return true;
}
return false;
}
Smart Default Settings
Copy
// Set smart defaults based on user behavior
class UserPreferences {
static getDefaults(userAddress) {
return {
preferredSlippage: this.getPreferredSlippage(userAddress),
maxGasFee: this.getMaxGasFee(userAddress),
mevProtection: this.shouldEnableMEVProtection(userAddress),
routingPreference: this.getRoutingPreference(userAddress) // 'fastest', 'cheapest', 'best_price'
};
}
}
## Handle Edge Cases Like a Pro
```javascript
/// Comprehensive error handling that helps users succeed
class SwapErrorHandler {
static async handleSwapError(error, originalParams) {
console.log(`❌ Swap failed: ${error.message}`);
switch (error.code) {
case 'INSUFFICIENT_BALANCE':
console.log('💡 Solution: Check your token balance');
const balance = await this.checkTokenBalance(originalParams.fromToken);
console.log(`📊 Current balance: ${balance.toLocaleString()}`);
break;
case 'SLIPPAGE_EXCEEDED':
console.log('⚠️ Price moved during transaction');
console.log('💡 Solutions:');
console.log(' • Increase slippage tolerance to', originalParams.slippage * 1.5, '%');
console.log(' • Try a smaller trade amount');
console.log(' • Wait for market to stabilize');
// Automatically retry with higher slippage if user approves
const retryWithHigherSlippage = await this.askUserConsent(
`Retry with ${(originalParams.slippage * 1.5).toFixed(1)}% slippage?`
);
if (retryWithHigherSlippage) {
return await this.retrySwap({ ...originalParams, slippage: originalParams.slippage * 1.5 });
}
break;
case 'NO_ROUTE_FOUND':
console.log('🔍 No direct liquidity found for this pair');
console.log('💡 Trying alternative solutions...');
// Try to find a multi-hop route
const alternativeRoute = await this.findAlternativeRoute(originalParams);
if (alternativeRoute) {
console.log(`✅ Found alternative route: ${alternativeRoute.path.join(' → ')}`);
return await this.executeAlternativeRoute(alternativeRoute);
} else {
console.log('💡 This token pair may not have sufficient liquidity');
console.log('💡 Try using a different DEX or waiting for more liquidity');
}
break;
case 'NETWORK_CONGESTION':
console.log('🚦 Network is congested - transactions may be slow');
console.log('💡 Options:');
console.log(' • Wait for network congestion to clear');
console.log(' • Increase priority fees for faster execution');
console.log(' • Try during off-peak hours');
break;
default:
console.log('🤔 Unexpected error occurred');
console.log('💡 Please try again or contact support with transaction details');
this.logErrorForSupport(error, originalParams);
}
}
static async suggestAlternatives(fromToken, toToken, amount) {
console.log('\n💡 Alternative suggestions:');
// Suggest splitting large trades
if (amount > 10000) {
console.log('📊 Split trade: Execute as 2-3 smaller swaps to reduce price impact');
}
// Suggest different timing
const marketHours = await this.getOptimalTradingHours();
console.log(`⏰ Best trading times: ${marketHours.join(', ')} UTC`);
// Suggest similar tokens if exact pair unavailable
const similarTokens = await this.findSimilarTokens(toToken);
if (similarTokens.length > 0) {
console.log('🔄 Similar tokens with better liquidity:');
similarTokens.forEach(token => {
console.log(` • ${token.symbol} (${token.liquidityUSD.toLocaleString()} liquidity)`);
});
}
}
}
Why Users Choose Apps with Smart Swapping
Better Execution → Users get more tokens for their moneyReliability → Transactions succeed even in volatile conditions
Transparency → Clear information about routes and fees
Protection → MEV protection saves money on large trades
Speed → Optimal routing finds the best price in seconds Next: Learn yield farming strategies to help users earn while they hold tokens, or explore liquidity management for institutional-grade portfolio tools.