Router Swap
Execute optimized swaps through Ferra's smart router for best rates.
Overview
The Router module automatically finds the optimal path for your swap by:
Path Discovery: Finds all possible routes between tokens
TVL Optimization: Prioritizes pools with higher liquidity
Multi-hop Support: Routes through intermediate tokens when beneficial
Best Rate Selection: Compares all paths to find optimal execution
Quick Start
// 1. Find best route
const bestRoute = await sdk.Router.getBestInternalRouter(
'0x2::sui::SUI', // From token
'0x...::usdc::USDC', // To token
new BN('1000000000'), // Amount (1 SUI)
true, // Fix input amount
0.01, // 1% slippage
'' // No partner
)
// 2. Create swap transaction
if (bestRoute && !bestRoute.isExceed) {
const tx = await TransactionUtil.buildRouterSwapTransaction(
sdk,
bestRoute.createTxParams,
true, // byAmountIn
allCoinAssets
)
const result = await sdk.fullClient.signAndExecuteTransaction({
transaction: tx,
signer: keypair
})
}
Find Optimal Route
Basic Route Finding
const bestRoute = await sdk.Router.getBestInternalRouter(
fromCoin, // Source token
toCoin, // Target token
amount, // Swap amount
true, // Fix input (true) or output (false)
0.005, // 0.5% slippage
'' // Partner ID (optional)
)
console.log({
inputAmount: bestRoute.amountIn.toString(),
outputAmount: bestRoute.amountOut.toString(),
paths: bestRoute.paths.length,
isExceed: bestRoute.isExceed
})
With Fallback Options
// Fallback params for direct swap if no route found
const fallbackParams = {
poolAddresses: ['0xpool1...', '0xpool2...'],
coinTypeA: fromCoin,
coinTypeB: toCoin,
a2b: true,
byAmountIn: true,
amount: swapAmount.toString()
}
const bestRoute = await sdk.Router.getBestInternalRouter(
fromCoin,
toCoin,
swapAmount,
true,
0.01,
'',
fallbackParams // Will use direct swap if no route
)
Route Types
Single-Hop Route
Direct swap in one pool:
// Route: SUI -> USDC
bestRoute.paths[0] = {
poolAddress: ['0xpool...'],
a2b: [true],
coinType: ['0x2::sui::SUI', '0x...::usdc::USDC'],
amountIn: BN,
amountOut: BN
}
Multi-Hop Route
Through intermediate token:
// Route: SUI -> USDT -> USDC
bestRoute.paths[0] = {
poolAddress: ['0xpool1...', '0xpool2...'],
a2b: [true, true],
coinType: ['0x2::sui::SUI', '0x...::usdt::USDT', '0x...::usdc::USDC'],
amountIn: BN,
amountOut: BN
}
Complete Swap Flow
async function smartRouterSwap() {
try {
// 1. Get user's coin assets
const allCoinAssets = await sdk.getOwnerCoinAssets(userAddress)
// 2. Define swap parameters
const fromCoin = '0x2::sui::SUI'
const toCoin = '0x...::usdc::USDC'
const swapAmount = new BN('10000000000') // 10 SUI
const slippage = 0.01 // 1%
// 3. Find optimal route
console.log('Finding best route...')
const bestRoute = await sdk.Router.getBestInternalRouter(
fromCoin,
toCoin,
swapAmount,
true, // Fix input
slippage,
'' // No partner
)
// 4. Check if route is valid
if (!bestRoute || bestRoute.isExceed) {
throw new Error('No valid route found')
}
// 5. Display route info
console.log('Route found:')
console.log(` Input: ${bestRoute.amountIn.toString()}`)
console.log(` Output: ${bestRoute.amountOut.toString()}`)
console.log(` Hops: ${bestRoute.paths[0].poolAddress.length}`)
console.log(` Pools: ${bestRoute.paths[0].poolAddress.join(' -> ')}`)
// 6. Create swap transaction
const tx = await TransactionUtil.buildRouterSwapTransaction(
sdk,
bestRoute.createTxParams,
true, // byAmountIn
allCoinAssets
)
// 7. Execute swap
const result = await sdk.fullClient.signAndExecuteTransaction({
transaction: tx,
signer: keypair
})
console.log('Swap completed:', result.digest)
} catch (error) {
console.error('Router swap failed:', error)
}
}
Load Graph Data
Router needs graph data to find paths:
// Method 1: Auto-load from API
if (!sdk.Router.isGraphLoaded) {
await sdk.Router.loadGraphData()
}
// Method 2: Manual load with custom data
const coinData = {
coins: [
{ address: '0x2::sui::SUI', decimals: 9 },
{ address: '0x...::usdc::USDC', decimals: 6 },
{ address: '0x...::usdt::USDT', decimals: 6 }
]
}
const pathData = {
paths: [
{
base: '0x2::sui::SUI',
quote: '0x...::usdc::USDC',
addressMap: new Map([[30, '0xpool1...']]) // 0.3% fee
}
]
}
sdk.Router.loadGraph(coinData, pathData)
Advanced Features
TVL-Based Routing
Router prioritizes high-TVL pools:
// Router automatically sorts multi-hop paths by minimum TVL
const poolsWithTvl = await sdk.Router.getPoolWithTVL()
poolsWithTvl.forEach(pool => {
console.log(`Pool ${pool.poolAddress}: ${pool.tvl}`)
})
Custom Path Preferences
// Find route with specific requirements
const bestRoute = await sdk.Router.getBestInternalRouter(
fromCoin,
toCoin,
swapAmount,
true,
0.005, // Tighter slippage for large trades
partnerID // Route fees to partner
)
// Check route quality
if (bestRoute.paths[0].poolAddress.length > 2) {
console.log('Route too complex, consider direct swap')
}
Fix Output Amount
// Want exactly 1000 USDC
const bestRoute = await sdk.Router.getBestInternalRouter(
'0x2::sui::SUI',
'0x...::usdc::USDC',
new BN('1000000000'), // 1000 USDC
false, // Fix output
0.01,
''
)
console.log(`Need ${bestRoute.amountIn} SUI`)
Error Handling
try {
const bestRoute = await sdk.Router.getBestInternalRouter(
fromCoin, toCoin, amount, true, 0.01, ''
)
if (!bestRoute) {
console.log('No route available')
} else if (bestRoute.isExceed) {
console.log('Insufficient liquidity in pools')
} else if (bestRoute.paths.length === 0) {
console.log('No valid path found')
}
} catch (error) {
if (error.code === 'InvalidCoin') {
console.log('Token not supported')
} else if (error.code === 'NotFoundPath') {
console.log('No trading path exists')
}
}
Route Information
interface BestInternalRouterResult {
amountIn: BN // Input amount
amountOut: BN // Output amount
paths: OnePath[] // Route paths
isExceed: boolean // Exceeds liquidity
createTxParams: SwapWithRouterParams // Ready-to-use params
}
interface OnePath {
poolAddress: string[] // Pool addresses in order
a2b: boolean[] // Swap directions
coinType: string[] // Coin types in path
amountIn: BN // Path input
amountOut: BN // Path output
}
Important Notes
Router automatically loads graph data on first use
Multi-hop limited to 2 pools (3 tokens max)
TVL-based routing improves execution quality
Partner fees not supported with split paths
Always check
isExceed
before executingGraph data cached for performance
Last updated