DEV Community

Cover image for How to Build an Arbitrage Bot with a Swap API
Moon Soon
Moon Soon

Posted on • Originally published at swapapi.dev

How to Build an Arbitrage Bot with a Swap API

Crypto arbitrage bots generated over $500 million in extracted value on Ethereum alone in 2024, and DEX trading volume across EVM chains exceeded $1.76 trillion that same year. The opportunity is real, but most tutorials drown you in smart contract ABIs, router addresses, and multi-library setups before you can even fetch a price. This guide takes a different approach: you will build an arbitrage bot using a single GET request to a swap API, skipping all the contract-level complexity. By the end, you will have a working bot that monitors price differences across chains and tokens, calculates profitability including gas costs, and executes swaps on-chain. No API keys, no SDKs, no accounts required.

What You'll Need

  • Node.js 18+ or Bun (examples use Bun for speed)
  • A wallet with a private key funded on your target chains
  • ethers.js v6 (npm install ethers)
  • Basic HTTP knowledge — the entire swap integration is one GET request

The bot uses swapapi.dev, a free DEX aggregator API covering 46 EVM chains. It returns executable transaction calldata from a single endpoint, so you do not need to manage router contracts, ABIs, or liquidity source configurations.

Step 1: Understand the Arbitrage Strategy

Arbitrage profits come from price discrepancies. The two most common patterns on DEXes:

Triangular arbitrage — trade through three tokens on the same chain. For example: ETH to USDC, USDC to DAI, DAI back to ETH. If the final ETH amount exceeds your starting amount minus gas, you profit.

Cross-pair arbitrage — compare the same swap across different routing paths. The API aggregates across multiple liquidity sources, so you compare the quoted output for the same trade at different amounts or with different intermediate tokens.

Over 70% of crypto spot trading is now automated, and DEX aggregators processed $128 billion in Q4 2024. The liquidity is there — the edge comes from speed and execution efficiency.

Step 2: Fetch Quotes from the Swap API

The entire price-fetching mechanism is a single GET request. Here is how to query the price of swapping 1 ETH to USDC on Ethereum:

GET https://api.swapapi.dev/v1/swap/1?tokenIn=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE&tokenOut=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48&amount=1000000000000000000&sender=0xYourWalletAddress
Enter fullscreen mode Exit fullscreen mode

The response includes everything you need:

  • expectedAmountOut — the best-case output in the token's smallest unit
  • minAmountOut — the slippage-protected minimum
  • priceImpact — how much the trade moves the market
  • tx — a ready-to-send transaction object with to, data, value, and gasPrice

Wrap this in a reusable function:

