From Symbol to Contract: Asset Resolution APIs for Multi-Chain Trading Bots
Your trading bot spotted the arbitrage window — SOL/USDC spread across Jupiter and a CEX, closing in seconds. The alpha is there. But before a single swap executes, your bot needs to resolve token addresses, verify it has the right session token, check gas conditions, and route the transaction through policy controls that won't silently reject a $500 move. Most of that infrastructure doesn't exist in your codebase yet. That's the problem this post solves.
Why Infrastructure Debt Kills Good Strategies
Algorithmic trading bots fail in two ways: bad strategy and bad plumbing. Bad strategy is hard to fix. Bad plumbing is just engineering work you haven't done yet.
The plumbing problem for multi-chain bots is specific: you're operating across Solana and EVM chains simultaneously, hitting 15+ DeFi protocols, managing gas costs, and maintaining risk controls that prevent your bot from blowing up a wallet on a bad trade. If you bolt all of that together yourself — custom signing logic, manual address lookups, ad hoc rate limiting, hand-rolled session management — you'll spend more time maintaining infrastructure than improving your edge. WAIaaS is a self-hosted Wallet-as-a-Service that provides that infrastructure as a local API, so you can focus on the strategy layer.
The Asset Resolution Problem
Multi-chain trading bots constantly need to answer a deceptively annoying question: what is the contract address for this token on this chain?
Hardcoding token addresses is fragile. Token lists go stale. New tokens get listed. Wrapped versions differ across chains. And when you're working across Solana (where tokens are identified by mint addresses like So11111111111111111111111111111111111111112) and EVM chains (where they're checksummed hex addresses), your address management code gets messy fast.
WAIaaS exposes a resolve-asset MCP tool and token resolution via the REST API that handles this lookup layer for you. But more importantly, it normalizes the entire execution path — from asset resolution through policy check through on-chain execution — so your bot doesn't have to think about chain-specific quirks at each step.
What WAIaaS Gives a Trading Bot
WAIaaS runs locally (default: 127.0.0.1:3100) and exposes a REST API with 39 route modules. For a trading bot, the relevant surface area is:
- Wallet management — create isolated wallets per strategy, per chain
- Session tokens — scoped credentials for bot processes
-
Transaction execution — 7 transaction types including
Batchfor atomic multi-step trades - 15 DeFi protocol integrations — Jupiter, Drift, Hyperliquid, Aave v3, LI.FI, Across, and more
- Gas conditional execution — transactions only fire when gas price meets your threshold
- Policy engine — 21 policy types with 4 security tiers to bound your bot's risk
- Dry-run simulation — test a trade path before committing gas
Let's walk through how a real trading bot interacts with each layer.
Step 1: Create an Isolated Wallet Per Strategy
Good bot architecture isolates capital per strategy. A Solana arb bot shouldn't share a wallet with your Drift perpetuals position manager. Create a wallet for each:
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"}'
Then create a session token scoped to that wallet — this is what your bot process uses at runtime:
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>"}'
The session token (wai_sess_...) is all your bot needs for transaction execution. The master password stays out of the hot path entirely.
Step 2: Check Balances Before You Trade
Before your bot enters a position, it needs to know what it's working with. The balance check is a single authenticated call:
curl http://127.0.0.1:3100/v1/wallet/balance \
-H "Authorization: Bearer wai_sess_eyJhbGciOiJIUzI1NiJ9..."
In the TypeScript SDK, the same call looks like:
import { WAIaaSClient } from '@waiaas/sdk';
const client = new WAIaaSClient({
baseUrl: 'http://127.0.0.1:3100',
sessionToken: process.env.WAIAAS_SESSION_TOKEN,
});
const balance = await client.getBalance();
console.log(`${balance.balance} ${balance.symbol} (${balance.chain}/${balance.network})`);
Use getAssets() if you need the full picture — all token balances across the wallet, not just the native token. That's your pre-flight check before sizing a position.
Step 3: Execute a Swap via Jupiter
Once your bot resolves that the Jupiter SOL/USDC spread is worth hitting, execution is a single API call:
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"
}'
Notice the token addresses here — So111...112 is the native SOL mint, EPjFW...t1v is USDC on Solana. WAIaaS handles the Jupiter routing, quote fetching, and transaction construction. Your bot just specifies the economic intent.
The same pattern works across all 15 integrated DeFi protocols. For Hyperliquid perpetuals, for Drift, for Aave v3 on EVM — the action provider pattern is consistent. Your bot doesn't need protocol-specific SDKs; it needs one authenticated HTTP client.
Step 4: Simulate Before You Execute
Sending a transaction without knowing if it'll succeed is expensive. WAIaaS has a dry-run mode that simulates the full transaction pipeline — including policy checks — without touching the chain:
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
}'
For a trading bot, this is valuable before executing large positions or testing a new strategy path. If a policy would block the trade, you find out before paying gas. If your balance is insufficient, you find out before the swap fails on-chain.
Step 5: Build Risk Controls with the Policy Engine
This is where WAIaaS earns its place in a serious trading setup. Bots go wrong. A bug in your sizing logic can drain a wallet. A policy engine that's always running gives you a hard floor on how badly things can go.
The policy engine has 21 policy types and 4 security tiers. For a trading bot, the relevant ones are:
SPENDING_LIMIT — the primary guardrail. Define how much your bot can move instantly, how much triggers a notification, how much requires a delay, and how much requires your explicit 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
}
}'
With this policy: trades under $100 execute immediately. Trades $100–$500 execute and notify you. Trades $500–$2000 wait 15 minutes (cancellable). Anything above $2000 requires manual approval. A runaway position-sizing bug can't drain more than $5000 in a day.
ALLOWED_TOKENS — default-deny whitelist. If your bot should only ever touch SOL and USDC, configure exactly that. Any attempt to approve or transfer an unknown token gets blocked at the policy layer, before signing.
CONTRACT_WHITELIST — only allows calls to contracts you've explicitly approved. If your bot is a Jupiter-only strategy, it should only be able to call the Jupiter router contract. Full stop.
PERP_MAX_LEVERAGE and PERP_MAX_POSITION_USD — for bots running on Hyperliquid or Drift, these policies enforce position sizing limits at the infrastructure layer, independent of your strategy code.
The critical detail: WAIaaS uses default-deny enforcement. A transaction is blocked unless it's explicitly permitted. You're not writing code that says "block this" — you're writing code that says "allow this, and deny everything else."
Step 6: Handle Policy Denials Gracefully
When a policy blocks a trade, your bot gets a structured error response:
{
"error": {
"code": "POLICY_DENIED",
"message": "Transaction denied by SPENDING_LIMIT policy",
"domain": "POLICY",
"retryable": false
}
}
The retryable field matters for bot logic. A POLICY_DENIED with retryable: false means you need human intervention — don't hammer the endpoint in a retry loop. A different error class might be retryable. Build your bot's error handling around these structured codes, not string matching on error messages.
In TypeScript:
import { WAIaaSClient, WAIaaSError } from '@waiaas/sdk';
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
}
}
Step 7: Multi-Step Execution with Batch Transactions
Real trading strategies often involve more than one step. Approve a token, then deposit into a lending protocol. Swap on Jupiter, then stake the output. WAIaaS supports a Batch transaction type as one of its 7 transaction types, letting you compose atomic multi-step operations into a single transaction submission.
This matters for MEV protection: if your strategy requires two actions, bundling them prevents another actor from sandwiching the intermediate state.
Connecting to Claude or an LLM Orchestrator via MCP
If your trading bot is LLM-orchestrated — using Claude or another model to interpret market signals and decide on trades — WAIaaS has a 45-tool MCP server that gives the model direct access to wallet operations without you building a custom tool layer.
Setup is a single command:
waiaas mcp setup --all
That auto-registers all your wallets with Claude Desktop. The MCP server exposes tools including get_balance, send_token, get_defi_positions, simulate_transaction, hyperliquid, polymarket, and get_assets — the full trading surface area, all authenticated and policy-gated.
For a multi-strategy setup where different LLM agents manage different wallets, you can run one MCP server 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"
}
},
"waiaas-solana": {
"command": "npx",
"args": ["-y", "@waiaas/mcp"],
"env": {
"WAIAAS_BASE_URL": "http://127.0.0.1:3100",
"WAIAAS_AGENT_ID": "019c4cd2-86e8-758f-a61e-9c560307c788",
"WAIAAS_AGENT_NAME": "solana-wallet",
"WAIAAS_DATA_DIR": "~/.waiaas"
}
}
}
}
Each agent gets its own session scope, its own policies, its own position limits. They can't interfere with each other's capital.
Quick Start: Bot Infrastructure in 5 Minutes
# 1. Install the CLI
npm install -g @waiaas/cli
# 2. Initialize and start the daemon
waiaas init
waiaas start
# 3. Create wallets and sessions in one command
waiaas quickset --mode mainnet
# 4. Connect your bot using the session token printed by quickset
# Set WAIAAS_SESSION_TOKEN in your bot's environment
# 5. (Optional) Register with Claude Desktop
waiaas mcp setup --all
For production deployments, Docker is the better path:
git clone https://github.com/minhoyoo-iotrust/WAIaaS.git
cd WAIaaS
docker compose up -d
The daemon runs on 127.0.0.1:3100 by default — local-only by design. Your API keys and session tokens never leave the host.
The OpenAPI Spec Is Your Friend
WAIaaS auto-generates an OpenAPI 3.0 spec and serves an interactive API reference:
# Download the spec for your bot's HTTP client generation
curl http://127.0.0.1:3100/doc -o openapi.json
# Browse the interactive reference
open http://127.0.0.1:3100/reference
If you're generating a typed HTTP client for your bot (which you should be), point your generator at /doc and get a fully typed interface to all 39 API route modules.
What's Next
WAIaaS is open-source and self-hosted — your keys stay on your infrastructure, your trades stay private, and you're not dependent on a third-party service staying online when your bot needs to execute. The full codebase, including the 15 DeFi protocol integrations and policy engine, is on GitHub.
Star the repo and read the full documentation to go deeper on policy configuration, account abstraction with ERC-4337, and the incoming transaction monitoring that lets your bot react to deposits in real time.
- GitHub: https://github.com/minhoyoo-iotrust/WAIaaS
- Official site: https://waiaas.ai
Top comments (0)