beignet 0.2.0 → 0.3.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/README.md +284 -1
- package/dist/cli/beignet-node.js +1019 -47
- package/dist/cli/beignet-node.js.map +1 -1
- package/dist/cli/cli.js +1201 -16
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/config.js +21 -1
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/daemon.js +342 -16
- package/dist/cli/daemon.js.map +1 -1
- package/dist/cli/errors.js +2 -0
- package/dist/cli/errors.js.map +1 -1
- package/dist/cli/openapi.js +1207 -14
- package/dist/cli/openapi.js.map +1 -1
- package/dist/cli/restore.js +89 -0
- package/dist/cli/restore.js.map +1 -0
- package/dist/cli/wallet-storage.js +34 -0
- package/dist/cli/wallet-storage.js.map +1 -0
- package/dist/electrum/index.js +105 -10
- package/dist/electrum/index.js.map +1 -1
- package/dist/lightning/advisor/fee-tuner.js +42 -0
- package/dist/lightning/advisor/fee-tuner.js.map +1 -0
- package/dist/lightning/advisor/index.js +9 -1
- package/dist/lightning/advisor/index.js.map +1 -1
- package/dist/lightning/advisor/rebalance-planner.js +55 -0
- package/dist/lightning/advisor/rebalance-planner.js.map +1 -0
- package/dist/lightning/backup/index.js +18 -0
- package/dist/lightning/backup/index.js.map +1 -0
- package/dist/lightning/backup/scb.js +42 -0
- package/dist/lightning/backup/scb.js.map +1 -0
- package/dist/lightning/chain/chain-monitor.js +27 -0
- package/dist/lightning/chain/chain-monitor.js.map +1 -1
- package/dist/lightning/chain/output-resolver.js +55 -6
- package/dist/lightning/chain/output-resolver.js.map +1 -1
- package/dist/lightning/chain/types.js +1 -0
- package/dist/lightning/chain/types.js.map +1 -1
- package/dist/lightning/channel/channel-manager.js +64 -0
- package/dist/lightning/channel/channel-manager.js.map +1 -1
- package/dist/lightning/channel/channel-state.js.map +1 -1
- package/dist/lightning/channel/channel.js +124 -4
- package/dist/lightning/channel/channel.js.map +1 -1
- package/dist/lightning/channel/dual-funding.js +6 -5
- package/dist/lightning/channel/dual-funding.js.map +1 -1
- package/dist/lightning/channel/types.js +3 -1
- package/dist/lightning/channel/types.js.map +1 -1
- package/dist/lightning/channel/validation.js +3 -3
- package/dist/lightning/channel/validation.js.map +1 -1
- package/dist/lightning/crypto/index.js +1 -0
- package/dist/lightning/crypto/index.js.map +1 -1
- package/dist/lightning/crypto/message-signing.js +116 -0
- package/dist/lightning/crypto/message-signing.js.map +1 -0
- package/dist/lightning/crypto/xchacha20poly1305.js +77 -0
- package/dist/lightning/crypto/xchacha20poly1305.js.map +1 -0
- package/dist/lightning/features/flags.js +1 -0
- package/dist/lightning/features/flags.js.map +1 -1
- package/dist/lightning/gossip/messages.js +37 -1
- package/dist/lightning/gossip/messages.js.map +1 -1
- package/dist/lightning/index.js +2 -1
- package/dist/lightning/index.js.map +1 -1
- package/dist/lightning/keys/wallet-keys.js +1 -0
- package/dist/lightning/keys/wallet-keys.js.map +1 -1
- package/dist/lightning/message/index.js +1 -0
- package/dist/lightning/message/index.js.map +1 -1
- package/dist/lightning/message/peer-storage.js +43 -0
- package/dist/lightning/message/peer-storage.js.map +1 -0
- package/dist/lightning/message/types.js +2 -0
- package/dist/lightning/message/types.js.map +1 -1
- package/dist/lightning/node/lightning-node.js +1583 -235
- package/dist/lightning/node/lightning-node.js.map +1 -1
- package/dist/lightning/node/types.js +18 -1
- package/dist/lightning/node/types.js.map +1 -1
- package/dist/lightning/offer/offer-manager.js +2 -5
- package/dist/lightning/offer/offer-manager.js.map +1 -1
- package/dist/lightning/offer/tlv.js +3 -1
- package/dist/lightning/offer/tlv.js.map +1 -1
- package/dist/lightning/storage/encryption.js +67 -0
- package/dist/lightning/storage/encryption.js.map +1 -0
- package/dist/lightning/storage/index.js +1 -0
- package/dist/lightning/storage/index.js.map +1 -1
- package/dist/lightning/storage/serialization.js +6 -2
- package/dist/lightning/storage/serialization.js.map +1 -1
- package/dist/lightning/storage/sqlite-storage.js +387 -33
- package/dist/lightning/storage/sqlite-storage.js.map +1 -1
- package/dist/lightning/watchtower/blob.js +135 -0
- package/dist/lightning/watchtower/blob.js.map +1 -0
- package/dist/lightning/watchtower/index.js +55 -0
- package/dist/lightning/watchtower/index.js.map +1 -0
- package/dist/lightning/watchtower/justice.js +182 -0
- package/dist/lightning/watchtower/justice.js.map +1 -0
- package/dist/lightning/watchtower/tower-connection.js +208 -0
- package/dist/lightning/watchtower/tower-connection.js.map +1 -0
- package/dist/lightning/watchtower/types.js +3 -0
- package/dist/lightning/watchtower/types.js.map +1 -0
- package/dist/lightning/watchtower/watchtower-client.js +402 -0
- package/dist/lightning/watchtower/watchtower-client.js.map +1 -0
- package/dist/lightning/watchtower/wtwire.js +201 -0
- package/dist/lightning/watchtower/wtwire.js.map +1 -0
- package/dist/shapes/electrum.js +32 -1
- package/dist/shapes/electrum.js.map +1 -1
- package/dist/shapes/wallet.js +11 -1
- package/dist/shapes/wallet.js.map +1 -1
- package/dist/transaction/index.js +163 -15
- package/dist/transaction/index.js.map +1 -1
- package/dist/types/cli/beignet-node.d.ts +144 -3
- package/dist/types/cli/daemon.d.ts +2 -0
- package/dist/types/cli/errors.d.ts +2 -0
- package/dist/types/cli/restore.d.ts +10 -0
- package/dist/types/cli/types.d.ts +228 -1
- package/dist/types/cli/wallet-storage.d.ts +3 -0
- package/dist/types/electrum/index.d.ts +12 -0
- package/dist/types/electrum.js +1 -0
- package/dist/types/electrum.js.map +1 -1
- package/dist/types/lightning/advisor/fee-tuner.d.ts +20 -0
- package/dist/types/lightning/advisor/index.d.ts +4 -0
- package/dist/types/lightning/advisor/rebalance-planner.d.ts +12 -0
- package/dist/types/lightning/backup/index.d.ts +1 -0
- package/dist/types/lightning/backup/scb.d.ts +24 -0
- package/dist/types/lightning/chain/chain-monitor.d.ts +1 -0
- package/dist/types/lightning/chain/types.d.ts +1 -0
- package/dist/types/lightning/channel/channel-manager.d.ts +7 -0
- package/dist/types/lightning/channel/channel-state.d.ts +2 -0
- package/dist/types/lightning/channel/channel.d.ts +6 -0
- package/dist/types/lightning/channel/dual-funding.d.ts +2 -1
- package/dist/types/lightning/channel/types.d.ts +2 -0
- package/dist/types/lightning/channel/validation.d.ts +1 -1
- package/dist/types/lightning/crypto/index.d.ts +1 -0
- package/dist/types/lightning/crypto/message-signing.d.ts +9 -0
- package/dist/types/lightning/crypto/xchacha20poly1305.d.ts +3 -0
- package/dist/types/lightning/features/flags.d.ts +1 -0
- package/dist/types/lightning/gossip/messages.d.ts +4 -0
- package/dist/types/lightning/index.d.ts +1 -0
- package/dist/types/lightning/keys/wallet-keys.d.ts +2 -1
- package/dist/types/lightning/message/index.d.ts +1 -0
- package/dist/types/lightning/message/peer-storage.d.ts +9 -0
- package/dist/types/lightning/message/types.d.ts +2 -0
- package/dist/types/lightning/node/lightning-node.d.ts +116 -4
- package/dist/types/lightning/node/types.d.ts +62 -1
- package/dist/types/lightning/storage/encryption.d.ts +11 -0
- package/dist/types/lightning/storage/index.d.ts +1 -0
- package/dist/types/lightning/storage/serialization.d.ts +2 -0
- package/dist/types/lightning/storage/sqlite-storage.d.ts +43 -3
- package/dist/types/lightning/storage/types.d.ts +62 -0
- package/dist/types/lightning/watchtower/blob.d.ts +32 -0
- package/dist/types/lightning/watchtower/index.d.ts +9 -0
- package/dist/types/lightning/watchtower/justice.d.ts +29 -0
- package/dist/types/lightning/watchtower/tower-connection.d.ts +34 -0
- package/dist/types/lightning/watchtower/types.d.ts +44 -0
- package/dist/types/lightning/watchtower/watchtower-client.d.ts +67 -0
- package/dist/types/lightning/watchtower/wtwire.d.ts +90 -0
- package/dist/types/shapes/electrum.d.ts +3 -1
- package/dist/types/transaction/index.d.ts +6 -0
- package/dist/types/transaction.js.map +1 -1
- package/dist/types/types/electrum.d.ts +3 -2
- package/dist/types/types/transaction.d.ts +1 -1
- package/dist/types/types/wallet.d.ts +78 -4
- package/dist/types/utils/descriptors.d.ts +2 -0
- package/dist/types/utils/fees.d.ts +3 -0
- package/dist/types/utils/helpers.d.ts +3 -1
- package/dist/types/utils/index.d.ts +5 -0
- package/dist/types/utils/multisig.d.ts +29 -0
- package/dist/types/utils/transaction.d.ts +7 -0
- package/dist/types/utils/wallet-storage-encryption.d.ts +3 -0
- package/dist/types/utils/wallet.d.ts +1 -1
- package/dist/types/utils/watch-only.d.ts +12 -0
- package/dist/types/wallet/constants.d.ts +1 -0
- package/dist/types/wallet/index.d.ts +61 -4
- package/dist/types/wallet.js +3 -0
- package/dist/types/wallet.js.map +1 -1
- package/dist/utils/derivation-path.js +8 -7
- package/dist/utils/derivation-path.js.map +1 -1
- package/dist/utils/descriptors.js +56 -0
- package/dist/utils/descriptors.js.map +1 -0
- package/dist/utils/electrum.js +10 -2
- package/dist/utils/electrum.js.map +1 -1
- package/dist/utils/fees.js +19 -0
- package/dist/utils/fees.js.map +1 -0
- package/dist/utils/helpers.js +22 -5
- package/dist/utils/helpers.js.map +1 -1
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/multisig.js +90 -0
- package/dist/utils/multisig.js.map +1 -0
- package/dist/utils/transaction.js +30 -3
- package/dist/utils/transaction.js.map +1 -1
- package/dist/utils/wallet-storage-encryption.js +45 -0
- package/dist/utils/wallet-storage-encryption.js.map +1 -0
- package/dist/utils/wallet.js +3 -1
- package/dist/utils/wallet.js.map +1 -1
- package/dist/utils/watch-only.js +102 -0
- package/dist/utils/watch-only.js.map +1 -0
- package/dist/wallet/constants.js +2 -1
- package/dist/wallet/constants.js.map +1 -1
- package/dist/wallet/index.js +787 -30
- package/dist/wallet/index.js.map +1 -1
- package/docs/ROADMAP.md +292 -0
- package/package.json +1 -1
package/dist/cli/cli.js
CHANGED
|
@@ -25,9 +25,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
25
25
|
};
|
|
26
26
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
27
|
const http = __importStar(require("http"));
|
|
28
|
+
const fs = __importStar(require("fs"));
|
|
29
|
+
const nodePath = __importStar(require("path"));
|
|
28
30
|
const helpers_1 = require("../utils/helpers");
|
|
29
31
|
const config_1 = require("./config");
|
|
30
32
|
const daemon_1 = require("./daemon");
|
|
33
|
+
const beignet_node_1 = require("./beignet-node");
|
|
34
|
+
const restore_1 = require("./restore");
|
|
35
|
+
const instance_lock_1 = require("./instance-lock");
|
|
31
36
|
const args = process.argv.slice(2);
|
|
32
37
|
const pretty = args.includes('--pretty');
|
|
33
38
|
const filteredArgs = args.filter((a) => a !== '--pretty');
|
|
@@ -44,6 +49,14 @@ function parseFlag(name) {
|
|
|
44
49
|
function hasFlag(name) {
|
|
45
50
|
return filteredArgs.includes(name);
|
|
46
51
|
}
|
|
52
|
+
function parseRepeatedFlag(name) {
|
|
53
|
+
const out = [];
|
|
54
|
+
for (let i = 0; i < filteredArgs.length - 1; i++) {
|
|
55
|
+
if (filteredArgs[i] === name)
|
|
56
|
+
out.push(filteredArgs[i + 1]);
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
47
60
|
function getApiToken() {
|
|
48
61
|
const flagToken = parseFlag('--api-token');
|
|
49
62
|
if (flagToken)
|
|
@@ -118,9 +131,36 @@ async function main() {
|
|
|
118
131
|
: '/transactions'));
|
|
119
132
|
case 'utxos':
|
|
120
133
|
return outputResult(await httpRequest('GET', '/utxos'));
|
|
134
|
+
case 'utxo':
|
|
135
|
+
return handleUtxo();
|
|
121
136
|
case 'fee-estimates':
|
|
122
137
|
return outputResult(await httpRequest('GET', '/fees/estimates'));
|
|
123
138
|
case 'address':
|
|
139
|
+
if (filteredArgs[1] === 'validate') {
|
|
140
|
+
return outputResult(await httpRequest('POST', '/address/validate', {
|
|
141
|
+
address: filteredArgs[2]
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
if (filteredArgs[1] === 'label') {
|
|
145
|
+
return outputResult(await httpRequest('POST', '/address/label', {
|
|
146
|
+
address: filteredArgs[2],
|
|
147
|
+
label: filteredArgs.slice(3).join(' ')
|
|
148
|
+
}));
|
|
149
|
+
}
|
|
150
|
+
if (filteredArgs[1] === 'labels') {
|
|
151
|
+
return outputResult(await httpRequest('GET', '/address/labels'));
|
|
152
|
+
}
|
|
153
|
+
if (hasFlag('--bip21')) {
|
|
154
|
+
const amountFlag = parseFlag('--amount');
|
|
155
|
+
const labelFlag = parseFlag('--label');
|
|
156
|
+
const messageFlag = parseFlag('--message');
|
|
157
|
+
return outputResult(await httpRequest('POST', '/address/new', {
|
|
158
|
+
bip21: true,
|
|
159
|
+
...(amountFlag ? { amountSats: parseInt(amountFlag, 10) } : {}),
|
|
160
|
+
...(labelFlag ? { label: labelFlag } : {}),
|
|
161
|
+
...(messageFlag ? { message: messageFlag } : {})
|
|
162
|
+
}));
|
|
163
|
+
}
|
|
124
164
|
return outputResult(await httpRequest('POST', '/address/new'));
|
|
125
165
|
case 'mnemonic':
|
|
126
166
|
return outputResult(await httpRequest('GET', '/mnemonic'));
|
|
@@ -129,6 +169,23 @@ async function main() {
|
|
|
129
169
|
address: filteredArgs[1],
|
|
130
170
|
amountSats: parseInt(filteredArgs[2], 10)
|
|
131
171
|
}));
|
|
172
|
+
case 'send-max':
|
|
173
|
+
return outputResult(await httpRequest('POST', '/send-max', {
|
|
174
|
+
address: filteredArgs[1],
|
|
175
|
+
satsPerVbyte: filteredArgs[2]
|
|
176
|
+
? parseInt(filteredArgs[2], 10)
|
|
177
|
+
: undefined
|
|
178
|
+
}));
|
|
179
|
+
case 'tx':
|
|
180
|
+
return handleTx();
|
|
181
|
+
case 'psbt':
|
|
182
|
+
return handlePsbt();
|
|
183
|
+
case 'consolidate':
|
|
184
|
+
return outputResult(await httpRequest('POST', '/consolidate', {
|
|
185
|
+
satsPerVbyte: filteredArgs[1]
|
|
186
|
+
? parseInt(filteredArgs[1], 10)
|
|
187
|
+
: undefined
|
|
188
|
+
}));
|
|
132
189
|
case 'peer':
|
|
133
190
|
return handlePeer();
|
|
134
191
|
case 'channel':
|
|
@@ -137,6 +194,30 @@ async function main() {
|
|
|
137
194
|
return handleInvoice();
|
|
138
195
|
case 'payment':
|
|
139
196
|
return handlePayment();
|
|
197
|
+
case 'keysend':
|
|
198
|
+
return handleKeysend();
|
|
199
|
+
case 'forwards':
|
|
200
|
+
return handleForwards();
|
|
201
|
+
case 'graph':
|
|
202
|
+
return handleGraph();
|
|
203
|
+
case 'gossip':
|
|
204
|
+
return handleGossip();
|
|
205
|
+
case 'message':
|
|
206
|
+
return handleMessage();
|
|
207
|
+
case 'recover-fallback-funds':
|
|
208
|
+
return outputResult(await httpRequest('POST', '/recover-fallback-funds', {
|
|
209
|
+
feeRatePerVbyte: parseFlag('--fee-rate')
|
|
210
|
+
? parseInt(parseFlag('--fee-rate'), 10)
|
|
211
|
+
: undefined
|
|
212
|
+
}));
|
|
213
|
+
case 'watchtower':
|
|
214
|
+
return handleWatchtower();
|
|
215
|
+
case 'route':
|
|
216
|
+
return handleRoute();
|
|
217
|
+
case 'rebalance':
|
|
218
|
+
return handleRebalance();
|
|
219
|
+
case 'advisor':
|
|
220
|
+
return handleAdvisor();
|
|
140
221
|
case 'bootstrap':
|
|
141
222
|
return handleBootstrap();
|
|
142
223
|
case 'trusted-peer':
|
|
@@ -145,16 +226,38 @@ async function main() {
|
|
|
145
226
|
return handleOffer();
|
|
146
227
|
case 'health':
|
|
147
228
|
return outputResult(await httpRequest('GET', '/health'));
|
|
229
|
+
case 'ready':
|
|
230
|
+
return outputResult(await httpRequest('GET', '/ready'));
|
|
148
231
|
case 'readiness':
|
|
149
232
|
return outputResult(await httpRequest('GET', '/readiness'));
|
|
150
233
|
case 'metrics':
|
|
151
234
|
return handleMetrics();
|
|
152
235
|
case 'stats':
|
|
153
236
|
return outputResult(await httpRequest('GET', filteredArgs[1] ? `/stats?window=${filteredArgs[1]}` : '/stats'));
|
|
237
|
+
case 'liquidity':
|
|
238
|
+
return outputResult(await httpRequest('GET', '/liquidity'));
|
|
239
|
+
case 'fees':
|
|
240
|
+
return outputResult(await httpRequest('GET', '/fees'));
|
|
241
|
+
case 'spend-limit':
|
|
242
|
+
return outputResult(await httpRequest('GET', '/spend-limit'));
|
|
243
|
+
case 'logs':
|
|
244
|
+
return handleLogs();
|
|
245
|
+
case 'can-send':
|
|
246
|
+
return outputResult(await httpRequest('GET', `/can-send?amountSats=${encodeURIComponent(filteredArgs[1] || '0')}`));
|
|
247
|
+
case 'can-receive':
|
|
248
|
+
return outputResult(await httpRequest('GET', `/can-receive?amountSats=${encodeURIComponent(filteredArgs[1] || '0')}`));
|
|
249
|
+
case 'wallet':
|
|
250
|
+
return handleWallet();
|
|
251
|
+
case 'node':
|
|
252
|
+
return handleNode();
|
|
253
|
+
case 'webhooks':
|
|
254
|
+
return handleWebhooks();
|
|
255
|
+
case 'queue':
|
|
256
|
+
return handleQueue();
|
|
154
257
|
case 'backup':
|
|
155
|
-
return
|
|
156
|
-
|
|
157
|
-
|
|
258
|
+
return handleBackup();
|
|
259
|
+
case 'restore':
|
|
260
|
+
return handleRestore();
|
|
158
261
|
default:
|
|
159
262
|
output({
|
|
160
263
|
ok: false,
|
|
@@ -222,6 +325,10 @@ async function handleStart() {
|
|
|
222
325
|
cliFlags.daemonHost = hostFlag;
|
|
223
326
|
if (hasFlag('--anchors'))
|
|
224
327
|
cliFlags.preferAnchors = true;
|
|
328
|
+
if (hasFlag('--large-channels'))
|
|
329
|
+
cliFlags.largeChannels = true;
|
|
330
|
+
if (hasFlag('--htlc-events'))
|
|
331
|
+
cliFlags.htlcEvents = true;
|
|
225
332
|
const apiTokenFlag = parseFlag('--api-token');
|
|
226
333
|
if (apiTokenFlag)
|
|
227
334
|
cliFlags.apiToken = apiTokenFlag;
|
|
@@ -249,6 +356,13 @@ async function handleStart() {
|
|
|
249
356
|
.split(',')
|
|
250
357
|
.map((a) => a.trim())
|
|
251
358
|
.filter((a) => a.length > 0);
|
|
359
|
+
const watchtowerFlags = parseRepeatedFlag('--watchtower');
|
|
360
|
+
if (watchtowerFlags.length > 0)
|
|
361
|
+
cliFlags.watchtowers = watchtowerFlags;
|
|
362
|
+
const feeSourceFlag = parseFlag('--fee-source');
|
|
363
|
+
if (feeSourceFlag)
|
|
364
|
+
cliFlags.feeEstimationSource =
|
|
365
|
+
feeSourceFlag;
|
|
252
366
|
const config = (0, config_1.resolveConfig)(cliFlags);
|
|
253
367
|
if (!config.mnemonic) {
|
|
254
368
|
output({
|
|
@@ -273,10 +387,12 @@ async function handleStart() {
|
|
|
273
387
|
electrumPort: config.electrumPort,
|
|
274
388
|
electrumTls: config.electrumTls,
|
|
275
389
|
electrumServers: config.electrumServers,
|
|
390
|
+
feeEstimationSource: config.feeEstimationSource,
|
|
276
391
|
listenPort: config.listenPort,
|
|
277
392
|
daemonPort,
|
|
278
393
|
daemonHost: config.daemonHost,
|
|
279
394
|
preferAnchors: config.preferAnchors,
|
|
395
|
+
largeChannels: config.largeChannels,
|
|
280
396
|
apiToken: config.apiToken,
|
|
281
397
|
backupPath: config.backupPath,
|
|
282
398
|
backupIntervalMs: config.backupIntervalMs,
|
|
@@ -284,7 +400,9 @@ async function handleStart() {
|
|
|
284
400
|
tlsCert: config.tlsCert,
|
|
285
401
|
tlsKey: config.tlsKey,
|
|
286
402
|
torProxy: config.torProxy,
|
|
287
|
-
announceAddresses: config.announceAddresses
|
|
403
|
+
announceAddresses: config.announceAddresses,
|
|
404
|
+
watchtowers: config.watchtowers,
|
|
405
|
+
htlcEvents: config.htlcEvents
|
|
288
406
|
});
|
|
289
407
|
(0, config_1.writePidFile)(process.pid, daemonPort);
|
|
290
408
|
output({
|
|
@@ -321,15 +439,96 @@ async function handleStop() {
|
|
|
321
439
|
output({ ok: false, error: { code: 'STOP_FAILED', message: msg } });
|
|
322
440
|
}
|
|
323
441
|
}
|
|
442
|
+
async function handleTx() {
|
|
443
|
+
const sub = filteredArgs[1];
|
|
444
|
+
switch (sub) {
|
|
445
|
+
case 'bump-fee':
|
|
446
|
+
return outputResult(await httpRequest('POST', '/tx/bump-fee', {
|
|
447
|
+
txid: filteredArgs[2],
|
|
448
|
+
satsPerVbyte: filteredArgs[3]
|
|
449
|
+
? parseInt(filteredArgs[3], 10)
|
|
450
|
+
: undefined
|
|
451
|
+
}));
|
|
452
|
+
case 'boost':
|
|
453
|
+
return outputResult(await httpRequest('POST', '/tx/boost', {
|
|
454
|
+
txid: filteredArgs[2],
|
|
455
|
+
satsPerVbyte: filteredArgs[3]
|
|
456
|
+
? parseInt(filteredArgs[3], 10)
|
|
457
|
+
: undefined
|
|
458
|
+
}));
|
|
459
|
+
case 'boostable':
|
|
460
|
+
return outputResult(await httpRequest('GET', '/transactions/boostable'));
|
|
461
|
+
default:
|
|
462
|
+
output({
|
|
463
|
+
ok: false,
|
|
464
|
+
error: {
|
|
465
|
+
code: 'UNKNOWN_COMMAND',
|
|
466
|
+
message: 'Usage: beignet tx [bump-fee <txid> <satsPerVbyte>|boost <txid> [satsPerVbyte]|boostable]'
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
process.exitCode = 1;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
function readPsbtArg(arg) {
|
|
473
|
+
if (!arg)
|
|
474
|
+
return undefined;
|
|
475
|
+
try {
|
|
476
|
+
if (fs.existsSync(arg) && fs.statSync(arg).isFile()) {
|
|
477
|
+
return fs.readFileSync(arg, 'utf8').trim();
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
catch {
|
|
481
|
+
}
|
|
482
|
+
return arg;
|
|
483
|
+
}
|
|
484
|
+
async function handlePsbt() {
|
|
485
|
+
const sub = filteredArgs[1];
|
|
486
|
+
switch (sub) {
|
|
487
|
+
case 'build':
|
|
488
|
+
return outputResult(await httpRequest('POST', '/psbt/build', {
|
|
489
|
+
outputs: [
|
|
490
|
+
{
|
|
491
|
+
address: filteredArgs[2],
|
|
492
|
+
amountSats: parseInt(filteredArgs[3], 10)
|
|
493
|
+
}
|
|
494
|
+
],
|
|
495
|
+
satsPerVbyte: filteredArgs[4]
|
|
496
|
+
? parseInt(filteredArgs[4], 10)
|
|
497
|
+
: undefined
|
|
498
|
+
}));
|
|
499
|
+
case 'import-signed':
|
|
500
|
+
return outputResult(await httpRequest('POST', '/psbt/import-signed', {
|
|
501
|
+
psbtBase64: readPsbtArg(filteredArgs[2])
|
|
502
|
+
}));
|
|
503
|
+
case 'combine':
|
|
504
|
+
return outputResult(await httpRequest('POST', '/psbt/combine', {
|
|
505
|
+
psbts: filteredArgs
|
|
506
|
+
.slice(2)
|
|
507
|
+
.map((arg) => readPsbtArg(arg))
|
|
508
|
+
.filter((psbt) => !!psbt)
|
|
509
|
+
}));
|
|
510
|
+
default:
|
|
511
|
+
output({
|
|
512
|
+
ok: false,
|
|
513
|
+
error: {
|
|
514
|
+
code: 'UNKNOWN_COMMAND',
|
|
515
|
+
message: 'Usage: beignet psbt [build <address> <sats> [satsPerVbyte]|import-signed <psbtBase64|file>|combine <psbt|file> <psbt|file> ...]'
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
process.exitCode = 1;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
324
521
|
async function handlePeer() {
|
|
325
522
|
const sub = filteredArgs[1];
|
|
326
523
|
switch (sub) {
|
|
327
524
|
case 'connect':
|
|
328
|
-
return outputResult(await httpRequest('POST', '/peer/connect',
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
525
|
+
return outputResult(await httpRequest('POST', '/peer/connect', filteredArgs[3] !== undefined
|
|
526
|
+
? {
|
|
527
|
+
pubkey: filteredArgs[2],
|
|
528
|
+
host: filteredArgs[3],
|
|
529
|
+
port: parseInt(filteredArgs[4], 10)
|
|
530
|
+
}
|
|
531
|
+
: { pubkey: filteredArgs[2] }));
|
|
333
532
|
case 'disconnect':
|
|
334
533
|
return outputResult(await httpRequest('POST', '/peer/disconnect', {
|
|
335
534
|
pubkey: filteredArgs[2]
|
|
@@ -399,12 +598,90 @@ async function handleChannel() {
|
|
|
399
598
|
count: parseInt(filteredArgs[2], 10),
|
|
400
599
|
satsPerChannel: parseInt(filteredArgs[3], 10)
|
|
401
600
|
}));
|
|
601
|
+
case 'diagnostics':
|
|
602
|
+
return outputResult(await httpRequest('GET', `/channel/diagnostics?channelId=${encodeURIComponent(filteredArgs[2] || '')}`));
|
|
603
|
+
case 'health':
|
|
604
|
+
return outputResult(await httpRequest('GET', `/channel/health?channelId=${encodeURIComponent(filteredArgs[2] || '')}`));
|
|
605
|
+
case 'policy':
|
|
606
|
+
return outputResult(await httpRequest('GET', `/channel/policy?channelId=${encodeURIComponent(filteredArgs[2] || '')}`));
|
|
607
|
+
case 'suggestions':
|
|
608
|
+
return outputResult(await httpRequest('GET', filteredArgs[2]
|
|
609
|
+
? `/channel/suggestions?count=${encodeURIComponent(filteredArgs[2])}`
|
|
610
|
+
: '/channel/suggestions'));
|
|
611
|
+
case 'ready':
|
|
612
|
+
return outputResult(await httpRequest('GET', '/channels/ready'));
|
|
613
|
+
case 'connect-and-open':
|
|
614
|
+
return outputResult(await httpRequest('POST', '/channel/connect-and-open', {
|
|
615
|
+
pubkey: filteredArgs[2],
|
|
616
|
+
host: filteredArgs[3],
|
|
617
|
+
port: filteredArgs[4] ? parseInt(filteredArgs[4], 10) : undefined,
|
|
618
|
+
amountSats: filteredArgs[5]
|
|
619
|
+
? parseInt(filteredArgs[5], 10)
|
|
620
|
+
: undefined,
|
|
621
|
+
pushSats: filteredArgs[6] ? parseInt(filteredArgs[6], 10) : undefined
|
|
622
|
+
}));
|
|
623
|
+
case 'open-and-wait': {
|
|
624
|
+
const timeout = parseFlag('--timeout');
|
|
625
|
+
return outputResult(await httpRequest('POST', '/channel/open-and-wait', {
|
|
626
|
+
pubkey: filteredArgs[2],
|
|
627
|
+
amountSats: filteredArgs[3]
|
|
628
|
+
? parseInt(filteredArgs[3], 10)
|
|
629
|
+
: undefined,
|
|
630
|
+
pushSats: filteredArgs[4] ? parseInt(filteredArgs[4], 10) : undefined,
|
|
631
|
+
timeoutMs: timeout !== undefined ? parseInt(timeout, 10) : undefined
|
|
632
|
+
}));
|
|
633
|
+
}
|
|
634
|
+
case 'wait-ready': {
|
|
635
|
+
const timeout = parseFlag('--timeout');
|
|
636
|
+
return outputResult(await httpRequest('POST', '/channel/wait-ready', {
|
|
637
|
+
channelId: filteredArgs[2],
|
|
638
|
+
timeoutMs: timeout !== undefined ? parseInt(timeout, 10) : undefined
|
|
639
|
+
}));
|
|
640
|
+
}
|
|
641
|
+
case 'update-commitment-feerate':
|
|
642
|
+
return outputResult(await httpRequest('POST', '/channel/update-commitment-feerate', {
|
|
643
|
+
channelId: filteredArgs[2],
|
|
644
|
+
feeratePerKw: filteredArgs[3]
|
|
645
|
+
? parseInt(filteredArgs[3], 10)
|
|
646
|
+
: undefined
|
|
647
|
+
}));
|
|
648
|
+
case 'update-policy': {
|
|
649
|
+
const target = filteredArgs[2];
|
|
650
|
+
if (!target) {
|
|
651
|
+
output({
|
|
652
|
+
ok: false,
|
|
653
|
+
error: {
|
|
654
|
+
code: 'INVALID_PARAMS',
|
|
655
|
+
message: 'Usage: beignet channel update-policy <channelId|all> [--base-fee-msat N] [--ppm N] [--cltv-delta N] [--htlc-min-msat N] [--htlc-max-msat N]'
|
|
656
|
+
}
|
|
657
|
+
});
|
|
658
|
+
process.exitCode = 1;
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
const body = target === 'all' ? { all: true } : { channelId: target };
|
|
662
|
+
const baseFee = parseFlag('--base-fee-msat');
|
|
663
|
+
if (baseFee !== undefined)
|
|
664
|
+
body.feeBaseMsat = parseInt(baseFee, 10);
|
|
665
|
+
const ppm = parseFlag('--ppm');
|
|
666
|
+
if (ppm !== undefined)
|
|
667
|
+
body.feeProportionalMillionths = parseInt(ppm, 10);
|
|
668
|
+
const cltvDelta = parseFlag('--cltv-delta');
|
|
669
|
+
if (cltvDelta !== undefined)
|
|
670
|
+
body.cltvExpiryDelta = parseInt(cltvDelta, 10);
|
|
671
|
+
const htlcMin = parseFlag('--htlc-min-msat');
|
|
672
|
+
if (htlcMin !== undefined)
|
|
673
|
+
body.htlcMinimumMsat = htlcMin;
|
|
674
|
+
const htlcMax = parseFlag('--htlc-max-msat');
|
|
675
|
+
if (htlcMax !== undefined)
|
|
676
|
+
body.htlcMaximumMsat = htlcMax;
|
|
677
|
+
return outputResult(await httpRequest('POST', '/channel/update-policy', body));
|
|
678
|
+
}
|
|
402
679
|
default:
|
|
403
680
|
output({
|
|
404
681
|
ok: false,
|
|
405
682
|
error: {
|
|
406
683
|
code: 'UNKNOWN_COMMAND',
|
|
407
|
-
message: 'Usage: beignet channel [open|open-zeroconf|open-v2|close|forceclose|splice-in|splice-out|ensure-minimum|list|get]'
|
|
684
|
+
message: 'Usage: beignet channel [open|open-zeroconf|open-v2|open-and-wait|connect-and-open|close|forceclose|splice-in|splice-out|ensure-minimum|update-policy|update-commitment-feerate|policy|diagnostics|health|suggestions|wait-ready|ready|list|get]'
|
|
408
685
|
}
|
|
409
686
|
});
|
|
410
687
|
process.exitCode = 1;
|
|
@@ -418,14 +695,79 @@ async function handleInvoice() {
|
|
|
418
695
|
amountSats: parseInt(filteredArgs[2], 10),
|
|
419
696
|
description: filteredArgs[3] || ''
|
|
420
697
|
}));
|
|
698
|
+
case 'create-hold': {
|
|
699
|
+
const paymentHash = filteredArgs[2];
|
|
700
|
+
if (!paymentHash) {
|
|
701
|
+
output({
|
|
702
|
+
ok: false,
|
|
703
|
+
error: {
|
|
704
|
+
code: 'INVALID_PARAMS',
|
|
705
|
+
message: 'Usage: beignet invoice create-hold <paymentHash> [amountSats] [description] [--expiry secs]'
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
process.exitCode = 1;
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
const expiryFlag = parseFlag('--expiry');
|
|
712
|
+
return outputResult(await httpRequest('POST', '/invoice/create-hold', {
|
|
713
|
+
paymentHash,
|
|
714
|
+
amountSats: filteredArgs[3]
|
|
715
|
+
? parseInt(filteredArgs[3], 10)
|
|
716
|
+
: undefined,
|
|
717
|
+
description: filteredArgs[4] || '',
|
|
718
|
+
expiry: expiryFlag ? parseInt(expiryFlag, 10) : undefined
|
|
719
|
+
}));
|
|
720
|
+
}
|
|
721
|
+
case 'settle-hold':
|
|
722
|
+
return outputResult(await httpRequest('POST', '/invoice/settle-hold', {
|
|
723
|
+
preimage: filteredArgs[2]
|
|
724
|
+
}));
|
|
725
|
+
case 'cancel-hold':
|
|
726
|
+
return outputResult(await httpRequest('POST', '/invoice/cancel-hold', {
|
|
727
|
+
paymentHash: filteredArgs[2]
|
|
728
|
+
}));
|
|
729
|
+
case 'held':
|
|
730
|
+
return outputResult(await httpRequest('GET', '/invoices/held'));
|
|
421
731
|
case 'decode':
|
|
422
732
|
return outputResult(await httpRequest('POST', '/invoice/decode', {
|
|
423
733
|
bolt11: filteredArgs[2]
|
|
424
734
|
}));
|
|
735
|
+
case 'validate':
|
|
736
|
+
return outputResult(await httpRequest('POST', '/invoice/validate', {
|
|
737
|
+
bolt11: filteredArgs[2],
|
|
738
|
+
amountSats: filteredArgs[3]
|
|
739
|
+
? parseInt(filteredArgs[3], 10)
|
|
740
|
+
: undefined
|
|
741
|
+
}));
|
|
742
|
+
case 'get':
|
|
743
|
+
return outputResult(await httpRequest('GET', `/invoice?paymentHash=${encodeURIComponent(filteredArgs[2] || '')}`));
|
|
425
744
|
case 'pay':
|
|
426
745
|
return outputResult(await httpRequest('POST', '/invoice/pay', {
|
|
427
746
|
bolt11: filteredArgs[2]
|
|
428
747
|
}));
|
|
748
|
+
case 'pay-safe':
|
|
749
|
+
return outputResult(await httpRequest('POST', '/invoice/pay-safe', {
|
|
750
|
+
bolt11: filteredArgs[2],
|
|
751
|
+
maxFeeSats: parseFlag('--max-fee')
|
|
752
|
+
? parseInt(parseFlag('--max-fee'), 10)
|
|
753
|
+
: undefined,
|
|
754
|
+
amountSats: parseFlag('--amount')
|
|
755
|
+
? parseInt(parseFlag('--amount'), 10)
|
|
756
|
+
: undefined,
|
|
757
|
+
timeoutMs: parseFlag('--timeout')
|
|
758
|
+
? parseInt(parseFlag('--timeout'), 10)
|
|
759
|
+
: undefined
|
|
760
|
+
}));
|
|
761
|
+
case 'pay-async':
|
|
762
|
+
return outputResult(await httpRequest('POST', '/invoice/pay-async', {
|
|
763
|
+
bolt11: filteredArgs[2],
|
|
764
|
+
maxFeeSats: parseFlag('--max-fee')
|
|
765
|
+
? parseInt(parseFlag('--max-fee'), 10)
|
|
766
|
+
: undefined,
|
|
767
|
+
amountSats: parseFlag('--amount')
|
|
768
|
+
? parseInt(parseFlag('--amount'), 10)
|
|
769
|
+
: undefined
|
|
770
|
+
}));
|
|
429
771
|
case 'pay-retry':
|
|
430
772
|
return outputResult(await httpRequest('POST', '/invoice/pay-retry', {
|
|
431
773
|
bolt11: filteredArgs[2],
|
|
@@ -446,7 +788,7 @@ async function handleInvoice() {
|
|
|
446
788
|
ok: false,
|
|
447
789
|
error: {
|
|
448
790
|
code: 'UNKNOWN_COMMAND',
|
|
449
|
-
message: 'Usage: beignet invoice [create|decode|pay|pay-retry|list]'
|
|
791
|
+
message: 'Usage: beignet invoice [create|create-hold|settle-hold|cancel-hold|held|decode|validate|get|pay|pay-safe|pay-async|pay-retry|list]'
|
|
450
792
|
}
|
|
451
793
|
});
|
|
452
794
|
process.exitCode = 1;
|
|
@@ -459,12 +801,520 @@ async function handlePayment() {
|
|
|
459
801
|
return outputResult(await httpRequest('GET', '/payments'));
|
|
460
802
|
case 'get':
|
|
461
803
|
return outputResult(await httpRequest('GET', `/payment?paymentHash=${encodeURIComponent(filteredArgs[2] || '')}`));
|
|
804
|
+
case 'send-to-route': {
|
|
805
|
+
const paymentHash = filteredArgs[2];
|
|
806
|
+
const routeArg = filteredArgs[3];
|
|
807
|
+
if (!paymentHash || !routeArg) {
|
|
808
|
+
output({
|
|
809
|
+
ok: false,
|
|
810
|
+
error: {
|
|
811
|
+
code: 'INVALID_PARAMS',
|
|
812
|
+
message: 'Usage: beignet payment send-to-route <paymentHash> <routeJson|routeFile> [--payment-secret <hex>]'
|
|
813
|
+
}
|
|
814
|
+
});
|
|
815
|
+
process.exitCode = 1;
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
818
|
+
let routeStr = routeArg;
|
|
819
|
+
if (!routeArg.trimStart().startsWith('{')) {
|
|
820
|
+
try {
|
|
821
|
+
routeStr = fs.readFileSync(routeArg, 'utf8');
|
|
822
|
+
}
|
|
823
|
+
catch (err) {
|
|
824
|
+
output({
|
|
825
|
+
ok: false,
|
|
826
|
+
error: {
|
|
827
|
+
code: 'INVALID_PARAMS',
|
|
828
|
+
message: `Cannot read route file: ${err.message}`
|
|
829
|
+
}
|
|
830
|
+
});
|
|
831
|
+
process.exitCode = 1;
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
let route;
|
|
836
|
+
try {
|
|
837
|
+
route = JSON.parse(routeStr);
|
|
838
|
+
}
|
|
839
|
+
catch {
|
|
840
|
+
output({
|
|
841
|
+
ok: false,
|
|
842
|
+
error: {
|
|
843
|
+
code: 'INVALID_PARAMS',
|
|
844
|
+
message: 'Route is not valid JSON'
|
|
845
|
+
}
|
|
846
|
+
});
|
|
847
|
+
process.exitCode = 1;
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
const result = route && typeof route === 'object' && 'result' in route
|
|
851
|
+
? route.result
|
|
852
|
+
: route;
|
|
853
|
+
return outputResult(await httpRequest('POST', '/payment/send-to-route', {
|
|
854
|
+
paymentHash,
|
|
855
|
+
route: { hops: result.hops },
|
|
856
|
+
paymentSecret: parseFlag('--payment-secret')
|
|
857
|
+
}));
|
|
858
|
+
}
|
|
859
|
+
case 'cancel':
|
|
860
|
+
return outputResult(await httpRequest('POST', '/payment/cancel', {
|
|
861
|
+
paymentHash: filteredArgs[2]
|
|
862
|
+
}));
|
|
863
|
+
case 'wait': {
|
|
864
|
+
const timeout = parseFlag('--timeout');
|
|
865
|
+
return outputResult(await httpRequest('POST', '/payment/wait', {
|
|
866
|
+
paymentHash: filteredArgs[2],
|
|
867
|
+
timeoutMs: timeout !== undefined ? parseInt(timeout, 10) : undefined
|
|
868
|
+
}));
|
|
869
|
+
}
|
|
870
|
+
case 'proof':
|
|
871
|
+
return outputResult(await httpRequest('GET', `/payment/proof?paymentHash=${encodeURIComponent(filteredArgs[2] || '')}`));
|
|
872
|
+
case 'verify-proof':
|
|
873
|
+
return outputResult(await httpRequest('GET', `/payment/verify-proof?paymentHash=${encodeURIComponent(filteredArgs[2] || '')}`));
|
|
874
|
+
case 'estimate':
|
|
875
|
+
return outputResult(await httpRequest('POST', '/payment/estimate', {
|
|
876
|
+
bolt11: filteredArgs[2],
|
|
877
|
+
amountSats: filteredArgs[3]
|
|
878
|
+
? parseInt(filteredArgs[3], 10)
|
|
879
|
+
: undefined
|
|
880
|
+
}));
|
|
881
|
+
case 'metadata': {
|
|
882
|
+
const paymentHash = filteredArgs[2];
|
|
883
|
+
const metadataArg = filteredArgs[3];
|
|
884
|
+
if (!paymentHash || !metadataArg) {
|
|
885
|
+
output({
|
|
886
|
+
ok: false,
|
|
887
|
+
error: {
|
|
888
|
+
code: 'INVALID_PARAMS',
|
|
889
|
+
message: 'Usage: beignet payment metadata <paymentHash> \'{"key":"value"}\''
|
|
890
|
+
}
|
|
891
|
+
});
|
|
892
|
+
process.exitCode = 1;
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
let metadata;
|
|
896
|
+
try {
|
|
897
|
+
metadata = JSON.parse(metadataArg);
|
|
898
|
+
}
|
|
899
|
+
catch {
|
|
900
|
+
output({
|
|
901
|
+
ok: false,
|
|
902
|
+
error: {
|
|
903
|
+
code: 'INVALID_PARAMS',
|
|
904
|
+
message: 'Metadata is not valid JSON'
|
|
905
|
+
}
|
|
906
|
+
});
|
|
907
|
+
process.exitCode = 1;
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
return outputResult(await httpRequest('POST', '/payment/metadata', {
|
|
911
|
+
paymentHash,
|
|
912
|
+
metadata
|
|
913
|
+
}));
|
|
914
|
+
}
|
|
915
|
+
default:
|
|
916
|
+
output({
|
|
917
|
+
ok: false,
|
|
918
|
+
error: {
|
|
919
|
+
code: 'UNKNOWN_COMMAND',
|
|
920
|
+
message: 'Usage: beignet payment [list|get|cancel|wait|proof|verify-proof|estimate|metadata|send-to-route]'
|
|
921
|
+
}
|
|
922
|
+
});
|
|
923
|
+
process.exitCode = 1;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
async function handleKeysend() {
|
|
927
|
+
const safe = filteredArgs[1] === 'safe';
|
|
928
|
+
const base = safe ? 2 : 1;
|
|
929
|
+
const pubkey = filteredArgs[base];
|
|
930
|
+
const sats = filteredArgs[base + 1];
|
|
931
|
+
if (!pubkey || !sats) {
|
|
932
|
+
output({
|
|
933
|
+
ok: false,
|
|
934
|
+
error: {
|
|
935
|
+
code: 'INVALID_PARAMS',
|
|
936
|
+
message: 'Usage: beignet keysend [safe] <pubkey> <sats> [--max-fee <sats>] [--timeout <ms>]'
|
|
937
|
+
}
|
|
938
|
+
});
|
|
939
|
+
process.exitCode = 1;
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
const maxFee = parseFlag('--max-fee');
|
|
943
|
+
const timeout = parseFlag('--timeout');
|
|
944
|
+
return outputResult(await httpRequest('POST', safe ? '/keysend/safe' : '/keysend', {
|
|
945
|
+
pubkey,
|
|
946
|
+
amountSats: parseInt(sats, 10),
|
|
947
|
+
maxFeeSats: maxFee !== undefined ? parseInt(maxFee, 10) : undefined,
|
|
948
|
+
timeoutMs: timeout !== undefined ? parseInt(timeout, 10) : undefined
|
|
949
|
+
}));
|
|
950
|
+
}
|
|
951
|
+
async function handleLogs() {
|
|
952
|
+
const params = new URLSearchParams();
|
|
953
|
+
const category = parseFlag('--category');
|
|
954
|
+
if (category !== undefined)
|
|
955
|
+
params.set('category', category);
|
|
956
|
+
const since = parseFlag('--since');
|
|
957
|
+
if (since !== undefined)
|
|
958
|
+
params.set('since', since);
|
|
959
|
+
const limit = parseFlag('--limit');
|
|
960
|
+
if (limit !== undefined)
|
|
961
|
+
params.set('limit', limit);
|
|
962
|
+
const qs = params.toString();
|
|
963
|
+
return outputResult(await httpRequest('GET', qs ? `/logs?${qs}` : '/logs'));
|
|
964
|
+
}
|
|
965
|
+
async function handleWallet() {
|
|
966
|
+
const sub = filteredArgs[1];
|
|
967
|
+
switch (sub) {
|
|
968
|
+
case 'refresh':
|
|
969
|
+
return outputResult(await httpRequest('POST', '/wallet/refresh'));
|
|
970
|
+
case 'descriptors':
|
|
971
|
+
return outputResult(await httpRequest('GET', '/wallet/descriptors'));
|
|
972
|
+
default:
|
|
973
|
+
output({
|
|
974
|
+
ok: false,
|
|
975
|
+
error: {
|
|
976
|
+
code: 'UNKNOWN_COMMAND',
|
|
977
|
+
message: 'Usage: beignet wallet [refresh|descriptors]'
|
|
978
|
+
}
|
|
979
|
+
});
|
|
980
|
+
process.exitCode = 1;
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
async function handleUtxo() {
|
|
984
|
+
const sub = filteredArgs[1];
|
|
985
|
+
const outpoint = () => ({
|
|
986
|
+
txid: filteredArgs[2],
|
|
987
|
+
index: parseInt(filteredArgs[3], 10)
|
|
988
|
+
});
|
|
989
|
+
switch (sub) {
|
|
990
|
+
case 'freeze':
|
|
991
|
+
return outputResult(await httpRequest('POST', '/utxo/freeze', outpoint()));
|
|
992
|
+
case 'unfreeze':
|
|
993
|
+
return outputResult(await httpRequest('POST', '/utxo/unfreeze', outpoint()));
|
|
994
|
+
case 'frozen': {
|
|
995
|
+
const res = await httpRequest('GET', '/utxos');
|
|
996
|
+
if (res.ok && Array.isArray(res.result)) {
|
|
997
|
+
return output({
|
|
998
|
+
ok: true,
|
|
999
|
+
result: res.result.filter((u) => u.frozen)
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
return outputResult(res);
|
|
1003
|
+
}
|
|
1004
|
+
default:
|
|
1005
|
+
output({
|
|
1006
|
+
ok: false,
|
|
1007
|
+
error: {
|
|
1008
|
+
code: 'UNKNOWN_COMMAND',
|
|
1009
|
+
message: 'Usage: beignet utxo [freeze <txid> <index>|unfreeze <txid> <index>|frozen]'
|
|
1010
|
+
}
|
|
1011
|
+
});
|
|
1012
|
+
process.exitCode = 1;
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
async function handleNode() {
|
|
1016
|
+
const sub = filteredArgs[1];
|
|
1017
|
+
switch (sub) {
|
|
1018
|
+
case 'uri': {
|
|
1019
|
+
const host = parseFlag('--host');
|
|
1020
|
+
return outputResult(await httpRequest('GET', host !== undefined
|
|
1021
|
+
? `/node/uri?host=${encodeURIComponent(host)}`
|
|
1022
|
+
: '/node/uri'));
|
|
1023
|
+
}
|
|
1024
|
+
case 'wait-ready': {
|
|
1025
|
+
const timeout = parseFlag('--timeout');
|
|
1026
|
+
return outputResult(await httpRequest('POST', '/node/wait-ready', {
|
|
1027
|
+
timeoutMs: timeout !== undefined ? parseInt(timeout, 10) : undefined
|
|
1028
|
+
}));
|
|
1029
|
+
}
|
|
1030
|
+
default:
|
|
1031
|
+
output({
|
|
1032
|
+
ok: false,
|
|
1033
|
+
error: {
|
|
1034
|
+
code: 'UNKNOWN_COMMAND',
|
|
1035
|
+
message: 'Usage: beignet node [uri [--host <addr>]|wait-ready [--timeout <ms>]]'
|
|
1036
|
+
}
|
|
1037
|
+
});
|
|
1038
|
+
process.exitCode = 1;
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
async function handleWebhooks() {
|
|
1042
|
+
const sub = filteredArgs[1];
|
|
1043
|
+
switch (sub) {
|
|
1044
|
+
case 'register': {
|
|
1045
|
+
const url = filteredArgs[2];
|
|
1046
|
+
const events = filteredArgs[3];
|
|
1047
|
+
if (!url || !events) {
|
|
1048
|
+
output({
|
|
1049
|
+
ok: false,
|
|
1050
|
+
error: {
|
|
1051
|
+
code: 'INVALID_PARAMS',
|
|
1052
|
+
message: 'Usage: beignet webhooks register <url> <event,event,...|*> [--secret <secret>]'
|
|
1053
|
+
}
|
|
1054
|
+
});
|
|
1055
|
+
process.exitCode = 1;
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1058
|
+
return outputResult(await httpRequest('POST', '/webhooks/register', {
|
|
1059
|
+
url,
|
|
1060
|
+
events: events
|
|
1061
|
+
.split(',')
|
|
1062
|
+
.map((e) => e.trim())
|
|
1063
|
+
.filter((e) => e.length > 0),
|
|
1064
|
+
secret: parseFlag('--secret')
|
|
1065
|
+
}));
|
|
1066
|
+
}
|
|
1067
|
+
case 'unregister':
|
|
1068
|
+
return outputResult(await httpRequest('DELETE', '/webhooks/unregister', {
|
|
1069
|
+
id: filteredArgs[2]
|
|
1070
|
+
}));
|
|
1071
|
+
case 'list':
|
|
1072
|
+
return outputResult(await httpRequest('GET', '/webhooks'));
|
|
1073
|
+
default:
|
|
1074
|
+
output({
|
|
1075
|
+
ok: false,
|
|
1076
|
+
error: {
|
|
1077
|
+
code: 'UNKNOWN_COMMAND',
|
|
1078
|
+
message: 'Usage: beignet webhooks [register <url> <events>|unregister <id>|list]'
|
|
1079
|
+
}
|
|
1080
|
+
});
|
|
1081
|
+
process.exitCode = 1;
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
async function handleQueue() {
|
|
1085
|
+
const sub = filteredArgs[1];
|
|
1086
|
+
switch (sub) {
|
|
1087
|
+
case 'add': {
|
|
1088
|
+
const bolt11 = filteredArgs[2];
|
|
1089
|
+
if (!bolt11) {
|
|
1090
|
+
output({
|
|
1091
|
+
ok: false,
|
|
1092
|
+
error: {
|
|
1093
|
+
code: 'INVALID_PARAMS',
|
|
1094
|
+
message: 'Usage: beignet queue add <bolt11> [--priority <1-10>] [--amount <sats>] [--max-fee <sats>]'
|
|
1095
|
+
}
|
|
1096
|
+
});
|
|
1097
|
+
process.exitCode = 1;
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
const priority = parseFlag('--priority');
|
|
1101
|
+
const amount = parseFlag('--amount');
|
|
1102
|
+
const maxFee = parseFlag('--max-fee');
|
|
1103
|
+
return outputResult(await httpRequest('POST', '/queue/add', {
|
|
1104
|
+
bolt11,
|
|
1105
|
+
priority: priority !== undefined ? parseInt(priority, 10) : undefined,
|
|
1106
|
+
amountSats: amount !== undefined ? parseInt(amount, 10) : undefined,
|
|
1107
|
+
maxFeeSats: maxFee !== undefined ? parseInt(maxFee, 10) : undefined
|
|
1108
|
+
}));
|
|
1109
|
+
}
|
|
1110
|
+
case 'cancel':
|
|
1111
|
+
return outputResult(await httpRequest('POST', '/queue/cancel', { id: filteredArgs[2] }));
|
|
1112
|
+
case 'list':
|
|
1113
|
+
return outputResult(await httpRequest('GET', '/queue'));
|
|
1114
|
+
default:
|
|
1115
|
+
output({
|
|
1116
|
+
ok: false,
|
|
1117
|
+
error: {
|
|
1118
|
+
code: 'UNKNOWN_COMMAND',
|
|
1119
|
+
message: 'Usage: beignet queue [add <bolt11>|cancel <id>|list]'
|
|
1120
|
+
}
|
|
1121
|
+
});
|
|
1122
|
+
process.exitCode = 1;
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
async function handleGraph() {
|
|
1126
|
+
const sub = filteredArgs[1];
|
|
1127
|
+
switch (sub) {
|
|
1128
|
+
case 'info':
|
|
1129
|
+
return outputResult(await httpRequest('GET', '/graph/info'));
|
|
1130
|
+
case 'node':
|
|
1131
|
+
return outputResult(await httpRequest('GET', `/graph/node?pubkey=${encodeURIComponent(filteredArgs[2] || '')}`));
|
|
1132
|
+
case 'channel':
|
|
1133
|
+
return outputResult(await httpRequest('GET', `/graph/channel?scid=${encodeURIComponent(filteredArgs[2] || '')}`));
|
|
1134
|
+
case 'describe': {
|
|
1135
|
+
const params = new URLSearchParams();
|
|
1136
|
+
const limit = parseFlag('--limit');
|
|
1137
|
+
if (limit !== undefined)
|
|
1138
|
+
params.set('limit', limit);
|
|
1139
|
+
const offset = parseFlag('--offset');
|
|
1140
|
+
if (offset !== undefined)
|
|
1141
|
+
params.set('offset', offset);
|
|
1142
|
+
const qs = params.toString();
|
|
1143
|
+
return outputResult(await httpRequest('GET', qs ? `/graph/describe?${qs}` : '/graph/describe'));
|
|
1144
|
+
}
|
|
1145
|
+
default:
|
|
1146
|
+
output({
|
|
1147
|
+
ok: false,
|
|
1148
|
+
error: {
|
|
1149
|
+
code: 'UNKNOWN_COMMAND',
|
|
1150
|
+
message: 'Usage: beignet graph [info|node <pubkey>|channel <scid>|describe [--limit N] [--offset N]]'
|
|
1151
|
+
}
|
|
1152
|
+
});
|
|
1153
|
+
process.exitCode = 1;
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
async function handleWatchtower() {
|
|
1157
|
+
const sub = filteredArgs[1];
|
|
1158
|
+
switch (sub) {
|
|
1159
|
+
case 'list':
|
|
1160
|
+
return outputResult(await httpRequest('GET', '/watchtowers'));
|
|
1161
|
+
case 'add': {
|
|
1162
|
+
const uri = filteredArgs[2];
|
|
1163
|
+
if (!uri) {
|
|
1164
|
+
output({
|
|
1165
|
+
ok: false,
|
|
1166
|
+
error: {
|
|
1167
|
+
code: 'INVALID_PARAMS',
|
|
1168
|
+
message: 'Usage: beignet watchtower add <pubkey@host:port>'
|
|
1169
|
+
}
|
|
1170
|
+
});
|
|
1171
|
+
process.exitCode = 1;
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
return outputResult(await httpRequest('POST', '/watchtower/add', { uri }));
|
|
1175
|
+
}
|
|
1176
|
+
case 'remove': {
|
|
1177
|
+
const uri = filteredArgs[2];
|
|
1178
|
+
if (!uri) {
|
|
1179
|
+
output({
|
|
1180
|
+
ok: false,
|
|
1181
|
+
error: {
|
|
1182
|
+
code: 'INVALID_PARAMS',
|
|
1183
|
+
message: 'Usage: beignet watchtower remove <pubkey@host:port>'
|
|
1184
|
+
}
|
|
1185
|
+
});
|
|
1186
|
+
process.exitCode = 1;
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
return outputResult(await httpRequest('DELETE', '/watchtower/remove', { uri }));
|
|
1190
|
+
}
|
|
1191
|
+
default:
|
|
1192
|
+
output({
|
|
1193
|
+
ok: false,
|
|
1194
|
+
error: {
|
|
1195
|
+
code: 'UNKNOWN_COMMAND',
|
|
1196
|
+
message: 'Usage: beignet watchtower [list|add <uri>|remove <uri>]'
|
|
1197
|
+
}
|
|
1198
|
+
});
|
|
1199
|
+
process.exitCode = 1;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
async function handleRoute() {
|
|
1203
|
+
const sub = filteredArgs[1];
|
|
1204
|
+
switch (sub) {
|
|
1205
|
+
case 'query': {
|
|
1206
|
+
const destination = filteredArgs[2];
|
|
1207
|
+
const sats = filteredArgs[3];
|
|
1208
|
+
if (!destination || !sats) {
|
|
1209
|
+
output({
|
|
1210
|
+
ok: false,
|
|
1211
|
+
error: {
|
|
1212
|
+
code: 'INVALID_PARAMS',
|
|
1213
|
+
message: 'Usage: beignet route query <destination> <sats> [--max-fee <sats>]'
|
|
1214
|
+
}
|
|
1215
|
+
});
|
|
1216
|
+
process.exitCode = 1;
|
|
1217
|
+
return;
|
|
1218
|
+
}
|
|
1219
|
+
const maxFee = parseFlag('--max-fee');
|
|
1220
|
+
return outputResult(await httpRequest('POST', '/route/query', {
|
|
1221
|
+
destination,
|
|
1222
|
+
amountSats: parseInt(sats, 10),
|
|
1223
|
+
maxFeeSats: maxFee !== undefined ? parseInt(maxFee, 10) : undefined
|
|
1224
|
+
}));
|
|
1225
|
+
}
|
|
1226
|
+
case 'estimate':
|
|
1227
|
+
return outputResult(await httpRequest('POST', '/route/estimate', {
|
|
1228
|
+
bolt11: filteredArgs[2],
|
|
1229
|
+
amountSats: filteredArgs[3]
|
|
1230
|
+
? parseInt(filteredArgs[3], 10)
|
|
1231
|
+
: undefined
|
|
1232
|
+
}));
|
|
1233
|
+
case 'probe': {
|
|
1234
|
+
const destination = filteredArgs[2];
|
|
1235
|
+
const sats = filteredArgs[3];
|
|
1236
|
+
if (!destination || !sats) {
|
|
1237
|
+
output({
|
|
1238
|
+
ok: false,
|
|
1239
|
+
error: {
|
|
1240
|
+
code: 'INVALID_PARAMS',
|
|
1241
|
+
message: 'Usage: beignet route probe <destination> <sats>'
|
|
1242
|
+
}
|
|
1243
|
+
});
|
|
1244
|
+
process.exitCode = 1;
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1247
|
+
return outputResult(await httpRequest('POST', '/route/probe', {
|
|
1248
|
+
destination,
|
|
1249
|
+
amountSats: parseInt(sats, 10)
|
|
1250
|
+
}));
|
|
1251
|
+
}
|
|
1252
|
+
default:
|
|
1253
|
+
output({
|
|
1254
|
+
ok: false,
|
|
1255
|
+
error: {
|
|
1256
|
+
code: 'UNKNOWN_COMMAND',
|
|
1257
|
+
message: 'Usage: beignet route [query <destination> <sats>|estimate <bolt11> [sats]|probe <destination> <sats>]'
|
|
1258
|
+
}
|
|
1259
|
+
});
|
|
1260
|
+
process.exitCode = 1;
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
async function handleForwards() {
|
|
1264
|
+
const params = new URLSearchParams();
|
|
1265
|
+
const since = parseFlag('--since');
|
|
1266
|
+
if (since !== undefined)
|
|
1267
|
+
params.set('since', since);
|
|
1268
|
+
if (filteredArgs[1] === 'summary') {
|
|
1269
|
+
const qs = params.toString();
|
|
1270
|
+
return outputResult(await httpRequest('GET', `/forwards/summary${qs ? `?${qs}` : ''}`));
|
|
1271
|
+
}
|
|
1272
|
+
const limit = parseFlag('--limit');
|
|
1273
|
+
if (limit !== undefined)
|
|
1274
|
+
params.set('limit', limit);
|
|
1275
|
+
const qs = params.toString();
|
|
1276
|
+
return outputResult(await httpRequest('GET', `/forwards${qs ? `?${qs}` : ''}`));
|
|
1277
|
+
}
|
|
1278
|
+
async function handleRebalance() {
|
|
1279
|
+
const fromChannelId = filteredArgs[1];
|
|
1280
|
+
const toChannelId = filteredArgs[2];
|
|
1281
|
+
const amountSats = filteredArgs[3];
|
|
1282
|
+
const maxFee = parseFlag('--max-fee');
|
|
1283
|
+
if (!fromChannelId || !toChannelId || !amountSats || maxFee === undefined) {
|
|
1284
|
+
output({
|
|
1285
|
+
ok: false,
|
|
1286
|
+
error: {
|
|
1287
|
+
code: 'INVALID_PARAMS',
|
|
1288
|
+
message: 'Usage: beignet rebalance <fromChannelId> <toChannelId> <amountSats> --max-fee <sats>'
|
|
1289
|
+
}
|
|
1290
|
+
});
|
|
1291
|
+
process.exitCode = 1;
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1294
|
+
return outputResult(await httpRequest('POST', '/rebalance', {
|
|
1295
|
+
fromChannelId,
|
|
1296
|
+
toChannelId,
|
|
1297
|
+
amountSats: parseInt(amountSats, 10),
|
|
1298
|
+
maxFeeSats: parseInt(maxFee, 10)
|
|
1299
|
+
}));
|
|
1300
|
+
}
|
|
1301
|
+
async function handleAdvisor() {
|
|
1302
|
+
const sub = filteredArgs[1];
|
|
1303
|
+
switch (sub) {
|
|
1304
|
+
case 'recommendations':
|
|
1305
|
+
return outputResult(await httpRequest('GET', '/advisor/recommendations'));
|
|
1306
|
+
case 'execute-rebalances': {
|
|
1307
|
+
const budget = parseFlag('--budget');
|
|
1308
|
+
return outputResult(await httpRequest('POST', '/advisor/execute-rebalances', {
|
|
1309
|
+
budgetSatsPerDay: budget !== undefined ? parseInt(budget, 10) : undefined
|
|
1310
|
+
}));
|
|
1311
|
+
}
|
|
462
1312
|
default:
|
|
463
1313
|
output({
|
|
464
1314
|
ok: false,
|
|
465
1315
|
error: {
|
|
466
1316
|
code: 'UNKNOWN_COMMAND',
|
|
467
|
-
message: 'Usage: beignet
|
|
1317
|
+
message: 'Usage: beignet advisor [recommendations|execute-rebalances [--budget <sats>]]'
|
|
468
1318
|
}
|
|
469
1319
|
});
|
|
470
1320
|
process.exitCode = 1;
|
|
@@ -526,6 +1376,10 @@ async function handleOffer() {
|
|
|
526
1376
|
}));
|
|
527
1377
|
case 'list':
|
|
528
1378
|
return outputResult(await httpRequest('GET', '/offers'));
|
|
1379
|
+
case 'decode':
|
|
1380
|
+
return outputResult(await httpRequest('POST', '/offer/decode', {
|
|
1381
|
+
offer: filteredArgs[2]
|
|
1382
|
+
}));
|
|
529
1383
|
case 'pay':
|
|
530
1384
|
return outputResult(await httpRequest('POST', '/offer/pay', {
|
|
531
1385
|
offer: filteredArgs[2],
|
|
@@ -538,11 +1392,197 @@ async function handleOffer() {
|
|
|
538
1392
|
ok: false,
|
|
539
1393
|
error: {
|
|
540
1394
|
code: 'UNKNOWN_COMMAND',
|
|
541
|
-
message: 'Usage: beignet offer [create|list|pay]'
|
|
1395
|
+
message: 'Usage: beignet offer [create|list|decode|pay]'
|
|
1396
|
+
}
|
|
1397
|
+
});
|
|
1398
|
+
process.exitCode = 1;
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
async function handleGossip() {
|
|
1402
|
+
const sub = filteredArgs[1];
|
|
1403
|
+
switch (sub) {
|
|
1404
|
+
case 'sync':
|
|
1405
|
+
return outputResult(await httpRequest('POST', '/gossip/sync', {
|
|
1406
|
+
pubkey: filteredArgs[2] || undefined
|
|
1407
|
+
}));
|
|
1408
|
+
case 'sync-rapid':
|
|
1409
|
+
return outputResult(await httpRequest('POST', '/gossip/sync-rapid'));
|
|
1410
|
+
default:
|
|
1411
|
+
output({
|
|
1412
|
+
ok: false,
|
|
1413
|
+
error: {
|
|
1414
|
+
code: 'UNKNOWN_COMMAND',
|
|
1415
|
+
message: 'Usage: beignet gossip [sync [pubkey]|sync-rapid]'
|
|
1416
|
+
}
|
|
1417
|
+
});
|
|
1418
|
+
process.exitCode = 1;
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
async function handleMessage() {
|
|
1422
|
+
const sub = filteredArgs[1];
|
|
1423
|
+
switch (sub) {
|
|
1424
|
+
case 'sign':
|
|
1425
|
+
return outputResult(await httpRequest('POST', '/message/sign', {
|
|
1426
|
+
message: filteredArgs[2]
|
|
1427
|
+
}));
|
|
1428
|
+
case 'verify':
|
|
1429
|
+
return outputResult(await httpRequest('POST', '/message/verify', {
|
|
1430
|
+
message: filteredArgs[2],
|
|
1431
|
+
signature: filteredArgs[3]
|
|
1432
|
+
}));
|
|
1433
|
+
default:
|
|
1434
|
+
output({
|
|
1435
|
+
ok: false,
|
|
1436
|
+
error: {
|
|
1437
|
+
code: 'UNKNOWN_COMMAND',
|
|
1438
|
+
message: 'Usage: beignet message [sign <message>|verify <message> <signature>]'
|
|
1439
|
+
}
|
|
1440
|
+
});
|
|
1441
|
+
process.exitCode = 1;
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
async function handleBackup() {
|
|
1445
|
+
const sub = filteredArgs[1];
|
|
1446
|
+
if (sub === 'trigger') {
|
|
1447
|
+
return outputResult(await httpRequest('POST', '/backup/trigger'));
|
|
1448
|
+
}
|
|
1449
|
+
if (sub === 'peer-retrieved') {
|
|
1450
|
+
return outputResult(await httpRequest('GET', '/backup/peer-retrieved'));
|
|
1451
|
+
}
|
|
1452
|
+
if (sub === 'scb') {
|
|
1453
|
+
const result = await httpRequest('GET', '/backup/scb');
|
|
1454
|
+
const destPath = filteredArgs[2];
|
|
1455
|
+
if (!result.ok || !destPath)
|
|
1456
|
+
return outputResult(result);
|
|
1457
|
+
const { encoded, channelCount } = result.result;
|
|
1458
|
+
fs.writeFileSync(destPath, encoded);
|
|
1459
|
+
return output({
|
|
1460
|
+
ok: true,
|
|
1461
|
+
result: { written: true, path: destPath, channelCount }
|
|
1462
|
+
});
|
|
1463
|
+
}
|
|
1464
|
+
if (!sub) {
|
|
1465
|
+
output({
|
|
1466
|
+
ok: false,
|
|
1467
|
+
error: {
|
|
1468
|
+
code: 'INVALID_PARAMS',
|
|
1469
|
+
message: 'Usage: beignet backup <destPath> | beignet backup scb [destPath] | beignet backup trigger'
|
|
1470
|
+
}
|
|
1471
|
+
});
|
|
1472
|
+
process.exitCode = 1;
|
|
1473
|
+
return;
|
|
1474
|
+
}
|
|
1475
|
+
return outputResult(await httpRequest('POST', '/backup', { destPath: sub }));
|
|
1476
|
+
}
|
|
1477
|
+
async function handleRestore() {
|
|
1478
|
+
const sub = filteredArgs[1];
|
|
1479
|
+
const file = filteredArgs[2];
|
|
1480
|
+
if (sub === 'scb') {
|
|
1481
|
+
if (!file) {
|
|
1482
|
+
output({
|
|
1483
|
+
ok: false,
|
|
1484
|
+
error: {
|
|
1485
|
+
code: 'INVALID_PARAMS',
|
|
1486
|
+
message: 'Usage: beignet restore scb <file>'
|
|
1487
|
+
}
|
|
1488
|
+
});
|
|
1489
|
+
process.exitCode = 1;
|
|
1490
|
+
return;
|
|
1491
|
+
}
|
|
1492
|
+
let encoded;
|
|
1493
|
+
try {
|
|
1494
|
+
encoded = fs.readFileSync(file, 'utf8').trim();
|
|
1495
|
+
}
|
|
1496
|
+
catch (err) {
|
|
1497
|
+
output({
|
|
1498
|
+
ok: false,
|
|
1499
|
+
error: {
|
|
1500
|
+
code: 'INVALID_PARAMS',
|
|
1501
|
+
message: `Cannot read SCB file: ${err.message}`
|
|
1502
|
+
}
|
|
1503
|
+
});
|
|
1504
|
+
process.exitCode = 1;
|
|
1505
|
+
return;
|
|
1506
|
+
}
|
|
1507
|
+
return outputResult(await httpRequest('POST', '/restore/scb', { encoded }));
|
|
1508
|
+
}
|
|
1509
|
+
if (sub === 'db') {
|
|
1510
|
+
if (!file) {
|
|
1511
|
+
output({
|
|
1512
|
+
ok: false,
|
|
1513
|
+
error: {
|
|
1514
|
+
code: 'INVALID_PARAMS',
|
|
1515
|
+
message: 'Usage: beignet restore db <backupFile>'
|
|
1516
|
+
}
|
|
1517
|
+
});
|
|
1518
|
+
process.exitCode = 1;
|
|
1519
|
+
return;
|
|
1520
|
+
}
|
|
1521
|
+
const config = (0, config_1.resolveConfig)({});
|
|
1522
|
+
if (!config.mnemonic) {
|
|
1523
|
+
output({
|
|
1524
|
+
ok: false,
|
|
1525
|
+
error: {
|
|
1526
|
+
code: 'NO_MNEMONIC',
|
|
1527
|
+
message: 'No mnemonic found. Run "beignet init" first or set BEIGNET_MNEMONIC (the restored DB is seed-encrypted and needs the same mnemonic).'
|
|
542
1528
|
}
|
|
543
1529
|
});
|
|
544
1530
|
process.exitCode = 1;
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1533
|
+
const pidInfo = (0, config_1.readPidFile)();
|
|
1534
|
+
if (pidInfo) {
|
|
1535
|
+
try {
|
|
1536
|
+
process.kill(pidInfo.pid, 0);
|
|
1537
|
+
output({
|
|
1538
|
+
ok: false,
|
|
1539
|
+
error: {
|
|
1540
|
+
code: 'DAEMON_RUNNING',
|
|
1541
|
+
message: `Daemon is running (PID ${pidInfo.pid}). Stop it with 'beignet stop' before restoring the database.`
|
|
1542
|
+
}
|
|
1543
|
+
});
|
|
1544
|
+
process.exitCode = 1;
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
catch {
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
const network = config.network || 'mainnet';
|
|
1551
|
+
const dataDir = config.dataDir || (0, beignet_node_1.defaultDataDirForMnemonic)(config.mnemonic);
|
|
1552
|
+
const dbPath = nodePath.join(dataDir, `${network}.db`);
|
|
1553
|
+
const lockPath = nodePath.join(dataDir, `${network}.lock`);
|
|
1554
|
+
try {
|
|
1555
|
+
fs.mkdirSync(dataDir, { recursive: true });
|
|
1556
|
+
const result = (0, restore_1.performDbRestore)(file, dbPath, lockPath);
|
|
1557
|
+
output({
|
|
1558
|
+
ok: true,
|
|
1559
|
+
result: {
|
|
1560
|
+
restored: true,
|
|
1561
|
+
dbPath: result.dbPath,
|
|
1562
|
+
preRestorePath: result.preRestorePath,
|
|
1563
|
+
network,
|
|
1564
|
+
note: 'DB is encrypted under the wallet seed; start the node with the same mnemonic.'
|
|
1565
|
+
}
|
|
1566
|
+
});
|
|
1567
|
+
}
|
|
1568
|
+
catch (err) {
|
|
1569
|
+
const code = err instanceof instance_lock_1.InstanceLockError ? 'DAEMON_RUNNING' : 'RESTORE_FAILED';
|
|
1570
|
+
output({
|
|
1571
|
+
ok: false,
|
|
1572
|
+
error: { code, message: err.message }
|
|
1573
|
+
});
|
|
1574
|
+
process.exitCode = 1;
|
|
1575
|
+
}
|
|
1576
|
+
return;
|
|
545
1577
|
}
|
|
1578
|
+
output({
|
|
1579
|
+
ok: false,
|
|
1580
|
+
error: {
|
|
1581
|
+
code: 'UNKNOWN_COMMAND',
|
|
1582
|
+
message: 'Usage: beignet restore scb <file> | beignet restore db <backupFile>'
|
|
1583
|
+
}
|
|
1584
|
+
});
|
|
1585
|
+
process.exitCode = 1;
|
|
546
1586
|
}
|
|
547
1587
|
async function handleMetrics() {
|
|
548
1588
|
const port = (0, config_1.getDaemonPort)();
|
|
@@ -584,18 +1624,68 @@ Info:
|
|
|
584
1624
|
info Node info
|
|
585
1625
|
balance On-chain + Lightning balance
|
|
586
1626
|
address New receive address
|
|
1627
|
+
address --bip21 [--amount <sats>] [--label L] [--message M]
|
|
1628
|
+
New address as a BIP21 URI
|
|
1629
|
+
address validate <address> Validate a Bitcoin address
|
|
1630
|
+
address label <address> [label] Set a user label for an address
|
|
1631
|
+
(omit the label to clear it)
|
|
1632
|
+
address labels List all user address labels
|
|
587
1633
|
mnemonic Show mnemonic
|
|
588
1634
|
health Node health status
|
|
1635
|
+
ready Whether the node is operational
|
|
589
1636
|
readiness Mainnet readiness checklist
|
|
590
1637
|
metrics Prometheus-format metrics (text/plain)
|
|
591
1638
|
stats [windowMs] Node statistics (optional time window)
|
|
1639
|
+
liquidity Liquidity snapshot + recommendations
|
|
1640
|
+
fees On-chain fee trend analysis
|
|
1641
|
+
spend-limit Combined LN + on-chain daily spend
|
|
1642
|
+
limit status (with breakdown)
|
|
1643
|
+
logs [--category C] [--since ts] [--limit n]
|
|
1644
|
+
Query the persistent action log
|
|
1645
|
+
can-send [sats] Check Lightning send capacity
|
|
1646
|
+
can-receive [sats] Check Lightning receive capacity
|
|
1647
|
+
node uri [--host <addr>] Node connection URI (pubkey@host:port)
|
|
1648
|
+
node wait-ready [--timeout ms] Block until the node is operational
|
|
592
1649
|
|
|
593
1650
|
On-chain:
|
|
594
1651
|
send <address> <sats> Send on-chain
|
|
1652
|
+
send-max <address> [satsPerVbyte] Sweep the whole on-chain balance
|
|
1653
|
+
tx bump-fee <txid> <satsPerVbyte> RBF an unconfirmed tx at a higher fee
|
|
1654
|
+
tx boost <txid> [satsPerVbyte] Fee-bump a tx (RBF when possible,
|
|
1655
|
+
else CPFP)
|
|
1656
|
+
tx boostable List unconfirmed txs eligible for
|
|
1657
|
+
RBF/CPFP
|
|
1658
|
+
consolidate [satsPerVbyte] Merge all UTXOs into one output at a
|
|
1659
|
+
fresh wallet address
|
|
1660
|
+
psbt build <address> <sats> [satsPerVbyte]
|
|
1661
|
+
Build an UNSIGNED PSBT for an external
|
|
1662
|
+
signer (hardware wallet)
|
|
1663
|
+
psbt import-signed <psbtBase64|file> Validate + finalize a signed PSBT;
|
|
1664
|
+
returns txid/txHex WITHOUT broadcast
|
|
1665
|
+
psbt combine <psbt|file> <psbt|file> Combine partially signed PSBT copies
|
|
595
1666
|
transactions [limit] List on-chain transactions (newest first)
|
|
596
|
-
utxos List wallet UTXOs
|
|
1667
|
+
utxos List wallet UTXOs (includes frozen flag)
|
|
1668
|
+
utxo freeze <txid> <index> Freeze a UTXO (excluded from coin
|
|
1669
|
+
selection until unfrozen)
|
|
1670
|
+
utxo unfreeze <txid> <index> Unfreeze a UTXO
|
|
1671
|
+
utxo frozen List frozen UTXOs
|
|
597
1672
|
fee-estimates Current fee estimates (sats/vbyte)
|
|
1673
|
+
wallet refresh Re-sync the on-chain wallet
|
|
1674
|
+
wallet descriptors Export BIP 380 output descriptors
|
|
1675
|
+
(public keys only, never private)
|
|
1676
|
+
recover-fallback-funds [--fee-rate N] Sweep funding-key fallback UTXOs into
|
|
1677
|
+
the wallet
|
|
598
1678
|
backup <destPath> Create database backup
|
|
1679
|
+
backup trigger Run the configured scheduled backup now
|
|
1680
|
+
backup scb [destPath] Export encrypted static channel backup
|
|
1681
|
+
backup peer-retrieved Show newest SCB returned by a peer
|
|
1682
|
+
(BOLT 1 peer storage)
|
|
1683
|
+
restore scb <file> Restore channels from an SCB (on-chain
|
|
1684
|
+
recovery only: peers force-close and
|
|
1685
|
+
funds are swept to the wallet)
|
|
1686
|
+
restore db <backupFile> Restore a database backup (full state;
|
|
1687
|
+
OFFLINE - stop the daemon first; needs
|
|
1688
|
+
the same mnemonic, DB is seed-encrypted)
|
|
599
1689
|
|
|
600
1690
|
Peers:
|
|
601
1691
|
peer connect <pubkey> <host> <port> Connect to peer
|
|
@@ -615,29 +1705,119 @@ Channels:
|
|
|
615
1705
|
channel open <pubkey> <sats> [push] Open channel (auto-funded)
|
|
616
1706
|
channel open-zeroconf <pk> <sats> [push] Open zero-conf channel
|
|
617
1707
|
channel open-v2 <pubkey> <sats> [feerate] Open dual-funded v2 channel
|
|
1708
|
+
channel open-and-wait <pubkey> <sats> [push] [--timeout ms]
|
|
1709
|
+
Open channel + block until NORMAL
|
|
1710
|
+
channel connect-and-open <pubkey> <host> <port> <sats> [push]
|
|
1711
|
+
Connect to peer + open in one call
|
|
618
1712
|
channel close <id> Cooperative close
|
|
619
1713
|
channel forceclose <id> Force close
|
|
620
1714
|
channel splice-in <id> <sats> <feerate> Add funds to channel
|
|
621
1715
|
channel splice-out <id> <sats> <feerate> Withdraw funds from channel
|
|
622
1716
|
channel ensure-minimum <count> <sats> Auto-open channels to minimum count
|
|
1717
|
+
channel update-policy <id|all> [--base-fee-msat N] [--ppm N] [--cltv-delta N]
|
|
1718
|
+
[--htlc-min-msat N] [--htlc-max-msat N]
|
|
1719
|
+
Set routing fee policy (channel_update)
|
|
1720
|
+
channel update-commitment-feerate <id> <feeratePerKw>
|
|
1721
|
+
Set COMMITMENT feerate (BOLT 2
|
|
1722
|
+
update_fee), not the routing policy
|
|
1723
|
+
channel policy <id> Effective routing policy for a channel
|
|
623
1724
|
channel list List channels
|
|
624
|
-
channel
|
|
1725
|
+
channel ready List channels in NORMAL state
|
|
1726
|
+
channel get <id> Channel details (includes routing policy)
|
|
1727
|
+
channel health <id> Channel health + liquidity warnings
|
|
1728
|
+
channel diagnostics <id> Routing-readiness diagnostics for a channel
|
|
1729
|
+
channel suggestions [count] Graph-based channel open suggestions
|
|
1730
|
+
channel wait-ready <id> [--timeout ms] Block until a channel reaches NORMAL
|
|
625
1731
|
|
|
626
1732
|
Invoices & Payments:
|
|
627
1733
|
invoice create <sats> [description] Create BOLT 11 invoice
|
|
1734
|
+
invoice create-hold <hash> [sats] [description] [--expiry secs]
|
|
1735
|
+
Create hold invoice for a payment hash
|
|
1736
|
+
you supply (keep the preimage; HTLCs
|
|
1737
|
+
park until settle-hold/cancel-hold)
|
|
1738
|
+
invoice settle-hold <preimage> Settle a parked hold invoice
|
|
1739
|
+
invoice cancel-hold <hash> Cancel a hold invoice (fails HTLCs back)
|
|
1740
|
+
invoice held List hold invoices + their state
|
|
628
1741
|
invoice decode <bolt11> Decode invoice
|
|
1742
|
+
invoice validate <bolt11> [sats] Pre-flight checks: should this be paid?
|
|
1743
|
+
invoice get <hash> Details of an invoice we created
|
|
629
1744
|
invoice pay <bolt11> Pay invoice (blocks until settled)
|
|
1745
|
+
invoice pay-safe <bolt11> [--max-fee N] [--amount N] [--timeout ms]
|
|
1746
|
+
Pay; resolves with status FAILED
|
|
1747
|
+
instead of erroring
|
|
1748
|
+
invoice pay-async <bolt11> [--max-fee N] [--amount N]
|
|
1749
|
+
Fire-and-forget pay; poll 'payment get'
|
|
630
1750
|
invoice pay-retry <bolt11> [flags] Pay with exponential backoff retry
|
|
631
1751
|
invoice list List created invoices
|
|
1752
|
+
keysend [safe] <pubkey> <sats> [--max-fee N] [--timeout ms]
|
|
1753
|
+
Spontaneous payment, no invoice needed
|
|
1754
|
+
('safe' resolves FAILED, never errors)
|
|
632
1755
|
payment list List payments
|
|
633
1756
|
payment get <hash> Payment details
|
|
1757
|
+
payment cancel <hash> Cancel a pending outbound payment
|
|
1758
|
+
payment wait <hash> [--timeout ms] Block until a payment settles
|
|
1759
|
+
payment proof <hash> Cryptographic payment proof
|
|
1760
|
+
payment verify-proof <hash> Verify a stored payment proof
|
|
1761
|
+
payment estimate <bolt11> [sats] Success probability + fee estimate
|
|
1762
|
+
payment metadata <hash> <json> Attach key-value metadata to a payment
|
|
1763
|
+
payment send-to-route <hash> <route> Pay along an explicit route (inline
|
|
1764
|
+
JSON or a file with 'route query'
|
|
1765
|
+
output) [--payment-secret <hex>]
|
|
1766
|
+
queue add <bolt11> [--priority N] [--amount N] [--max-fee N]
|
|
1767
|
+
Enqueue a payment for ordered dispatch
|
|
1768
|
+
queue cancel <id> Cancel a queued payment
|
|
1769
|
+
queue list List the payment queue
|
|
1770
|
+
|
|
1771
|
+
Graph Queries:
|
|
1772
|
+
graph info Graph summary (node/channel counts)
|
|
1773
|
+
graph node <pubkey> Node announcement info + its channels
|
|
1774
|
+
graph channel <scid> Channel endpoints + both fee policies
|
|
1775
|
+
(scid: <block>x<tx>x<out> or hex)
|
|
1776
|
+
graph describe [--limit N] [--offset N] Paged channel dump (default 500)
|
|
1777
|
+
gossip sync [pubkey] Sync gossip from peers (or one peer)
|
|
1778
|
+
gossip sync-rapid Rapid Gossip Sync snapshot (mainnet)
|
|
1779
|
+
route query <destination> <sats> Compute a route without paying
|
|
1780
|
+
[--max-fee <sats>]
|
|
1781
|
+
route estimate <bolt11> [sats] Estimate route fee for an invoice
|
|
1782
|
+
route probe <destination> <sats> Probe route viability (no payment)
|
|
1783
|
+
|
|
1784
|
+
Routing:
|
|
1785
|
+
forwards [--since ts] [--limit n] List settled forwards (fees earned)
|
|
1786
|
+
forwards summary [--since ts] Forwarding totals (count, volume, fees)
|
|
1787
|
+
rebalance <fromId> <toId> <sats> --max-fee <sats>
|
|
1788
|
+
Circular rebalance between two of our
|
|
1789
|
+
channels (aborts if fee exceeds cap)
|
|
1790
|
+
advisor recommendations Liquidity analysis + rebalance plan
|
|
1791
|
+
advisor execute-rebalances [--budget <sats>]
|
|
1792
|
+
Run the advisor's rebalance plan under
|
|
1793
|
+
a per-day fee budget
|
|
1794
|
+
|
|
1795
|
+
Messages:
|
|
1796
|
+
message sign <message> Sign with the node key (LND-compatible)
|
|
1797
|
+
message verify <message> <signature> Recover + check the signer pubkey
|
|
1798
|
+
Watchtowers:
|
|
1799
|
+
watchtower list Per-tower session + backlog health
|
|
1800
|
+
watchtower add <pubkey@host:port> Add an LND altruist watchtower
|
|
1801
|
+
watchtower remove <pubkey@host:port> Remove a watchtower
|
|
634
1802
|
|
|
635
1803
|
BOLT 12 Offers:
|
|
636
1804
|
offer create <description> [amountSats] Create reusable offer
|
|
637
1805
|
offer list List local offers
|
|
1806
|
+
offer decode <offer> Decode a BOLT 12 offer string
|
|
638
1807
|
offer pay <offer> [amountSats] Pay a BOLT 12 offer
|
|
639
1808
|
|
|
1809
|
+
Webhooks (event push; see also GET /events SSE):
|
|
1810
|
+
webhooks register <url> <events> [--secret S]
|
|
1811
|
+
Register a callback URL; <events> is
|
|
1812
|
+
comma-separated (or '*' for all)
|
|
1813
|
+
webhooks unregister <id> Remove a webhook
|
|
1814
|
+
webhooks list List registered webhooks
|
|
1815
|
+
|
|
640
1816
|
Start flags:
|
|
1817
|
+
--network <name> mainnet | testnet | signet | regtest
|
|
1818
|
+
--fee-source <src> Fee estimate source: electrum | http |
|
|
1819
|
+
auto (default: auto = Electrum first,
|
|
1820
|
+
HTTP fallback)
|
|
641
1821
|
--port <N> HTTP daemon port (default: 2112)
|
|
642
1822
|
--host <addr> HTTP daemon bind address (default: 127.0.0.1)
|
|
643
1823
|
--daemon Run in background
|
|
@@ -645,7 +1825,9 @@ Start flags:
|
|
|
645
1825
|
--api-token <token> API authentication token
|
|
646
1826
|
--backup-path <path> Enable automated backups to path
|
|
647
1827
|
--backup-interval <ms> Backup interval (default: 21600000 = 6h)
|
|
648
|
-
--daily-spend-limit <sats>
|
|
1828
|
+
--daily-spend-limit <sats> Combined daily spending limit in sats
|
|
1829
|
+
(Lightning payments AND external
|
|
1830
|
+
on-chain sends share one budget)
|
|
649
1831
|
--tls-cert <path> TLS certificate file (enables HTTPS)
|
|
650
1832
|
--tls-key <path> TLS private key file (requires --tls-cert)
|
|
651
1833
|
--tor-proxy <host:port> SOCKS5 proxy for outbound Lightning peer
|
|
@@ -653,6 +1835,9 @@ Start flags:
|
|
|
653
1835
|
--announce-addr <addr[,addr...]> Addresses to advertise in node_announcement
|
|
654
1836
|
(IPv4, [ipv6]:port, .onion v3, or hostname;
|
|
655
1837
|
port defaults to 9735)
|
|
1838
|
+
--htlc-events Relay per-HTLC events (htlc:forwarded/
|
|
1839
|
+
fulfilled/failed) over SSE + webhooks
|
|
1840
|
+
(off by default: high volume on routers)
|
|
656
1841
|
|
|
657
1842
|
Pay-retry flags:
|
|
658
1843
|
--max-retries <N> Max retry attempts (default: 3)
|