Midnight
Midnight is the chain DPO2U uses for private attestation: a compliance verdict is sealed on-chain while the zero-knowledge proof is produced inside a Compact circuit, so the underlying evidence is never published. The officially documented network is preview. This page does not claim mainnet support.
Role in DPO2U
- Gateway route. The pilot gateway accepts attestation attempts with
chain=midnightand hands them toprocessAttestationMidnight(packages/pilot-gateway/src/routes/attestation.ts:203-204,:269). - Feature flag. The route is gated by
MIDNIGHT_CHAIN_ENABLED=1. With the flag off, the attempt fails with codemidnight_disabled; Stellar and Solana routes are untouched (attestation.ts:29-31,:270-275). - Asynchronous anchoring. The gateway does not submit a transaction itself. It enqueues the seal with a warm self-funding agent (
packages/pilot-gateway/src/lib/midnight-driver.ts,sealManagedMidnight). The returned handle points to the public verify page; the on-chain result appears once the agent seals it (attestation.ts:267-268,midnight-driver.ts:51). - Compliance engine driver.
MidnightDriverimplementsComplianceChainClientagainst preview. It never runs a wallet or syncs shielded history; it pushes work to the agent queue and reads results back from the agent ledger and the public preview indexer (packages/compliance-engine/src/chain/MidnightDriver.ts:1-23). - Proof generation. The ZK proof is produced inside the on-chain circuit by a local proof-server (
MidnightDriver.ts:8-10). - Verdict encoding.
0FAIL,1PASS,2REVIEW (MidnightDriver.ts:102).
Preview endpoints used by the driver
| Setting | Default | Source |
|---|---|---|
| Indexer (GraphQL) | https://indexer.preview.midnight.network/api/v4/graphql | MidnightDriver.ts:28, :63 |
| Network | preview (also accepts preprod, standalone) | MidnightDriver.ts:32 |
| Proof-server | local, overridable via MIDNIGHT_PROOF_SERVER_URL | MidnightDriver.ts:29, :64 |
| Indexer verdict read | off unless MIDNIGHT_VERIFY_VIA_INDEXER=1 | MidnightDriver.ts:33-34 |
No contract addresses are published here.
Compact contracts (lab)
The lab repository dpo2u-midnight-lab holds three Compact contracts under contracts/, all declaring pragma language_version >= 0.21.0. They store hashes (Bytes<32>), not personal data.
The full contract catalogue of the agent system is documented in Self-funding agents.
The gateway and driver seal on the ComplianceRegistry contract owned by the self-funding agent repository (MidnightDriver.ts:6-9), not on the three lab contracts below.
ConsentRegistry
LGPD/GDPR consent. contracts/ConsentRegistry.compact.
- Ledgers (lines 27-31):
consent_status,consent_purposes,consent_policy_version(eachMap<Bytes<32>, Uint<8>>),total_consents_granted,total_revocations(Counter). - Circuits:
grantConsent(subject_id, purposes, policy_version)(line 36),revokeConsent(51),updateConsentPurposes(60), and read circuitsgetConsentStatus,getConsentPurposes,getConsentPolicyVersion,getTotalConsentsGranted,getTotalRevocations(75-97). - Encoding: purposes is a bitmask (1 essential, 2 analytics, 4 marketing, 8 third-party sharing, 16 profiling); status 0 no record, 1 active, 2 revoked (header comments, lines 12-25).
DataAuditLog
Processing event log. contracts/DataAuditLog.compact.
- Ledgers (28-34):
event_count,deletion_requests,deletions_confirmed,breach_events(Counter);events_by_controller(Map<Bytes<32>, Uint<64>>),last_event_type(Uint<8>),last_event_block(Uint<64>). - Circuits:
logEvent(38),logDeletionRequest(56),confirmDeletion(73),logBreachEvent(90), and gettersgetControllerEventCount,getLastEventType,getLastEventBlock,getTotalEvents,getTotalDeletionRequests,getTotalDeletionsConfirmed,getTotalBreachEvents(105-135).
DataSubjectRights
LGPD data-subject requests with a deadline. contracts/DataSubjectRights.compact.
- Ledgers (36-43):
request_status,request_type(Uint<8>),request_submitted_block,request_resolved_block(Uint<32>),total_requests,total_fulfilled,total_rejected,total_overdue(Counter). - Circuits:
submitRequest(52),fulfillRequest(69),rejectRequest(85),markRequestOverdue(101), gettersgetRequestStatus,getRequestType,getRequestSubmittedBlock,getRequestResolvedBlock,getTotalRequests,getTotalFulfilled,getTotalRejected,getTotalOverdue(119-154).lgpd_deadline_blocksis apure circuitreturning 21600 blocks (15 days at one block per minute, LGPD Art. 19; lines 47-49).
Version matrix (lab)
| Component | Version | Source |
|---|---|---|
Compact compiler (compactc) | 0.31.0 | scripts/compile-contracts.sh:16 |
| Node | midnightntwrk/midnight-node:0.21.0 | docker-compose.yml:3 |
| Indexer | midnightntwrk/indexer-standalone:3.1.0 | docker-compose.yml:24 |
| Proof-server | midnightntwrk/proof-server:7.0.0 | docker-compose.yml:51 |
compact-js | 2.4.0 | package.json:18 |
compact-runtime | 0.14.0 | package.json:19 |
ledger-v7 | 7.0.0 | package.json:20 |
midnight-js-* | 3.0.0 | package.json:21-27 |
wallet-sdk-facade | 1.0.0 | package.json:31 |
| Node.js | >= 22 | package.json:6 |
The compose file is a standalone/local stack (indexer network_id: "undeployed", indexer-config.yaml:5). scripts/pre-deploy-check.sh:19-22 and scripts/check-version-consistency.sh keep the duplicated version constants in sync.
Development flow
From the lab root (package.json:8-15):
| Step | Command | What it runs |
|---|---|---|
| Compile contracts | npm run compile | scripts/compile-contracts.sh (optionally --contract <name>) |
| Check version drift | npm run check-versions | scripts/check-version-consistency.sh |
| Typecheck | npm run typecheck | tsc --noEmit -p tsconfig.json |
| Pre-deploy checks | npm run predeploy | scripts/pre-deploy-check.sh [--network standalone|preprod|preview] |
| Deploy all | npm run deploy:all | tsx scripts/deploy-all.ts |
| Status | npm run status | tsx scripts/status.ts |
| Interact | npm run interact | tsx scripts/interact-full-suite.ts |
compile-contracts.sh aborts when /tmp has less than 500 MB free, because compactc fails with an unreadable assertion on a full disk (compile-contracts.sh:67-70).
Known pitfalls
- Facade API 1.0.0 vs 2.0.0.
WalletFacade.init({...})is the 2.0.0 API; withwallet-sdk-facade1.0.0 it throwsWalletFacade.init is not a function. The lab pins 1.0.0 and builds the wallet throughnew WalletFacade(...)plusstart()inscripts/lib/wallet-facade.ts(seelogs/2026-09-26-dev.md:6-8,:24-35). Do not mix SDK and infrastructure versions. - Indexer tag: preview vs preprod. Indexer tags differ per network tier.
scripts/pre-deploy-check.sh:22records that a preview-tier tag (4.0.0-rc.4) had been mismatched against the preprod node 0.21.0 and was corrected to 3.1.0. The driver's preview indexer endpoint is/api/v4/graphql, while the lab's preprod scripts use/api/v3/graphql(scripts/status.ts:91). PROOF_SERVER_URLwhen another proof-server owns the default port. If a different project's container already listens on the default proof-server port, the pre-deploy check fails with a version mismatch (scripts/pre-deploy-check.sh:55-68). Start a proof-server7.0.0on another port and pointPROOF_SERVER_URLat it; the deploy and status scripts honor the variable. The gateway-side driver readsMIDNIGHT_PROOF_SERVER_URLinstead (MidnightDriver.ts:29).