Mandate.Finance
Founding Product Engineer & Technical Co-founder · Mar 2026 – present
Visit websiteProblem
Build a DeFi platform where autonomous AI agents manage real on-chain funds while preserving user self-custody, gasless UX and real-time oversight. Strong guardrails are mandatory — on-chain irreversibility is unforgiving.
Architecture
Multi-repo platform across 11 workspaces — 6 runtime services on GCP Cloud Run (`backend`, `agent-executor`, `signing-service`, `mcp-gateway`, `jobs`, `stats-api`), a Foundry smart-contract suite (ERC-7821 `KairosBatchExecutor` + UUPS `KairosBillingTreasury` deployed at the same address on Base, Arbitrum and Ethereum mainnet via CREATE2), a private Postgres 16 with 59 versioned SQL migrations, two Next.js 15 frontends (`ui` and `landing`), an SSE-based agent test harness, and a public docs site. Agent layer: a single LLM loop in `agent-executor` parameterised by 7 job types (deploy / scan / trade / rebalance / report / exit / chat) and ~8 strategy templates stored in Postgres — per-task tool whitelists, code-level SELL GUARDs and per-vault prompt overrides at three resolution tiers. The MCP gateway (Python + FastAPI) brokers all read-only DeFi data via JSON-RPC over stdio with request-id correlation to prevent cross-tenant pollution; the signing-service is the sole custodian of per-agent EOAs (AES-256-GCM keystore in Postgres) and the only path to chain writes — every write rides on EIP-7702 Type-4 transactions sponsored by a single hot wallet, with a Redis-backed atomic nonce counter so multi-instance Cloud Run scale-out is safe.
Decisions
Single agent loop + 7 job types + 8 strategy templates
One LLM loop (`runAgentLoop` in `agent-executor/src/llm/loop.ts`), one source of truth for prompts (`strategy_templates` table in Postgres), per-job-type tool whitelists (deploy / scan / trade / rebalance / report / exit / chat) and three-tier per-vault prompt overrides. Adding a new strategy is a SQL row, not a service. This replaces the 'multi-agent (evaluator/researcher/manager/executor)' framing — the real story is runtime parameterisation, not a role topology.
Three layers of defense against deploy-step hallucinations
When small models hallucinated 'Deployment Complete' without calling `register_vault`, the platform deployed second on-chain vaults and stranded funds. Three layers: (1) receipt-parsed auto-register inside the `deploy_vault` branch using the signing-service's `VaultCreated` topic, (2) idempotent `registerVaultInDb` that short-circuits on duplicate-active, (3) post-loop validator that overrides the LLM's claimed decision to `'error'` when `getVaultStatus(vaultId)` shows pending/null.
Code-level SELL GUARD the LLM cannot bypass
On trader vaults (`category.endsWith('-trader')`), when `factor_swap_openocean` would sell the trading token for the denominator the executor calls `simulate_exit` server-side, computes cost basis from `vault_trades`, and blocks the swap if PnL exceeds the stop-loss threshold. The LLM cannot retry or argue — it only sees `SELL_BLOCKED`. Origin: deepseek bypassed the prompt-level mandate three times → enforcement moved into code.
Per-agent EOA custody + sponsor pays gas
Backend never sees plaintext keys: each agent EOA is generated and AES-256-GCM-encrypted inside `signing-service/src/keystore.ts`, persisted in `signing_keystores`, decrypted into a 5-min TTL cache. Users sign EIP-7702 authorizations delegating to a single batch executor at the same CREATE2 address on three chains; the platform's hot wallet pays gas. Result: gasless self-custody UX with zero trusted wallet relayers in between.
Atomic sponsor nonce via Redis EVAL Lua
The in-process `SponsorMutex` only serializes a single replica; multi-instance Cloud Run scale-out could race on `getTransactionCount(sponsor, 'pending')`. Fix: Redis-backed atomic counter `sponsor-nonce:{chainId}` driven by an `EVAL` Lua script (`GET → SET(n+1) → return n` atomically), with cold-start path that reads chain nonce only when the key is absent. Fallback to in-memory `Map` when Redis is unavailable, with warn log for ops.
Multi-tenant MCP-over-stdio with request-id correlation
Naive JSON-RPC over a single stdin/stdout pipe is unsafe for a multi-tenant gateway: a single `console.log` from any transitive dep polluted the response stream and produced cross-vault data scrambling (observed in production 2026-04-15 — agent A saw agent B's `factor_vault_analytics` result). The gateway loops on `stdout.readline()` discarding any frame whose `id` doesn't match the in-flight request — the only durable defence against this class of multi-tenant bug.
In-process leverage watchdog (HF<1.2 emergency exit)
`agent-executor/src/leverage-watchdog.ts`: 60s `setInterval` started post-`app.listen`, stopped on SIGTERM. Each tick: (1) load vaults with `mode: leverage`, (2) read `min(healthFactor)` across Aave + Morpho via `factor_vault_analytics`, (3) on `HF < config.minHealthFactor` insert a `custom_jobs` row with the exit-leverage prompt scheduled `* * * * *`, (4) below the hard 1.2 floor emit an EMERGENCY-prefixed prompt and `log.error`. Single-replica Cloud Run + in-process `inFlight` guard prevents concurrent ticks.
Gasless UX with self-custody
Privy + EIP-7702 Type-4 sponsored transactions + ERC-7821 batch executor: users never touch a private key and never pay gas, while keeping self-custody. Cross-chain via LiFi feels like a single operation.
Cost-driven multi-provider LLM
Multi-provider abstraction in production (DeepInfra as default, OpenRouter as backup). Anthropic stays for review/research, not in the production LLM router. Migration from Ollama Cloud to DeepInfra cut cost ~50%. Cost-driven pattern, not capability-driven.