We will be undergoing planned maintenance on Oct 7th 6:00AM UTC / Oct 7th 2:00AM ET

NightPool

Trade in the dark. Settle in the light. A dark-pool trading desk + sealed-bid batch auction on Midnight.

Inspiration

In June 2025, trader James Wynn's billion-dollar Hyperliquid positions were liquidation-hunted in public, and CZ told 10M followers: "now may be a good time for someone to launch a dark-pool perpetuals DEX." On every public DEX your size, strategy, and balance are a broadcast — whales get hunted, strategies get copy-traded, blocks get front-run. TradFi solved this decades ago with dark pools. Midnight's own Request-for-Startups asks for exactly this ("Hidden Order Dark Pool DEX", "Private Auction Platform"). Nobody had built it. We did, this weekend.

What it does

Two trading venues, both with hidden orders, both settled by zero-knowledge proofs on Midnight:

  1. The RFQ desk — rest an order whose size, price, and identity exist on-chain only as a hiding commitment. Hand the quote to a counterparty off-chain (like real OTC), and a ZK circuit settles atomically at exactly the committed terms — neither side can cheat. Every fill writes a salted audit fingerprint: disclose the trade record to your auditor and they verify it against the chain; disclose nothing and it stays dark forever.
  2. The sealed-bid batch auction — submit sealed bids; every ~45s the round clears at one uniform price. Unlike commit-reveal auctions, bids are never revealed on-chain, not even after clearing — only the clearing price and counts become public. Claims are ZK proofs that your settlement equals amount × clearingPrice exactly. Front-running and copy-trading aren't discouraged; there is nothing to see.

Plus a dark-terminal web UI with a live "public chain view" that shows judges exactly what the chain sees: opaque commitments, nullifiers, counters — nothing else.

How we built it

  • Two Compact contracts, 14 ZK circuits (compiler 0.31.1, language 0.23): a commitment-nullifier note pool (deposit → private notes in a HistoricMerkleTree, spends prove membership + publish nullifiers), hidden orders/bids as persistentCommit values, atomic multi-mint settlement, uniform-price verification via division-free fixed-point math (quoteDue == amount × price), and per-trade salted audit fingerprints.
  • midnight-js 4.1.1 six-provider stack, local proof server, devnet (node 1.0.0 + indexer v4); every flow verified end-to-end with real proofs (~1.5–5s each).
  • React trading-terminal UI (mock-mode for instant exploration, VITE_BRIDGE_URL flips it to the live chain bridge).

Challenges we ran into

  • Deploy transactions carry one verifier key per circuit — our combined 14-circuit contract exhausted the devnet block limit ("Transaction would exhaust the block limits"). Solution: split the venues into two contracts. Real protocol constraint, learned the hard way.
  • Compact's privacy-by-default is strict: even circuit parameters are private until disclose()d, and branch conditions on witness data that change the transaction shape must be explicitly disclosed — the compiler forced us to make every single leak a conscious decision (and we equalized settlement branches so a claim's side doesn't leak from its shape).
  • A live indexer bug that only our second contract hit: reading three historic Merkle-tree roots in one transaction reliably panics the current standalone indexer's storage backend (roots counts can't be negative) — even though the transaction verifies fine on the node. We isolated it by diffing against our RFQ desk (two historic trees, never crashed), then restructured auction claims to prove marking-tree membership only, holding to two historic reads per transaction. A protocol-depth debugging win we didn't expect to need.
  • Concurrent personas sharing one funding wallet raced coin selection — fixed by serializing all chain calls through a queue.
  • Docker Desktop died and the dev machine's disk hit 100% mid-hackathon; we rebuilt the devnet on colima.

Accomplishments we're proud of

  • The RFQ desk works against real proofs on a real Midnight devnet — not a mock: the full deposit → hidden order → RFQ fill → payout claim → salted-fingerprint audit verification (and tampered-record rejection) → withdraw flow passes 8/8 end-to-end. The sealed-bid auction deploys as a second contract and verifies its sealed bids, hidden uniform-price clearing, and buy-side settlement live (6 passing); sell-side settlement has one tracked ZKIR-marshaling bug.
  • The auction's "sealed forever" property: no reveal phase, ever — stronger than classic commit-reveal.
  • An honest threat model: the README states exactly what the chain sees, what the operator can and cannot do, and what's demo scaffolding vs. protocol.

What we learned

Kachina's public/private dual-state model rewards designs where all shared writes are commutative (Merkle appends, set inserts, counter bumps) — our whole architecture is contention-free by construction. And "rational privacy" is a real design constraint, not marketing: the salted fingerprint exists because an unsalted one would have let an auditor brute-force undisclosed trades.

What's next

Zswap shielded-coin custody at the pool boundary (real escrow), MPC blind matching for the RFQ desk, in-circuit clearing-optimality proofs for the auction, per-trade key rotation, OpenZeppelin Allowlist KYC-gated institutional pools, Lace wallet flow on Preview, and cross-chain settlement.

Built with

Midnight (Compact 0.23 / compiler 0.31.1, midnight-js 4.1.1, proof server, indexer v4, devnet), TypeScript, React, Vite, Node 22, colima/Docker, vitest.

Built With

Share this project:

Updates

Submission history