<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Wallet Guy</title>
    <description>The latest articles on DEV Community by Wallet Guy (@walletguy).</description>
    <link>https://dev.to/walletguy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3839576%2Fca8024e8-c8ac-4f6a-845c-e8ad44732a67.jpeg</url>
      <title>DEV Community: Wallet Guy</title>
      <link>https://dev.to/walletguy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/walletguy"/>
    <language>en</language>
    <item>
      <title>Build Gasless AI Trading Bots with ERC-4337 Account Abstraction</title>
      <dc:creator>Wallet Guy</dc:creator>
      <pubDate>Thu, 23 Jul 2026 08:48:57 +0000</pubDate>
      <link>https://dev.to/walletguy/build-gasless-ai-trading-bots-with-erc-4337-account-abstraction-1jo9</link>
      <guid>https://dev.to/walletguy/build-gasless-ai-trading-bots-with-erc-4337-account-abstraction-1jo9</guid>
      <description>&lt;h1&gt;
  
  
  Build Gasless AI Trading Bots with ERC-4337 Account Abstraction
&lt;/h1&gt;

&lt;p&gt;Gasless AI trading bots are finally practical — but only if you're not spending half your development time wiring up 13 different protocol SDKs. Jupiter, Aave, Lido, Drift, Hyperliquid, Across — every DeFi protocol has its own integration story, its own auth model, its own quirks. If you're building a trading bot or automated yield strategy, that integration tax quietly becomes the actual project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Integration Tax Kills DeFi Bots
&lt;/h2&gt;

&lt;p&gt;Here's the reality of building a multi-protocol DeFi bot in 2026: you pick a strategy — say, borrow on Aave, bridge to Solana via Across, deploy liquidity on Kamino — and suddenly you're maintaining separate SDKs for each leg. When Aave pushes a contract upgrade, you patch one library. When Jupiter changes its routing API, you patch another. Before you know it, 60% of your codebase is protocol glue code, not strategy logic.&lt;/p&gt;

&lt;p&gt;The stakes are real. A bot that goes offline during a market move because a dependency broke isn't just annoying — it's a P&amp;amp;L event. Developers building serious automated strategies need one stable interface that handles the protocol-level complexity so they can focus on the logic that actually generates returns.&lt;/p&gt;

&lt;p&gt;ERC-4337 Account Abstraction makes gasless transactions possible in theory. What makes them practical in production is having a system that combines AA with policy enforcement, multi-protocol access, and security controls that don't require you to rebuild from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  What WAIaaS Actually Gives You
&lt;/h2&gt;

&lt;p&gt;WAIaaS is an open-source, self-hosted Wallet-as-a-Service for AI agents. The relevant part for DeFi developers: it exposes 15 integrated DeFi protocol providers through a single REST API, with ERC-4337 Account Abstraction, a 7-stage transaction pipeline, and a policy engine with 21 policy types baked in.&lt;/p&gt;

&lt;p&gt;The 15 protocols are: &lt;code&gt;aave-v3&lt;/code&gt;, &lt;code&gt;across&lt;/code&gt;, &lt;code&gt;dcent-swap&lt;/code&gt;, &lt;code&gt;drift&lt;/code&gt;, &lt;code&gt;erc8004&lt;/code&gt;, &lt;code&gt;hyperliquid&lt;/code&gt;, &lt;code&gt;jito-staking&lt;/code&gt;, &lt;code&gt;jupiter-swap&lt;/code&gt;, &lt;code&gt;kamino&lt;/code&gt;, &lt;code&gt;lido-staking&lt;/code&gt;, &lt;code&gt;lifi&lt;/code&gt;, &lt;code&gt;pendle&lt;/code&gt;, &lt;code&gt;polymarket&lt;/code&gt;, &lt;code&gt;xrpl-dex&lt;/code&gt;, and &lt;code&gt;zerox-swap&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That covers the major DeFi categories you actually care about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Swaps&lt;/strong&gt;: Jupiter (Solana), 0x, LI.FI, D'CENT&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lending&lt;/strong&gt;: Aave v3, Kamino&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Liquid staking&lt;/strong&gt;: Lido (EVM), Jito (Solana)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-chain bridging&lt;/strong&gt;: LI.FI, Across&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Perpetuals and spot&lt;/strong&gt;: Hyperliquid, Drift&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prediction markets&lt;/strong&gt;: Polymarket&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fixed yield&lt;/strong&gt;: Pendle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two chain types — EVM and Solana — across 18 networks. One API surface.&lt;/p&gt;

&lt;p&gt;On the account abstraction side, WAIaaS provides ERC-4337 support with smart accounts, gasless transactions, and a UserOp build/sign API. That means your bot can execute transactions without holding ETH for gas on every chain it operates on — the sponsor handles it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three-Auth Model You Need to Understand
&lt;/h2&gt;

&lt;p&gt;Before diving into code, the auth model matters for how you architect your bot.&lt;/p&gt;

&lt;p&gt;WAIaaS uses three authentication layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# masterAuth — system administrator (wallet creation, session management, policies)&lt;/span&gt;
&lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt;

&lt;span class="c"&gt;# sessionAuth — AI agent (transactions, balance queries, DeFi actions)&lt;/span&gt;
&lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_eyJhbGciOiJIUzI1NiJ9..."&lt;/span&gt;

&lt;span class="c"&gt;# ownerAuth — fund owner (transaction approval, kill switch recovery)&lt;/span&gt;
&lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Owner-Signature: &amp;lt;ed25519-or-secp256k1-signature&amp;gt;"&lt;/span&gt;
&lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Owner-Message: &amp;lt;signed-message&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a trading bot, the pattern is: your system admin creates wallets and sessions with &lt;code&gt;masterAuth&lt;/code&gt;, the bot itself runs with &lt;code&gt;sessionAuth&lt;/code&gt; (a JWT scoped to a specific wallet), and you as the fund owner retain &lt;code&gt;ownerAuth&lt;/code&gt; for approving large transactions or recovering control. The bot never touches your master password.&lt;/p&gt;

&lt;p&gt;Auth methods under the hood: &lt;code&gt;masterAuth&lt;/code&gt; uses Argon2id, &lt;code&gt;ownerAuth&lt;/code&gt; uses SIWS/SIWE (Sign-In with Solana/Ethereum), and &lt;code&gt;sessionAuth&lt;/code&gt; uses JWT HS256. Per-session TTL, &lt;code&gt;maxRenewals&lt;/code&gt;, and &lt;code&gt;absoluteLifetime&lt;/code&gt; are all configurable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Your Trading Bot Wallet
&lt;/h2&gt;

&lt;p&gt;Start with Docker — it's the fastest path to a running instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/waiaas/WAIaaS.git
&lt;span class="nb"&gt;cd &lt;/span&gt;WAIaaS
docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The daemon binds to &lt;code&gt;127.0.0.1:3100&lt;/code&gt; by default. Create a wallet for your bot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/wallets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "trading-wallet", "chain": "solana", "environment": "mainnet"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create a session token for the bot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/sessions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"walletId": "&amp;lt;wallet-uuid&amp;gt;"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That session token (&lt;code&gt;wai_sess_...&lt;/code&gt;) is what your bot uses for every subsequent call. Scope it tight — the policy engine is what enforces the actual limits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Policy Engine: Your Bot's Risk Manager
&lt;/h2&gt;

&lt;p&gt;This is the part that separates production-grade bots from scripts. WAIaaS has a policy engine with 21 policy types and 4 security tiers: &lt;code&gt;INSTANT&lt;/code&gt;, &lt;code&gt;NOTIFY&lt;/code&gt;, &lt;code&gt;DELAY&lt;/code&gt;, and &lt;code&gt;APPROVAL&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The default is deny. Transactions are blocked unless explicitly allowed. This is the right default for autonomous agents moving real funds.&lt;/p&gt;

