Skip to main content
Glama

get_swap_quote

Retrieve a token swap quote on SailFish DEX by specifying input and output token addresses, amount, and fee tier for accurate exchange calculations.

Instructions

Get a quote for swapping tokens on SailFish DEX

Input Schema

NameRequiredDescriptionDefault
amountInYesAmount of input token to swap
feeNoFee tier (100=0.01%, 500=0.05%, 3000=0.3%, 10000=1%)
tokenInYesAddress of the input token
tokenOutYesAddress of the output token

Input Schema (JSON Schema)

{ "properties": { "amountIn": { "description": "Amount of input token to swap", "type": "string" }, "fee": { "description": "Fee tier (100=0.01%, 500=0.05%, 3000=0.3%, 10000=1%)", "type": "number" }, "tokenIn": { "description": "Address of the input token", "type": "string" }, "tokenOut": { "description": "Address of the output token", "type": "string" } }, "required": [ "tokenIn", "tokenOut", "amountIn" ], "type": "object" }

Implementation Reference

  • src/index.ts:492-515 (registration)
    Registration of the 'get_swap_quote' tool including its schema definition in the ListToolsRequestSchema handler.
    name: 'get_swap_quote', description: 'Get a quote for swapping tokens on SailFish DEX', inputSchema: { type: 'object', properties: { tokenIn: { type: 'string', description: 'Address of the input token', }, tokenOut: { type: 'string', description: 'Address of the output token', }, amountIn: { type: 'string', description: 'Amount of input token to swap', }, fee: { type: 'number', description: 'Fee tier (100=0.01%, 500=0.05%, 3000=0.3%, 10000=1%)', }, }, required: ['tokenIn', 'tokenOut', 'amountIn'], },
  • MCP tool handler for 'get_swap_quote' in the CallToolRequestSchema switch statement. Validates input, calls swap.getSwapQuote, formats and returns the quote.
    case 'get_swap_quote': { if (!args.tokenIn || typeof args.tokenIn !== 'string') { throw new McpError(ErrorCode.InvalidParams, 'Input token address is required'); } if (!args.tokenOut || typeof args.tokenOut !== 'string') { throw new McpError(ErrorCode.InvalidParams, 'Output token address is required'); } if (!args.amountIn || typeof args.amountIn !== 'string') { throw new McpError(ErrorCode.InvalidParams, 'Input amount is required'); } const slippagePercentage = typeof args.slippagePercentage === 'number' ? args.slippagePercentage : 0.5; const quote = await swap.getSwapQuote(args.tokenIn, args.tokenOut, args.amountIn, slippagePercentage); return { content: [ { type: 'text', text: JSON.stringify({ inputToken: { address: args.tokenIn, symbol: quote.tokenInSymbol, decimals: quote.tokenInDecimals, amount: args.amountIn, rawAmount: ethers.parseUnits(args.amountIn, quote.tokenInDecimals).toString() }, outputToken: { address: args.tokenOut, symbol: quote.tokenOutSymbol, decimals: quote.tokenOutDecimals, amount: quote.formattedAmountOut, minimumAmount: quote.formattedMinimumAmountOut, rawAmount: quote.amountOut, rawMinimumAmount: quote.minimumAmountOut }, exchangeRate: (Number(quote.formattedAmountOut) / Number(args.amountIn)).toString(), priceImpact: quote.priceImpact.toFixed(2), routeType: quote.route.type, slippage: slippagePercentage.toString(), note: "Amounts are formatted using the token's decimal places. Raw amounts are in wei units." }, null, 2), }, ], }; }
  • Core implementation of getSwapQuote helper function: finds best route, gets token info, queries QuoterV2 for amountOut (direct/multi-hop), applies slippage, calculates price impact.
    export async function getSwapQuote( tokenIn: string, tokenOut: string, amountIn: string, slippagePercentage: number = 0.5 ): Promise<{ amountOut: string; formattedAmountOut: string; minimumAmountOut: string; formattedMinimumAmountOut: string; tokenInSymbol: string; tokenOutSymbol: string; tokenInDecimals: number; tokenOutDecimals: number; route: routes.RouteInfo; priceImpact: number; midPrice: string; }> { try { // Find the best route for the token pair const route = await findBestRoute(tokenIn, tokenOut); const provider = blockchain.getProvider(); // Get token details const tokenInContract = new ethers.Contract(tokenIn, ERC20_ABI, provider); const tokenOutContract = new ethers.Contract(tokenOut, ERC20_ABI, provider); const [tokenInDecimals, tokenOutDecimals, tokenInSymbol, tokenOutSymbol] = await Promise.all([ tokenInContract.decimals(), tokenOutContract.decimals(), tokenInContract.symbol(), tokenOutContract.symbol(), ]); // Convert amount to token units const amountInWei = ethers.parseUnits(amountIn, tokenInDecimals); // Get quote based on route type let amountOutWei: bigint; let midPrice: string; if (route.type === 'direct') { // Direct route (single hop) const pool = route.path[0]; const fee = parseInt(pool.feeTier); // Get quote using the QuoterV2 contract const quoterContract = new ethers.Contract(CONTRACTS.QuoterV2, QUOTER_ABI, provider); const quoteParams = { tokenIn, tokenOut, amountIn: amountInWei, fee, sqrtPriceLimitX96: 0 // No price limit }; // Use a static call to get the quote without sending a transaction const quoterInterface = new ethers.Interface(QUOTER_ABI); const calldata = quoterInterface.encodeFunctionData('quoteExactInputSingle', [quoteParams]); const result = await provider.call({ to: CONTRACTS.QuoterV2, data: calldata, }); const decodedResult = quoterInterface.decodeFunctionResult('quoteExactInputSingle', result); amountOutWei = decodedResult[0]; // Get the first return value (amountOut) // Get mid price from the pool if (pool.token0.address.toLowerCase() === tokenIn.toLowerCase()) { midPrice = pool.token1Price || '0'; } else { midPrice = pool.token0Price || '0'; } } else { // Indirect route (multi-hop) // For simplicity, we'll use the direct route approach for each hop and multiply the results // In a production environment, you would use the exactInput function with a path // First hop const pool1 = route.path[0]; const fee1 = parseInt(pool1.feeTier); const intermediaryToken = route.intermediaryToken!; // Second hop const pool2 = route.path[1]; const fee2 = parseInt(pool2.feeTier); // Get quote for first hop const quoterContract = new ethers.Contract(CONTRACTS.QuoterV2, QUOTER_ABI, provider); // First hop quote const quoteParams1 = { tokenIn, tokenOut: intermediaryToken.address, amountIn: amountInWei, fee: fee1, sqrtPriceLimitX96: 0 }; const quoterInterface = new ethers.Interface(QUOTER_ABI); const calldata1 = quoterInterface.encodeFunctionData('quoteExactInputSingle', [quoteParams1]); const result1 = await provider.call({ to: CONTRACTS.QuoterV2, data: calldata1, }); const decodedResult1 = quoterInterface.decodeFunctionResult('quoteExactInputSingle', result1); const intermediateAmountWei = decodedResult1[0]; // Second hop quote const quoteParams2 = { tokenIn: intermediaryToken.address, tokenOut, amountIn: intermediateAmountWei, fee: fee2, sqrtPriceLimitX96: 0 }; const calldata2 = quoterInterface.encodeFunctionData('quoteExactInputSingle', [quoteParams2]); const result2 = await provider.call({ to: CONTRACTS.QuoterV2, data: calldata2, }); const decodedResult2 = quoterInterface.decodeFunctionResult('quoteExactInputSingle', result2); amountOutWei = decodedResult2[0]; // Calculate mid price for multi-hop (approximate) const midPrice1 = pool1.token0.address.toLowerCase() === tokenIn.toLowerCase() ? pool1.token1Price || '0' : pool1.token0Price || '0'; const midPrice2 = pool2.token0.address.toLowerCase() === intermediaryToken.address.toLowerCase() ? pool2.token1Price || '0' : pool2.token0Price || '0'; midPrice = (parseFloat(midPrice1) * parseFloat(midPrice2)).toString(); } // Format amount out const formattedAmountOut = ethers.formatUnits(amountOutWei, tokenOutDecimals); // Calculate minimum amount out with slippage const minimumAmountOut = applySlippage(amountOutWei.toString(), slippagePercentage); const formattedMinimumAmountOut = ethers.formatUnits(minimumAmountOut, tokenOutDecimals); // Calculate price impact const priceImpact = calculatePriceImpact( amountIn, formattedAmountOut, midPrice, tokenInDecimals, tokenOutDecimals ); return { amountOut: amountOutWei.toString(), formattedAmountOut, minimumAmountOut, formattedMinimumAmountOut, tokenInSymbol, tokenOutSymbol, tokenInDecimals, tokenOutDecimals, route, priceImpact, midPrice }; } catch (error) {
  • Helper function findBestRoute that delegates to routes.getBestRoute to find optimal swap path (direct or indirect).
    export async function findBestRoute( tokenA: string, tokenB: string ): Promise<routes.RouteInfo> { try { // Get the best route from the routes module const bestRoute = await routes.getBestRoute(tokenA, tokenB); if (!bestRoute) { throw new Error(`No route found for token pair ${tokenA}/${tokenB}`); } // Remove console.log to prevent interference with JSON parsing // console.log(`Found ${bestRoute.type} route for ${tokenA}/${tokenB} with fee: ${bestRoute.totalFee * 100}%`); return bestRoute; } catch (error) { console.error('Error finding best route:', error); throw error; }
  • Input schema definition for the get_swap_quote tool.
    inputSchema: { type: 'object', properties: { tokenIn: { type: 'string', description: 'Address of the input token', }, tokenOut: { type: 'string', description: 'Address of the output token', }, amountIn: { type: 'string', description: 'Amount of input token to swap', }, fee: { type: 'number', description: 'Fee tier (100=0.01%, 500=0.05%, 3000=0.3%, 10000=1%)', }, }, required: ['tokenIn', 'tokenOut', 'amountIn'], },

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/SailFish-Finance/educhain-ai-agent-kit'

If you have feedback or need assistance with the MCP directory API, please join our Discord server