LiquidSwap Docs
  • Welcome to LiquidSwap
    • Key Features
  • Using The LiquidSwap Dapp
    • Swapping
    • Revoke Approvals
  • API
    • Using The API
      • Find Pools
      • Route Finding
      • Token List
      • Token Balances
      • Interacting with the Smart Contract
Powered by GitBook
On this page
  1. API
  2. Using The API

Interacting with the Smart Contract

The route data from the API can be used directly with the MultiHopRouter smart contract. Below is a guide on how to use the API response with the contract's executeMultiHopSwap function.

Contract Address

0x744489ee3d540777a66f2cf297479745e0852f7a

Contract Function Signature

function executeMultiHopSwap(
    address[] calldata tokens,
    uint256 amountIn,
    uint256 minAmountOut,
    Swap[][] calldata hopSwaps
) external payable returns (uint256 totalAmountOut)
Parameter
Type
Description

tokens

address[]

Array of token addresses in the swap path (including intermediates)

amountIn

uint256

Amount of input tokens (for ERC-20 tokens only)

minAmountOut

uint256

Minimum acceptable output amount (slippage protection)

hopSwaps

Swap[][]

2D array of Swap structs, where each inner array is a hop

Note: When swapping native HYPE, the amountIn parameter is ignored and the contract uses msg.value instead.

Integration Example (JavaScript/ethers.js)

This example shows how to call the API and use the response to execute a multi-hop swap:

const { ethers } = require('ethers');
const axios = require('axios');

// Constants
const RPC_URL = 'https://rpc.hyperliquid.xyz/evm';
const ROUTER_ADDRESS = '0x744489ee3d540777a66f2cf297479745e0852f7a';
const PRIVATE_KEY = 'your-private-key';
const NATIVE_TOKEN = '0x000000000000000000000000000000000000dEaD'; // NATIVE_HYPE address

// MultiHopRouter ABI (just the executeMultiHopSwap function)
const ROUTER_ABI = [
  "function executeMultiHopSwap(address[] calldata tokens, uint256 amountIn, uint256 minAmountOut, tuple(address tokenIn, address tokenOut, uint8 routerIndex, uint24 fee, uint256 amountIn, bool stable)[][] calldata hopSwaps) external payable returns (uint256 totalAmountOut)"
];

// Function to get route from API
async function getRoute(tokenA, tokenB, amountIn) {
  try {
    const response = await axios.get(
      `https://api.liqd.ag/route?tokenA=${tokenA}&tokenB=${tokenB}&amountIn=${amountIn}&multiHop=true`
    );
    return response.data;
  } catch (error) {
    console.error('Error fetching route:', error.message);
    throw error;
  }
}

// Main function to execute a multi-hop swap
async function executeMultiHopSwap(tokenA, tokenB, amountIn) {
  try {
    // Setup provider and wallet
    const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
    const wallet = new ethers.Wallet(PRIVATE_KEY, provider);
    const router = new ethers.Contract(ROUTER_ADDRESS, ROUTER_ABI, wallet);
    
    // Get route from API
    const routeData = await getRoute(tokenA, tokenB, amountIn);
    
    if (!routeData || !routeData.data || !routeData.data.bestPath) {
      throw new Error('Invalid route data returned from API');
    }
    
    // Extract path information
    const bestPath = routeData.data.bestPath;
    const tokenInfo = routeData.data.tokenInfo;
    
    // Format data for contract call
    let tokens = [];
    let hopSwaps = [];
    
    // Process the path
    if (bestPath.hop.length > 0) {
      // Build the token path array
      tokens = [bestPath.hop[0].tokenIn];
      for (let i = 0; i < bestPath.hop.length; i++) {
        tokens.push(bestPath.hop[i].tokenOut);
      }
      
      // Process each hop
      for (let i = 0; i < bestPath.hop.length; i++) {
        const hopData = bestPath.hop[i];
        const swapsForHop = [];
        
        // Get the appropriate decimals for this hop's input token
        const tokenInDecimals = i === 0 
          ? tokenInfo.tokenIn.decimals 
          : tokenInfo.intermediate.decimals;
        
        // Process each allocation in this hop
        for (const allocation of hopData.allocations) {
          swapsForHop.push({
            tokenIn: allocation.tokenIn,
            tokenOut: allocation.tokenOut,
            routerIndex: parseInt(allocation.routerIndex) || 0,
            fee: parseInt(allocation.fee) || 0,
            amountIn: ethers.utils.parseUnits(allocation.amountIn, tokenInDecimals).toString(),
            stable: allocation.stable || false
          });
        }
        
        hopSwaps.push(swapsForHop);
      }
    }
    
    // Calculate minAmountOut with 1% slippage tolerance
    const expectedOut = ethers.utils.parseUnits(bestPath.amountOut, tokenInfo.tokenOut.decimals);
    const minAmountOut = expectedOut.mul(99).div(100); // 1% slippage tolerance
    
    // Prepare transaction parameters
    const parsedAmountIn = ethers.utils.parseUnits(amountIn, tokenInfo.tokenIn.decimals);
    
    // Check if native token is used
    const isNativeToken = tokenInfo.tokenIn.address.toLowerCase() === NATIVE_TOKEN.toLowerCase();
    
    let tx;
    // Handle transaction based on token type
    if (isNativeToken) {
      // For native token (HYPE), send the amount as value
      tx = await router.executeMultiHopSwap(
        tokens,
        0,  // This value is ignored when sending native tokens
        minAmountOut,
        hopSwaps,
        {
          gasLimit: 2000000,
          value: parsedAmountIn // Send the native token amount as transaction value
        }
      );
    } else {
      // For ERC-20 tokens
      // Approve first
      const tokenContract = new ethers.Contract(
        tokenInfo.tokenIn.address,
        ['function approve(address spender, uint256 amount) returns (bool)'],
        wallet
      );
      
      const approveTx = await tokenContract.approve(ROUTER_ADDRESS, parsedAmountIn);
      await approveTx.wait();
      
      // Execute the swap with ERC-20 token
      tx = await router.executeMultiHopSwap(
        tokens,
        parsedAmountIn, // For ERC-20, pass the actual amount
        minAmountOut,
        hopSwaps,
        {
          gasLimit: 2000000,
          value: 0 // No value needed for ERC-20 swaps
        }
      );
    }
    
    const receipt = await tx.wait();
    return receipt;
  } catch (error) {
    console.error('Error executing multi-hop swap:', error);
    throw error;
  }
}

Important Notes

  1. Slippage Protection: Always include a reasonable minAmountOut value. The example uses 1% slippage tolerance.

  2. Token Approval: For ERC-20 tokens, you must approve the router contract to spend your tokens before calling executeMultiHopSwap.

  3. Gas Limits: Multi-hop swaps consume more gas than direct swaps. You may need to adjust the gas limit based on network conditions.

  4. Native HYPE Handling: When using native HYPE:

    • Send the amount in the transaction's value field

    • The contract automatically wraps the native token

    • The amountIn parameter is ignored when using native HYPE

PreviousToken Balances

Last updated 1 month ago