&lt;p&gt;Here's a practical policy setup for a trading bot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Spending limit with 4-tier security&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "walletId": "&amp;lt;wallet-uuid&amp;gt;",
    "type": "SPENDING_LIMIT",
    "rules": {
      "instant_max_usd": 100,
      "notify_max_usd": 500,
      "delay_max_usd": 2000,
      "delay_seconds": 900,
      "daily_limit_usd": 5000
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tier assignment logic: &lt;code&gt;amount &amp;lt;= instant_max&lt;/code&gt; → execute immediately. &lt;code&gt;&amp;lt;= notify_max&lt;/code&gt; → execute and notify you. &lt;code&gt;&amp;lt;= delay_max&lt;/code&gt; → queue for 900 seconds (cancellable). &lt;code&gt;&amp;gt; delay_max&lt;/code&gt; → requires human approval via WalletConnect, Telegram, or push notification.&lt;/p&gt;

&lt;p&gt;For a bot that trades across protocols, you also want contract and token whitelists — these are default-deny independently:&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;CONTRACT_WHITELIST&lt;/code&gt; policy blocks calls to any contract not explicitly listed. The &lt;code&gt;ALLOWED_TOKENS&lt;/code&gt; policy blocks transfers of any token not on the list. The &lt;code&gt;APPROVED_SPENDERS&lt;/code&gt; policy controls which addresses can be approved to spend from the wallet. For perpetuals, &lt;code&gt;PERP_MAX_LEVERAGE&lt;/code&gt;, &lt;code&gt;PERP_MAX_POSITION_USD&lt;/code&gt;, and &lt;code&gt;PERP_ALLOWED_MARKETS&lt;/code&gt; let you enforce risk limits at the infrastructure layer rather than in your bot code.&lt;/p&gt;

&lt;p&gt;DeFi-specific policies worth knowing: &lt;code&gt;LENDING_LTV_LIMIT&lt;/code&gt; caps loan-to-value ratios on Aave/Kamino positions, &lt;code&gt;LENDING_ASSET_WHITELIST&lt;/code&gt; restricts which assets can be used as collateral or borrowed, and &lt;code&gt;VENUE_WHITELIST&lt;/code&gt; controls which trading venues the bot can route through.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-Protocol Execution: The Actual API Calls
&lt;/h2&gt;

&lt;p&gt;Here's what unified protocol access looks like in practice. All of these use the same session token pattern.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Swap on Jupiter (Solana):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/actions/jupiter-swap/swap &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_&amp;lt;token&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "inputMint": "So11111111111111111111111111111111111111112",
    "outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "amount": "1000000000"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's SOL → USDC. The routing, slippage handling, and transaction construction happen inside the provider — your bot just sends the intent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check balance before acting:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://127.0.0.1:3100/v1/wallet/balance &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_eyJhbGciOiJIUzI1NiJ9..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Simulate before executing (critical for bots):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/transactions/send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_&amp;lt;token&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "type": "TRANSFER",
    "to": "recipient-address",
    "amount": "0.1",
    "dryRun": true
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;dryRun&lt;/code&gt; flag runs the transaction through the full 7-stage pipeline — validate, auth, policy check, wait, execute, confirm — but stops before broadcast. You get the policy decision, the simulated outcome, and any errors before any funds move. For automated strategies, always dry-run before live execution on new code paths.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gas conditional execution&lt;/strong&gt; is another pipeline feature worth knowing: transactions can be configured to execute only when gas price meets a threshold. That's &lt;code&gt;stage4-wait&lt;/code&gt; in the pipeline — your bot queues the transaction and the pipeline holds it until conditions are met.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Bot in TypeScript
&lt;/h2&gt;

&lt;p&gt;The TypeScript SDK gives you typed access to the same API surface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSError&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@waiaas/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WAIaaSClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WAIAAS_BASE_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3100&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WAIAAS_SESSION_TOKEN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Check balance before trading&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBalance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Balance: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Execute a transfer — DeFi action calls follow the same pattern&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sendResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendToken&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TRANSFER&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;recipient-address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.001&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Transaction submitted: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;sendResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (status: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;sendResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Poll for confirmation&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;POLL_TIMEOUT_MS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;POLL_TIMEOUT_MS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sendResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;COMPLETED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Confirmed! Hash: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;txHash&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FAILED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Failed: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Error handling is worth being explicit about. Policy denials come back as structured errors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendToken&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`API Error: [&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;] &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// error.code examples: INSUFFICIENT_BALANCE, POLICY_DENIED, TOKEN_EXPIRED&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;POLICY_DENIED&lt;/code&gt; error with code detail tells you exactly which policy fired — &lt;code&gt;SPENDING_LIMIT&lt;/code&gt;, &lt;code&gt;CONTRACT_WHITELIST&lt;/code&gt;, &lt;code&gt;PERP_MAX_LEVERAGE&lt;/code&gt;, etc. That's actionable. Your bot can log it, alert you, and back off — rather than silently failing or throwing an opaque RPC error.&lt;/p&gt;

&lt;h2&gt;
  
  
  MCP Integration for AI-Driven Strategies
&lt;/h2&gt;

&lt;p&gt;If your bot uses an LLM for decision-making (Claude, GPT-4, or any MCP-compatible agent), WAIaaS exposes 45 MCP tools that map directly to wallet, transaction, DeFi, NFT, and x402 operations.&lt;/p&gt;

&lt;p&gt;Quick setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;waiaas mcp setup &lt;span class="nt"&gt;--all&lt;/span&gt;    &lt;span class="c"&gt;# Auto-register all wallets with Claude Desktop&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Claude Desktop config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"waiaas-trading"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@waiaas/mcp"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"WAIAAS_BASE_URL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://127.0.0.1:3100"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"WAIAAS_AGENT_ID"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"019c47d6-51ef-7f43-a76b-d50e875d95f4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"WAIAAS_AGENT_NAME"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"trading-agent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"WAIAAS_DATA_DIR"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~/.waiaas"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can run multiple wallets as separate MCP servers — one for your Solana trading wallet, one for your EVM yield strategies — with separate policy sets for each. The agent calls &lt;code&gt;get_defi_positions&lt;/code&gt; to see current exposure across Aave, Kamino, Lido, and Jito, then acts on the result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start: Five Steps to a Running Bot
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Deploy WAIaaS&lt;/strong&gt;: &lt;code&gt;docker compose up -d&lt;/code&gt; — daemon runs at &lt;code&gt;127.0.0.1:3100&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create a wallet&lt;/strong&gt;: &lt;code&gt;POST /v1/wallets&lt;/code&gt; with &lt;code&gt;masterAuth&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create a session&lt;/strong&gt;: &lt;code&gt;POST /v1/sessions&lt;/code&gt; with &lt;code&gt;masterAuth&lt;/code&gt;, get &lt;code&gt;wai_sess_...&lt;/code&gt; token&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set policies&lt;/strong&gt;: At minimum, &lt;code&gt;SPENDING_LIMIT&lt;/code&gt; + &lt;code&gt;ALLOWED_TOKENS&lt;/code&gt; + &lt;code&gt;CONTRACT_WHITELIST&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execute&lt;/strong&gt;: Use &lt;code&gt;sessionAuth&lt;/code&gt; for all bot calls — swap, lend, stake, bridge through the unified API&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For auto-provisioning without a manual password setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; waiaas &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 127.0.0.1:3100:3100 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; waiaas-data:/data &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;WAIAAS_AUTO_PROVISION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/waiaas/waiaas:latest

docker &lt;span class="nb"&gt;exec &lt;/span&gt;waiaas &lt;span class="nb"&gt;cat&lt;/span&gt; /data/recovery.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full OpenAPI 3.0 spec is at &lt;code&gt;http://127.0.0.1:3100/doc&lt;/code&gt; with an interactive reference UI at &lt;code&gt;/reference&lt;/code&gt;. All 39 REST API route modules are documented there — useful when you're mapping protocol-specific action parameters.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The 15 integrated DeFi protocols, 21 policy types, and ERC-4337 support are documented in full detail on the &lt;a href="https://github.com/waiaas/WAIaaS" rel="noopener noreferrer"&gt;WAIaaS GitHub repository&lt;/a&gt; — the codebase is open source and the protocol provider implementations are readable. For production deployments, review the Docker Secrets overlay pattern (&lt;code&gt;docker-compose.secrets.yml&lt;/code&gt;) and the 3-layer security architecture before going live with real funds. Visit &lt;a href="https://waiaas.ai" rel="noopener noreferrer"&gt;waiaas.ai&lt;/a&gt; for the full documentation and community resources.&lt;/p&gt;

</description>
      <category>ethereum</category>
      <category>defi</category>
      <category>api</category>
      <category>ai</category>
    </item>
    <item>
      <title>Complete Self-Hosting Guide: 20 CLI Commands + Docker for AI Agent Wallets</title>
      <dc:creator>Wallet Guy</dc:creator>
      <pubDate>Wed, 22 Jul 2026 15:12:02 +0000</pubDate>
      <link>https://dev.to/walletguy/complete-self-hosting-guide-20-cli-commands-docker-for-ai-agent-wallets-1381</link>
      <guid>https://dev.to/walletguy/complete-self-hosting-guide-20-cli-commands-docker-for-ai-agent-wallets-1381</guid>
      <description>&lt;h1&gt;
  
  
  Complete Self-Hosting Guide: 20 CLI Commands + Docker for AI Agent Wallets
&lt;/h1&gt;

&lt;p&gt;Self-hosting your AI agent's wallet infrastructure means your private keys never leave your server — and with WAIaaS, you can have the whole stack running in a single Docker command. If you've ever asked yourself whether you'd trust a third-party service with the keys that control your autonomous agent's funds, this guide is for you. We'll walk through every CLI command, the Docker setup, and the policy engine that keeps your agent from going rogue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Self-Custody for AI Agents Actually Matters
&lt;/h2&gt;

&lt;p&gt;There's a meaningful difference between self-hosting a blog and self-hosting financial infrastructure. When an AI agent can autonomously send transactions, the question of &lt;em&gt;who controls the keys&lt;/em&gt; becomes genuinely important — not just philosophically, but operationally.&lt;/p&gt;

&lt;p&gt;With a hosted wallet service, you're trusting a third party to hold private keys on behalf of your agent, enforce your spending rules, and keep your transaction history private. Every request you make passes through their infrastructure, subject to their rate limits, their uptime SLAs, and their terms of service. Self-hosting flips this entirely: your keys are generated and stored on your own hardware, your policies run in your own process, and the only rate limits you face are the ones your server can handle. It's the crypto equivalent of running your own email server — except in 2026, WAIaaS makes it genuinely practical rather than a masochistic weekend project.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You're Actually Installing
&lt;/h2&gt;

&lt;p&gt;WAIaaS is a 15-package monorepo organized as a Wallet-as-a-Service designed specifically for AI agents. The core daemon exposes 39 REST API route modules, provides 45 MCP tools for AI agent integration, supports 18 networks across both Solana and EVM chains, and integrates 15 DeFi protocol providers. It ships as two Docker images: the main WAIaaS daemon and a push-relay service for mobile notifications.&lt;/p&gt;

&lt;p&gt;The architecture is built around three distinct principals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Master password&lt;/strong&gt; — system administrator, creates wallets and sessions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session tokens&lt;/strong&gt; — what your AI agent actually uses to transact&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Owner auth&lt;/strong&gt; — you, the human, approving high-value transactions via WalletConnect or Telegram&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This separation means your AI agent has &lt;em&gt;just enough&lt;/em&gt; access to do its job, and nothing more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation: One Command or the Full CLI Path
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Docker Fast Lane
&lt;/h3&gt;

&lt;p&gt;If you want to be running in under two minutes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; waiaas &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 127.0.0.1:3100:3100 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; waiaas-data:/data &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;WAIAAS_AUTO_PROVISION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/minhoyoo-iotrust/waiaas:latest

&lt;span class="c"&gt;# Retrieve auto-generated master password&lt;/span&gt;
docker &lt;span class="nb"&gt;exec &lt;/span&gt;waiaas &lt;span class="nb"&gt;cat&lt;/span&gt; /data/recovery.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;WAIAAS_AUTO_PROVISION=true&lt;/code&gt; flag tells the entrypoint to generate a master password on first start and write it to &lt;code&gt;/data/recovery.key&lt;/code&gt;. Notice the port binding: &lt;code&gt;127.0.0.1:3100:3100&lt;/code&gt; — by default, the daemon only listens on localhost. This is a deliberate choice. You don't want an AI wallet daemon accidentally exposed to the public internet.&lt;/p&gt;

&lt;p&gt;For a more production-ready setup, the included Docker Compose file handles health checks, restart policies, and environment configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;daemon&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io/minhoyoo-iotrust/waiaas:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;waiaas-daemon&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1:3100:3100"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;waiaas-data:/data&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WAIAAS_DATA_DIR=/data&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WAIAAS_DAEMON_HOSTNAME=0.0.0.0&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;curl"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-f"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:3100/health"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;start_period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;waiaas-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/waiaas/WAIaaS.git
&lt;span class="nb"&gt;cd &lt;/span&gt;WAIaaS
docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For production deployments where you want to keep secrets out of environment variables entirely, there's a secrets overlay:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; secrets
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"your-secure-password"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; secrets/master_password.txt
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 secrets/master_password.txt

docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.secrets.yml up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;docker-compose.secrets.yml&lt;/code&gt; overlay uses Docker Secrets to inject credentials into the container without exposing them in &lt;code&gt;docker inspect&lt;/code&gt; output or shell history. This is the pattern you want for anything running in a homelab that faces even semi-public networks.&lt;/p&gt;

&lt;h3&gt;
  
  
  The CLI Path (All 20 Commands)
&lt;/h3&gt;

&lt;p&gt;If you prefer installing locally or want more granular control, the CLI gives you everything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @waiaas/cli
waiaas init                    &lt;span class="c"&gt;# Create data directory + config.toml&lt;/span&gt;
waiaas start                   &lt;span class="c"&gt;# Start daemon&lt;/span&gt;
waiaas quickset &lt;span class="nt"&gt;--mode&lt;/span&gt; mainnet &lt;span class="c"&gt;# Create wallets + MCP sessions in one step&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full CLI ships with exactly 20 commands:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;init&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create data directory and config.toml&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;start&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start the daemon process&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;stop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stop the daemon&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check daemon health&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;quickstart&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Opinionated first-run setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;quickset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create wallets + sessions in one step&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;set-master&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Harden master password after auto-provision&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;wallet create&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a new wallet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;wallet info&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Display wallet details and address&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;session prompt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open interactive session management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;owner connect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Link owner wallet via WalletConnect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;owner disconnect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unlink owner wallet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;owner status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show owner connection status&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mcp setup&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Register wallets with Claude Desktop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notification setup&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Configure push/Telegram notifications&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;backup create&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create encrypted backup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;backup inspect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read backup metadata without restoring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;backup list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List available backups&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;restore&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Restore from backup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;update&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Update WAIaaS to latest version&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The recommended self-hosted workflow uses auto-provision to avoid typing a password during setup, then hardens it afterward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @waiaas/cli
waiaas init &lt;span class="nt"&gt;--auto-provision&lt;/span&gt;   &lt;span class="c"&gt;# Generates random master password → recovery.key&lt;/span&gt;
waiaas start                   &lt;span class="c"&gt;# No password prompt&lt;/span&gt;
waiaas quickset                &lt;span class="c"&gt;# Creates wallets + sessions automatically&lt;/span&gt;
waiaas set-master              &lt;span class="c"&gt;# Later: set a real password, then delete recovery.key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating Wallets and Sessions
&lt;/h2&gt;

&lt;p&gt;Once the daemon is running, wallet creation goes through the master password:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/wallets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "trading-wallet", "chain": "solana", "environment": "mainnet"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create a session token for your AI agent to use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/sessions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"walletId": "&amp;lt;wallet-uuid&amp;gt;"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That session token (&lt;code&gt;wai_sess_...&lt;/code&gt;) is what your agent gets. It can check balances, send transactions, and call DeFi actions — but it cannot create new wallets, modify policies, or access the master password. Sessions support per-token TTL, &lt;code&gt;maxRenewals&lt;/code&gt;, and &lt;code&gt;absoluteLifetime&lt;/code&gt; configuration, so you can scope exactly how long an agent credential stays valid.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Policy Engine: Where Self-Hosting Really Pays Off
&lt;/h2&gt;

&lt;p&gt;This is where running your own WAIaaS instance genuinely shines. The policy engine has 21 policy types, 4 security tiers, and enforces default-deny: if &lt;code&gt;ALLOWED_TOKENS&lt;/code&gt; or &lt;code&gt;CONTRACT_WHITELIST&lt;/code&gt; aren't configured, transactions are blocked by default. You're not opting &lt;em&gt;into&lt;/em&gt; restrictions — you're explicitly opting &lt;em&gt;out&lt;/em&gt; of the safest state.&lt;/p&gt;

&lt;p&gt;The four security tiers determine what happens when a transaction comes in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;INSTANT&lt;/strong&gt; — Execute immediately, no notification&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NOTIFY&lt;/strong&gt; — Execute immediately, send you a notification&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DELAY&lt;/strong&gt; — Queue for N seconds, giving you time to cancel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;APPROVAL&lt;/strong&gt; — Hold until you explicitly approve via WalletConnect or Telegram&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A spending limit policy that uses all four tiers looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "walletId": "&amp;lt;wallet-uuid&amp;gt;",
    "type": "SPENDING_LIMIT",
    "rules": {
      "instant_max_usd": 100,
      "notify_max_usd": 500,
      "delay_max_usd": 2000,
      "delay_seconds": 900,
      "daily_limit_usd": 5000
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under this policy: transactions under $100 go straight through, $100–$500 trigger a notification to your phone, $500–$2,000 are queued for 15 minutes (cancellable), and anything above $2,000 requires your explicit approval. The transaction pipeline runs through 7 stages — validate, auth, policy, wait, execute, confirm — so the delay and approval mechanics are enforced at the infrastructure level, not in application code you wrote.&lt;/p&gt;

&lt;p&gt;Beyond spending limits, you have policies like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ALLOWED_TOKENS&lt;/code&gt; — whitelist which tokens the agent can touch&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CONTRACT_WHITELIST&lt;/code&gt; — whitelist which contracts it can call&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PERP_MAX_LEVERAGE&lt;/code&gt; — cap leverage for Hyperliquid perp trading&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;X402_ALLOWED_DOMAINS&lt;/code&gt; — control which APIs the agent can autonomously pay&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;REPUTATION_THRESHOLD&lt;/code&gt; — require minimum ERC-8004 onchain reputation score before transacting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full list of 21 types covers everything from &lt;code&gt;TIME_RESTRICTION&lt;/code&gt; (only allow transactions during business hours) to &lt;code&gt;LENDING_LTV_LIMIT&lt;/code&gt; (max loan-to-value ratio for Aave positions).&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting Your AI Agent
&lt;/h2&gt;

&lt;p&gt;Once you have a session token, connecting Claude or any MCP-compatible agent takes about 30 seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;waiaas mcp setup &lt;span class="nt"&gt;--all&lt;/span&gt;    &lt;span class="c"&gt;# Auto-register all wallets with Claude Desktop&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or configure manually in &lt;code&gt;claude_desktop_config.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"waiaas"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@waiaas/mcp"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"WAIAAS_BASE_URL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://127.0.0.1:3100"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"WAIAAS_SESSION_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wai_sess_&amp;lt;your-token&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"WAIAAS_DATA_DIR"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~/.waiaas"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP server exposes 45 tools covering wallet operations, transfers, DeFi actions, NFT management, and x402 HTTP payments. After setup, you can tell Claude to check your balance, swap SOL for USDC on Jupiter, or show your DeFi positions across all 15 integrated protocols — and every one of those transactions flows through the policy engine you configured on your own server.&lt;/p&gt;

&lt;p&gt;For agents built with the TypeScript SDK instead of MCP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@waiaas/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WAIaaSClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://127.0.0.1:3100&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WAIAAS_SESSION_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBalance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendToken&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;recipient-address...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Python SDK (&lt;code&gt;pip install waiaas&lt;/code&gt;) is also available with async/await support, using the same session token for auth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping Things Running
&lt;/h2&gt;

&lt;p&gt;A few operational notes for self-hosters:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backups&lt;/strong&gt;: Use &lt;code&gt;waiaas backup create&lt;/code&gt; before any major changes. The &lt;code&gt;backup inspect&lt;/code&gt; command lets you read metadata from a backup file without actually restoring it — useful for verifying that your automated backup job is producing valid files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Updates&lt;/strong&gt;: &lt;code&gt;waiaas update&lt;/code&gt; handles pulling the latest version. If you're running Docker Compose, you can also use Watchtower for automatic image updates — the daemon image supports this pattern.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RPC endpoints&lt;/strong&gt;: By default you'll want to configure your own RPC endpoints rather than relying on public nodes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;WAIAAS_RPC_SOLANA_MAINNET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your-rpc-url&amp;gt;
&lt;span class="nv"&gt;WAIAAS_RPC_EVM_ETHEREUM_MAINNET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your-rpc-url&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Dry-run before you commit&lt;/strong&gt;: The simulate endpoint lets you preview a transaction's outcome before actually executing it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/transactions/send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_&amp;lt;token&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "type": "TRANSFER",
    "to": "recipient-address",
    "amount": "0.1",
    "dryRun": true
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;API docs&lt;/strong&gt;: Once the daemon is running, hit &lt;code&gt;http://127.0.0.1:3100/reference&lt;/code&gt; for the interactive Scalar API reference UI, or download the full OpenAPI 3.0 spec at &lt;code&gt;/doc&lt;/code&gt;. With 39 route modules, having searchable docs locally is genuinely useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Self-Hosted Philosophy in Practice
&lt;/h2&gt;

&lt;p&gt;There's a particular type of developer who runs their own Nextcloud instead of Dropbox, their own Gitea instead of a hosted alternative, their own Vaultwarden instead of a hosted password manager. The motivation isn't that hosted services are bad — it's that sovereignty over your own data and infrastructure is worth the operational overhead.&lt;/p&gt;

&lt;p&gt;AI agent wallets fit this mindset naturally. The agent is acting on your behalf, with your funds, following your rules. Having that entire system run on hardware you control — with private keys that never leave your server, policies enforced by your own process, and transaction logs stored in your own database — is simply the consistent application of the same principle you already apply to the rest of your stack.&lt;/p&gt;

&lt;p&gt;WAIaaS is built for exactly this use case: open-source, self-hostable, with a 683+ test file codebase and a Docker image that runs as a non-root user (UID 1001) by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The best next step is getting the daemon running and creating your first wallet — the &lt;code&gt;quickstart&lt;/code&gt; flow takes about five minutes from zero. From there, spend time with the policy engine before connecting any live funds: understanding the 21 policy types and how the 4 security tiers compose gives you real confidence in what your agent can and cannot do autonomously.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/waiaas/WAIaaS" rel="noopener noreferrer"&gt;https://github.com/waiaas/WAIaaS&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Official site: &lt;a href="https://waiaas.ai" rel="noopener noreferrer"&gt;https://waiaas.ai&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>selfhosted</category>
      <category>docker</category>
      <category>cli</category>
      <category>opensource</category>
    </item>
    <item>
      <title>AI Agents as Prediction Traders: Automating Polymarket with Real Money</title>
      <dc:creator>Wallet Guy</dc:creator>
      <pubDate>Wed, 22 Jul 2026 09:03:28 +0000</pubDate>
      <link>https://dev.to/walletguy/ai-agents-as-prediction-traders-automating-polymarket-with-real-money-5541</link>
      <guid>https://dev.to/walletguy/ai-agents-as-prediction-traders-automating-polymarket-with-real-money-5541</guid>
      <description>&lt;h1&gt;
  
  
  AI Agents as Prediction Traders: Automating Polymarket with Real Money
&lt;/h1&gt;

&lt;p&gt;Prediction market trading with AI agents isn't a research concept anymore — it's something you can deploy today, with real money, on Polymarket, using infrastructure that exists right now. The gap between "AI that can reason about probabilities" and "AI that can act on those probabilities in a market" has always been wallet infrastructure. That gap is now closed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters More Than You Think
&lt;/h2&gt;

&lt;p&gt;Polymarket is one of the few places on the internet where being right about the future has immediate, verifiable financial consequences. Prediction markets aggregate information better than most institutions. They're also one of the cleaner venues for AI agents to demonstrate economic judgment — the signal is unambiguous. Either the market resolves in your favor or it doesn't.&lt;/p&gt;

&lt;p&gt;But reasoning about outcomes is the easy part. The hard part is the infrastructure layer underneath: How does an agent hold funds? How does it execute a trade without a human approving every click? How do you prevent it from losing everything in a single bad position? These aren't AI problems. They're wallet problems. And they've been largely ignored while everyone focused on making agents smarter.&lt;/p&gt;

&lt;p&gt;The moment you want an agent to participate in a prediction market autonomously — not just recommend trades, but actually execute them — you need autonomous wallet infrastructure. Not a custodied account with a human holding the keys. Not a hot wallet you paste into a config file and hope for the best. Something designed from the ground up for agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "Autonomous Wallet Infrastructure" Actually Means
&lt;/h2&gt;

&lt;p&gt;WAIaaS (Wallet-as-a-Service for AI agents) is an open-source, self-hosted daemon that gives AI agents their own wallet with full transaction capabilities, a policy engine that enforces spending rules, and a security model that keeps a human owner in the loop for decisions that matter — without requiring human approval for every small trade.&lt;/p&gt;

&lt;p&gt;Here's what that looks like in practice for a Polymarket trading agent.&lt;/p&gt;

&lt;p&gt;The agent needs to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Hold USDC (Polymarket's settlement token)&lt;/li&gt;
&lt;li&gt;Call Polymarket's smart contracts to place and manage positions&lt;/li&gt;
&lt;li&gt;Stay within predefined risk limits&lt;/li&gt;
&lt;li&gt;Report back to its owner when something significant happens&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;WAIaaS handles all four. The agent gets a session token. The owner sets policies. The daemon enforces them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Policy Engine: Your Risk Manager That Never Sleeps
&lt;/h2&gt;

&lt;p&gt;Before writing a single line of agent code, you configure what the agent is allowed to do. WAIaaS has 21 policy types organized into 4 security tiers: INSTANT, NOTIFY, DELAY, and APPROVAL.&lt;/p&gt;

&lt;p&gt;For a Polymarket agent, a reasonable starting configuration looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Set a spending limit with tiered security&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "walletId": "&amp;lt;wallet-uuid&amp;gt;",
    "type": "SPENDING_LIMIT",
    "rules": {
      "instant_max_usd": 100,
      "notify_max_usd": 500,
      "delay_max_usd": 2000,
      "delay_seconds": 900,
      "daily_limit_usd": 5000
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this does: any trade under $100 executes immediately with no notification. Trades between $100–$500 execute immediately but you get a notification. Trades between $500–$2,000 go into a 15-minute queue — you can cancel them. Anything over $2,000 requires explicit human approval. The daily cap is $5,000 regardless.&lt;/p&gt;

&lt;p&gt;This is exactly how you'd configure a junior trader with a defined mandate. The agent has real autonomy within the envelope. You retain control over decisions outside it.&lt;/p&gt;

&lt;p&gt;You'd also configure a &lt;code&gt;CONTRACT_WHITELIST&lt;/code&gt; to make sure the agent can only interact with Polymarket's contracts — nothing else:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "walletId": "&amp;lt;wallet-uuid&amp;gt;",
    "type": "CONTRACT_WHITELIST",
    "rules": {
      "contracts": [{"address": "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045", "name": "Polymarket CTF Exchange", "chain": "polygon"}]
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;WAIaaS enforces default-deny: if &lt;code&gt;CONTRACT_WHITELIST&lt;/code&gt; is configured, the agent cannot call any contract that isn't on the list. Even if the agent's reasoning goes completely sideways and it tries to do something else with the funds, the policy layer blocks it at the daemon level — before the transaction ever hits the network.&lt;/p&gt;

&lt;p&gt;The Polymarket integration itself is available through the &lt;code&gt;polymarket&lt;/code&gt; provider, which is one of WAIaaS's 15 integrated DeFi protocol providers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Giving the Agent Its Session Token
&lt;/h2&gt;

&lt;p&gt;The wallet is created by a human administrator using the master password. The agent operates using a session token — a scoped credential that can be revoked at any time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create the wallet (you do this once)&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/wallets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "polymarket-agent", "chain": "evm", "environment": "mainnet"}'&lt;/span&gt;

&lt;span class="c"&gt;# Create a session for the agent (scoped to this wallet)&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/sessions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"walletId": "&amp;lt;wallet-uuid&amp;gt;"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The session token goes into your agent's environment. The agent never sees the master password. It can't create new wallets, change policies, or touch anything outside its session scope. This is the authentication separation that makes autonomous operation safe: three distinct auth layers (masterAuth, sessionAuth, ownerAuth) with different capabilities and different holders.&lt;/p&gt;

&lt;p&gt;Sessions support per-session TTL, maximum renewals, and absolute lifetime limits — so a compromised session has a hard expiry.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Agent Code: Checking Balance and Executing a Trade
&lt;/h2&gt;

&lt;p&gt;Once the agent has a session token, it operates through the REST API or the TypeScript SDK. Here's what a minimal Polymarket trading loop looks like using the SDK:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSError&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@waiaas/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WAIaaSClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WAIAAS_BASE_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3100&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WAIAAS_SESSION_TOKEN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Check available balance before placing any position&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBalance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Available: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; on &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Agent reasoning happens here — probability assessment, Kelly criterion sizing, etc.&lt;/span&gt;
&lt;span class="c1"&gt;// Once the agent decides to place a trade, it submits via the actions API&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The actual Polymarket position is executed through the &lt;code&gt;polymarket&lt;/code&gt; action provider. The agent calls the action endpoint with the position details, and WAIaaS handles the rest: policy validation, transaction construction, signing, and submission.&lt;/p&gt;

&lt;p&gt;If the transaction is within the INSTANT tier, it goes through immediately. If it hits the NOTIFY tier, it executes and the owner gets a notification. If it's large enough to require DELAY or APPROVAL, the agent gets back a pending transaction ID and can poll for status.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check a pending transaction status&lt;/span&gt;
curl http://127.0.0.1:3100/v1/transactions/&amp;lt;tx-id&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_&amp;lt;token&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Simulating Before You Commit Real Money
&lt;/h2&gt;

&lt;p&gt;Before the agent goes live, you can run every transaction in dry-run mode. The simulation API evaluates the full pipeline — policy checks, balance validation, transaction construction — without actually submitting anything to the network.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/transactions/send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_&amp;lt;token&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "type": "TRANSFER",
    "to": "recipient-address",
    "amount": "0.1",
    "dryRun": true
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run your agent in dry-run mode for a week. Watch what it would have done. Tune the policies. Then flip the switch.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the Agent Needs Human Sign-Off
&lt;/h2&gt;

&lt;p&gt;For positions above your APPROVAL threshold, the owner gets a notification and can approve or reject via WalletConnect, Telegram, or a push notification. The transaction sits in the queue until the owner acts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Owner approves a pending large position&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/transactions/&amp;lt;tx-id&amp;gt;/approve &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Owner-Signature: &amp;lt;ed25519-or-secp256k1-signature&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Owner-Message: &amp;lt;signed-message&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;WAIaaS has 3 signing channels built in: push relay, Telegram, and wallet notification. The owner can approve from a phone while the agent continues operating normally on everything within its autonomous envelope.&lt;/p&gt;

&lt;p&gt;This is the human-in-the-loop model that actually scales. Not "approve every trade" — that's not autonomous. Not "approve nothing" — that's not safe. The policy engine defines the boundary, and the agent operates freely within it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting to Claude or Any MCP-Compatible Agent
&lt;/h2&gt;

&lt;p&gt;If you're using Claude or another MCP-compatible agent framework, WAIaaS exposes 45 MCP tools that cover the full wallet and trading surface. Setup is one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;waiaas mcp setup &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add the configuration to Claude Desktop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"waiaas-polymarket"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@waiaas/mcp"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"WAIAAS_BASE_URL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://127.0.0.1:3100"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"WAIAAS_SESSION_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wai_sess_&amp;lt;your-token&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"WAIAAS_DATA_DIR"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~/.waiaas"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude can now call &lt;code&gt;get_balance&lt;/code&gt;, &lt;code&gt;execute_action&lt;/code&gt; with the Polymarket provider, &lt;code&gt;get_defi_positions&lt;/code&gt;, and &lt;code&gt;simulate_transaction&lt;/code&gt; directly. The conversation becomes the trading interface. The policies you set in WAIaaS are the guardrails Claude operates within, regardless of what prompt someone feeds it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start: Get a Polymarket Agent Running
&lt;/h2&gt;

&lt;p&gt;Here's the minimal path from zero to a running agent:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Install and start WAIaaS&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @waiaas/cli
waiaas init
waiaas start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Create a wallet and configure policies&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create the agent wallet&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/wallets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "polymarket-agent", "chain": "evm", "environment": "mainnet"}'&lt;/span&gt;

&lt;span class="c"&gt;# Set spending limits&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"walletId": "&amp;lt;wallet-uuid&amp;gt;", "type": "SPENDING_LIMIT", "rules": {"instant_max_usd": 100, "notify_max_usd": 500, "delay_max_usd": 2000, "delay_seconds": 900, "daily_limit_usd": 5000}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Create a session token for your agent&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/sessions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"walletId": "&amp;lt;wallet-uuid&amp;gt;"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Install the SDK and start building&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @waiaas/sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 5: Run in dry-run mode first.&lt;/strong&gt; Test your agent's logic against real market conditions without risking funds. Watch the policy engine catch anything outside your configured parameters.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Deeper Point
&lt;/h2&gt;

&lt;p&gt;What makes this interesting isn't Polymarket specifically. It's the model it demonstrates: an AI agent with a real economic presence, operating within a policy envelope defined by a human owner, capable of autonomous action within that envelope and escalation outside it.&lt;/p&gt;

&lt;p&gt;Prediction markets are one of the cleaner test cases because the feedback loop is tight and objective. But the same infrastructure — scoped session tokens, a 21-type policy engine, 7-stage transaction pipeline, incoming transaction monitoring, and human-in-the-loop approval channels — applies to any economic activity you want an agent to perform.&lt;/p&gt;

&lt;p&gt;The question "how do AI agents participate in economic activity" now has a working answer. The infrastructure exists. What agents do with it is the open question.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The WAIaaS Admin UI at &lt;code&gt;/admin&lt;/code&gt; gives you a real-time view of your agent's positions, transaction history, and policy status without touching the API. For production deployments, the Docker setup with secrets overlay handles credential management properly — worth reading before you go live with real funds.&lt;/p&gt;

&lt;p&gt;Explore the codebase and full documentation on GitHub at &lt;a href="https://github.com/waiaas/WAIaaS" rel="noopener noreferrer"&gt;https://github.com/waiaas/WAIaaS&lt;/a&gt;, or visit &lt;a href="https://waiaas.ai" rel="noopener noreferrer"&gt;https://waiaas.ai&lt;/a&gt; for the official site. The OpenAPI spec and interactive API reference are available at &lt;code&gt;/doc&lt;/code&gt; and &lt;code&gt;/reference&lt;/code&gt; once your daemon is running — start there to understand the full surface area before building your agent.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>defi</category>
      <category>web3</category>
      <category>trading</category>
    </item>
    <item>
      <title>Instant Cross-Chain Arbitrage: Across Protocol Integration for Trading Bots</title>
      <dc:creator>Wallet Guy</dc:creator>
      <pubDate>Tue, 21 Jul 2026 15:14:05 +0000</pubDate>
      <link>https://dev.to/walletguy/instant-cross-chain-arbitrage-across-protocol-integration-for-trading-bots-2ph5</link>
      <guid>https://dev.to/walletguy/instant-cross-chain-arbitrage-across-protocol-integration-for-trading-bots-2ph5</guid>
      <description>&lt;h1&gt;
  
  
  Instant Cross-Chain Arbitrage: Across Protocol Integration for Trading Bots
&lt;/h1&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Infrastructure Is the Bottleneck
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Available for Trading Bots
&lt;/h2&gt;

&lt;p&gt;WAIaaS integrates 15 DeFi protocol providers out of the box:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cross-chain bridging&lt;/strong&gt;: Across and LI.FI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spot and perp trading&lt;/strong&gt;: Jupiter Swap (Solana), Drift (Solana perps), Hyperliquid (perps + spot), 0x Swap, D'CENT Swap&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lending/yield&lt;/strong&gt;: Aave v3, Kamino, Pendle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Staking&lt;/strong&gt;: Lido (EVM), Jito (Solana)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prediction markets&lt;/strong&gt;: Polymarket&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;XRPL DEX&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent reputation&lt;/strong&gt;: ERC-8004&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a cross-chain arb bot, the critical trio is: &lt;strong&gt;Jupiter Swap&lt;/strong&gt; for Solana-side execution, &lt;strong&gt;Across&lt;/strong&gt; for bridging capital between chains, and &lt;strong&gt;Drift&lt;/strong&gt; or &lt;strong&gt;Hyperliquid&lt;/strong&gt; for hedging exposure while the bridge settles.&lt;/p&gt;

&lt;p&gt;The system runs across 18 networks (EVM + Solana) and supports 7 transaction types: Transfer, TokenTransfer, ContractCall, Approve, Batch, NftTransfer, and ContractDeploy.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 7-Stage Transaction Pipeline
&lt;/h2&gt;

&lt;p&gt;Before diving into code, understand what happens when your bot submits a trade. WAIaaS runs every transaction through a 7-stage pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Validate&lt;/strong&gt; — schema and parameter checks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auth&lt;/strong&gt; — session token verification&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policy&lt;/strong&gt; — 21 policy types evaluated against the transaction&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wait&lt;/strong&gt; — gas condition checks, time delays if policy requires&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execute&lt;/strong&gt; — broadcast to chain&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confirm&lt;/strong&gt; — wait for on-chain confirmation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up a Trading Wallet
&lt;/h2&gt;

&lt;p&gt;Start the daemon and create a dedicated wallet for your arb bot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install CLI and start daemon&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @waiaas/cli
waiaas init
waiaas start

&lt;span class="c"&gt;# Or with Docker&lt;/span&gt;
docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create the wallet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/wallets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "arb-bot-eth", "chain": "evm", "environment": "mainnet"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a session token your bot will use for all trading operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/sessions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"walletId": "&amp;lt;wallet-uuid&amp;gt;"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store the returned session token as &lt;code&gt;WAIAAS_SESSION_TOKEN&lt;/code&gt;. Every trade your bot makes will authenticate with this token. No private key exposure, no nonce management in your bot code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Policy Configuration for Trading Bots
&lt;/h2&gt;

&lt;p&gt;This is the part most bot builders skip — and regret. Configure spending controls before your bot goes live.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Daily limit with tiered approval thresholds&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "walletId": "&amp;lt;wallet-uuid&amp;gt;",
    "type": "SPENDING_LIMIT",
    "rules": {
      "instant_max_usd": 100,
      "notify_max_usd": 500,
      "delay_max_usd": 2000,
      "delay_seconds": 900,
      "daily_limit_usd": 5000
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The 4-tier system maps directly to trading risk management:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;INSTANT&lt;/strong&gt; (≤ $100): Small arb trades execute immediately — no latency added&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NOTIFY&lt;/strong&gt; (≤ $500): Executes immediately, but you get notified — good for monitoring&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DELAY&lt;/strong&gt; (≤ $2,000): Queued for 15 minutes, cancellable if market moves against you&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;APPROVAL&lt;/strong&gt; (&amp;gt; $2,000): Requires human sign-off via WalletConnect or Telegram&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a bot trading smaller sizes at high frequency, set &lt;code&gt;instant_max_usd&lt;/code&gt; to your max position size and let the engine handle the rest.&lt;/p&gt;

&lt;p&gt;You should also whitelist the specific contracts your bot interacts with. The policy engine uses &lt;strong&gt;default-deny&lt;/strong&gt; for contract calls — if &lt;code&gt;CONTRACT_WHITELIST&lt;/code&gt; is configured, any contract not on the list is blocked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "walletId": "&amp;lt;wallet-uuid&amp;gt;",
    "type": "CONTRACT_WHITELIST",
    "rules": {
      "contracts": [
        {"address": "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4", "name": "Jupiter v6", "chain": "solana"},
        {"address": "&amp;lt;across-spoke-pool-address&amp;gt;", "name": "Across SpokePool", "chain": "ethereum-mainnet"}
      ]
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For perpetual trading on Drift or Hyperliquid, add leverage limits to prevent your bot from over-leveraging in volatile conditions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Max 5x leverage on perps&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "walletId": "&amp;lt;wallet-uuid&amp;gt;",
    "type": "PERP_MAX_LEVERAGE",
    "rules": {"maxLeverage": 5}
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All 21 policy types are available — PERP_MAX_POSITION_USD, PERP_ALLOWED_MARKETS, RATE_LIMIT, and VENUE_WHITELIST are all relevant for systematic trading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Executing the Arb: Swap → Bridge → Hedge
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Leg 1: Swap USDC → SOL on Jupiter&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/actions/jupiter-swap/swap &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_&amp;lt;token&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "inputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "outputMint": "So11111111111111111111111111111111111111112",
    "amount": "1000000000"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Leg 2: Bridge USDC to Ethereum via Across&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Across provider handles the cross-chain bridge. Your bot submits to the &lt;code&gt;/v1/actions/across/&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Leg 3: Simulate before committing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before any large trade fires, use dry-run to validate execution without spending gas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/transactions/send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_&amp;lt;token&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "type": "TRANSFER",
    "to": "recipient-address",
    "amount": "0.1",
    "dryRun": true
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"POLICY_DENIED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Transaction denied by SPENDING_LIMIT policy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"POLICY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"retryable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;retryable: false&lt;/code&gt; means don't retry. &lt;code&gt;retryable: true&lt;/code&gt; means transient failure — safe to retry with backoff. Your bot's error handler can branch on &lt;code&gt;error.code&lt;/code&gt; directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  TypeScript Bot Integration
&lt;/h2&gt;

&lt;p&gt;Use the TypeScript SDK for cleaner bot code with full type safety:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSError&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@waiaas/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WAIaaSClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WAIAAS_BASE_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3100&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WAIAAS_SESSION_TOKEN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;executeArbLeg&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Check balance before trading&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBalance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Balance: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Submit trade&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sendResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendToken&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TRANSFER&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;recipient-address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.001&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Transaction submitted: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;sendResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (status: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;sendResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Poll for confirmation&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;POLL_TIMEOUT_MS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;POLL_TIMEOUT_MS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sendResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;COMPLETED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Transaction confirmed! Hash: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;txHash&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FAILED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Transaction failed: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Handle policy denials and other errors&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;executeArbLeg&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`API Error: [&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;] &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// error.code: INSUFFICIENT_BALANCE, POLICY_DENIED, TOKEN_EXPIRED&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The SDK has zero external dependencies. Methods you'll use constantly: &lt;code&gt;getBalance()&lt;/code&gt;, &lt;code&gt;getAssets()&lt;/code&gt;, &lt;code&gt;sendToken()&lt;/code&gt;, &lt;code&gt;getTransaction()&lt;/code&gt;, &lt;code&gt;listTransactions()&lt;/code&gt;, &lt;code&gt;signTransaction()&lt;/code&gt;. The full TypeScript SDK ships as &lt;code&gt;@waiaas/sdk&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gas Conditional Execution
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;For arb bots, this is valuable in two scenarios:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Rebalancing operations&lt;/strong&gt; — moving capital between wallets or chains is not time-sensitive. Let gas conditions decide when it executes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-leg setups with tolerance&lt;/strong&gt; — 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.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring DeFi Positions
&lt;/h2&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://127.0.0.1:3100/v1/wallet/defi-positions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_&amp;lt;token&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting Claude or Other AI Agents to Your Bot Infrastructure
&lt;/h2&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;waiaas mcp setup &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This auto-registers all wallets with Claude Desktop. The MCP tool list includes &lt;code&gt;hyperliquid&lt;/code&gt;, &lt;code&gt;polymarket&lt;/code&gt;, &lt;code&gt;get-defi-positions&lt;/code&gt;, &lt;code&gt;simulate-transaction&lt;/code&gt;, &lt;code&gt;send-batch&lt;/code&gt;, and &lt;code&gt;x402-fetch&lt;/code&gt; — the full surface area of the wallet API exposed as structured tools the LLM can call.&lt;/p&gt;

&lt;p&gt;For multi-strategy setups, run separate MCP server instances per wallet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"waiaas-trading"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@waiaas/mcp"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"WAIAAS_BASE_URL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://127.0.0.1:3100"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"WAIAAS_AGENT_ID"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"019c47d6-51ef-7f43-a76b-d50e875d95f4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"WAIAAS_AGENT_NAME"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"trading-agent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"WAIAAS_DATA_DIR"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~/.waiaas"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Quickstart: Bot Infrastructure in 5 Steps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install and start&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @waiaas/cli
   waiaas init
   waiaas quickset &lt;span class="nt"&gt;--mode&lt;/span&gt; mainnet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create a trading wallet&lt;/strong&gt; — POST to &lt;code&gt;/v1/wallets&lt;/code&gt; with &lt;code&gt;chain: "evm"&lt;/code&gt; or &lt;code&gt;chain: "solana"&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configure policies&lt;/strong&gt; — SPENDING_LIMIT + CONTRACT_WHITELIST at minimum before going live&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Install the SDK&lt;/strong&gt; — &lt;code&gt;npm install @waiaas/sdk&lt;/code&gt;, initialize with your session token&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dry-run every leg&lt;/strong&gt; — set &lt;code&gt;dryRun: true&lt;/code&gt; in your transaction payload, validate the response, then submit for real&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The interactive API reference at &lt;code&gt;http://127.0.0.1:3100/reference&lt;/code&gt; (Scalar UI) documents all 39 route modules. The OpenAPI 3.0 spec is downloadable at &lt;code&gt;/doc&lt;/code&gt; for generating client code in any language. A Python SDK (&lt;code&gt;pip install waiaas&lt;/code&gt;) is also available with full async/await support.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;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&lt;/p&gt;

</description>
      <category>defi</category>
      <category>ethereum</category>
      <category>solana</category>
      <category>trading</category>
    </item>
    <item>
      <title>The Future of API Bills: When Machines Pay Machines with x402 Protocol</title>
      <dc:creator>Wallet Guy</dc:creator>
      <pubDate>Tue, 21 Jul 2026 09:05:36 +0000</pubDate>
      <link>https://dev.to/walletguy/the-future-of-api-bills-when-machines-pay-machines-with-x402-protocol-282e</link>
      <guid>https://dev.to/walletguy/the-future-of-api-bills-when-machines-pay-machines-with-x402-protocol-282e</guid>
      <description>&lt;h1&gt;
  
  
  The Future of API Bills: When Machines Pay Machines with x402 Protocol
&lt;/h1&gt;

&lt;p&gt;AI agents will need to pay for compute, data, and API calls — and right now, the infrastructure to let them do that autonomously barely exists. Most agents today either rely on humans to top up a credit card, or they're locked inside a platform's billing system with no ability to operate independently. That's a fundamental mismatch between what agents need to do and what they're actually capable of doing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters More Than It Sounds
&lt;/h2&gt;

&lt;p&gt;Think about what an autonomous AI agent actually does all day. It calls APIs. It fetches data. It runs inference. It queries databases. Every one of those actions has a cost, and today, a human is almost always the one footing the bill — manually, via a shared API key, or through some corporate account the agent doesn't actually control.&lt;/p&gt;

&lt;p&gt;This works fine when agents are simple tools. But as agents become more autonomous — running multi-step workflows, operating overnight, spawning sub-agents, coordinating with other systems — the billing model breaks down. You can't have a human approve every $0.003 API call at 2am. You need the agent to handle it.&lt;/p&gt;

&lt;p&gt;The x402 protocol is one of the clearest answers to this problem that exists today. And WAIaaS ships it as a first-class feature, built into the wallet infrastructure your agents already use.&lt;/p&gt;

&lt;h2&gt;
  
  
  What x402 Actually Is
&lt;/h2&gt;

&lt;p&gt;x402 is an HTTP payment protocol. The idea is simple but powerful: when a server needs payment before serving a response, it returns an HTTP 402 status code ("Payment Required") with machine-readable payment details. The client — in this case, your AI agent — reads those details, makes the payment automatically, and retries the request. The whole thing happens in milliseconds, with no human in the loop.&lt;/p&gt;

&lt;p&gt;This isn't speculative. The HTTP 402 status code has existed since 1991, reserved for exactly this purpose. x402 finally gives it a practical implementation for the blockchain era.&lt;/p&gt;

&lt;p&gt;What it looks like from the outside: your agent calls an API, the API says "pay me first," your agent pays, the API responds. One transaction, zero friction, zero human involvement.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Wallet Problem
&lt;/h2&gt;

&lt;p&gt;Here's the catch: for x402 to work, your agent needs a wallet. Not a wallet managed by a human who logs in to approve things — a wallet the agent can operate autonomously, within defined limits you set in advance.&lt;/p&gt;

&lt;p&gt;This is where most attempts fall apart. Either the wallet is too custodied (a human has to approve every payment) or too open (the agent has unconstrained access to funds). Neither works for production autonomous agents.&lt;/p&gt;

&lt;p&gt;WAIaaS is designed to solve exactly this. It's an open-source, self-hosted Wallet-as-a-Service built for AI agents. The agent gets a session token that gives it access to a wallet. You, as the owner, set policies in advance that define what the agent can and can't do. The agent operates within those boundaries autonomously.&lt;/p&gt;

&lt;h2&gt;
  
  
  x402 Support in WAIaaS
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;x402Fetch&lt;/code&gt; capability is built directly into the WAIaaS SDK. It wraps a standard HTTP fetch call with automatic 402 payment handling. Your agent code doesn't need to know anything about the payment mechanics — it just calls &lt;code&gt;x402Fetch&lt;/code&gt; instead of &lt;code&gt;fetch&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's what that looks like in TypeScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@waiaas/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WAIaaSClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://127.0.0.1:3100&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WAIAAS_SESSION_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// This call automatically handles 402 Payment Required responses&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;x402Fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.some-paid-service.com/data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the API returns 402, the SDK reads the payment requirements, the agent's wallet makes the payment, and the request retries — all transparently. Your agent code is the same whether the API charges or not.&lt;/p&gt;

&lt;p&gt;The MCP integration exposes this as the &lt;code&gt;x402-fetch&lt;/code&gt; tool, one of the 45 MCP tools available to AI agents connected through the Model Context Protocol. That means an agent running in Claude Desktop can make paid API calls without any custom code — the tool handles everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Policy Guardrails: How You Stay in Control
&lt;/h2&gt;

&lt;p&gt;Giving an agent a wallet doesn't mean giving it unlimited access. WAIaaS has a policy engine with 21 policy types and 4 security tiers — and for x402 specifically, there's a dedicated policy type: &lt;code&gt;X402_ALLOWED_DOMAINS&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is a domain whitelist. You specify which domains the agent is allowed to make automatic payments to. Anything not on the list gets blocked. Combined with &lt;code&gt;SPENDING_LIMIT&lt;/code&gt; policies, you can define exactly how much the agent can spend per transaction, per day, and per month — without touching a line of agent code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "walletId": "&amp;lt;wallet-uuid&amp;gt;",
    "type": "X402_ALLOWED_DOMAINS",
    "rules": {
      "domains": ["api.example.com", "*.openai.com"]
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And alongside that, a spending limit to cap what the agent can spend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "walletId": "&amp;lt;wallet-uuid&amp;gt;",
    "type": "SPENDING_LIMIT",
    "rules": {
      "instant_max_usd": 100,
      "notify_max_usd": 500,
      "delay_max_usd": 2000,
      "delay_seconds": 900,
      "daily_limit_usd": 5000
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The four security tiers work like this: transactions below &lt;code&gt;instant_max_usd&lt;/code&gt; execute immediately with no notification. Below &lt;code&gt;notify_max_usd&lt;/code&gt;, they execute but you get a notification. Below &lt;code&gt;delay_max_usd&lt;/code&gt;, they're queued for &lt;code&gt;delay_seconds&lt;/code&gt; before executing — giving you a cancellation window. Above that threshold, they require explicit human approval via WalletConnect or Telegram.&lt;/p&gt;

&lt;p&gt;For x402 micropayments — the $0.001 to $0.10 range where most API calls live — the INSTANT tier means the agent pays without any friction. For larger unusual payments, the system escalates automatically.&lt;/p&gt;

&lt;p&gt;Policies follow a default-deny model: if &lt;code&gt;ALLOWED_TOKENS&lt;/code&gt; or &lt;code&gt;CONTRACT_WHITELIST&lt;/code&gt; policies aren't configured, transactions are blocked. This means you can't accidentally leave an agent with unconstrained spending — you have to explicitly grant permissions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 7-Stage Pipeline Behind Every Payment
&lt;/h2&gt;

&lt;p&gt;Every transaction an agent makes — including x402 payments — goes through a 7-stage pipeline: validate, auth, policy, wait, execute, confirm, and stage management. This isn't just for safety theater. It means every payment has an audit trail, every policy check is logged, and the agent can't bypass the rules even if it tries.&lt;/p&gt;

&lt;p&gt;The dry-run API lets you simulate any transaction before it executes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/transactions/send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_&amp;lt;token&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "type": "TRANSFER",
    "to": "recipient-address",
    "amount": "0.1",
    "dryRun": true
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful during development — you can verify that your policy configuration works the way you expect before deploying with real funds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up an Agent Wallet in Under 5 Minutes
&lt;/h2&gt;

&lt;p&gt;Here's the minimal path from zero to a wallet-equipped agent that can make x402 payments:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Install and start WAIaaS&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @waiaas/cli
waiaas init
waiaas start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Create a wallet and session&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/wallets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "agent-wallet", "chain": "solana", "environment": "mainnet"}'&lt;/span&gt;

curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/sessions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"walletId": "&amp;lt;wallet-uuid&amp;gt;"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The session response includes a &lt;code&gt;wai_sess_...&lt;/code&gt; token. That's what your agent uses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Set x402 policy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create an &lt;code&gt;X402_ALLOWED_DOMAINS&lt;/code&gt; policy and a &lt;code&gt;SPENDING_LIMIT&lt;/code&gt; policy as shown above. The agent can only make x402 payments to domains you've whitelisted, within the spending limits you've set.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Connect to Claude via MCP (optional)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;waiaas mcp setup &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This auto-registers your wallet with Claude Desktop. The &lt;code&gt;x402-fetch&lt;/code&gt; tool becomes available immediately — Claude can make paid API calls on your behalf without any additional configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5: Fund the wallet and run your agent&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Send funds to the wallet address (get it with &lt;code&gt;waiaas wallet info&lt;/code&gt;), then run your agent with the session token in the environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;WAIAAS_SESSION_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;wai_sess_... node my-agent.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Bigger Picture: Machine-to-Machine Economies
&lt;/h2&gt;

&lt;p&gt;x402 is compelling on its own, but it becomes genuinely interesting when you think about where it leads. Right now, APIs are sold to developers. Developers pay monthly fees, manage API keys, handle billing — all human-in-the-loop activity.&lt;/p&gt;

&lt;p&gt;x402 shifts this model. APIs can be sold to agents. An agent can discover a data source, evaluate its pricing, pay for access, and use the data — all without human involvement. The billing granularity drops from monthly subscriptions to per-request micropayments. The relationship isn't developer-to-vendor anymore, it's agent-to-service.&lt;/p&gt;

&lt;p&gt;WAIaaS supports this with 18 networks across Solana and EVM chains (fact NET-01). An agent operating on Solana can make x402 payments in SOL or USDC. An agent on Ethereum or a Layer 2 can do the same in ETH or stablecoins. The wallet infrastructure handles the chain-specific details — your agent code doesn't need to know.&lt;/p&gt;

&lt;p&gt;The 3-layer security model (session auth → time delay + approval → monitoring + kill switch) means this isn't a system you deploy and lose control of. You can monitor what your agent is spending, set kill switches, and recover access through owner authentication (SIWS/SIWE signature). The agent operates autonomously within the boundaries you set — not because you trust it blindly, but because you've defined exactly what "within bounds" means.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Looks Like at Scale
&lt;/h2&gt;

&lt;p&gt;Imagine a research agent that needs to pull data from a dozen different sources during a multi-hour analysis run. Some sources are free. Some charge per query. Some have tiered pricing. Today, you either pre-purchase access to all of them (wasteful) or the agent has to stop and wait for human approval (slow).&lt;/p&gt;

&lt;p&gt;With x402 and WAIaaS, the agent queries each source. Free sources respond normally. Paid sources return 402. The wallet pays automatically, within your pre-configured domain whitelist and spending limits. The analysis runs uninterrupted. You get a notification log of what was spent. If anything looks wrong, the policy engine already blocked it.&lt;/p&gt;

&lt;p&gt;This is infrastructure for agents that do real work in the real economy. Not a demo, not a proof of concept — it runs today, on the chains that matter, with the security guarantees you need to actually trust an autonomous system with funds.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The x402 protocol support in WAIaaS is one piece of a larger picture around autonomous agent infrastructure — if you want to understand how the policy engine works in depth or how DeFi actions fit into an agent's capabilities, the &lt;a href="https://github.com/waiaas/WAIaaS" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; has the full source and documentation. The &lt;a href="http://127.0.0.1:3100/reference" rel="noopener noreferrer"&gt;OpenAPI reference at &lt;code&gt;/reference&lt;/code&gt;&lt;/a&gt; is also worth exploring once you have the daemon running — it's interactive and covers all 39 API route modules.&lt;/p&gt;

&lt;p&gt;If you're building agents that need to participate in the economy rather than just simulate it, the place to start is the official site at &lt;a href="https://waiaas.ai" rel="noopener noreferrer"&gt;https://waiaas.ai&lt;/a&gt; and the repository at &lt;a href="https://github.com/waiaas/WAIaaS" rel="noopener noreferrer"&gt;https://github.com/waiaas/WAIaaS&lt;/a&gt;. Both are live, both reflect real working software, and the setup genuinely does take under five minutes.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>web3</category>
      <category>api</category>
      <category>opensource</category>
    </item>
    <item>
      <title>APPROVE_TIER_OVERRIDE: Emergency Controls for High-Stakes DeFi Operations</title>
      <dc:creator>Wallet Guy</dc:creator>
      <pubDate>Mon, 20 Jul 2026 15:19:59 +0000</pubDate>
      <link>https://dev.to/walletguy/approvetieroverride-emergency-controls-for-high-stakes-defi-operations-16l8</link>
      <guid>https://dev.to/walletguy/approvetieroverride-emergency-controls-for-high-stakes-defi-operations-16l8</guid>
      <description>&lt;h1&gt;
  
  
  APPROVE_TIER_OVERRIDE: Emergency Controls for High-Stakes DeFi Operations
&lt;/h1&gt;

&lt;p&gt;Giving an AI agent a wallet without guardrails is like giving a toddler a credit card — the intentions might be fine, but the outcomes can be catastrophic. If you're building systems where AI agents execute DeFi operations autonomously, the question isn't whether something will go wrong, it's whether your security architecture will contain the damage when it does. WAIaaS is an open-source, self-hosted Wallet-as-a-Service built specifically for this problem, and this post walks through exactly how its layered security model — and specifically the &lt;code&gt;APPROVE_TIER_OVERRIDE&lt;/code&gt; policy — keeps high-stakes DeFi operations under human control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters More Than You Think
&lt;/h2&gt;

&lt;p&gt;Autonomous AI agents executing DeFi trades, managing lending positions, or running arbitrage strategies represent a genuinely new threat surface. The agent doesn't get tired, doesn't second-guess itself, and won't pause before submitting a transaction that wipes out a position. Traditional wallet security was designed for humans who read confirmations. It was not designed for a loop that fires 200 transactions per hour.&lt;/p&gt;

&lt;p&gt;The stakes compound quickly. A misconfigured leverage position, a swap against a manipulated price feed, an approval transaction that grants unlimited spend to a malicious contract — any of these can drain a wallet in seconds. If your security model is "we trust the agent's logic," you're one bug away from a very bad day.&lt;/p&gt;

&lt;p&gt;The honest answer to this problem is layered, explicit security that does not trust the agent by default. That's the design philosophy behind WAIaaS.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 3-Layer Security Model
&lt;/h2&gt;

&lt;p&gt;WAIaaS structures security as three concentric layers, each independent of the others:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 1 — Session Authentication:&lt;/strong&gt; Every agent gets a session token (&lt;code&gt;wai_sess_...&lt;/code&gt;) with configurable TTL, maximum renewals, and an absolute lifetime. The agent can only operate within its session scope.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 2 — Policy Engine:&lt;/strong&gt; A 21-type policy engine with default-deny enforcement. Transactions are blocked unless explicitly allowed. This is where &lt;code&gt;APPROVE_TIER_OVERRIDE&lt;/code&gt; lives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 3 — Monitoring and Kill Switch:&lt;/strong&gt; Incoming transaction monitoring with real-time notifications and owner-controlled approval channels via WalletConnect, Telegram, or push relay.&lt;/p&gt;

&lt;p&gt;Three separate authentication methods map to three roles: &lt;code&gt;masterAuth&lt;/code&gt; (Argon2id) for the system administrator who creates wallets and configures policies, &lt;code&gt;sessionAuth&lt;/code&gt; (JWT HS256) for the AI agent, and &lt;code&gt;ownerAuth&lt;/code&gt; (SIWS/SIWE signatures) for the fund owner who approves transactions. The agent never holds the master password. The owner's approval is cryptographic, not just a button click.&lt;/p&gt;

&lt;h2&gt;
  
  
  Default-Deny: The Foundation
&lt;/h2&gt;

&lt;p&gt;Before getting into &lt;code&gt;APPROVE_TIER_OVERRIDE&lt;/code&gt; specifically, you need to understand the default-deny posture. In WAIaaS, if you create a wallet and give an agent a session token without configuring policies, the agent cannot transfer tokens that aren't on an explicit whitelist, and cannot call contracts that aren't on an explicit whitelist.&lt;/p&gt;

&lt;p&gt;This is not a "warn on suspicious activity" model. It's a hard block. The error response is unambiguous:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"POLICY_DENIED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Transaction denied by SPENDING_LIMIT policy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"POLICY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"retryable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To allow token transfers, you configure an &lt;code&gt;ALLOWED_TOKENS&lt;/code&gt; policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Master-Password: &amp;lt;password&amp;gt;'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "walletId": "&amp;lt;wallet-uuid&amp;gt;",
    "type": "ALLOWED_TOKENS",
    "rules": {
      "tokens": [
        {
          "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
          "symbol": "USDC",
          "chain": "solana"
        }
      ]
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your agent can't touch tokens you haven't explicitly allowed. That's the foundation everything else builds on.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 4 Security Tiers
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;SPENDING_LIMIT&lt;/code&gt; policy assigns every transaction to one of four tiers based on its USD value:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;INSTANT&lt;/strong&gt; — Execute immediately, no notification&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NOTIFY&lt;/strong&gt; — Execute immediately, notify the owner&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DELAY&lt;/strong&gt; — Queue the transaction for a configurable number of seconds, then execute (cancellable during the window)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;APPROVAL&lt;/strong&gt; — Require explicit human approval before execution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's what a realistic &lt;code&gt;SPENDING_LIMIT&lt;/code&gt; configuration looks like for a DeFi trading agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "walletId": "&amp;lt;wallet-uuid&amp;gt;",
    "type": "SPENDING_LIMIT",
    "rules": {
      "instant_max_usd": 100,
      "notify_max_usd": 500,
      "delay_max_usd": 2000,
      "delay_seconds": 900,
      "daily_limit_usd": 5000
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this configuration: swaps under $100 execute immediately, swaps between $100–$500 execute but you get notified, swaps between $500–$2,000 are queued for 15 minutes (giving you a window to cancel), and anything above $2,000 requires your explicit approval. The daily limit caps total exposure regardless of individual transaction size.&lt;/p&gt;

&lt;p&gt;The tier assignment is deterministic: &lt;code&gt;amount &amp;lt;= instant_max&lt;/code&gt; → INSTANT, &lt;code&gt;&amp;lt;= notify_max&lt;/code&gt; → NOTIFY, &lt;code&gt;&amp;lt;= delay_max&lt;/code&gt; → DELAY, &lt;code&gt;&amp;gt; delay_max&lt;/code&gt; → APPROVAL.&lt;/p&gt;

&lt;h2&gt;
  
  
  APPROVE_TIER_OVERRIDE: Why It Exists
&lt;/h2&gt;

&lt;p&gt;Here's the problem &lt;code&gt;APPROVE_TIER_OVERRIDE&lt;/code&gt; solves. Your &lt;code&gt;SPENDING_LIMIT&lt;/code&gt; policy handles regular transfers based on their USD value. But &lt;code&gt;APPROVE&lt;/code&gt; transactions — token approvals — don't transfer funds. They grant a smart contract permission to transfer funds later, potentially without limit.&lt;/p&gt;

&lt;p&gt;A $0 approval transaction could grant an unlimited spend allowance to a DEX router. Under a pure spending-limit model, that $0 transaction sails through as INSTANT because it moves no funds. But the downstream risk is enormous.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;APPROVE_TIER_OVERRIDE&lt;/code&gt; forces token approval transactions into a specific security tier regardless of their dollar value. You can force every approval operation to require human sign-off, every time, no matter how small the nominal value appears to the spending limit check.&lt;/p&gt;

&lt;p&gt;This is the right model for high-stakes DeFi operations. You want your agent to execute swaps autonomously within limits — that's the whole point — but you want to personally review every new approval that grants a contract access to your tokens.&lt;/p&gt;

&lt;p&gt;The complementary policy &lt;code&gt;APPROVE_AMOUNT_LIMIT&lt;/code&gt; lets you block unlimited approvals entirely, ensuring your agent only grants bounded allowances even when approvals are permitted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simulate Before You Execute
&lt;/h2&gt;

&lt;p&gt;Before any transaction reaches the policy engine in production, you can run it through the simulation API. The &lt;code&gt;dryRun&lt;/code&gt; flag submits the full transaction payload through the 7-stage pipeline — validation, auth, policy check, gas condition evaluation — without broadcasting to the network:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/transactions/send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_&amp;lt;token&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "type": "TRANSFER",
    "to": "recipient-address",
    "amount": "0.1",
    "dryRun": true
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is particularly useful when you're configuring policies for a new DeFi strategy. Run representative transactions through dry-run first to verify they land in the tier you expect before your agent starts operating in production. A transaction you thought would be NOTIFY hitting APPROVAL in production because you miscalculated the USD value is an annoying surprise. Catching it in dry-run is just good engineering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Human Approval Channels
&lt;/h2&gt;

&lt;p&gt;When a transaction requires APPROVAL tier, the owner receives a notification and must cryptographically approve it. The approval uses ownerAuth — the owner signs a message with their private key (ed25519 for Solana, secp256k1 for EVM):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/transactions/&amp;lt;tx-id&amp;gt;/approve &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Owner-Signature: &amp;lt;ed25519-or-secp256k1-signature&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Owner-Message: &amp;lt;signed-message&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;WAIaaS supports three signing channels for delivering these approval requests: push relay, Telegram, and WalletConnect. The WalletConnect integration means the owner can approve transactions from any WalletConnect-compatible wallet app — a familiar interface for anyone in the DeFi space.&lt;/p&gt;

&lt;p&gt;For DeFi operations that involve high-value positions, perpetual futures, or new contract interactions, the approval channel gives you a hard checkpoint that can't be bypassed by agent logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Policies Purpose-Built for DeFi
&lt;/h2&gt;

&lt;p&gt;Beyond the general-purpose policies, WAIaaS includes several policy types designed specifically for DeFi risk management:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;LENDING_LTV_LIMIT&lt;/code&gt;&lt;/strong&gt; — Caps the loan-to-value ratio for lending positions. Your agent cannot open a position that would put your collateral at immediate liquidation risk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;LENDING_ASSET_WHITELIST&lt;/code&gt;&lt;/strong&gt; — Restricts which assets the agent can use as collateral or borrow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;PERP_MAX_LEVERAGE&lt;/code&gt;&lt;/strong&gt; — Hard cap on perpetual futures leverage. If you've integrated Hyperliquid for perp trading, this prevents the agent from opening positions at 50x when you intended 5x.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;PERP_MAX_POSITION_USD&lt;/code&gt;&lt;/strong&gt; — Maximum single position size in USD.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;PERP_ALLOWED_MARKETS&lt;/code&gt;&lt;/strong&gt; — Whitelist of permitted perpetual markets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;VENUE_WHITELIST&lt;/code&gt;&lt;/strong&gt; — Restricts which trading venues the agent can interact with.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ACTION_CATEGORY_LIMIT&lt;/code&gt;&lt;/strong&gt; — Caps DeFi action categories (lending, staking, swapping) independently.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't bolt-ons. They're part of the same policy engine that handles spending limits and token whitelists, applied through the same default-deny framework, enforced in the same transaction pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Standing Up the Full Stack
&lt;/h2&gt;

&lt;p&gt;The fastest path from zero to a secured DeFi agent runs through the CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @waiaas/cli
waiaas init                        &lt;span class="c"&gt;# Create data directory + config.toml&lt;/span&gt;
waiaas start                       &lt;span class="c"&gt;# Start daemon (sets master password on first run)&lt;/span&gt;
waiaas quickset &lt;span class="nt"&gt;--mode&lt;/span&gt; mainnet     &lt;span class="c"&gt;# Create wallets + MCP sessions in one step&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if you prefer Docker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/waiaas/WAIaaS.git
&lt;span class="nb"&gt;cd &lt;/span&gt;WAIaaS
docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Docker image runs as a non-root user (UID 1001), exposes only &lt;code&gt;127.0.0.1:3100&lt;/code&gt; by default, and supports Docker Secrets for production secret management. For production deployments, use the secrets overlay:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; secrets
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"your-secure-password"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; secrets/master_password.txt
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 secrets/master_password.txt
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.secrets.yml up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the daemon is running, create a wallet, attach policies, generate a session token for your agent, and test your policy configuration with dry-run before going live. The OpenAPI 3.0 spec is available at &lt;code&gt;http://127.0.0.1:3100/doc&lt;/code&gt; and the interactive Scalar reference UI at &lt;code&gt;http://127.0.0.1:3100/reference&lt;/code&gt; — useful for exploring the full policy configuration options.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the TypeScript SDK in Your Agent
&lt;/h2&gt;

&lt;p&gt;If you're building the agent itself rather than just the infrastructure, the TypeScript SDK gives you typed access to the full API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSError&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@waiaas/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WAIaaSClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WAIAAS_BASE_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3100&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WAIAAS_SESSION_TOKEN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendToken&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TRANSFER&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;recipient-address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.001&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Transaction submitted: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (status: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`API Error: [&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;] &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// POLICY_DENIED surfaces here — handle gracefully, not with a retry loop&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The SDK is zero external dependencies. A &lt;code&gt;POLICY_DENIED&lt;/code&gt; error with &lt;code&gt;retryable: false&lt;/code&gt; means exactly that — the policy blocked it and retrying won't help. Your agent should surface that to a monitoring system or log it, not hammer the API hoping the policy changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Security Architecture in One Mental Model
&lt;/h2&gt;

&lt;p&gt;If you want a single frame for how this all fits together: WAIaaS assumes the agent will eventually do something wrong — a bug, a bad inference, a manipulated input — and builds the security architecture around containing that failure rather than preventing it through correctness.&lt;/p&gt;

&lt;p&gt;The session token limits the blast radius to a single wallet with a configured scope. The policy engine's default-deny posture means misconfigured agent permissions fail closed rather than open. The spending limit tiers route high-value operations through human review. &lt;code&gt;APPROVE_TIER_OVERRIDE&lt;/code&gt; ensures approval transactions never slip through on a technicality. The 15-minute delay window gives you time to intervene before a queued transaction executes.&lt;/p&gt;

&lt;p&gt;None of these layers individually make your agent secure. Together, they mean a compromised or buggy agent has a very hard time causing catastrophic damage.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The full policy reference, including all 21 policy types and their configuration schemas, is available in the interactive API docs at &lt;code&gt;http://127.0.0.1:3100/reference&lt;/code&gt; once your daemon is running. For MCP-based agent integration with Claude Desktop, the &lt;code&gt;waiaas mcp setup --all&lt;/code&gt; command handles the configuration automatically — your agent gets access to 45 MCP tools including DeFi positions, transaction simulation, and approval workflows without writing integration code.&lt;/p&gt;

&lt;p&gt;The codebase is open source and self-hosted — you run it, you control the keys, and the policy engine is yours to inspect and extend.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/waiaas/WAIaaS" rel="noopener noreferrer"&gt;https://github.com/waiaas/WAIaaS&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Official site: &lt;a href="https://waiaas.ai" rel="noopener noreferrer"&gt;https://waiaas.ai&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>defi</category>
      <category>web3</category>
      <category>api</category>
    </item>
    <item>
      <title>Localhost-Only Security: Why Self-Hosted AI Wallets Should Never Bind to 0.0.0.0</title>
      <dc:creator>Wallet Guy</dc:creator>
      <pubDate>Mon, 20 Jul 2026 09:39:16 +0000</pubDate>
      <link>https://dev.to/walletguy/localhost-only-security-why-self-hosted-ai-wallets-should-never-bind-to-0000-1h2l</link>
      <guid>https://dev.to/walletguy/localhost-only-security-why-self-hosted-ai-wallets-should-never-bind-to-0000-1h2l</guid>
      <description>&lt;h1&gt;
  
  
  Localhost-Only Security: Why Self-Hosted AI Wallets Should Never Bind to 0.0.0.0
&lt;/h1&gt;

&lt;p&gt;Self-hosted AI wallets give you complete control over your keys and infrastructure — but that control means nothing if your wallet daemon is accidentally exposed to the world. If you're running an AI agent that holds real funds, the network binding of your wallet service is the first line of defense, and getting it wrong is the kind of mistake you only make once.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem With "Just Open It Up"
&lt;/h2&gt;

&lt;p&gt;When developers spin up a new service, there's a tempting shortcut: bind to &lt;code&gt;0.0.0.0&lt;/code&gt; so it's reachable from anywhere. For a static site or a read-only API, this is fine. For a service that holds private keys and can authorize cryptocurrency transactions on behalf of an AI agent, it's a serious risk.&lt;/p&gt;

&lt;p&gt;The stakes here are different from a misconfigured web server. If someone reaches your wallet daemon unexpectedly — from another container, another machine on your LAN, or through a misconfigured firewall — they're not reading your blog posts. They're potentially talking to an API that can sign and broadcast transactions. The damage is irreversible. On-chain transactions don't have a "dispute with your bank" option.&lt;/p&gt;

&lt;p&gt;This is why self-hosting your AI wallet infrastructure isn't just about privacy and sovereignty (though those matter too). It's about applying the correct security defaults for what the service actually does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Self-Hosting in the First Place?
&lt;/h2&gt;

&lt;p&gt;Before getting into the technical details, it's worth grounding the philosophy here.&lt;/p&gt;

&lt;p&gt;When you use a hosted Wallet-as-a-Service, someone else holds your keys or at minimum has the infrastructure-level ability to inspect, delay, or block your agent's transactions. You're trusting a third party's uptime, their security practices, their API rate limits, and their business continuity. For many use cases, that trade-off is fine. But for developers who care about sovereignty — running their own infrastructure, keeping their own keys, knowing exactly what software is executing — the hosted model has a ceiling.&lt;/p&gt;

&lt;p&gt;Self-hosting an AI wallet is roughly the crypto equivalent of running your own email server. It was once seen as unnecessarily complicated. Now, with containers making it a one-command operation, the calculus has changed. You get full control over where your data lives, what network it's exposed to, and who can reach it.&lt;/p&gt;

&lt;p&gt;WAIaaS is an open-source self-hosted Wallet-as-a-Service built specifically for AI agents. It runs as a local daemon, exposes a REST API over HTTP, and is designed from the start to live on &lt;code&gt;127.0.0.1&lt;/code&gt; — not the public internet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Default: &lt;code&gt;127.0.0.1:3100&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The WAIaaS Docker Compose configuration binds to &lt;code&gt;127.0.0.1:3100:3100&lt;/code&gt; by default. That colon-separated IP address at the front is doing critical work. It means the port is only reachable from the local machine — not from your LAN, not from another Docker network unless you explicitly configure it, and certainly not from the internet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;daemon&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io/minhoyoo-iotrust/waiaas:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;waiaas-daemon&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1:3100:3100"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;waiaas-data:/data&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WAIAAS_DATA_DIR=/data&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WAIAAS_DAEMON_HOSTNAME=0.0.0.0&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;curl"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-f"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:3100/health"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;start_period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;waiaas-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll notice &lt;code&gt;WAIAAS_DAEMON_HOSTNAME=0.0.0.0&lt;/code&gt; in the environment. This is not a contradiction — it means the daemon inside the container listens on all interfaces within the container's network namespace. The binding restriction (&lt;code&gt;127.0.0.1:3100&lt;/code&gt;) is enforced by Docker at the host level. The process inside the container doesn't need to know it's isolated; Docker handles the network boundary.&lt;/p&gt;

&lt;p&gt;This is the correct pattern: let the container runtime enforce network exposure, not hope the application gets it right.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Auth Layers Before Any Transaction Moves
&lt;/h2&gt;

&lt;p&gt;Network isolation is layer zero. WAIaaS also enforces a 3-layer authentication model that separates concerns between the system administrator, the fund owner, and the AI agent itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# masterAuth — system administrator (wallet creation, session management, policies)&lt;/span&gt;
&lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt;

&lt;span class="c"&gt;# sessionAuth — AI agent (transactions, balance queries, DeFi actions)&lt;/span&gt;
&lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_eyJhbGciOiJIUzI1NiJ9..."&lt;/span&gt;

&lt;span class="c"&gt;# ownerAuth — fund owner (transaction approval, kill switch recovery)&lt;/span&gt;
&lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Owner-Signature: &amp;lt;ed25519-or-secp256k1-signature&amp;gt;"&lt;/span&gt;
&lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Owner-Message: &amp;lt;signed-message&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The AI agent only ever holds a session token — a JWT that can be scoped, time-limited, and revoked. It never touches the master password. The master password (hashed with Argon2id) is only used for administrative operations: creating wallets, managing sessions, configuring policies. The fund owner, who holds an ed25519 or secp256k1 keypair, is the only one who can approve transactions that exceed the policy thresholds or recover from a compromised session.&lt;/p&gt;

&lt;p&gt;Even if an attacker somehow reaches the API on localhost (which requires they already have code execution on your machine, at which point you have bigger problems), they still need to know which token or password authorizes which operation. The separation of roles limits blast radius significantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Production Secrets Without Environment Variables in Plain Text
&lt;/h2&gt;

&lt;p&gt;For production deployments, WAIaaS supports Docker Secrets — a mechanism where secret values live in files rather than environment variables, reducing the risk of accidental exposure through &lt;code&gt;docker inspect&lt;/code&gt;, log scraping, or process listings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create secret files&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; secrets
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"your-secure-password"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; secrets/master_password.txt
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 secrets/master_password.txt

&lt;span class="c"&gt;# Deploy with secrets overlay&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.secrets.yml up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;docker-compose.secrets.yml&lt;/code&gt; overlay patches in the secret mounts without changing your base configuration. This means your base &lt;code&gt;docker-compose.yml&lt;/code&gt; stays clean and can be committed to version control, while the secrets file stays out of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auto-Provision for First Boot
&lt;/h2&gt;

&lt;p&gt;If you're spinning up WAIaaS for the first time and don't want to manually set a master password, the auto-provision flag generates one for you and writes it to a recovery key file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; waiaas &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 127.0.0.1:3100:3100 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; waiaas-data:/data &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;WAIAAS_AUTO_PROVISION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/minhoyoo-iotrust/waiaas:latest

&lt;span class="c"&gt;# Retrieve auto-generated master password&lt;/span&gt;
docker &lt;span class="nb"&gt;exec &lt;/span&gt;waiaas &lt;span class="nb"&gt;cat&lt;/span&gt; /data/recovery.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The recovery key approach is practical: you get a running system immediately, and you can harden the password later using &lt;code&gt;waiaas set-master&lt;/code&gt; from the CLI. The important thing is to delete the recovery key file once you've stored the password somewhere safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Policy Engine as Your Second Network
&lt;/h2&gt;

&lt;p&gt;Even after you've locked down network access and authentication, there's still the question of what the AI agent is allowed to do once it has a valid session token. This is where WAIaaS's policy engine becomes part of the security architecture rather than just a feature.&lt;/p&gt;

&lt;p&gt;The policy engine enforces 21 policy types with 4 security tiers. Default-deny is the enforced behavior: if &lt;code&gt;ALLOWED_TOKENS&lt;/code&gt; is not configured, token transfers are blocked. If &lt;code&gt;CONTRACT_WHITELIST&lt;/code&gt; is not configured, contract calls are blocked.&lt;/p&gt;

&lt;p&gt;Here's a policy that limits spending with tiered escalation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "walletId": "&amp;lt;wallet-uuid&amp;gt;",
    "type": "SPENDING_LIMIT",
    "rules": {
      "instant_max_usd": 100,
      "notify_max_usd": 500,
      "delay_max_usd": 2000,
      "delay_seconds": 900,
      "daily_limit_usd": 5000
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The four tiers — INSTANT, NOTIFY, DELAY, and APPROVAL — mean that small transactions go through immediately, mid-range transactions send a notification to the owner, larger ones queue for a time delay (and are cancellable during that window), and anything above the threshold requires explicit human approval. This is enforced through a 7-stage transaction pipeline.&lt;/p&gt;

&lt;p&gt;The AI agent has no way to bypass this. The pipeline enforces policy at the server level, not at the client level. The agent submits a transaction, and the pipeline decides what happens next based on the configured policies.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Minimal Self-Hosted Setup in Five Steps
&lt;/h2&gt;

&lt;p&gt;Here's the complete path from zero to a running, locally-bound AI wallet daemon:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Install the CLI&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @waiaas/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Initialize and start&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;waiaas init &lt;span class="nt"&gt;--auto-provision&lt;/span&gt;
waiaas start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Create wallets and sessions in one command&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;waiaas quickset &lt;span class="nt"&gt;--mode&lt;/span&gt; mainnet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Connect to your AI agent (Claude Desktop)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;waiaas mcp setup &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This auto-registers all wallets with Claude Desktop by writing the MCP configuration. The MCP server exposes 45 tools to the AI agent — everything from balance checks to DeFi actions — all proxied through your local daemon with session authentication enforced.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5: Set a real master password&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;waiaas set-master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once done, delete the auto-generated recovery key.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "Your Keys, Your Server" Actually Means
&lt;/h2&gt;

&lt;p&gt;Self-hosted infrastructure means the keys never leave your machine. WAIaaS runs entirely on your hardware, with data stored in a named Docker volume that only you control. There's no telemetry, no cloud sync, no third-party service that holds or proxies your keys.&lt;/p&gt;

&lt;p&gt;The WAIaaS monorepo is a 15-package open-source codebase. The daemon, the CLI, the MCP server, the TypeScript SDK, the Python SDK, the admin UI — all of it is in the repository and auditable. If you want to know exactly what's running on your machine when you start the daemon, you can read the source.&lt;/p&gt;

&lt;p&gt;This also means the Docker image comes from a specific, versioned registry path (&lt;code&gt;ghcr.io/minhoyoo-iotrust/waiaas:latest&lt;/code&gt;) that you can verify. The entrypoint script handles auto-provisioning and Docker Secrets in a way you can inspect before running.&lt;/p&gt;

&lt;p&gt;The daemon also runs as a non-root user (UID 1001) inside the container. This is a small detail with meaningful consequences: even if a bug in the daemon led to container escape, the process wouldn't have root privileges on the host. Defense in depth applies at every layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;If you want to go deeper on the policy engine and understand how to configure the full set of 21 policy types for your specific use case, the policy configuration documentation is the right next step. For teams who want to integrate WAIaaS into an existing AI agent framework rather than Claude Desktop, the OpenClaw plugin and the TypeScript or Python SDK are worth looking at — the SDK has over 40 methods and zero external dependencies.&lt;/p&gt;

&lt;p&gt;The full source is at &lt;a href="https://github.com/minhoyoo-iotrust/WAIaaS" rel="noopener noreferrer"&gt;https://github.com/minhoyoo-iotrust/WAIaaS&lt;/a&gt; and the official site with documentation is at &lt;a href="https://waiaas.ai" rel="noopener noreferrer"&gt;https://waiaas.ai&lt;/a&gt;. If you're running this in a homelab or a privacy-focused setup, the GitHub issues and discussions are the right place to share what you're building and ask questions.&lt;/p&gt;

</description>
      <category>selfhosted</category>
      <category>security</category>
      <category>docker</category>
      <category>web3</category>
    </item>
    <item>
      <title>The API Economy Goes Autonomous: When AI Agents Pay Their Own Bills</title>
      <dc:creator>Wallet Guy</dc:creator>
      <pubDate>Sun, 19 Jul 2026 14:34:21 +0000</pubDate>
      <link>https://dev.to/walletguy/the-api-economy-goes-autonomous-when-ai-agents-pay-their-own-bills-20ga</link>
      <guid>https://dev.to/walletguy/the-api-economy-goes-autonomous-when-ai-agents-pay-their-own-bills-20ga</guid>
      <description>&lt;h1&gt;
  
  
  The API Economy Goes Autonomous: When AI Agents Pay Their Own Bills
&lt;/h1&gt;

&lt;p&gt;AI agents will need to pay for compute, data, and API calls — and right now, almost none of the infrastructure to support that exists. We talk endlessly about autonomous agents that research, trade, and act on our behalf, but we hand-wave past a fundamental question: when an agent needs to pay for something, who actually pays, and how? The answer today is usually "a human does it manually," which quietly defeats the entire point of autonomy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Gap Matters More Than It Seems
&lt;/h2&gt;

&lt;p&gt;Think about what a genuinely autonomous agent needs to do its job. It calls APIs to fetch data. It pays for compute time. It moves funds between protocols based on market conditions. It settles microtransactions in milliseconds. Every one of those operations has a cost, and every cost requires a payment method.&lt;/p&gt;

&lt;p&gt;The current workarounds are either custodial (a company holds funds on the agent's behalf, reintroducing the human intermediary) or fragile (hardcoded private keys with no spending controls, which is how you get drained wallets at 3am). Neither is acceptable infrastructure for agents operating at any real scale or value.&lt;/p&gt;

&lt;p&gt;The missing layer is autonomous wallet infrastructure — something an agent can operate independently, with guardrails that protect against mistakes and malicious behavior, without requiring a human to approve every transaction.&lt;/p&gt;

&lt;p&gt;That infrastructure exists today. Let's look at how it actually works.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture: Wallets That Agents Can Drive
&lt;/h2&gt;

&lt;p&gt;WAIaaS (Wallet-as-a-Service for AI agents) is an open-source, self-hosted daemon that gives agents structured access to crypto wallets across 18 networks, with a policy engine that lets you define exactly what the agent can and cannot do.&lt;/p&gt;

&lt;p&gt;The core idea is a three-role authentication model that cleanly separates concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;masterAuth&lt;/strong&gt; (Argon2id) — the system administrator who creates wallets and sets policies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;sessionAuth&lt;/strong&gt; (JWT HS256) — the AI agent, which operates with a scoped session token&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ownerAuth&lt;/strong&gt; (SIWS/SIWE signatures) — the fund owner, who can approve high-value transactions or kill the session entirely&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The agent only ever sees a session token. It can't create new wallets, change policies, or override spending limits. Those are administrator and owner concerns. The agent just operates within the sandbox you've defined.&lt;/p&gt;

&lt;p&gt;This sounds simple, but it solves a genuinely hard problem: how do you give an agent enough autonomy to be useful while retaining the ability to constrain and audit everything it does?&lt;/p&gt;

&lt;h2&gt;
  
  
  The x402 Protocol: Machines That Pay for What They Use
&lt;/h2&gt;

&lt;p&gt;The most forward-looking piece of this is x402 HTTP payment support. The x402 protocol extends standard HTTP with a payment flow: an API returns a &lt;code&gt;402 Payment Required&lt;/code&gt; response with payment details, the client pays, and retries the request with proof of payment.&lt;/p&gt;

&lt;p&gt;For humans, this is awkward. For agents, it's natural. An agent calling a data API that costs $0.001 per request should just... pay for it. No billing account setup, no OAuth dance, no human approving a subscription. The agent pays directly, in real time, for what it uses.&lt;/p&gt;

&lt;p&gt;WAIaaS exposes this as a single method in the SDK:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@waiaas/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WAIaaSClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://127.0.0.1:3100&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WAIAAS_SESSION_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// This fetch automatically handles 402 responses and pays inline&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;x402Fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.someservice.com/data/premium-endpoint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent doesn't know or care that a payment happened. It made an HTTP request and got data back. The wallet handled the payment. You can whitelist domains via the &lt;code&gt;X402_ALLOWED_DOMAINS&lt;/code&gt; policy, so the agent can only auto-pay approved services — not arbitrary endpoints it decides to call.&lt;/p&gt;

&lt;p&gt;This is the economic model for agentic compute: pay-per-call, with the payment infrastructure embedded in the agent's toolkit rather than managed by a billing dashboard somewhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Policy Engine: Guardrails That Actually Work
&lt;/h2&gt;

&lt;p&gt;Giving an agent a wallet with no constraints is not a product — it's a liability. The policy engine is what makes autonomous wallets safe enough to actually deploy.&lt;/p&gt;

&lt;p&gt;WAIaaS ships 21 policy types across 4 security tiers: INSTANT (execute immediately), NOTIFY (execute and notify the owner), DELAY (queue for a configurable number of seconds, cancellable), and APPROVAL (require explicit human sign-off via WalletConnect or a notification channel).&lt;/p&gt;

&lt;p&gt;A realistic policy setup for a trading agent looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "walletId": "&amp;lt;wallet-uuid&amp;gt;",
    "type": "SPENDING_LIMIT",
    "rules": {
      "instant_max_usd": 100,
      "notify_max_usd": 500,
      "delay_max_usd": 2000,
      "delay_seconds": 900,
      "daily_limit_usd": 5000
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this policy, transactions under $100 execute instantly. Between $100 and $500, they execute but you get a notification. Between $500 and $2,000, the transaction is queued for 15 minutes — enough time to cancel it if something looks wrong. Anything above $2,000 requires your explicit approval.&lt;/p&gt;

&lt;p&gt;The policy engine enforces default-deny for token transfers and contract interactions: if you haven't explicitly whitelisted a token or contract, the transaction is blocked. An agent can't start sending funds to new addresses it discovers on its own unless you've allowed it.&lt;/p&gt;

&lt;p&gt;Other policy types cover perpetual futures trading (max leverage, max position size, allowed markets), DeFi lending (max LTV ratio, asset whitelist), ERC-8004 onchain reputation thresholds, and more — 21 types in total, designed for the specific risk surface of autonomous financial agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  DeFi Operations: What Agents Can Actually Do
&lt;/h2&gt;

&lt;p&gt;Once you have the session token and policies in place, an agent can execute across 15 DeFi protocol integrations. On Solana, that includes Jupiter swaps, Kamino lending, and Jito staking. On EVM chains, it includes Aave v3, Lido staking, Pendle, Hyperliquid perpetuals, and Polymarket prediction markets, among others. Cross-chain operations run through LI.FI and Across.&lt;/p&gt;

&lt;p&gt;A Jupiter swap from an agent looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/actions/jupiter-swap/swap &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_&amp;lt;token&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "inputMint": "So11111111111111111111111111111111111111112",
    "outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "amount": "1000000000"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent sends one API call. The daemon handles route optimization, transaction construction, signing, and submission. The policy engine checks the transaction against all applicable policies before anything is signed. A 7-stage pipeline handles validation, authorization, policy evaluation, optional time delays, execution, and confirmation.&lt;/p&gt;

&lt;p&gt;Before execution, agents can also simulate: add &lt;code&gt;"dryRun": true&lt;/code&gt; to any transaction payload to get back exactly what would happen — fees, expected output, policy evaluation results — without committing to the chain. This matters for agents making decisions based on expected costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting Claude (or Any AI) Directly
&lt;/h2&gt;

&lt;p&gt;For agents running inside Claude or other LLM frameworks, WAIaaS ships 45 MCP tools covering wallet operations, transactions, DeFi positions, NFTs, and x402 payments. Setup is one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;waiaas mcp setup &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That registers all wallets with Claude Desktop automatically. After that, Claude can check balances, execute swaps, query DeFi positions, and handle x402 payments as native tool calls — no custom integration code required.&lt;/p&gt;

&lt;p&gt;The Claude Desktop configuration looks like this if you're setting it up manually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"waiaas"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@waiaas/mcp"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"WAIAAS_BASE_URL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://127.0.0.1:3100"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"WAIAAS_SESSION_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wai_sess_&amp;lt;your-token&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"WAIAAS_DATA_DIR"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~/.waiaas"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For multi-agent setups where you want different agents with different permissions, you configure one MCP server per wallet — each with its own session token and associated policies. A trading agent gets broad DeFi permissions with aggressive spending limits. A data-fetching agent gets x402 domain whitelist only. Permissions are scoped at the wallet and session level, not globally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying the Infrastructure
&lt;/h2&gt;

&lt;p&gt;The daemon runs as a self-hosted Docker container, which means you control the keys and the data — nothing is custodied by a third party.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; waiaas &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 127.0.0.1:3100:3100 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; waiaas-data:/data &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;WAIAAS_AUTO_PROVISION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/minhoyoo-iotrust/waiaas:latest

&lt;span class="c"&gt;# Retrieve auto-generated master password&lt;/span&gt;
docker &lt;span class="nb"&gt;exec &lt;/span&gt;waiaas &lt;span class="nb"&gt;cat&lt;/span&gt; /data/recovery.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Auto-provision generates a master password on first start and writes it to a recovery key file. After initial setup, you can harden the password and delete the recovery file. The container runs as a non-root user (UID 1001), includes a healthcheck, and supports Watchtower for automatic updates.&lt;/p&gt;

&lt;p&gt;For production, Docker Secrets via the secrets overlay file keeps credentials out of environment variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; secrets
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"your-secure-password"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; secrets/master_password.txt
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 secrets/master_password.txt

docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.secrets.yml up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI gives you 20 commands for managing the daemon, wallets, sessions, backups, and MCP configuration without touching the REST API directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @waiaas/cli
waiaas init
waiaas start
waiaas quickset &lt;span class="nt"&gt;--mode&lt;/span&gt; mainnet   &lt;span class="c"&gt;# Creates wallets + MCP sessions in one step&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Broader Picture
&lt;/h2&gt;

&lt;p&gt;What we're describing is economic infrastructure for the agentic layer — the missing piece between "AI that can reason about financial decisions" and "AI that can actually execute them safely."&lt;/p&gt;

&lt;p&gt;The x402 protocol is particularly significant here. Today, API monetization assumes human billing accounts. As agents become the primary consumers of certain APIs — data feeds, inference endpoints, specialized tools — that assumption breaks down. Pay-per-call, agent-native payment infrastructure is the natural replacement. An agent that can pay for exactly what it consumes, with no subscription overhead, no billing reconciliation, and no human in the loop for routine payments, is genuinely more economically efficient than the alternative.&lt;/p&gt;

&lt;p&gt;The guardrails matter just as much as the capability. An autonomous agent with unconstrained wallet access is not a product anyone should ship. A policy engine that enforces spending limits, whitelists, time delays, and human approval thresholds at the transaction level — with 21 policy types covering the specific risk surface of DeFi and API payments — is what makes autonomous wallets deployable in practice.&lt;/p&gt;

&lt;p&gt;This infrastructure exists today, it's open source, and it runs on your own hardware.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start: Running Your First Autonomous Agent Wallet
&lt;/h2&gt;

&lt;p&gt;Getting a wallet running that an agent can use takes about five minutes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install the CLI&lt;/strong&gt; — &lt;code&gt;npm install -g @waiaas/cli&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Initialize and start&lt;/strong&gt; — &lt;code&gt;waiaas init &amp;amp;&amp;amp; waiaas start&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create wallets and sessions&lt;/strong&gt; — &lt;code&gt;waiaas quickset --mode mainnet&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set spending policy&lt;/strong&gt; — Use the REST API or Admin UI to configure SPENDING_LIMIT and ALLOWED_TOKENS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connect to Claude&lt;/strong&gt; — &lt;code&gt;waiaas mcp setup --all&lt;/code&gt;, paste the config into Claude Desktop&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The agent is now operating with real wallet access, bounded by the policies you've defined, with full transaction history and audit trail.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The open-source codebase, API reference, and Docker images are all available now. If you're building agents that need to participate in the economy — paying for APIs, executing DeFi strategies, handling microtransactions — this is the infrastructure layer worth understanding.&lt;/p&gt;

&lt;p&gt;Explore the project on GitHub at &lt;a href="https://github.com/minhoyoo-iotrust/WAIaaS" rel="noopener noreferrer"&gt;https://github.com/minhoyoo-iotrust/WAIaaS&lt;/a&gt; and find documentation, deployment guides, and SDK references at &lt;a href="https://waiaas.ai" rel="noopener noreferrer"&gt;https://waiaas.ai&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>web3</category>
      <category>api</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>Cross-Chain Arbitrage with LI.FI: When Your Bot Finds Profit Across Networks</title>
      <dc:creator>Wallet Guy</dc:creator>
      <pubDate>Sun, 19 Jul 2026 08:37:57 +0000</pubDate>
      <link>https://dev.to/walletguy/cross-chain-arbitrage-with-lifi-when-your-bot-finds-profit-across-networks-3mi2</link>
      <guid>https://dev.to/walletguy/cross-chain-arbitrage-with-lifi-when-your-bot-finds-profit-across-networks-3mi2</guid>
      <description>&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Cost of Arbitrage Infrastructure
&lt;/h2&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hold and sign transactions on multiple chains simultaneously&lt;/li&gt;
&lt;li&gt;Bridge assets without losing your shirt on gas&lt;/li&gt;
&lt;li&gt;Apply position limits so a runaway bot doesn't drain your treasury&lt;/li&gt;
&lt;li&gt;Know whether it's even worth executing given current gas prices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  What WAIaaS Gives a Trading Bot Builder
&lt;/h2&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LI.FI&lt;/strong&gt; — cross-chain bridging and swapping aggregation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Across&lt;/strong&gt; — fast cross-chain bridging&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jupiter&lt;/strong&gt; — Solana swap aggregation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drift&lt;/strong&gt; — Solana perpetuals for hedging&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hyperliquid&lt;/strong&gt; — perpetual futures, spot trading, and sub-accounts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;0x Swap&lt;/strong&gt; — EVM DEX aggregation&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Beyond protocol access, the features that matter for automated trading are:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gas conditional execution.&lt;/strong&gt; 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.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;21 policy types&lt;/strong&gt; 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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dry-run / simulation API&lt;/strong&gt; so you can validate transaction structure and policy compliance before committing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Daemon
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Docker — fastest path to a running daemon&lt;/span&gt;
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; waiaas &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 127.0.0.1:3100:3100 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; waiaas-data:/data &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;WAIAAS_AUTO_PROVISION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/minhoyoo-iotrust/waiaas:latest

&lt;span class="c"&gt;# Retrieve auto-generated master password&lt;/span&gt;
docker &lt;span class="nb"&gt;exec &lt;/span&gt;waiaas &lt;span class="nb"&gt;cat&lt;/span&gt; /data/recovery.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The daemon binds to &lt;code&gt;127.0.0.1:3100&lt;/code&gt; by default — keep it off the public internet. For a production deployment, use the secrets overlay:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; secrets
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"your-secure-password"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; secrets/master_password.txt
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 secrets/master_password.txt

docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.secrets.yml up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating Wallets for Your Arb System
&lt;/h2&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# EVM wallet&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/wallets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "arb-evm", "chain": "evm", "environment": "mainnet"}'&lt;/span&gt;

&lt;span class="c"&gt;# Solana wallet&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/wallets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "arb-solana", "chain": "solana", "environment": "mainnet"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create a session token for each wallet. Your bot uses session tokens — the master password never leaves your ops environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/sessions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"walletId": "&amp;lt;solana-wallet-uuid&amp;gt;"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store the returned session token as &lt;code&gt;WAIAAS_SESSION_TOKEN&lt;/code&gt; in your bot's environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trade Execution Flow
&lt;/h2&gt;

&lt;p&gt;Here's the cross-chain arb sequence your bot would execute:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Check balance before committing&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://127.0.0.1:3100/v1/wallet/balance &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_eyJhbGciOiJIUzI1NiJ9..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Simulate the swap before execution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before spending gas on a real transaction, validate it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/transactions/send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_&amp;lt;token&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "type": "TRANSFER",
    "to": "recipient-address",
    "amount": "0.1",
    "dryRun": true
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Execute the swap on Jupiter (Solana leg)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/actions/jupiter-swap/swap &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_&amp;lt;token&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "inputMint": "So11111111111111111111111111111111111111112",
    "outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "amount": "1000000000"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Bridge via LI.FI (EVM leg)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your EVM session token hits the lifi action provider directly. Same pattern — POST to &lt;code&gt;/v1/actions/lifi/&amp;lt;action&amp;gt;&lt;/code&gt; with the bridge parameters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5: Hedge on Drift or Hyperliquid&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;/v1/actions/hyperliquid/&amp;lt;action&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Policy Configuration for a Trading Bot
&lt;/h2&gt;

&lt;p&gt;This is where WAIaaS earns its keep. A runaway bot is an existential risk. Configure your circuit breakers before you go live.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Set a spending limit with tiered approval&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "walletId": "&amp;lt;wallet-uuid&amp;gt;",
    "type": "SPENDING_LIMIT",
    "rules": {
      "instant_max_usd": 100,
      "notify_max_usd": 500,
      "delay_max_usd": 2000,
      "delay_seconds": 900,
      "daily_limit_usd": 5000
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;For a trading bot you also want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PERP_MAX_LEVERAGE&lt;/strong&gt; — cap leverage on Hyperliquid or Drift positions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PERP_MAX_POSITION_USD&lt;/strong&gt; — absolute position size limit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VENUE_WHITELIST&lt;/strong&gt; — only trade on protocols you've explicitly approved&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ALLOWED_TOKENS&lt;/strong&gt; — token transfer whitelist (default-deny means if you don't list USDC, the bot cannot send USDC, period)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CONTRACT_WHITELIST&lt;/strong&gt; — same default-deny for contract calls&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  TypeScript SDK for Tighter Bot Integration
&lt;/h2&gt;

&lt;p&gt;If your bot is TypeScript-based, skip the curl layer and use the SDK directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSError&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@waiaas/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WAIaaSClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WAIAAS_BASE_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3100&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WAIAAS_SESSION_TOKEN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Step 1: Check wallet balance&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBalance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Balance: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Step 2: Send tokens&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sendResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendToken&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TRANSFER&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;recipient-address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.001&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Transaction submitted: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;sendResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (status: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;sendResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Step 3: Poll for confirmation&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;POLL_TIMEOUT_MS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;POLL_TIMEOUT_MS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sendResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;COMPLETED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Transaction confirmed! Hash: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;txHash&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FAILED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Transaction failed: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendToken&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`API Error: [&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;] &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// error.code examples: INSUFFICIENT_BALANCE, POLICY_DENIED, TOKEN_EXPIRED&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;POLICY_DENIED&lt;/code&gt; means your circuit breaker fired. Log it, alert, and halt — don't retry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start for Trading Bot Builders
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Run the daemon&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; waiaas &lt;span class="nt"&gt;-p&lt;/span&gt; 127.0.0.1:3100:3100 &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-v&lt;/span&gt; waiaas-data:/data &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;WAIAAS_AUTO_PROVISION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     ghcr.io/minhoyoo-iotrust/waiaas:latest
   docker &lt;span class="nb"&gt;exec &lt;/span&gt;waiaas &lt;span class="nb"&gt;cat&lt;/span&gt; /data/recovery.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create wallets and session tokens&lt;/strong&gt; for each chain your strategy touches (EVM, Solana)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configure policies before going live&lt;/strong&gt;: SPENDING_LIMIT, ALLOWED_TOKENS, CONTRACT_WHITELIST, PERP_MAX_LEVERAGE at minimum&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dry-run your first trade&lt;/strong&gt;: add &lt;code&gt;"dryRun": true&lt;/code&gt; to any transaction request and validate it clears policy&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Install the SDK&lt;/strong&gt; (&lt;code&gt;npm install @waiaas/sdk&lt;/code&gt;) and wire your strategy to the session token — your signing and gas logic is done&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The OpenAPI 3.0 spec is available at &lt;code&gt;http://127.0.0.1:3100/doc&lt;/code&gt; and the interactive Scalar API reference at &lt;code&gt;http://127.0.0.1:3100/reference&lt;/code&gt; — 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.&lt;/p&gt;

&lt;p&gt;Build your strategy, not your wallet infrastructure. The code is at &lt;a href="https://github.com/minhoyoo-iotrust/WAIaaS" rel="noopener noreferrer"&gt;github.com/minhoyoo-iotrust/WAIaaS&lt;/a&gt; and the project site is at &lt;a href="https://waiaas.ai" rel="noopener noreferrer"&gt;waiaas.ai&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>defi</category>
      <category>web3</category>
      <category>ethereum</category>
      <category>solana</category>
    </item>
    <item>
      <title>NOTIFY Tier Policies: Silent Monitoring for Your Trading Bot's Risky Moves</title>
      <dc:creator>Wallet Guy</dc:creator>
      <pubDate>Sat, 18 Jul 2026 14:24:01 +0000</pubDate>
      <link>https://dev.to/walletguy/notify-tier-policies-silent-monitoring-for-your-trading-bots-risky-moves-5hgm</link>
      <guid>https://dev.to/walletguy/notify-tier-policies-silent-monitoring-for-your-trading-bots-risky-moves-5hgm</guid>
      <description>&lt;h1&gt;
  
  
  NOTIFY Tier Policies: Silent Monitoring for Your Trading Bot's Risky Moves
&lt;/h1&gt;

&lt;p&gt;Your trading bot spotted the opportunity — but does your wallet infrastructure know when to let it run and when to quietly flag a move for review? For developers building automated trading bots, arbitrage systems, or algorithmic strategies, the challenge isn't just execution speed. It's knowing which trades should fire instantly, which ones deserve a second look, and which ones should never happen without a human in the loop. WAIaaS's NOTIFY tier policy gives you exactly that middle layer: transactions execute immediately, but you get notified in real time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem With All-or-Nothing Risk Controls
&lt;/h2&gt;

&lt;p&gt;Most wallet setups for trading bots are binary. Either the bot has full autonomy — which is terrifying at 3am when something misbehaves — or you've locked everything down so tightly that the bot misses opportunities while waiting for manual approval. Neither extreme is workable for serious algo trading.&lt;/p&gt;

&lt;p&gt;What you actually want is &lt;strong&gt;graduated control&lt;/strong&gt;. Small, routine trades? Fire instantly, no noise. A swap that's 10x your usual size? Execute it, but ping me right now so I can watch the position. An attempted transfer well above any reasonable threshold? Stop it cold and demand explicit approval before a single satoshi moves.&lt;/p&gt;

&lt;p&gt;This is exactly what WAIaaS's 4-tier policy engine is designed for, and the NOTIFY tier is the unsung workhorse of the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the 4-Tier Security Model Works
&lt;/h2&gt;

&lt;p&gt;WAIaaS enforces a &lt;code&gt;SPENDING_LIMIT&lt;/code&gt; policy with four tiers that map to transaction value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSTANT   — Execute immediately, no notification
NOTIFY    — Execute immediately, send notification
DELAY     — Queue for delay_seconds, then execute (cancellable)
APPROVAL  — Require human approval via WalletConnect/Telegram/Push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tier is determined automatically based on the transaction amount versus your configured thresholds. Here's what a realistic trading bot policy looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Master-Password: &amp;lt;password&amp;gt;'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "walletId": "&amp;lt;wallet-uuid&amp;gt;",
    "type": "SPENDING_LIMIT",
    "rules": {
      "instant_max_usd": 10,
      "notify_max_usd": 100,
      "delay_max_usd": 1000,
      "delay_seconds": 300,
      "daily_limit_usd": 500,
      "monthly_limit_usd": 5000
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A $8 arbitrage fee payment → &lt;strong&gt;INSTANT&lt;/strong&gt; (fires immediately, zero noise)&lt;/li&gt;
&lt;li&gt;A $75 SOL-to-USDC swap on Jupiter → &lt;strong&gt;NOTIFY&lt;/strong&gt; (executes immediately, you get pinged)&lt;/li&gt;
&lt;li&gt;A $600 position open on Drift → &lt;strong&gt;DELAY&lt;/strong&gt; (queued for 5 minutes, cancellable)&lt;/li&gt;
&lt;li&gt;Anything above $1,000 → &lt;strong&gt;APPROVAL&lt;/strong&gt; (hard stop, requires your explicit sign-off)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The NOTIFY tier is your surveillance layer. Your bot keeps running at full speed, but you have eyes on every move that matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why NOTIFY Matters More Than You Think
&lt;/h2&gt;

&lt;p&gt;When you're running an arb bot or an algorithmic strategy across multiple protocols, unusual transaction sizes are your earliest signal that something is wrong. Maybe your position sizing logic has a bug. Maybe a price oracle fed in a bad value. Maybe someone is replaying a transaction.&lt;/p&gt;

&lt;p&gt;The NOTIFY tier catches these situations &lt;strong&gt;without interrupting execution&lt;/strong&gt;. The transaction still goes through — you're not adding latency to your hot path — but you get an immediate alert so you can intervene before the next trade compounds the problem.&lt;/p&gt;

&lt;p&gt;This is meaningfully different from the DELAY tier. With DELAY, you've added a 5-minute queue to every transaction in that bracket, which is fine for large, deliberate position changes but completely unworkable for a bot that needs to respond to market conditions in real time. NOTIFY gives you observability without the latency penalty.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Full Policy Stack for a Trading Bot
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;SPENDING_LIMIT&lt;/code&gt; policy handles your size-based tiers, but a production trading bot needs more layers. WAIaaS gives you 21 policy types, and several of them are specifically designed for DeFi trading scenarios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lock down which tokens can move:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ALLOWED_TOKENS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"symbol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USDC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"chain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"solana"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"So11111111111111111111111111111111111111112"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"symbol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SOL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"chain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"solana"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ALLOWED_TOKENS&lt;/code&gt; is default-deny. If your bot tries to transfer any token not on this list — even accidentally — the transaction is blocked before it reaches the pipeline. This is your first line of defense against logic bugs that try to touch tokens you never intended to trade.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Whitelist the contracts your bot is allowed to call:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CONTRACT_WHITELIST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"contracts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Jupiter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"chain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"solana"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, default-deny. Your bot can only interact with contracts you've explicitly approved. If a compromised dependency or a buggy trade router tries to call an unknown contract, it's blocked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cap perpetual futures leverage and position size:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PERP_MAX_LEVERAGE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"maxLeverage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PERP_MAX_POSITION_USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"maxPositionUsd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are specifically built for strategies running on Hyperliquid or Drift, both of which are integrated as DeFi protocol providers in WAIaaS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Restrict which markets you're allowed to trade:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PERP_ALLOWED_MARKETS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"markets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"SOL-PERP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ETH-PERP"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Executing Trades Through the Pipeline
&lt;/h2&gt;

&lt;p&gt;Every transaction your bot submits goes through WAIaaS's 7-stage pipeline: validate → auth → policy → wait → execute → confirm. The policy stage is where your SPENDING_LIMIT thresholds are evaluated and tier assignment happens. If the transaction hits NOTIFY, it continues through the pipeline immediately while the notification fires asynchronously.&lt;/p&gt;

&lt;p&gt;Here's what a typical Jupiter swap looks like from your bot's perspective:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/actions/jupiter-swap/swap &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_&amp;lt;token&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "inputMint": "So11111111111111111111111111111111111111112",
    "outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "amount": "1000000000"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your bot sends the request. The pipeline validates the session, checks your token whitelist and contract whitelist, evaluates the USD value against your spending tiers, assigns NOTIFY if it's in that bracket, and fires the swap. The notification goes out in parallel. From your bot's perspective, this is functionally identical to an INSTANT transaction — same response time, same execution path.&lt;/p&gt;

&lt;p&gt;If the policy engine denies the transaction instead, you get a structured error you can handle cleanly in your code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"POLICY_DENIED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Transaction denied by SPENDING_LIMIT policy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"POLICY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"retryable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Before You Execute: Dry Run Mode
&lt;/h2&gt;

&lt;p&gt;For a trading bot, testing your logic against real market conditions without actually moving funds is essential. WAIaaS has a dry-run mode built directly into the transaction endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/transactions/send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_&amp;lt;token&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "type": "TRANSFER",
    "to": "recipient-address",
    "amount": "0.1",
    "dryRun": true
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add &lt;code&gt;"dryRun": true&lt;/code&gt; to any transaction payload and WAIaaS simulates the full pipeline — including policy evaluation — without submitting anything to the network. This lets you verify that your SPENDING_LIMIT thresholds are behaving as expected and that your NOTIFY tier is triggering at the right amounts before you go live.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Bot Wallet
&lt;/h2&gt;

&lt;p&gt;Getting a trading bot wallet running takes about five minutes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Install the CLI and start the daemon&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @waiaas/cli
waiaas init
waiaas start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Create a wallet and get a session token&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/wallets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "trading-wallet", "chain": "solana", "environment": "mainnet"}'&lt;/span&gt;

curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/sessions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"walletId": "&amp;lt;wallet-uuid&amp;gt;"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Apply your SPENDING_LIMIT policy&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "walletId": "&amp;lt;wallet-uuid&amp;gt;",
    "type": "SPENDING_LIMIT",
    "rules": {
      "instant_max_usd": 10,
      "notify_max_usd": 100,
      "delay_max_usd": 1000,
      "delay_seconds": 300,
      "daily_limit_usd": 500,
      "monthly_limit_usd": 5000
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Add your token and contract whitelists&lt;/strong&gt; (use the JSON examples above, same endpoint, same master auth)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5: Start trading with the session token&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@waiaas/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WAIaaSClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://127.0.0.1:3100&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WAIAAS_SESSION_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBalance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The session token is what your bot uses. The master password stays out of the hot path entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy with Docker for Production
&lt;/h2&gt;

&lt;p&gt;When you're ready to run this in production, Docker handles the infrastructure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; waiaas &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 127.0.0.1:3100:3100 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; waiaas-data:/data &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;WAIAAS_AUTO_PROVISION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/minhoyoo-iotrust/waiaas:latest

docker &lt;span class="nb"&gt;exec &lt;/span&gt;waiaas &lt;span class="nb"&gt;cat&lt;/span&gt; /data/recovery.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The daemon binds to &lt;code&gt;127.0.0.1:3100&lt;/code&gt; by default — not exposed to the public internet. Your bot talks to it over localhost. The data volume persists your wallets, sessions, and policy configuration across container restarts.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Protocols Your Bot Can Access
&lt;/h2&gt;

&lt;p&gt;WAIaaS integrates 15 DeFi protocol providers, which means your bot can interact with a serious range of venues through a single authenticated session. On Solana: Jupiter for swaps, Drift for perpetuals, Kamino for lending, Jito for staking. Cross-chain bridging through LI.FI and Across. Prediction markets via Polymarket. Yield via Pendle. Perpetuals on Hyperliquid. All of them accessible through the same session token, all of them subject to the same policy engine.&lt;/p&gt;

&lt;p&gt;That means your SPENDING_LIMIT policy applies uniformly whether your bot is swapping on Jupiter, opening a position on Drift, or bridging assets via LI.FI. One policy layer covers the entire surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The NOTIFY tier is one piece of a larger risk management architecture. As you push more volume through your bot, you'll want to layer in &lt;code&gt;RATE_LIMIT&lt;/code&gt; to cap transaction frequency, &lt;code&gt;LENDING_LTV_LIMIT&lt;/code&gt; if you're using DeFi lending as part of your strategy, and &lt;code&gt;PERP_ALLOWED_MARKETS&lt;/code&gt; to prevent any edge case from opening positions in markets you're not tracking.&lt;/p&gt;

&lt;p&gt;The full OpenAPI spec is available at &lt;code&gt;http://127.0.0.1:3100/reference&lt;/code&gt; once your daemon is running — interactive, explorable, and worth spending time with before you go live.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Explore the codebase and deploy your trading bot wallet:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/minhoyoo-iotrust/WAIaaS" rel="noopener noreferrer"&gt;https://github.com/minhoyoo-iotrust/WAIaaS&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Official site: &lt;a href="https://waiaas.ai" rel="noopener noreferrer"&gt;https://waiaas.ai&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>ai</category>
      <category>defi</category>
      <category>web3</category>
    </item>
    <item>
      <title>Docker Auto-Provisioning Deep Dive: Zero-Config AI Wallet Deployment</title>
      <dc:creator>Wallet Guy</dc:creator>
      <pubDate>Sat, 18 Jul 2026 08:13:09 +0000</pubDate>
      <link>https://dev.to/walletguy/docker-auto-provisioning-deep-dive-zero-config-ai-wallet-deployment-53hc</link>
      <guid>https://dev.to/walletguy/docker-auto-provisioning-deep-dive-zero-config-ai-wallet-deployment-53hc</guid>
      <description>&lt;h1&gt;
  
  
  Docker Auto-Provisioning Deep Dive: Zero-Config AI Wallet Deployment
&lt;/h1&gt;

&lt;p&gt;Docker auto-provisioning for AI wallets sounds like it should require a weekend of configuration — but WAIaaS ships with a zero-config path that gets you from &lt;code&gt;docker run&lt;/code&gt; to a fully operational, self-hosted AI wallet daemon in under a minute. If you've ever asked yourself whether you'd trust a third-party service with your AI agent's private keys, this post is for you. We're going to walk through exactly how WAIaaS's auto-provision system works, why self-hosting matters for AI agent wallets specifically, and how to go from nothing to a running wallet daemon with one command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Self-Hosting an AI Wallet Actually Matters
&lt;/h2&gt;

&lt;p&gt;There's a philosophical argument for self-hosting almost anything — privacy, control, no vendor lock-in. But with AI agent wallets, the stakes are higher than with, say, a self-hosted RSS reader.&lt;/p&gt;

&lt;p&gt;An AI agent with a wallet has the ability to sign and broadcast real transactions. It can move funds, interact with DeFi protocols, pay for API calls via x402, trade on perpetual markets, and bridge assets across chains. That's not a read-only integration — it's an agent with real financial authority. When that agent lives inside a hosted service, you're trusting that service with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your private keys (or their custody of them)&lt;/li&gt;
&lt;li&gt;The policy rules that govern what your agent can and can't do&lt;/li&gt;
&lt;li&gt;The audit log of every transaction your agent executes&lt;/li&gt;
&lt;li&gt;Uptime and rate limits that are outside your control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Self-hosting doesn't just satisfy a philosophical preference. It means your keys never leave your infrastructure, your policy engine runs on hardware you control, and your agent's transaction history is yours. Think of it like running your own email server — except this one actually holds money, so the sovereignty argument isn't just ideological.&lt;/p&gt;

&lt;p&gt;WAIaaS is open-source and designed from the ground up to run on your own hardware. The Docker image at &lt;code&gt;ghcr.io/minhoyoo-iotrust/waiaas:latest&lt;/code&gt; is the canonical distribution, and the auto-provisioning system means you don't need to configure anything to get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Auto-Provisioning Actually Does
&lt;/h2&gt;

&lt;p&gt;When you pass &lt;code&gt;WAIAAS_AUTO_PROVISION=true&lt;/code&gt; to the container, the Docker entrypoint generates a master password for you on first start and writes it to a recovery key file. This means you can spin up a fully secured daemon without ever typing a password manually — the system creates one, stores it somewhere safe, and you retrieve it after the fact.&lt;/p&gt;

&lt;p&gt;Here's the full one-liner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; waiaas &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 127.0.0.1:3100:3100 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; waiaas-data:/data &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;WAIAAS_AUTO_PROVISION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/minhoyoo-iotrust/waiaas:latest

&lt;span class="c"&gt;# Retrieve auto-generated master password&lt;/span&gt;
docker &lt;span class="nb"&gt;exec &lt;/span&gt;waiaas &lt;span class="nb"&gt;cat&lt;/span&gt; /data/recovery.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things worth noting about that single command:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The port binding is &lt;code&gt;127.0.0.1:3100:3100&lt;/code&gt;&lt;/strong&gt; — localhost only, by default. The daemon doesn't expose itself to the network unless you deliberately change this. That's a sane default for a service that controls wallets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The data volume is named&lt;/strong&gt;, not a bind mount to a random path. Your keys and transaction history survive &lt;code&gt;docker compose down&lt;/code&gt; and come back intact on restart.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The recovery key is in &lt;code&gt;/data&lt;/code&gt;&lt;/strong&gt; — the same volume you mounted. If you're running this in production, that volume should be encrypted at rest and backed up. The key itself is just a file, so treat it like one.&lt;/p&gt;

&lt;p&gt;The entrypoint also supports Docker Secrets for production deployments, which we'll cover shortly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Full Docker Compose Setup
&lt;/h2&gt;

&lt;p&gt;For anything beyond a quick test, &lt;code&gt;docker compose&lt;/code&gt; is the right tool. The full &lt;code&gt;docker-compose.yml&lt;/code&gt; that ships with WAIaaS looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;daemon&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io/minhoyoo-iotrust/waiaas:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;waiaas-daemon&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1:3100:3100"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;waiaas-data:/data&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WAIAAS_DATA_DIR=/data&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WAIAAS_DAEMON_HOSTNAME=0.0.0.0&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;curl"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-f"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:3100/health"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;start_period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;waiaas-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The healthcheck matters if you're running this behind a reverse proxy or with a process supervisor that needs to know when the daemon is actually ready. It polls &lt;code&gt;/health&lt;/code&gt; every 30 seconds and gives the container 10 seconds to warm up before starting checks.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;restart: unless-stopped&lt;/code&gt; policy means the daemon comes back after host reboots without you having to do anything. For a homelab or dedicated server, that's the behavior you want.&lt;/p&gt;

&lt;p&gt;To get started from the repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/minhoyoo-iotrust/WAIaaS.git
&lt;span class="nb"&gt;cd &lt;/span&gt;WAIaaS
docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Three commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hardening for Production: Docker Secrets
&lt;/h2&gt;

&lt;p&gt;Environment variables are fine for development, but for a production self-hosted deployment, you don't want your master password sitting in shell history or visible in &lt;code&gt;docker inspect&lt;/code&gt;. WAIaaS ships with a &lt;code&gt;docker-compose.secrets.yml&lt;/code&gt; overlay specifically for this use case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create secret files&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; secrets
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"your-secure-password"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; secrets/master_password.txt
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 secrets/master_password.txt

&lt;span class="c"&gt;# Deploy with secrets overlay&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.yml &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.secrets.yml up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The secrets overlay injects the password as a Docker Secret rather than an environment variable. The file permission (&lt;code&gt;chmod 600&lt;/code&gt;) ensures only root can read it on the host, and Docker Secrets mount it into the container at a path inaccessible from &lt;code&gt;docker inspect&lt;/code&gt; output. For homelabbers running Portainer or Dockge, this is worth setting up even if it feels like extra steps — the master password controls wallet creation, session management, and policy configuration, so it's worth protecting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Environment Variables You Should Know
&lt;/h2&gt;

&lt;p&gt;The daemon is configured primarily through environment variables. The ones you're most likely to need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;WAIAAS_AUTO_PROVISION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;              &lt;span class="c"&gt;# Auto-generate master password on first start&lt;/span&gt;
&lt;span class="nv"&gt;WAIAAS_DAEMON_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3100                 &lt;span class="c"&gt;# Listening port&lt;/span&gt;
&lt;span class="nv"&gt;WAIAAS_DAEMON_HOSTNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.0.0.0         &lt;span class="c"&gt;# Bind address&lt;/span&gt;
&lt;span class="nv"&gt;WAIAAS_DAEMON_LOG_LEVEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;info            &lt;span class="c"&gt;# Log level (trace/debug/info/warn/error)&lt;/span&gt;
&lt;span class="nv"&gt;WAIAAS_DATA_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/data                   &lt;span class="c"&gt;# Data directory&lt;/span&gt;
&lt;span class="nv"&gt;WAIAAS_RPC_SOLANA_MAINNET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;url&amp;gt;         &lt;span class="c"&gt;# Solana mainnet RPC endpoint&lt;/span&gt;
&lt;span class="nv"&gt;WAIAAS_RPC_EVM_ETHEREUM_MAINNET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;url&amp;gt;   &lt;span class="c"&gt;# Ethereum mainnet RPC endpoint&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The RPC endpoint variables deserve special mention. By default, WAIaaS will use public RPC endpoints, which are fine for experimentation but rate-limited for production. If you're running this seriously — especially if you have an agent executing DeFi actions across 18 supported networks — you'll want to plug in your own RPC URLs from providers like Alchemy, Helius, or your own node. This is another advantage of self-hosting: you control the entire stack, including where your RPC calls go.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Running Container to Configured Wallet: The CLI Path
&lt;/h2&gt;

&lt;p&gt;Once your container is up, you have two paths to initial configuration: the REST API directly, or the CLI. The CLI is faster for humans.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @waiaas/cli
waiaas init                        &lt;span class="c"&gt;# Create data directory + config.toml&lt;/span&gt;
waiaas start                       &lt;span class="c"&gt;# Start daemon (sets master password on first run)&lt;/span&gt;
waiaas quickset &lt;span class="nt"&gt;--mode&lt;/span&gt; mainnet     &lt;span class="c"&gt;# Create wallets + MCP sessions in one step&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you went the auto-provision route with Docker, you skip &lt;code&gt;init&lt;/code&gt; and &lt;code&gt;start&lt;/code&gt; and go straight to &lt;code&gt;quickset&lt;/code&gt;. The &lt;code&gt;quickset&lt;/code&gt; command creates wallets and MCP sessions in one step — it's designed for exactly this use case where you want to go from zero to an AI agent that can actually do things as fast as possible.&lt;/p&gt;

&lt;p&gt;The CLI has 20 commands in total. The ones most relevant to initial Docker setup are &lt;code&gt;init&lt;/code&gt;, &lt;code&gt;start&lt;/code&gt;, &lt;code&gt;quickset&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;stop&lt;/code&gt;, and &lt;code&gt;wallet create&lt;/code&gt;. The &lt;code&gt;backup create&lt;/code&gt; and &lt;code&gt;restore&lt;/code&gt; commands are worth knowing about for ongoing maintenance of a self-hosted instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verifying Your Setup with the REST API
&lt;/h2&gt;

&lt;p&gt;Once the daemon is running, the REST API is available at &lt;code&gt;http://127.0.0.1:3100&lt;/code&gt;. The interactive API reference lives at &lt;code&gt;/reference&lt;/code&gt; and the OpenAPI 3.0 spec is at &lt;code&gt;/doc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Download OpenAPI 3.0 spec&lt;/span&gt;
curl http://127.0.0.1:3100/doc &lt;span class="nt"&gt;-o&lt;/span&gt; openapi.json

&lt;span class="c"&gt;# View interactive API reference&lt;/span&gt;
open http://127.0.0.1:3100/reference
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are 39 REST API route modules in total, covering wallets, transactions, policies, DeFi actions, NFTs, sessions, and more. But for a sanity check after initial deployment, the simplest test is creating a wallet and checking its balance.&lt;/p&gt;

&lt;p&gt;First, create a wallet using your master password (retrieved from &lt;code&gt;recovery.key&lt;/code&gt; if you used auto-provision):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/wallets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "trading-wallet", "chain": "solana", "environment": "mainnet"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create a session token for an AI agent to use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/sessions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"walletId": "&amp;lt;wallet-uuid&amp;gt;"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And verify the session works by checking balance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://127.0.0.1:3100/v1/wallet/balance &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer wai_sess_eyJhbGciOiJIUzI1NiJ9..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you get a balance response, your self-hosted AI wallet daemon is fully operational. Your keys are on your hardware, your transactions are in your database, and your policy engine is running under your control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Policies Before Letting Your Agent Loose
&lt;/h2&gt;

&lt;p&gt;This is the step self-hosters sometimes skip because they're excited to get their agent running — don't skip it. WAIaaS uses a default-deny policy model, meaning certain transaction types are blocked unless explicitly allowed. Before you hand a session token to an AI agent, set at least a spending limit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "walletId": "&amp;lt;wallet-uuid&amp;gt;",
    "type": "SPENDING_LIMIT",
    "rules": {
      "instant_max_usd": 100,
      "notify_max_usd": 500,
      "delay_max_usd": 2000,
      "delay_seconds": 900,
      "daily_limit_usd": 5000
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are 21 policy types available, organized around 4 security tiers: INSTANT (execute immediately), NOTIFY (execute and alert), DELAY (queue and wait before executing), and APPROVAL (require human sign-off). The spending limit policy shown above maps dollar thresholds to these tiers — transactions under $100 go through instantly, transactions between $100-$500 trigger a notification, transactions between $500-$2000 wait 15 minutes before executing (giving you time to cancel), and anything above $2000 requires your explicit approval.&lt;/p&gt;

&lt;p&gt;The policy engine runs entirely on your server. There's no external service deciding whether your agent's transaction is legitimate — it's all local, deterministic rules that you wrote.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Docker Maintenance Commands
&lt;/h2&gt;

&lt;p&gt;For ongoing management of your self-hosted instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;          &lt;span class="c"&gt;# Start daemon&lt;/span&gt;
docker compose logs &lt;span class="nt"&gt;-f&lt;/span&gt;        &lt;span class="c"&gt;# Follow logs&lt;/span&gt;
docker compose down           &lt;span class="c"&gt;# Stop (data preserved in named volume)&lt;/span&gt;
docker compose down &lt;span class="nt"&gt;-v&lt;/span&gt;        &lt;span class="c"&gt;# Stop + delete data volume&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The distinction between &lt;code&gt;down&lt;/code&gt; and &lt;code&gt;down -v&lt;/code&gt; is important. Without &lt;code&gt;-v&lt;/code&gt;, your wallet keys, transaction history, and policies survive the container being removed. With &lt;code&gt;-v&lt;/code&gt;, everything is gone. Keep that in mind before running the second variant.&lt;/p&gt;

&lt;p&gt;For backups, the CLI has a dedicated command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;waiaas backup create
waiaas backup list
waiaas restore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a self-hosted setup that's actually managing funds, treat backups the way you'd treat a hardware wallet seed phrase backup — redundant, offline, and tested.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Two-Image Architecture
&lt;/h2&gt;

&lt;p&gt;WAIaaS actually ships two Docker images: the main &lt;code&gt;waiaas&lt;/code&gt; daemon and a &lt;code&gt;push-relay&lt;/code&gt; service. The push-relay handles the signing channel notifications — when your agent initiates a transaction that requires human approval, the push-relay is what delivers that approval request to you via push notification. For a minimal self-hosted setup, you can start with just the daemon. The push-relay becomes relevant when you want to approve transactions from your phone rather than having to be at your terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start Summary
&lt;/h2&gt;

&lt;p&gt;If you want to go from zero to running right now:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pull and start&lt;/strong&gt;: &lt;code&gt;docker compose up -d&lt;/code&gt; from the cloned repo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retrieve your password&lt;/strong&gt;: &lt;code&gt;docker exec waiaas cat /data/recovery.key&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create a wallet&lt;/strong&gt;: POST to &lt;code&gt;/v1/wallets&lt;/code&gt; with your master password&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set a spending policy&lt;/strong&gt;: POST to &lt;code&gt;/v1/policies&lt;/code&gt; before creating any agent sessions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create a session&lt;/strong&gt;: POST to &lt;code&gt;/v1/sessions&lt;/code&gt; and hand that token to your agent&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The whole process takes under five minutes. Everything runs on your hardware, your keys never leave your server, and you have full audit visibility into everything your agent does.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;Once your daemon is running, the natural next step is connecting it to an AI agent via the MCP integration — WAIaaS provides 45 MCP tools that give Claude and other MCP-compatible agents direct wallet access within the policy guardrails you've set. From there, you can explore the DeFi integrations across 15 supported protocols, or set up the Admin Web UI at &lt;code&gt;/admin&lt;/code&gt; for a visual dashboard of your wallets, sessions, and positions.&lt;/p&gt;

&lt;p&gt;The full source is at &lt;a href="https://github.com/minhoyoo-iotrust/WAIaaS" rel="noopener noreferrer"&gt;https://github.com/minhoyoo-iotrust/WAIaaS&lt;/a&gt; and the project site is at &lt;a href="https://waiaas.ai" rel="noopener noreferrer"&gt;https://waiaas.ai&lt;/a&gt;. If you're running this in a homelab or on a VPS and have questions, the GitHub issues and discussions are the right place — this is open-source software maintained in the open.&lt;/p&gt;

&lt;p&gt;Your keys, your server, your rules.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>selfhosted</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Automated Yield Optimization: Building Pendle Protocol Trading Bots</title>
      <dc:creator>Wallet Guy</dc:creator>
      <pubDate>Fri, 17 Jul 2026 14:51:32 +0000</pubDate>
      <link>https://dev.to/walletguy/automated-yield-optimization-building-pendle-protocol-trading-bots-90f</link>
      <guid>https://dev.to/walletguy/automated-yield-optimization-building-pendle-protocol-trading-bots-90f</guid>
      <description>&lt;h1&gt;
  
  
  Automated Yield Optimization: Building Pendle Protocol Trading Bots
&lt;/h1&gt;

&lt;p&gt;Pendle trading bots live and die by execution — your bot spotted the PT/YT mispricing, the yield curve shifted, and you have seconds before the market corrects. Building that bot on fragile wallet infrastructure means watching profitable trades fail at the signing step, burning gas on failed transactions, or — worse — having no risk controls when your bot misbehaves at 3am. WAIaaS gives you the wallet layer purpose-built for this: multi-protocol DeFi access, gas conditional execution, a 7-stage transaction pipeline, and a policy engine with 21 policy types so you can automate aggressively without losing sleep.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Yield Trading Bots Need Infrastructure, Not Just Code
&lt;/h2&gt;

&lt;p&gt;Pendle splits yield-bearing assets into Principal Tokens (PT) and Yield Tokens (YT), creating a rich surface for yield curve arbitrage, fixed-rate locking, and leveraged yield plays. But the complexity doesn't stop at the strategy layer. Your bot needs to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Execute across Pendle and connected protocols (lending, bridging, staking) without managing separate wallet integrations for each&lt;/li&gt;
&lt;li&gt;Avoid wasting gas on transactions that will fail policy checks or hit insufficient balances&lt;/li&gt;
&lt;li&gt;Apply risk controls at the infrastructure level — not bolted on in application code that can have bugs&lt;/li&gt;
&lt;li&gt;Let you observe and intervene when positions move against you, without shutting down the entire system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are solved problems at the infrastructure layer. The mistake most bot builders make is solving them at the application layer, in the same codebase as their alpha. Separating concerns here is the difference between a bot you can maintain and one that becomes a liability.&lt;/p&gt;

&lt;h2&gt;
  
  
  What WAIaaS Brings to Pendle Bot Infrastructure
&lt;/h2&gt;

&lt;p&gt;WAIaaS is a self-hosted Wallet-as-a-Service built for AI agents, but its architecture maps directly onto automated trading bot requirements. Let's walk through what matters for Pendle trading specifically.&lt;/p&gt;

&lt;h3&gt;
  
  
  15 DeFi Protocol Providers Out of the Box
&lt;/h3&gt;

&lt;p&gt;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. Pendle is directly integrated — your bot calls the action API, not a hand-rolled contract interaction layer you have to maintain.&lt;/p&gt;

&lt;p&gt;For a Pendle yield optimization strategy that also hedges on Drift perpetuals or uses Aave v3 for leverage, all of that is accessible through a single wallet and a single session token. One bot, one API, multiple protocols.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gas Conditional Execution
&lt;/h3&gt;

&lt;p&gt;This one matters a lot for profitability. WAIaaS includes gas conditional execution — transactions execute only when the gas price meets your configured threshold. For a yield arb strategy where your edge is measured in basis points, paying 3x the expected gas because you submitted during a network spike can erase the trade entirely.&lt;/p&gt;

&lt;p&gt;Configure your gas threshold at the infrastructure level and let the pipeline handle it. Your bot submits the intent; WAIaaS waits for the right conditions.&lt;/p&gt;

&lt;h3&gt;
  
  
  7-Stage Transaction Pipeline
&lt;/h3&gt;

&lt;p&gt;Every transaction runs through a 7-stage pipeline: validate, auth, policy, wait, execute, confirm, and a final stages step. For a trading bot, this means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Validate&lt;/strong&gt; catches malformed transactions before they touch the network&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auth&lt;/strong&gt; verifies your session is valid — no surprise authorization failures mid-trade&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policy&lt;/strong&gt; applies your risk rules before execution — spending limits, allowed tokens, contract whitelists&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wait&lt;/strong&gt; handles gas conditions and time delays&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execute&lt;/strong&gt; submits to chain&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confirm&lt;/strong&gt; tracks the transaction to completion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You get this pipeline for free. Your bot doesn't need to implement retry logic, gas polling, or confirmation tracking — the daemon handles it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Policy Engine as a Risk Management Layer
&lt;/h3&gt;

&lt;p&gt;The policy engine is where WAIaaS becomes genuinely useful for serious trading systems. 21 policy types, 4 security tiers (INSTANT, NOTIFY, DELAY, APPROVAL), and default-deny enforcement.&lt;/p&gt;

&lt;p&gt;For a Pendle bot, relevant policies include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SPENDING_LIMIT&lt;/strong&gt; — 4-tier security based on transaction amount. Small routine trades execute instantly; large position entries require your approval via WalletConnect or Telegram&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CONTRACT_WHITELIST&lt;/strong&gt; — default-deny contract whitelist. Your bot can only interact with Pendle contracts and the other protocols you explicitly list. No scope creep, no accidental interactions with unvetted contracts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ALLOWED_TOKENS&lt;/strong&gt; — default-deny token whitelist. The bot can only transact in assets you've approved&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PERP_MAX_LEVERAGE&lt;/strong&gt; — if your strategy involves leveraged positions on Drift, cap the leverage at the infrastructure level&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PERP_MAX_POSITION_USD&lt;/strong&gt; — hard cap on position size in USD, enforced before execution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LENDING_LTV_LIMIT&lt;/strong&gt; — max loan-to-value ratio for lending positions, relevant if your strategy uses Aave v3 leverage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RATE_LIMIT&lt;/strong&gt; — max transactions per period, useful for preventing runaway bots from draining gas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's how you configure a spending limit for a Pendle trading session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "walletId": "&amp;lt;wallet-uuid&amp;gt;",
    "type": "SPENDING_LIMIT",
    "rules": {
      "instant_max_usd": 100,
      "notify_max_usd": 500,
      "delay_max_usd": 2000,
      "delay_seconds": 900,
      "daily_limit_usd": 5000
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trades under $100 execute immediately. Trades between $100-$500 execute and notify you. Trades between $500-$2000 queue for 15 minutes (giving you time to cancel). Anything over $2000 requires your explicit approval. This is risk management built into the wall, not the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Your Pendle Bot
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Spin Up the Daemon
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; waiaas &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 127.0.0.1:3100:3100 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; waiaas-data:/data &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;WAIAAS_AUTO_PROVISION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/minhoyoo-iotrust/waiaas:latest

&lt;span class="c"&gt;# Retrieve auto-generated master password&lt;/span&gt;
docker &lt;span class="nb"&gt;exec &lt;/span&gt;waiaas &lt;span class="nb"&gt;cat&lt;/span&gt; /data/recovery.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The daemon binds to localhost by default. For a trading bot running on the same machine, this is the right posture — don't expose it externally.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Create a Wallet and Session
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a trading wallet&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/wallets &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "pendle-bot", "chain": "evm", "environment": "mainnet"}'&lt;/span&gt;

&lt;span class="c"&gt;# Create a session token for the bot process&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/sessions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"walletId": "&amp;lt;wallet-uuid&amp;gt;"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The session token (&lt;code&gt;wai_sess_...&lt;/code&gt;) is what your bot uses for all transaction operations. The master password stays out of the bot process entirely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Configure Your Risk Policies
&lt;/h3&gt;

&lt;p&gt;Apply your CONTRACT_WHITELIST before funding the wallet. This ensures the bot can only touch the contracts you've vetted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://127.0.0.1:3100/v1/policies &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Master-Password: my-secret-password"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "walletId": "&amp;lt;wallet-uuid&amp;gt;",
    "type": "CONTRACT_WHITELIST",
    "rules": {
      "contracts": [
        {"address": "&amp;lt;pendle-router-address&amp;gt;", "name": "Pendle Router", "chain": "ethereum-mainnet"},
        {"address": "&amp;lt;pendle-market-address&amp;gt;", "name": "Pendle Market", "chain": "ethereum-mainnet"}
      ]
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Write Your Bot Using the TypeScript SDK
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSError&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@waiaas/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WAIaaSClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WAIAAS_BASE_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3100&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WAIAAS_SESSION_TOKEN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;executePendleStrategy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Check balance before attempting trade&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBalance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Balance: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Dry-run first to validate the transaction will pass policy checks&lt;/span&gt;
  &lt;span class="c1"&gt;// and simulate execution before committing gas&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dryRun&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendToken&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TRANSFER&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pendle-contract-address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dryRun&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Dry run status: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;dryRun&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Execute the actual Pendle action&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendToken&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TRANSFER&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pendle-contract-address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Poll for confirmation&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;POLL_TIMEOUT_MS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;POLL_TIMEOUT_MS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;txStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;txStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;COMPLETED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Confirmed: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;txStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;txHash&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;txStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FAILED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Failed: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;txStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dry-run API is particularly valuable for yield trading: simulate the transaction before committing gas, verify it passes all policy checks, and confirm the expected output before execution. This is a call to &lt;code&gt;POST /v1/transactions/send&lt;/code&gt; with &lt;code&gt;"dryRun": true&lt;/code&gt; in the payload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Policy Denials Gracefully
&lt;/h2&gt;

&lt;p&gt;Your bot will hit policy denials. That's the point — the policy engine is catching things before they become problems. Handle them explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendToken&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;WAIaaSError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`API Error: [&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;] &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// error.code examples: INSUFFICIENT_BALANCE, POLICY_DENIED, TOKEN_EXPIRED&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POLICY_DENIED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Log the denied trade, alert, wait for manual approval&lt;/span&gt;
      &lt;span class="c1"&gt;// Do NOT retry automatically — that's how bots get into trouble&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The error response format gives you a structured code, message, domain, and retryable flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"POLICY_DENIED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Transaction denied by SPENDING_LIMIT policy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"POLICY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"retryable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Non-retryable errors like &lt;code&gt;POLICY_DENIED&lt;/code&gt; should trigger an alert to your monitoring system, not a retry loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-Protocol Yield Strategies
&lt;/h2&gt;

&lt;p&gt;If your Pendle strategy involves more than just PT/YT swaps — say, borrowing on Aave v3 to lever up a yield position, then hedging duration risk on Drift — WAIaaS handles all of this through the actions API. The same session token, the same wallet, the same policy rules applying across every protocol.&lt;/p&gt;

&lt;p&gt;The 15 integrated providers cover the main protocols a yield optimizer would touch. Bridging is covered by LI.FI and Across if your strategy spans chains. Liquid staking via Lido (EVM) and Jito (Solana) is available if part of your yield stack involves staked assets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observability and Human Override
&lt;/h2&gt;

&lt;p&gt;For a trading bot running unattended, observability is not optional. WAIaaS provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Incoming transaction monitoring&lt;/strong&gt; with real-time notifications for deposits — you know when funds arrive&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WalletConnect integration&lt;/strong&gt; for owner approval of APPROVAL-tier transactions — your phone becomes the hardware approval step for large trades&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transaction history&lt;/strong&gt; queryable via the SDK with &lt;code&gt;listTransactions()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;39 REST API route modules&lt;/strong&gt; exposed for custom monitoring integrations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAPI 3.0 spec&lt;/strong&gt; at &lt;code&gt;/doc&lt;/code&gt; and interactive reference at &lt;code&gt;/reference&lt;/code&gt; — useful when building custom dashboards&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interactive API reference at &lt;code&gt;http://127.0.0.1:3100/reference&lt;/code&gt; is worth bookmarking during development. You can test endpoints directly against your running instance, which speeds up the iteration loop considerably.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start Checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Deploy the daemon&lt;/strong&gt; via Docker with &lt;code&gt;WAIAAS_AUTO_PROVISION=true&lt;/code&gt; — takes about 60 seconds&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create a dedicated trading wallet&lt;/strong&gt; — never use a wallet for multiple bots&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set up CONTRACT_WHITELIST and SPENDING_LIMIT policies before funding&lt;/strong&gt; — default-deny means nothing executes until you explicitly allow it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test with dry-run&lt;/strong&gt; — use &lt;code&gt;dryRun: true&lt;/code&gt; to validate your transaction logic before going live&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure WalletConnect&lt;/strong&gt; for APPROVAL-tier override — your kill switch for large positions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The 20-command CLI (&lt;code&gt;waiaas quickset&lt;/code&gt;, &lt;code&gt;waiaas start&lt;/code&gt;, &lt;code&gt;waiaas status&lt;/code&gt;, etc.) handles the initialization flow if you prefer not to script the API directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The WAIaaS codebase is open-source and self-hosted — you control your keys, your data, and your infrastructure. Start with the GitHub repository to review the policy engine implementation and transaction pipeline before deploying capital:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/minhoyoo-iotrust/WAIaaS" rel="noopener noreferrer"&gt;https://github.com/minhoyoo-iotrust/WAIaaS&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Official site&lt;/strong&gt;: &lt;a href="https://waiaas.ai" rel="noopener noreferrer"&gt;https://waiaas.ai&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interactive API docs at &lt;code&gt;/reference&lt;/code&gt; are the fastest way to understand the full surface area once your daemon is running. With 39 REST API routes, 45 MCP tools, and 21 policy types, there's significant depth to explore as your strategy matures — but the core flow for a Pendle trading bot is straightforward enough to have running in an afternoon.&lt;/p&gt;

</description>
      <category>defi</category>
      <category>ethereum</category>
      <category>trading</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
