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.
Files changed (58) hide show
  1. package/dist/cli/beignet-node.js +152 -63
  2. package/dist/cli/beignet-node.js.map +1 -1
  3. package/dist/cli/daemon.js +18 -9
  4. package/dist/cli/daemon.js.map +1 -1
  5. package/dist/cli/errors.js +5 -1
  6. package/dist/cli/errors.js.map +1 -1
  7. package/dist/cli/openapi.js +36 -7
  8. package/dist/cli/openapi.js.map +1 -1
  9. package/dist/lightning/chain/chain-watcher.js +164 -1
  10. package/dist/lightning/chain/chain-watcher.js.map +1 -1
  11. package/dist/lightning/channel/channel-actions.js +2 -0
  12. package/dist/lightning/channel/channel-actions.js.map +1 -1
  13. package/dist/lightning/channel/channel-manager.js +62 -1
  14. package/dist/lightning/channel/channel-manager.js.map +1 -1
  15. package/dist/lightning/channel/channel-state.js +2 -0
  16. package/dist/lightning/channel/channel-state.js.map +1 -1
  17. package/dist/lightning/channel/channel.js +334 -17
  18. package/dist/lightning/channel/channel.js.map +1 -1
  19. package/dist/lightning/channel/splice.js +13 -2
  20. package/dist/lightning/channel/splice.js.map +1 -1
  21. package/dist/lightning/direct-funding/receiver/engine.js +74 -3
  22. package/dist/lightning/direct-funding/receiver/engine.js.map +1 -1
  23. package/dist/lightning/direct-funding/receiver/types.js +2 -1
  24. package/dist/lightning/direct-funding/receiver/types.js.map +1 -1
  25. package/dist/lightning/liquidity/jit-receive.js +18 -1
  26. package/dist/lightning/liquidity/jit-receive.js.map +1 -1
  27. package/dist/lightning/message/custom.js +2 -0
  28. package/dist/lightning/message/custom.js.map +1 -1
  29. package/dist/lightning/message/splice-conflict.js +76 -0
  30. package/dist/lightning/message/splice-conflict.js.map +1 -0
  31. package/dist/lightning/message/splice.js +93 -39
  32. package/dist/lightning/message/splice.js.map +1 -1
  33. package/dist/lightning/node/lightning-node.js +569 -11
  34. package/dist/lightning/node/lightning-node.js.map +1 -1
  35. package/dist/lightning/node/types.js.map +1 -1
  36. package/dist/lightning/storage/serialization.js +34 -2
  37. package/dist/lightning/storage/serialization.js.map +1 -1
  38. package/dist/types/cli/beignet-node.d.ts +6 -3
  39. package/dist/types/cli/errors.d.ts +2 -0
  40. package/dist/types/cli/types.d.ts +28 -0
  41. package/dist/types/lightning/chain/chain-watcher.d.ts +23 -0
  42. package/dist/types/lightning/channel/channel-actions.d.ts +14 -1
  43. package/dist/types/lightning/channel/channel-manager.d.ts +4 -0
  44. package/dist/types/lightning/channel/channel-state.d.ts +23 -0
  45. package/dist/types/lightning/channel/channel.d.ts +25 -1
  46. package/dist/types/lightning/channel/splice.d.ts +4 -0
  47. package/dist/types/lightning/direct-funding/receiver/engine.d.ts +8 -0
  48. package/dist/types/lightning/direct-funding/receiver/types.d.ts +12 -1
  49. package/dist/types/lightning/liquidity/jit-receive.d.ts +1 -0
  50. package/dist/types/lightning/message/custom.d.ts +3 -1
  51. package/dist/types/lightning/message/splice-conflict.d.ts +19 -0
  52. package/dist/types/lightning/message/splice.d.ts +5 -0
  53. package/dist/types/lightning/node/lightning-node.d.ts +26 -1
  54. package/dist/types/lightning/node/types.d.ts +8 -1
  55. package/dist/types/lightning/storage/serialization.d.ts +23 -0
  56. package/docs/AI_AGENT_GUIDE.md +2 -0
  57. package/docs/SPLICE-LOCK-DEPTH.md +170 -0
  58. package/package.json +1 -1
@@ -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/ffor/types");
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 types_2 = require("../lightning/gossip/types");
57
+ const types_3 = require("../lightning/gossip/types");
56
58
  const electrum_backend_1 = require("../lightning/chain/electrum-backend");
