A privacy-preserving NFT marketplace on the Midnight Network. Sellers list tokenized certificates as NFTs; buyers acquire them with zero-knowledge, commitment-based ownership and pay in a contract-minted shielded Night token (a 1:1 wrapper over native NIGHT).
The certificate uses generic enums (Category, Tier, Region) so one deployment can
serve multiple use cases (e.g. renewable-energy certificates, recycling credits) — each UI
maps the generic values to domain-specific labels.
This repo is the contract + sandbox (providers, wallet, deploy scripts, and integration tests). There is no UI/CLI package here.
certificate-sandbox/
├── certificate-contract/ # Compact smart contract + simulator unit tests
│ └── src/
│ ├── certificate.compact # Full contract (24 verifier-key circuits)
│ ├── certificate-deploy.compact # Deploy subset (~15 circuits) for deploy-in-parts
│ └── modules/
│ ├── token-nft/NonFungibleToken.compact # NFT (Certificate struct, mint/burn/owners)
│ ├── nft-pool/NFTPool.compact # Listing, ZK-commitment purchase, seller payouts
│ ├── shielded-night/ShieldedNight.compact # NIGHT ↔ shielded-Night 1:1 wrapper
│ └── utils/Utils.compact
├── certificate-sandbox/ # Providers, wallet, deploy scripts, integration tests
│ └── src/
│ ├── api.ts # Providers, balancing, circuit wrappers, shielded helpers
│ ├── config.ts # Network configs (undeployed/preview/preprod)
│ ├── deploy/ # standalone / preview / preprod deploy entrypoints
│ └── test/ # Integration tests (testcontainers) + simulators
├── docs/ # Living architecture + investigation reports
├── turbo.json # Build pipeline
└── pnpm-workspace.yaml # Monorepo workspace
- Node.js v22+
- pnpm v10+
- Docker (proof server, node, indexer)
- Compact toolchain 0.31.0
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/midnightntwrk/compact/releases/latest/download/compact-installer.sh | sh
compact update +0.31.0pnpm install# Fast iteration — type/shape check, NO ZK keys (seconds)
pnpm -C certificate-contract compact-fast
# Full compile WITH ZK proving/verifier keys (required for deploy + integration tests)
pnpm -C certificate-contract compact
# Refresh dist/ so certificate-sandbox sees the freshly compiled circuits
pnpm -C certificate-contract buildBoth files are compiled: certificate.compact (full, 24 circuits) and
certificate-deploy.compact (the deploy subset used by deploy-in-parts).
zkircan intermittently segfault (exit -11) on the full compile, more often as the circuit count/size grows. It is flaky — just re-runpnpm -C certificate-contract compact.
Two independent layers:
Call impureCircuits directly — fast, deterministic, exercise contract logic and ledger
state transitions. They do not do balancing, proving, transcript segmentation, or the
contract's on-chain unshielded balance.
pnpm -C certificate-contract testSpin up the real stack via testcontainers (standalone.yml: proof server :6300,
indexer :8088, node :9944), deploy-in-parts, and drive transactions through the real
wallet SDK balancer + node.
pnpm -C certificate-sandbox test-undeployed# Local standalone stack
pnpm -C certificate-sandbox deploy-standalone
pnpm -C certificate-sandbox standalone-down # tear down
# Testnets (proof server via docker)
pnpm -C certificate-sandbox deploy-preview
pnpm -C certificate-sandbox deploy-preprod- NonFungibleToken —
CertificateNFTs (mint, burn, owners, price), genericCategory/Tier/Regionenums. - NFTPool — list/delist,
purchaseNFT(ZK commitment-based ownership),proofOwnership,burnPurchased, per-seller payment custody +withdrawSellerFunds. - ShieldedNight —
swapNightForShielded(lock native NIGHT 1:1, deliver shielded Night from the recycled reserve first, minting only the shortfall — single-send circuit) andredeemShieldedForNight(receive shielded Night into the reserve, release NIGHT). Supply tracks_totalLocked; redeemed coins pool in_reserveand are recycled by later swaps.
purchaseNFT and redeemShieldedForNight require the wallet to spend a shielded coin
into the contract. This was blocked by a balancer limitation in wallet-sdk-shielded
3.0.1 and is fixed since @midnightntwrk/wallet-sdk 1.2.0 (pulls
wallet-sdk-shielded 3.0.2). The reserve-recycling swap was separately blocked by a zkir
coin-commitment alignment failure and is fixed by restructuring to a single
unconditional shielded send with a funding mux. Both flows are proven on-chain by the
integration tests (4/4). Background: docs/arquitecture.md §6,
docs/shielded-payment-balancing-failure-report.md,
docs/shielded-recycling-swap-failure-report.md (§10 resolution), and the shielded-token
section of CLAUDE.md.
The full contract exceeds a single deploy transaction's size budget, so deployment uses a
two-phase strategy: deploy the certificate-deploy.compact subset, then insert the
remaining verifier keys via maintenance transactions, and joinContract with the full
compiled contract so all circuits are callable. See certificate-sandbox/src/api.ts
(deployInParts) and docs/arquitecture.md §8.
docs/arquitecture.md— canonical living architecture + test-coverage reference.docs/shielded-payment-balancing-failure-report.md— on-chain shielded-payment balancing investigation (for the Midnight Foundation).CLAUDE.md— practices, gotchas, and hard constraints learned building this (read before touching shielded circuits, the proof server, or the compile pipeline).
| Command | Description |
|---|---|
pnpm install |
Install all dependencies |
pnpm build |
Build all packages (turbo) |
pnpm compact |
Full ZK compile (turbo → contract) |
pnpm -C certificate-contract compact-fast |
Fast compile, no ZK keys |
pnpm -C certificate-contract test |
Simulator unit tests |
pnpm -C certificate-contract build |
Refresh dist/ for the sandbox |
pnpm -C certificate-sandbox test-undeployed |
Integration tests (testcontainers) |
pnpm -C certificate-sandbox deploy-standalone |
Deploy to local standalone stack |
pnpm -C certificate-sandbox ps-all |
Start the proof server via Docker |
Built by Edda Labs