Copy 0x744489ee3d540777a66f2cf297479745e0852f7a
Copy function executeMultiHopSwap(
address[] calldata tokens,
uint256 amountIn,
uint256 minAmountOut,
Swap[][] calldata hopSwaps
) external payable returns (uint256 totalAmountOut)
Note: When swapping native HYPE, the amountIn
parameter is ignored and the contract uses msg.value
instead.
This example shows how to call the API and use the response to execute a multi-hop swap:
Copy 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;
}
}