Cross-Chain Arbitrage with LI.FI: When Your Bot Finds Profit Across Networks

Cross-chain arbitrage bots live and die by execution speed — your bot spotted a price discrepancy between Ethereum and Solana, but bridging, swapping, and hedging across networks typically means juggling multiple SDKs, fragile key management, and zero built-in risk controls. That's the infrastructure tax that eats your edge before you even get to the trade.

The Real Cost of Arbitrage Infrastructure

Most arb bot write-ups focus on the strategy: find the spread, calculate profitability, execute. What they gloss over is the plumbing. You need to:

Every piece of that is custom code you have to write, audit, and maintain. A bug in your key management or a misconfigured gas estimate doesn't cost you a trade — it costs you the wallet. WAIaaS is a self-hosted Wallet-as-a-Service that bundles all of this into a single daemon with a REST API, so you can focus on your strategy instead of your signing logic.

What WAIaaS Gives a Trading Bot Builder

Let's be concrete. WAIaaS ships with 15 DeFi protocol providers integrated: aave-v3, across, dcent-swap, drift, erc8004, hyperliquid, jito-staking, jupiter-swap, kamino, lido-staking, lifi, pendle, polymarket, xrpl-dex, and zerox-swap. For a cross-chain arb system, the immediately relevant ones are:

One daemon, one session token, all of these reachable via REST. Your bot doesn't need separate SDK integrations for each protocol.

Beyond protocol access, the features that matter for automated trading are:

Gas conditional execution. Transactions execute only when the gas price meets a configured threshold. Your bot doesn't have to implement its own gas oracle and gating logic — WAIaaS handles it at the pipeline stage before the transaction is even submitted.

A 7-stage transaction pipeline that handles validation, authentication, policy enforcement, waiting (for gas conditions or time delays), execution, and confirmation. You get structured status responses at each stage.

21 policy types with 4 security tiers (INSTANT, NOTIFY, DELAY, APPROVAL). For a trading bot, the critical ones are SPENDING_LIMIT, ALLOWED_TOKENS, CONTRACT_WHITELIST, APPROVED_SPENDERS, PERP_MAX_LEVERAGE, PERP_MAX_POSITION_USD, PERP_ALLOWED_MARKETS, and VENUE_WHITELIST. These are your circuit breakers — they run server-side so a strategy bug can't bypass them.

Dry-run / simulation API so you can validate transaction structure and policy compliance before committing.

Setting Up the Daemon

# Docker — fastest path to a running daemon
docker run -d \
  --name waiaas \
  -p 127.0.0.1:3100:3100 \
  -v waiaas-data:/data \
  -e WAIAAS_AUTO_PROVISION=true \
  ghcr.io/minhoyoo-iotrust/waiaas:latest

# Retrieve auto-generated master password
docker exec waiaas cat /data/recovery.key

The daemon binds to 127.0.0.1:3100 by default — keep it off the public internet. For a production deployment, use the secrets overlay:

mkdir -p secrets
echo "your-secure-password" > secrets/master_password.txt
chmod 600 secrets/master_password.txt

docker compose -f docker-compose.yml -f docker-compose.secrets.yml up -d

Creating Wallets for Your Arb System

A cross-chain arb bot typically needs at least two wallets: one on EVM (for bridging out via LI.FI, trading via 0x) and one on Solana (for Jupiter swaps and Drift hedges). Create them with masterAuth:

# EVM wallet
curl -X POST http://127.0.0.1:3100/v1/wallets \
  -H "Content-Type: application/json" \
  -H "X-Master-Password: my-secret-password" \
  -d '{"name": "arb-evm", "chain": "evm", "environment": "mainnet"}'

# Solana wallet
curl -X POST http://127.0.0.1:3100/v1/wallets \
  -H "Content-Type: application/json" \
  -H "X-Master-Password: my-secret-password" \
  -d '{"name": "arb-solana", "chain": "solana", "environment": "mainnet"}'

Then create a session token for each wallet. Your bot uses session tokens — the master password never leaves your ops environment:

curl -X POST http://127.0.0.1:3100/v1/sessions \
  -H "Content-Type: application/json" \
  -H "X-Master-Password: my-secret-password" \
  -d '{"walletId": "<solana-wallet-uuid>"}'

Store the returned session token as WAIAAS_SESSION_TOKEN in your bot's environment.

The Trade Execution Flow

Here's the cross-chain arb sequence your bot would execute:

Step 1: Check balance before committing

curl http://127.0.0.1:3100/v1/wallet/balance \
  -H "Authorization: Bearer wai_sess_eyJhbGciOiJIUzI1NiJ9..."

Step 2: Simulate the swap before execution

Before spending gas on a real transaction, validate it:

curl -X POST http://127.0.0.1:3100/v1/transactions/send \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer wai_sess_<token>" \
  -d '{
    "type": "TRANSFER",
    "to": "recipient-address",
    "amount": "0.1",
    "dryRun": true
  }'

The dry-run runs the full pipeline including policy checks — so if your SPENDING_LIMIT policy would block this trade, you find out now, not after the gas is spent.

Step 3: Execute the swap on Jupiter (Solana leg)

