TOKEN2049 Got a code? Redeem it for a free ODATANO API key. Redeem now →

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

ServicePathWhat
NightgateService/odata/v4/midnightchain data, wallet sessions, token, contract, attestation and agent-grant actions
NightgateIndexerService/odata/v4/midnight-indexersync state, health, reorg history, Prometheus metrics, crawler control
NightgateAnalyticsService/odata/v4/midnight-analyticsaggregate counts
NightgateAdminService/odata/v4/midnight-adminsessions, contract registration, role grants, diagnostics
NightgateVerifyService/odata/v4/midnight-verifystate 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, UnshieldedUtxos and NightBalances fill from the node.
  • Wallet sessions: connectWallet (viewing key, read only) and connectWalletForSigning (BIP39 mnemonic, Lace-compatible derivation). Secrets are AES-256-GCM encrypted at rest. deriveWalletInfo creates a wallet without Lace.
  • Tokens: sendNight moves NIGHT or a custom token (tokenTypeHex). getWalletBalance and estimateSendNightFee run before you spend.
  • Compact contracts: deployContract, submitContractCall, submitContractCallBatch with 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_URL switches to a proof server for production.
  • Fee sponsoring: sponsorSessionId on every submit action; the caller needs neither NIGHT nor DUST. A sponsor policy limits contracts, circuits, token types and deploys per grant.
  • Document anchoring: anchorDocument and verifyDocument put a hash on chain; storage stays with the caller. prepareDocumentProof turns 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: issueDocumentIntegrityAttestation and issueDocumentDiffAttestation compare two anchored documents.
  • Crawler-free verification: verifyAttestationState and verifyPredicateState read live contract state from the public indexer. The verify service serves both without login.
  • Tiered disclosure: grantDisclosure, revokeDisclosure, registerGranteeIdentity decide who reads which tier of a document.
  • Agent grants: createAgentGrant issues an ngat_… token with action allow list, budgets, pinned session and sponsor. attestAgentOutput anchors agent-output provenance.
  • Local building: @odatano/nightgate-tx builds, proves and signs with your own key; sponsorFinalizedTransaction and sponsorUnboundTransaction pay and submit.
  • Browser: @odatano/nightgate/browser plus /zk-config and /contract-manifest for 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

LayerTech
NetworkMidnight preprod, preview, mainnet; undeployed for a local stack
Chain accessSubstrate RPC over WebSocket, GraphQL indexer
BackendSAP CAP, Node.js, TypeScript; midnight-js in worker_threads
DatabaseSQLite in development; PostgreSQL or SAP HANA in production
AuthCAP 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

Built on NIGHTGATE: NIGHTPASS, the EU battery passport with three disclosure tiers.