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 + disclose pattern
  • Midnight JS SDK ([email protected], [email protected], [email protected]) — deploy and interact
  • Midnight Lace wallet (mnLace DApp 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
Share this project:

Updates

Submission history