A C# / .NET SDK for the Midnight Network — work in progress, focused on what's possible without the WASM-bound JS SDK.
- Wallet creation & HD derivation — BIP39 24-word mnemonic, BIP32 derivation
with Midnight's coin type (
m/44'/2400'/account'/role/index). Bit-for-bit compatible with 1AM / Lace / the official JS SDK. - Indexer sync — connects to the Midnight indexer over
graphql-transport-wsand consumes the three sync streams in parallel (zswapLedgerEvents,dustLedgerEvents,unshieldedTransactions). - Unshielded UTXO tracking — full live state of NIGHT balance and UTXOs
for any address, including
registeredForDustGenerationflag. The indexer decodes unshielded data server-side, so no WASM is needed. - Address tx history — full sent/received history for any unshielded address, including counterparty addresses.
Anything that builds a transaction (mint, transfer, contract call) requires the WASM ledger lib for binary serialization, ZK transcript, and shielded output handling. The SDK can't do this in pure C#.
For these operations the SDK shells out to a tiny Node helper
(worker/midnight-worker.mjs in the nmkr-midnight-api
project) over stdin/stdout JSON-RPC. The Node process is short-lived — it
spawns, builds the tx, submits it, and exits.
The pool architecture — keep a set of dust-funded wallets always-synced in the API server's watch list, then mint in parallel via HTTP — is the production-ready alternative for high-volume minting.
src/Midnight.Sdk/
├── MidnightConfig.cs Network config (preview / preprod / mainnet)
├── Hd/
│ ├── Roles.cs BIP44 roles (NightExternal / Internal / Dust / Zswap / Metadata)
│ ├── Bip39Helper.cs Mnemonic generate / recover (24 words)
│ └── HdWallet.cs BIP32 derivation with Midnight path
├── Wallet/
│ └── MidnightWallet.cs High-level wallet (create / recover / info)
├── Sync/
│ ├── IndexerClient.cs graphql-transport-ws WebSocket client
│ ├── SyncSubscriptions.cs GraphQL queries (Zswap / Dust / Unshielded)
│ ├── IndexerEvents.cs Event DTOs
│ ├── UnshieldedState.cs UTXO tracking + NIGHT balance
│ └── WalletSync.cs Sync orchestrator (3 parallel streams)
├── Api/
│ └── MidnightApiClient.cs HTTP client for the nmkr-midnight-api REST API
├── Bridge/
│ └── NodeWorker.cs Spawns Node worker for one-shot tx operations
└── Wasm/
└── LedgerWasm.cs (Skeleton — direct WASM loading is not feasible
with wasm-bindgen output without a JS host)
demo/ Console app exercising every command
dotnet build
cd demo
# create a fresh wallet
dotnet run -- create
# show derived keys for a seed
dotnet run -- info <hex-seed>
# live indexer sync for an address (no seed needed)
dotnet run -- sync mn_addr_preprod1xy...
# transfer NIGHT (uses Node worker)
dotnet run -- transfer <senderSeed> <toAddr> 1 preview
# mint via HTTP API
dotnet run -- bulk-mint-api <ownerSeed> <contractAddr> 10 http://localhost:3002 /tmp/dust-pool.jsondotnet run without arguments lists every available command.
The HD-derived role keys produce bit-for-bit identical bytes as the JS
@scure/bip32 + bip39 pair used by the official wallet SDK. A wallet
created in C# can be opened in 1AM / Lace, and vice versa.
- Wallet creation, HD derivation, mnemonic
- Indexer WebSocket sync (3 parallel subscriptions)
- Unshielded UTXO state, NIGHT balance, dust-registration flag
- NIGHT transfer (via Node worker)
- NFT collection deploy + mint (via Node worker)
- HTTP client for nmkr-midnight-api
- Direct WASM ledger lib bindings (research; wasm-bindgen output is heavily JS-coupled and not straightforward to host in C#)
- Shielded balance / state (needs WASM)
- Pure-C# tx building (would require Midnight to publish the binary tx format spec)
Apache-2.0 — same as the underlying Midnight wallet-sdk we draw from.