RathRath Finance

End-to-End Transaction Example

Follow a complete xPath flow from quote to execution and status tracking.

End-to-End Transaction Example

This example shows a typical xPath flow for quoting a route, building executable calldata, sending the transaction, and tracking execution status.

Step by Step

Start by calling GET /quote with the source chain, destination chain, token pair, amount, sender, and route mode.

import axios from 'axios';

const API_URL = 'https://api.xpath.rath.fi';

async function getQuote() {
  const response = await axios.get(`${API_URL}/quote`, {
    params: {
      fromChain: 8453,
      toChain: 42161,
      fromToken: '0x4200000000000000000000000000000000000006',
      toToken: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
      amount: '1000000000000000000',
      sender: '0x1111111111111111111111111111111111111111',
      routeMode: 'suggested',
    },
    headers: {
      'api-key': 'YOUR_API_KEY',
    },
  });

  return response.data.data;
}

const routes = await getQuote();
const selectedRoute = routes[0];

xPath can return multiple ranked routes. Choose the route that matches your price, speed, or UX preference, then use that route to request executable calldata.

Use POST /build-path to convert the selected route into a transaction payload your wallet can send onchain.

async function buildPath(route) {
  const response = await axios.post(
    `${API_URL}/build-path`,
    {
      route,
      sender: '0x1111111111111111111111111111111111111111',
    },
    {
      headers: {
        'api-key': 'YOUR_API_KEY',
      },
    }
  );

  return response.data.data;
}

const builtPath = await buildPath(selectedRoute);

If the route uses an ERC-20 input token, make sure the wallet has approved the spender before sending the main transaction.

import { Contract, ethers } from 'ethers';

const ERC20_ABI = [
  'function allowance(address owner, address spender) view returns (uint256)',
  'function approve(address spender, uint256 amount) returns (bool)',
];

async function ensureAllowance(wallet, tokenAddress, spender, amount) {
  if (tokenAddress === ethers.constants.AddressZero) {
    return;
  }

  const token = new Contract(tokenAddress, ERC20_ABI, wallet);
  const owner = await wallet.getAddress();
  const allowance = await token.allowance(owner, spender);

  if (allowance.lt(amount)) {
    const approvalTx = await token.approve(spender, amount);
    await approvalTx.wait();
  }
}

Once the route is built, send the returned transaction payload with your signer.

import { ethers } from 'ethers';

const provider = new ethers.providers.JsonRpcProvider('https://mainnet.base.org', 8453);
const wallet = ethers.Wallet.fromMnemonic(YOUR_PERSONAL_MNEMONIC).connect(provider);

await ensureAllowance(
  wallet,
  selectedRoute.fromToken.address,
  builtPath.approvalAddress,
  selectedRoute.fromAmount
);

const tx = await wallet.sendTransaction({
  to: builtPath.to,
  data: builtPath.data,
  value: builtPath.value ?? '0x0',
});

await tx.wait();

After the transaction is submitted, poll GET /status to monitor route and bridge progress until the execution is complete.

async function getStatus(txHash) {
  const response = await axios.get(`${API_URL}/status`, {
    params: {
      txHash,
    },
    headers: {
      'api-key': 'YOUR_API_KEY',
    },
  });

  return response.data.data;
}

let status;
do {
  status = await getStatus(tx.hash);
} while (status?.status !== 'DONE' && status?.status !== 'FAILED');

Full Example

import axios from 'axios';
import { Contract, ethers } from 'ethers';

const API_URL = 'https://api.xpath.rath.fi';
const ERC20_ABI = [
  'function allowance(address owner, address spender) view returns (uint256)',
  'function approve(address spender, uint256 amount) returns (bool)',
];

async function getQuote() {
  const response = await axios.get(`${API_URL}/quote`, {
    params: {
      fromChain: 8453,
      toChain: 42161,
      fromToken: '0x4200000000000000000000000000000000000006',
      toToken: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
      amount: '1000000000000000000',
      sender: '0x1111111111111111111111111111111111111111',
      routeMode: 'suggested',
    },
    headers: {
      'api-key': 'YOUR_API_KEY',
    },
  });

  return response.data.data[0];
}

async function buildPath(route) {
  const response = await axios.post(
    `${API_URL}/build-path`,
    {
      route,
      sender: '0x1111111111111111111111111111111111111111',
    },
    {
      headers: {
        'api-key': 'YOUR_API_KEY',
      },
    }
  );

  return response.data.data;
}

async function getStatus(txHash) {
  const response = await axios.get(`${API_URL}/status`, {
    params: { txHash },
    headers: {
      'api-key': 'YOUR_API_KEY',
    },
  });

  return response.data.data;
}

async function ensureAllowance(wallet, tokenAddress, spender, amount) {
  if (tokenAddress === ethers.constants.AddressZero) {
    return;
  }

  const token = new Contract(tokenAddress, ERC20_ABI, wallet);
  const owner = await wallet.getAddress();
  const allowance = await token.allowance(owner, spender);

  if (allowance.lt(amount)) {
    const approvalTx = await token.approve(spender, amount);
    await approvalTx.wait();
  }
}

async function run() {
  const provider = new ethers.providers.JsonRpcProvider('https://mainnet.base.org', 8453);
  const wallet = ethers.Wallet.fromMnemonic(YOUR_PERSONAL_MNEMONIC).connect(provider);

  const route = await getQuote();
  const builtPath = await buildPath(route);

  await ensureAllowance(
    wallet,
    route.fromToken.address,
    builtPath.approvalAddress,
    route.fromAmount
  );

  const tx = await wallet.sendTransaction({
    to: builtPath.to,
    data: builtPath.data,
    value: builtPath.value ?? '0x0',
  });

  await tx.wait();

  let status;
  do {
    status = await getStatus(tx.hash);
  } while (status?.status !== 'DONE' && status?.status !== 'FAILED');

  console.log(status);
}

run();

On this page