NIGHTGATE Plugin

@odatano/nightgate ties a SAP CAP runtime directly to the Midnight blockchain. A built-in crawler indexes blocks from a Substrate RPC node into CAP entities; a worker-thread-isolated wallet stack handles ZK-aware transaction submission — deploy/call Compact contracts, send NIGHT, shield/unshield, dust generation. The whole surface is standard OData V4: no GraphQL, no SDK lock-in for consumers.

Highlights

  • Block-level indexing: Live + catch-up crawler with reorg detection
  • Wallet sessions: Read-only (viewing key) + signing (seed), AES-256-GCM at rest
  • Contract deploy / call: Compact-compiled contracts via deployContract / submitContractCall
  • ZK predicate attestations: issuePredicateAttestation proves value ≤/≥ threshold without revealing the value
  • Document anchoring: anchorDocument / verifyDocument — hash on-chain, caller-managed storage
  • Shield / unshield: shieldFunds / unshieldFunds move NIGHT between ledgers; sendNight auto-detects the receiver ledger
  • Browser connector surface: @odatano/nightgate/browser + /zk-config + /contract-manifest for wallet-driven (Lace) contract calls
  • Offline mode: the CAP app starts even if the upstream node is unreachable

Stack

LayerTech
NetworkMidnight preprod / mainnet
Chain accessSubstrate RPC (wss) + GraphQL indexer
BackendSAP CAP, Node.js, TypeScript
Wallet SDKMidnight SDK in worker_threads (Effect.ts fibers)
DatabaseSQLite / SAP HANA
APIOData V4
TestsJest — 49 suites, 688 tests

Architecture

Main thread                       Worker thread
┌────────────────────┐            ┌────────────────────────┐
│ Crawler            │            │ Wallet SDK             │
│ - BlockProcessor   │            │ - facade.start (sync)  │
│ - reorg detection  │            │ - transferTransaction  │
└────────┬───────────┘            │ - deployContract       │
         ▼  atomic writes         │ - submitContractCall   │
┌────────────────────┐            └───────────┬────────────┘
│ CAP DB             │◄────state-save─────────┘
└────────┬───────────┘
         ▼  OData V4
4 services on /api/v1/{nightgate, indexer, analytics, admin}

The wallet SDK lives in worker_threads because Midnight’s Effect.ts fiber scheduler saturates the microtask queue during sync — isolation keeps the main CAP request pipeline responsive.

Service Surface

ServicePathWhat
NightgateService/api/v1/nightgateBlocks / transactions / wallet sessions / token + contract ops
NightgateIndexerService/api/v1/indexerSync state, health, reorg history, Prometheus metrics, crawler control
NightgateAnalyticsService/api/v1/analyticsAggregate counts
NightgateAdminService/api/v1/adminSession invalidation

Submit actions are async: they return { jobId, status }; poll getJobStatus(jobId, sessionId) for the result.

Use as a CAP Plugin

{
  "cds": {
    "requires": {
      "db": { "kind": "sqlite" },
      "nightgate": { "kind": "nightgate" }
    }
  }
}

Then cds watch — defaults to Preprod with public RPC + hosted indexer.

Quick Start

npm install @odatano/nightgate @cap-js/sqlite
npm ci
npm run dev            # connects to public preprod RPC + hosted indexer

# for wallet signing + submission:
docker compose -f docker/docker-compose.yml up -d proof-server
npm run serve:sync     # sets the ~12 GB heap (override via NIGHTGATE_HEAP_MB)

Sourcecode

github.com/ODATANO/NIGHTGATE