curl -X POST http://127.0.0.1:3100/v1/actions/jupiter-swap/swap \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer wai_sess_<token>" \
  -d '{
    "inputMint": "So11111111111111111111111111111111111111112",
    "outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "amount": "1000000000"
  }'

Step 4: Bridge via LI.FI (EVM leg)

Your EVM session token hits the lifi action provider directly. Same pattern — POST to /v1/actions/lifi/<action> with the bridge parameters.

Step 5: Hedge on Drift or Hyperliquid

The Hyperliquid provider supports perpetual futures, spot trading, and sub-accounts. If your arb strategy requires a delta-neutral hedge, it's the same API surface — POST to /v1/actions/hyperliquid/<action>.

Policy Configuration for a Trading Bot

This is where WAIaaS earns its keep. A runaway bot is an existential risk. Configure your circuit breakers before you go live.

# Set a spending limit with tiered approval
curl -X POST http://127.0.0.1:3100/v1/policies \
  -H "Content-Type: application/json" \
  -H "X-Master-Password: my-secret-password" \
  -d '{
    "walletId": "<wallet-uuid>",
    "type": "SPENDING_LIMIT",
    "rules": {
      "instant_max_usd": 100,
      "notify_max_usd": 500,
      "delay_max_usd": 2000,
      "delay_seconds": 900,
      "daily_limit_usd": 5000
    }
  }'

The 4-tier logic: transactions under $100 execute immediately (INSTANT), $100–$500 execute and notify you (NOTIFY), $500–$2000 queue for 15 minutes then execute (DELAY, cancellable), and anything over $2000 requires your explicit approval (APPROVAL). This is your kill switch without having to write kill switch code.

For a trading bot you also want:

Default-deny is the right default for a trading bot. If you don't explicitly whitelist a contract, the bot cannot call it. A compromised strategy or a dependency with a bug cannot drain to an unexpected address.

TypeScript SDK for Tighter Bot Integration

If your bot is TypeScript-based, skip the curl layer and use the SDK directly:

import { WAIaaSClient, WAIaaSError } from '@waiaas/sdk';

const client = new WAIaaSClient({
  baseUrl: process.env['WAIAAS_BASE_URL'] ?? 'http://localhost:3100',
  sessionToken: process.env['WAIAAS_SESSION_TOKEN'],
});

// Step 1: Check wallet balance
const balance = await client.getBalance();
console.log(`Balance: ${balance.balance} ${balance.symbol} (${balance.chain}/${balance.network})`);

// Step 2: Send tokens
const sendResult = await client.sendToken({
  type: 'TRANSFER',
  to: 'recipient-address',
  amount: '0.001',
});
console.log(`Transaction submitted: ${sendResult.id} (status: ${sendResult.status})`);

// Step 3: Poll for confirmation
const POLL_TIMEOUT_MS = 60_000;
const startTime = Date.now();
while (Date.now() - startTime < POLL_TIMEOUT_MS) {
  const tx = await client.getTransaction(sendResult.id);
  if (tx.status === 'COMPLETED') {
    console.log(`Transaction confirmed! Hash: ${tx.txHash}`);
    break;
  }
  if (tx.status === 'FAILED') {
    console.error(`Transaction failed: ${tx.error}`);
    break;
  }
  await new Promise(resolve => setTimeout(resolve, 1000));
}

Error handling is typed — WAIaaSError gives you a code field (INSUFFICIENT_BALANCE, POLICY_DENIED, TOKEN_EXPIRED) that your bot can branch on without string-matching error messages:

try {
  const tx = await client.sendToken({ to: '...', amount: '1.0' });
} catch (error) {
  if (error instanceof WAIaaSError) {
    console.error(`API Error: [${error.code}] ${error.message}`);
    // error.code examples: INSUFFICIENT_BALANCE, POLICY_DENIED, TOKEN_EXPIRED
  }
}

POLICY_DENIED means your circuit breaker fired. Log it, alert, and halt — don't retry.

Quick Start for Trading Bot Builders

  1. Run the daemon

    docker run -d --name waiaas -p 127.0.0.1:3100:3100 \
      -v waiaas-data:/data -e WAIAAS_AUTO_PROVISION=true \
      ghcr.io/minhoyoo-iotrust/waiaas:latest
    docker exec waiaas cat /data/recovery.key
    
  2. Create wallets and session tokens for each chain your strategy touches (EVM, Solana)

  3. Configure policies before going live: SPENDING_LIMIT, ALLOWED_TOKENS, CONTRACT_WHITELIST, PERP_MAX_LEVERAGE at minimum

  4. Dry-run your first trade: add "dryRun": true to any transaction request and validate it clears policy

  5. Install the SDK (npm install @waiaas/sdk) and wire your strategy to the session token — your signing and gas logic is done

What's Next

The OpenAPI 3.0 spec is available at http://127.0.0.1:3100/doc and the interactive Scalar API reference at http://127.0.0.1:3100/reference — every endpoint, parameter, and response schema is documented there, which makes it straightforward to generate a client in whatever language your bot runs in. The 39 REST API route modules cover everything from batch transactions to ERC-4337 UserOps if your strategy needs account abstraction and gasless execution.

Build your strategy, not your wallet infrastructure. The code is at github.com/minhoyoo-iotrust/WAIaaS and the project site is at waiaas.ai.