Inspiration
Agents settling deals with each other need to verify solvency — "can this counterparty actually cover the trade?" — without either side revealing their full balance sheet. Current approaches either disclose raw balances (a privacy leak) or rely on trusted third parties (a centralization risk). Neither works for an agent economy where counterparties are ephemeral, trust is minimal, and every intermediary is a new attack surface.
Midnight Network lets us solve this properly: write the privacy guarantee into the circuit itself, so the balance physically cannot leak.
What it does
Verdict is a zero-knowledge solvency proof system on Midnight. A requester sets a deal ID and a threshold. The counterparty's actual balance enters a Compact ZK circuit as a witness — read locally, compared inside the proof, never serialized. Only a single boolean (1 = solvent, 0 = insufficient) hits the ledger alongside the deal metadata.
Privacy invariant: of 6 ledger fields per verdict, zero are the actual balance. The circuit has no code path that can disclose it.
The project ships with an interactive CLI, a dark-themed web UI with Lace wallet integration, a REST API for agent-to-agent calls, and a natural-language front door via OpenRouter tool calls.
How we built it
- Compact v0.23 language, v0.31 compiler — ZK circuit with
witness+disclosepattern - Midnight JS SDK (
[email protected],[email protected],[email protected]) — deploy and interact - Midnight Lace wallet (
mnLaceDApp Connector API) — wallet connectivity in the web UI - Next.js 16 + Tailwind v4 — dark-themed frontend
- Docker Compose — local devnet with node, indexer, and proof-server
- OpenRouter GPT-4o — natural-language agent front door
Challenges we ran into
The wallet SDK's sync algorithm requires processing all ~1.3M historical ZswapEvents from genesis before isSynced returns true for a fresh wallet. At ~70 events/sec that's ~5 hours — blocking deployment on PreProd testnet. The contract runs identically on local devnet (which has ~0 historical events). We've documented the root cause and filed it with the Midnight team.
Also hit a coinNonces.difference is not a function error on shielded wallet state restore — handled by falling back to fresh sync.
Accomplishments that we're proud of
- Full end-to-end flow working on local devnet: deploy → CLI → verdict on-chain → web UI → REST API → NL agent
- Real ZK circuit with verifiable on-chain transactions — every SOLVENT verdict has a real tx hash and block height
- Privacy guarantee enforced at the circuit level, not the UI level — there is literally no code path that puts the balance on-chain
- Multiple interfaces — CLI, web UI, REST API, natural language — all hitting the same deployed contract
What we learned
How Midnight's Compact circuit compilation, proving, and on-chain settlement work end-to-end. How witness vs disclose maps to shielded vs public contract state. How the wallet SDK's indexer sync works (and where it falls short for fresh wallets on networks with deep history).
What's next for Verdict
- Deploy to Midnight PreProd and Mainnet once the wallet SDK sync issue is resolved
- Multi-threshold solvency tiers (silver / gold / platinum)
- x402 payment wiring so agents pay per verdict call via micropayments
- Verdict history page querying past results directly from the ledger
Built With
- compact
- next.js
- tailwind
Log in or sign up for Devpost to join the conversation.