lightning 5.16.4 → 5.17.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 (32) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +11 -0
  3. package/bolt00/mtokens_amount.js +5 -0
  4. package/grpc/protos/lightning.proto +70 -0
  5. package/grpc/protos/signer.proto +31 -5
  6. package/index.js +3 -1
  7. package/lnd_methods/index.js +2 -0
  8. package/lnd_methods/info/get_network_graph.d.ts +1 -1
  9. package/lnd_methods/invoices/subscribe_to_invoices.js +26 -4
  10. package/lnd_methods/macaroon/methods.json +4 -0
  11. package/lnd_methods/offchain/get_channels.d.ts +1 -1
  12. package/lnd_methods/offchain/get_channels.js +5 -1
  13. package/lnd_methods/offchain/get_closed_channels.js +16 -1
  14. package/lnd_methods/offchain/get_ephemeral_channel_ids.js +86 -0
  15. package/lnd_methods/offchain/index.js +2 -0
  16. package/lnd_methods/offchain/subscribe_to_channels.js +4 -0
  17. package/lnd_methods/offchain/subscribe_to_open_requests.js +6 -0
  18. package/lnd_methods/onchain/open_channels.js +9 -0
  19. package/lnd_responses/channel_accept_as_open_request.js +3 -0
  20. package/lnd_responses/rpc_channel_as_channel.js +17 -1
  21. package/lnd_responses/rpc_closed_channel_as_closed.js +17 -1
  22. package/package.json +8 -8
  23. package/test/bolt00/test_mtokens_amount.js +10 -0
  24. package/test/lnd_methods/invoices/test_subscribe_to_invoices.js +2 -0
  25. package/test/lnd_methods/offchain/test_get_channels.js +3 -0
  26. package/test/lnd_methods/offchain/test_get_closed_channels.js +23 -0
  27. package/test/lnd_methods/offchain/test_get_ephemeral_channel_ids.js +68 -0
  28. package/test/lnd_methods/offchain/test_subscribe_to_channels.js +5 -0
  29. package/test/lnd_methods/offchain/test_subscribe_to_open_requests.js +1 -0
  30. package/test/lnd_responses/test_channel_accept_as_open_request.js +1 -0
  31. package/test/lnd_responses/test_rpc_channel_as_channel.js +13 -0
  32. package/test/lnd_responses/test_rpc_closed_channel_as_closed.js +15 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Versions
2
2
 
3
+ ## 5.17.0
4
+
5
+ - `getChannels`: Add support for `is_trusted_funding` and `other_ids`
6
+ - `getClosedChannels`: Add support for `other_ids`
7
+ - `getEphemeralChannelIds`: Add method to get other channel ids
8
+ - `openChannels`: Add support for `is_trusted_funding` for instant opening
9
+ - `subscribeToChannels`: Add support for `is_trusted_funding`, `other_ids`
10
+ - `subscribeToOpenRequests`: Add support for `is_trusted_funding`
11
+
12
+ ## 5.16.6
13
+
14
+ - `subscribeToInvoices`: Cancel subscription when there are no event listeners
15
+
3
16
  ## 5.16.4
4
17
 
5
18
  - `signTransaction`: Add `root_hash` to support Taproot signatures with scripts
package/README.md CHANGED
@@ -18,6 +18,7 @@ Methods for working with the Lightning Network
18
18
  https://github.com/ibz/lightning-shell
