Skip to content

Repository files navigation

Certificate Sandbox — Private Buyer NFT Marketplace (Midnight)

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.

Repository layout

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
│   ├── deployments/          # Per-network deploy records (address, endpoints) — data for apps
│   └── 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

Prerequisites

curl --proto '=https' --tlsv1.2 -LsSf \
  https://github.com/midnightntwrk/compact/releases/latest/download/compact-installer.sh | sh
compact update +0.31.0

Setup

pnpm install

Compile the contract

# 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 build

Both files are compiled: certificate.compact (full, 24 circuits) and certificate-deploy.compact (the deploy subset used by deploy-in-parts).

zkir can intermittently segfault (exit -11) on the full compile, more often as the circuit count/size grows. It is flaky — just re-run pnpm -C certificate-contract compact.

Testing

Two independent layers:

1. Simulator unit tests (certificate-contract)

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 test

2. Integration tests (certificate-sandbox)

Spin 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

Stack images: midnight-node:1.0.0, indexer-standalone:4.3.3, proof-server:8.1.0 (see standalone.yml). If a run hangs at "Setting up wallet", check docker logs certificate-indexer — indexer 4.3.3 dies at startup if the fresh node hasn't finalized block 1 yet; standalone.yml gates its start on a node healthcheck that requires finalized block ≥ 1, with restart: on-failure as backstop (details in CLAUDE.md, "Local stack gotchas").

To run against public testnets (pnpm test-preview / test-preprod): set MY_MNEMONIC in .env (funded wallet — faucet link prints at startup), and run only ONE test/deploy process at a time per wallet — concurrent runs race each other's UTXOs and the node rejects transactions (see CLAUDE.md, "Preview/testnet gotchas").

Deploy

The deploy scripts provision a network for a consuming application: they start the required infrastructure detached (it stays running until stopped manually), deploy the contract, and persist the result to certificate-sandbox/deployments/<network>.json — a machine-readable record with the contract address, name/symbol, timestamp, endpoint URLs, and (standalone only) the funding result. Each deploy overwrites its network's record; the logs/ files keep history.

# Local standalone: starts node + indexer + proof server, deploys, then funds
# MY_UNDEPLOYED_UNSHIELDED_ADDRESS (.env) with FUND_AMOUNT tNight (default 1000)
pnpm -C certificate-sandbox deploy-standalone
pnpm -C certificate-sandbox standalone-down   # manual tear-down (nothing stops otherwise)

# Testnets: starts only the local proof server (zk-params mounted for the k=16
# circuits); node + indexer are the public endpoints. No funding step — that is
# handled at the application level. Requires MY_MNEMONIC in .env (funded wallet).
pnpm -C certificate-sandbox deploy-preview
pnpm -C certificate-sandbox deploy-preprod
# stop the proof server manually: docker compose -f proof-server.yml down

Contract overview

  • NonFungibleTokenCertificate NFTs (mint, burn, owners, price), generic Category/Tier/Region enums.
  • NFTPool — list/delist, purchaseNFT (ZK commitment-based ownership), proofOwnership, burnPurchased, per-seller payment custody + withdrawSellerFunds.
  • ShieldedNightswapNightForShielded (lock native NIGHT 1:1, deliver shielded Night from the recycled reserve first, minting only the shortfall — single-send circuit) and redeemShieldedForNight (receive shielded Night into the reserve, release NIGHT). Supply tracks _totalLocked; redeemed coins pool in _reserve and 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.

Deploy-in-parts

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

  • 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).

Scripts reference

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 Start local stack + deploy + fund (record → deployments/undeployed.json)
pnpm -C certificate-sandbox deploy-preview Start proof server + deploy to preview (record → deployments/preview.json)
pnpm -C certificate-sandbox deploy-preprod Start proof server + deploy to preprod
pnpm -C certificate-sandbox ps-all Start the proof server via Docker

Built by Edda Labs

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages