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