lightning 5.15.1 → 5.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/CHANGELOG.md +5 -1
  2. package/README.md +14 -0
  3. package/grpc/protos/lightning.proto +19 -3
  4. package/grpc/protos/signer.proto +47 -9
  5. package/lnd_methods/address/create_chain_address.js +37 -1
  6. package/lnd_methods/info/get_route_to_destination.js +8 -0
  7. package/lnd_methods/macaroon/methods.json +1 -0
  8. package/lnd_methods/peers/add_external_socket.d.ts +20 -0
  9. package/lnd_methods/peers/index.d.ts +4 -0
  10. package/lnd_methods/peers/remove_external_socket.d.ts +20 -0
  11. package/lnd_methods/peers/update_alias.d.ts +11 -0
  12. package/lnd_methods/peers/update_color.d.ts +11 -0
  13. package/lnd_methods/signer/begin_group_signing_session.d.ts +33 -0
  14. package/lnd_methods/signer/end_group_signing_session.d.ts +21 -0
  15. package/lnd_methods/signer/index.d.ts +3 -0
  16. package/lnd_methods/signer/input_signing_method.js +42 -0
  17. package/lnd_methods/signer/sign_transaction.d.ts +3 -1
  18. package/lnd_methods/signer/sign_transaction.js +27 -20
  19. package/lnd_methods/signer/update_group_signing_session.d.ts +23 -0
  20. package/package.json +7 -7
  21. package/test/lnd_methods/address/test_create_chain_address.js +87 -0
  22. package/test/lnd_methods/info/test_get_route_to_destination.js +15 -0
  23. package/test/lnd_methods/signer/test_input_signing_method.js +53 -0
  24. package/test/typescript/add_external_socket.test-d.ts +14 -0
  25. package/test/typescript/begin_group_signing_session.test-d.ts +60 -0
  26. package/test/typescript/end_group_signing_session.test-d.ts +32 -0
  27. package/test/typescript/remove_external_socket.test-d.ts +14 -0
  28. package/test/typescript/sign_transaction.test-d.ts +0 -1
  29. package/test/typescript/update_alias.test-d.ts +14 -0
  30. package/test/typescript/update_color.test-d.ts +14 -0
  31. package/test/typescript/update_group_signing_session.test-d.ts +29 -0
package/CHANGELOG.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Versions
2
2
 
3
- ## 5.15.1
3
+ ## 5.16.1
4
+
5
+ - `signTransaction`: Add `root_hash` to support Taproot signatures with scripts
6
+
7
+ ## 5.15.2
4
8
 
5
9
  - `getFailedPayments`, `getPayments`, `getPendingPayments`: Remove
6
10
  `confirmed_at` date when a payment is not confirmed, add `created_at` and
package/README.md CHANGED
@@ -66,9 +66,13 @@ To access unauthenticated methods like the wallet unlocker, use
66
66
 
67
67
  ## Methods
68
68
 
