Giving an AI agent a wallet without guardrails is like giving a toddler a credit card β technically functional, potentially catastrophic. If you're building AI agents that interact with crypto wallets, the security model you choose isn't an afterthought. It's the difference between a useful autonomous system and one that drains your funds on a bad inference.
This post is about exactly how WAIaaS handles that problem. Not vague promises about "enterprise-grade security" β specific mechanisms, specific policy types, and specific code you can run today.
Let's be honest about what can go wrong when you give an AI agent wallet access:
None of these require a malicious agent. They can all happen with a well-intentioned model operating outside the boundaries you forgot to define. The solution isn't to avoid giving agents wallet access β it's to define exactly what they're allowed to do, and nothing more.
WAIaaS approaches this with three distinct security layers, a default-deny policy engine with 21 policy types across 4 security tiers, and multiple channels for human approval when transactions exceed your defined thresholds.
The first layer is role separation. WAIaaS uses three authentication methods that map to three distinct principals:
masterAuth (Argon2id) β The system administrator role. Creates wallets, manages sessions, configures policies. This credential never touches the agent.
sessionAuth (JWT HS256) β The AI agent's credential. Scoped to a specific wallet, carries TTL and renewal limits. This is what your agent uses at runtime.
ownerAuth (SIWS/SIWE signature) β The fund owner. Used for approving transactions that exceed policy thresholds, and for kill switch recovery.
-H "X-Master-Password: my-secret-password"
-H "Authorization: Bearer wai_sess_eyJhbGciOiJIUzI1NiJ9..."
-H "X-Owner-Signature: <ed25519-or-secp256k1-signature>"
-H "X-Owner-Message: <signed-message>"
Your agent only ever holds the session token. Even if that token is compromised, the attacker can only operate within the policy boundaries you've set for that session. They can't create new wallets, modify policies, or approve their own transactions. Sessions also carry per-session TTL, maximum renewal counts, and absolute lifetime limits β so a leaked token has a hard expiry.
This is where the real work happens. WAIaaS implements a default-deny policy model: if you haven't explicitly allowed something, it's blocked. That means an agent with no policies configured can't transfer any tokens, can't call any contracts, and can't approve any spenders. The safe state is locked down, not open.
Policies are created by the administrator (masterAuth) and enforced by the daemon before any transaction reaches the network.
Every policy evaluation produces a tier assignment, and that tier determines what happens next:
INSTANT β Execute immediately, no notification
NOTIFY β Execute immediately, send notification to owner
DELAY β Queue for delay_seconds, then execute (cancellable during window)
APPROVAL β Require explicit human approval via WalletConnect, Telegram, or Push
The SPENDING_LIMIT policy maps transaction amounts to these tiers:
curl -X POST http://localhost:3100/v1/policies \
-H 'Content-Type: application/json' \
-H 'X-Master-Password: <password>' \
-d '{
"walletId": "<wallet-uuid>",
"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
}
}'
With this configuration: transactions under $10 go through immediately. $10β$100 go through but you get notified. $100β$1,000 are queued for 5 minutes β long enough to cancel if something looks wrong. Anything over $1,000 requires your explicit approval. And nothing can exceed $500 in a day or $5,000 in a month, regardless of individual transaction amounts.
That's a meaningful security boundary defined in a single API call.
The SPENDING_LIMIT is the most intuitive, but the full policy set covers nearly every attack surface in crypto agent interactions:
Token and asset controls:
ALLOWED_TOKENS
β Default-deny token whitelist. Your agent can only transfer tokens you've explicitly listed. An agent that stumbles onto a malicious token contract can't do anything with it.APPROVE_AMOUNT_LIMIT
β Caps the maximum token approval amount. Blocks unlimited allowances, which are a common attack vector.APPROVED_SPENDERS
β Whitelist of addresses that can receive token approvals. Your agent can't approve a random contract.APPROVE_TIER_OVERRIDE
β Forces approval transactions into a higher security tier regardless of amount. Useful when you want human review on all approvals.Contract and method controls:
CONTRACT_WHITELIST
β Default-deny contract call whitelist. Your agent can only interact with contracts you've named.METHOD_WHITELIST
β Allowed function selectors. You can permit swap()
on Jupiter while blocking withdrawAll()
on the same protocol.Network and address controls:
WHITELIST
β Allowed recipient addresses for transfers.ALLOWED_NETWORKS
β Restricts the agent to specific chains. An Ethereum agent has no business touching Solana, and vice versa.Rate and time controls:
RATE_LIMIT
β Maximum transactions per period (hourly, daily).TIME_RESTRICTION
β Allowed hours of operation. Your trading agent doesn't need to execute at 3am.DeFi-specific controls:
LENDING_LTV_LIMIT
β Maximum loan-to-value ratio for lending positions. Prevents your agent from over-leveraging a lending position.LENDING_ASSET_WHITELIST
β Allowed assets for lending protocols.PERP_MAX_LEVERAGE
β Maximum leverage for perpetual futures positions on Hyperliquid and similar protocols.PERP_MAX_POSITION_USD
β Maximum position size in USD.PERP_ALLOWED_MARKETS
β Approved markets for perpetual trading.VENUE_WHITELIST
β Allowed trading venues across protocols.ACTION_CATEGORY_LIMIT
β Caps on DeFi action categories.Protocol-specific controls:
X402_ALLOWED_DOMAINS
β Whitelist for x402 HTTP payment domains. Your agent can auto-pay API calls, but only to domains you've approved.ERC8128_ALLOWED_DOMAINS
β Allowed domains for ERC-8128 HTTP signing.REPUTATION_THRESHOLD
β Minimum ERC-8004 onchain reputation score required for agent interactions.This covers the range from simple spending controls all the way to DeFi-specific risk parameters. You don't have to use all 21 β but they're there when you need them.
Here's what the token whitelist looks like in practice:
curl -X POST http://localhost:3100/v1/policies \
-H 'Content-Type: application/json' \
-H 'X-Master-Password: <password>' \
-d '{
"walletId": "<wallet-uuid>",
"type": "ALLOWED_TOKENS",
"rules": {
"tokens": [
{
"address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"symbol": "USDC",
"chain": "solana"
}
]
}
}'
If your agent tries to transfer any token not on this list, the daemon returns a policy denial before the transaction is ever signed:
{
"error": {
"code": "POLICY_DENIED",
"message": "Transaction denied by SPENDING_LIMIT policy",
"domain": "POLICY",
"retryable": false
}
}
The agent gets a structured error it can handle. The transaction never leaves your node.
The third layer handles the APPROVAL tier β transactions that exceed your defined thresholds and require a human decision. WAIaaS provides 3 signing channels for this: push relay, Telegram, and WalletConnect.
When a transaction hits the APPROVAL tier, it's queued. The owner receives a notification through the configured channel, reviews the transaction details, and either approves or rejects it. The daemon holds the transaction in the pipeline until that decision arrives.
curl -X POST http://127.0.0.1:3100/v1/transactions/<tx-id>/approve \
-H "X-Owner-Signature: <ed25519-or-secp256k1-signature>" \
-H "X-Owner-Message: <signed-message>"
Approval requires a valid owner signature β the kind that comes from a hardware wallet or mobile signing app, not from the daemon itself. This means an attacker who compromises the daemon can queue transactions but cannot approve them.
Before any transaction reaches a network, it passes through a 7-stage pipeline: validate β auth β policy β wait β execute β confirm. The policy stage is where your 21 policy types are evaluated. If any policy returns a denial, the pipeline stops there. The transaction never reaches the execute stage.
This sequential architecture means policies aren't advisory β they're enforced at the infrastructure level, not in your application code.
One more safety mechanism worth knowing about: the dry-run API. Before committing any transaction, your agent can simulate it to see what would happen:
curl -X POST http://127.0.0.1:3100/v1/transactions/send \
-H "Content-Type: application/json" \
-H "Authorization: Bearer wai_sess_<token>" \
-d '{
"type": "TRANSFER",
"to": "recipient-address",
"amount": "0.1",
"dryRun": true
}'
The simulation runs the full pipeline β including policy evaluation β without broadcasting to the network. Your agent can check whether a transaction would be approved, denied, or queued before actually submitting it. This is useful for pre-flight validation in agent logic and for testing policy configurations without real funds.
Step 1: Start the daemon
npm install -g @waiaas/cli
waiaas init
waiaas start
Step 2: Create a wallet
curl -X POST http://127.0.0.1:3100/v1/wallets \
-H "Content-Type: application/json" \
-H "X-Master-Password: my-secret-password" \
-d '{"name": "trading-wallet", "chain": "solana", "environment": "mainnet"}'
Step 3: Set a spending limit policy
curl -X POST http://127.0.0.1:3100/v1/policies \
-H "Content-Type: application/json" \
-H "X-Master-Password: my-secret-password" \
-d '{
"walletId": "<wallet-uuid>",
"type": "SPENDING_LIMIT",
"rules": {
"instant_max_usd": 100,
"notify_max_usd": 500,
"delay_max_usd": 2000,
"delay_seconds": 900,
"daily_limit_usd": 5000
}
}'
Step 4: Create a session for your agent
curl -X POST http://127.0.0.1:3100/v1/sessions \
-H "Content-Type: application/json" \
-H "X-Master-Password: my-secret-password" \
-d '{"walletId": "<wallet-uuid>"}'
Step 5: Your agent checks balance and operates within policy
curl http://127.0.0.1:3100/v1/wallet/balance \
-H "Authorization: Bearer wai_sess_eyJhbGciOiJIUzI1NiJ9..."
From this point, the session token is the only credential your agent holds. Everything above the $100 instant threshold requires your attention. The agent operates within defined parameters, and you get notified or asked for approval on anything that exceeds them.
The policy engine is documented interactively at http://127.0.0.1:3100/reference
once your daemon is running β it's an OpenAPI 3.0 spec with a live Scalar UI where you can explore all 39 route modules and test requests directly. If you want to dig into the architecture before deploying, the codebase is fully open source and the monorepo structure (15 packages) makes it readable without needing to understand everything at once.
Start with the GitHub repo to review the security model before running anything in production: https://github.com/minhoyoo-iotrust/WAIaaS. Full documentation and the hosted version are at https://waiaas.ai.