Providers
The Midnight SDK requires six providers to deploy and interact with a contract. Kosh configures them in src/dapp/providers.ts with two separate factory functions: one for the browser (backed by the Lace wallet) and one for Node.js scripts.
The Six Providers
| Provider | Interface | Purpose |
|---|---|---|
privateStateProvider | PrivateStateProvider | Reads/writes member secrets |
publicDataProvider | PublicDataProvider | Queries ledger state via Indexer GraphQL |
zkConfigProvider | ZKConfigProvider | Loads ZK circuit keys |
proofProvider | ProofProvider | Sends circuit inputs to the remote proof server |
walletProvider | WalletProvider | Balances and signs transactions via Lace |
midnightProvider | MidnightProvider | Submits signed transactions to the node |
The first four are infrastructure providers. The last two are backed by the user's connected Lace wallet and are required for any operation that moves funds or modifies on-chain state.
Browser Providers
In the browser, all six providers are created by createBrowserProviders():
import { createBrowserProviders } from '@/dapp/providers';
import type { ConnectedAPI } from '@midnight-ntwrk/dapp-connector-api';
const providers = await createBrowserProviders(connectedApi);
This calls createAllBrowserProviders() from src/dapp/lace-providers.ts, which wraps the Lace ConnectedAPI into the SDK provider interfaces:
walletProvider— delegatesbalanceTxtoapi.balanceUnsealedTransaction()midnightProvider— delegatessubmitTxtoapi.submitTransaction()zkConfigProvider— fetches ZK keys from/build/keys/and/build/zkir/(served statically)proofProvider— sends proof requests tohttps://proof-server.preprod.midnight.networkpublicDataProvider— reads state from the preprod Indexer GraphQL endpointprivateStateProvider— stores member secrets in-memory during the browser session
// src/dapp/lace-providers.ts (simplified)
export async function createAllBrowserProviders(
connectedApi: ConnectedAPI,
indexerUri: string,
): Promise<KoshProviders> {
return {
walletProvider: createWalletProvider(connectedApi),
midnightProvider: createMidnightProvider(connectedApi),
zkConfigProvider: createBrowserZkConfigProvider('/build'),
proofProvider: createBrowserProofProvider(ENV.PROOF_SERVER_URL),
publicDataProvider: createBrowserPublicDataProvider(indexerUri),
privateStateProvider: createInMemoryPrivateStateProvider(),
};
}
Node.js Providers (Local Dev)
For deploy scripts and integration tests, createProviders() returns Node.js-compatible providers:
import { createProviders } from '@/dapp/providers';
const providers = await createProviders(
'./build', // Path to Compact compiler output
'~/.kosh/state', // LevelDB path for private state
);
These use:
levelPrivateStateProvider— LevelDB on the local filesystemNodeZkConfigProvider— loads keys frombuild/keys/andbuild/zkir/HttpClientProofProvider— HTTP client to the proof server (local Docker at:6300or remote)IndexerPublicDataProvider— GraphQL client to the Indexer
The Node.js providers do not include walletProvider or midnightProvider — these must be supplied separately when running against a real network.
Environment Variables
All endpoint URLs are configurable via .env.local:
NEXT_PUBLIC_INDEXER_URL=https://indexer.preprod.midnight.network/api/v3/graphql
NEXT_PUBLIC_INDEXER_WS_URL=wss://indexer.preprod.midnight.network/api/v3/graphql/ws
NEXT_PUBLIC_NODE_URL=https://rpc.preprod.midnight.network
NEXT_PUBLIC_PROOF_SERVER_URL=https://proof-server.preprod.midnight.network
NEXT_PUBLIC_NETWORK_ID=preprod
If no .env.local is present, these preprod network defaults are used. For local Docker dev, override with localhost URLs and set NEXT_PUBLIC_NETWORK_ID=undeployed.
Lace Wallet Config
On wallet connect, Kosh saves the wallet's own endpoint configuration to sessionStorage:
const cfg = await api.getConfiguration();
sessionStorage.setItem('kosh:wallet:config', JSON.stringify(cfg));
getLaceConfig() reads this to ensure publicDataProvider uses the same Indexer endpoint as the wallet — keeping them in sync regardless of .env.local.
Network ID
The network ID must be set once before any SDK calls:
import { setNetworkId } from '@midnight-ntwrk/midnight-js-network-id';
setNetworkId('preprod'); // Set at module load time in providers.ts
The network ID affects shielded address encoding and is validated by the Lace wallet. Use preprod for the beta testnet, undeployed for local Docker dev.