Developer wallet for the Midnight blockchain ecosystem
A Chrome extension wallet designed for QA teams and developers to test Midnight dApps. Implements the full @midnight-ntwrk/dapp-connector-api specification with real wallet SDK integration.
- Generate wallets - BIP39 mnemonic seed phrase generation
- Import wallets - From seed phrase, private key, or hex seed
- Prefunded localnet wallets - One-click import of genesis mint wallets (0-3)
- Secure key storage - In-memory only, keys never persisted to disk
- Full
window.midnightAPI implementation (v4.0.0-beta.2) InitialAPIwith connect flowConnectedAPIwith balance queries, signing, configuration- Compatible with Midnight dApps expecting standard wallet interface
| Network | Node | Indexer | Prover |
|---|---|---|---|
| Localnet | localhost:9944 | localhost:8088 | localhost:6300 |
| DevNet | devnet.midnight.network | devnet indexer | devnet prover |
| QANET | qanet.midnight.network | qanet indexer | qanet prover |
| Preview | preview.midnight.network | preview indexer | preview prover |
| PreProd | preprod.midnight.network | preprod indexer | preprod prover |
| Custom | User-defined URLs |
- Dust tab - DUST coin inventory with values and status
- Shielded tab - Shielded wallet state and balances
- Unshielded tab - Unshielded wallet state and balances
- Transactions tab - Recent transaction history from both wallets
- Real-time status indicators for Node, Indexer, and Prover
- Color-coded health dots (green/yellow/red)
- Latency display and error reporting
- Automatic polling with exponential backoff
- Node.js 18+
- npm 9+
- Chrome browser
# Clone the repository
git clone https://github.com/user/lumen.git
cd lumen
# Install dependencies
npm install
# Build the extension
npm run build- Open Chrome and navigate to
chrome://extensions - Enable Developer mode (toggle in top right)
- Click Load unpacked
- Select the
dist/folder from the project
- Click the Lumen extension icon in Chrome toolbar
- Select your target network (Localnet, DevNet, etc.)
- Either:
- Click Generate Wallet to create a new wallet
- Click Import to restore from seed phrase
- For Localnet: Use quick-import buttons for prefunded wallets
// Check if Lumen is installed
if (window.midnight && window.midnight['lumen-wallet']) {
console.log('Lumen wallet detected');
}
// Listen for wallet availability
window.addEventListener('midnight#ready', (event) => {
console.log('Wallet ready:', event.detail.uuid);
});const lumen = window.midnight['lumen-wallet'];
// Connect to wallet
const api = await lumen.connect('devnet');
// Get addresses
const { dustAddress } = await api.getDustAddress();
const { unshieldedAddress } = await api.getUnshieldedAddress();
// Get balance
const { balance, cap } = await api.getDustBalance();
console.log(`Balance: ${balance} / ${cap}`);const signature = await api.signData('Hello Midnight', {
encoding: 'text',
keyType: 'unshielded'
});
console.log('Signature:', signature.signature);
console.log('Verifying key:', signature.verifyingKey);const config = await api.getConfiguration();
// Returns: { indexerUri, indexerWsUri, proverServerUri, substrateNodeUri, networkId }βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Chrome Extension β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
β β Popup β β Content β β Inject β β
β β (popup.ts) β β (content.ts)β β (inject.ts) β β
β β β β β β β β
β β - UI/UX β β - Message β β - window. β β
β β - Settings β β relay β β midnight β β
β β - Debug β β - Origin β β - dApp API β β
β β panel β β validationβ β β β
β ββββββββ¬ββββββββ ββββββββ¬ββββββββ ββββββββ¬ββββββββ β
β β β β β
β βββββββββββ¬ββββββββββ΄ββββββββββ¬ββββββββββ β
β β β β
β βΌ βΌ β
β βββββββββββββββββββββββββββββββββββββββ β
β β Service Worker β β
β β (service-worker.ts) β β
β β β β
β β βββββββββββββββ βββββββββββββββββ β β
β β β Wallet β β Facade β β β
β β β Core β β (SDK wrap) β β β
β β β β β β β β
β β β - Keys β β - DustWallet β β β
β β β - Signing β β - Shielded β β β
β β β - Import β β - Unshielded β β β
β β βββββββββββββββ βββββββββββββββββ β β
β βββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββ
β Midnight Network β
β β
β Node βββ Indexer βββ Prover β
βββββββββββββββββββββββββββββββββ
src/
βββ background/
β βββ service-worker.ts # Wallet state, message handlers, SDK facade
βββ content/
β βββ content.ts # Message relay, origin validation
βββ inject/
β βββ inject.ts # window.midnight API implementation
βββ popup/
β βββ popup.html # Extension popup markup
β βββ popup.css # Styles
β βββ popup.ts # UI logic, debug panel
βββ core/
β βββ wallet.ts # Key generation, signing, import
β βββ network.ts # RPC client, health checks
β βββ facade.ts # Wallet SDK wrapper
β βββ types.ts # Shared type definitions
βββ lib/
βββ messaging.ts # Message passing utilities
Lumen implements defense-in-depth security measures:
- In-memory only - Keys never written to disk or chrome.storage
- Secure wiping - Random overwrite before clearing key buffers
- Popup-only access - Sensitive methods restricted to extension popup
- Error cleanup - Automatic key wipe on uncaught errors
- Origin validation - Approved origins tracked per session
- Protocol blocking - Rejects
data:,blob:,file:,javascript:URLs - Rate limiting - 100 requests/minute per origin
- Specific postMessage - No wildcard origins
- XSS prevention - HTML escaping for all blockchain data
- Config integrity - SHA-256 checksums for stored settings
- Response limits - 100KB max for health check responses
- Generic errors - No implementation details leaked
- Conditional logging - Sensitive data only logged in development
- Private IP blocking - SSRF protection for custom URLs
- Exponential backoff - Circuit breaker for failed operations
Run a local Midnight network for development and testing.
- Docker and Docker Compose
- Ports 9944, 8088, and 6300 available
npm run localnet:up # Start all services
npm run localnet:down # Stop all services
npm run localnet:logs # View service logs
npm run localnet:reset # Reset data and restart| Service | Port | Description |
|---|---|---|
| node | 9944 | Midnight Substrate node (WebSocket RPC) |
| indexer | 8088 | GraphQL indexer API |
| proof-server | 6300 | ZK proof generation server |
Localnet includes 4 prefunded genesis wallets with DUST:
| Wallet | Quick Import |
|---|---|
| Wallet 0 | Click "0" button in popup |
| Wallet 1 | Click "1" button in popup |
| Wallet 2 | Click "2" button in popup |
| Wallet 3 | Click "3" button in popup |
cp .env.example .env
# Edit .env to customize:
# - APP_INFRA_SECRET for indexer authnpm install # Install dependencies
npm run build # Production build
npm run dev # Watch mode (rebuilds on changes)npm test # Run unit tests- Load the extension in Chrome (see Quick Start)
- Open
test/dapp-test.htmlin a browser tab - Click "Detect Wallet" to verify API injection
- Click "Connect" to test wallet connection flow
dist/
βββ manifest.json # Extension manifest
βββ background.js # Service worker bundle (~29MB with WASM)
βββ content.js # Content script
βββ inject.js # Injected script
βββ popup/
βββ popup.html
βββ popup.css
βββ popup.js
| Property | Type | Description |
|---|---|---|
rdns |
string | Reverse DNS identifier (io.lumen.wallet) |
name |
string | Wallet name (Lumen) |
icon |
string | Base64 SVG icon |
apiVersion |
string | API version (4.0.0-beta.2) |
connect(networkId) |
function | Connect and return ConnectedAPI |
| Method | Returns | Description |
|---|---|---|
getDustAddress() |
{ dustAddress } |
Get DUST address |
getUnshieldedAddress() |
{ unshieldedAddress } |
Get unshielded address |
getDustBalance() |
{ balance, cap } |
Get DUST balance |
signData(data, options) |
{ data, signature, verifyingKey } |
Sign arbitrary data |
getConfiguration() |
Configuration |
Get network endpoints |
getConnectionStatus() |
{ status, networkId } |
Check connection state |
- Ensure
dist/folder exists (runnpm run build) - Check Chrome developer mode is enabled
- Look for errors in
chrome://extensions
- Verify the dApp page is using
window.midnight['lumen-wallet'] - Check browser console for connection errors
- Ensure wallet is unlocked (has active wallet loaded)
- Wait for wallet sync (check debug panel for sync progress)
- Verify network selection matches where funds exist
- For localnet, use prefunded wallets (0-3)
- Check if localnet services are running (
npm run localnet:logs) - Verify network URLs in settings
- Check network connectivity
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- TypeScript strict mode
- No
anytypes without justification - ESLint + Prettier formatting
MIT License - see LICENSE for details.
- Midnight Network - Blockchain platform
- @midnight-ntwrk packages - Official SDK
- Polkadot.js - Substrate RPC client