57
- const types_3 = require("../lightning/invoice/types");
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 types_4 = require("../lightning/node/types");
67
- const types_5 = require("../lightning/channel/types");
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, types_2.decodeShortChannelId)(scid);
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, types_2.encodeShortChannelId)({
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
- [types_4.ChannelFundingUnavailableCode.FUNDING_PROVIDER_REQUIRED]: errors_1.BeignetErrorCode.FUNDING_PROVIDER_REQUIRED,
198
- [types_4.ChannelFundingUnavailableCode.INSUFFICIENT_BALANCE]: errors_1.BeignetErrorCode.INSUFFICIENT_BALANCE,
199
- [types_4.ChannelFundingUnavailableCode.FEE_ESTIMATE_NOT_READY]: errors_1.BeignetErrorCode.FEE_ESTIMATE_NOT_READY,
200
- [types_4.ChannelFundingUnavailableCode.CHANNEL_NOT_FOUND]: errors_1.BeignetErrorCode.CHANNEL_NOT_FOUND
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
- [types_4.SpliceRefusalCode.CHANNEL_NOT_FOUND]: errors_1.BeignetErrorCode.CHANNEL_NOT_FOUND,
204
- [types_4.SpliceRefusalCode.SPLICING_NOT_NEGOTIATED]: errors_1.BeignetErrorCode.SPLICING_NOT_NEGOTIATED,
205
- [types_4.SpliceRefusalCode.INVALID_PARAMS]: errors_1.BeignetErrorCode.INVALID_PARAMS,
206
- [types_4.SpliceRefusalCode.INSUFFICIENT_BALANCE]: errors_1.BeignetErrorCode.INSUFFICIENT_BALANCE,
207
- [types_4.SpliceRefusalCode.FUNDING_PROVIDER_REQUIRED]: errors_1.BeignetErrorCode.FUNDING_PROVIDER_REQUIRED,
208
- [types_4.SpliceRefusalCode.SPLICE_BUSY]: errors_1.BeignetErrorCode.SPLICE_BUSY,
209
- [types_4.SpliceRefusalCode.SPLICE_REFUSED]: errors_1.BeignetErrorCode.SPLICE_REFUSED
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 types_4.InvalidRequestError) {
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 types_4.ChannelFundingUnavailableError) {
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 = types_5.BITCOIN_CHAIN_HASH;
747
+ let chainHash = types_6.BITCOIN_CHAIN_HASH;
746
748
  if (networkName === 'regtest')
747
- chainHash = types_5.REGTEST_CHAIN_HASH;
749
+ chainHash = types_6.REGTEST_CHAIN_HASH;
748
750
  if (networkName === 'signet')
749
- chainHash = types_5.SIGNET_CHAIN_HASH;
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: types_1.FforState[state] ?? String(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
- types_5.ChannelState.FORCE_CLOSED,
2810
- types_5.ChannelState.SHUTTING_DOWN,
2811
- types_5.ChannelState.NEGOTIATING_CLOSING
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 === types_5.ChannelState.ERRORED) {
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 types_4.InvalidRequestError) {
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, types_5.isAnchorChannel)(state.channelType)
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] === types_1.FforSlotState.SETTLED
3696
+ f.slotStates[i] === types_2.FforSlotState.SETTLED
3653
3697
  ? 'settled'
3654
- : f.slotStates[i] === types_1.FforSlotState.SETTLING
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: types_1.FforState[f.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
- : types_1.FforAbortReason.OPERATOR, body.text ?? 'operator abort');
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, types_5.isAnchorChannel)(ch.channelType ?? null)
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
- async payInvoice(bolt11, timeoutMs = 60000, maxFeeSats, amountSats, metadata) {
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, types_5.isAnchorChannel)(state.channelType)
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, types_5.isAnchorChannel)(state.channelType)
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 === types_5.ChannelState.NORMAL && !isHeldRestore(ch));
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 === types_5.ChannelState.NORMAL ||
5986
- ch.state === types_5.ChannelState.SPLICING) &&
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 === types_5.ChannelState.AWAITING_REESTABLISH ||
5989
- ch.state === types_5.ChannelState.ERRORED);
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, types_5.isAnchorChannel)(ch.channelType));
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 !== types_5.ChannelState.NORMAL && !ch.htlcUsable)
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 & types_2.CHANNEL_FLAG_DISABLED) !== 0,
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, types_3.DEFAULT_MIN_FINAL_CLTV_EXPIRY);
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: types_3.DEFAULT_MIN_FINAL_CLTV_EXPIRY
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 === types_5.ChannelState.NORMAL && !isHeldRestore(ch))
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 !== types_5.ChannelState.NORMAL || isHeldRestore(ch))
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 !== types_5.ChannelState.NORMAL || isHeldRestore(ch))
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 types_3.Network.MAINNET;
7119
+ return types_4.Network.MAINNET;
7031
7120
  case 'testnet':
7032
- return types_3.Network.TESTNET;
7121
+ return types_4.Network.TESTNET;
7033
7122
  case 'regtest':
7034
- return types_3.Network.REGTEST;
7123
+ return types_4.Network.REGTEST;
7035
7124
  case 'signet':
7036
- return types_3.Network.SIGNET;
7125
+ return types_4.Network.SIGNET;
7037
7126
  default:
7038
- return types_3.Network.MAINNET;
7127
+ return types_4.Network.MAINNET;
7039
7128
  }
7040
7129
  }
7041
7130
  toCoinType(network) {