lightning 5.8.6 → 5.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Versions
2
2
 
3
+ ## 5.10.0
4
+
5
+ - `signTransaction`: Add `spending` attribute for specifying external inputs
6
+
7
+ ## 5.9.1
8
+
9
+ - `createChainAddress`: Add support for creating P2TR addresses
10
+ - `getUtxos`: Add support for showing P2TR address types
11
+
3
12
  ## 5.8.6
4
13
 
5
14
  - `getWalletInfo`, `payViaPaymentDetails`: Correct typescript fields
@@ -119,7 +119,11 @@ message SpendRequest {
119
119
  /*
120
120
  The outpoint for which we should request a spend notification for. If set to
121
121
  a zero outpoint, then the spend notification will be requested for the
122
- script instead.
122
+ script instead. A zero or nil outpoint is not supported for Taproot spends
123
+ because the output script cannot reliably be computed from the witness alone
124
+ and the spent output script is not always available in the rescan context.
125
+ So an outpoint must _always_ be specified when registering a spend
126
+ notification for a Taproot output.
123
127
  */
124
128
  Outpoint outpoint = 1;
125
129
 
@@ -1138,12 +1138,15 @@ message ListUnspentResponse {
1138
1138
 
1139
1139
  - `p2wkh`: Pay to witness key hash (`WITNESS_PUBKEY_HASH` = 0)
1140
1140
  - `np2wkh`: Pay to nested witness key hash (`NESTED_PUBKEY_HASH` = 1)
1141
+ - `p2tr`: Pay to taproot pubkey (`TAPROOT_PUBKEY` = 4)
1141
1142
  */
1142
1143
  enum AddressType {
1143
1144
  WITNESS_PUBKEY_HASH = 0;
1144
1145
  NESTED_PUBKEY_HASH = 1;
1145
1146
  UNUSED_WITNESS_PUBKEY_HASH = 2;
1146
1147
  UNUSED_NESTED_PUBKEY_HASH = 3;
1148
+ TAPROOT_PUBKEY = 4;
1149
+ UNUSED_TAPROOT_PUBKEY = 5;
1147
1150
  }
1148
1151
 
1149
1152
  message NewAddressRequest {
@@ -129,8 +129,11 @@ message SignDescriptor {
129
129
  bytes double_tweak = 3;
130
130
 
131
131
  /*
132
- The full script required to properly redeem the output. This field will
133
- only be populated if a p2wsh or a p2sh output is being signed.
132
+ The full script required to properly redeem the output. This field will
133
+ only be populated if a p2tr, p2wsh or a p2sh output is being signed. In case
134
+ taproot_key_spend is set to true then this value must correspond to the
135
+ taproot root hash (in case of a tapscript output) or the tap hashed internal
136
+ public key (in case of a BIP-0086 output).
134
137
  */
135
138
  bytes witness_script = 4;
136
139
 
@@ -150,6 +153,14 @@ message SignDescriptor {
150
153
  The target input within the transaction that should be signed.
151
154
  */
152
155
  int32 input_index = 8;
156
+
157
+ /*
158
+ Indicates that this should produce a signature that can be used for the key
159
+ spend path of a taproot input. This requires the witness_script field to be
160
+ set to the taproot root hash (in case of a tapscript output) or the tap
161
+ hashed internal public key (in case of a BIP-0086 output).
162
+ */
163
+ bool taproot_key_spend = 9;
153
164
  }
154
165
 
155
166
  message SignReq {
@@ -158,6 +169,12 @@ message SignReq {
158
169
 
159
170
  // A set of sign descriptors, for each input to be signed.
160
171
  repeated SignDescriptor sign_descs = 2;
172
+
173
+ /*
174
+ The full list of UTXO information for each of the inputs being spent. This
175
+ is required when spending one or more taproot (SegWit v1) outputs.
176
+ */
177
+ repeated TxOut prev_outputs = 3;
161
178
  }
162
179
 
163
180
  message SignResp {
@@ -334,6 +334,7 @@ enum AddressType {
334
334
  WITNESS_PUBKEY_HASH = 1;
335
335
  NESTED_WITNESS_PUBKEY_HASH = 2;
336
336
  HYBRID_NESTED_WITNESS_PUBKEY_HASH = 3;
337
+ TAPROOT_PUBKEY = 4;
337
338
  }
338
339
  message Account {
339
340
  // The name used to identify the account.
@@ -1,6 +1,8 @@
1
1
  {
2
2
  "np2wpkh": 1,
3
+ "p2tr": 4,
3
4
  "p2wpkh": 0,
4
- "unused_p2wpkh": 2,
5
- "unused_np2wpkh": 3
5
+ "unused_np2wpkh": 3,
6
+ "unused_p2tr": 5,
7
+ "unused_p2wpkh": 2
6
8
  }
@@ -5,7 +5,7 @@ import {
5
5
 
6
6
  export type CreateChainAddressArgs = AuthenticatedLightningArgs<{
7
7
  /** Receive Address Type */
8
- format?: 'np2wpkh' | 'p2wpkh';
8
+ format?: 'np2wpkh' | 'p2tr' | 'p2wpkh';
9
9
  /** Get As-Yet Unused Address */
10
10
  is_unused?: boolean;
11
11
  }>;
@@ -13,8 +13,10 @@ const type = 'default';
13
13
 
14
14
  Requires `address:write` permission
15
15
 
16
+ LND 0.14.3 and below do not support p2tr addresses
17
+
16
18
  {
17
- [format]: <Receive Address Type String> // "np2wpkh" || "p2wpkh"
19
+ [format]: <Receive Address Type String> // "np2wpkh" || "p2tr" || "p2wpkh"
18
20
  [is_unused]: <Get As-Yet Unused Address Bool>
19
21
  lnd: <Authenticated LND API Object>
20
22
  }
@@ -20,7 +20,7 @@ export type PartiallySignPsbtResult = {
20
20
  *
21
21
  * Requires LND built with `walletrpc` tag
22
22
  *
23
- * This method is not supported in LND 0.14.2 and below
23
+ * This method is not supported in LND 0.14.3 and below
24
24
  */
25
25
  export const partiallySignPsbt: AuthenticatedLightningMethod<
26
26
  PartiallySignPsbtArgs,
@@ -16,7 +16,7 @@ const type = 'wallet';
16
16
 
17
17
  Requires LND built with `walletrpc` tag
18
18
 
19
- This method is not supported in LND 0.14.2 and below
19
+ This method is not supported in LND 0.14.3 and below
20
20
 
21
21
  {
22
22
  lnd: <Authenticated LND API Object>
@@ -25,7 +25,7 @@ const type = 'chain';
25
25
 
26
26
  {
27
27
  [bech32_address]: <Address String>
28
- lnd: <Chain RPC LND API Object>
28
+ lnd: <Authenticated LND API Object>
29
29
  [min_confirmations]: <Minimum Confirmations Number>
30
30
  min_height: <Minimum Transaction Inclusion Blockchain Height Number>
31
31
  [output_script]: <Output Script Hex String>
@@ -5,19 +5,27 @@ const scriptFromChainAddress = require('./script_from_chain_address');
5
5
 
6
6
  const bufferAsHex = buffer => buffer.toString('hex');
7
7
  const dummyTxId = Buffer.alloc(32).toString('hex');
8
+ const events = ['confirmation', 'reorg'];
8
9
  const hexAsBuffer = hex => Buffer.from(hex, 'hex');
9
10
  const {isBuffer} = Buffer;
10
11
  const method = 'registerSpendNtfn';
12
+ const shutDownMessage = 'chain notifier shutting down';
13
+ const sumOf = arr => arr.reduce((sum, n) => sum + n, Number());
11
14
  const type = 'chain';
12
15
 
13
16
  /** Subscribe to confirmations of a spend
14
17
 
15
18
  A chain address or raw output script is required
16
19
 
20
+ When specifying a P2TR output script, `transaction_id` and `transaction_vout`
21
+ are required.
22
+
17
23
  Requires LND built with `chainrpc` build tag
18
24
 
19
25
  Requires `onchain:read` permission
20
26
 
27
+ Subscribing to P2TR outputs is not supported in LND 0.14.3 and below
28
+
21
29
  {
22
30
  [bech32_address]: <Bech32 P2WPKH or P2WSH Address String>
23
31
  lnd: <Authenticated LND API Object>
@@ -74,11 +82,33 @@ module.exports = args => {
74
82
  script: hexAsBuffer(script || args.output_script),
75
83
  });
76
84
 
85
+ // Cancel the subscription when all listeners are removed
86
+ eventEmitter.on('removeListener', () => {
87
+ const listenerCounts = events.map(n => eventEmitter.listenerCount(n));
88
+
89
+ // Exit early when there are still listeners
90
+ if (!!sumOf(listenerCounts)) {
91
+ return;
92
+ }
93
+
94
+ subscription.cancel();
95
+
96
+ return;
97
+ });
98
+
77
99
  subscription.on('end', () => eventEmitter.emit('end'));
78
100
  subscription.on('status', n => eventEmitter.emit('status', n));
79
101
 
80
102
  subscription.on('error', err => {
81
- eventEmitter.emit('error', new Error('UnexpectedErrInSpendSubscription'));
103
+ if (err.details === shutDownMessage) {
104
+ subscription.removeAllListeners();
105
+ }
106
+
107
+ if (!eventEmitter.listenerCount('error')) {
108
+ return;
109
+ }
110
+
111
+ eventEmitter.emit('error', err);
82
112
 
83
113
  return;
84
114
  });
@@ -3,16 +3,24 @@ const {returnResult} = require('asyncjs-util');
3
3
 
4
4
  const {isLnd} = require('./../../lnd_requests');
5
5
 
6
+ const bufferAsHex = buffer => buffer.toString('hex');
7
+ const hexAsBuffer = hex => Buffer.from(hex, 'hex');
6
8
  const {isArray} = Array;
9
+ const method = 'signOutputRaw';
7
10
  const notFound = -1;
11
+ const type = 'signer';
8
12
  const unimplementedError = '12 UNIMPLEMENTED: unknown service signrpc.Signer';
9
13
 
10
14
  /** Sign transaction
11
15
 
16
+ `spending` is required for non-internal inputs for a Taproot signature
17
+
12
18
  Requires LND built with `signrpc` build tag
13
19
 
14
20
  Requires `signer:generate` permission
15
21
 
22
+ `spending` is not supported in LND 0.14.3 and below
23
+
16
24
  {
17
25
  inputs: [{
18
26
  key_family: <Key Family Number>
@@ -24,6 +32,10 @@ const unimplementedError = '12 UNIMPLEMENTED: unknown service signrpc.Signer';
24
32
  witness_script: <Witness Script Hex String>
25
33
  }]
26
34
  lnd: <Authenticated LND API Object>
35
+ [spending]: [{
36
+ output_script: <Non-Internal Spend Output Script Hex String>
37
+ output_tokens: <Non-Internal Spend Output Tokens Number>
38
+ }]
27
39
  transaction: <Unsigned Transaction Hex String>
28
40
  }
29
41
 
@@ -32,7 +44,7 @@ const unimplementedError = '12 UNIMPLEMENTED: unknown service signrpc.Signer';
32
44
  signatures: [<Signature Hex String>]
33
45
  }
34
46
  */
35
- module.exports = ({inputs, lnd, transaction}, cbk) => {
47
+ module.exports = ({inputs, lnd, spending, transaction}, cbk) => {
36
48
  return new Promise((resolve, reject) => {
37
49
  return asyncAuto({
38
50
  // Check arguments
@@ -41,7 +53,7 @@ module.exports = ({inputs, lnd, transaction}, cbk) => {
41
53
  return cbk([400, 'ExpectedInputsToSignTransaction']);
42
54
  }
43
55
 
44
- if (!isLnd({lnd, method: 'signOutputRaw', type: 'signer'})) {
56
+ if (!isLnd({lnd, method, type})) {
45
57
  return cbk([400, 'ExpectedAuthenticatedLndToSignTransaction']);
46
58
  }
47
59
 
@@ -54,8 +66,12 @@ module.exports = ({inputs, lnd, transaction}, cbk) => {
54
66
 
55
67
  // Get signatures
56
68
  signTransaction: ['validate', ({}, cbk) => {
57
- return lnd.signer.signOutputRaw({
58
- raw_tx_bytes: Buffer.from(transaction, 'hex'),
69
+ return lnd[type][method]({
70
+ prev_outputs: [].concat(inputs).concat(spending || []).map(utxo => ({
71
+ pk_script: hexAsBuffer(utxo.output_script),
72
+ value: utxo.output_tokens,
73
+ })),
74
+ raw_tx_bytes: hexAsBuffer(transaction),
59
75
  sign_descs: inputs.map(input => ({
60
76
  input_index: input.vin,
61
77
  key_desc: {
@@ -65,11 +81,11 @@ module.exports = ({inputs, lnd, transaction}, cbk) => {
65
81
  },
66
82
  },
67
83
  output: {
68
- pk_script: Buffer.from(input.output_script, 'hex'),
84
+ pk_script: hexAsBuffer(input.output_script),
69
85
  value: input.output_tokens,
70
86
  },
71
87
  sighash: input.sighash,
72
- witness_script: Buffer.from(input.witness_script, 'hex'),
88
+ witness_script: hexAsBuffer(input.witness_script),
73
89
  })),
74
90
  },
75
91
  (err, res) => {
@@ -93,9 +109,7 @@ module.exports = ({inputs, lnd, transaction}, cbk) => {
93
109
  return cbk([503, 'ExpectedSignatureBuffersInSignResponse']);
94
110
  }
95
111
 
96
- return cbk(null, {
97
- signatures: res.raw_sigs.map(n => n.toString('hex'))
98
- });
112
+ return cbk(null, {signatures: res.raw_sigs.map(bufferAsHex)});
99
113
  });
100
114
  }],
101
115
  },
@@ -1,4 +1,9 @@
1
1
  {
2
+ "addressFormats": {
3
+ "np2wpkh": "NESTED_PUBKEY_HASH",
4
+ "p2tr": "TAPROOT_PUBKEY",
5
+ "p2wpkh": "WITNESS_PUBKEY_HASH"
6
+ },
2
7
  "adjustedChannelTypes": {
3
8
  "LEGACY": "STATIC_REMOTE_KEY",
4
9
  "STATIC_REMOTE_KEY": "ANCHORS",
@@ -1,4 +1,6 @@
1
- const formats = {np2wpkh: 'NESTED_PUBKEY_HASH', p2wpkh: 'WITNESS_PUBKEY_HASH'};
1
+ const constants = require('./constants');
2
+
3
+ const formats = constants.addressFormats;
2
4
  const {keys} = Object;
3
5
 
4
6
  /** Derive UTXO details from RPC UTXO details
package/package.json CHANGED
@@ -7,24 +7,24 @@
7
7
  "url": "https://github.com/alexbosworth/lightning/issues"
8
8
  },
9
9
  "dependencies": {
10
- "@grpc/grpc-js": "1.6.1",
10
+ "@grpc/grpc-js": "1.6.2",
11
11
  "@grpc/proto-loader": "0.6.9",
12
12
  "@types/express": "4.17.13",
13
13
  "@types/node": "17.0.23",
14
14
  "@types/request": "2.48.8",
15
15
  "@types/ws": "8.5.3",
16
16
  "async": "3.2.3",
17
- "asyncjs-util": "1.2.8",
17
+ "asyncjs-util": "1.2.9",
18
18
  "bitcoinjs-lib": "6.0.1",
19
19
  "bn.js": "5.2.0",
20
- "body-parser": "1.19.2",
21
- "bolt07": "1.8.0",
22
- "bolt09": "0.2.2",
20
+ "body-parser": "1.20.0",
21
+ "bolt07": "1.8.1",
22
+ "bolt09": "0.2.3",
23
23
  "cbor": "8.1.0",
24
24
  "ecpair": "2.0.1",
25
25
  "express": "4.17.3",
26
- "invoices": "2.0.4",
27
- "psbt": "2.0.0",
26
+ "invoices": "2.0.5",
27
+ "psbt": "2.0.1",
28
28
  "tiny-secp256k1": "2.2.1",
29
29
  "type-fest": "2.12.2"
30
30
  },
@@ -59,5 +59,5 @@
59
59
  "directory": "test/typescript"
60
60
  },
61
61
  "types": "index.d.ts",
62
- "version": "5.8.6"
62
+ "version": "5.10.0"
63
63
  }
@@ -82,6 +82,8 @@ const tests = [
82
82
  ];
83
83
 
84
84
  tests.forEach(({args, description, error, expected}) => {
85
+ args.restart_delay_ms = 1;
86
+
85
87
  return test(description, async ({end, equal, match, strictSame, throws}) => {
86
88
  if (!!error) {
87
89
  throws(() => subscribeToInvoices(args), new Error(error), 'Got error');