@aaronbassett/midnight-local-devnet 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +212 -0
- package/dist/cli/commands/accounts.d.ts +3 -0
- package/dist/cli/commands/accounts.js +38 -0
- package/dist/cli/commands/accounts.js.map +1 -0
- package/dist/cli/commands/network.d.ts +3 -0
- package/dist/cli/commands/network.js +84 -0
- package/dist/cli/commands/network.js.map +1 -0
- package/dist/cli/commands/wallet.d.ts +3 -0
- package/dist/cli/commands/wallet.js +49 -0
- package/dist/cli/commands/wallet.js.map +1 -0
- package/dist/cli/interactive.d.ts +2 -0
- package/dist/cli/interactive.js +90 -0
- package/dist/cli/interactive.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +48 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/accounts.d.ts +17 -0
- package/dist/core/accounts.js +80 -0
- package/dist/core/accounts.js.map +1 -0
- package/dist/core/config.d.ts +12 -0
- package/dist/core/config.js +22 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/docker.d.ts +13 -0
- package/dist/core/docker.js +101 -0
- package/dist/core/docker.js.map +1 -0
- package/dist/core/funding.d.ts +15 -0
- package/dist/core/funding.js +105 -0
- package/dist/core/funding.js.map +1 -0
- package/dist/core/health.d.ts +13 -0
- package/dist/core/health.js +34 -0
- package/dist/core/health.js.map +1 -0
- package/dist/core/logger.d.ts +2 -0
- package/dist/core/logger.js +16 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/network-manager.d.ts +31 -0
- package/dist/core/network-manager.js +101 -0
- package/dist/core/network-manager.js.map +1 -0
- package/dist/core/types.d.ts +51 -0
- package/dist/core/types.js +11 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/wallet.d.ts +23 -0
- package/dist/core/wallet.js +163 -0
- package/dist/core/wallet.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/resources/config.d.ts +3 -0
- package/dist/mcp/resources/config.js +28 -0
- package/dist/mcp/resources/config.js.map +1 -0
- package/dist/mcp/server.d.ts +3 -0
- package/dist/mcp/server.js +28 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/accounts.d.ts +3 -0
- package/dist/mcp/tools/accounts.js +28 -0
- package/dist/mcp/tools/accounts.js.map +1 -0
- package/dist/mcp/tools/funding.d.ts +3 -0
- package/dist/mcp/tools/funding.js +59 -0
- package/dist/mcp/tools/funding.js.map +1 -0
- package/dist/mcp/tools/health.d.ts +3 -0
- package/dist/mcp/tools/health.js +19 -0
- package/dist/mcp/tools/health.js.map +1 -0
- package/dist/mcp/tools/network.d.ts +3 -0
- package/dist/mcp/tools/network.js +64 -0
- package/dist/mcp/tools/network.js.map +1 -0
- package/dist/mcp/tools/wallet.d.ts +3 -0
- package/dist/mcp/tools/wallet.js +19 -0
- package/dist/mcp/tools/wallet.js.map +1 -0
- package/docker/standalone.env +5 -0
- package/docker/standalone.yml +49 -0
- package/package.json +64 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DevRel AI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# midnight-local-devnet
|
|
2
|
+
|
|
3
|
+
A CLI and MCP (Model Context Protocol) server for managing a local Docker-based Midnight development network. It spins up a Midnight node, indexer, and proof server in Docker containers, initializes a genesis master wallet pre-loaded with NIGHT tokens and DUST, and provides commands to fund test accounts, generate wallets, and monitor network health -- all from the command line or from any MCP-compatible AI assistant.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- **Node.js >= 22** (uses native ES modules and `node:` imports)
|
|
8
|
+
- **Docker** (Docker Desktop or Docker Engine with Compose v2)
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install
|
|
14
|
+
npm run build
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
### CLI
|
|
20
|
+
|
|
21
|
+
Run with no arguments to enter interactive mode:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx midnight-devnet
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Or start the network directly:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx midnight-devnet start
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### MCP Server
|
|
34
|
+
|
|
35
|
+
Add the server to your `.mcp.json` (Claude Code, Cursor, or any MCP client):
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"mcpServers": {
|
|
40
|
+
"midnight-devnet": {
|
|
41
|
+
"command": "node",
|
|
42
|
+
"args": ["--enable-source-maps", "/absolute/path/to/midnight-local-devnet/dist/index.js"]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The MCP server communicates over stdio and exposes tools, resources, and prompts that an AI assistant can use to manage the devnet on your behalf.
|
|
49
|
+
|
|
50
|
+
## CLI Command Reference
|
|
51
|
+
|
|
52
|
+
| Command | Description | Options |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| `start` | Start the local Midnight devnet | `--pull` Pull latest Docker images |
|
|
55
|
+
| `stop` | Stop the devnet | `--remove-volumes` Remove volumes and containers |
|
|
56
|
+
| `restart` | Restart the network | `--pull`, `--remove-volumes` |
|
|
57
|
+
| `status` | Show network status and per-service info | |
|
|
58
|
+
| `logs` | Show network service logs | `--service <name>` (node, indexer, proof-server), `--lines <n>` (default: 50) |
|
|
59
|
+
| `health` | Check health of all services | |
|
|
60
|
+
| `balances` | Show master wallet NIGHT/DUST balances | |
|
|
61
|
+
| `fund <address>` | Fund a Bech32 address with NIGHT tokens | `--amount <n>` Amount in NIGHT (default: 50,000) |
|
|
62
|
+
| `fund-file <path>` | Fund all accounts from an accounts.json file | |
|
|
63
|
+
| `generate-accounts` | Generate random test accounts | `--count <n>`, `--format <mnemonic\|privateKey>`, `--output <path>`, `--fund`, `--register-dust` |
|
|
64
|
+
| `interactive` | Start interactive menu mode | |
|
|
65
|
+
|
|
66
|
+
Running the CLI with no arguments automatically enters interactive mode.
|
|
67
|
+
|
|
68
|
+
## MCP Tool Reference
|
|
69
|
+
|
|
70
|
+
| Tool | Description | Parameters |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| `start-network` | Start the devnet (node, indexer, proof-server) | `pull?` boolean |
|
|
73
|
+
| `stop-network` | Stop the devnet and close wallets | `removeVolumes?` boolean |
|
|
74
|
+
| `restart-network` | Restart the network | `pull?` boolean, `removeVolumes?` boolean |
|
|
75
|
+
| `network-status` | Get current network and per-service status | |
|
|
76
|
+
| `network-logs` | Get recent logs from services | `service?` (node, indexer, proof-server), `lines?` number |
|
|
77
|
+
| `health-check` | Check health of all service endpoints | |
|
|
78
|
+
| `get-network-config` | Get endpoint URLs, network ID, image versions | |
|
|
79
|
+
| `get-wallet-balances` | Get NIGHT and DUST balances of master wallet | |
|
|
80
|
+
| `fund-account` | Transfer NIGHT to a Bech32 address | `address` string, `amount?` string |
|
|
81
|
+
| `fund-account-from-mnemonic` | Derive wallet from mnemonic, fund NIGHT, register DUST | `name` string, `mnemonic` string |
|
|
82
|
+
| `fund-accounts-from-file` | Batch fund accounts from accounts.json | `filePath` string |
|
|
83
|
+
| `generate-test-account` | Generate random test accounts | `format` (mnemonic\|privateKey), `count?`, `fund?`, `registerDust?`, `outputFile?` |
|
|
84
|
+
|
|
85
|
+
## MCP Resource Reference
|
|
86
|
+
|
|
87
|
+
| URI | Description |
|
|
88
|
+
|---|---|
|
|
89
|
+
| `devnet://config` | Current network configuration: endpoints, network ID, Docker image versions |
|
|
90
|
+
| `devnet://status` | Live network status including per-service container state |
|
|
91
|
+
|
|
92
|
+
Resources are read-only and can be accessed by any MCP client to display context to an AI assistant.
|
|
93
|
+
|
|
94
|
+
## accounts.json Format
|
|
95
|
+
|
|
96
|
+
The `fund-file` CLI command and `fund-accounts-from-file` MCP tool accept a JSON file describing accounts to fund. Each account is identified by a mnemonic; the tool derives its wallet, transfers NIGHT tokens, and registers DUST.
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"accounts": [
|
|
101
|
+
{
|
|
102
|
+
"name": "Alice",
|
|
103
|
+
"mnemonic": "abandon abandon abandon ... art"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"name": "Bob",
|
|
107
|
+
"mnemonic": "zoo zoo zoo ... vote"
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
See `accounts.example.json` for a complete example with valid 24-word BIP39 mnemonics.
|
|
114
|
+
|
|
115
|
+
Each account entry requires:
|
|
116
|
+
|
|
117
|
+
- **name** -- A display label for the account.
|
|
118
|
+
- **mnemonic** -- A 24-word BIP39 mnemonic phrase.
|
|
119
|
+
|
|
120
|
+
## Docker Services
|
|
121
|
+
|
|
122
|
+
The devnet runs three containers managed via Docker Compose:
|
|
123
|
+
|
|
124
|
+
| Service | Container Name | Image | Port | URL |
|
|
125
|
+
|---|---|---|---|---|
|
|
126
|
+
| Node | midnight-node | `midnightntwrk/midnight-node:0.20.0` | 9944 | `http://127.0.0.1:9944` |
|
|
127
|
+
| Indexer | midnight-indexer | `midnightntwrk/indexer-standalone:3.0.0` | 8088 | `http://127.0.0.1:8088/api/v3/graphql` |
|
|
128
|
+
| Proof Server | midnight-proof-server | `midnightntwrk/proof-server:7.0.0` | 6300 | `http://127.0.0.1:6300` |
|
|
129
|
+
|
|
130
|
+
The indexer also exposes a WebSocket endpoint at `ws://127.0.0.1:8088/api/v3/graphql/ws`.
|
|
131
|
+
|
|
132
|
+
The network ID is `undeployed` (development mode).
|
|
133
|
+
|
|
134
|
+
## Network Endpoints for DApp Development
|
|
135
|
+
|
|
136
|
+
When connecting a Midnight DApp to the local devnet, use the following configuration:
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
const config = {
|
|
140
|
+
indexer: 'http://127.0.0.1:8088/api/v3/graphql',
|
|
141
|
+
indexerWS: 'ws://127.0.0.1:8088/api/v3/graphql/ws',
|
|
142
|
+
node: 'http://127.0.0.1:9944',
|
|
143
|
+
proofServer: 'http://127.0.0.1:6300',
|
|
144
|
+
networkId: 'undeployed',
|
|
145
|
+
};
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
You can also retrieve this configuration at runtime via the `get-network-config` MCP tool or the `devnet://config` MCP resource.
|
|
149
|
+
|
|
150
|
+
## Troubleshooting
|
|
151
|
+
|
|
152
|
+
### Docker containers fail to start
|
|
153
|
+
|
|
154
|
+
Make sure Docker is running and your user has permissions to use it:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
docker info
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
If you see a permission error, add your user to the `docker` group or use `sudo`.
|
|
161
|
+
|
|
162
|
+
### Port conflicts
|
|
163
|
+
|
|
164
|
+
The devnet uses ports 9944, 8088, and 6300. If another process is using one of these ports, stop it before starting the devnet:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
lsof -i :9944
|
|
168
|
+
lsof -i :8088
|
|
169
|
+
lsof -i :6300
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Containers are unhealthy
|
|
173
|
+
|
|
174
|
+
Run the health check to see which service is not responding:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
npx midnight-devnet health
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Check the logs for the failing service:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
npx midnight-devnet logs --service node
|
|
184
|
+
npx midnight-devnet logs --service indexer
|
|
185
|
+
npx midnight-devnet logs --service proof-server
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Clean restart
|
|
189
|
+
|
|
190
|
+
If the network is in a broken state, do a clean restart that removes all volumes:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
npx midnight-devnet restart --remove-volumes
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
This removes all chain data and starts fresh.
|
|
197
|
+
|
|
198
|
+
### Wallet sync takes too long
|
|
199
|
+
|
|
200
|
+
The master wallet must synchronize with the chain on first start. This can take 10--30 seconds depending on your machine. The CLI and MCP server wait for synchronization automatically.
|
|
201
|
+
|
|
202
|
+
### "Network is not running" error
|
|
203
|
+
|
|
204
|
+
The tool detects running containers on startup. If you stopped the containers externally (e.g. via `docker compose down`), run `start` again:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
npx midnight-devnet start
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## License
|
|
211
|
+
|
|
212
|
+
MIT
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { generateAccounts, generateAndFundAccounts, writeAccountsFile } from '../../core/accounts.js';
|
|
2
|
+
export function registerAccountCommands(program, manager) {
|
|
3
|
+
program
|
|
4
|
+
.command('generate-accounts')
|
|
5
|
+
.description('Generate random test accounts')
|
|
6
|
+
.option('--count <n>', 'Number of accounts', '1')
|
|
7
|
+
.option('--format <type>', 'mnemonic or privateKey', 'mnemonic')
|
|
8
|
+
.option('--output <path>', 'Write to file in accounts.json format')
|
|
9
|
+
.option('--fund', 'Fund accounts from master wallet')
|
|
10
|
+
.option('--register-dust', 'Register DUST for funded accounts')
|
|
11
|
+
.action(async (opts) => {
|
|
12
|
+
const format = opts.format;
|
|
13
|
+
const count = parseInt(opts.count, 10);
|
|
14
|
+
let accounts;
|
|
15
|
+
if (opts.fund) {
|
|
16
|
+
const wallet = await manager.ensureWallet();
|
|
17
|
+
accounts = await generateAndFundAccounts(wallet, manager.config, {
|
|
18
|
+
format,
|
|
19
|
+
count,
|
|
20
|
+
fund: true,
|
|
21
|
+
registerDust: opts.registerDust ?? false,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
accounts = await generateAccounts({ format, count });
|
|
26
|
+
}
|
|
27
|
+
if (opts.output) {
|
|
28
|
+
await writeAccountsFile(opts.output, accounts);
|
|
29
|
+
console.log(`Accounts written to ${opts.output}`);
|
|
30
|
+
}
|
|
31
|
+
console.table(accounts.map((a) => ({
|
|
32
|
+
Name: a.name,
|
|
33
|
+
Address: a.address || '(generated on fund)',
|
|
34
|
+
...(a.mnemonic ? { Mnemonic: a.mnemonic.split(' ').slice(0, 3).join(' ') + '...' } : {}),
|
|
35
|
+
})));
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=accounts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accounts.js","sourceRoot":"","sources":["../../../src/cli/commands/accounts.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEtG,MAAM,UAAU,uBAAuB,CAAC,OAAgB,EAAE,OAAuB;IAC/E,OAAO;SACJ,OAAO,CAAC,mBAAmB,CAAC;SAC5B,WAAW,CAAC,+BAA+B,CAAC;SAC5C,MAAM,CAAC,aAAa,EAAE,oBAAoB,EAAE,GAAG,CAAC;SAChD,MAAM,CAAC,iBAAiB,EAAE,wBAAwB,EAAE,UAAU,CAAC;SAC/D,MAAM,CAAC,iBAAiB,EAAE,uCAAuC,CAAC;SAClE,MAAM,CAAC,QAAQ,EAAE,kCAAkC,CAAC;SACpD,MAAM,CAAC,iBAAiB,EAAE,mCAAmC,CAAC;SAC9D,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAmC,CAAC;QACxD,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAEvC,IAAI,QAAQ,CAAC;QACb,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,YAAY,EAAE,CAAC;YAC5C,QAAQ,GAAG,MAAM,uBAAuB,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE;gBAC/D,MAAM;gBACN,KAAK;gBACL,IAAI,EAAE,IAAI;gBACV,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,KAAK;aACzC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,QAAQ,GAAG,MAAM,gBAAgB,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACvD,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,MAAM,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YAC/C,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACpD,CAAC;QAED,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACjC,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,qBAAqB;YAC3C,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzF,CAAC,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { checkAllHealth } from '../../core/health.js';
|
|
2
|
+
export function registerNetworkCommands(program, manager) {
|
|
3
|
+
program
|
|
4
|
+
.command('start')
|
|
5
|
+
.description('Start the local Midnight development network')
|
|
6
|
+
.option('--pull', 'Pull latest Docker images before starting')
|
|
7
|
+
.action(async (opts) => {
|
|
8
|
+
console.log('Starting Midnight local devnet...');
|
|
9
|
+
const result = await manager.start({ pull: opts.pull ?? false });
|
|
10
|
+
if (result === 'already-running') {
|
|
11
|
+
console.log('Network is already running.');
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
console.log('Network is ready.');
|
|
15
|
+
}
|
|
16
|
+
const services = await manager.getServices();
|
|
17
|
+
console.table(services.map((s) => ({ Service: s.name, Port: s.port, URL: s.url, Status: s.status })));
|
|
18
|
+
});
|
|
19
|
+
program
|
|
20
|
+
.command('stop')
|
|
21
|
+
.description('Stop the local Midnight development network')
|
|
22
|
+
.option('--remove-volumes', 'Remove volumes and containers')
|
|
23
|
+
.action(async (opts) => {
|
|
24
|
+
await manager.stop({ removeVolumes: opts.removeVolumes ?? false });
|
|
25
|
+
console.log('Network stopped.');
|
|
26
|
+
});
|
|
27
|
+
program
|
|
28
|
+
.command('restart')
|
|
29
|
+
.description('Restart the network')
|
|
30
|
+
.option('--pull', 'Pull latest Docker images')
|
|
31
|
+
.option('--remove-volumes', 'Remove volumes for clean restart')
|
|
32
|
+
.action(async (opts) => {
|
|
33
|
+
await manager.restart({
|
|
34
|
+
pull: opts.pull ?? false,
|
|
35
|
+
removeVolumes: opts.removeVolumes ?? false,
|
|
36
|
+
});
|
|
37
|
+
console.log('Network restarted and ready.');
|
|
38
|
+
});
|
|
39
|
+
program
|
|
40
|
+
.command('status')
|
|
41
|
+
.description('Show network status')
|
|
42
|
+
.action(async () => {
|
|
43
|
+
try {
|
|
44
|
+
const services = await manager.getServices();
|
|
45
|
+
if (services.length === 0) {
|
|
46
|
+
console.log('Network is not running.');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
console.table(services.map((s) => ({
|
|
50
|
+
Service: s.name,
|
|
51
|
+
Status: s.status,
|
|
52
|
+
Port: s.port,
|
|
53
|
+
URL: s.url,
|
|
54
|
+
})));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
console.log('Network is not running.');
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
program
|
|
61
|
+
.command('logs')
|
|
62
|
+
.description('Show network service logs')
|
|
63
|
+
.option('--service <name>', 'Specific service (node, indexer, proof-server)')
|
|
64
|
+
.option('--lines <n>', 'Number of lines', '50')
|
|
65
|
+
.action(async (opts) => {
|
|
66
|
+
const logs = await manager.getLogs({
|
|
67
|
+
service: opts.service,
|
|
68
|
+
lines: parseInt(opts.lines, 10),
|
|
69
|
+
});
|
|
70
|
+
console.log(logs);
|
|
71
|
+
});
|
|
72
|
+
program
|
|
73
|
+
.command('health')
|
|
74
|
+
.description('Check health of all services')
|
|
75
|
+
.action(async () => {
|
|
76
|
+
const health = await checkAllHealth(manager.config);
|
|
77
|
+
console.table({
|
|
78
|
+
Node: { Healthy: health.node.healthy, 'Response (ms)': health.node.responseTime },
|
|
79
|
+
Indexer: { Healthy: health.indexer.healthy, 'Response (ms)': health.indexer.responseTime },
|
|
80
|
+
'Proof Server': { Healthy: health.proofServer.healthy, 'Response (ms)': health.proofServer.responseTime },
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=network.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network.js","sourceRoot":"","sources":["../../../src/cli/commands/network.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { getWalletBalances } from '../../core/wallet.js';
|
|
2
|
+
import { fundAccount, fundAccountsFromFile } from '../../core/funding.js';
|
|
3
|
+
export function registerWalletCommands(program, manager) {
|
|
4
|
+
program
|
|
5
|
+
.command('balances')
|
|
6
|
+
.description('Show master wallet balances')
|
|
7
|
+
.action(async () => {
|
|
8
|
+
const wallet = await manager.ensureWallet();
|
|
9
|
+
const b = await getWalletBalances(wallet);
|
|
10
|
+
console.table({
|
|
11
|
+
Unshielded: b.unshielded.toString(),
|
|
12
|
+
Shielded: b.shielded.toString(),
|
|
13
|
+
DUST: b.dust.toString(),
|
|
14
|
+
Total: b.total.toString(),
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
program
|
|
18
|
+
.command('fund <address>')
|
|
19
|
+
.description('Fund an address with NIGHT tokens')
|
|
20
|
+
.option('--amount <n>', 'Amount in NIGHT (default: 50000)')
|
|
21
|
+
.action(async (address, opts) => {
|
|
22
|
+
const wallet = await manager.ensureWallet();
|
|
23
|
+
let amount;
|
|
24
|
+
if (opts.amount) {
|
|
25
|
+
if (!/^[1-9]\d*$/.test(opts.amount)) {
|
|
26
|
+
console.error('Error: --amount must be a positive whole number of NIGHT tokens.');
|
|
27
|
+
process.exitCode = 1;
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
amount = BigInt(opts.amount) * 10n ** 6n;
|
|
31
|
+
}
|
|
32
|
+
const result = await fundAccount(wallet, address, amount);
|
|
33
|
+
console.log(`Funded ${result.address} with ${result.amount} NIGHT (tx: ${result.txHash})`);
|
|
34
|
+
});
|
|
35
|
+
program
|
|
36
|
+
.command('fund-file <path>')
|
|
37
|
+
.description('Fund accounts from an accounts.json file')
|
|
38
|
+
.action(async (filePath) => {
|
|
39
|
+
const wallet = await manager.ensureWallet();
|
|
40
|
+
const results = await fundAccountsFromFile(wallet, filePath, manager.config);
|
|
41
|
+
console.table(results.map((r) => ({
|
|
42
|
+
Name: r.name,
|
|
43
|
+
Address: r.address,
|
|
44
|
+
Amount: r.amount.toString(),
|
|
45
|
+
DUST: r.hasDust ? 'Yes' : 'No',
|
|
46
|
+
})));
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=wallet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wallet.js","sourceRoot":"","sources":["../../../src/cli/commands/wallet.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE1E,MAAM,UAAU,sBAAsB,CAAC,OAAgB,EAAE,OAAuB;IAC9E,OAAO;SACJ,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,6BAA6B,CAAC;SAC1C,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,YAAY,EAAE,CAAC;QAC5C,MAAM,CAAC,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC1C,OAAO,CAAC,KAAK,CAAC;YACZ,UAAU,EAAE,CAAC,CAAC,UAAU,CAAC,QAAQ,EAAE;YACnC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE;YAC/B,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE;YACvB,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE;SAC1B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CAAC,mCAAmC,CAAC;SAChD,MAAM,CAAC,cAAc,EAAE,kCAAkC,CAAC;SAC1D,MAAM,CAAC,KAAK,EAAE,OAAe,EAAE,IAAI,EAAE,EAAE;QACtC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,YAAY,EAAE,CAAC;QAC5C,IAAI,MAA0B,CAAC;QAC/B,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;gBACpC,OAAO,CAAC,KAAK,CAAC,kEAAkE,CAAC,CAAC;gBAClF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;gBACrB,OAAO;YACT,CAAC;YACD,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,EAAE,CAAC;QAC3C,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,UAAU,MAAM,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,eAAe,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7F,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,kBAAkB,CAAC;SAC3B,WAAW,CAAC,0CAA0C,CAAC;SACvD,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,EAAE;QACjC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,YAAY,EAAE,CAAC;QAC5C,MAAM,OAAO,GAAG,MAAM,oBAAoB,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAC7E,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAChC,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;YAC3B,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;SAC/B,CAAC,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { stdin as input, stdout as output } from 'node:process';
|
|
2
|
+
import { createInterface } from 'node:readline/promises';
|
|
3
|
+
import { fundAccount, fundAccountsFromFile } from '../core/funding.js';
|
|
4
|
+
import { generateAccounts, writeAccountsFile } from '../core/accounts.js';
|
|
5
|
+
import { getWalletBalances } from '../core/wallet.js';
|
|
6
|
+
export async function startInteractiveMode(manager) {
|
|
7
|
+
const rli = createInterface({ input, output });
|
|
8
|
+
console.log('Midnight Local Devnet — Interactive Mode\n');
|
|
9
|
+
if (manager.getStatus() === 'running') {
|
|
10
|
+
console.log('Detected running network. Initializing wallet...');
|
|
11
|
+
await manager.ensureWallet();
|
|
12
|
+
console.log('Ready.\n');
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
console.log('Starting network...');
|
|
16
|
+
await manager.start({ pull: false });
|
|
17
|
+
console.log('Network ready.\n');
|
|
18
|
+
}
|
|
19
|
+
const showMenu = () => {
|
|
20
|
+
console.log('\nChoose an option:');
|
|
21
|
+
console.log(' [1] Fund accounts from config file (NIGHT + DUST)');
|
|
22
|
+
console.log(' [2] Fund account by address (NIGHT only)');
|
|
23
|
+
console.log(' [3] Generate test accounts');
|
|
24
|
+
console.log(' [4] Display master wallet balances');
|
|
25
|
+
console.log(' [5] Show network status');
|
|
26
|
+
console.log(' [6] Exit');
|
|
27
|
+
};
|
|
28
|
+
let running = true;
|
|
29
|
+
while (running) {
|
|
30
|
+
showMenu();
|
|
31
|
+
const choice = await rli.question('> ');
|
|
32
|
+
try {
|
|
33
|
+
switch (choice.trim()) {
|
|
34
|
+
case '1': {
|
|
35
|
+
const path = await rli.question('Path to accounts JSON file: ');
|
|
36
|
+
const wallet = await manager.ensureWallet();
|
|
37
|
+
const results = await fundAccountsFromFile(wallet, path.trim(), manager.config);
|
|
38
|
+
console.table(results.map((r) => ({ Name: r.name, Address: r.address, DUST: r.hasDust })));
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
case '2': {
|
|
42
|
+
const addr = await rli.question('Bech32 address: ');
|
|
43
|
+
const wallet = await manager.ensureWallet();
|
|
44
|
+
await fundAccount(wallet, addr.trim());
|
|
45
|
+
console.log('Funded.');
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
case '3': {
|
|
49
|
+
const countStr = await rli.question('How many accounts? [1]: ');
|
|
50
|
+
const count = parseInt(countStr.trim() || '1', 10);
|
|
51
|
+
const accounts = await generateAccounts({ format: 'mnemonic', count });
|
|
52
|
+
const outPath = await rli.question('Save to file? (path or empty to skip): ');
|
|
53
|
+
if (outPath.trim()) {
|
|
54
|
+
await writeAccountsFile(outPath.trim(), accounts);
|
|
55
|
+
}
|
|
56
|
+
console.table(accounts.map((a) => ({ Name: a.name, Mnemonic: a.mnemonic })));
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
case '4': {
|
|
60
|
+
const wallet = await manager.ensureWallet();
|
|
61
|
+
const b = await getWalletBalances(wallet);
|
|
62
|
+
console.table({
|
|
63
|
+
Unshielded: b.unshielded.toString(),
|
|
64
|
+
Shielded: b.shielded.toString(),
|
|
65
|
+
DUST: b.dust.toString(),
|
|
66
|
+
});
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
case '5': {
|
|
70
|
+
const services = await manager.getServices();
|
|
71
|
+
console.table(services);
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
case '6':
|
|
75
|
+
running = false;
|
|
76
|
+
break;
|
|
77
|
+
default:
|
|
78
|
+
console.log('Invalid option.');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
console.error('Error:', err instanceof Error ? err.message : err);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
console.log('\nShutting down wallet (containers left running)...');
|
|
86
|
+
await manager.shutdown();
|
|
87
|
+
rli.close();
|
|
88
|
+
console.log('Goodbye.');
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=interactive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive.js","sourceRoot":"","sources":["../../src/cli/interactive.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { NetworkManager } from './core/network-manager.js';
|
|
4
|
+
import { registerNetworkCommands } from './cli/commands/network.js';
|
|
5
|
+
import { registerWalletCommands } from './cli/commands/wallet.js';
|
|
6
|
+
import { registerAccountCommands } from './cli/commands/accounts.js';
|
|
7
|
+
import { startInteractiveMode } from './cli/interactive.js';
|
|
8
|
+
import { createLogger } from './core/logger.js';
|
|
9
|
+
import { setLogger as setWalletLogger } from './core/wallet.js';
|
|
10
|
+
import { setLogger as setFundingLogger } from './core/funding.js';
|
|
11
|
+
import { setLogger as setAccountsLogger } from './core/accounts.js';
|
|
12
|
+
const manager = new NetworkManager();
|
|
13
|
+
const logger = createLogger();
|
|
14
|
+
setWalletLogger(logger);
|
|
15
|
+
setFundingLogger(logger);
|
|
16
|
+
setAccountsLogger(logger);
|
|
17
|
+
manager.setLogger(logger);
|
|
18
|
+
// Detect existing containers before running any command
|
|
19
|
+
await manager.detectRunningNetwork();
|
|
20
|
+
// Graceful shutdown on Ctrl+C
|
|
21
|
+
const shutdown = async () => {
|
|
22
|
+
await manager.shutdown();
|
|
23
|
+
process.exit(0);
|
|
24
|
+
};
|
|
25
|
+
process.on('SIGINT', shutdown);
|
|
26
|
+
process.on('SIGTERM', shutdown);
|
|
27
|
+
const program = new Command();
|
|
28
|
+
program
|
|
29
|
+
.name('midnight-local-devnet')
|
|
30
|
+
.description('Manage a local Midnight development network')
|
|
31
|
+
.version('0.1.0');
|
|
32
|
+
registerNetworkCommands(program, manager);
|
|
33
|
+
registerWalletCommands(program, manager);
|
|
34
|
+
registerAccountCommands(program, manager);
|
|
35
|
+
program
|
|
36
|
+
.command('interactive')
|
|
37
|
+
.description('Start interactive menu mode')
|
|
38
|
+
.action(async () => {
|
|
39
|
+
await startInteractiveMode(manager);
|
|
40
|
+
});
|
|
41
|
+
// No arguments = interactive mode
|
|
42
|
+
if (process.argv.length <= 2) {
|
|
43
|
+
startInteractiveMode(manager).catch(console.error);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
program.parse();
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,SAAS,IAAI,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,SAAS,IAAI,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,SAAS,IAAI,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEpE,MAAM,OAAO,GAAG,IAAI,cAAc,EAAE,CAAC;AAErC,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;AAC9B,eAAe,CAAC,MAAM,CAAC,CAAC;AACxB,gBAAgB,CAAC,MAAM,CAAC,CAAC;AACzB,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAC1B,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AAE1B,wDAAwD;AACxD,MAAM,OAAO,CAAC,oBAAoB,EAAE,CAAC;AAErC,8BAA8B;AAC9B,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;IAC1B,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC;IACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC;AACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAEhC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,uBAAuB,CAAC;KAC7B,WAAW,CAAC,6CAA6C,CAAC;KAC1D,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,uBAAuB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAC1C,sBAAsB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AACzC,uBAAuB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAE1C,OAAO;KACJ,OAAO,CAAC,aAAa,CAAC;KACtB,WAAW,CAAC,6BAA6B,CAAC;KAC1C,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;AACtC,CAAC,CAAC,CAAC;AAEL,kCAAkC;AAClC,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;IAC7B,oBAAoB,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AACrD,CAAC;KAAM,CAAC;IACN,OAAO,CAAC,KAAK,EAAE,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { GeneratedAccount, NetworkConfig } from './types.js';
|
|
2
|
+
import type { WalletContext } from './wallet.js';
|
|
3
|
+
import type { Logger } from 'pino';
|
|
4
|
+
export declare function setLogger(l: Logger): void;
|
|
5
|
+
export interface GenerateOptions {
|
|
6
|
+
format: 'mnemonic' | 'privateKey';
|
|
7
|
+
count?: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function generateAccounts(opts: GenerateOptions): Promise<GeneratedAccount[]>;
|
|
10
|
+
export declare function generateAndFundAccounts(masterWallet: WalletContext, config: NetworkConfig, opts: GenerateOptions & {
|
|
11
|
+
fund?: boolean;
|
|
12
|
+
registerDust?: boolean;
|
|
13
|
+
}): Promise<(GeneratedAccount & {
|
|
14
|
+
funded?: boolean;
|
|
15
|
+
dustRegistered?: boolean;
|
|
16
|
+
})[]>;
|
|
17
|
+
export declare function writeAccountsFile(filePath: string, accounts: GeneratedAccount[]): Promise<void>;
|