DEV Community

Cover image for 39 REST API Routes: How We Built Comprehensive Wallet Control for Trading Bots
Wallet Guy
Wallet Guy

Posted on

39 REST API Routes: How We Built Comprehensive Wallet Control for Trading Bots

39 REST API Routes: How We Built Comprehensive Wallet Control for Trading Bots

Your trading bot spotted the arbitrage opportunity — the price gap is there, the math checks out, but can it actually execute before the block closes? Reliable wallet infrastructure is the unglamorous part of trading bot development that determines whether your strategy lives or dies in production. WAIaaS is an open-source, self-hosted Wallet-as-a-Service that gives trading bots a complete REST API with built-in risk controls, multi-protocol DeFi access, and the execution primitives you actually need.

Why Wallet Infrastructure Is the Hard Part

Most trading bot tutorials stop at strategy. They show you how to detect a price discrepancy on Jupiter versus another DEX, and then wave their hands at "signing and sending a transaction." In production, that hand-wave collapses into a pile of problems: gas spikes eating your margins, unsigned approvals blocking execution, no way to simulate before committing, and a single compromised key wiping out everything your bot has earned.

The infrastructure layer needs to handle gas optimization, policy enforcement, transaction simulation, and multi-protocol execution — and it needs to do all of that without becoming the bottleneck in your execution path. That's the problem WAIaaS was built to solve.

39 API Routes Covering Every Trading Primitive

WAIaaS exposes 39 REST API route modules. For a trading bot, that full surface area matters because different trading scenarios need different primitives. Let's walk through the ones that matter most.

Authentication: Three Layers for Three Roles

WAIaaS separates concerns cleanly with three authentication methods:

# masterAuth — system administrator (wallet creation, session management, policies)
-H "X-Master-Password: my-secret-password"

# sessionAuth — AI agent or trading bot (transactions, balance queries, DeFi actions)
-H "Authorization: Bearer wai_sess_eyJhbGciOiJIUzI1NiJ9..."

# ownerAuth — fund owner (transaction approval, kill switch recovery)
-H "X-Owner-Signature: <ed25519-or-secp256k1-signature>"
-H "X-Owner-Message: <signed-message>"
Enter fullscreen mode Exit fullscreen mode

Your trading bot runs exclusively on sessionAuth. It never touches the master password. This means a compromised bot session has bounded blast radius — it can only operate within the policies you've configured for that session, and you can revoke it instantly without affecting the underlying wallet or other sessions.

Step 1: Create the Trading Wallet

Before your bot executes a single trade, you set up the wallet once using masterAuth:

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": "trading-wallet", "chain": "solana", "environment": "mainnet"}'
Enter fullscreen mode Exit fullscreen mode

Then create a session token that your bot will use for every subsequent request:

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>"}'
Enter fullscreen mode Exit fullscreen mode

From this point, your bot operates entirely with the returned session token. The wallet creation and session management are one-time setup steps — your hot path only uses sessionAuth.

Gas Conditional Execution: Only Trade When Gas Is Cheap

One of the most practical features for any bot running on EVM chains is gas conditional execution. WAIaaS has a dedicated pipeline stage (stage-gas-condition) that holds a transaction in queue until the gas price meets your configured threshold. Your bot submits the transaction, and the daemon handles the gas monitoring — you're not writing a polling loop.

For MEV bots and arbitrage strategies with thin margins, this is the difference between a profitable trade and a loss. You define the acceptable gas ceiling in your policy, and the execution engine enforces it automatically.

15 DeFi Protocols, One Wallet

This is where WAIaaS gets interesting for multi-leg strategies. WAIaaS integrates 15 DeFi protocol providers: 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 Solana-based bot, you can swap on Jupiter in the same session you use to open a Drift perpetual:

# Leg 1: Swap SOL → USDC 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": "So11111111111111111111111111111111111111112",
    "outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "amount": "1000000000"
  }'
Enter fullscreen mode Exit fullscreen mode

The Hyperliquid integration covers perpetual futures, spot trading, and sub-accounts. The cross-chain story is handled by LI.FI and Across, both integrated as first-class DeFi providers. Swap on Solana, hedge the exposure on an EVM chain, bridge the collateral — all through the same session token, same API surface, same policy enforcement layer.

Simulate Before You Execute

Trading bots that don't simulate are trading bots that occasionally blow up. WAIaaS has a dry-run API baked into the transaction route:

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
  }'
Enter fullscreen mode Exit fullscreen mode

The dryRun: true flag runs the transaction through the full 7-stage pipeline — validation, auth, policy check, gas conditions — without committing to the chain. Your bot can verify that a planned execution would actually pass all policy gates before spending gas on a transaction that was going to get blocked anyway.

The 7-stage pipeline is: validate → auth → policy → wait → execute → confirm. Every transaction goes through all of these stages. Simulation gives you deterministic pipeline output without the on-chain side effect.

Policy Engine: Risk Controls That Run Before Every Trade

The policy engine has 21 policy types with 4 security tiers (INSTANT, NOTIFY, DELAY, APPROVAL) and enforces default-deny on token transfers and contract calls. For a trading bot, the most relevant policies are:

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
    }
  }'
Enter fullscreen mode Exit fullscreen mode

The tier assignment is deterministic: transaction value ≤ instant_max_usd executes immediately, ≤ notify_max_usd executes with a notification, ≤ delay_max_usd queues for delay_seconds before executing (and can be cancelled in that window), and anything above that requires explicit owner approval.

For a bot you want running autonomously, you set instant_max_usd to the maximum trade size you're comfortable with the bot executing without any human in the loop. Large unexpected transactions hit the DELAY or APPROVAL tier automatically.

