Instant Cross-Chain Arbitrage: Across Protocol Integration for Trading Bots
Instant Cross-Chain Arbitrage: Across Protocol Integration for Trading Bots
Your arb bot spotted the opportunity — a price discrepancy between Ethereum and Solana that closes in seconds. The real question isn't whether your strategy is correct. It's whether your wallet infrastructure can execute before the window disappears. Cross-chain arbitrage bots fail not because of bad alpha, but because of brittle plumbing: fragmented wallets, missing gas checks, no policy guardrails, and no way to coordinate multi-leg trades across protocols in a single coherent loop.
Why Infrastructure Is the Bottleneck
Most trading bot builders spend weeks writing the alpha logic, then another month duct-taping wallet management together. You end up with hardcoded private keys, manual nonce tracking, no spending limits, and zero observability. When a trade goes sideways — wrong gas estimate, slippage exceeded, network congestion — there's no recovery path. The bot either throws or silently bleeds funds.
The infrastructure problem compounds as your strategy grows. A simple single-chain swap is manageable. But the moment you add cross-chain bridging, perpetual futures hedging, and automated token approvals, you need a system that handles auth, policy enforcement, transaction sequencing, and multi-protocol routing as first-class concerns — not afterthoughts bolted onto a key-value store.
WAIaaS is a self-hosted Wallet-as-a-Service built specifically for this. It's open-source, runs in Docker, and exposes a REST API your bots talk to over localhost. Your private keys never leave your infrastructure.
What's Available for Trading Bots
WAIaaS integrates 15 DeFi protocol providers out of the box:
- Cross-chain bridging: Across and LI.FI
- Spot and perp trading: Jupiter Swap (Solana), Drift (Solana perps), Hyperliquid (perps + spot), 0x Swap, D'CENT Swap
- Lending/yield: Aave v3, Kamino, Pendle
- Staking: Lido (EVM), Jito (Solana)
- Prediction markets: Polymarket
- XRPL DEX
- Agent reputation: ERC-8004
For a cross-chain arb bot, the critical trio is: Jupiter Swap for Solana-side execution, Across for bridging capital between chains, and Drift or Hyperliquid for hedging exposure while the bridge settles.
The system runs across 18 networks (EVM + Solana) and supports 7 transaction types: Transfer, TokenTransfer, ContractCall, Approve, Batch, NftTransfer, and ContractDeploy.
The 7-Stage Transaction Pipeline
Before diving into code, understand what happens when your bot submits a trade. WAIaaS runs every transaction through a 7-stage pipeline:
- Validate — schema and parameter checks
- Auth — session token verification
- Policy — 21 policy types evaluated against the transaction
- Wait — gas condition checks, time delays if policy requires
- Execute — broadcast to chain
- Confirm — wait for on-chain confirmation
Stage 3 and Stage 4 are where trading bots benefit most. Policy enforcement means your bot can't accidentally blow past a daily limit. Gas conditional execution means the transaction only fires when network conditions meet your threshold — your bot doesn't waste gas on congested blocks.
Setting Up a Trading Wallet
Start the daemon and create a dedicated wallet for your arb bot:
# Install CLI and start daemon
npm install -g @waiaas/cli
waiaas init
waiaas start
# Or with Docker
docker compose up -d
Then create the 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-bot-eth", "chain": "evm", "environment": "mainnet"}'
Create a session token your bot will use for all trading operations:
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": "<wallet-uuid>"}'
Store the returned session token as WAIAAS_SESSION_TOKEN. Every trade your bot makes will authenticate with this token. No private key exposure, no nonce management in your bot code.
Policy Configuration for Trading Bots
This is the part most bot builders skip — and regret. Configure spending controls before your bot goes live.
# Daily limit with tiered approval thresholds
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 system maps directly to trading risk management:
- INSTANT (≤ $100): Small arb trades execute immediately — no latency added
- NOTIFY (≤ $500): Executes immediately, but you get notified — good for monitoring
- DELAY (≤ $2,000): Queued for 15 minutes, cancellable if market moves against you
- APPROVAL (> $2,000): Requires human sign-off via WalletConnect or Telegram
For a bot trading smaller sizes at high frequency, set instant_max_usd to your max position size and let the engine handle the rest.
You should also whitelist the specific contracts your bot interacts with. The policy engine uses default-deny for contract calls — if CONTRACT_WHITELIST is configured, any contract not on the list is blocked:
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": "CONTRACT_WHITELIST",
"rules": {
"contracts": [
{"address": "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4", "name": "Jupiter v6", "chain": "solana"},
{"address": "<across-spoke-pool-address>", "name": "Across SpokePool", "chain": "ethereum-mainnet"}
]
}
}'
For perpetual trading on Drift or Hyperliquid, add leverage limits to prevent your bot from over-leveraging in volatile conditions:
# Max 5x leverage on perps
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": "PERP_MAX_LEVERAGE",
"rules": {"maxLeverage": 5}
}'
All 21 policy types are available — PERP_MAX_POSITION_USD, PERP_ALLOWED_MARKETS, RATE_LIMIT, and VENUE_WHITELIST are all relevant for systematic trading.
Executing the Arb: Swap → Bridge → Hedge
Here's a concrete multi-leg flow. Your bot detects a SOL/USDC price discrepancy between Jupiter and a CEX. The play: buy SOL on Jupiter, bridge USDC to Ethereum via Across, then hedge the delta on Hyperliquid perps.
Leg 1: Swap USDC → SOL on Jupiter
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": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"outputMint": "So11111111111111111111111111111111111111112",
"amount": "1000000000"
}'
Leg 2: Bridge USDC to Ethereum via Across
The Across provider handles the cross-chain bridge. Your bot submits to the /v1/actions/across/ endpoint with the origin and destination parameters. Across uses intent-based bridging with relayers, which means faster settlement than optimistic bridges — critical for arb timing.
Leg 3: Simulate before committing
Before any large trade fires, use dry-run to validate execution without spending gas:
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
}'
Run this on every leg before committing. If the simulation fails — policy denied, insufficient balance, contract revert — your bot gets a structured error response with a machine-readable code:
{
"error": {
"code": "POLICY_DENIED",
"message": "Transaction denied by SPENDING_LIMIT policy",
"domain": "POLICY",
"retryable": false
}
}
retryable: false means don't retry. retryable: true means transient failure — safe to retry with backoff. Your bot's error handler can branch on error.code directly.
TypeScript Bot Integration
Use the TypeScript SDK for cleaner bot code with full type safety:
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'],
});
async function executeArbLeg() {
// Check balance before trading
const balance = await client.getBalance();
console.log(`Balance: ${balance.balance} ${balance.symbol} (${balance.chain}/${balance.network})`);
// Submit trade
const sendResult = await client.sendToken({
type: 'TRANSFER',
to: 'recipient-address',
amount: '0.001',
});
console.log(`Transaction submitted: ${sendResult.id} (status: ${sendResult.status})`);
// 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));
}
}
// Handle policy denials and other errors
try {
await executeArbLeg();
} catch (error) {
if (error instanceof WAIaaSError) {
console.error(`API Error: [${error.code}] ${error.message}`);
// error.code: INSUFFICIENT_BALANCE, POLICY_DENIED, TOKEN_EXPIRED
}
}
The SDK has zero external dependencies. Methods you'll use constantly: getBalance(), getAssets(), sendToken(), getTransaction(), listTransactions(), signTransaction(). The full TypeScript SDK ships as @waiaas/sdk.
Gas Conditional Execution
This deserves its own section because it's underused. WAIaaS has a built-in gas condition stage in the pipeline — transactions queue until gas price drops below your configured threshold.
For arb bots, this is valuable in two scenarios:
- Rebalancing operations — moving capital between wallets or chains is not time-sensitive. Let gas conditions decide when it executes.
- Multi-leg setups with tolerance — if your arb margin is 0.3% and gas eats 0.25% at current prices, the trade isn't worth it. Gas conditional execution enforces this automatically.
Your bot submits the transaction, the pipeline holds it at stage 4, and execution fires when conditions are met. No polling loop required in your bot code.
Monitoring DeFi Positions
After your bot has deployed capital across Aave, Kamino, or Drift, you need to track aggregate exposure. The DeFi positions endpoint aggregates across all integrated protocols:
curl http://127.0.0.1:3100/v1/wallet/defi-positions \
-H "Authorization: Bearer wai_sess_<token>"
For lending protocols, the LENDING_LTV_LIMIT policy type enforces a maximum loan-to-value ratio. If your bot is borrowing against collateral, this policy prevents it from opening positions that approach liquidation territory.
Connecting Claude or Other AI Agents to Your Bot Infrastructure
If you're building a hybrid system where an LLM agent assists with trade decisions, WAIaaS provides 45 MCP tools that connect directly to Claude Desktop or any MCP-compatible framework:
waiaas mcp setup --all
This auto-registers all wallets with Claude Desktop. The MCP tool list includes hyperliquid, polymarket, get-defi-positions, simulate-transaction, send-batch, and x402-fetch — the full surface area of the wallet API exposed as structured tools the LLM can call.
For multi-strategy setups, run separate MCP server instances per wallet:
{
"mcpServers": {
"waiaas-trading": {
"command": "npx",
"args": ["-y", "@waiaas/mcp"],
"env": {
"WAIAAS_BASE_URL": "http://127.0.0.1:3100",
"WAIAAS_AGENT_ID": "019c47d6-51ef-7f43-a76b-d50e875d95f4",
"WAIAAS_AGENT_NAME": "trading-agent",
"WAIAAS_DATA_DIR": "~/.waiaas"
}
}
}
}
Quickstart: Bot Infrastructure in 5 Steps
Install and start
npm install -g @waiaas/cli waiaas init waiaas quickset --mode mainnetCreate a trading wallet — POST to
/v1/walletswithchain: "evm"orchain: "solana"Configure policies — SPENDING_LIMIT + CONTRACT_WHITELIST at minimum before going live
Install the SDK —
npm install @waiaas/sdk, initialize with your session tokenDry-run every leg — set
dryRun: truein your transaction payload, validate the response, then submit for real
The interactive API reference at http://127.0.0.1:3100/reference (Scalar UI) documents all 39 route modules. The OpenAPI 3.0 spec is downloadable at /doc for generating client code in any language. A Python SDK (pip install waiaas) is also available with full async/await support.
What's Next
WAIaaS is open-source and self-hosted — your keys stay on your infrastructure, your bot logic stays private, and you're not dependent on third-party custody. The 15 integrated DeFi protocols, 21 policy types, and