beignet 0.30.2 → 0.31.1
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 +15 -10
- package/dist/cli/beignet-node.js +124 -139
- package/dist/cli/beignet-node.js.map +1 -1
- package/dist/cli/cli.js +5 -0
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/config.js +7 -0
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/daemon-options.js +2 -0
- package/dist/cli/daemon-options.js.map +1 -1
- package/dist/cli/daemon.js +29 -10
- package/dist/cli/daemon.js.map +1 -1
- package/dist/cli/electrum-tls-config.js +105 -0
- package/dist/cli/electrum-tls-config.js.map +1 -0
- package/dist/cli/offline-receive.js +16 -6
- package/dist/cli/offline-receive.js.map +1 -1
- package/dist/cli/onchain-sweep.js.map +1 -1
- package/dist/cli/openapi.js +1359 -60
- package/dist/cli/openapi.js.map +1 -1
- package/dist/electrum/index.js +241 -155
- package/dist/electrum/index.js.map +1 -1
- package/dist/lightning/chain/chain-monitor.js +46 -0
- package/dist/lightning/chain/chain-monitor.js.map +1 -1
- package/dist/lightning/chain/chain-watcher.js +50 -3
- package/dist/lightning/chain/chain-watcher.js.map +1 -1
- package/dist/lightning/channel/channel-manager.js +87 -7
- 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 +45 -15
- package/dist/lightning/channel/channel.js.map +1 -1
- package/dist/lightning/channel/htlc-snapshots.js +40 -0
- package/dist/lightning/channel/htlc-snapshots.js.map +1 -0
- package/dist/lightning/direct-funding/receiver/engine.js +143 -14
- package/dist/lightning/direct-funding/receiver/engine.js.map +1 -1
- package/dist/lightning/direct-funding/receiver/index.js +2 -1
- package/dist/lightning/direct-funding/receiver/index.js.map +1 -1
- package/dist/lightning/direct-funding/receiver/types.js +6 -1
- package/dist/lightning/direct-funding/receiver/types.js.map +1 -1
- package/dist/lightning/direct-funding/receiver/verify.js +23 -1
- package/dist/lightning/direct-funding/receiver/verify.js.map +1 -1
- package/dist/lightning/gossip/network-graph.js +50 -3
- package/dist/lightning/gossip/network-graph.js.map +1 -1
- package/dist/lightning/gossip/pathfinding.js +74 -179
- package/dist/lightning/gossip/pathfinding.js.map +1 -1
- package/dist/lightning/gossip/pay-all.js +4 -7
- package/dist/lightning/gossip/pay-all.js.map +1 -1
- package/dist/lightning/gossip/types.js.map +1 -1
- package/dist/lightning/message/splice.js +11 -36
- package/dist/lightning/message/splice.js.map +1 -1
- package/dist/lightning/node/lightning-node.js +133 -89
- package/dist/lightning/node/lightning-node.js.map +1 -1
- package/dist/lightning/offer/merkle.js +3 -21
- package/dist/lightning/offer/merkle.js.map +1 -1
- package/dist/lightning/recovery/capsule.js +13 -0
- package/dist/lightning/recovery/capsule.js.map +1 -1
- package/dist/lightning/recovery/frame-codec.js +7 -5
- package/dist/lightning/recovery/frame-codec.js.map +1 -1
- package/dist/lightning/recovery/journal.js +43 -45
- package/dist/lightning/recovery/journal.js.map +1 -1
- package/dist/lightning/recovery/recovery-manager.js +22 -0
- package/dist/lightning/recovery/recovery-manager.js.map +1 -1
- package/dist/lightning/script/htlc-taproot.js +2 -17
- package/dist/lightning/script/htlc-taproot.js.map +1 -1
- package/dist/lightning/storage/serialization.js +30 -18
- package/dist/lightning/storage/serialization.js.map +1 -1
- package/dist/lightning/storage/sqlite-storage.js +193 -53
- package/dist/lightning/storage/sqlite-storage.js.map +1 -1
- package/dist/lightning/storage/types.js.map +1 -1
- package/dist/lightning/transport/peer-manager.js +20 -1
- package/dist/lightning/transport/peer-manager.js.map +1 -1
- package/dist/lightning/watchtower/watchtower-client.js +3 -1
- package/dist/lightning/watchtower/watchtower-client.js.map +1 -1
- package/dist/shapes/electrum.js +2 -1
- package/dist/shapes/electrum.js.map +1 -1
- package/dist/transaction/index.js +359 -306
- package/dist/transaction/index.js.map +1 -1
- package/dist/types/cli/beignet-node.d.ts +11 -13
- package/dist/types/cli/electrum-tls-config.d.ts +12 -0
- package/dist/types/cli/types.d.ts +9 -1
- package/dist/types/electrum/index.d.ts +18 -4
- package/dist/types/lightning/chain/chain-monitor.d.ts +4 -0
- package/dist/types/lightning/chain/chain-watcher.d.ts +7 -0
- package/dist/types/lightning/channel/channel-manager.d.ts +5 -0
- package/dist/types/lightning/channel/channel.d.ts +3 -0
- package/dist/types/lightning/channel/htlc-snapshots.d.ts +5 -0
- package/dist/types/lightning/direct-funding/receiver/engine.d.ts +5 -0
- package/dist/types/lightning/direct-funding/receiver/index.d.ts +2 -2
- package/dist/types/lightning/direct-funding/receiver/types.d.ts +10 -0
- package/dist/types/lightning/direct-funding/receiver/verify.d.ts +12 -0
- package/dist/types/lightning/gossip/network-graph.d.ts +7 -1
- package/dist/types/lightning/gossip/pathfinding.d.ts +5 -4
- package/dist/types/lightning/gossip/types.d.ts +6 -0
- package/dist/types/lightning/node/lightning-node.d.ts +6 -3
- package/dist/types/lightning/recovery/frame-codec.d.ts +1 -1
- package/dist/types/lightning/recovery/journal.d.ts +0 -3
- package/dist/types/lightning/recovery/recovery-manager.d.ts +1 -0
- package/dist/types/lightning/recovery/types.d.ts +1 -1
- package/dist/types/lightning/storage/serialization.d.ts +4 -1
- package/dist/types/lightning/storage/sqlite-storage.d.ts +13 -2
- package/dist/types/lightning/storage/types.d.ts +5 -0
- package/dist/types/lightning/transport/peer-manager.d.ts +3 -0
- package/dist/types/transaction/index.d.ts +10 -6
- package/dist/types/transaction.js.map +1 -1
- package/dist/types/types/transaction.d.ts +1 -0
- package/dist/types/types/wallet.d.ts +24 -1
- package/dist/types/utils/boost.d.ts +4 -0
- package/dist/types/utils/derive-path-cached.d.ts +2 -0
- package/dist/types/utils/index.d.ts +1 -0
- package/dist/types/utils/multisig.d.ts +5 -0
- package/dist/types/utils/node-version.d.ts +3 -0
- package/dist/types/utils/tls-verification.d.ts +3 -1
- package/dist/types/utils/wallet.d.ts +5 -2
- package/dist/types/wallet/constants.d.ts +2 -0
- package/dist/types/wallet/index.d.ts +45 -14
- package/dist/types/wallet.js.map +1 -1
- package/dist/utils/boost.js +12 -0
- package/dist/utils/boost.js.map +1 -0
- package/dist/utils/derive-path-cached.js +31 -0
- package/dist/utils/derive-path-cached.js.map +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/multisig.js +16 -5
- package/dist/utils/multisig.js.map +1 -1
- package/dist/utils/node-version.js +40 -0
- package/dist/utils/node-version.js.map +1 -0
- package/dist/utils/tls-verification.js +12 -5
- package/dist/utils/tls-verification.js.map +1 -1
- package/dist/utils/wallet.js +18 -2
- package/dist/utils/wallet.js.map +1 -1
- package/dist/wallet/constants.js +3 -1
- package/dist/wallet/constants.js.map +1 -1
- package/dist/wallet/index.js +715 -335
- package/dist/wallet/index.js.map +1 -1
- package/docs/AI_AGENT_GUIDE.md +2 -0
- package/docs/RECOVERY-PROTOCOL.md +2 -0
- package/docs/SPLICE-LOCK-DEPTH.md +12 -1
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Two layers, one mnemonic:
|
|
|
7
7
|
- **On-chain wallet:** HD keys, address generation, UTXO tracking, transaction building, PSBT/hardware signing, multisig, watch-only, Electrum connectivity.
|
|
8
8
|
- **Lightning:** channel lifecycle, onion-routed payments, BOLT 11 invoices, BOLT 12 offers, gossip and pathfinding, anchors, splicing, taproot channels, watchtower client. Interop-tested against LND, Core Lightning and Eclair on regtest.
|
|
9
9
|
|
|
10
|
-
Requires **Node.js
|
|
10
|
+
Requires **Node.js 22.23.4+, 24.22.1+ or 26.12.1+**. Earlier releases on those lines, and all of Node.js 18 and 20, lack the October 21, 2026 Node.js security fixes; the daemon warns at startup when it runs on one. MIT licensed.
|
|
11
11
|
|
|
12
12
|
**Jump to:** [Install](#install) · [Examples](#try-the-examples) · [On-chain wallet](#on-chain-wallet) · [Lightning](#lightning) · [Daemon & CLI](#http-daemon--cli) · [Protocol layer](#protocol-layer-advanced) · [Tests](#tests) · [Status & limitations](#status--limitations)
|
|
13
13
|
|
|
@@ -52,16 +52,16 @@ npm install
|
|
|
52
52
|
npm run example
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
Creates a
|
|
55
|
+
Creates a regtest wallet (a fresh mnemonic unless you pass one), syncs it against a public Electrum server, prints the balance and a receive address, then drops you at a `>` prompt with the wallet bound to `wallet`. Type `help()` for the command list.
|
|
56
56
|
|
|
57
57
|
```js
|
|
58
58
|
> wallet.getBalance()
|
|
59
59
|
> await wallet.getAddress()
|
|
60
60
|
> await wallet.refreshWallet()
|
|
61
|
-
> await wallet.send({ address: '
|
|
61
|
+
> await wallet.send({ address: 'bcrt1q...', amount: 10000, satsPerByte: 2 })
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
State persists as JSON under `example/walletData/`. Pass a mnemonic
|
|
64
|
+
State persists as JSON under `example/walletData/`. Pass a mnemonic to reuse a wallet: `npm run example -- "abandon abandon ... about"`. Pass `testnet` or `mainnet` to change the network.
|
|
65
65
|
|
|
66
66
|
### 2. Lightning node REPL
|
|
67
67
|
|
|
@@ -69,7 +69,7 @@ State persists as JSON under `example/walletData/`. Pass a mnemonic as the first
|
|
|
69
69
|
npm run example:lightning
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
Boots a real Lightning node (`BeignetNode`) with an auto-created wallet, storage and funding provider, waits for it to become operational, prints info/balance/health, and drops you at a `beignet>` prompt with the node bound to `node`. Type `help()` for the command list. Top-level `await` works.
|
|
72
|
+
Boots a real regtest Lightning node (`BeignetNode`) with an auto-created wallet, storage and funding provider, waits for it to become operational, prints info/balance/health, and drops you at a `beignet>` prompt with the node bound to `node`. Type `help()` for the command list. Top-level `await` works.
|
|
73
73
|
|
|
74
74
|
```js
|
|
75
75
|
beignet> await node.getNewAddress() // fund this on-chain, then:
|
|
@@ -83,7 +83,7 @@ The flags you will actually reach for (everything after `--`):
|
|
|
83
83
|
|
|
84
84
|
| Flag | Effect |
|
|
85
85
|
|------|--------|
|
|
86
|
-
| `mainnet` \| `testnet` \| `regtest` | Network, as a bare positional arg (default `
|
|
86
|
+
| `mainnet` \| `testnet` \| `regtest` | Network, as a bare positional arg (default `regtest`) |
|
|
87
87
|
| `<12 or 24 words>` | Reuse a mnemonic, as bare positional args (default generates one) |
|
|
88
88
|
| `--electrum-host <h>` `--electrum-port <p>` | Point at your own Electrum server |
|
|
89
89
|
| `--alias <name>` | Node alias in `node_announcement` |
|
|
@@ -93,6 +93,8 @@ The flags you will actually reach for (everything after `--`):
|
|
|
93
93
|
npm run example:lightning -- regtest --electrum-host 127.0.0.1 --electrum-port 60001 --alias mynode
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
+
Both examples print the network and the mnemonic before anything else. A generated mnemonic exists only in that output, so write it down before funding the wallet, and pass your own on mainnet.
|
|
97
|
+
|
|
96
98
|
Tor, full-graph gossip, the low-level `LightningNode` variant and the non-interactive payment-API walkthrough have flags too: see [the flag reference](example/REPL_TESTING.md#repl-flags).
|
|
97
99
|
|
|
98
100
|
Node state lives in a SQLite DB under `~/.beignet/data/<hash-of-mnemonic>/` (the `--low-level` example uses `example/lightningData/node.db`).
|
|
@@ -160,7 +162,7 @@ const res = await Wallet.create({
|
|
|
160
162
|
```
|
|
161
163
|
|
|
162
164
|
- **Failover:** with multiple servers the wallet rotates through them in order on connect/reconnect failure, then through hardcoded fallback peers for the network, with a per-server cooldown so dead servers are not hammered. Inspect `wallet.electrum.currentServer` and `wallet.electrum.rotationCount`.
|
|
163
|
-
- **Certificate verification:** by default a TLS Electrum connection is encrypted but the server certificate is not checked, because the client library dials with `rejectUnauthorized: false`. An on-path attacker can therefore stand in for the server. On Node, pass `tls: withTlsVerification(tls)` to accept only certificates that chain to a trusted CA and match the host, and add `{ fingerprints: ['AB:CD:…'] }` to also accept self-signed servers by SHA-256 fingerprint (`openssl x509 -noout -fingerprint -sha256`). The
|
|
165
|
+
- **Certificate verification:** by default a TLS Electrum connection is encrypted but the server certificate is not checked, because the client library dials with `rejectUnauthorized: false`. An on-path attacker can therefore stand in for the server. On Node, pass `tls: withTlsVerification(tls)` to accept only certificates that chain to a trusted CA and match the host, and add `{ fingerprints: ['AB:CD:…'] }` to also accept self-signed servers by SHA-256 fingerprint (`openssl x509 -noout -fingerprint -sha256`). A caller that resolves the host itself and dials the address passes `{ servernames: { [address]: hostName } }` so the check still uses the name. The client library keeps one connection per network for the whole process, shared by every wallet on that network, so wallets in one process should all pass the same `tls`. The daemon verifies when `BEIGNET_ELECTRUM_TLS_VERIFY=true` (see `src/cli/README.md`); it is off by default. React Native does not verify yet.
|
|
164
166
|
- **Fee source:** `'electrum'` queries only the connected server via `blockchain.estimatefee`, so fee lookups never leak to mempool.space/blocktank over clearnet. `'auto'` prefers Electrum and falls back to HTTP. All remote rates are clamped to 5000 sat/vB.
|
|
165
167
|
- **Networks:** mainnet, testnet, regtest and signet work end to end (wallet, Electrum, CLI/daemon `--network signet`, Lightning chain hash and `tbs` invoice prefix). Signet shares testnet address formats and coin type 1.
|
|
166
168
|
- **BIP21:** `encodeBip21({ address, amountSats?, label?, message? })` builds a `bitcoin:` URI.
|
|
@@ -291,6 +293,8 @@ coordinator.exportDescriptors();
|
|
|
291
293
|
|
|
292
294
|
The wallet persists through the host-injected `TStorage` interface (`storage: { getData, setData }`), and values are handed over as-is, so by default they are stored in plaintext. Persisted data is addresses, indexes, UTXOs, transactions, balance and fee estimates: no private keys and no mnemonic are ever written, so exposure is a privacy concern (full wallet history), not fund loss. The staged send (`transaction`) is written without signing keys, so a key pair handed to `sweepPrivateKey` or `addExternalInputs` never reaches storage, and `send`, `sendMany`, `sendMax`, `buildPsbt` and `sweepPrivateKey` reset the staged send when they return, so a restart never replays an earlier call's recipients.
|
|
293
295
|
|
|
296
|
+
`getData` must return `ok(undefined)` for a key it does not hold and `err` only when the read fails. `Wallet.create` returns an error on a failed read rather than start from defaults and save them over the data it could not read; pass `resetOnReadFailure: true` to start from defaults anyway.
|
|
297
|
+
|
|
294
298
|
Wrap any `TStorage` with `createEncryptedStorage` to encrypt at rest with AES-256-GCM under an HKDF-derived key from the seed. Pre-existing plaintext values pass through unchanged and migrate lazily as they are rewritten.
|
|
295
299
|
|
|
296
300
|
```typescript
|
|
@@ -403,6 +407,7 @@ Automatic modes, opt-in via `BeignetNodeOptions` / `INodeConfig`:
|
|
|
403
407
|
```typescript
|
|
404
408
|
const node = await BeignetNode.create({
|
|
405
409
|
mnemonic,
|
|
410
|
+
network: 'mainnet',
|
|
406
411
|
// Periodically executes the rebalance plan. Routing fees spent on rebalances
|
|
407
412
|
// are capped per UTC day and the running spend is persisted, so restarts
|
|
408
413
|
// never overspend the same day. Resets at midnight UTC.
|
|
@@ -428,6 +433,7 @@ Penalty enforcement normally needs this node's chain monitor to be online: if a
|
|
|
428
433
|
```typescript
|
|
429
434
|
const node = await BeignetNode.create({
|
|
430
435
|
mnemonic,
|
|
436
|
+
network: 'mainnet',
|
|
431
437
|
watchtowers: ['03abc...@tower.example.com:9911'] // off when empty
|
|
432
438
|
});
|
|
433
439
|
```
|
|
@@ -670,9 +676,8 @@ LightningNode High-level API (EventEmitter)
|
|
|
670
676
|
|
|
671
677
|
## Tests
|
|
672
678
|
|
|
673
|
-
Use **Node.js
|
|
674
|
-
|
|
675
|
-
CI uses Node.js 20.
|
|
679
|
+
Use **Node.js 24 (24.22.1+)** for development and `npm ci` to install the locked tools.
|
|
680
|
+
CI uses Node.js 24.22.1.
|
|
676
681
|
|
|
677
682
|
The lint configuration keeps the established CommonJS imports, enum aliases,
|
|
678
683
|
unused catch bindings, `any` warnings and Chai assertion style. Rules removed
|
package/dist/cli/beignet-node.js
CHANGED
|
@@ -25,13 +25,13 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.BeignetNode = exports.jitInvoiceError = exports.holdInvoiceEvent = exports.jsonSafeEvent = exports.jitReceiveRefusal = exports.leaseRatesRefusal = exports.defaultMaxFeeMsat = exports.DEFAULT_MAX_FEE_FLOOR_SATS = exports.DEFAULT_MAX_FEE_PPM = exports.clampDirectFundingMinimum = exports.DAILY_SPEND_STATE_KEY = exports.MAX_ASYNC_SPEND_CLAIMS = exports.ASYNC_SPEND_CLAIM_TTL_MS = exports.jsonToRouteHops = exports.routeHopsToJson = exports.spliceRefusalError = exports.decodeOfferInput = exports.paymentAdmissionSats = exports.paymentSpendSats = exports.hopFeeMsat = exports.spendLimitSats = exports.decodeInvoiceInput = exports.ENGINE_PAYMENT_ERROR_CODES = exports.parseScid = exports.formatScid = exports.gossipPrimeLatch = exports.defaultDataDirForMnemonic = exports.parseRecoveryMode = void 0;
|
|
27
27
|
const iroh_config_1 = require("./iroh-config");
|
|
28
|
+
const electrum_tls_config_1 = require("./electrum-tls-config");
|
|
28
29
|
const iroh_node_1 = require("../lightning/transport/iroh-node");
|
|
29
30
|
const offline_receive_1 = require("./offline-receive");
|
|
30
31
|
const ffor_receive_1 = require("./ffor-receive");
|
|
31
32
|
const path = __importStar(require("path"));
|
|
32
33
|
const fs = __importStar(require("fs"));
|
|
33
34
|
const net = __importStar(require("net"));
|
|
34
|
-
const tls = __importStar(require("tls"));
|
|
35
35
|
const dns_1 = require("dns");
|
|
36
36
|
const instance_lock_1 = require("./instance-lock");
|
|
37
37
|
const crypto = __importStar(require("crypto"));
|
|
@@ -41,6 +41,7 @@ const wallet_2 = require("../shapes/wallet");
|
|
|
41
41
|
const logger_1 = require("../logger");
|
|
42
42
|
const helpers_1 = require("../utils/helpers");
|
|
43
43
|
const conversion_1 = require("../utils/conversion");
|
|
44
|
+
const boost_1 = require("../utils/boost");
|
|
44
45
|
const wallet_3 = require("../types/wallet");
|
|
45
46
|
const wallet_storage_1 = require("./wallet-storage");
|
|
46
47
|
const onchain_sweep_1 = require("./onchain-sweep");
|
|
@@ -347,6 +348,10 @@ const nextUtcMidnight = () => {
|
|
|
347
348
|
};
|
|
348
349
|
const MAX_DIRECT_FUNDING_CHARGES = 1024;
|
|
349
350
|
const DEFAULT_L402_MAX_RESPONSE_BYTES = 5 * 1024 * 1024;
|
|
351
|
+
const NETWORK_NAMES = ['mainnet', 'testnet', 'signet', 'regtest'];
|
|
352
|
+
function unknownNetwork(network) {
|
|
353
|
+
throw new errors_1.BeignetError('INVALID_PARAMS', `unknown network '${String(network)}'`);
|
|
354
|
+
}
|
|
350
355
|
const DEFAULT_ELECTRUM = {
|
|
351
356
|
mainnet: { host: 'fulcrum.bitkit.blocktank.to', port: 8900, useTls: true },
|
|
352
357
|
testnet: { host: 'electrum.blockstream.info', port: 60002, useTls: true },
|
|
@@ -764,12 +769,25 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
764
769
|
static async create(opts = {}) {
|
|
765
770
|
try {
|
|
766
771
|
(0, iroh_config_1.validateIrohConfig)(opts);
|
|
772
|
+
(0, electrum_tls_config_1.validateElectrumTlsConfig)(opts);
|
|
767
773
|
}
|
|
768
774
|
catch (err) {
|
|
769
775
|
throw new errors_1.BeignetError('INVALID_PARAMS', err.message);
|
|
770
776
|
}
|
|
777
|
+
if (!opts.network) {
|
|
778
|
+
throw new errors_1.BeignetError('INVALID_PARAMS', "network is required: 'mainnet', 'testnet', 'signet' or 'regtest'");
|
|
779
|
+
}
|
|
780
|
+
if (!NETWORK_NAMES.includes(opts.network)) {
|
|
781
|
+
throw new errors_1.BeignetError('INVALID_PARAMS', `unknown network '${opts.network}': expected 'mainnet', 'testnet', 'signet' or 'regtest'`);
|
|
782
|
+
}
|
|
771
783
|
const mnemonic = opts.mnemonic || (0, helpers_1.generateMnemonic)();
|
|
772
|
-
const networkName = opts.network
|
|
784
|
+
const networkName = opts.network;
|
|
785
|
+
try {
|
|
786
|
+
(0, electrum_tls_config_1.checkElectrumTls)(networkName, opts);
|
|
787
|
+
}
|
|
788
|
+
catch (err) {
|
|
789
|
+
throw new errors_1.BeignetError('INVALID_PARAMS', err.message);
|
|
790
|
+
}
|
|
773
791
|
const dataDir = opts.dataDir || defaultDataDirForMnemonic(mnemonic);
|
|
774
792
|
const dirMode = (0, fs_utils_1.ensurePrivateDir)(dataDir);
|
|
775
793
|
const instance = new BeignetNode(mnemonic, networkName, dataDir);
|
|
@@ -973,6 +991,24 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
973
991
|
ipv4: electrumHost
|
|
974
992
|
});
|
|
975
993
|
}
|
|
994
|
+
const walletTls = (0, electrum_tls_config_1.electrumTlsModule)(opts, electrumHost, rawElectrumHost);
|
|
995
|
+
try {
|
|
996
|
+
(0, electrum_tls_config_1.claimElectrumTls)(this, networkName, opts);
|
|
997
|
+
}
|
|
998
|
+
catch (err) {
|
|
999
|
+
throw new errors_1.BeignetError('INVALID_PARAMS', err.message);
|
|
1000
|
+
}
|
|
1001
|
+
if (opts.electrumTlsVerify === true) {
|
|
1002
|
+
const pinnedFingerprints = opts.electrumTlsFingerprints?.length ?? 0;
|
|
1003
|
+
this.log('info', 'Verifying Electrum TLS certificates', {
|
|
1004
|
+
pinnedFingerprints
|
|
1005
|
+
});
|
|
1006
|
+
if (!electrumTls) {
|
|
1007
|
+
this.log('warn', 'The configured Electrum server is plain TCP, so its certificate is ' +
|
|
1008
|
+
'never checked and pinned fingerprints are not used for it; only ' +
|
|
1009
|
+
'the TLS fallback servers are verified', { host: rawElectrumHost, port: electrumPort, pinnedFingerprints });
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
976
1012
|
const beignetNetwork = this.toBeignetNetwork(networkName);
|
|
977
1013
|
const lnNetwork = this.toLnNetwork(networkName);
|
|
978
1014
|
const coinType = this.toCoinType(networkName);
|
|
@@ -996,7 +1032,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
996
1032
|
: {}),
|
|
997
1033
|
electrumOptions: {
|
|
998
1034
|
net,
|
|
999
|
-
tls,
|
|
1035
|
+
tls: walletTls,
|
|
1000
1036
|
servers: electrumServer
|
|
1001
1037
|
},
|
|
1002
1038
|
disableMessagesOnCreate: true,
|
|
@@ -1006,6 +1042,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
1006
1042
|
storage: (0, wallet_storage_1.createWalletStorage)(this.storage)
|
|
1007
1043
|
});
|
|
1008
1044
|
if (walletResult.isErr()) {
|
|
1045
|
+
(0, electrum_tls_config_1.releaseElectrumTls)(this);
|
|
1009
1046
|
throw new errors_1.BeignetError('WALLET_CREATE_FAILED', walletResult.error.message);
|
|
1010
1047
|
}
|
|
1011
1048
|
this.wallet = walletResult.value;
|
|
@@ -3488,12 +3525,15 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
3488
3525
|
this._onchainSendLock = run.catch(() => undefined);
|
|
3489
3526
|
return run;
|
|
3490
3527
|
}
|
|
3528
|
+
_runWalletSend(fn) {
|
|
3529
|
+
return this._runOnchainSend(() => this.wallet.withSendLock(fn));
|
|
3530
|
+
}
|
|
3491
3531
|
async sendOnchain(address, amountSats, satsPerVbyte) {
|
|
3492
3532
|
this._checkMaxPayment(amountSats);
|
|
3493
3533
|
this._checkSpendLimit(amountSats);
|
|
3494
|
-
return this.
|
|
3534
|
+
return this._runWalletSend(async (locked) => {
|
|
3495
3535
|
try {
|
|
3496
|
-
const result = await
|
|
3536
|
+
const result = await locked.send({
|
|
3497
3537
|
address,
|
|
3498
3538
|
amount: amountSats,
|
|
3499
3539
|
broadcast: false,
|
|
@@ -3541,9 +3581,9 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
3541
3581
|
}
|
|
3542
3582
|
}
|
|
3543
3583
|
this._validateFeeRate(satsPerVbyte);
|
|
3544
|
-
return this.
|
|
3584
|
+
return this._runWalletSend(async (locked) => {
|
|
3545
3585
|
try {
|
|
3546
|
-
const result = await
|
|
3586
|
+
const result = await locked.buildPsbt({
|
|
3547
3587
|
txs: outputs.map((o) => ({
|
|
3548
3588
|
address: o.address,
|
|
3549
3589
|
amount: o.amountSats
|
|
@@ -3740,9 +3780,9 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
3740
3780
|
throw new errors_1.BeignetError(errors_1.BeignetErrorCode.INVALID_PARAMS, `Invalid ${this.networkName} address: ${address}`);
|
|
3741
3781
|
}
|
|
3742
3782
|
this._validateFeeRate(satsPerVbyte);
|
|
3743
|
-
return this.
|
|
3783
|
+
return this._runWalletSend(async (locked) => {
|
|
3744
3784
|
try {
|
|
3745
|
-
const result = await
|
|
3785
|
+
const result = await locked.sendMax({
|
|
3746
3786
|
address,
|
|
3747
3787
|
satsPerByte: satsPerVbyte ?? this.wallet.feeEstimates.normal,
|
|
3748
3788
|
rbf: this.wallet.rbf,
|
|
@@ -3814,7 +3854,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
3814
3854
|
});
|
|
3815
3855
|
}
|
|
3816
3856
|
prepareOnchainSweep(request) {
|
|
3817
|
-
return this.
|
|
3857
|
+
return this._runWalletSend(() => this.onchainSweeps().prepare(request));
|
|
3818
3858
|
}
|
|
3819
3859
|
submitOnchainSweep(requestId) {
|
|
3820
3860
|
return this._runOnchainSend(() => this.onchainSweeps().submit(requestId));
|
|
@@ -3834,7 +3874,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
3834
3874
|
? `Transaction ${txid} cannot be replaced via RBF; use POST /tx/boost (CPFP) instead`
|
|
3835
3875
|
: `Transaction ${txid} is not boostable (unknown, already confirmed, or balance too low)`);
|
|
3836
3876
|
}
|
|
3837
|
-
return this.
|
|
3877
|
+
return this._boost(txid, wallet_3.EBoostType.rbf, satsPerVbyte);
|
|
3838
3878
|
}
|
|
3839
3879
|
async boostOnchain(txid, satsPerVbyte) {
|
|
3840
3880
|
this._validateTxid(txid);
|
|
@@ -3845,7 +3885,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
3845
3885
|
}
|
|
3846
3886
|
if (can.rbf) {
|
|
3847
3887
|
try {
|
|
3848
|
-
return await this.
|
|
3888
|
+
return await this._boost(txid, wallet_3.EBoostType.rbf, satsPerVbyte);
|
|
3849
3889
|
}
|
|
3850
3890
|
catch (e) {
|
|
3851
3891
|
const rbfImpossible = e instanceof errors_1.BeignetError &&
|
|
@@ -3854,94 +3894,34 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
3854
3894
|
throw e;
|
|
3855
3895
|
}
|
|
3856
3896
|
}
|
|
3857
|
-
return this.
|
|
3858
|
-
}
|
|
3859
|
-
async _boostRbf(txid, satsPerVbyte) {
|
|
3860
|
-
return this._runOnchainSend(async () => {
|
|
3861
|
-
const setup = await this.wallet.transaction.setupRbf({ txid });
|
|
3862
|
-
if (setup.isErr()) {
|
|
3863
|
-
await this.wallet.resetSendTransaction();
|
|
3864
|
-
throw new errors_1.BeignetError(errors_1.BeignetErrorCode.NOT_BOOSTABLE, setup.error.message);
|
|
3865
|
-
}
|
|
3866
|
-
try {
|
|
3867
|
-
if (satsPerVbyte !== undefined) {
|
|
3868
|
-
const feeRes = this.wallet.transaction.updateFee({
|
|
3869
|
-
satsPerByte: satsPerVbyte
|
|
3870
|
-
});
|
|
3871
|
-
if (feeRes.isErr()) {
|
|
3872
|
-
throw new errors_1.BeignetError(errors_1.BeignetErrorCode.INVALID_PARAMS, feeRes.error.message);
|
|
3873
|
-
}
|
|
3874
|
-
}
|
|
3875
|
-
const original = this.wallet.unconfirmedTransactions[txid] ??
|
|
3876
|
-
this.wallet.transactions[txid];
|
|
3877
|
-
const originalFeeSats = original ? (0, conversion_1.btcToSats)(original.fee) : 0;
|
|
3878
|
-
const newFeeSats = this.wallet.transaction.data.fee;
|
|
3879
|
-
if (newFeeSats <= originalFeeSats) {
|
|
3880
|
-
throw new errors_1.BeignetError(errors_1.BeignetErrorCode.INVALID_PARAMS, `Replacement fee ${newFeeSats} sats does not exceed the original fee ${originalFeeSats} sats; raise satsPerVbyte`);
|
|
3881
|
-
}
|
|
3882
|
-
const createRes = await this.wallet.transaction.createTransaction();
|
|
3883
|
-
if (createRes.isErr()) {
|
|
3884
|
-
throw new errors_1.BeignetError('SEND_FAILED', createRes.error.message);
|
|
3885
|
-
}
|
|
3886
|
-
const info = await this._broadcastRawTx(createRes.value.hex);
|
|
3887
|
-
await this._recordBoost(txid, info.txid, wallet_3.EBoostType.rbf, newFeeSats);
|
|
3888
|
-
return {
|
|
3889
|
-
...info,
|
|
3890
|
-
boostType: 'rbf',
|
|
3891
|
-
feeSats: newFeeSats,
|
|
3892
|
-
originalTxid: txid
|
|
3893
|
-
};
|
|
3894
|
-
}
|
|
3895
|
-
finally {
|
|
3896
|
-
await this.wallet.resetSendTransaction();
|
|
3897
|
-
}
|
|
3898
|
-
});
|
|
3897
|
+
return this._boost(txid, wallet_3.EBoostType.cpfp, satsPerVbyte);
|
|
3899
3898
|
}
|
|
3900
|
-
|
|
3899
|
+
_boost(txid, type, satsPerVbyte) {
|
|
3901
3900
|
return this._runOnchainSend(async () => {
|
|
3902
|
-
const
|
|
3901
|
+
const res = await this.wallet.boost({
|
|
3903
3902
|
txid,
|
|
3903
|
+
type,
|
|
3904
3904
|
...(satsPerVbyte !== undefined ? { satsPerByte: satsPerVbyte } : {})
|
|
3905
3905
|
});
|
|
3906
|
-
if (
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
}
|
|
3916
|
-
const info = await this._broadcastRawTx(createRes.value.hex);
|
|
3917
|
-
await this._recordBoost(txid, info.txid, wallet_3.EBoostType.cpfp, feeSats);
|
|
3918
|
-
return {
|
|
3919
|
-
...info,
|
|
3920
|
-
boostType: 'cpfp',
|
|
3921
|
-
feeSats,
|
|
3922
|
-
originalTxid: txid
|
|
3923
|
-
};
|
|
3924
|
-
}
|
|
3925
|
-
finally {
|
|
3926
|
-
await this.wallet.resetSendTransaction();
|
|
3906
|
+
if (res.isErr()) {
|
|
3907
|
+
const code = res.error instanceof boost_1.BoostError
|
|
3908
|
+
? {
|
|
3909
|
+
NOT_BOOSTABLE: errors_1.BeignetErrorCode.NOT_BOOSTABLE,
|
|
3910
|
+
INVALID_FEE: errors_1.BeignetErrorCode.INVALID_PARAMS,
|
|
3911
|
+
SEND_FAILED: errors_1.BeignetErrorCode.SEND_FAILED
|
|
3912
|
+
}[res.error.code]
|
|
3913
|
+
: errors_1.BeignetErrorCode.SEND_FAILED;
|
|
3914
|
+
throw new errors_1.BeignetError(code, res.error.message);
|
|
3927
3915
|
}
|
|
3916
|
+
return {
|
|
3917
|
+
txid: res.value.id,
|
|
3918
|
+
hex: res.value.hex,
|
|
3919
|
+
boostType: type === wallet_3.EBoostType.rbf ? 'rbf' : 'cpfp',
|
|
3920
|
+
feeSats: res.value.fee,
|
|
3921
|
+
originalTxid: txid
|
|
3922
|
+
};
|
|
3928
3923
|
});
|
|
3929
3924
|
}
|
|
3930
|
-
async _recordBoost(oldTxId, newTxId, type, fee) {
|
|
3931
|
-
const res = await this.wallet.addBoostedTransaction({
|
|
3932
|
-
oldTxId,
|
|
3933
|
-
newTxId,
|
|
3934
|
-
type,
|
|
3935
|
-
fee
|
|
3936
|
-
});
|
|
3937
|
-
if (res.isErr()) {
|
|
3938
|
-
this.log('warn', 'Failed to record boosted transaction', {
|
|
3939
|
-
oldTxId,
|
|
3940
|
-
newTxId,
|
|
3941
|
-
error: res.error.message
|
|
3942
|
-
});
|
|
3943
|
-
}
|
|
3944
|
-
}
|
|
3945
3925
|
listBoostableTransactions() {
|
|
3946
3926
|
const { rbf, cpfp } = this.wallet.getBoostableTransactions();
|
|
3947
3927
|
return {
|
|
@@ -3958,9 +3938,9 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
3958
3938
|
throw new errors_1.BeignetError(errors_1.BeignetErrorCode.NOTHING_TO_CONSOLIDATE, `Nothing to consolidate: wallet has ${utxoCount} spendable UTXO(s), need at least 2`);
|
|
3959
3939
|
}
|
|
3960
3940
|
const address = await this.getNewAddress();
|
|
3961
|
-
return this.
|
|
3941
|
+
return this._runWalletSend(async (locked) => {
|
|
3962
3942
|
try {
|
|
3963
|
-
const result = await
|
|
3943
|
+
const result = await locked.sendMax({
|
|
3964
3944
|
address,
|
|
3965
3945
|
satsPerByte: satsPerVbyte ?? this.wallet.feeEstimates.normal,
|
|
3966
3946
|
rbf: this.wallet.rbf,
|
|
@@ -3992,6 +3972,15 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
3992
3972
|
this.emit('onchain:rbf', { txids: data });
|
|
3993
3973
|
return;
|
|
3994
3974
|
}
|
|
3975
|
+
if (key === 'storageWriteFailed') {
|
|
3976
|
+
const failure = data;
|
|
3977
|
+
this.log('error', 'Wallet storage write failed', {
|
|
3978
|
+
key: failure.key,
|
|
3979
|
+
storageKey: failure.storageKey,
|
|
3980
|
+
error: failure.error
|
|
3981
|
+
});
|
|
3982
|
+
return;
|
|
3983
|
+
}
|
|
3995
3984
|
const relayed = {
|
|
3996
3985
|
transactionReceived: {
|
|
3997
3986
|
event: 'transaction:received',
|
|
@@ -4412,10 +4401,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
4412
4401
|
return this.raceWithTimeout(this.resolveCurrentWalletAddressScript().catch(() => undefined), this._closeAddressLookupTimeoutMs);
|
|
4413
4402
|
}
|
|
4414
4403
|
fforChannelId(channelId) {
|
|
4415
|
-
|
|
4416
|
-
throw new errors_1.BeignetError('INVALID_PARAMS', 'channelId must be 64 hex characters');
|
|
4417
|
-
}
|
|
4418
|
-
const idBuf = Buffer.from(channelId, 'hex');
|
|
4404
|
+
const idBuf = requireChannelIdHex(channelId);
|
|
4419
4405
|
if (!this.node.getChannel(idBuf)) {
|
|
4420
4406
|
throw new errors_1.BeignetError(errors_1.BeignetErrorCode.CHANNEL_NOT_FOUND, `Channel not found: ${idBuf.toString('hex')}`);
|
|
4421
4407
|
}
|
|
@@ -4747,6 +4733,9 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
4747
4733
|
}
|
|
4748
4734
|
throw err;
|
|
4749
4735
|
});
|
|
4736
|
+
if (r.action === 'force-close-refused') {
|
|
4737
|
+
throw new errors_1.BeignetError(errors_1.BeignetErrorCode.FORCE_CLOSE_FAILED, r.error ?? 'Force close failed');
|
|
4738
|
+
}
|
|
4750
4739
|
return {
|
|
4751
4740
|
action: r.action,
|
|
4752
4741
|
preimagesKnown: r.preimagesKnown,
|
|
@@ -4857,10 +4846,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
4857
4846
|
};
|
|
4858
4847
|
}
|
|
4859
4848
|
forceCloseChannel(channelId, acceptStaleStateRisk = false) {
|
|
4860
|
-
|
|
4861
|
-
throw new errors_1.BeignetError('INVALID_PARAMS', 'channelId must be 64 hex characters');
|
|
4862
|
-
}
|
|
4863
|
-
const idBuf = Buffer.from(channelId, 'hex');
|
|
4849
|
+
const idBuf = requireChannelIdHex(channelId);
|
|
4864
4850
|
if (!this.node.getChannel(idBuf)) {
|
|
4865
4851
|
throw new errors_1.BeignetError(errors_1.BeignetErrorCode.CHANNEL_NOT_FOUND, `Channel not found: ${idBuf.toString('hex')}`);
|
|
4866
4852
|
}
|
|
@@ -4921,23 +4907,23 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
4921
4907
|
: REESTABLISH_FORCE_CLOSE_REFUSAL);
|
|
4922
4908
|
}
|
|
4923
4909
|
}
|
|
4924
|
-
rebroadcastClose(channelId) {
|
|
4925
|
-
return this.node.rebroadcastClose(
|
|
4910
|
+
async rebroadcastClose(channelId) {
|
|
4911
|
+
return this.node.rebroadcastClose(requireChannelIdHex(channelId));
|
|
4926
4912
|
}
|
|
4927
4913
|
listChannels() {
|
|
4928
4914
|
return this.node.listChannels().map((ch) => this.toChannelInfo(ch));
|
|
4929
4915
|
}
|
|
4930
4916
|
getChannel(channelId) {
|
|
4931
|
-
const ch = this.node.getChannel(
|
|
4917
|
+
const ch = this.node.getChannel(requireChannelIdHex(channelId));
|
|
4932
4918
|
if (!ch)
|
|
4933
4919
|
return null;
|
|
4934
4920
|
return this.toChannelInfo(ch);
|
|
4935
4921
|
}
|
|
4936
4922
|
getChannelHealth(channelId) {
|
|
4937
|
-
return this.node.getChannelHealth(
|
|
4923
|
+
return this.node.getChannelHealth(requireChannelIdHex(channelId));
|
|
4938
4924
|
}
|
|
4939
4925
|
getChannelDiagnostics(channelId) {
|
|
4940
|
-
const channelIdBuf =
|
|
4926
|
+
const channelIdBuf = requireChannelIdHex(channelId);
|
|
4941
4927
|
const channel = this.node.getChannelManager().getChannel(channelIdBuf);
|
|
4942
4928
|
if (!channel)
|
|
4943
4929
|
return null;
|
|
@@ -6958,9 +6944,15 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
6958
6944
|
return { valid: true, proof };
|
|
6959
6945
|
}
|
|
6960
6946
|
updateChannelFee(channelId, feeratePerKw) {
|
|
6961
|
-
return this.node.updateChannelFee(
|
|
6947
|
+
return this.node.updateChannelFee(requireChannelIdHex(channelId), feeratePerKw);
|
|
6962
6948
|
}
|
|
6963
6949
|
updateChannelPolicy(channelId, policy) {
|
|
6950
|
+
return this.applyChannelPolicy(requireChannelIdHex(channelId), [channelId], policy);
|
|
6951
|
+
}
|
|
6952
|
+
updateAllChannelPolicies(policy) {
|
|
6953
|
+
return this.applyChannelPolicy('all', this.node.listChannels().map((ch) => ch.channelId.toString('hex')), policy);
|
|
6954
|
+
}
|
|
6955
|
+
applyChannelPolicy(target, channelIds, policy) {
|
|
6964
6956
|
const update = {};
|
|
6965
6957
|
if (policy.feeBaseMsat !== undefined)
|
|
6966
6958
|
update.feeBaseMsat = policy.feeBaseMsat;
|
|
@@ -6972,17 +6964,14 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
6972
6964
|
update.htlcMinimumMsat = requireMsatValue(policy.htlcMinimumMsat, 'htlcMinimumMsat');
|
|
6973
6965
|
if (policy.htlcMaximumMsat !== undefined)
|
|
6974
6966
|
update.htlcMaximumMsat = requireMsatValue(policy.htlcMaximumMsat, 'htlcMaximumMsat');
|
|
6975
|
-
|
|
6976
|
-
|
|
6977
|
-
: [channelId];
|
|
6978
|
-
this.node.setChannelPolicy(channelId === 'all' ? 'all' : Buffer.from(channelId, 'hex'), update);
|
|
6979
|
-
const policies = targets
|
|
6967
|
+
this.node.setChannelPolicy(target, update);
|
|
6968
|
+
const policies = channelIds
|
|
6980
6969
|
.map((id) => this.getChannelPolicy(id))
|
|
6981
6970
|
.filter((p) => p !== null);
|
|
6982
6971
|
return { updated: policies.length, policies };
|
|
6983
6972
|
}
|
|
6984
6973
|
getChannelPolicy(channelId) {
|
|
6985
|
-
const policy = this.node.getChannelPolicy(
|
|
6974
|
+
const policy = this.node.getChannelPolicy(requireChannelIdHex(channelId));
|
|
6986
6975
|
if (!policy)
|
|
6987
6976
|
return null;
|
|
6988
6977
|
return {
|
|
@@ -7069,7 +7058,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
7069
7058
|
return info;
|
|
7070
7059
|
}
|
|
7071
7060
|
async waitForChannelReady(channelId, timeoutMs = 60000) {
|
|
7072
|
-
return this.node.waitForChannelReady(
|
|
7061
|
+
return this.node.waitForChannelReady(requireChannelIdHex(channelId), timeoutMs);
|
|
7073
7062
|
}
|
|
7074
7063
|
async waitForReady(timeoutMs = 30000) {
|
|
7075
7064
|
return this.node.waitForReady(timeoutMs);
|
|
@@ -7373,21 +7362,17 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
7373
7362
|
paid = settlesInvoice(live);
|
|
7374
7363
|
}
|
|
7375
7364
|
else {
|
|
7376
|
-
if (!durablePaid)
|
|
7377
|
-
durablePaid = this.
|
|
7365
|
+
if (!durablePaid) {
|
|
7366
|
+
durablePaid = this.storage.paymentHashesWith({
|
|
7367
|
+
status: 'COMPLETED',
|
|
7368
|
+
direction: 'INCOMING'
|
|
7369
|
+
});
|
|
7370
|
+
}
|
|
7378
7371
|
paid = durablePaid.has(inv.paymentHash);
|
|
7379
7372
|
}
|
|
7380
7373
|
return this.toInvoiceInfo(inv, paid);
|
|
7381
7374
|
});
|
|
7382
7375
|
}
|
|
7383
|
-
durablePaidHashes() {
|
|
7384
|
-
const paid = new Set();
|
|
7385
|
-
for (const { paymentHash, payment } of this.storage.loadAllPayments()) {
|
|
7386
|
-
if (settlesInvoice(payment))
|
|
7387
|
-
paid.add(paymentHash);
|
|
7388
|
-
}
|
|
7389
|
-
return paid;
|
|
7390
|
-
}
|
|
7391
7376
|
toInvoiceInfo(inv, paid) {
|
|
7392
7377
|
const info = {
|
|
7393
7378
|
bolt11: inv.bolt11,
|
|
@@ -7698,10 +7683,8 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
7698
7683
|
async rebalanceChannel(fromChannelId, toChannelId, amountSats, maxFeeSats) {
|
|
7699
7684
|
if (this.isGraphRestoring())
|
|
7700
7685
|
await this.whenGraphRestored();
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
if (!/^[0-9a-fA-F]{64}$/.test(toChannelId))
|
|
7704
|
-
throw new errors_1.BeignetError(errors_1.BeignetErrorCode.INVALID_PARAMS, 'toChannelId must be 64 hex chars');
|
|
7686
|
+
const fromIdBuf = requireChannelIdHex(fromChannelId, 'fromChannelId');
|
|
7687
|
+
const toIdBuf = requireChannelIdHex(toChannelId, 'toChannelId');
|
|
7705
7688
|
if (!Number.isInteger(amountSats) || amountSats <= 0)
|
|
7706
7689
|
throw new errors_1.BeignetError(errors_1.BeignetErrorCode.INVALID_PARAMS, 'amountSats must be a positive integer');
|
|
7707
7690
|
if (!Number.isInteger(maxFeeSats) || maxFeeSats < 0)
|
|
@@ -7717,8 +7700,8 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
7717
7700
|
let result;
|
|
7718
7701
|
try {
|
|
7719
7702
|
result = await this.node.rebalanceChannel({
|
|
7720
|
-
fromChannelId:
|
|
7721
|
-
toChannelId:
|
|
7703
|
+
fromChannelId: fromIdBuf,
|
|
7704
|
+
toChannelId: toIdBuf,
|
|
7722
7705
|
amountSats: BigInt(amountSats),
|
|
7723
7706
|
maxFeeSats: BigInt(maxFeeSats)
|
|
7724
7707
|
});
|
|
@@ -7907,13 +7890,13 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
7907
7890
|
describeGraph(limit, offset) {
|
|
7908
7891
|
const cappedLimit = Math.min(Math.max(1, Math.floor(limit ?? GRAPH_DESCRIBE_MAX_LIMIT)), GRAPH_DESCRIBE_MAX_LIMIT);
|
|
7909
7892
|
const safeOffset = Math.max(0, Math.floor(offset ?? 0));
|
|
7910
|
-
const
|
|
7893
|
+
const graph = this.node.getGraph();
|
|
7911
7894
|
return {
|
|
7912
|
-
totalChannels:
|
|
7895
|
+
totalChannels: graph.getChannelCount(),
|
|
7913
7896
|
limit: cappedLimit,
|
|
7914
7897
|
offset: safeOffset,
|
|
7915
|
-
channels:
|
|
7916
|
-
.
|
|
7898
|
+
channels: graph
|
|
7899
|
+
.getChannelPage(safeOffset, cappedLimit)
|
|
7917
7900
|
.map((ch) => this.toGraphChannelInfo(ch))
|
|
7918
7901
|
};
|
|
7919
7902
|
}
|
|
@@ -8849,7 +8832,9 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
8849
8832
|
this._nodeStorageView?.close();
|
|
8850
8833
|
this.removeAllListeners();
|
|
8851
8834
|
try {
|
|
8852
|
-
await this.wallet?.stop();
|
|
8835
|
+
const stopped = await this.wallet?.stop();
|
|
8836
|
+
if (!stopped?.isErr())
|
|
8837
|
+
(0, electrum_tls_config_1.releaseElectrumTls)(this);
|
|
8853
8838
|
}
|
|
8854
8839
|
catch {
|
|
8855
8840
|
}
|
|
@@ -8881,7 +8866,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
8881
8866
|
case 'signet':
|
|
8882
8867
|
return wallet_3.EAvailableNetworks.signet;
|
|
8883
8868
|
default:
|
|
8884
|
-
return
|
|
8869
|
+
return unknownNetwork(network);
|
|
8885
8870
|
}
|
|
8886
8871
|
}
|
|
8887
8872
|
toLnNetwork(network) {
|
|
@@ -8895,7 +8880,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
8895
8880
|
case 'signet':
|
|
8896
8881
|
return types_5.Network.SIGNET;
|
|
8897
8882
|
default:
|
|
8898
|
-
return
|
|
8883
|
+
return unknownNetwork(network);
|
|
8899
8884
|
}
|
|
8900
8885
|
}
|
|
8901
8886
|
toCoinType(network) {
|
|
@@ -8909,7 +8894,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
8909
8894
|
case 'signet':
|
|
8910
8895
|
return wallet_keys_1.LnCoinType.SIGNET;
|
|
8911
8896
|
default:
|
|
8912
|
-
return
|
|
8897
|
+
return unknownNetwork(network);
|
|
8913
8898
|
}
|
|
8914
8899
|
}
|
|
8915
8900
|
getBitcoinNetwork() {
|