NIGHTGATE on Midnight
@odatano/nightgate is the OData V4 API for the Midnight blockchain. A crawler indexes blocks from a Substrate RPC node into CAP entities. A wallet stack in a worker thread submits transactions: NIGHT and custom-token transfers, Compact contract deploys and calls, document anchoring, zero-knowledge attestations that prove a claim without revealing the value. No GraphQL, no SDK on the client.
It runs hosted at api.odatano.dev, standalone from the repo or Docker image, or as a plugin in your SAP CAP app. Needs Node.js 22.12 or newer and @sap/cds 10.
Services
| Service | Path | What |
|---|---|---|
NightgateService | /odata/v4/midnight | chain data, wallet sessions, token, contract, attestation and agent-grant actions |
NightgateIndexerService | /odata/v4/midnight-indexer | sync state, health, reorg history, Prometheus metrics, crawler control |
NightgateAnalyticsService | /odata/v4/midnight-analytics | aggregate counts |
NightgateAdminService | /odata/v4/midnight-admin | sessions, contract registration, role grants, diagnostics |
NightgateVerifyService | /odata/v4/midnight-verify | state verification without login, when NIGHTGATE_PUBLIC_VERIFY=true |
The hosted API serves the same paths. The older /api/v1/… spelling keeps answering until 1.0.
Write actions are async. They return { jobId, status }; poll getJobStatus(jobId, sessionId) for the result. Jobs survive restarts: idempotency keys, leased execution, chainStatus confirmed from the indexer. Write actions answer 503 with Retry-After while the wallet runtime is down.
What it does
- Block indexing: live and catch-up crawler with reorg detection.
Blocks,Transactions,ContractActions,UnshieldedUtxosandNightBalancesfill from the node. - Wallet sessions:
connectWallet(viewing key, read only) andconnectWalletForSigning(BIP39 mnemonic, Lace-compatible derivation). Secrets are AES-256-GCM encrypted at rest.deriveWalletInfocreates a wallet without Lace. - Tokens:
sendNightmoves NIGHT or a custom token (tokenTypeHex).getWalletBalanceandestimateSendNightFeerun before you spend. - Compact contracts:
deployContract,submitContractCall,submitContractCallBatchwith up to 8 calls in one transaction. Admins register contract artifacts at runtime. - Proving: in-process WASM by default, no proof server.
NIGHTGATE_PROOF_SERVER_URLswitches to a proof server for production. - Fee sponsoring:
sponsorSessionIdon every submit action; the caller needs neither NIGHT nor DUST. A sponsor policy limits contracts, circuits, token types and deploys per grant. - Document anchoring:
anchorDocumentandverifyDocumentput a hash on chain; storage stays with the caller.prepareDocumentProofturns canonical JSON into a content root with per-field paths, 16 or 32 slots. - Field proofs:
issueFieldPredicateAttestation(value at most or at least a threshold),issueFieldEqualityAttestation,issueFieldMembershipAttestation, and a batch of up to 8 claims in one transaction. Values stay hidden. - Cross-document proofs:
issueDocumentIntegrityAttestationandissueDocumentDiffAttestationcompare two anchored documents. - Crawler-free verification:
verifyAttestationStateandverifyPredicateStateread live contract state from the public indexer. The verify service serves both without login. - Tiered disclosure:
grantDisclosure,revokeDisclosure,registerGranteeIdentitydecide who reads which tier of a document. - Agent grants:
createAgentGrantissues anngat_…token with action allow list, budgets, pinned session and sponsor.attestAgentOutputanchors agent-output provenance. - Local building:
@odatano/nightgate-txbuilds, proves and signs with your own key;sponsorFinalizedTransactionandsponsorUnboundTransactionpay and submit. - Browser:
@odatano/nightgate/browserplus/zk-configand/contract-manifestfor wallet-driven Lace dApps. - Operations: liveness, readiness and Prometheus metrics without login, crawler pause, resume and reindex, offline start when the node is unreachable.
Architecture
Main thread Worker thread
┌────────────────────┐ ┌────────────────────────┐
│ Crawler │ │ Wallet SDK │
│ - BlockProcessor │ │ - facade.start (sync) │
│ - reorg detection │ │ - transferTransaction │
└────────┬───────────┘ │ - finalize (ZK prove) │
▼ atomic writes │ - deployContract │
┌────────────────────┐ │ - submitContractCall │
│ CAP DB │◄─state-save┤ - private-state-rpc │
└────────┬───────────┘ └────────────────────────┘
▼ OData V4
5 services on /api/v1/{nightgate, indexer, analytics, admin, verify}
The wallet SDK lives in a worker thread because its sync saturates the microtask queue. The CAP request pipeline stays responsive.
Run it
As a CAP plugin
npm install @odatano/nightgate @cap-js/sqlite
{
"cds": {
"requires": {
"db": { "kind": "sqlite" },
"nightgate": { "network": "preprod" }
}
}
}
Then cds watch. network is the only required key. Defaults: public preprod RPC, hosted Midnight indexer, WASM proving. Every key is settable under cds.requires.nightgate; NIGHTGATE_* variables override it.
Standalone
git clone https://github.com/ODATANO/NIGHTGATE && cd NIGHTGATE
npm ci
npm run dev # cds watch with a 12 GB heap
npm run serve:sync # cds-serve for long syncs
NIGHTGATE_NETWORK=preprod
NIGHTGATE_NODE_URL=wss://rpc.preprod.midnight.network/
NIGHTGATE_INDEXER_HTTP_URL=https://indexer.preprod.midnight.network/api/v4/graphql
# NIGHTGATE_PROOF_SERVER_URL=http://localhost:6300 # unset = in-process WASM proving
NIGHTGATE_CRAWLER_ENABLED=false
ENCRYPTION_KEY=<random secret>
Docker
docker run -d --name nightgate -p 4004:4004 \
-e ENCRYPTION_KEY=$(openssl rand -hex 32) \
-e NIGHTGATE_HTTP_PASSWORD=change-me \
-v nightgate-data:/data \
ghcr.io/odatano/nightgate:latest
The image targets Midnight preprod, serves with HTTP basic auth, persists its database in the volume and proves in-process. NIGHTGATE_DB_URL=postgres://… switches to PostgreSQL. Production refuses SQLite.
Stack
| Layer | Tech |
|---|---|
| Network | Midnight preprod, preview, mainnet; undeployed for a local stack |
| Chain access | Substrate RPC over WebSocket, GraphQL indexer |
| Backend | SAP CAP, Node.js, TypeScript; midnight-js in worker_threads |
| Database | SQLite in development; PostgreSQL or SAP HANA in production |
| Auth | CAP auth in a host app; @odatano/cap-auth in the image: basic auth, agent-token lane, public verify lane |
On GitHub
The repo holds the detail this page leaves out. github.com/ODATANO/NIGHTGATE
- Quickstart: first wallet-signed transaction
- Actions: every action and function with parameters, results and error codes
- Architecture: worker thread, submission flow, persistence
- Operations: scripts, local indexer, troubleshooting
- Docker: container, configuration, schema upgrades
- Transaction builder: build sponsorable transactions without a server
- Reference: every configuration key, project structure
- Changelog · npm: @odatano/nightgate
Built on NIGHTGATE: NIGHTPASS, the EU battery passport with three disclosure tiers.