Architecture
System Overview
How ClawdGo works end-to-end — from agent API call to on-chain settlement.
Stack
| Layer | Technology |
|---|---|
| Blockchain | Solana Mainnet |
| Smart Contract | Anchor (Rust) |
| Stablecoin | USDC (SPL Token) |
| Circle Integration | Circle Web3 Services API |
| API Backend | Node.js / TypeScript |
| API Framework | Fastify |
| Database | PostgreSQL — accounts, policies, audit log |
| Queue | BullMQ + Redis — async transaction processing |
| Frontend Dashboard | Next.js + TypeScript |
| Auth | API keys (HMAC-signed) + operator OAuth2 |
| Monitoring | Datadog + custom Solana RPC health checks |
| SDK (primary) | TypeScript |
| SDK (secondary) | Python (Phase 3) |
Request flow
A transfer from an AI agent to an on-chain address follows this path:
text
Agent (OpenClaw / direct HTTP)
│
▼
ClawdGo REST API (Fastify / Node.js)
│ 1. Authenticate agent key
│ 2. Validate request schema
│ 3. Check idempotency key
│
▼
Policy Engine
│ 4. Load spending policy from PostgreSQL + on-chain PDA
│ 5. Enforce: single-transfer limit, daily spend window,
│ counterparty allowlist, memo requirement, pause flag
│ → Reject here if any rule fails
│
▼
Transaction Builder
│ 6. Construct Solana SPL token transfer instruction
│ 7. Sign with PDA authority keypair
│
▼
BullMQ Queue (async submission)
│ 8. Submit transaction to Solana RPC
│ 9. Poll for finality confirmation
│
▼
Solana Mainnet
│ 10. On-chain settlement (~400ms)
│
▼
Post-processing
│ 11. Write settled transfer to PostgreSQL audit log
│ 12. Update daily spend counter
│ 13. Fire webhooks
│
▼
Response to Agent
transfer_id, tx_signature, status: "settled", settled_at
On-chain program structure
The ClawdGo Solana program, written in Anchor (Rust), owns all agent account PDAs:
text
ClawdGo Program (on-chain)
├── Agent PDA (one per agent account)
│ ├── USDC SPL token account
│ ├── Spending policy state
│ │ ├── max_single_transfer
│ │ ├── max_daily_spend
│ │ ├── allowed_counterparties[]
│ │ ├── require_memo
│ │ └── paused
│ └── Transaction nonce (replay protection)
└── Operator registry
└── Maps each agent PDA to an operator public key
Policy rules stored in the PDA are enforced by the program before any token transfer instruction is executed. A compromised API layer cannot bypass these constraints — they are validated at the program level.
Database schema (simplified)
accounts
| Column | Type | Notes |
|---|---|---|
account_id | varchar | Primary key. Format: acct_* |
operator_id | uuid | FK to operators table |
name | varchar | Display name |
solana_address | varchar(44) | Base58 PDA address |
usdc_token_account | varchar(44) | Base58 SPL token account |
status | enum | active | paused |
created_at | timestamptz |
transfers
| Column | Type | Notes |
|---|---|---|
transfer_id | varchar | Primary key. Format: txn_* |
account_id | varchar | FK to accounts |
to_address | varchar(44) | Recipient SPL address |
amount_usdc | numeric(20,6) | |
memo | varchar(200) | Nullable |
idempotency_key | varchar(128) | Unique per account |
tx_signature | varchar(88) | Nullable until settled |
status | enum | pending | settled | rejected | failed |
rejection_reason | varchar | Nullable |
created_at | timestamptz | |
settled_at | timestamptz | Nullable |
Async transaction processing
Transfer submissions are processed via BullMQ + Redis. The API response is synchronous — ClawdGo waits for on-chain finality before returning. The queue handles:
- RPC retry on transient Solana network errors
- Confirmation polling with timeout and fallback
- Webhook fan-out after settlement