69
+ - [addExternalSocket](https://github.com/alexbosworth/ln-service#addexternalsocket):
70
+ Add a new LN p2p network socket to node advertisement
69
71
  - [addPeer](https://github.com/alexbosworth/ln-service#addpeer): Connect to a new peer
70
72
  - [authenticatedLndGrpc](https://github.com/alexbosworth/ln-service#authenticatedlndgrpc):
71
73
  Instantiate connection to authenticated lnd methods.
74
+ - [beginGroupSigningSession](https://github.com/alexbosworth/ln-service#begingroupsigningsession):
75
+ Start a new MuSig2 signing session
72
76
  - [broadcastChainTransaction](https://github.com/alexbosworth/ln-service#broadcastchaintransaction):
73
77
  Publish an on-chain transaction to the network.
74
78
  - [cancelHodlInvoice](https://github.com/alexbosworth/ln-service#cancelhodlinvoice): Cancel an
@@ -111,6 +115,8 @@ To access unauthenticated methods like the wallet unlocker, use
111
115
  Remove a connected watchtower
112
116
  - [enableChannel](https://github.com/alexbosworth/ln-service#enablechannel): Signal forwarding
113
117
  enabled towards a peer.
118
+ - [endGroupSigningSession](https://github.com/alexbosworth/ln-service#endgroupsigningsession):
119
+ End a MuSig2 signing session
114
120
  - [fundPendingChannels](https://github.com/alexbosworth/ln-service#fundpendingchannels):
115
121
  Provide a signed funding source for opening channels.
116
122
  - [fundPsbt](https://github.com/alexbosworth/ln-service#fundpsbt): Make a PSBT with funds and
@@ -235,6 +241,8 @@ To access unauthenticated methods like the wallet unlocker, use
235
241
  Attempt to recover channel funds from a specific channel backup.
236
242
  - [recoverFundsFromChannels](https://github.com/alexbosworth/ln-service#recoverfundsfromchannels):
237
243
  Attempt to recover funds from multiple channels using a multiple channel backup.
244
+ - [removeExternalSocket](https://github.com/alexbosworth/ln-service#removeexternalsocket):
245
+ Remove a LN p2p network socket from the node advertisement
238
246
  - [removePeer](https://github.com/alexbosworth/ln-service#removepeer): Disconnect from a
239
247
  connected peer.
240
248
  - [requestChainFeeIncrease](https://github.com/alexbosworth/ln-service#requestchainfeeincrease):
@@ -313,10 +321,16 @@ To access unauthenticated methods like the wallet unlocker, use
313
321
  UTXO to allow it to be selected for spending again.
314
322
  - [unlockWallet](https://github.com/alexbosworth/ln-service#unlockwallet): Decrypt the wallet and
315
323
  start the daemon
324
+ - [updateAlias](https://github.com/alexbosworth/ln-service#updatealias):
325
+ Update the advertised node alias
316
326
  - [updateChainTransaction](https://github.com/alexbosworth/ln-service#updatechaintransaction):
317
327
  Edit the metadata of an on-chain transaction record.
328
+ - [updateColor](https://github.com/alexbosworth/ln-service#updatecolor):
329
+ Update the advertised node color
318
330
  - [updateConnectedWatchtower](https://github.com/alexbosworth/ln-service#updateconnectedwatchtower):
319
331
  Edit the settings on an added watchtower
332
+ - [updateGroupSigningSession](https://github.com/alexbosworth/ln-service#updategroupsigningsession):
333
+ Update a MuSig2 signing session with nonces and get a partial signature
320
334
  - [updatePathfindingSettings](https://github.com/alexbosworth/ln-service#updatepathfindingsettings):
321
335
  Edit the configuration for routing calculations
322
336
  - [updateRoutingFees](https://github.com/alexbosworth/ln-service#updateroutingfees): Set the
@@ -2369,9 +2369,6 @@ message PendingChannelsResponse {
2369
2369
  // The pending channel
2370
2370
  PendingChannel channel = 1;
2371
2371
 
2372
- // The height at which this channel will be confirmed
2373
- uint32 confirmation_height = 2;
2374
-
2375
2372
  /*
2376
2373
  The amount calculated to be paid in fees for the current set of
2377
2374
  commitment transactions. The fee amount is persisted with the channel
@@ -2390,6 +2387,9 @@ message PendingChannelsResponse {
2390
2387
  transaction. This value can later be updated once the channel is open.
2391
2388
  */
2392
2389
  int64 fee_per_kw = 6;
2390
+
2391
+ // Previously used for confirmation_height. Do not reuse.
2392
+ reserved 2;
2393
2393
  }
2394
2394
 
2395
2395
  message WaitingCloseChannel {
@@ -3633,6 +3633,14 @@ message ListPaymentsRequest {
3633
3633
  of the returned payments is always oldest first (ascending index order).
3634
3634
  */
3635
3635
  bool reversed = 4;
3636
+
3637
+ /*
3638
+ If set, all payments (complete and incomplete, independent of the
3639
+ max_payments parameter) will be counted. Note that setting this to true will
3640
+ increase the run time of the call significantly on systems that have a lot
3641
+ of payments, as all of them have to be iterated through to be counted.
3642
+ */
3643
+ bool count_total_payments = 5;
3636
3644
  }
3637
3645
 
3638
3646
  message ListPaymentsResponse {
@@ -3650,6 +3658,14 @@ message ListPaymentsResponse {
3650
3658
  as the index_offset to continue seeking forwards in the next request.
3651
3659
  */
3652
3660
  uint64 last_index_offset = 3;
3661
+
3662
+ /*
3663
+ Will only be set if count_total_payments in the request was set. Represents
3664
+ the total number of payments (complete and incomplete, independent of the
3665
+ number of payments requested in the query) currently present in the payments
3666
+ database.
3667
+ */
3668
+ uint64 total_num_payments = 4;
3653
3669
  }
3654
3670
 
3655
3671
  message DeletePaymentRequest {
@@ -137,6 +137,7 @@ service Signer {
137
137
  MuSig2Cleanup (experimental!) allows a caller to clean up a session early in
138
138
  cases where it's obvious that the signing session won't succeed and the
139
139
  resources can be released.
140
+
140
141
  NOTE: The MuSig2 BIP is not final yet and therefore this API must be
141
142
  considered to be HIGHLY EXPERIMENTAL and subject to change in upcoming
142
143
  releases. Backward compatibility is not guaranteed!
@@ -174,6 +175,32 @@ message TxOut {
174
175
  bytes pk_script = 2;
175
176
  }
176
177
 
178
+ enum SignMethod {
179
+ /*
180
+ Specifies that a SegWit v0 (p2wkh, np2wkh, p2wsh) input script should be
181
+ signed.
182
+ */
183
+ SIGN_METHOD_WITNESS_V0 = 0;
184
+
185
+ /*
186
+ Specifies that a SegWit v1 (p2tr) input should be signed by using the
187
+ BIP0086 method (commit to internal key only).
188
+ */
189
+ SIGN_METHOD_TAPROOT_KEY_SPEND_BIP0086 = 1;
190
+
191
+ /*
192
+ Specifies that a SegWit v1 (p2tr) input should be signed by using a given
193
+ taproot hash to commit to in addition to the internal key.
194
+ */
195
+ SIGN_METHOD_TAPROOT_KEY_SPEND = 2;
196
+
197
+ /*
198
+ Specifies that a SegWit v1 (p2tr) input should be spent using the script
199
+ path and that a specific leaf script should be signed for.
200
+ */
201
+ SIGN_METHOD_TAPROOT_SCRIPT_SPEND = 3;
202
+ }
203
+
177
204
  message SignDescriptor {
178
205
  /*
179
206
  A descriptor that precisely describes *which* key to use for signing. This
@@ -208,12 +235,23 @@ message SignDescriptor {
208
235
  */
209
236
  bytes double_tweak = 3;
210
237
 
238
+ /*
239
+ The 32 byte input to the taproot tweak derivation that is used to derive
240
+ the output key from an internal key: outputKey = internalKey +
241
+ tagged_hash("tapTweak", internalKey || tapTweak).
242
+
243
+ When doing a BIP 86 spend, this field can be an empty byte slice.
244
+
245
+ When doing a normal key path spend, with the output key committing to an
246
+ actual script root, then this field should be: the tapscript root hash.
247
+ */
248
+ bytes tap_tweak = 10;
249
+
211
250
  /*
212
251
  The full script required to properly redeem the output. This field will
213
- only be populated if a p2tr, p2wsh or a p2sh output is being signed. In case
214
- taproot_key_spend is set to true then this value must correspond to the
215
- taproot root hash (in case of a tapscript output) or the tap hashed internal
216
- public key (in case of a BIP-0086 output).
252
+ only be populated if a p2tr, p2wsh or a p2sh output is being signed. If a
253
+ taproot script path spend is being attempted, then this should be the raw
254
+ leaf script.
217
255
  */
218
256
  bytes witness_script = 4;
219
257
 
@@ -235,12 +273,12 @@ message SignDescriptor {
235
273
  int32 input_index = 8;
236
274
 
237
275
  /*
238
- Indicates that this should produce a signature that can be used for the key
239
- spend path of a taproot input. This requires the witness_script field to be
240
- set to the taproot root hash (in case of a tapscript output) or the tap
241
- hashed internal public key (in case of a BIP-0086 output).
276
+ The sign method specifies how the input should be signed. Depending on the
277
+ method, either the tap_tweak, witness_script or both need to be specified.
278
+ Defaults to SegWit v0 signing to be backward compatible with older RPC
279
+ clients.
242
280
  */
243
- bool taproot_key_spend = 9;
281
+ SignMethod sign_method = 9;
244
282
  }
245
283
 
246
284
  message SignReq {
@@ -6,7 +6,11 @@ const {isLnd} = require('./../../lnd_requests');
6
6
 
7
7
  const connectFailMessage = '14 UNAVAILABLE: Connect Failed';
8
8
  const defaultAddressFormat = 'p2wpkh';
9
+ const {isArray} = Array;
10
+ const isNeedingDerivationsCheck = format => format === 'p2tr';
11
+ const isTrSupported = n => !!n.find(n => n.address_type === 'TAPROOT_PUBKEY');
9
12
  const method = 'newAddress';
13
+ const notSupported = /unknown.*walletrpc.WalletKit/;
10
14
  const type = 'default';
11
15
 
12
16
  /** Create a new receive address.
@@ -42,6 +46,38 @@ module.exports = (args, cbk) => {
42
46
  return cbk();
43
47
  },
44
48
 
49
+ // Get account derivations to confirm P2TR support
50
+ checkFormat: ['validate', ({}, cbk) => {
51
+ // Exit early when there is no need to check the derivations
52
+ if (!isNeedingDerivationsCheck(args.format)) {
53
+ return cbk();
54
+ }
55
+
56
+ return args.lnd.wallet.listAccounts({}, (err, res) => {
57
+ if (!!err && notSupported.test(err.details)) {
58
+ return cbk([501, 'CreationOfTaprootAddressesUnsupported']);
59
+ }
60
+
61
+ if (!!err) {
62
+ return cbk([503, 'UnexpectedErrorCheckingTaprootSupport', {err}]);
63
+ }
64
+
65
+ if (!res) {
66
+ return cbk([503, 'ExpectedResultForDerivationPathsRequest']);
67
+ }
68
+
69
+ if (!isArray(res.accounts)) {
70
+ return cbk([503, 'ExpectedAccountsInDerivationPathsResult']);
71
+ }
72
+
73
+ if (!isTrSupported(res.accounts)) {
74
+ return cbk([501, 'ExpectedTaprootSupportingLndToCreateAddress']);
75
+ }
76
+
77
+ return cbk();
78
+ });
79
+ }],
80
+
45
81
  // Type
46
82
  type: ['validate', ({}, cbk) => {
47
83
  const format = args.format || defaultAddressFormat;
@@ -54,7 +90,7 @@ module.exports = (args, cbk) => {
54
90
  }],
55
91
 
56
92
  // Get the address
57
- createAddress: ['type', ({type}, cbk) => {
93
+ createAddress: ['checkFormat', 'type', ({type}, cbk) => {
58
94
  return args.lnd.default.newAddress({type}, (err, res) => {
59
95
  if (!!err && err.message === connectFailMessage) {
60
96
  return cbk([503, 'FailedToConnectToDaemonToCreateChainAddress']);
@@ -129,6 +129,14 @@ module.exports = (args, cbk) => {
129
129
  return cbk([400, 'ExpectedLndApiObjectToGetRouteToDestination']);
130
130
  }
131
131
 
132
+ if (!!args.outgoing_channel) {
133
+ try {
134
+ chanNumber({channel: args.outgoing_channel});
135
+ } catch (err) {
136
+ return cbk([400, 'ExpectedStandardFormatChannelIdForOutChannel']);
137
+ }
138
+ }
139
+
132
140
  if (!!args.total_mtokens && !args.payment) {
133
141
  return cbk([400, 'ExpectedTotalMtokensWithPaymentIdentifier']);
134
142
  }
@@ -34,6 +34,7 @@
34
34
  "type": "tower_client"
35
35
  },
36
36
  "createChainAddress": {
37
+ "depends_on": ["getMasterPublicKeys"],
37
38
  "method": "NewAddress",
38
39
  "type": "default"
39
40
  },
@@ -0,0 +1,20 @@
1
+ import {
2
+ AuthenticatedLightningArgs,
3
+ AuthenticatedLightningMethod,
4
+ } from '../../typescript/shared';
5
+
6
+ export type AddExternalSocketArgs = AuthenticatedLightningArgs<{
7
+ /** Add Socket Address String */
8
+ socket: string;
9
+ }>;
10
+
11
+ /**
12
+ * Add a new advertised p2p socket address
13
+ *
14
+ * Note: this method is not supported in LND versions 0.14.3 and below
15
+ *
16
+ * Requires LND built with `peersrpc` build tag
17
+ *
18
+ * Requires `peers:write` permissions
19
+ */
20
+ export const addExternalSocket: AuthenticatedLightningMethod<AddExternalSocketArgs>;
@@ -1,4 +1,8 @@
1
+ export * from './add_external_socket';
1
2
  export * from './add_peer';
2
3
  export * from './get_peers';
4
+ export * from './remove_external_socket';
3
5
  export * from './remove_peer';
4
6
  export * from './subscribe_to_peers';
7
+ export * from './update_alias';
8
+ export * from './update_color';
@@ -0,0 +1,20 @@
1
+ import {
2
+ AuthenticatedLightningArgs,
3
+ AuthenticatedLightningMethod,
4
+ } from '../../typescript/shared';
5
+
6
+ export type RemoveExternalSocketArgs = AuthenticatedLightningArgs<{
7
+ /** Remove Socket Address String */
8
+ socket: string;
9
+ }>;
10
+
11
+ /**
12
+ * Remove an existing advertised p2p socket address
13
+ *
14
+ * Note: this method is not supported in LND versions 0.14.3 and below
15
+ *
16
+ * Requires LND built with `peersrpc` build tag
17
+ *
18
+ * Requires `peers:write` permissions
19
+ */
20
+ export const removeExternalSocket: AuthenticatedLightningMethod<RemoveExternalSocketArgs>;
@@ -0,0 +1,11 @@
1
+ import {
2
+ AuthenticatedLightningArgs,
3
+ AuthenticatedLightningMethod,
4
+ } from '../../typescript/shared';
5
+
6
+ export type UpdateAliasArgs = AuthenticatedLightningArgs<{
7
+ /** Node Alias String */
8
+ node: string;
9
+ }>;
10
+
11
+ export const updateAlias: AuthenticatedLightningMethod<UpdateAliasArgs>;
@@ -0,0 +1,11 @@
1
+ import {
2
+ AuthenticatedLightningArgs,
3
+ AuthenticatedLightningMethod,
4
+ } from '../../typescript/shared';
5
+
6
+ export type UpdateColorArgs = AuthenticatedLightningArgs<{
7
+ /** Node Color String */
8
+ color: string;
9
+ }>;
10
+
11
+ export const updateColor: AuthenticatedLightningMethod<UpdateColorArgs>;
@@ -0,0 +1,33 @@
1
+ import {
2
+ AuthenticatedLightningArgs,
3
+ AuthenticatedLightningMethod,
4
+ } from '../../typescript/shared';
5
+
6
+ export type BeginGroupSigningSessionArgs = AuthenticatedLightningArgs<{
7
+ /** Key Is BIP 86 Key Spend Key Bool */
8
+ is_key_spend?: boolean;
9
+ /** HD Seed Key Family Number */
10
+ key_family: number;
11
+ /** Key Index Number */
12
+ key_index: number;
13
+ /** External Public Key Hex String */
14
+ public_keys: string[];
15
+ /** Taproot Script Root Hash Hex String */
16
+ root_hash?: string;
17
+ }>;
18
+
19
+ export type BeginGroupSigningSessionResult = {
20
+ /** Final Script or Top Level Public Key Hex String */
21
+ external_key: string;
22
+ /** Session Id Hex String */
23
+ id: string;
24
+ /** Internal Top Level Public Key Hex String */
25
+ internal_key?: string;
26
+ /** Session Compound Nonces Hex String */
27
+ nonce: string;
28
+ };
29
+
30
+ export const beginGroupSigningSession: AuthenticatedLightningMethod<
31
+ BeginGroupSigningSessionArgs,
32
+ BeginGroupSigningSessionResult
33
+ >;
@@ -0,0 +1,21 @@
1
+ import {
2
+ AuthenticatedLightningArgs,
3
+ AuthenticatedLightningMethod,
4
+ } from '../../typescript/shared';
5
+
6
+ export type EndGroupSigningSessionArgs = AuthenticatedLightningArgs<{
7
+ /** Session Id Hex String */
8
+ id: string;
9
+ /** Combine External Partial Signature Hex Strings */
10
+ signatures?: string[];
11
+ }>;
12
+
13
+ export type EndGroupSigningSessionResult = {
14
+ /** Combined Signature Hex String */
15
+ signature?: string;
16
+ };
17
+
18
+ export const endGroupSigningSession: AuthenticatedLightningMethod<
19
+ EndGroupSigningSessionArgs,
20
+ EndGroupSigningSessionResult
21
+ >;
@@ -1,4 +1,7 @@
1
+ export * from './begin_group_signing_session';
1
2
  export * from './diffie_hellman_compute_secret';
3
+ export * from './end_group_signing_session';
2
4
  export * from './sign_bytes';
3
5
  export * from './sign_transaction';
6
+ export * from './update_group_signing_session';
4
7
  export * from './verify_bytes_signature';
@@ -0,0 +1,42 @@
1
+ const v0SpendMethod = 0;
2
+ const v1Bip86Method = 1;
3
+ const v1SpendMethod = 2;
4
+ const v1ScriptSpend = 3;
5
+
6
+ /** Determine a signing method for an input
7
+
8
+ {
9
+ input: [{
10
+ [root_hash]: <Taproot Root Hash Hex String>
11
+ [witness_script]: <Witness Script Hex String>
12
+ }]
13
+ [outputs]: [{
14
+ pk_script: <UTXO Output Script Buffer Object>
15
+ value: <UTXO Tokens Number>
16
+ }]
17
+ }
18
+
19
+ @returns
20
+ {
21
+ method: <Signing Method Number>
22
+ }
23
+ */
24
+ module.exports = ({input, outputs}, cbk) => {
25
+ // Exit early when lack of previous outputs indicates a v0 spend
26
+ if (!outputs) {
27
+ return {method: v0SpendMethod};
28
+ }
29
+
30
+ // Exit early when no leaf script or script commitment is present
31
+ if (!input.root_hash && !input.witness_script) {
32
+ return {method: v1Bip86Method};
33
+ }
34
+
35
+ // Exit early when there is no leaf script, just a top level key spend
36
+ if (!input.witness_script) {
37
+ return {method: v1SpendMethod};
38
+ }
39
+
40
+ // Sign for a leaf script for a key that commits to the scripts root hash
41
+ return {method: v1ScriptSpend};
42
+ };
@@ -13,12 +13,14 @@ export type SignTransactionArgs = AuthenticatedLightningArgs<{
13
13
  output_script: string;
14
14
  /** Output Tokens */
15
15
  output_tokens: number;
16
+ /** Taproot Root Hash Hex String */
17
+ root_hash?: string;
16
18
  /** Sighash Type */
17
19
  sighash: number;
18
20
  /** Input Index To Sign */
19
21
  vin: number;
20
22
  /** Witness Script Hex String */
21
- witness_script: string;
23
+ witness_script?: string;
22
24
  }[];
23
25
  spending?: {
24
26
  /** Non-Internal Spend Output Script Hex String */
@@ -1,10 +1,11 @@
1
1
  const asyncAuto = require('async/auto');
2
2
  const {returnResult} = require('asyncjs-util');
3
3
 
4
+ const inputSigningMethod = require('./input_signing_method');
4
5
  const {isLnd} = require('./../../lnd_requests');
5
6
 
6
7
  const bufferAsHex = buffer => buffer.toString('hex');
7
- const hexAsBuffer = hex => Buffer.from(hex, 'hex');
8
+ const hexAsBuffer = hex => Buffer.from(hex || '', 'hex');
8
9
  const {isArray} = Array;
9
10
  const isV1 = scriptHex => scriptHex.length === 68 && /5120/.test(scriptHex);
10
11
  const method = 'signOutputRaw';
@@ -20,6 +21,7 @@ const unimplementedError = '12 UNIMPLEMENTED: unknown service signrpc.Signer';
20
21
 
21
22
  Requires `signer:generate` permission
22
23
 
24
+ `root_hash` is not supported in LND 0.14.3 and below
23
25
  `spending` is not supported in LND 0.14.3 and below
24
26
 
25
27
  {
@@ -28,9 +30,10 @@ const unimplementedError = '12 UNIMPLEMENTED: unknown service signrpc.Signer';
28
30
  key_index: <Key Index Number>
29
31
  output_script: <Output Script Hex String>
30
32
  output_tokens: <Output Tokens Number>
33
+ [root_hash]: <Taproot Root Hash Hex String>
31
34
  sighash: <Sighash Type Number>
32
35
  vin: <Input Index To Sign Number>
33
- witness_script: <Witness Script Hex String>
36
+ [witness_script]: <Witness Script Hex String>
34
37
  }]
35
38
  lnd: <Authenticated LND API Object>
36
39
  [spending]: [{
@@ -65,8 +68,8 @@ module.exports = ({inputs, lnd, spending, transaction}, cbk) => {
65
68
  return cbk();
66
69
  },
67
70
 
68
- // Derive the previous outputs set
69
- previousOutputs: ['validate', ({}, cbk) => {
71
+ // Derive the previous outputs set for Taproot spends
72
+ outputs: ['validate', ({}, cbk) => {
70
73
  const outputs = [].concat(inputs).concat(spending || []).map(utxo => ({
71
74
  pk_script: hexAsBuffer(utxo.output_script),
72
75
  value: utxo.output_tokens,
@@ -83,25 +86,29 @@ module.exports = ({inputs, lnd, spending, transaction}, cbk) => {
83
86
  }],
84
87
 
85
88
  // Get signatures
86
- signTransaction: ['previousOutputs', ({previousOutputs}, cbk) => {
89
+ signTransaction: ['outputs', ({outputs}, cbk) => {
87
90
  return lnd[type][method]({
88
- prev_outputs: previousOutputs,
91
+ prev_outputs: outputs,
89
92
  raw_tx_bytes: hexAsBuffer(transaction),
90
- sign_descs: inputs.map(input => ({
91
- input_index: input.vin,
92
- key_desc: {
93
- key_loc: {
94
- key_family: input.key_family,
95
- key_index: input.key_index,
93
+ sign_descs: inputs.map(input => {
94
+ return {
95
+ input_index: input.vin,
96
+ key_desc: {
97
+ key_loc: {
98
+ key_family: input.key_family,
99
+ key_index: input.key_index,
100
+ },
96
101
  },
97
- },
98
- output: {
99
- pk_script: hexAsBuffer(input.output_script),
100
- value: input.output_tokens,
101
- },
102
- sighash: input.sighash,
103
- witness_script: hexAsBuffer(input.witness_script),
104
- })),
102
+ output: {
103
+ pk_script: hexAsBuffer(input.output_script),
104
+ value: input.output_tokens,
105
+ },
106
+ sighash: input.sighash,
107
+ sign_method: inputSigningMethod({input, outputs}).method,
108
+ tap_tweak: hexAsBuffer(input.root_hash),
109
+ witness_script: hexAsBuffer(input.witness_script),
110
+ };
111
+ }),
105
112
  },
106
113
  (err, res) => {
107
114
  if (!!err && err.message === unimplementedError) {
@@ -0,0 +1,23 @@
1
+ import {
2
+ AuthenticatedLightningArgs,
3
+ AuthenticatedLightningMethod,
4
+ } from '../../typescript/shared';
5
+
6
+ export type UpdateGroupSigningSessionArgs = AuthenticatedLightningArgs<{
7
+ /** Hash to Sign Hex String */
8
+ hash: string;
9
+ /** MuSig2 Session Id Hex String */
10
+ id: string;
11
+ /** Nonce Hex Strings */
12
+ nonces: string[];
13
+ }>;
14
+
15
+ export type UpdateGroupSigningSessionResult = {
16
+ /** Partial Signature Hex String */
17
+ signature: string;
18
+ };
19
+
20
+ export const updateGroupSigningSession: AuthenticatedLightningMethod<
21
+ UpdateGroupSigningSessionArgs,
22
+ UpdateGroupSigningSessionResult
23
+ >;
package/package.json CHANGED
@@ -10,13 +10,13 @@
10
10
  "@grpc/grpc-js": "1.6.7",
11
11
  "@grpc/proto-loader": "0.6.12",
12
12
  "@types/express": "4.17.13",
13
- "@types/node": "17.0.31",
13
+ "@types/node": "17.0.38",
14
14
  "@types/request": "2.48.8",
15
15
  "@types/ws": "8.5.3",
16
16
  "async": "3.2.3",
17
17
  "asyncjs-util": "1.2.9",
18
18
  "bitcoinjs-lib": "6.0.1",
19
- "bn.js": "5.2.0",
19
+ "bn.js": "5.2.1",
20
20
  "body-parser": "1.20.0",
21
21
  "bolt07": "1.8.1",
22
22
  "bolt09": "0.2.3",
@@ -24,17 +24,17 @@
24
24
  "ecpair": "2.0.1",
25
25
  "express": "4.18.1",
26
26
  "invoices": "2.0.6",
27
- "psbt": "2.0.1",
27
+ "psbt": "2.3.0",
28
28
  "tiny-secp256k1": "2.2.1",
29
- "type-fest": "2.12.2"
29
+ "type-fest": "2.13.0"
30
30
  },
31
31
  "description": "Lightning Network client library",
32
32
  "devDependencies": {
33
33
  "@alexbosworth/node-fetch": "2.6.2",
34
34
  "@alexbosworth/tap": "15.0.11",
35
35
  "tsd": "0.20.0",
36
- "typescript": "4.6.4",
37
- "ws": "8.6.0"
36
+ "typescript": "4.7.2",
37
+ "ws": "8.7.0"
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.15.1"
62
+ "version": "5.16.1"
63
63
  }
@@ -66,6 +66,93 @@ const tests = [
66
66
  description: 'An address is required',
67
67
  expected: {address: 'addr'},
68
68
  },
69
+ {
70
+ args: {
71
+ lnd: {default: {newAddress: ({}, cbk) => cbk(null, {address: 'addr'})}},
72
+ },
73
+ description: 'The default address is p2wpkh',
74
+ expected: {address: 'addr'},
75
+ },
76
+ {
77
+ args: {
78
+ format: 'p2tr',
79
+ lnd: {
80
+ default: {
81
+ newAddress: ({}, cbk) => cbk(null, {address: 'addr'}),
82
+ },
83
+ wallet: {
84
+ listAccounts: ({}, cbk) => cbk({
85
+ details: 'unknown.service.walletrpc.WalletKit',
86
+ }),
87
+ },
88
+ },
89
+ },
90
+ description: 'Taproot requires TR account',
91
+ error: [501, 'CreationOfTaprootAddressesUnsupported'],
92
+ },
93
+ {
94
+ args: {
95
+ format: 'p2tr',
96
+ lnd: {
97
+ default: {newAddress: ({}, cbk) => cbk(null, {address: 'addr'})},
98
+ wallet: {listAccounts: ({}, cbk) => cbk('err')},
99
+ },
100
+ },
101
+ description: 'Taproot check errors are passed back',
102
+ error: [503, 'UnexpectedErrorCheckingTaprootSupport'],
103
+ },
104
+ {
105
+ args: {
106
+ format: 'p2tr',
107
+ lnd: {
108
+ default: {newAddress: ({}, cbk) => cbk(null, {address: 'addr'})},
109
+ wallet: {listAccounts: ({}, cbk) => cbk()},
110
+ },
111
+ },
112
+ description: 'Taproot requires account result',
113
+ error: [503, 'ExpectedResultForDerivationPathsRequest'],
114
+ },
115
+ {
116
+ args: {
117
+ format: 'p2tr',
118
+ lnd: {
119
+ default: {newAddress: ({}, cbk) => cbk(null, {address: 'addr'})},
120
+ wallet: {listAccounts: ({}, cbk) => cbk(null, {})},
121
+ },
122
+ },
123
+ description: 'Taproot accounts are expected',
124
+ error: [503, 'ExpectedAccountsInDerivationPathsResult'],
125
+ },
126
+ {
127
+ args: {
128
+ format: 'p2tr',
129
+ lnd: {
130
+ default: {newAddress: ({}, cbk) => cbk(null, {address: 'addr'})},
131
+ wallet: {listAccounts: ({}, cbk) => cbk(null, {accounts: []})},
132
+ },
133
+ },
134
+ description: 'Taproot supporting account is expected',
135
+ error: [501, 'ExpectedTaprootSupportingLndToCreateAddress'],
136
+ },
137
+ {
138
+ args: {
139
+ format: 'p2tr',
140
+ lnd: {
141
+ default: {
142
+ newAddress: ({}, cbk) => cbk(null, {
143
+ address: 'taproot_address',
144
+ }),
145
+ },
146
+ wallet: {
147
+ listAccounts: ({}, cbk) => cbk(null, {
148
+ accounts: [{address_type: 'TAPROOT_PUBKEY'}],
149
+ }),
150
+ },
151
+ },
152
+ },
153
+ description: 'Taproot supporting account',
154
+ expected: {address: 'taproot_address'},
155
+ },
69
156
  {
70
157
  args: {
71
158
  format: 'p2wpkh',
@@ -70,6 +70,11 @@ const makeArgs = override => {
70
70
  };
71
71
 
72
72
  const tests = [
73
+ {
74
+ args: makeArgs({confidence: NaN}),
75
+ description: 'Valid confidence is required',
76
+ error: [400, 'ExpectedConfidenceInPartsPerMillionForQuery'],
77
+ },
73
78
  {
74
79
  args: makeArgs({destination: undefined}),
75
80
  description: 'A destination is required',
@@ -85,6 +90,11 @@ const tests = [
85
90
  description: 'LND is required',
86
91
  error: [400, 'ExpectedLndApiObjectToGetRouteToDestination'],
87
92
  },
93
+ {
94
+ args: makeArgs({outgoing_channel: 12345}),
95
+ description: 'Outgoing channel is expected in standard format',
96
+ error: [400, 'ExpectedStandardFormatChannelIdForOutChannel'],
97
+ },
88
98
  {
89
99
  args: makeArgs({payment: undefined}),
90
100
  description: 'Total mtokens requires linking payment identifier',
@@ -132,6 +142,11 @@ const tests = [
132
142
  description: 'No route is found with error',
133
143
  expected: {},
134
144
  },
145
+ {
146
+ args: makeArgs({lnd: makeLnd({err: {details: 'is too large'}})}),
147
+ description: 'Payment cannot exceed maximum size',
148
+ error: [400, 'PaymentTooLargeToFindRoute'],
149
+ },
135
150
  {
136
151
  args: makeArgs({lnd: makeLnd({res: {routes: []}})}),
137
152
  description: 'No route is found',
@@ -0,0 +1,53 @@
1
+ const {test} = require('@alexbosworth/tap');
2
+
3
+ const method = require('./../../../lnd_methods/signer/input_signing_method');
4
+
5
+ const makeArgs = override => {
6
+ const args = {
7
+ input: {
8
+ root_hash: '00',
9
+ witness_script: '00',
10
+ },
11
+ outputs: [{
12
+ pk_script: Buffer.alloc(1),
13
+ value: 1,
14
+ }],
15
+ };
16
+
17
+ Object.keys(override || {}).forEach(key => args[key] = override[key]);
18
+
19
+ return args;
20
+ };
21
+
22
+ const tests = [
23
+ {
24
+ args: makeArgs({}),
25
+ description: 'Input signing method is returned for a leaf spend',
26
+ expected: {method: 3},
27
+ },
28
+ {
29
+ args: makeArgs({input: {}, outputs: undefined}),
30
+ description: 'Input signing method is returned for a regular spend',
31
+ expected: {method: 0},
32
+ },
33
+ {
34
+ args: makeArgs({input: {}}),
35
+ description: 'Input signing method is returned for a bip86 spend',
36
+ expected: {method: 1},
37
+ },
38
+ {
39
+ args: makeArgs({input: {root_hash: '00'}}),
40
+ description: 'Input signing method is returned for a top key script spend',
41
+ expected: {method: 2},
42
+ },
43
+ ];
44
+
45
+ tests.forEach(({args, description, expected}) => {
46
+ return test(description, async ({end, strictSame}) => {
47
+ const res = method(args);
48
+
49
+ strictSame(res, expected, 'Got expected result');
50
+
51
+ return end();
52
+ });
53
+ });
@@ -0,0 +1,14 @@
1
+ import {expectError, expectType} from 'tsd';
2
+ import {addExternalSocket} from '../../lnd_methods';
3
+ import {AuthenticatedLnd} from '../../lnd_grpc';
4
+
5
+ const lnd = {} as AuthenticatedLnd;
6
+ const socket = 'socket';
7
+
8
+ expectError(addExternalSocket());
9
+ expectError(addExternalSocket({}));
10
+ expectError(addExternalSocket({lnd}));
11
+ expectError(addExternalSocket({socket}));
12
+
13
+ expectType<void>(await addExternalSocket({lnd, socket}));
14
+ expectType<void>(addExternalSocket({lnd, socket}, () => {}));
@@ -0,0 +1,60 @@
1
+ import {expectError, expectType} from 'tsd';
2
+ import {
3
+ beginGroupSigningSession,
4
+ BeginGroupSigningSessionResult,
5
+ } from '../../lnd_methods';
6
+ import {AuthenticatedLnd} from '../../lnd_grpc';
7
+
8
+ const lnd = {} as AuthenticatedLnd;
9
+ const is_key_spend = true;
10
+ const key_family = 0;
11
+ const key_index = 0;
12
+ const public_keys = ['pubkey'];
13
+ const root_hash = 'root hash';
14
+
15
+ expectError(beginGroupSigningSession());
16
+ expectError(beginGroupSigningSession({}));
17
+ expectError(beginGroupSigningSession({lnd}));
18
+ expectError(beginGroupSigningSession({key_family}));
19
+ expectError(beginGroupSigningSession({key_index}));
20
+ expectError(beginGroupSigningSession({public_keys}));
21
+ expectError(beginGroupSigningSession({lnd, key_family}));
22
+ expectError(beginGroupSigningSession({lnd, key_index}));
23
+ expectError(beginGroupSigningSession({lnd, public_keys}));
24
+ expectError(beginGroupSigningSession({key_family, key_index}));
25
+ expectError(beginGroupSigningSession({key_family, public_keys}));
26
+ expectError(beginGroupSigningSession({key_index, public_keys}));
27
+ expectError(beginGroupSigningSession({lnd, key_family, key_index}));
28
+ expectError(beginGroupSigningSession({lnd, key_family, public_keys}));
29
+ expectError(beginGroupSigningSession({lnd, key_index, public_keys}));
30
+ expectError(beginGroupSigningSession({key_family, key_index, public_keys}));
31
+
32
+ expectType<BeginGroupSigningSessionResult>(
33
+ await beginGroupSigningSession({lnd, key_family, key_index, public_keys})
34
+ );
35
+ expectType<BeginGroupSigningSessionResult>(
36
+ await beginGroupSigningSession({
37
+ lnd,
38
+ key_family,
39
+ key_index,
40
+ public_keys,
41
+ is_key_spend,
42
+ root_hash,
43
+ })
44
+ );
45
+ expectType<void>(
46
+ beginGroupSigningSession(
47
+ {lnd, key_family, key_index, public_keys},
48
+ (err, res) => {
49
+ expectType<BeginGroupSigningSessionResult>(res);
50
+ }
51
+ )
52
+ );
53
+ expectType<void>(
54
+ beginGroupSigningSession(
55
+ {lnd, key_family, key_index, public_keys, is_key_spend, root_hash},
56
+ (err, res) => {
57
+ expectType<BeginGroupSigningSessionResult>(res);
58
+ }
59
+ )
60
+ );
@@ -0,0 +1,32 @@
1
+ import {expectError, expectType} from 'tsd';
2
+ import {
3
+ endGroupSigningSession,
4
+ EndGroupSigningSessionResult,
5
+ } from '../../lnd_methods';
6
+ import {AuthenticatedLnd} from '../../lnd_grpc';
7
+
8
+ const lnd = {} as AuthenticatedLnd;
9
+ const id = 'id';
10
+ const signatures = ['signature'];
11
+
12
+ expectError(endGroupSigningSession());
13
+ expectError(endGroupSigningSession({}));
14
+ expectError(endGroupSigningSession({lnd}));
15
+ expectError(endGroupSigningSession({id}));
16
+
17
+ expectType<EndGroupSigningSessionResult>(
18
+ await endGroupSigningSession({lnd, id})
19
+ );
20
+ expectType<EndGroupSigningSessionResult>(
21
+ await endGroupSigningSession({lnd, id, signatures})
22
+ );
23
+ expectType<void>(
24
+ endGroupSigningSession({lnd, id}, (err, res) => {
25
+ expectType<EndGroupSigningSessionResult>(res);
26
+ })
27
+ );
28
+ expectType<void>(
29
+ endGroupSigningSession({lnd, id, signatures}, (err, res) => {
30
+ expectType<EndGroupSigningSessionResult>(res);
31
+ })
32
+ );
@@ -0,0 +1,14 @@
1
+ import {expectError, expectType} from 'tsd';
2
+ import {removeExternalSocket} from '../../lnd_methods';
3
+ import {AuthenticatedLnd} from '../../lnd_grpc';
4
+
5
+ const lnd = {} as AuthenticatedLnd;
6
+ const socket = 'socket';
7
+
8
+ expectError(removeExternalSocket());
9
+ expectError(removeExternalSocket({}));
10
+ expectError(removeExternalSocket({lnd}));
11
+ expectError(removeExternalSocket({socket}));
12
+
13
+ expectType<void>(await removeExternalSocket({lnd, socket}));
14
+ expectType<void>(removeExternalSocket({lnd, socket}, () => {}));
@@ -11,7 +11,6 @@ const inputs = [
11
11
  output_tokens: 1,
12
12
  sighash: 1,
13
13
  vin: 0,
14
- witness_script: '00',
15
14
  },
16
15
  ];
17
16
  const spending = [
@@ -0,0 +1,14 @@
1
+ import {expectError, expectType} from 'tsd';
2
+ import {updateAlias} from '../../lnd_methods';
3
+ import {AuthenticatedLnd} from '../../lnd_grpc';
4
+
5
+ const lnd = {} as AuthenticatedLnd;
6
+ const node = 'node';
7
+
8
+ expectError(updateAlias());
9
+ expectError(updateAlias({}));
10
+ expectError(updateAlias({lnd}));
11
+ expectError(updateAlias({node}));
12
+
13
+ expectType<void>(await updateAlias({lnd, node}));
14
+ expectType<void>(updateAlias({lnd, node}, () => {}));
@@ -0,0 +1,14 @@
1
+ import {expectError, expectType} from 'tsd';
2
+ import {updateColor} from '../../lnd_methods';
3
+ import {AuthenticatedLnd} from '../../lnd_grpc';
4
+
5
+ const lnd = {} as AuthenticatedLnd;
6
+ const color = 'color';
7
+
8
+ expectError(updateColor());
9
+ expectError(updateColor({}));
10
+ expectError(updateColor({lnd}));
11
+ expectError(updateColor({color}));
12
+
13
+ expectType<void>(await updateColor({lnd, color}));
14
+ expectType<void>(updateColor({lnd, color}, () => {}));
@@ -0,0 +1,29 @@
1
+ import {expectError, expectType} from 'tsd';
2
+ import {
3
+ updateGroupSigningSession,
4
+ UpdateGroupSigningSessionResult,
5
+ } from '../../lnd_methods';
6
+ import {AuthenticatedLnd} from '../../lnd_grpc';
7
+
8
+ const lnd = {} as AuthenticatedLnd;
9
+ const hash = 'hash';
10
+ const id = 'id';
11
+ const nonces = ['nonce'];
12
+
13
+ expectError(updateGroupSigningSession());
14
+ expectError(updateGroupSigningSession({}));
15
+ expectError(updateGroupSigningSession({lnd}));
16
+ expectError(updateGroupSigningSession({hash}));
17
+ expectError(updateGroupSigningSession({id}));
18
+ expectError(updateGroupSigningSession({nonces}));
19
+ expectError(updateGroupSigningSession({lnd, hash}));
20
+ expectError(updateGroupSigningSession({lnd, id}));
21
+ expectError(updateGroupSigningSession({lnd, nonces}));
22
+ expectError(updateGroupSigningSession({lnd, hash, id}));
23
+ expectError(updateGroupSigningSession({lnd, hash, nonces}));
24
+ expectError(updateGroupSigningSession({lnd, id, nonces}));
25
+
26
+ expectType<UpdateGroupSigningSessionResult>(
27
+ await updateGroupSigningSession({lnd, hash, id, nonces})
28
+ );
29
+ expectType<void>(updateGroupSigningSession({lnd, hash, id, nonces}, () => {}));