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();