Components
Client
- Next.js 14 App Router, React 18, TypeScript, Tailwind CSS, Framer Motion
- Privy auth — Google OAuth + embedded wallet, or wallet login (MetaMask / Rabby as the signing key), plus a signature-free backup-key link
- Wallets are Safe multisigs with computed profiles — starter / guarded / protected / detached
- Signs standard SafeTxs (EIP-712), 1 of the threshold, then POSTs to
/queue - WalletConnect v2 — acts as a wallet for DApps; requests flow through the same pipeline
- Portfolio via Zerion API (live balances, prices, 24h change)
Server
- Express with TypeScript (
tsxfor dev, PM2 for production) - Owns canonical state: user records, the transaction queue, notifications (Telegram + email), and the Supabase (Postgres) database — the runtime never touches any of these directly
- Hard-validates every proposal: signature recovery against the recorded owner set, threshold arithmetic for screening-off, and owner-management transitions
- Sends every screening and signing request to the runtime as a job over the Runtime API (bearer-authenticated, fail-closed) and applies the verdicts that come back — exactly once, atomically
- Mirrors every proposal to the Safe Transaction Service so it appears in app.safe.global at 1/2; a
safeSyncworker reconciles transactions confirmed or executed there directly - Relays execution: a dedicated sponsor EOA submits
execTransactionand pays BNB gas — relay-only (no agent signature) whenever user signatures meet the threshold - Derives addresses server-side through a versioned registry
Agent Runtime
- A separate worker process — the security core of the system
- Screens every proposal with the shared risk engine, from inputs the server assembles into the job itself
- Holds the only signing key, behind a verifying authority: before signing anything it independently recomputes the transaction hash, reads the Safe’s owners and nonce from chain, and requires its own record of having screened this exact transaction — a claim in the request is not evidence
- Keeps its own append-only decision log; has no database credential and opens no inbound port (a localhost health endpoint is its only listener)
- Fail-closed: if the runtime is down, screened transactions simply wait — nothing executes without a verdict, and flows that never need the agent’s signature (relay-only, backup co-sign) continue unaffected
Conversational Agent
- NanoBot/Hermes skill pack — Telegram commands, review dialogue, deep analysis (GoPlus + Honeypot.is) on REVIEW-tier transactions
- Sends every command through the server’s authenticated API (via MCP) — it holds no keys and touches no state directly