async function getQuote(chainId: number, tokenIn: string, tokenOut: string, amount: string, sender: string) {
    const url = `https://api.swapapi.dev/v1/swap/${chainId}?tokenIn=${tokenIn}&tokenOut=${tokenOut}&amount=${amount}&sender=${sender}`;
    const res = await fetch(url);
    return res.json();
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Implement Triangular Arbitrage Detection

Triangular arbitrage checks whether cycling through three tokens yields more than you started with. Define your token addresses and loop through triangle paths:

const TOKENS = {
    ETH: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
    USDC: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
    DAI: "0x6B175474E89094C44Da98b954EedeAC495271d0F",
    WBTC: "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
};
Enter fullscreen mode Exit fullscreen mode

For each triangle (e.g., ETH -> USDC -> DAI -> ETH), fetch three sequential quotes and compare the final output to the initial input:

async function checkTriangle(path: string[], decimals: number[], amountIn: string, sender: string) {
    let currentAmount = amountIn;
    for (let i = 0; i < path.length - 1; i++) {
        const quote = await getQuote(1, path[i], path[i + 1], currentAmount, sender);
        if (!quote.success || quote.data.status !== "Successful") return null;
        currentAmount = quote.data.expectedAmountOut;
    }
    return { input: amountIn, output: currentAmount };
}
Enter fullscreen mode Exit fullscreen mode

If output > input, you have a potential arbitrage opportunity. But you need to account for gas before celebrating.

Step 4: Calculate Profitability After Gas

A common mistake in arbitrage bot tutorials is ignoring gas costs. On Ethereum mainnet, a single swap can cost $5-50 in gas. A triangle of three swaps means 3x that cost. Your profit calculation must include gas:

async function estimateGas(provider: ethers.JsonRpcProvider, tx: any) {
    const gasEstimate = await provider.estimateGas({
        from: tx.from,
        to: tx.to,
        data: tx.data,
        value: tx.value,
    });
    return gasEstimate * BigInt(120) / BigInt(100);
}
Enter fullscreen mode Exit fullscreen mode

The 20% buffer on gas estimation is critical — multi-hop swap routes are complex and can exceed initial estimates. The API's gasPrice field gives you the current gas price in wei. Multiply by the estimated gas to get total cost.

For tighter margins, consider running on Layer 2 chains. On Arbitrum (chain 42161) or Base (chain 8453), gas costs drop to fractions of a cent, making smaller arbitrage opportunities viable. Arbitrum processes over $1 billion in weekly DEX volume, providing sufficient liquidity with minimal transaction costs.

Step 5: Execute the Swap On-Chain

When your bot detects a profitable opportunity, execution must be fast. The API calldata expires after 30 seconds, so fetch a fresh quote immediately before submitting:

import { ethers } from "ethers";

async function executeSwap(provider: ethers.JsonRpcProvider, wallet: ethers.Wallet, quote: any) {
    const tx = quote.data.tx;
    const gasLimit = await estimateGas(provider, tx);
    const transaction = await wallet.sendTransaction({
        to: tx.to,
        data: tx.data,
        value: tx.value,
        gasLimit,
    });
    return transaction.wait();
}
Enter fullscreen mode Exit fullscreen mode

Before executing, always run a simulation with eth_call to verify the transaction will not revert. The API response includes rpcUrls — an array of recommended RPC endpoints for the chain, so you do not need to hardcode providers:

const rpcUrl = quote.data.rpcUrls[0];
const provider = new ethers.JsonRpcProvider(rpcUrl);
Enter fullscreen mode Exit fullscreen mode

Step 6: Build the Monitoring Loop

Tie everything together into a continuous monitoring loop. The API allows approximately 30 requests per minute per IP, so pace your queries accordingly:

const SCAN_INTERVAL = 3000;
const MIN_PROFIT_BPS = 50;

async function monitorLoop(sender: string, wallet: ethers.Wallet) {
    const triangles = [
        [TOKENS.ETH, TOKENS.USDC, TOKENS.DAI, TOKENS.ETH],
        [TOKENS.ETH, TOKENS.USDC, TOKENS.WBTC, TOKENS.ETH],
        [TOKENS.ETH, TOKENS.DAI, TOKENS.USDC, TOKENS.ETH],
    ];

    while (true) {
        for (const path of triangles) {
            const result = await checkTriangle(path, [], "1000000000000000000", sender);
            if (!result) continue;

            const profit = BigInt(result.output) - BigInt(result.input);
            const profitBps = (profit * BigInt(10000)) / BigInt(result.input);

            if (profitBps > BigInt(MIN_PROFIT_BPS)) {
                console.log(`Opportunity: ${profitBps} bps profit`);
            }
        }
        await new Promise((r) => setTimeout(r, SCAN_INTERVAL));
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 7: Handle Edge Cases

Production arbitrage bots must handle several response states from the API:

Partial fills — The API may return status: "Partial" when liquidity is insufficient for your full amount. The amountIn in the response reflects the partial amount, not your original request. Compare it to your requested amount to detect this.

NoRoute — When status: "NoRoute", no swap path exists for that pair. Skip it and move to the next opportunity.

Price impact checks — Always check priceImpact before executing. A value below -0.05 (-5%) indicates excessive slippage. Reject these trades:

if (quote.data.priceImpact < -0.05) {
    console.log("Price impact too high, skipping");
    continue;
}
Enter fullscreen mode Exit fullscreen mode

ERC-20 approvals — When the input token is not the native gas token, you must approve the router contract (tx.to) to spend your tokens before executing. Note that USDT on Ethereum requires setting the allowance to 0 before setting a new value.

FAQ

How much capital do I need to start an arbitrage bot?
On Ethereum mainnet, you need enough to cover gas costs for three swaps per triangle, which can be $15-150 per attempt. On Layer 2 chains like Arbitrum or Base, you can start with as little as $100 since gas costs are under $0.01 per transaction.

Is the swap API really free?
Yes. swapapi.dev requires no API key, no account, and no payment. It supports 46 chains with a rate limit of approximately 30 requests per minute per IP. That is sufficient for monitoring dozens of token pairs.

What chains are best for arbitrage bots?
Chains with high DEX volume and low gas costs offer the best ratio of opportunity to execution cost. Arbitrum (chain 42161), Base (chain 8453), and BSC (chain 56) are strong choices. Ethereum mainnet has the deepest liquidity but the highest gas costs, making only larger opportunities profitable.

Can I run multiple bots on different chains simultaneously?
Yes. Since the API uses chain ID as a path parameter, you can run parallel monitoring loops for different chains. Each chain has independent liquidity pools and independent arbitrage opportunities.

How do I avoid losing money to failed transactions?
Always simulate with eth_call before submitting. Always check priceImpact. Always estimate gas and include a 20% buffer. Never execute when status is anything other than "Successful". If eth_estimateGas fails, the swap would revert on-chain — do not submit.

Get Started

Test the API right now with a single curl command. This fetches a quote for swapping 1 ETH to USDC on Ethereum:

curl "https://api.swapapi.dev/v1/swap/1?tokenIn=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE&tokenOut=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48&amount=1000000000000000000&sender=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
Enter fullscreen mode Exit fullscreen mode

The response includes the full transaction object ready for on-chain execution. Read the complete API documentation to explore all 46 supported chains and start building your arbitrage bot today.

Top comments (0)