Beyond SPENDING_LIMIT, the policy types most relevant to trading bots are:

  • CONTRACT_WHITELIST — default-deny contract calls. Your bot can only interact with protocols you've explicitly whitelisted. A compromised session can't drain funds into an arbitrary contract.
  • ALLOWED_TOKENS — default-deny token transfers. Only the tokens you've listed can be moved.
  • PERP_MAX_LEVERAGE — hard cap on perpetual futures leverage, enforced at the API layer before the order reaches the protocol.
  • PERP_MAX_POSITION_USD — maximum position size in USD across perp markets.
  • PERP_ALLOWED_MARKETS — restrict which perpetual markets the bot can trade.
  • RATE_LIMIT — maximum transactions per period, useful for preventing runaway execution loops.
  • VENUE_WHITELIST — restrict which trading venues the bot can route through.

The default-deny enforcement means ALLOWED_TOKENS and CONTRACT_WHITELIST block all transfers and contract calls unless explicitly configured. This is the correct default for a bot wallet — not permissive until locked down, but locked down until explicitly opened.

Batch Transactions for Multi-Leg Strategies

The transaction schema supports 7 types in a discriminated union: Transfer, TokenTransfer, ContractCall, Approve, Batch, NftTransfer, and ContractDeploy. The Batch type lets you bundle multiple operations into a single atomic submission — useful for strategies that need to approve a spender and execute a swap in the same block, or open a position and set a stop-loss simultaneously.

Checking Balance Before Every Trade

Your bot's execution loop almost certainly starts with a balance check:

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

The TypeScript SDK wraps all of these calls with type safety and async/await ergonomics:

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'],
});

// Check balance before attempting execution
const balance = await client.getBalance();
console.log(`Balance: ${balance.balance} ${balance.symbol} (${balance.chain}/${balance.network})`);

// Send tokens
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(`Confirmed! Hash: ${tx.txHash}`);
    break;
  }
  if (tx.status === 'FAILED') {
    console.error(`Failed: ${tx.error}`);
    break;
  }
  await new Promise(resolve => setTimeout(resolve, 1000));
}
Enter fullscreen mode Exit fullscreen mode

Error codes from the API are structured and machine-readable:

{
  "error": {
    "code": "POLICY_DENIED",
    "message": "Transaction denied by SPENDING_LIMIT policy",
    "domain": "POLICY",
    "retryable": false
  }
}
Enter fullscreen mode Exit fullscreen mode

POLICY_DENIED with retryable: false means your bot should not retry — the transaction was blocked by a policy rule. INSUFFICIENT_BALANCE and TOKEN_EXPIRED are also first-class error codes your execution loop can handle explicitly.

ERC-4337 Account Abstraction for Gasless Execution

For EVM bots, WAIaaS supports ERC-4337 Account Abstraction with a dedicated UserOp build/sign API. This means gasless transactions and smart account execution — your bot can execute strategies without holding the native gas token, relying instead on a paymaster. The build-userop and sign-userop tools are available both via REST and through the 45 MCP tools.

x402: Paying for API Calls Automatically

The x402 HTTP payment protocol support deserves a mention for bots that consume paid data APIs. When your bot hits an API endpoint that returns an HTTP 402 Payment Required, WAIaaS can handle the micropayment automatically using the x402-fetch route. Combined with X402_ALLOWED_DOMAINS policy, you whitelist which API domains the bot is allowed to pay, and the payment flow is fully automated.

Quick Start for Trading Bot Developers

Getting WAIaaS running for a trading bot takes five steps:

1. Start the daemon with Docker:

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
Enter fullscreen mode Exit fullscreen mode

2. Create a wallet and session:

curl -X POST http://127.0.0.1:3100/v1/wallets \
  -H "Content-Type: application/json" \
  -H "X-Master-Password: <from-recovery.key>" \
  -d '{"name": "trading-wallet", "chain": "solana", "environment": "mainnet"}'

curl -X POST http://127.0.0.1:3100/v1/sessions \
  -H "Content-Type: application/json" \
  -H "X-Master-Password: <from-recovery.key>" \
  -d '{"walletId": "<wallet-uuid>"}'
Enter fullscreen mode Exit fullscreen mode

3. Set policies before funding the wallet:

Configure SPENDING_LIMIT, ALLOWED_TOKENS, and CONTRACT_WHITELIST policies as shown above. Default-deny enforcement means you must set ALLOWED_TOKENS and CONTRACT_WHITELIST before the bot can transact.

4. Install the SDK and point it at your daemon:

npm install @waiaas/sdk
Enter fullscreen mode Exit fullscreen mode
const client = new WAIaaSClient({
  baseUrl: 'http://127.0.0.1:3100',
  sessionToken: process.env.WAIAAS_SESSION_TOKEN,
});
Enter fullscreen mode Exit fullscreen mode

5. Explore the interactive API reference:

open http://127.0.0.1:3100/reference
Enter fullscreen mode Exit fullscreen mode

The OpenAPI 3.0 spec is auto-generated at /doc and the interactive Scalar API reference is at /reference — useful for exploring the full 39 route surface without reading source code.

What's Next

The full API surface — all 39 route modules with request/response schemas — is available interactively at /reference once you have the daemon running. The GitHub repository has the complete source for the policy engine, pipeline stages, and all 15 DeFi protocol integrations if you want to understand exactly what happens between your bot's API call and the on-chain transaction.

If you're building a trading bot that needs wallet infrastructure that doesn't get in the way of your strategy, start here:

Top comments (0)