19
19
  - [LNMarkets](https://twitter.com/lnmarkets) -
20
20
  https://github.com/lnmarkets/umbrel
21
+ - [mempool.space](https://mempool.space/) - https://github.com/mempool/mempool
21
22
  - [p2plnbot](https://telegram.me/lnp2pbot) - https://github.com/grunch/p2plnbot
22
23
  - [rekr](https://rekr.app/) - https://github.com/ryan-lingle/rekr
23
24
  - [stackernews](https://stacker.news/) -
@@ -64,6 +65,14 @@ const {lnd} = authenticatedLndGrpc({
64
65
  To access unauthenticated methods like the wallet unlocker, use
65
66
  `unauthenticatedLndGrpc` instead.
66
67
 
68
+ ## Debugging
69
+
70
+ If you encounter any issues connecting and wish to view detailed information
71
+ about the underlying grpc calls, you can run Node with these environment
72
+ variables set:
73
+
74
+ GRPC_VERBOSITY=DEBUG GRPC_TRACE=all node YOURSCRIPTNAME.js
75
+
67
76
  ## Methods
68
77
 
69
78
  - [addExternalSocket](https://github.com/alexbosworth/ln-service#addexternalsocket):
@@ -147,6 +156,8 @@ To access unauthenticated methods like the wallet unlocker, use
147
156
  channels on the node.
148
157
  - [getConnectedWatchtowers](https://github.com/alexbosworth/ln-service#getconnectedwatchtowers):
149
158
  List watchtowers that were added
159
+ - [getEphemeralChannelIds](https://github.com/alexbosworth/ln-service#getephemeralchannelids):
160
+ List other channel ids for channels
150
161
  - [getFailedPayments](https://github.com/alexbosworth/ln-service#getfailedpayments): List out
151
162
  past payments that failed.
152
163
  - [getFeeRates](https://github.com/alexbosworth/ln-service#getfeerates): List routing fee rates
@@ -1,3 +1,4 @@
1
+ const isNumber = n => !isNaN(n);
1
2
  const tokensAsMtokens = tokens => (BigInt(tokens) * BigInt(1e3)).toString();
2
3
 
3
4
  /** Derive millitokens from tokens and mtokens
@@ -20,6 +21,10 @@ module.exports = ({mtokens, tokens}) => {
20
21
  return {};
21
22
  }
22
23
 
24
+ if (!mtokens && !isNumber(tokens)) {
25
+ throw new Error('ExpectedEitherTokensNumberOrMtokensStringForAmountValue');
26
+ }
27
+
23
28
  // Exit early when there is only tokens set
24
29
  if (!mtokens) {
25
30
  return {mtokens: tokensAsMtokens(tokens)};
@@ -570,6 +570,13 @@ service Lightning {
570
570
  */
571
571
  rpc SubscribeCustomMessages (SubscribeCustomMessagesRequest)
572
572
  returns (stream CustomMessage);
573
+
574
+ /* lncli: `listaliases`
575
+ ListAliases returns the set of all aliases that have ever existed with
576
+ their confirmed SCID (if it exists) and/or the base SCID (in the case of
577
+ zero conf).
578
+ */
579
+ rpc ListAliases (ListAliasesRequest) returns (ListAliasesResponse);
573
580
  }
574
581
 
575
582
  message SubscribeCustomMessagesRequest {
@@ -915,6 +922,14 @@ message ChannelAcceptRequest {
915
922
 
916
923
  // The commitment type the initiator wishes to use for the proposed channel.
917
924
  CommitmentType commitment_type = 14;
925
+
926
+ // Whether the initiator wants to open a zero-conf channel via the channel
927
+ // type.
928
+ bool wants_zero_conf = 15;
929
+
930
+ // Whether the initiator wants to use the scid-alias channel type. This is
931
+ // separate from the feature bit.
932
+ bool wants_scid_alias = 16;
918
933
  }
919
934
 
920
935
  message ChannelAcceptResponse {
@@ -975,6 +990,13 @@ message ChannelAcceptResponse {
975
990
  The number of confirmations we require before we consider the channel open.
976
991
  */
977
992
  uint32 min_accept_depth = 10;
993
+
994
+ /*
995
+ Whether the responder wants this to be a zero-conf channel. This will fail
996
+ if either side does not have the scid-alias feature bit set. The minimum
997
+ depth field must be zero if this is true.
998
+ */
999
+ bool zero_conf = 11;
978
1000
  }
979
1001
 
980
1002
  message ChannelPoint {
@@ -1458,6 +1480,18 @@ message Channel {
1458
1480
 
1459
1481
  // List constraints for the remote node.
1460
1482
  ChannelConstraints remote_constraints = 30;
1483
+
1484
+ /*
1485
+ This lists out the set of alias short channel ids that exist for a channel.
1486
+ This may be empty.
1487
+ */
1488
+ repeated uint64 alias_scids = 31;
1489
+
1490
+ // Whether or not this is a zero-conf channel.
1491
+ bool zero_conf = 32;
1492
+
1493
+ // This is the confirmed / on-chain zero-conf SCID.
1494
+ uint64 zero_conf_confirmed_scid = 33;
1461
1495
  }
1462
1496
 
1463
1497
  message ListChannelsRequest {
@@ -1477,6 +1511,22 @@ message ListChannelsResponse {
1477
1511
  repeated Channel channels = 11;
1478
1512
  }
1479
1513
 
1514
+ message AliasMap {
1515
+ /*
1516
+ For non-zero-conf channels, this is the confirmed SCID. Otherwise, this is
1517
+ the first assigned "base" alias.
1518
+ */
1519
+ uint64 base_scid = 1;
1520
+
1521
+ // The set of all aliases stored for the base SCID.
1522
+ repeated uint64 aliases = 2;
1523
+ }
1524
+ message ListAliasesRequest {
1525
+ }
1526
+ message ListAliasesResponse {
1527
+ repeated AliasMap alias_maps = 1;
1528
+ }
1529
+
1480
1530
  enum Initiator {
1481
1531
  INITIATOR_UNKNOWN = 0;
1482
1532
  INITIATOR_LOCAL = 1;
@@ -1541,6 +1591,15 @@ message ChannelCloseSummary {
1541
1591
  Initiator close_initiator = 12;
1542
1592
 
1543
1593
  repeated Resolution resolutions = 13;
1594
+
1595
+ /*
1596
+ This lists out the set of alias short channel ids that existed for the
1597
+ closed channel. This may be empty.
1598
+ */
1599
+ repeated uint64 alias_scids = 14;
1600
+
1601
+ // The confirmed SCID for a zero-conf channel.
1602
+ uint64 zero_conf_confirmed_scid = 15 [jstype = JS_STRING];
1544
1603
  }
1545
1604
 
1546
1605
  enum ResolutionType {
@@ -2097,6 +2156,17 @@ message OpenChannelRequest {
2097
2156
  the remote peer supports explicit channel negotiation.
2098
2157
  */
2099
2158
  CommitmentType commitment_type = 18;
2159
+
2160
+ /*
2161
+ If this is true, then a zero-conf channel open will be attempted.
2162
+ */
2163
+ bool zero_conf = 19;
2164
+
2165
+ /*
2166
+ If this is true, then an option-scid-alias channel-type open will be
2167
+ attempted.
2168
+ */
2169
+ bool scid_alias = 20;
2100
2170
  }
2101
2171
  message OpenStatusUpdate {
2102
2172
  oneof update {
@@ -320,7 +320,10 @@ message InputScriptResp {
320
320
  }
321
321
 
322
322
  message SignMessageReq {
323
- // The message to be signed.
323
+ /*
324
+ The message to be signed. When using REST, this field must be encoded as
325
+ base64.
326
+ */
324
327
  bytes msg = 1;
325
328
 
326
329
  // The key locator that identifies which key to use for signing.
@@ -331,9 +334,21 @@ message SignMessageReq {
331
334
 
332
335
  /*
333
336
  Use the compact (pubkey recoverable) format instead of the raw lnwire
334
- format.
337
+ format. This option cannot be used with Schnorr signatures.
335
338
  */
336
339
  bool compact_sig = 4;
340
+
341
+ /*
342
+ Use Schnorr signature. This option cannot be used with compact format.
343
+ */
344
+ bool schnorr_sig = 5;
345
+
346
+ /*
347
+ The optional Taproot tweak bytes to apply to the private key before creating
348
+ a Schnorr signature. The private key is tweaked as described in BIP-341:
349
+ privKey + h_tapTweak(internalKey || tapTweak)
350
+ */
351
+ bytes schnorr_sig_tap_tweak = 6;
337
352
  }
338
353
  message SignMessageResp {
339
354
  /*
@@ -343,17 +358,28 @@ message SignMessageResp {
343
358
  }
344
359
 
345
360
  message VerifyMessageReq {
346
- // The message over which the signature is to be verified.
361
+ // The message over which the signature is to be verified. When using
362
+ // REST, this field must be encoded as base64.
347
363
  bytes msg = 1;
348
364
 
349
365
  /*
350
366
  The fixed-size LN wire encoded signature to be verified over the given
351
- message.
367
+ message. When using REST, this field must be encoded as base64.
352
368
  */
353
369
  bytes signature = 2;
354
370
 
355
- // The public key the signature has to be valid for.
371
+ /*
372
+ The public key the signature has to be valid for. When using REST, this
373
+ field must be encoded as base64. If the is_schnorr_sig option is true, then
374
+ the public key is expected to be in the 32-byte x-only serialization
375
+ according to BIP-340.
376
+ */
356
377
  bytes pubkey = 3;
378
+
379
+ /*
380
+ Specifies if the signature is a Schnorr signature.
381
+ */
382
+ bool is_schnorr_sig = 4;
357
383
  }
358
384
  message VerifyMessageResp {
359
385
  // Whether the signature was valid over the given message.
package/index.js CHANGED
@@ -41,6 +41,7 @@ const {getChannelBalance} = require('./lnd_methods');
41
41
  const {getChannels} = require('./lnd_methods');
42
42
  const {getClosedChannels} = require('./lnd_methods');
43
43
  const {getConnectedWatchtowers} = require('./lnd_methods');
44
+ const {getEphemeralChannelIds} = require('./lnd_methods');
44
45
  const {getFailedPayments} = require('./lnd_methods');
45
46
  const {getFeeRates} = require('./lnd_methods');
46
47
  const {getForwardingConfidence} = require('./lnd_methods');
@@ -183,11 +184,12 @@ module.exports = {
183
184
  getChainFeeEstimate,
184
185
  getChainFeeRate,
185
186
  getChainTransactions,
186
- getChannelBalance,
187
187
  getChannel,
188
+ getChannelBalance,
188
189
  getChannels,
189
190
  getClosedChannels,
190
191
  getConnectedWatchtowers,
192
+ getEphemeralChannelIds,
191
193
  getFailedPayments,
192
194
  getFeeRates,
193
195
  getForwardingConfidence,
@@ -39,6 +39,7 @@ const {getChannelBalance} = require('./offchain');
39
39
  const {getChannels} = require('./offchain');
40
40
  const {getClosedChannels} = require('./offchain');
41
41
  const {getConnectedWatchtowers} = require('./offchain');
42
+ const {getEphemeralChannelIds} = require('./offchain');
42
43
  const {getFailedPayments} = require('./offchain');
43
44
  const {getFeeRates} = require('./offchain');
44
45
  const {getForwardingConfidence} = require('./offchain');
@@ -182,6 +183,7 @@ module.exports = {
182
183
  getChannels,
183
184
  getClosedChannels,
184
185
  getConnectedWatchtowers,
186
+ getEphemeralChannelIds,
185
187
  getFailedPayments,
186
188
  getFeeRates,
187
189
  getForwardingConfidence,
@@ -8,7 +8,7 @@ export type GetNetworkGraphResult = {
8
8
  /** Standard Format Channel Id */
9
9
  id: string;
10
10
  policies: {
11
- /** Bae Fee Millitokens */
11
+ /** Base Fee Millitokens */
12
12
  base_fee_mtokens?: string;
13
13
  /** CLTV Height Delta */
14
14
  cltv_delta?: number;
@@ -2,12 +2,15 @@ const EventEmitter = require('events');
2
2
 
3
3
  const asyncDoUntil = require('async/doUntil');
4
4
 
5
- const {rpcInvoiceAsInvoice} = require('./../../lnd_responses');
5
+ const {handleRemoveListener} = require('./../../grpc');
6
6
  const {isLnd} = require('./../../lnd_requests');
7
+ const {rpcInvoiceAsInvoice} = require('./../../lnd_responses');
7
8
 
8
9
  const connectionFailureMessage = 'failed to connect to all addresses';
10
+ const events = ['end', 'error', 'invoice_updated', 'status'];
9
11
  const msPerSec = 1e3;
10
12
  const restartSubscriptionMs = 1000 * 30;
13
+ const sumOf = arr => arr.reduce((sum, n) => sum + n, Number());
11
14
  const updateEvent = 'invoice_updated';
12
15
 
13
16
  /** Subscribe to invoices
@@ -94,6 +97,9 @@ module.exports = args => {
94
97
  settle_index: !!confirmedAfter ? confirmedAfter.toString() : undefined,
95
98
  });
96
99
 
100
+ // Terminate subscription when all listeners are removed
101
+ handleRemoveListener({subscription, events, emitter: eventEmitter});
102
+
97
103
  // Subscription finished callback
98
104
  const finished = err => {
99
105
  if (!!eventEmitter.listenerCount('error')) {
@@ -107,14 +113,30 @@ module.exports = args => {
107
113
 
108
114
  isFinished = true;
109
115
 
116
+ const listenerCount = eventEmitter.listenerCount(updateEvent);
117
+
118
+ // Exit early when there are no listeners
119
+ if (!listenerCount) {
120
+ return cbk(null, {listener_count: listenerCount});
121
+ }
122
+
123
+ // Delay restart when there are listeners
110
124
  return setTimeout(() => {
111
- return cbk(null, {
112
- listener_count: eventEmitter.listenerCount(updateEvent),
113
- });
125
+ return cbk(null, {listener_count: listenerCount});
114
126
  },
115
127
  args.restart_delay_ms || restartSubscriptionMs);
116
128
  };
117
129
 
130
+ // Finish early when all listeners are removed
131
+ eventEmitter.on('removeListener', () => {
132
+ // Exit early when there are still active listeners
133
+ if (!!sumOf(events.map(n => eventEmitter.listenerCount(n)))) {
134
+ return;
135
+ }
136
+
137
+ return finished();
138
+ });
139
+
118
140
  // Relay invoice updates to the emitter
119
141
  subscription.on('data', invoice => {
120
142
  try {
@@ -157,6 +157,10 @@
157
157
  "methods": ["ListTowers", "Policy", "Stats"],
158
158
  "type": "tower_client"
159
159
  },
160
+ "getEphemeralChannelIds": {
161
+ "method": "ListAliases",
162
+ "type": "default"
163
+ },
160
164
  "getFailedPayments": {
161
165
  "method": "ListPayments",
162
166
  "type": "default"
@@ -44,7 +44,7 @@ export type GetChannelsResult = {
44
44
  local_balance: number;
45
45
  /** Local CSV Blocks Delay */
46
46
  local_csv?: number;
47
- /** Remote Non-Enforceable Amount Tokens */
47
+ /** Local Non-Enforceable Amount Tokens */
48
48
  local_dust?: number;
49
49
  /** Local Initially Pushed Tokens */
50
50
  local_given?: number;
@@ -15,6 +15,8 @@ const type = 'default';
15
15
  `in_channel`, `in_payment`, `is_forward`, `out_channel`, `out_payment`,
16
16
  `payment` are not supported on LND 0.11.1 and below
17
17
 
18
+ `is_trusted_funding` is not supported on LND 0.15.0 and below
19
+
18
20
  {
19
21
  [is_active]: <Limit Results To Only Active Channels Bool> // false
20
22
  [is_offline]: <Limit Results To Only Offline Channels Bool> // false
@@ -38,14 +40,16 @@ const type = 'default';
38
40
  is_opening: <Channel Is Opening Bool>
39
41
  is_partner_initiated: <Channel Partner Opened Channel Bool>
40
42
  is_private: <Channel Is Private Bool>
43
+ [is_trusted_funding]: <Funding Output is Trusted Bool>
41
44
  local_balance: <Local Balance Tokens Number>
42
45
  [local_csv]: <Local CSV Blocks Delay Number>
43
- [local_dust]: <Remote Non-Enforceable Amount Tokens Number>
46
+ [local_dust]: <Local Non-Enforceable Amount Tokens Number>
44
47
  [local_given]: <Local Initially Pushed Tokens Number>
45
48
  [local_max_htlcs]: <Local Maximum Attached HTLCs Number>
46
49
  [local_max_pending_mtokens]: <Local Maximum Pending Millitokens String>
47
50
  [local_min_htlc_mtokens]: <Local Minimum HTLC Millitokens String>
48
51
  local_reserve: <Local Reserved Tokens Number>
52
+ other_ids: [<Other Channel Id String>]
49
53
  partner_public_key: <Channel Partner Public Key String>
50
54
  past_states: <Total Count of Past Channel States Number>
51
55
  pending_payments: [{
@@ -17,6 +17,8 @@ const outpointSeparator = ':';
17
17
 
18
18
  Requires `offchain:read` permission
19
19
 
20
+ `other_ids is not supported on LND 0.15.0 and below
21
+
20
22
  {
21
23
  [is_breach_close]: <Only Return Breach Close Channels Bool>
22
24
  [is_cooperative_close]: <Only Return Cooperative Close Channels Bool>
@@ -54,6 +56,7 @@ const outpointSeparator = ':';
54
56
  [is_partner_closed]: <Channel Was Closed By Channel Peer Bool>
55
57
  [is_partner_initiated]: <Channel Was Initiated By Channel Peer Bool>
56
58
  is_remote_force_close: <Is Remote Force Close Bool>
59
+ other_ids: [<Other Channel Id String>]
57
60
  partner_public_key: <Partner Public Key Hex String>
58
61
  transaction_id: <Channel Funding Transaction Id Hex String>
59
62
  transaction_vout: <Channel Funding Output Index Number>
@@ -101,6 +104,10 @@ module.exports = (args, cbk) => {
101
104
  // Map channels
102
105
  mapChannels: ['getClosedChannels', ({getClosedChannels}, cbk) => {
103
106
  return asyncMapSeries(getClosedChannels, (chan, cbk) => {
107
+ if (!isArray(chan.alias_scids)) {
108
+ return cbk([503, 'ExpectedArrayOfAliasShortChannelIds']);
109
+ }
110
+
104
111
  if (!chan.capacity) {
105
112
  return cbk([503, 'ExpectedCloseChannelCapacity']);
106
113
  }
@@ -133,6 +140,10 @@ module.exports = (args, cbk) => {
133
140
  return cbk([503, 'ExpectedFinalTimeLockedBalanceForClosedChan']);
134
141
  }
135
142
 
143
+ const otherIds = chan.alias_scids
144
+ .filter(n => n !== chan.zero_conf_confirmed_scid)
145
+ .map(number => chanFormat({number}));
146
+
136
147
  const closer = chan.close_initiator;
137
148
  const finalTimeLock = Number(chan.time_locked_balance);
138
149
  const hasCloseTx = chan.closing_tx_hash !== emptyTxId;
@@ -141,11 +152,14 @@ module.exports = (args, cbk) => {
141
152
  let isPartnerClosed;
142
153
  let isPartnerInitiated;
143
154
  const [txId, vout] = chan.channel_point.split(outpointSeparator);
155
+ const zeroConfId = chan.zero_conf_confirmed_scid;
144
156
 
145
- const chanId = !hasId ? null : chanFormat({number: chan.chan_id});
146
157
  const closeTxId = !hasCloseTx ? undefined : chan.closing_tx_hash;
147
158
  const isLocalCooperativeClose = closer === 'INITIATOR_LOCAL';
148
159
  const isRemoteCooperativeClose = closer === 'INITIATOR_REMOTE';
160
+ const number = !!Number(zeroConfId) ? zeroConfId : chan.chan_id;
161
+
162
+ const chanId = !hasId ? null : chanFormat({number});
149
163
 
150
164
  // Try and determine if the channel was opened by our peer
151
165
  if (chan.open_initiator === 'INITIATOR_LOCAL') {
@@ -197,6 +211,7 @@ module.exports = (args, cbk) => {
197
211
  is_partner_closed: isPartnerClosed,
198
212
  is_partner_initiated: isPartnerInitiated,
199
213
  is_remote_force_close: chan.close_type === 'REMOTE_FORCE_CLOSE',
214
+ other_ids: otherIds.map(n => n.channel),
200
215
  partner_public_key: chan.remote_pubkey,
201
216
  transaction_id: txId,
202
217
  transaction_vout: Number(vout),
@@ -0,0 +1,86 @@
1
+ const asyncAuto = require('async/auto');
2
+ const {chanFormat} = require('bolt07');
3
+ const {returnResult} = require('asyncjs-util');
4
+
5
+ const {isLnd} = require('./../../lnd_requests');
6
+
7
+ const {isArray} = Array;
8
+ const method = 'listAliases';
9
+ const notSupported = /unknown/;
10
+ const type = 'default';
11
+
12
+ /** Get ephemeral channel ids
13
+
14
+ Requires `offchain:read` permission
15
+
16
+ This method is not supported on LND 0.15.0 and below
17
+
18
+ {
19
+ lnd: <Authenticated LND API Object>
20
+ }
21
+
22
+ @returns via cbk or Promise
23
+ {
24
+ channels: [{
25
+ other_ids: [<Channel Identifier String>]
26
+ reference_id: <Top Level Channel Identifier String>
27
+ }]
28
+ }
29
+ */
30
+ module.exports = (args, cbk) => {
31
+ return new Promise((resolve, reject) => {
32
+ return asyncAuto({
33
+ // Check arguments
34
+ validate: cbk => {
35
+ if (!isLnd({method, type, lnd: args.lnd})) {
36
+ return cbk([400, 'ExpectedAuthenticatedLndToGetChannelIds']);
37
+ }
38
+
39
+ return cbk();
40
+ },
41
+
42
+ // Get the list of channel ids
43
+ getChannelIds: ['validate', ({}, cbk) => {
44
+ return args.lnd[type][method]({}, (err, res) => {
45
+ if (!!err && notSupported.test(err.details)) {
46
+ return cbk([501, 'ListAliasesMethodNotSupported']);
47
+ }
48
+
49
+ if (!!err) {
50
+ return cbk([503, 'UnexpectedGetChannelIdsError', {err}]);
51
+ }
52
+
53
+ if (!res || !isArray(res.alias_maps)) {
54
+ return cbk([503, 'ExpectedChannelMapsArray']);
55
+ }
56
+
57
+ try {
58
+ const channels = res.alias_maps.map(map => {
59
+ if (!isArray(map.aliases)) {
60
+ throw new Error('ExpectedArrayOfAliasesInAliasMap');
61
+ }
62
+
63
+ if (!map.base_scid) {
64
+ throw new Error('ExpectedBaseScidInAliasMap');
65
+ }
66
+
67
+ const otherIds = map.aliases
68
+ .filter(n => n !== map.base_scid)
69
+ .map(number => chanFormat({number}).channel);
70
+
71
+ return {
72
+ other_ids: otherIds,
73
+ reference_id: chanFormat({number: map.base_scid}).channel,
74
+ };
75
+ });
76
+
77
+ return cbk(null, {channels});
78
+ } catch (err) {
79
+ return cbk([503, err.message]);
80
+ }
81
+ });
82
+ }],
83
+ },
84
+ returnResult({reject, resolve, of: 'getChannelIds'}, cbk));
85
+ });
86
+ };
@@ -15,6 +15,7 @@ const getChannelBalance = require('./get_channel_balance');
15
15
  const getChannels = require('./get_channels');
16
16
  const getClosedChannels = require('./get_closed_channels');
17
17
  const getConnectedWatchtowers = require('./get_connected_watchtowers');
18
+ const getEphemeralChannelIds = require('./get_ephemeral_channel_ids');
18
19
  const getFailedPayments = require('./get_failed_payments');
19
20
  const getFeeRates = require('./get_fee_rates');
20
21
  const getForwardingConfidence = require('./get_forwarding_confidence');
@@ -71,6 +72,7 @@ module.exports = {
71
72
  getChannels,
72
73
  getClosedChannels,
73
74
  getConnectedWatchtowers,
75
+ getEphemeralChannelIds,
74
76
  getFailedPayments,
75
77
  getFeeRates,
76
78
  getForwardingConfidence,
@@ -29,6 +29,8 @@ const updateOpening = 'pending_open_channel';
29
29
  lnd: <Authenticated LND API Object>
30
30
  }
31
31
 
32
+ `is_trusted_funding`, `other_ids` are not supported on LND 0.15.0 and below
33
+
32
34
  @throws
33
35
  <Error>
34
36
 
@@ -69,6 +71,7 @@ const updateOpening = 'pending_open_channel';
69
71
  is_partner_closed: <Channel Was Closed By Channel Peer Bool>
70
72
  is_partner_initiated: <Channel Was Initiated By Channel Peer Bool>
71
73
  is_remote_force_close: <Is Remote Force Close Bool>
74
+ other_ids: [<Other Channel Id String>]
72
75
  partner_public_key: <Partner Public Key Hex String>
73
76
  transaction_id: <Channel Funding Transaction Id Hex String>
74
77
  transaction_vout: <Channel Funding Output Index Number>
@@ -87,6 +90,7 @@ const updateOpening = 'pending_open_channel';
87
90
  is_opening: <Channel Is Opening Bool>
88
91
  is_partner_initiated: <Channel Partner Opened Channel Bool>
89
92
  is_private: <Channel Is Private Bool>
93
+ [is_trusted_funding]: <Funding Output is Trusted Bool>
90
94
  local_balance: <Local Balance Tokens Number>
91
95
  local_given: <Local Initially Pushed Tokens Number>
92
96
  local_reserve: <Local Reserved Tokens Number>
@@ -19,6 +19,8 @@ const type = 'default';
19
19
 
20
20
  LND 0.11.1 and below do not support `accept` or `reject` arguments
21
21
 
22
+ LND 0.15.0 and below do not support `is_trusted_funding`
23
+
22
24
  {
23
25
  lnd: <Authenticated LND API Object>
24
26
  }
@@ -33,6 +35,7 @@ const type = 'default';
33
35
  {
34
36
  accept: <Accept Request Function> ({
35
37
  [cooperative_close_address]: <Restrict Coop Close To Address String>
38
+ [is_trusted_funding]: <Accept Funding as Trusted Bool>
36
39
  [min_confirmations]: <Required Confirmations Before Channel Open Number>
37
40
  [remote_csv]: <Peer Unilateral Balance Output CSV Delay Number>
38
41
  [remote_reserve]: <Minimum Tokens Peer Must Keep On Their Side Number>
@@ -46,6 +49,7 @@ const type = 'default';
46
49
  csv_delay: <CSV Delay Blocks Number>
47
50
  id: <Request Id Hex String>
48
51
  is_private: <Incoming Channel Is Private Bool>
52
+ is_trusted_funding: <Request Immediate Trusted Funding Bool>
49
53
  local_balance: <Channel Local Tokens Balance Number>
50
54
  local_reserve: <Channel Local Reserve Tokens Number>
51
55
  max_pending_mtokens: <Maximum Millitokens Pending In Channel String>
@@ -94,6 +98,7 @@ module.exports = ({lnd}) => {
94
98
  accept: true,
95
99
  csv_delay: params.remote_csv || undefined,
96
100
  in_flight_max_msat: params.remote_max_pending_mtokens || undefined,
101
+ zero_conf: params.is_trusted_funding || undefined,
97
102
  max_htlc_count: params.remote_max_htlcs || undefined,
98
103
  min_accept_depth: params.min_confirmations || undefined,
99
104
  min_htlc_in: params.remote_min_htlc_mtokens || undefined,
@@ -108,6 +113,7 @@ module.exports = ({lnd}) => {
108
113
  csv_delay: request.csv_delay,
109
114
  id: request.id,
110
115
  is_private: request.is_private,
116
+ is_trusted_funding: request.is_trusted_funding,
111
117
  local_balance: request.local_balance,
112
118
  local_reserve: request.local_reserve,
113
119
  max_pending_mtokens: request.max_pending_mtokens,
@@ -32,12 +32,17 @@ const type = 'default';
32
32
  Use `is_avoiding_broadcast` only when self-publishing the raw transaction
33
33
  after the funding step.
34
34
 
35
+ `is_trusted_funding` is not supported on LND 0.15.0 and below and requires
36
+ `--protocol.option-scid-alias` and `--protocol.zero-conf` set on both sides
37
+ as well as a channel open request listener to accept the trusted funding.
38
+
35
39
  {
36
40
  channels: [{
37
41
  capacity: <Channel Capacity Tokens Number>
38
42
  [cooperative_close_address]: <Restrict Coop Close To Address String>
39
43
  [give_tokens]: <Tokens to Gift To Partner Number> // Defaults to zero
40
44
  [is_private]: <Channel is Private Bool> // Defaults to false
45
+ [is_trusted_funding]: <Peer Should Avoid Waiting For Confirmation Bool>
41
46
  [min_htlc_mtokens]: <Minimum HTLC Millitokens String>
42
47
  [partner_csv_delay]: <Peer Output CSV Delay Number>
43
48
  partner_public_key: <Public Key Hex String>
@@ -91,6 +96,7 @@ module.exports = (args, cbk) => {
91
96
  cooperative_close_address: channel.cooperative_close_address,
92
97
  give_tokens: channel.give_tokens,
93
98
  is_private: channel.is_private,
99
+ is_trusted_funding: channel.is_trusted_funding,
94
100
  min_htlc_mtokens: channel.min_htlc_mtokens,
95
101
  partner_public_key: channel.partner_public_key,
96
102
  partner_csv_delay: channel.partner_csv_delay,
@@ -107,6 +113,7 @@ module.exports = (args, cbk) => {
107
113
 
108
114
  const channelOpen = args.lnd[type][method]({
109
115
  close_address: channel.cooperative_close_address || undefined,
116
+ commitment_type: channel.is_trusted_funding ? 'ANCHORS' : undefined,
110
117
  funding_shim: {
111
118
  psbt_shim: {
112
119
  no_publish: !!isSelfPublish || !channel.id.equals(lastChannel),
@@ -119,6 +126,8 @@ module.exports = (args, cbk) => {
119
126
  private: !!channel.is_private,
120
127
  push_sat: channel.give_tokens || undefined,
121
128
  remote_csv_delay: channel.partner_csv_delay || undefined,
129
+ scid_alias: channel.is_trusted_funding && channel.is_private,
130
+ zero_conf: channel.is_trusted_funding || undefined,
122
131
  });
123
132
 
124
133
  const done = (err, res) => {
@@ -23,6 +23,7 @@ const weightPerVByte = 4;
23
23
  node_pubkey: <Peer Public Key Bytes Buffer Object>
24
24
  pending_chan_id: <Temporary Pending Id Bytes Buffer Object>
25
25
  push_amt: <Gifted Millitokens From Peer String>
26
+ wants_zero_conf: <Request Is Trusted Funding Bool>
26
27
  }
27
28
 
28
29
  @throws
@@ -36,6 +37,7 @@ const weightPerVByte = 4;
36
37
  csv_delay: <CSV Delay Blocks Number>
37
38
  id: <Request Id Hex String>
38
39
  is_private: <Incoming Channel Is Private Bool>
40
+ is_trusted_funding: <Accept Funding as Trusted Bool>
39
41
  local_balance: <Channel Local Tokens Balance Number>
40
42
  local_reserve: <Channel Local Reserve Tokens Number>
41
43
  max_pending_mtokens: <Maximum Millitokens Pending In Channel String>
@@ -115,6 +117,7 @@ module.exports = data => {
115
117
  csv_delay: data.csv_delay,
116
118
  id: bufferAsHex(data.pending_chan_id),
117
119
  is_private: !(data.channel_flags & privateChannel),
120
+ is_trusted_funding: !!data.wants_zero_conf,
118
121
  local_balance: millitokensAsTokens(data.push_amt),
119
122
  local_reserve: Number(data.channel_reserve),
120
123
  max_pending_mtokens: data.max_value_in_flight,
@@ -12,6 +12,7 @@ const outpointDelimiter = ':';
12
12
 
13
13
  {
14
14
  active: <Channel Is Active Bool>
15
+ alias_scids: [<Channel Id Number String>]
15
16
  capacity: <Capacity Tokens String>
16
17
  chan_id: <Numeric Format Channel String>
17
18
  channel_point: <Channel Funding Outpoint String>
@@ -60,6 +61,7 @@ const outpointDelimiter = ':';
60
61
  total_satoshis_sent: <Total Tokens Transferred Outbound String>
61
62
  unsettled_balance: <Balance In Transaction Tokens String>
62
63
  uptime: <Channel Internal Monitoring Channel Active Seconds Number>
64
+ zero_conf_confirmed_scid: <Trusted Channel Confirmed Id Number String>
63
65
  }
64
66
 
65
67
  @throws
@@ -78,6 +80,7 @@ const outpointDelimiter = ':';
78
80
  is_opening: <Channel Is Opening Bool>
79
81
  is_partner_initiated: <Channel Partner Opened Channel Bool>
80
82
  is_private: <Channel Is Private Bool>
83
+ [is_trusted_funding]: <Funding Output is Trusted Bool>
81
84
  local_balance: <Local Balance Tokens Number>
82
85
  local_csv: <Local CSV Blocks Delay Number>
83
86
  local_dust: <Remote Non-Enforceable Amount Tokens Number>
@@ -86,6 +89,7 @@ const outpointDelimiter = ':';
86
89
  local_max_pending_mtokens: <Local Maximum Pending Millitokens String>
87
90
  local_min_htlc_mtokens: <Local Minimum HTLC Millitokens String>
88
91
  local_reserve: <Local Reserved Tokens Number>
92
+ other_ids: [<Other Channel Id String>]
89
93
  partner_public_key: <Channel Partner Public Key String>
90
94
  past_states: <Total Count of Past States Number>
91
95
  pending_payments: [{
@@ -122,6 +126,10 @@ module.exports = args => {
122
126
  throw new Error('ExpectedChannelActiveStateInChannelMessage');
123
127
  }
124
128
 
129
+ if (!isArray(args.alias_scids)) {
130
+ throw new Error('ExpectedArrayOfAliasShortChannelIdsInChannelMessage');
131
+ }
132
+
125
133
  if (args.capacity === undefined) {
126
134
  throw new Error('ExpectedChannelCapacityInChannelMessage');
127
135
  }
@@ -210,21 +218,28 @@ module.exports = args => {
210
218
  const pushAmount = Number(args.push_amount_sat) || Number();
211
219
  const [transactionId, vout] = args.channel_point.split(outpointDelimiter);
212
220
  const uptime = Number(args.uptime) * msPerSec;
221
+ const zeroConfRealId = args.zero_conf_confirmed_scid;
213
222
 
223
+ const channelId = !!Number(zeroConfRealId) ? zeroConfRealId : args.chan_id;
214
224
  const downtime = Number(args.lifetime) * msPerSec - uptime;
215
225
 
226
+ const otherIds = args.alias_scids
227
+ .filter(n => n !== channelId)
228
+ .map(number => chanFormat({number}));
229
+
216
230
  return {
217
231
  capacity: Number(args.capacity),
218
232
  commit_transaction_fee: Number(args.commit_fee),
219
233
  commit_transaction_weight: commitWeight,
220
234
  cooperative_close_address: args.close_address || undefined,
221
235
  cooperative_close_delay_height: height,
222
- id: chanFormat({number: args.chan_id}).channel,
236
+ id: chanFormat({number: channelId}).channel,
223
237
  is_active: args.active,
224
238
  is_closing: false,
225
239
  is_opening: false,
226
240
  is_partner_initiated: !args.initiator,
227
241
  is_private: args.private,
242
+ is_trusted_funding: args.zero_conf || undefined,
228
243
  local_balance: Number(args.local_balance),
229
244
  local_csv: own.csv_delay,
230
245
  local_dust: Number(own.dust_limit_sat),
@@ -233,6 +248,7 @@ module.exports = args => {
233
248
  local_max_pending_mtokens: own.max_pending_amt_msat,
234
249
  local_min_htlc_mtokens: own.min_htlc_msat,
235
250
  local_reserve: Number(own.chan_reserve_sat),
251
+ other_ids: otherIds.map(n => n.channel),
236
252
  partner_public_key: args.remote_pubkey,
237
253
  past_states: Number(args.num_updates),
238
254
  pending_payments: args.pending_htlcs.map(rpcHtlcAsPayment),
@@ -9,6 +9,7 @@ const emptyTxId = Buffer.alloc(32).toString('hex');
9
9
  const fundingCanceled = 'FUNDING_CANCELED';
10
10
  const initiatorLocal = 'INITIATOR_LOCAL';
11
11
  const initiatorRemote = 'INITIATOR_REMOTE';
12
+ const {isArray} = Array;
12
13
  const local = 'LOCAL';
13
14
  const localForceClose = 'LOCAL_FORCE_CLOSE';
14
15
  const outpointSeparator = ':';
@@ -18,6 +19,7 @@ const remoteForceClose = 'REMOTE_FORCE_CLOSE';
18
19
  /** RPC closed local channel as close details
19
20
 
20
21
  {
22
+ alias_scids: [<Channel Id Number String>]
21
23
  capacity: <Channel Capacity Tokens String>
22
24
  chan_id: <Numeric Format Channel Id String>
23
25
  channel_point: <Channel Funding Outpoint String>
@@ -39,6 +41,7 @@ const remoteForceClose = 'REMOTE_FORCE_CLOSE';
39
41
  }]
40
42
  settled_balance: <Channel Close Settle Balance Tokens String>
41
43
  time_locked_balance: <Channel Time Locked Balance Tokens String>
44
+ zero_conf_confirmed_scid: <Trusted Channel Confirmed Id Number String>
42
45
  }
43
46
 
44
47
  @throws
@@ -71,6 +74,7 @@ const remoteForceClose = 'REMOTE_FORCE_CLOSE';
71
74
  [is_partner_closed]: <Channel Was Closed By Channel Peer Bool>
72
75
  [is_partner_initiated]: <Channel Was Initiated By Channel Peer Bool>
73
76
  is_remote_force_close: <Is Remote Force Close Bool>
77
+ other_ids: [<Other Channel Id String>]
74
78
  partner_public_key: <Partner Public Key Hex String>
75
79
  transaction_id: <Channel Funding Transaction Id Hex String>
76
80
  transaction_vout: <Channel Funding Output Index Number>
@@ -81,6 +85,10 @@ module.exports = chan => {
81
85
  throw new Error('ExpectedChannelCloseDetailsToDeriveClosedChannel');
82
86
  }
83
87
 
88
+ if (!isArray(chan.alias_scids)) {
89
+ throw new Error('ExpectedArrayOfAliasShortChannelIdsInClosedChannel');
90
+ }
91
+
84
92
  if (!chan.capacity) {
85
93
  throw new Error('ExpectedCloseChannelCapacity');
86
94
  }
@@ -113,6 +121,10 @@ module.exports = chan => {
113
121
  throw new Error('ExpectedFinalTimeLockedBalanceForClosedChan');
114
122
  }
115
123
 
124
+ const otherIds = chan.alias_scids
125
+ .filter(n => n !== chan.zero_conf_confirmed_scid)
126
+ .map(number => chanFormat({number}));
127
+
116
128
  const closer = chan.close_initiator;
117
129
  const finalTimeLock = Number(chan.time_locked_balance);
118
130
  const hasCloseTx = chan.closing_tx_hash !== emptyTxId;
@@ -121,11 +133,14 @@ module.exports = chan => {
121
133
  let isPartnerClosed;
122
134
  let isPartnerInitiated;
123
135
  const [txId, vout] = chan.channel_point.split(outpointSeparator);
136
+ const zeroConfId = chan.zero_conf_confirmed_scid;
124
137
 
125
- const chanId = !hasId ? null : chanFormat({number: chan.chan_id});
126
138
  const closeTxId = !hasCloseTx ? undefined : chan.closing_tx_hash;
127
139
  const isLocalCooperativeClose = closer === initiatorLocal;
128
140
  const isRemoteCooperativeClose = closer === initiatorRemote;
141
+ const number = !!Number(zeroConfId) ? zeroConfId : chan.chan_id;
142
+
143
+ const chanId = !hasId ? null : chanFormat({number});
129
144
 
130
145
  // Try and determine if the channel was opened by our peer
131
146
  if (chan.open_initiator === local) {
@@ -170,6 +185,7 @@ module.exports = chan => {
170
185
  is_partner_closed: isPartnerClosed,
171
186
  is_partner_initiated: isPartnerInitiated,
172
187
  is_remote_force_close: chan.close_type === remoteForceClose,
188
+ other_ids: otherIds.map(n => n.channel),
173
189
  partner_public_key: chan.remote_pubkey,
174
190
  transaction_id: txId,
175
191
  transaction_vout: Number(vout),
package/package.json CHANGED
@@ -7,15 +7,15 @@
7
7
  "url": "https://github.com/alexbosworth/lightning/issues"
8
8
  },
9
9
  "dependencies": {
10
- "@grpc/grpc-js": "1.6.7",
11
- "@grpc/proto-loader": "0.6.13",
10
+ "@grpc/grpc-js": "1.6.10",
11
+ "@grpc/proto-loader": "0.7.2",
12
12
  "@types/express": "4.17.13",
13
- "@types/node": "18.0.3",
13
+ "@types/node": "18.7.8",
14
14
  "@types/request": "2.48.8",
15
15
  "@types/ws": "8.5.3",
16
16
  "async": "3.2.4",
17
17
  "asyncjs-util": "1.2.10",
18
- "bitcoinjs-lib": "6.0.1",
18
+ "bitcoinjs-lib": "6.0.2",
19
19
  "bn.js": "5.2.1",
20
20
  "body-parser": "1.20.0",
21
21
  "bolt07": "1.8.2",
@@ -24,9 +24,9 @@
24
24
  "ecpair": "2.0.1",
25
25
  "express": "4.18.1",
26
26
  "invoices": "2.1.0",
27
- "psbt": "2.6.0",
27
+ "psbt": "2.7.1",
28
28
  "tiny-secp256k1": "2.2.1",
29
- "type-fest": "2.16.0"
29
+ "type-fest": "2.18.1"
30
30
  },
31
31
  "description": "Lightning Network client library",
32
32
  "devDependencies": {
@@ -34,7 +34,7 @@
34
34
  "@alexbosworth/tap": "15.0.11",
35
35
  "tsd": "0.22.0",
36
36
  "typescript": "4.7.4",
37
- "ws": "8.8.0"
37
+ "ws": "8.8.1"
38
38
  },
39
39
  "engines": {
40
40
  "node": ">=12.20"
@@ -59,5 +59,5 @@
59
59
  "directory": "test/typescript"
60
60
  },
61
61
  "types": "index.d.ts",
62
- "version": "5.16.4"
62
+ "version": "5.17.0"
63
63
  }
@@ -8,11 +8,21 @@ const tests = [
8
8
  description: 'Default mtokens is undefined',
9
9
  expected: {},
10
10
  },
11
+ {
12
+ args: {tokens: 0},
13
+ description: 'Tokens can be zero',
14
+ expected: {mtokens: '0'},
15
+ },
11
16
  {
12
17
  args: {tokens: 1},
13
18
  description: 'Tokens are converted to mtokens',
14
19
  expected: {mtokens: '1000'},
15
20
  },
21
+ {
22
+ args: {tokens: 'invalid number'},
23
+ description: 'Tokens must be a valid number',
24
+ error: 'ExpectedEitherTokensNumberOrMtokensStringForAmountValue',
25
+ },
16
26
  {
17
27
  args: {mtokens: '1000'},
18
28
  description: 'Mtokens are returned',
@@ -7,6 +7,8 @@ const {subscribeToInvoices} = require('./../../../');
7
7
 
8
8
  const emitter = new EventEmitter();
9
9
 
10
+ emitter.cancel = () => {};
11
+
10
12
  const makeLnd = ({err}) => ({default: {subscribeInvoices: ({}) => emitter}});
11
13
 
12
14
  const tests = [
@@ -15,6 +15,7 @@ const makeExpected = overrides => {
15
15
  is_opening: false,
16
16
  is_partner_initiated: false,
17
17
  is_private: true,
18
+ is_trusted_funding: undefined,
18
19
  local_balance: 1,
19
20
  local_csv: 1,
20
21
  local_dust: 1,
@@ -23,6 +24,7 @@ const makeExpected = overrides => {
23
24
  local_max_htlcs: 1,
24
25
  local_max_pending_mtokens: '1',
25
26
  local_reserve: 1,
27
+ other_ids: [],
26
28
  partner_public_key: 'b',
27
29
  past_states: 1,
28
30
  pending_payments: [{
@@ -62,6 +64,7 @@ const makeExpected = overrides => {
62
64
  const makeLnd = overrides => {
63
65
  const channel = {
64
66
  active: true,
67
+ alias_scids: [],
65
68
  capacity: 1,
66
69
  chan_id: '1',
67
70
  channel_point: '00:1',
@@ -4,6 +4,7 @@ const {getClosedChannels} = require('./../../../');
4
4
 
5
5
  const makeLnd = (err, override, response) => {
6
6
  const channel = {
7
+ alias_scids: [],
7
8
  capacity: '1',
8
9
  chan_id: '1',
9
10
  channel_point: '00:1',
@@ -56,6 +57,7 @@ const makeExpectedChannel = ({override}) => {
56
57
  is_partner_closed: true,
57
58
  is_partner_initiated: false,
58
59
  is_remote_force_close: false,
60
+ other_ids: [],
59
61
  partner_public_key: 'b',
60
62
  transaction_id: '00',
61
63
  transaction_vout: 1,
@@ -87,6 +89,11 @@ const tests = [
87
89
  description: 'A response with channels is expected',
88
90
  error: [503, 'ExpectedChannels'],
89
91
  },
92
+ {
93
+ args: makeArgs({override: {lnd: makeLnd(null, {alias_scids: undefined})}}),
94
+ description: 'Alias scids are expected',
95
+ error: [503, 'ExpectedArrayOfAliasShortChannelIds'],
96
+ },
90
97
  {
91
98
  args: makeArgs({override: {lnd: makeLnd(null, {capacity: undefined})}}),
92
99
  description: 'Capacity is expected',
@@ -144,6 +151,22 @@ const tests = [
144
151
  description: 'Closed channels are returned',
145
152
  expected: {channels: [makeExpectedChannel({})]},
146
153
  },
154
+ {
155
+ args: makeArgs({
156
+ override: {
157
+ lnd: makeLnd(null, {
158
+ alias_scids: ['2', '3'],
159
+ zero_conf_confirmed_scid: '2',
160
+ }),
161
+ },
162
+ }),
163
+ description: 'Closed channels with alias scids is returned',
164
+ expected: {
165
+ channels: [
166
+ makeExpectedChannel({override: {id: '0x0x2', other_ids: ['0x0x3']}}),
167
+ ],
168
+ },
169
+ },
147
170
  {
148
171
  args: makeArgs({
149
172
  override: {lnd: makeLnd(null, {close_type: 'REMOTE_FORCE_CLOSE'})},
@@ -0,0 +1,68 @@
1
+ const {test} = require('@alexbosworth/tap');
2
+
3
+ const {getEphemeralChannelIds} = require('./../../../lnd_methods');
4
+
5
+ const makeLnd = ({err, res}) => {
6
+ const response = {alias_maps: [{aliases: ['1', '2'], base_scid: '1'}]};
7
+
8
+ const r = res !== undefined ? res : response;
9
+
10
+ return {default: {listAliases: ({}, cbk) => cbk(err, r)}};
11
+ };
12
+
13
+ const tests = [
14
+ {
15
+ args: {},
16
+ description: 'LND object is required',
17
+ error: [400, 'ExpectedAuthenticatedLndToGetChannelIds'],
18
+ },
19
+ {
20
+ args: {lnd: makeLnd({err: {details: 'unknown'}})},
21
+ description: 'Not supported error is returned',
22
+ error: [501, 'ListAliasesMethodNotSupported'],
23
+ },
24
+ {
25
+ args: {lnd: makeLnd({err: 'err'})},
26
+ description: 'Unknown error is returned',
27
+ error: [503, 'UnexpectedGetChannelIdsError', {err: 'err'}],
28
+ },
29
+ {
30
+ args: {lnd: makeLnd({res: null})},
31
+ description: 'A response is expected',
32
+ error: [503, 'ExpectedChannelMapsArray'],
33
+ },
34
+ {
35
+ args: {lnd: makeLnd({res: {}})},
36
+ description: 'A response array is expected',
37
+ error: [503, 'ExpectedChannelMapsArray'],
38
+ },
39
+ {
40
+ args: {lnd: makeLnd({res: {alias_maps: [{}]}})},
41
+ description: 'Alias maps array is expected',
42
+ error: [503, 'ExpectedArrayOfAliasesInAliasMap'],
43
+ },
44
+ {
45
+ args: {lnd: makeLnd({res: {alias_maps: [{aliases: []}]}})},
46
+ description: 'A base scid is expected',
47
+ error: [503, 'ExpectedBaseScidInAliasMap'],
48
+ },
49
+ {
50
+ args: {lnd: makeLnd({})},
51
+ description: 'Channel ids are returned',
52
+ expected: {channels: [{other_ids: ['0x0x2'], reference_id: '0x0x1'}]},
53
+ },
54
+ ];
55
+
56
+ tests.forEach(({args, description, error, expected}) => {
57
+ return test(description, async ({end, rejects, strictSame}) => {
58
+ if (!!error) {
59
+ await rejects(getEphemeralChannelIds(args), error, 'Got expected error');
60
+ } else {
61
+ const res = await getEphemeralChannelIds(args);
62
+
63
+ strictSame(res, expected, 'Got expected result');
64
+ }
65
+
66
+ return end();
67
+ });
68
+ });
@@ -32,6 +32,7 @@ const makeLnd = ({data, err}) => {
32
32
 
33
33
  emitter.emit('data', {
34
34
  closed_channel: {
35
+ alias_scids: [],
35
36
  capacity: '1',
36
37
  chan_id: '1',
37
38
  channel_point: '00:0',
@@ -57,6 +58,7 @@ const makeLnd = ({data, err}) => {
57
58
  emitter.emit('data', {
58
59
  open_channel: {
59
60
  active: false,
61
+ alias_scids: [],
60
62
  capacity: '1',
61
63
  chan_id: '1',
62
64
  channel_point: `${Buffer.alloc(32).toString('hex')}:0`,
@@ -221,6 +223,7 @@ const tests = [
221
223
  is_partner_closed: undefined,
222
224
  is_partner_initiated: false,
223
225
  is_remote_force_close: false,
226
+ other_ids: [],
224
227
  partner_public_key: '000000000000000000000000000000000000000000000000000000000000000000',
225
228
  transaction_id: '00',
226
229
  transaction_vout: 0,
@@ -248,6 +251,7 @@ const tests = [
248
251
  is_opening: false,
249
252
  is_partner_initiated: false,
250
253
  is_private: false,
254
+ is_trusted_funding: undefined,
251
255
  local_balance: 1,
252
256
  local_csv: 1,
253
257
  local_dust: 1,
@@ -256,6 +260,7 @@ const tests = [
256
260
  local_max_pending_mtokens: '1',
257
261
  local_min_htlc_mtokens: '1',
258
262
  local_reserve: 1,
263
+ other_ids: [],
259
264
  partner_public_key: '000000000000000000000000000000000000000000000000000000000000000000',
260
265
  past_states: 1,
261
266
  pending_payments: [],
@@ -82,6 +82,7 @@ const tests = [
82
82
  csv_delay: 1,
83
83
  id: '0000000000000000000000000000000000000000000000000000000000000000',
84
84
  is_private: true,
85
+ is_trusted_funding: false,
85
86
  local_balance: 1,
86
87
  local_reserve: 1,
87
88
  max_pending_mtokens: '1000',
@@ -35,6 +35,7 @@ const tests = [
35
35
  csv_delay: 1,
36
36
  id: Buffer.alloc(32).toString('hex'),
37
37
  is_private: true,
38
+ is_trusted_funding: false,
38
39
  local_balance: 1,
39
40
  local_reserve: 1,
40
41
  max_pending_mtokens: '1000',
@@ -5,6 +5,7 @@ const {rpcChannelAsChannel} = require('./../../lnd_responses');
5
5
  const makeArgs = overrides => {
6
6
  const args = {
7
7
  active: true,
8
+ alias_scids: [],
8
9
  capacity: '1',
9
10
  chan_id: '1',
10
11
  channel_point: '00:1',
@@ -73,6 +74,7 @@ const makeExpected = overrides => {
73
74
  is_opening: false,
74
75
  is_partner_initiated: true,
75
76
  is_private: true,
77
+ is_trusted_funding: undefined,
76
78
  local_balance: 1,
77
79
  local_csv: 1,
78
80
  local_dust: 1,
@@ -81,6 +83,7 @@ const makeExpected = overrides => {
81
83
  local_max_pending_mtokens: '1',
82
84
  local_min_htlc_mtokens: '1',
83
85
  local_reserve: 1,
86
+ other_ids: [],
84
87
  partner_public_key: '00',
85
88
  past_states: 1,
86
89
  pending_payments: [{
@@ -123,6 +126,11 @@ const tests = [
123
126
  description: 'Channel active is expected',
124
127
  error: 'ExpectedChannelActiveStateInChannelMessage',
125
128
  },
129
+ {
130
+ args: makeArgs({alias_scids: undefined}),
131
+ description: 'Alias scids are expected',
132
+ error: 'ExpectedArrayOfAliasShortChannelIdsInChannelMessage',
133
+ },
126
134
  {
127
135
  args: makeArgs({capacity: undefined}),
128
136
  description: 'Channel capacity is expected',
@@ -228,6 +236,11 @@ const tests = [
228
236
  description: 'RPC channel is mapped to channel',
229
237
  expected: makeExpected({}),
230
238
  },
239
+ {
240
+ args: makeArgs({alias_scids: ['2', '3'], zero_conf_confirmed_scid: '2'}),
241
+ description: 'RPC channel is mapped to channel with scids',
242
+ expected: makeExpected({id: '0x0x2', other_ids: ['0x0x3']}),
243
+ },
231
244
  {
232
245
  args: makeArgs({commitment_type: 'STATIC_REMOTE_KEY', initiator: true}),
233
246
  description: 'Initiated RPC channel is mapped to channel',
@@ -4,6 +4,7 @@ const {rpcClosedChannelAsClosed} = require('./../../lnd_responses');
4
4
 
5
5
  const makeArgs = overrides => {
6
6
  const args = {
7
+ alias_scids: [],
7
8
  capacity: '1',
8
9
  chan_id: '1',
9
10
  channel_point: '0102:0',
@@ -59,6 +60,7 @@ const makeExpected = overrides => {
59
60
  is_partner_closed: false,
60
61
  is_partner_initiated: undefined,
61
62
  is_remote_force_close: false,
63
+ other_ids: [],
62
64
  partner_public_key: Buffer.alloc(33).toString('hex'),
63
65
  transaction_id: '0102',
64
66
  transaction_vout: 0,
@@ -75,6 +77,11 @@ const tests = [
75
77
  description: 'Channel close details expected',
76
78
  error: 'ExpectedChannelCloseDetailsToDeriveClosedChannel',
77
79
  },
80
+ {
81
+ args: makeArgs({alias_scids: undefined}),
82
+ description: 'Alias scids are expected',
83
+ error: 'ExpectedArrayOfAliasShortChannelIdsInClosedChannel',
84
+ },
78
85
  {
79
86
  args: makeArgs({capacity: undefined}),
80
87
  description: 'Channel capacity is expected',
@@ -120,6 +127,14 @@ const tests = [
120
127
  description: 'Local channel closed mapped to closed channel',
121
128
  expected: makeExpected({}),
122
129
  },
130
+ {
131
+ args: makeArgs({
132
+ alias_scids: ['2', '3'],
133
+ zero_conf_confirmed_scid: '2',
134
+ }),
135
+ description: 'Alias scids are mapped to other ids',
136
+ expected: makeExpected({id: '0x0x2', other_ids: ['0x0x3']}),
137
+ },
123
138
  {
124
139
  args: makeArgs({
125
140
  close_initiator: 'REMOTE',