Inspiration

DAO treasuries fail not because of bad intent but because a single AI agent has no one to argue with. We wanted to build a system where agents disagree, debate, and veto each other before a single satoshi moves — mirroring how real governance committees work.

What it does

SyndiChain is a five-agent AI swarm that manages crypto treasuries on the Somnia blockchain:

  1. Manager (Qwen-Plus) decomposes a plain-English goal into parallel sub-tasks
  2. Analyst (Qwen-Turbo) fetches live yield pools from Somnia Exchange and Potion Swap DEX
  3. Risk (Qwen-Turbo) queries SomniaAgentRiskOracle.sol on-chain and vetoes anything with risk score > 70
  4. Debate protocol — 2 rounds of LLM-powered arguments if Analyst and Risk disagree; Manager adjudicates
  5. Human escalation — deadlocked debates surface to the user with both sides presented
  6. Execution (Qwen-Turbo) encodes a gas-optimised Multicall3 batch via Somnia Agent Kit + viem
  7. Compliance verifies against TreasuryPolicy.sol — daily limits, allowlists, multisig thresholds
  8. Human approval → transaction broadcast to Somnia Testnet

Alongside the swarm, a keeper bot calls batchUpdateStreams() every 10 seconds on StreamPay.sol so recipients can withdraw real-time STT streams without transactions reverting.

How we built it

  • Next.js 14 App Router with output: 'standalone' for Docker deployment
  • Qwen-Plus / Qwen-Turbo via Alibaba Cloud DashScope (dashscope-intl.aliyuncs.com/compatible-mode/v1)
  • viem for all on-chain reads and writes (Somnia Testnet, Chain ID 50312)
  • Somnia Agent Kit Multicall3 SDK for batched transaction encoding
  • ioredis hybrid session store — in-memory for speed, Redis for persistence across restarts
  • Multi-stage Dockerfile — Next.js standalone + keeper compiled to CommonJS via separate tsconfig
  • GitHub Actions CI/CD — typecheck → Docker build/push → SSH deploy via docker compose
  • Smart contracts on Somnia Testnet: TreasuryPolicy.sol, SomniaAgentRiskOracle.sol, StreamPay.sol, StreamFactory.sol, StreamKeeper.sol, Multicall3

Challenges we faced

  • viem v2 discriminated unionmaxFeePerGas and gasPrice cannot coexist in sendTransaction; required a typed branch to satisfy the compiler
  • ioredis in Next.js standalone — webpack externals are not bundled, so ioredis and its peer dependencies had to be manually copied into standalone/node_modules/ in the Dockerfile
  • Stream withdrawals revertingStreamPay.sol stores realTimeBalance in contract storage, only updated by batchUpdateStreams. The keeper bot running every 10s solved this entirely
  • EIP-7702 type bleed — viem v2.19+ added authorizationList to the readContract union, requiring a cast to bypass until the Agent Kit types are updated

What we learned

How to build production-grade multi-agent systems: structured debate protocols, hybrid persistence strategies, and the subtle differences between testnet RPC behaviour and what the ABI expects. Qwen-Plus for reasoning-heavy tasks and Qwen-Turbo for fast structured extraction was the right split — it kept latency under 10 seconds for the full swarm pipeline.

What's next

  • Multisig threshold enforcement via on-chain governance votes
  • Agent memory across sessions using vector embeddings

Built With

Share this project:

Updates