beignet 0.16.0 → 0.18.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/dist/cli/beignet-node.js +152 -63
- package/dist/cli/beignet-node.js.map +1 -1
- package/dist/cli/daemon.js +18 -9
- package/dist/cli/daemon.js.map +1 -1
- package/dist/cli/errors.js +5 -1
- package/dist/cli/errors.js.map +1 -1
- package/dist/cli/openapi.js +36 -7
- package/dist/cli/openapi.js.map +1 -1
- package/dist/lightning/chain/chain-watcher.js +164 -1
- package/dist/lightning/chain/chain-watcher.js.map +1 -1
- package/dist/lightning/channel/channel-actions.js +2 -0
- package/dist/lightning/channel/channel-actions.js.map +1 -1
- package/dist/lightning/channel/channel-manager.js +62 -1
- package/dist/lightning/channel/channel-manager.js.map +1 -1
- package/dist/lightning/channel/channel-state.js +2 -0
- package/dist/lightning/channel/channel-state.js.map +1 -1
- package/dist/lightning/channel/channel.js +334 -17
- package/dist/lightning/channel/channel.js.map +1 -1
- package/dist/lightning/channel/splice.js +13 -2
- package/dist/lightning/channel/splice.js.map +1 -1
- package/dist/lightning/direct-funding/receiver/engine.js +74 -3
- package/dist/lightning/direct-funding/receiver/engine.js.map +1 -1
- package/dist/lightning/direct-funding/receiver/types.js +2 -1
- package/dist/lightning/direct-funding/receiver/types.js.map +1 -1
- package/dist/lightning/liquidity/jit-receive.js +18 -1
- package/dist/lightning/liquidity/jit-receive.js.map +1 -1
- package/dist/lightning/message/custom.js +2 -0
- package/dist/lightning/message/custom.js.map +1 -1
- package/dist/lightning/message/splice-conflict.js +76 -0
- package/dist/lightning/message/splice-conflict.js.map +1 -0
- package/dist/lightning/message/splice.js +93 -39
- package/dist/lightning/message/splice.js.map +1 -1
- package/dist/lightning/node/lightning-node.js +569 -11
- package/dist/lightning/node/lightning-node.js.map +1 -1
- package/dist/lightning/node/types.js.map +1 -1
- package/dist/lightning/storage/serialization.js +34 -2
- package/dist/lightning/storage/serialization.js.map +1 -1
- package/dist/types/cli/beignet-node.d.ts +6 -3
- package/dist/types/cli/errors.d.ts +2 -0
- package/dist/types/cli/types.d.ts +28 -0
- package/dist/types/lightning/chain/chain-watcher.d.ts +23 -0
- package/dist/types/lightning/channel/channel-actions.d.ts +14 -1
- package/dist/types/lightning/channel/channel-manager.d.ts +4 -0
- package/dist/types/lightning/channel/channel-state.d.ts +23 -0
- package/dist/types/lightning/channel/channel.d.ts +25 -1
- package/dist/types/lightning/channel/splice.d.ts +4 -0
- package/dist/types/lightning/direct-funding/receiver/engine.d.ts +8 -0
- package/dist/types/lightning/direct-funding/receiver/types.d.ts +12 -1
- package/dist/types/lightning/liquidity/jit-receive.d.ts +1 -0
- package/dist/types/lightning/message/custom.d.ts +3 -1
- package/dist/types/lightning/message/splice-conflict.d.ts +19 -0
- package/dist/types/lightning/message/splice.d.ts +5 -0
- package/dist/types/lightning/node/lightning-node.d.ts +26 -1
- package/dist/types/lightning/node/types.d.ts +8 -1
- package/dist/types/lightning/storage/serialization.d.ts +23 -0
- package/docs/AI_AGENT_GUIDE.md +2 -0
- package/docs/SPLICE-LOCK-DEPTH.md +170 -0
- package/package.json +1 -1
package/dist/cli/beignet-node.js
CHANGED
|
@@ -41,7 +41,9 @@ const wallet_3 = require("../types/wallet");
|
|
|
41
41
|
const wallet_storage_1 = require("./wallet-storage");
|
|
42
42
|
const electrum_1 = require("../types/electrum");
|
|
43
43
|
const lightning_node_1 = require("../lightning/node/lightning-node");
|
|
44
|
-
const types_1 = require("../lightning/
|
|
44
|
+
const types_1 = require("../lightning/direct-funding/receiver/types");
|
|
45
|
+
const splice_1 = require("../lightning/message/splice");
|
|
46
|
+
const types_2 = require("../lightning/ffor/types");
|
|
45
47
|
const messages_1 = require("../lightning/ffor/messages");
|
|
46
48
|
const splice_weight_1 = require("../lightning/channel/splice-weight");
|
|
47
49
|
const l402_1 = require("../lightning/l402");
|
|
@@ -52,9 +54,9 @@ const scb_1 = require("../lightning/backup/scb");
|
|
|
52
54
|
const bip39 = __importStar(require("bip39"));
|
|
53
55
|
const rapid_sync_1 = require("../lightning/gossip/rapid-sync");
|
|
54
56
|
const messages_2 = require("../lightning/gossip/messages");
|
|
55
|
-
const
|
|
57
|
+
const types_3 = require("../lightning/gossip/types");
|
|
56
58
|
const electrum_backend_1 = require("../lightning/chain/electrum-backend");
|
|
57
|
-
const
|
|
59
|
+
const types_4 = require("../lightning/invoice/types");
|
|
58
60
|
const wallet_keys_1 = require("../lightning/keys/wallet-keys");
|
|
59
61
|
const recovery_1 = require("../lightning/recovery");
|
|
60
62
|
const peer_manager_1 = require("../lightning/transport/peer-manager");
|
|
@@ -63,8 +65,8 @@ const ecdh_1 = require("../lightning/crypto/ecdh");
|
|
|
63
65
|
const direct_funding_1 = require("../lightning/direct-funding");
|
|
64
66
|
const direct_funding_2 = require("./direct-funding");
|
|
65
67
|
const auth_1 = require("./auth");
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
+
const types_5 = require("../lightning/node/types");
|
|
69
|
+
const types_6 = require("../lightning/channel/types");
|
|
68
70
|
const decode_1 = require("../lightning/invoice/decode");
|
|
69
71
|
const decode_2 = require("../lightning/offer/decode");
|
|
70
72
|
const errors_1 = require("./errors");
|
|
@@ -146,14 +148,14 @@ function gossipPrimeLatch(rgs, timeoutMs) {
|
|
|
146
148
|
}
|
|
147
149
|
exports.gossipPrimeLatch = gossipPrimeLatch;
|
|
148
150
|
function formatScid(scid) {
|
|
149
|
-
const { block, txIndex, outputIndex } = (0,
|
|
151
|
+
const { block, txIndex, outputIndex } = (0, types_3.decodeShortChannelId)(scid);
|
|
150
152
|
return `${block}x${txIndex}x${outputIndex}`;
|
|
151
153
|
}
|
|
152
154
|
exports.formatScid = formatScid;
|
|
153
155
|
function parseScid(scid) {
|
|
154
156
|
const human = scid.match(/^(\d+)x(\d+)x(\d+)$/);
|
|
155
157
|
if (human) {
|
|
156
|
-
return (0,
|
|
158
|
+
return (0, types_3.encodeShortChannelId)({
|
|
157
159
|
block: parseInt(human[1], 10),
|
|
158
160
|
txIndex: parseInt(human[2], 10),
|
|
159
161
|
outputIndex: parseInt(human[3], 10)
|
|
@@ -194,19 +196,19 @@ function decodeOfferInput(offerStr) {
|
|
|
194
196
|
}
|
|
195
197
|
exports.decodeOfferInput = decodeOfferInput;
|
|
196
198
|
const FUNDING_UNAVAILABLE_CODES = {
|
|
197
|
-
[
|
|
198
|
-
[
|
|
199
|
-
[
|
|
200
|
-
[
|
|
199
|
+
[types_5.ChannelFundingUnavailableCode.FUNDING_PROVIDER_REQUIRED]: errors_1.BeignetErrorCode.FUNDING_PROVIDER_REQUIRED,
|
|
200
|
+
[types_5.ChannelFundingUnavailableCode.INSUFFICIENT_BALANCE]: errors_1.BeignetErrorCode.INSUFFICIENT_BALANCE,
|
|
201
|
+
[types_5.ChannelFundingUnavailableCode.FEE_ESTIMATE_NOT_READY]: errors_1.BeignetErrorCode.FEE_ESTIMATE_NOT_READY,
|
|
202
|
+
[types_5.ChannelFundingUnavailableCode.CHANNEL_NOT_FOUND]: errors_1.BeignetErrorCode.CHANNEL_NOT_FOUND
|
|
201
203
|
};
|
|
202
204
|
const SPLICE_REFUSAL_CODES = {
|
|
203
|
-
[
|
|
204
|
-
[
|
|
205
|
-
[
|
|
206
|
-
[
|
|
207
|
-
[
|
|
208
|
-
[
|
|
209
|
-
[
|
|
205
|
+
[types_5.SpliceRefusalCode.CHANNEL_NOT_FOUND]: errors_1.BeignetErrorCode.CHANNEL_NOT_FOUND,
|
|
206
|
+
[types_5.SpliceRefusalCode.SPLICING_NOT_NEGOTIATED]: errors_1.BeignetErrorCode.SPLICING_NOT_NEGOTIATED,
|
|
207
|
+
[types_5.SpliceRefusalCode.INVALID_PARAMS]: errors_1.BeignetErrorCode.INVALID_PARAMS,
|
|
208
|
+
[types_5.SpliceRefusalCode.INSUFFICIENT_BALANCE]: errors_1.BeignetErrorCode.INSUFFICIENT_BALANCE,
|
|
209
|
+
[types_5.SpliceRefusalCode.FUNDING_PROVIDER_REQUIRED]: errors_1.BeignetErrorCode.FUNDING_PROVIDER_REQUIRED,
|
|
210
|
+
[types_5.SpliceRefusalCode.SPLICE_BUSY]: errors_1.BeignetErrorCode.SPLICE_BUSY,
|
|
211
|
+
[types_5.SpliceRefusalCode.SPLICE_REFUSED]: errors_1.BeignetErrorCode.SPLICE_REFUSED
|
|
210
212
|
};
|
|
211
213
|
function spliceRefusalError(result) {
|
|
212
214
|
if (result.ok)
|
|
@@ -221,10 +223,10 @@ function fundingOrRefuse(run) {
|
|
|
221
223
|
return run();
|
|
222
224
|
}
|
|
223
225
|
catch (err) {
|
|
224
|
-
if (err instanceof
|
|
226
|
+
if (err instanceof types_5.InvalidRequestError) {
|
|
225
227
|
throw new errors_1.BeignetError(errors_1.BeignetErrorCode.INVALID_PARAMS, err.message);
|
|
226
228
|
}
|
|
227
|
-
if (err instanceof
|
|
229
|
+
if (err instanceof types_5.ChannelFundingUnavailableError) {
|
|
228
230
|
throw new errors_1.BeignetError(FUNDING_UNAVAILABLE_CODES[err.code], err.message);
|
|
229
231
|
}
|
|
230
232
|
throw err;
|
|
@@ -742,11 +744,11 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
742
744
|
const beignetNetwork = this.toBeignetNetwork(networkName);
|
|
743
745
|
const lnNetwork = this.toLnNetwork(networkName);
|
|
744
746
|
const coinType = this.toCoinType(networkName);
|
|
745
|
-
let chainHash =
|
|
747
|
+
let chainHash = types_6.BITCOIN_CHAIN_HASH;
|
|
746
748
|
if (networkName === 'regtest')
|
|
747
|
-
chainHash =
|
|
749
|
+
chainHash = types_6.REGTEST_CHAIN_HASH;
|
|
748
750
|
if (networkName === 'signet')
|
|
749
|
-
chainHash =
|
|
751
|
+
chainHash = types_6.SIGNET_CHAIN_HASH;
|
|
750
752
|
const electrumServer = {
|
|
751
753
|
host: electrumHost,
|
|
752
754
|
ssl: electrumTls ? electrumPort : 0,
|
|
@@ -1138,8 +1140,50 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
1138
1140
|
this.log('info', 'Channel resolved', { channelId });
|
|
1139
1141
|
this.emit('channel:resolved', { channelId });
|
|
1140
1142
|
});
|
|
1141
|
-
this.node.on('splice:complete', () => {
|
|
1143
|
+
this.node.on('splice:complete', (data) => {
|
|
1142
1144
|
this.refreshStaticChannelBackup();
|
|
1145
|
+
const channelId = data.channelId.toString('hex');
|
|
1146
|
+
const fundingTxid = data.fundingTxid
|
|
1147
|
+
? Buffer.from(data.fundingTxid).reverse().toString('hex')
|
|
1148
|
+
: undefined;
|
|
1149
|
+
this.log('info', 'Splice complete', { channelId, fundingTxid });
|
|
1150
|
+
this.emit('splice:complete', { channelId, fundingTxid });
|
|
1151
|
+
});
|
|
1152
|
+
this.node.on('splice:aborted', (data) => {
|
|
1153
|
+
const channelId = data.channelId.toString('hex');
|
|
1154
|
+
this.log('info', 'Splice aborted', { channelId, reason: data.reason });
|
|
1155
|
+
this.emit('splice:aborted', { channelId, reason: data.reason });
|
|
1156
|
+
});
|
|
1157
|
+
this.node.on('splice:conflicted', (data) => {
|
|
1158
|
+
const channelId = data.channelId.toString('hex');
|
|
1159
|
+
this.log('warn', 'Splice cannot confirm: an input was spent elsewhere; asking the peer to revert', {
|
|
1160
|
+
channelId,
|
|
1161
|
+
spliceTxid: data.spliceTxid,
|
|
1162
|
+
conflictTxid: data.conflictTxid,
|
|
1163
|
+
inputIndex: data.inputIndex,
|
|
1164
|
+
height: data.height
|
|
1165
|
+
});
|
|
1166
|
+
this.emit('splice:conflicted', {
|
|
1167
|
+
channelId,
|
|
1168
|
+
spliceTxid: data.spliceTxid,
|
|
1169
|
+
conflictTxid: data.conflictTxid,
|
|
1170
|
+
inputIndex: data.inputIndex,
|
|
1171
|
+
height: data.height
|
|
1172
|
+
});
|
|
1173
|
+
});
|
|
1174
|
+
this.node.on('splice:reverted', (data) => {
|
|
1175
|
+
const channelId = data.channelId.toString('hex');
|
|
1176
|
+
this.log('info', 'Splice reverted to the pre-splice funding', {
|
|
1177
|
+
channelId,
|
|
1178
|
+
spliceTxid: data.spliceTxid,
|
|
1179
|
+
conflictTxid: data.conflictTxid
|
|
1180
|
+
});
|
|
1181
|
+
this.refreshStaticChannelBackup();
|
|
1182
|
+
this.emit('splice:reverted', {
|
|
1183
|
+
channelId,
|
|
1184
|
+
spliceTxid: data.spliceTxid,
|
|
1185
|
+
conflictTxid: data.conflictTxid
|
|
1186
|
+
});
|
|
1143
1187
|
});
|
|
1144
1188
|
this.node.on('channel:opening', (data) => {
|
|
1145
1189
|
const channelId = data.channelId.toString('hex');
|
|
@@ -1333,7 +1377,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
1333
1377
|
const hex = channelId.toString('hex');
|
|
1334
1378
|
this.emit('ffor:state', {
|
|
1335
1379
|
channelId: hex,
|
|
1336
|
-
state:
|
|
1380
|
+
state: types_2.FforState[state] ?? String(state),
|
|
1337
1381
|
epoch: this.fforEpochView(hex, record)
|
|
1338
1382
|
});
|
|
1339
1383
|
});
|
|
@@ -2806,9 +2850,9 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
2806
2850
|
}
|
|
2807
2851
|
getPendingCloseBalanceSats() {
|
|
2808
2852
|
const recovering = new Set([
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2853
|
+
types_6.ChannelState.FORCE_CLOSED,
|
|
2854
|
+
types_6.ChannelState.SHUTTING_DOWN,
|
|
2855
|
+
types_6.ChannelState.NEGOTIATING_CLOSING
|
|
2812
2856
|
]);
|
|
2813
2857
|
let totalMsat = 0n;
|
|
2814
2858
|
for (const ch of this.node.listChannels()) {
|
|
@@ -2821,7 +2865,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
2821
2865
|
getErroredBalanceSats() {
|
|
2822
2866
|
let totalMsat = 0n;
|
|
2823
2867
|
for (const ch of this.node.listChannels()) {
|
|
2824
|
-
if (ch.state ===
|
|
2868
|
+
if (ch.state === types_6.ChannelState.ERRORED) {
|
|
2825
2869
|
totalMsat += ch.localBalanceMsat;
|
|
2826
2870
|
}
|
|
2827
2871
|
}
|
|
@@ -3457,7 +3501,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
3457
3501
|
catch (err) {
|
|
3458
3502
|
if (err instanceof errors_1.BeignetError)
|
|
3459
3503
|
throw err;
|
|
3460
|
-
if (err instanceof
|
|
3504
|
+
if (err instanceof types_5.InvalidRequestError) {
|
|
3461
3505
|
throw new errors_1.BeignetError(errors_1.BeignetErrorCode.INVALID_PARAMS, err.message);
|
|
3462
3506
|
}
|
|
3463
3507
|
throw new errors_1.BeignetError('CONNECT_FAILED', `Failed to connect to ${pubkey.slice(0, 16)}…@${target}: ${err.message}`);
|
|
@@ -3557,7 +3601,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
3557
3601
|
localBalanceSats: Number(balances.localMsat / 1000n),
|
|
3558
3602
|
remoteBalanceSats: Number(balances.remoteMsat / 1000n),
|
|
3559
3603
|
capacitySats: Number(state.fundingSatoshis),
|
|
3560
|
-
isAnchor: (0,
|
|
3604
|
+
isAnchor: (0, types_6.isAnchorChannel)(state.channelType)
|
|
3561
3605
|
};
|
|
3562
3606
|
}
|
|
3563
3607
|
async openChannelAndWait(pubkey, amountSats, opts) {
|
|
@@ -3649,9 +3693,9 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
3649
3693
|
let state;
|
|
3650
3694
|
if (f.role === 'S') {
|
|
3651
3695
|
state =
|
|
3652
|
-
f.slotStates[i] ===
|
|
3696
|
+
f.slotStates[i] === types_2.FforSlotState.SETTLED
|
|
3653
3697
|
? 'settled'
|
|
3654
|
-
: f.slotStates[i] ===
|
|
3698
|
+
: f.slotStates[i] === types_2.FforSlotState.SETTLING
|
|
3655
3699
|
? 'settling'
|
|
3656
3700
|
: 'unused';
|
|
3657
3701
|
}
|
|
@@ -3677,7 +3721,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
3677
3721
|
return {
|
|
3678
3722
|
channelId: channelIdHex,
|
|
3679
3723
|
role: f.role,
|
|
3680
|
-
state:
|
|
3724
|
+
state: types_2.FforState[f.state],
|
|
3681
3725
|
epochId: f.epochId.toString('hex'),
|
|
3682
3726
|
peerNodeId: f.remoteNodeId.toString('hex'),
|
|
3683
3727
|
variant: f.params.variant,
|
|
@@ -3803,7 +3847,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
3803
3847
|
const idBuf = this.fforChannelId(body.channelId);
|
|
3804
3848
|
const res = this.node.abortFforEpoch(idBuf.toString('hex'), typeof body.reason === 'number'
|
|
3805
3849
|
? body.reason
|
|
3806
|
-
:
|
|
3850
|
+
: types_2.FforAbortReason.OPERATOR, body.text ?? 'operator abort');
|
|
3807
3851
|
if (!res.ok)
|
|
3808
3852
|
throw new errors_1.BeignetError('FFOR_REFUSED', res.error ?? 'abort refused');
|
|
3809
3853
|
return this.fforEpoch(idBuf.toString('hex'));
|
|
@@ -4087,7 +4131,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
4087
4131
|
localBalanceSats: Number(ch.localBalanceMsat / 1000n),
|
|
4088
4132
|
remoteBalanceSats: Number(ch.remoteBalanceMsat / 1000n),
|
|
4089
4133
|
capacitySats: Number(ch.fundingSatoshis),
|
|
4090
|
-
isAnchor: (0,
|
|
4134
|
+
isAnchor: (0, types_6.isAnchorChannel)(ch.channelType ?? null)
|
|
4091
4135
|
};
|
|
4092
4136
|
if (peerPubkey) {
|
|
4093
4137
|
const splice = this.node.peerSupportsSplicing(peerPubkey);
|
|
@@ -4116,6 +4160,9 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
4116
4160
|
info.fundingUnaccounted = ch.fundingUnaccounted;
|
|
4117
4161
|
if (ch.payThroughSplice !== undefined)
|
|
4118
4162
|
info.payThroughSplice = ch.payThroughSplice;
|
|
4163
|
+
if (ch.revertedSplices?.length) {
|
|
4164
|
+
info.revertedSplices = ch.revertedSplices.map((r) => ({ ...r }));
|
|
4165
|
+
}
|
|
4119
4166
|
if (ch.isPrivate !== undefined)
|
|
4120
4167
|
info.isPrivate = ch.isPrivate;
|
|
4121
4168
|
if (ch.feeBaseMsat !== undefined)
|
|
@@ -4228,6 +4275,21 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
4228
4275
|
await this.node.startDirectFunding();
|
|
4229
4276
|
}
|
|
4230
4277
|
configureDirectFunding(update) {
|
|
4278
|
+
for (const flag of [
|
|
4279
|
+
'trusted',
|
|
4280
|
+
'allowSplice',
|
|
4281
|
+
'allowUnpairedSplice'
|
|
4282
|
+
]) {
|
|
4283
|
+
if (update[flag] !== undefined && typeof update[flag] !== 'boolean') {
|
|
4284
|
+
throw new errors_1.BeignetError(errors_1.BeignetErrorCode.INVALID_PARAMS, `${flag} must be a boolean`);
|
|
4285
|
+
}
|
|
4286
|
+
}
|
|
4287
|
+
if (update.unpairedSpliceDepth !== undefined &&
|
|
4288
|
+
(!Number.isInteger(update.unpairedSpliceDepth) ||
|
|
4289
|
+
update.unpairedSpliceDepth < 1 ||
|
|
4290
|
+
update.unpairedSpliceDepth > splice_1.SPLICE_LOCK_DEPTH_ACCEPT_MAX)) {
|
|
4291
|
+
throw new errors_1.BeignetError(errors_1.BeignetErrorCode.INVALID_PARAMS, `unpairedSpliceDepth must be an integer between 1 and ${splice_1.SPLICE_LOCK_DEPTH_ACCEPT_MAX}`);
|
|
4292
|
+
}
|
|
4231
4293
|
if (update.lspPubkey !== undefined &&
|
|
4232
4294
|
!/^0[23][0-9a-fA-F]{64}$/.test(update.lspPubkey)) {
|
|
4233
4295
|
throw new errors_1.BeignetError(errors_1.BeignetErrorCode.INVALID_PARAMS, 'lspPubkey must be a 33-byte compressed public key (66 hex chars)');
|
|
@@ -4258,6 +4320,12 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
4258
4320
|
...(update.allowSplice !== undefined
|
|
4259
4321
|
? { allowSplice: update.allowSplice }
|
|
4260
4322
|
: {}),
|
|
4323
|
+
...(update.allowUnpairedSplice !== undefined
|
|
4324
|
+
? { allowUnpairedSplice: update.allowUnpairedSplice }
|
|
4325
|
+
: {}),
|
|
4326
|
+
...(update.unpairedSpliceDepth !== undefined
|
|
4327
|
+
? { unpairedSpliceDepth: update.unpairedSpliceDepth }
|
|
4328
|
+
: {}),
|
|
4261
4329
|
...(update.targetInboundSat !== undefined
|
|
4262
4330
|
? {
|
|
4263
4331
|
targetInboundSat: requireNonNegativeSafeInteger(update.targetInboundSat, 'targetInboundSat')
|
|
@@ -4398,6 +4466,8 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
4398
4466
|
targetInboundSat: policy.targetInboundSat ?? 0,
|
|
4399
4467
|
trusted: policy.allowZeroConf === true,
|
|
4400
4468
|
allowSplice: policy.allowSplice === true,
|
|
4469
|
+
allowUnpairedSplice: policy.allowUnpairedSplice === true,
|
|
4470
|
+
unpairedSpliceDepth: policy.unpairedSpliceDepth ?? types_1.DF_DEFAULT_UNPAIRED_SPLICE_DEPTH,
|
|
4401
4471
|
minAmountSat: clampDirectFundingMinimum(policy.minAmountSat ?? 0)
|
|
4402
4472
|
};
|
|
4403
4473
|
}
|
|
@@ -4999,7 +5069,19 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
4999
5069
|
}
|
|
5000
5070
|
return { status, summary, checks, invoice };
|
|
5001
5071
|
}
|
|
5002
|
-
|
|
5072
|
+
_cltvCeiling(cltvLimit) {
|
|
5073
|
+
if (cltvLimit === undefined)
|
|
5074
|
+
return undefined;
|
|
5075
|
+
if (!Number.isSafeInteger(cltvLimit) || cltvLimit < 1) {
|
|
5076
|
+
throw new errors_1.BeignetError('INVALID_PARAMS', 'cltvLimit must be a positive integer number of blocks');
|
|
5077
|
+
}
|
|
5078
|
+
const height = this.node.getCurrentBlockHeight();
|
|
5079
|
+
if (!(height > 0)) {
|
|
5080
|
+
throw new errors_1.BeignetError('CHAIN_NOT_SYNCED', 'cltvLimit needs the current block height, which is not known yet');
|
|
5081
|
+
}
|
|
5082
|
+
return height + cltvLimit;
|
|
5083
|
+
}
|
|
5084
|
+
async payInvoice(bolt11, timeoutMs = 60000, maxFeeSats, amountSats, metadata, cltvLimit) {
|
|
5003
5085
|
this._checkDraining();
|
|
5004
5086
|
const decoded = decodeInvoiceInput(bolt11);
|
|
5005
5087
|
const paymentHashHex = decoded.paymentHash.toString('hex');
|
|
@@ -5012,6 +5094,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
5012
5094
|
? BigInt(requireNonNegativeSafeInteger(amountSats, 'amountSats')) *
|
|
5013
5095
|
1000n
|
|
5014
5096
|
: undefined;
|
|
5097
|
+
const maxCltvExpiryHeight = this._cltvCeiling(cltvLimit);
|
|
5015
5098
|
if (spendAmountSats > 0) {
|
|
5016
5099
|
this._checkMaxPayment(spendAmountSats);
|
|
5017
5100
|
this._checkSpendLimit(spendAmountSats);
|
|
@@ -5077,7 +5160,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
5077
5160
|
this.node.on('payment:sent', onSent);
|
|
5078
5161
|
this.node.on('payment:failed', onFailed);
|
|
5079
5162
|
try {
|
|
5080
|
-
this.node.sendPayment(bolt11, undefined, maxFeeMsat, amountMsat);
|
|
5163
|
+
this.node.sendPayment(bolt11, undefined, maxFeeMsat, amountMsat, maxCltvExpiryHeight);
|
|
5081
5164
|
}
|
|
5082
5165
|
catch (err) {
|
|
5083
5166
|
cleanup();
|
|
@@ -5091,6 +5174,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
5091
5174
|
DUPLICATE_PAYMENT: 'DUPLICATE_PAYMENT',
|
|
5092
5175
|
NO_CHANNEL_TO_HOP: 'PEER_NOT_CONNECTED',
|
|
5093
5176
|
FEE_EXCEEDS_MAX: 'PAYMENT_FAILED',
|
|
5177
|
+
CLTV_EXCEEDS_MAX: 'CLTV_EXCEEDS_MAX',
|
|
5094
5178
|
MISSING_AMOUNT: 'INVALID_PARAMS',
|
|
5095
5179
|
INVALID_INVOICE: 'INVALID_PARAMS',
|
|
5096
5180
|
INVOICE_EXPIRED: 'INVOICE_EXPIRED'
|
|
@@ -5110,9 +5194,9 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
5110
5194
|
}
|
|
5111
5195
|
});
|
|
5112
5196
|
}
|
|
5113
|
-
async payInvoiceSafe(bolt11, timeoutMs = 60000, maxFeeSats, amountSats, metadata) {
|
|
5197
|
+
async payInvoiceSafe(bolt11, timeoutMs = 60000, maxFeeSats, amountSats, metadata, cltvLimit) {
|
|
5114
5198
|
try {
|
|
5115
|
-
return await this.payInvoice(bolt11, timeoutMs, maxFeeSats, amountSats, metadata);
|
|
5199
|
+
return await this.payInvoice(bolt11, timeoutMs, maxFeeSats, amountSats, metadata, cltvLimit);
|
|
5116
5200
|
}
|
|
5117
5201
|
catch (err) {
|
|
5118
5202
|
let hashHex = 'unknown';
|
|
@@ -5152,7 +5236,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
5152
5236
|
let lastError;
|
|
5153
5237
|
for (let attempt = 1; attempt <= maxRetries + 1; attempt++) {
|
|
5154
5238
|
try {
|
|
5155
|
-
const result = await this.payInvoice(bolt11, 60000, opts.maxFeeSats, opts.amountSats, opts.metadata);
|
|
5239
|
+
const result = await this.payInvoice(bolt11, 60000, opts.maxFeeSats, opts.amountSats, opts.metadata, opts.cltvLimit);
|
|
5156
5240
|
return { ...result, attempts: attempt };
|
|
5157
5241
|
}
|
|
5158
5242
|
catch (err) {
|
|
@@ -5242,7 +5326,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
5242
5326
|
attempts: maxRetries + 1
|
|
5243
5327
|
};
|
|
5244
5328
|
}
|
|
5245
|
-
sendPaymentAsync(bolt11, maxFeeSats, amountSats, metadata) {
|
|
5329
|
+
sendPaymentAsync(bolt11, maxFeeSats, amountSats, metadata, cltvLimit) {
|
|
5246
5330
|
this._checkDraining();
|
|
5247
5331
|
const decoded = decodeInvoiceInput(bolt11);
|
|
5248
5332
|
const paymentHashHex = decoded.paymentHash.toString('hex');
|
|
@@ -5255,6 +5339,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
5255
5339
|
? BigInt(requireNonNegativeSafeInteger(amountSats, 'amountSats')) *
|
|
5256
5340
|
1000n
|
|
5257
5341
|
: undefined;
|
|
5342
|
+
const maxCltvExpiryHeight = this._cltvCeiling(cltvLimit);
|
|
5258
5343
|
let claim;
|
|
5259
5344
|
if (spendAmountSats > 0) {
|
|
5260
5345
|
this._checkMaxPayment(spendAmountSats);
|
|
@@ -5266,11 +5351,15 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
5266
5351
|
if (metadata) {
|
|
5267
5352
|
this.node.setPaymentMetadata(decoded.paymentHash, metadata);
|
|
5268
5353
|
}
|
|
5269
|
-
result = this.node.sendPayment(bolt11, undefined, maxFeeMsat, amountMsat);
|
|
5354
|
+
result = this.node.sendPayment(bolt11, undefined, maxFeeMsat, amountMsat, maxCltvExpiryHeight);
|
|
5270
5355
|
}
|
|
5271
5356
|
catch (err) {
|
|
5272
5357
|
if (claim)
|
|
5273
5358
|
this._closeAsyncSpendClaim(paymentHashHex, claim);
|
|
5359
|
+
if (err instanceof Error &&
|
|
5360
|
+
err.code === 'CLTV_EXCEEDS_MAX') {
|
|
5361
|
+
throw new errors_1.BeignetError('CLTV_EXCEEDS_MAX', err.message);
|
|
5362
|
+
}
|
|
5274
5363
|
throw err;
|
|
5275
5364
|
}
|
|
5276
5365
|
if (claim && result.status === 'FAILED') {
|
|
@@ -5679,7 +5768,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
5679
5768
|
localBalanceSats: Number(balances.localMsat / 1000n),
|
|
5680
5769
|
remoteBalanceSats: Number(balances.remoteMsat / 1000n),
|
|
5681
5770
|
capacitySats: amountSats,
|
|
5682
|
-
isAnchor: (0,
|
|
5771
|
+
isAnchor: (0, types_6.isAnchorChannel)(state.channelType)
|
|
5683
5772
|
};
|
|
5684
5773
|
}
|
|
5685
5774
|
openChannelV2(peerPubkey, params) {
|
|
@@ -5728,7 +5817,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
5728
5817
|
localBalanceSats: Number(balances.localMsat / 1000n),
|
|
5729
5818
|
remoteBalanceSats: Number(balances.remoteMsat / 1000n),
|
|
5730
5819
|
capacitySats: params.amountSats,
|
|
5731
|
-
isAnchor: (0,
|
|
5820
|
+
isAnchor: (0, types_6.isAnchorChannel)(state.channelType)
|
|
5732
5821
|
};
|
|
5733
5822
|
}
|
|
5734
5823
|
spliceQuote(channelId, direction, feeratePerkw) {
|
|
@@ -5979,14 +6068,14 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
5979
6068
|
const blockHeight = this.node.getCurrentBlockHeight();
|
|
5980
6069
|
const electrumConnected = this.wallet?.electrum?.connectedToElectrum ?? false;
|
|
5981
6070
|
const channels = this.node.listChannels();
|
|
5982
|
-
const readyChannels = channels.filter((ch) => ch.state ===
|
|
6071
|
+
const readyChannels = channels.filter((ch) => ch.state === types_6.ChannelState.NORMAL && !isHeldRestore(ch));
|
|
5983
6072
|
const peerCount = this.node.listPeers().length;
|
|
5984
6073
|
const graph = this.node.getGraph();
|
|
5985
|
-
const operating = channels.filter((ch) => (ch.state ===
|
|
5986
|
-
ch.state ===
|
|
6074
|
+
const operating = channels.filter((ch) => (ch.state === types_6.ChannelState.NORMAL ||
|
|
6075
|
+
ch.state === types_6.ChannelState.SPLICING) &&
|
|
5987
6076
|
!isHeldRestore(ch));
|
|
5988
|
-
const broken = channels.filter((ch) => ch.state ===
|
|
5989
|
-
ch.state ===
|
|
6077
|
+
const broken = channels.filter((ch) => ch.state === types_6.ChannelState.AWAITING_REESTABLISH ||
|
|
6078
|
+
ch.state === types_6.ChannelState.ERRORED);
|
|
5990
6079
|
let status = 'ready';
|
|
5991
6080
|
if (!electrumConnected) {
|
|
5992
6081
|
status = 'degraded';
|
|
@@ -6046,7 +6135,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
6046
6135
|
? 'Networking and auto-reconnect enabled'
|
|
6047
6136
|
: 'Networking disabled — node cannot reconnect to peers'
|
|
6048
6137
|
});
|
|
6049
|
-
const hasAnchor = channels.some((ch) => ch.channelType != null && (0,
|
|
6138
|
+
const hasAnchor = channels.some((ch) => ch.channelType != null && (0, types_6.isAnchorChannel)(ch.channelType));
|
|
6050
6139
|
checks.push({
|
|
6051
6140
|
name: 'ANCHOR_CHANNELS_PREFERRED',
|
|
6052
6141
|
status: hasAnchor || channels.length === 0 ? 'PASS' : 'WARN',
|
|
@@ -6217,7 +6306,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
6217
6306
|
for (const ch of this.node.listChannels()) {
|
|
6218
6307
|
if (isHeldRestore(ch))
|
|
6219
6308
|
continue;
|
|
6220
|
-
if (ch.state !==
|
|
6309
|
+
if (ch.state !== types_6.ChannelState.NORMAL && !ch.htlcUsable)
|
|
6221
6310
|
continue;
|
|
6222
6311
|
const chReserveMsat = ch.localReserveMsat ?? 0n;
|
|
6223
6312
|
reserveMsat += chReserveMsat;
|
|
@@ -6418,7 +6507,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
6418
6507
|
feeProportionalMillionths: update.feeProportionalMillionths,
|
|
6419
6508
|
cltvExpiryDelta: update.cltvExpiryDelta,
|
|
6420
6509
|
htlcMinimumMsat: update.htlcMinimumMsat.toString(),
|
|
6421
|
-
disabled: (update.channelFlags &
|
|
6510
|
+
disabled: (update.channelFlags & types_3.CHANNEL_FLAG_DISABLED) !== 0,
|
|
6422
6511
|
lastUpdate: update.timestamp
|
|
6423
6512
|
};
|
|
6424
6513
|
if (update.htlcMaximumMsat !== undefined) {
|
|
@@ -6437,7 +6526,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
6437
6526
|
requireNonNegativeSafeInteger(maxFeeSats, 'maxFeeSats');
|
|
6438
6527
|
}
|
|
6439
6528
|
const amountMsat = BigInt(amountSats) * 1000n;
|
|
6440
|
-
const route = this.node.queryRoute(Buffer.from(destination, 'hex'), amountMsat,
|
|
6529
|
+
const route = this.node.queryRoute(Buffer.from(destination, 'hex'), amountMsat, types_4.DEFAULT_MIN_FINAL_CLTV_EXPIRY);
|
|
6441
6530
|
if (!route) {
|
|
6442
6531
|
throw new errors_1.BeignetError(errors_1.BeignetErrorCode.NO_ROUTE, 'No route found to destination');
|
|
6443
6532
|
}
|
|
@@ -6452,7 +6541,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
6452
6541
|
totalAmountMsat: route.totalAmountMsat.toString(),
|
|
6453
6542
|
totalFeeMsat: route.totalFeeMsat.toString(),
|
|
6454
6543
|
totalCltvDelta: route.totalCltvDelta,
|
|
6455
|
-
finalCltvExpiry:
|
|
6544
|
+
finalCltvExpiry: types_4.DEFAULT_MIN_FINAL_CLTV_EXPIRY
|
|
6456
6545
|
};
|
|
6457
6546
|
}
|
|
6458
6547
|
sendToRoute(paymentHash, route, paymentSecret) {
|
|
@@ -6485,7 +6574,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
6485
6574
|
getReadyChannels() {
|
|
6486
6575
|
return this.node
|
|
6487
6576
|
.listChannels()
|
|
6488
|
-
.filter((ch) => ch.state ===
|
|
6577
|
+
.filter((ch) => ch.state === types_6.ChannelState.NORMAL && !isHeldRestore(ch))
|
|
6489
6578
|
.map((ch) => this.toChannelInfo(ch));
|
|
6490
6579
|
}
|
|
6491
6580
|
canSend(amountSats) {
|
|
@@ -6494,7 +6583,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
6494
6583
|
let bestAvailableMsat = 0n;
|
|
6495
6584
|
let totalAvailableMsat = 0n;
|
|
6496
6585
|
for (const ch of this.node.listChannels()) {
|
|
6497
|
-
if (ch.state !==
|
|
6586
|
+
if (ch.state !== types_6.ChannelState.NORMAL || isHeldRestore(ch))
|
|
6498
6587
|
continue;
|
|
6499
6588
|
const reserveMsat = ch.localReserveMsat ?? 0n;
|
|
6500
6589
|
const available = ch.localBalanceMsat > reserveMsat
|
|
@@ -6518,7 +6607,7 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
6518
6607
|
let bestAvailableMsat = 0n;
|
|
6519
6608
|
let totalAvailableMsat = 0n;
|
|
6520
6609
|
for (const ch of this.node.listChannels()) {
|
|
6521
|
-
if (ch.state !==
|
|
6610
|
+
if (ch.state !== types_6.ChannelState.NORMAL || isHeldRestore(ch))
|
|
6522
6611
|
continue;
|
|
6523
6612
|
const reserveMsat = ch.remoteReserveMsat ?? 0n;
|
|
6524
6613
|
const available = ch.remoteBalanceMsat > reserveMsat
|
|
@@ -7027,15 +7116,15 @@ class BeignetNode extends events_1.EventEmitter {
|
|
|
7027
7116
|
toLnNetwork(network) {
|
|
7028
7117
|
switch (network) {
|
|
7029
7118
|
case 'mainnet':
|
|
7030
|
-
return
|
|
7119
|
+
return types_4.Network.MAINNET;
|
|
7031
7120
|
case 'testnet':
|
|
7032
|
-
return
|
|
7121
|
+
return types_4.Network.TESTNET;
|
|
7033
7122
|
case 'regtest':
|
|
7034
|
-
return
|
|
7123
|
+
return types_4.Network.REGTEST;
|
|
7035
7124
|
case 'signet':
|
|
7036
|
-
return
|
|
7125
|
+
return types_4.Network.SIGNET;
|
|
7037
7126
|
default:
|
|
7038
|
-
return
|
|
7127
|
+
return types_4.Network.MAINNET;
|
|
7039
7128
|
}
|
|
7040
7129
|
}
|
|
7041
7130
|
toCoinType(network) {
|