Quick Start
The 1AM wallet injects itself at window.midnight['1am']
1. DETECT THE WALLET
1function detectWallet(): Promise<InitialAPI | null> {
2 return new Promise((resolve) => {
3 const wallet = window.midnight?.['1am'];
4 if (wallet) { resolve(wallet); return; }
5
6 let attempts = 0;
7 const interval = setInterval(() => {
8 const w = window.midnight?.['1am'];
9 if (w) { clearInterval(interval); resolve(w); }
10 else if (++attempts > 50) { clearInterval(interval); resolve(null); }
11 }, 100);
12 });
13}2. CONNECT
1const wallet = await detectWallet();
2if (!wallet) throw new Error('1AM wallet not installed');
3
4const connectedAPI = await wallet.connect('preview');3. GET ADDRESSES & BALANCES
1const { shieldedAddress } = await connectedAPI.getShieldedAddresses();
2const { unshieldedAddress } = await connectedAPI.getUnshieldedAddress();
3const { dustAddress } = await connectedAPI.getDustAddress();
4
5const shieldedBalances = await connectedAPI.getShieldedBalances();
6const unshieldedBalances = await connectedAPI.getUnshieldedBalances();
7const { balance, cap } = await connectedAPI.getDustBalance();4. GET NETWORK CONFIG
1const config = await connectedAPI.getConfiguration();
2// {
3// networkId: 'preview',
4// indexerUri: 'https://indexer.preview.midnight.network/api/v4/graphql',
5// indexerWsUri: 'wss://indexer.preview.midnight.network/api/v4/graphql/ws',
6// proverServerUri: 'https://api-preview.1am.xyz',
7// substrateNodeUri: 'wss://rpc.preview.midnight.network',
8// }Build Providers
Your DApp builds providers that delegate proving and transaction balancing to the wallet and its configured services.
INSTALL DEPENDENCIES
1npm install @midnight-ntwrk/compact-js \
2 @midnight-ntwrk/midnight-js-contracts \
3 @midnight-ntwrk/midnight-js-types \
4 @midnight-ntwrk/midnight-js-fetch-zk-config-provider \
5 @midnight-ntwrk/midnight-js-indexer-public-data-provider \
6 @midnight-ntwrk/midnight-js-network-id \
7 @midnight-ntwrk/ledger-v8BUILD PROVIDERS
1import { setNetworkId } from '@midnight-ntwrk/midnight-js-network-id';
2import { FetchZkConfigProvider } from '@midnight-ntwrk/midnight-js-fetch-zk-config-provider';
3import { indexerPublicDataProvider } from '@midnight-ntwrk/midnight-js-indexer-public-data-provider';
4
5async function buildProviders(connectedAPI) {
6 const config = await connectedAPI.getConfiguration();
7 setNetworkId(config.networkId);
8
9 const zkConfigProvider = new FetchZkConfigProvider(
10 'https://your-app.com/contract/compiled/your-contract',
11 fetch.bind(window),
12 );
13
14 const publicDataProvider = indexerPublicDataProvider(
15 config.indexerUri, config.indexerWsUri,
16 );
17
18 const provingProvider = await connectedAPI.getProvingProvider(zkConfigProvider);
19 const proofProvider = {
20 async proveTx(unprovenTx) {
21 const { CostModel } = await import('@midnight-ntwrk/ledger-v8');
22 return unprovenTx.prove(provingProvider, CostModel.initialCostModel());
23 },
24 };
25
26 const shieldedAddress = await connectedAPI.getShieldedAddresses();
27 const walletProvider = {
28 getCoinPublicKey: () => shieldedAddress.shieldedCoinPublicKey,
29 getEncryptionPublicKey: () => shieldedAddress.shieldedEncryptionPublicKey,
30 async balanceTx(tx) {
31 const serialized = tx.serialize();
32 const hex = Array.from(serialized).map(b => b.toString(16).padStart(2, '0')).join('');
33 const result = await connectedAPI.balanceUnsealedTransaction(hex);
34 const { Transaction } = await import('@midnight-ntwrk/ledger-v8');
35 const bytes = new Uint8Array(result.tx.match(/.{2}/g).map(b => parseInt(b, 16)));
36 return Transaction.deserialize('signature', 'proof', 'binding', bytes);
37 },
38 };
39
40 const midnightProvider = {
41 async submitTx(tx) {
42 const serialized = tx.serialize();
43 const hex = Array.from(serialized).map(b => b.toString(16).padStart(2, '0')).join('');
44 await connectedAPI.submitTransaction(hex);
45 return tx.identifiers()[0];
46 },
47 };
48
49 return { publicDataProvider, zkConfigProvider, proofProvider, walletProvider, midnightProvider };
50}Deploy & Call Contracts
DEPLOY A CONTRACT
1import { CompiledContract } from '@midnight-ntwrk/compact-js';
2import { deployContract } from '@midnight-ntwrk/midnight-js-contracts';
3import { Contract } from './your-compiled-contract';
4
5const compiledContract = CompiledContract.make('YourContract', Contract).pipe(
6 CompiledContract.withVacantWitnesses,
7 CompiledContract.withCompiledFileAssets('./contract/compiled/your-contract'),
8);
9
10const providers = await buildProviders(connectedAPI);
11const deployed = await deployContract(providers, { compiledContract });
12console.log('Contract address:', deployed.deployTxData.public.contractAddress);CALL A CIRCUIT
1import { submitCallTx } from '@midnight-ntwrk/midnight-js-contracts';
2
3const result = await submitCallTx(providers, {
4 compiledContract,
5 contractAddress: '09dbe05f...',
6 circuitId: 'register',
7 args: [nameHash, 1n],
8});
9
10console.log('Tx hash:', result.public.txHash);Transaction Flow
Build
DApp builds unproven tx (SDK + compiled contract)
Prove
DApp calls proveTx() → wallet → proof server → ZK proof generated
Balance
DApp calls balanceTx() → wallet → balance service, with DUST sponsorship where available
Submit
DApp calls submitTx() → wallet → broadcasts to Midnight chain
ProofStation can sponsor DUST on supported networks. Availability and limits depend on the service configuration.
DApp Connector API Reference
window.midnight['1am'] — InitialAPI
| Method | Returns | Description |
|---|---|---|
| connect(networkId) | ConnectedAPI | Connect to wallet |
| name | string | '1AM' |
| apiVersion | string | Reported connector API version |
ConnectedAPI
| Method | Returns | Description |
|---|---|---|
| getShieldedBalances() | Record<string, bigint> | Shielded token balances |
| getUnshieldedBalances() | Record<string, bigint> | Unshielded token balances |
| getDustBalance() | { cap, balance } | Dust balance |
| getShieldedAddresses() | { shieldedAddress, ... } | Shielded keys |
| getUnshieldedAddress() | { unshieldedAddress } | Unshielded address |
| getDustAddress() | { dustAddress } | Dust address |
| getConfiguration() | Configuration | Network URLs, proof server |
| balanceUnsealedTransaction(hex) | { tx } | Balance a proved transaction |
| submitTransaction(hex) | void | Submit to chain |
| getProvingProvider(keyProvider) | ProvingProvider | Get ZK proving provider |
| signData(data, options) | Signature | Sign arbitrary data |
| makeTransfer(outputs) | { tx } | Create a token transfer |
Hosting ZK Keys
Your compiled contract produces prover keys, verifier keys, and ZKIR files. These must be served via HTTP with CORS enabled.
1your-cdn.com/contract/compiled/your-contract/
2 keys/
3 circuitName.prover (2-10 MB each)
4 circuitName.verifier (2 KB each)
5 zkir/
6 circuitName.bzkir (1-3 KB each)The FetchZkConfigProvider fetches these on demand. Host on any CDN with Access-Control-Allow-Origin: *.
Networks
| Network | Indexer | RPC |
|---|---|---|
| preview | indexer.preview.midnight.network | rpc.preview.midnight.network |
| preprod | indexer.preprod.midnight.network | rpc.preprod.midnight.network |
| mainnet | indexer.mainnet.midnight.network | rpc.mainnet.midnight.network |
Start development on preview. Read the connected wallet's getConfiguration() for the configured endpoints, and check service availability before submitting transactions.
DUST sponsorship
Sponsored transaction fees.
ProofStation can add DUST from a funded sponsorship wallet. Availability depends on the network, service configuration and applicable limits.
1Your DApp → 1AM Wallet → ProofStation
2 ↓
3 1. Proves ZK circuits
4 2. Adds DUST when sponsorship is available
5 3. Returns finalized transaction
6 ↓
7 1AM Wallet submits to Midnight chain
8
9Sponsorship depends on network and service availability.The walletProvider.balanceTx() provider routes the transaction to ProofStation's /balance-only endpoint, where an available sponsorship wallet can add DUST.
ProofStation API
ProofStation is the proving + balancing infrastructure behind 1AM Wallet — ZK proof generation, dust sponsorship, and Cardano queries.
| Endpoint | Method | Description |
|---|---|---|
| /health | GET | Server health + upstream status |
| /prove | POST | Generate ZK proof (native binary) |
| /verify | POST | Verify a ZK proof |
| /prove-and-balance | POST | Prove + balance an unproved TX |
| /balance-only | POST | Balance a pre-proven TX |
| /wallet-status | GET | Sponsorship wallet dust balance |
Auth: X-API-Key: pk_live_xxx · 3 networks: api.1am.xyz · api-preprod.1am.xyz · api-preview.1am.xyz
List Your DApp
Submit your DApp to the 1AM app registry to appear in the wallet's Apps tab.
1{
2 "name": "Your DApp",
3 "description": "Short description",
4 "logo": "https://your-app.com/logo.svg",
5 "link": "https://your-app.com",
6 "chains": ["midnight"],
7 "categories": ["defi", "games", "collectibles", "social", "other"]
8}Submit via the 1AM App Registry on GitHub or DM @oneamxyz
AI Skill for Claude Code
Install Midnight Agent Skills for guidance on wallet integration, Compact contracts and deployment workflows.
1npx skills add UvRoxx/midnight-agent-skillsWhat the skill teaches your AI:
Wallet Detection
Detect and connect the 1AM extension
Provider Setup
Build all 5 providers for contract ops
DUST sponsorship
Use sponsorship where available
Contract Deployment
Deploy and call Compact circuits
ZK Key Hosting
Serve prover keys from CDN
App Registry
Get listed in the 1AM wallet
Demo
Working Example
See the working example at ZKMint: a DApp that compiles a Compact contract, deploys it and calls circuits through 1AM Wallet.
View ZKMintSupport
Need help integrating? Reach out through any of these channels.