7-Stage Transaction Validation: How Trading Bots Execute Safe DeFi Operations
Trading bots live and die by execution reliability — your arbitrage strategy is worthless if the transaction pipeline between "signal fired" and "swap confirmed" is a black box you can't reason about. Whether you're running a Jupiter-based SOL/USDC arb loop, hedging perpetual positions on Drift, or bridging liquidity across chains via LI.FI, every millisecond and every failed transaction represents real money. WAIaaS gives your trading bot a structured 7-stage transaction pipeline with built-in policy guardrails, gas optimization, and 15 integrated DeFi protocols — so you can focus on alpha generation instead of wallet plumbing.
Why Execution Infrastructure Is the Unglamorous Edge
Most trading bot builders spend 80% of their time on signal generation and 20% on execution. That ratio should probably be closer to 50/50. A 10bps edge evaporates if your bot double-spends due to nonce mismanagement, gets wrecked by a gas spike during high network congestion, or triggers an unintended token approval that a malicious contract later exploits.
What you actually need from wallet infrastructure:
- Deterministic execution — know exactly what happens between sending a transaction and on-chain confirmation
- Gas control — don't let your bot bleed fees when it shouldn't be trading
- Risk guardrails — spend limits, token whitelists, and leverage caps that survive even buggy bot code
- Multi-protocol reach — swap, hedge, stake, and bridge from a single session token
WAIaaS is a self-hosted Wallet-as-a-Service built specifically for AI agents and automated systems. It runs locally (or on your infra), exposes a REST API and 45 MCP tools, and wraps every transaction in a structured pipeline before anything touches the chain.
The 7-Stage Transaction Pipeline
Every transaction your bot submits — whether it's a token transfer, a Jupiter swap, or a Hyperliquid perp order — passes through a 7-stage pipeline:
stage1-validate → stage2-auth → stage3-policy → stage4-wait → stage5-execute → stage6-confirm → stages
Let's break down what each stage does for a trading bot context.
Stage 1: Validate
Schema validation happens before anything else. The transaction payload is checked against one of 7 transaction types (Transfer, TokenTransfer, ContractCall, Approve, Batch, NftTransfer, ContractDeploy). If your bot sends a malformed payload — wrong field types, missing required fields, unsupported chain — it fails fast here with a structured error, not a cryptic RPC rejection three seconds later.
Stage 2: Auth
WAIaaS uses three distinct auth layers. Your trading bot operates at the sessionAuth level — a JWT (wai_sess_...) scoped to a specific wallet. This means:
- Bot credentials are isolated from the master password used to create wallets and policies
- A compromised session token can't create new wallets or modify policies
- Per-session
TTL,maxRenewals, andabsoluteLifetimeare configurable, so you can rotate bot credentials on a schedule
# Create a session for your trading bot (masterAuth — run once during setup)
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 returned here is what your bot uses for all subsequent calls. The master password never touches bot code.
Stage 3: Policy
This is where WAIaaS earns its keep for trading infrastructure. The policy engine has 21 policy types and enforces default-deny — if ALLOWED_TOKENS or CONTRACT_WHITELIST aren't configured, transactions are blocked. For a trading bot this is a feature, not a bug: a misconfigured strategy can't accidentally drain funds into an unexpected contract.
Policies are assigned to one of 4 security tiers:
- INSTANT — execute immediately, no notification
- NOTIFY — execute immediately, push notification to owner
- DELAY — queue for N seconds, cancellable (useful for large rebalances)
- APPROVAL — require human approval via WalletConnect or Telegram
For a high-frequency arb bot, you'd configure the INSTANT tier for small trades and APPROVAL for anything above your max position size:
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
}
}'
For a perp trading bot on Hyperliquid or Drift, you'd pair this with leverage and position caps:
PERP_MAX_LEVERAGE — Max perpetual futures leverage
PERP_MAX_POSITION_USD — Max position size in USD
PERP_ALLOWED_MARKETS — Allowed perpetual markets
These aren't soft limits your bot can reason around — they're enforced at the pipeline level before any execution touches the RPC.
Stage 4: Wait (Gas Conditional Execution)
This is the stage most wallet libraries skip entirely. WAIaaS supports gas conditional execution — a transaction won't proceed to execution until the current gas price meets your configured threshold.
For Ethereum-based strategies especially, this matters enormously. A long-tail arb that's profitable at 20 gwei becomes a loss at 80 gwei. Rather than building gas polling into your bot logic, you set the condition at the infrastructure level and the pipeline handles the wait.
This stage is also where DELAY-tier transactions sit until their countdown expires or get cancelled by an owner action.
Stage 5: Execute
Actual RPC submission happens here. For supported DeFi protocols, WAIaaS constructs and submits the transaction through the appropriate provider. The 15 integrated protocols cover most trading use cases:
Swaps: jupiter-swap, zerox-swap, dcent-swap
Perps: hyperliquid, drift
Lending: aave-v3, kamino
Bridging: lifi, across
Staking: lido-staking, jito-staking
Options: pendle
Predict: polymarket
DEX: xrpl-dex
A Jupiter swap from your bot looks like this:
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"
}'
One session token. One API call. The protocol-specific construction, signing, and submission are handled inside the pipeline.
Stage 6: Confirm
Post-submission, the pipeline monitors for on-chain confirmation. Transaction status is queryable — your bot can poll or use the incoming transaction monitoring to get real-time deposit notifications. The TypeScript SDK makes this straightforward:
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'],
});
const sendResult = await client.sendToken({
type: 'TRANSFER',
to: 'recipient-address',
amount: '0.001',
});
// Poll for confirmation with timeout
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: ${tx.txHash}`);
break;
}
if (tx.status === 'FAILED') {
console.error(`Failed: ${tx.error}`);
break;
}
await new Promise(resolve => setTimeout(resolve, 1000));
}
Dry-Run Before You Fire
Before sending any real transaction, your bot can simulate 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 passes through the full pipeline — validation, auth, policy evaluation — but stops before execution. This is useful for testing policy configurations and catching schema errors in bot payloads before they hit the chain.
Error Handling That Actually Tells You What Failed
WAIaaS returns structured errors with a consistent format:
{
"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 is not retryable — your bot should log it and move on. A transient RPC failure might be. Building this distinction into your error handling loop is straightforward with the 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
}
}
Quick Start for Trading Bot Builders
Step 1: Deploy WAIaaS locally
git clone https://github.com/waiaas/WAIaaS.git
cd WAIaaS
docker compose up -d
WAIaaS binds to 127.0.0.1:3100 by default — it doesn't expose to the public internet out of the box.
Step 2: Create a trading wallet and session
# Create 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": "trading-wallet", "chain": "solana", "environment": "mainnet"}'
# Create bot session
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>"}'
Step 3: Configure trading policies
Set a spending limit, token whitelist, and contract whitelist before funding the wallet. The default-deny enforcement means an unconfigured wallet blocks all transactions — configure policy before adding capital.
Step 4: Install the SDK and wire up your bot
npm install @waiaas/sdk
Use client.executeAction() for DeFi protocol calls, client.sendToken() for transfers, and client.getBalance() / client.getAssets() for portfolio checks.
Step 5: Explore the full API
# Interactive API reference with all 39 route modules
open http://127.0.0.1:3100/reference
The interactive Scalar UI at /reference documents every endpoint. The OpenAPI 3.0 spec is downloadable at /doc if you want to generate a typed client in another language.
The Policy Layer as a Risk Management System
One pattern worth calling out explicitly: WAIaaS policies can function as a hard-coded risk management layer that's independent from your bot logic. Even if your strategy code has a bug that generates an absurd order size, PERP_MAX_POSITION_USD at the infrastructure level prevents execution. Even if your bot's contract interaction logic is compromised, CONTRACT_WHITELIST blocks calls to non-whitelisted addresses.
This separation matters because bot bugs and exploits happen. Having a second enforcement layer that doesn't share code with your strategy logic is a genuine architectural improvement over managing risk purely in application code.
The 21 policy types cover trading-specific scenarios you'd otherwise build yourself:
-
LENDING_LTV_LIMIT— prevents over-leveraged lending positions -
APPROVE_AMOUNT_LIMIT— blocks unlimited token approvals (a common attack vector) -
X402_ALLOWED_DOMAINS— whitelists domains your bot can auto-pay via x402 -
VENUE_WHITELIST— restricts which trading venues the bot can interact with -
ACTION_CATEGORY_LIMIT— caps DeFi action categories (e.g., limit total lending exposure)
What's Next
WAIaaS is open-source and self-hosted — your keys, your data, your infrastructure. The full codebase including the 15-package monorepo, 684+ test files, and Docker deployment configuration is on GitHub. The official site has documentation and additional setup guides.
- GitHub: https://github.com/waiaas/WAIaaS
- Official site: https://waiaas.ai
If you're building a trading system that needs reliable, auditable, policy-governed transaction execution across Solana and EVM chains, clone the repo and run docker compose up -d — you'll have a local wallet API running in under a minute.
Top comments (0)