lightning 9.9.1 → 9.11.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.
@@ -11,10 +11,10 @@ jobs:
11
11
  strategy:
12
12
  matrix:
13
13
  os: [ubuntu-latest]
14
- node: ['14', '16', '18']
14
+ node: ['16', '18', '20']
15
15
  steps:
16
16
  - uses: actions/checkout@v2
17
17
  - uses: actions/setup-node@v2
18
18
  - run: npm install
19
19
  - name: Run unit tests
20
- run: npm test
20
+ run: npm run unit-tests
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Versions
2
2
 
3
+ ## 9.11.0
4
+
5
+ - `openChannel`: Add `inputs` to select inputs for channel open funding
6
+
7
+ ## 9.10.0
8
+
9
+ - `createInvoice`, `createHodlInvoice`: Add `routes` to customize the hop hints
10
+
3
11
  ## 9.9.1
4
12
 
5
13
  - `openChannel`: Add `is_trusted_funding` to support skipping confirmation wait
@@ -2128,6 +2128,76 @@ message BatchOpenChannel {
2128
2128
  the remote peer supports explicit channel negotiation.
2129
2129
  */
2130
2130
  CommitmentType commitment_type = 9;
2131
+
2132
+ /*
2133
+ The maximum amount of coins in millisatoshi that can be pending within
2134
+ the channel. It only applies to the remote party.
2135
+ */
2136
+ uint64 remote_max_value_in_flight_msat = 10;
2137
+
2138
+ /*
2139
+ The maximum number of concurrent HTLCs we will allow the remote party to add
2140
+ to the commitment transaction.
2141
+ */
2142
+ uint32 remote_max_htlcs = 11;
2143
+
2144
+ /*
2145
+ Max local csv is the maximum csv delay we will allow for our own commitment
2146
+ transaction.
2147
+ */
2148
+ uint32 max_local_csv = 12;
2149
+
2150
+ /*
2151
+ If this is true, then a zero-conf channel open will be attempted.
2152
+ */
2153
+ bool zero_conf = 13;
2154
+
2155
+ /*
2156
+ If this is true, then an option-scid-alias channel-type open will be
2157
+ attempted.
2158
+ */
2159
+ bool scid_alias = 14;
2160
+
2161
+ /*
2162
+ The base fee charged regardless of the number of milli-satoshis sent.
2163
+ */
2164
+ uint64 base_fee = 15;
2165
+
2166
+ /*
2167
+ The fee rate in ppm (parts per million) that will be charged in
2168
+ proportion of the value of each forwarded HTLC.
2169
+ */
2170
+ uint64 fee_rate = 16;
2171
+
2172
+ /*
2173
+ If use_base_fee is true the open channel announcement will update the
2174
+ channel base fee with the value specified in base_fee. In the case of
2175
+ a base_fee of 0 use_base_fee is needed downstream to distinguish whether
2176
+ to use the default base fee value specified in the config or 0.
2177
+ */
2178
+ bool use_base_fee = 17;
2179
+
2180
+ /*
2181
+ If use_fee_rate is true the open channel announcement will update the
2182
+ channel fee rate with the value specified in fee_rate. In the case of
2183
+ a fee_rate of 0 use_fee_rate is needed downstream to distinguish whether
2184
+ to use the default fee rate value specified in the config or 0.
2185
+ */
2186
+ bool use_fee_rate = 18;
2187
+
2188
+ /*
2189
+ The number of satoshis we require the remote peer to reserve. This value,
2190
+ if specified, must be above the dust limit and below 20% of the channel
2191
+ capacity.
2192
+ */
2193
+ uint64 remote_chan_reserve_sat = 19;
2194
+
2195
+ /*
2196
+ An optional note-to-self to go along with the channel containing some
2197
+ useful information. This is only ever stored locally and in no way impacts
2198
+ the channel's operation.
2199
+ */
2200
+ string memo = 20;
2131
2201
  }
2132
2202
 
2133
2203
  message BatchOpenChannelResponse {
@@ -2290,6 +2360,11 @@ message OpenChannelRequest {
2290
2360
  the channel's operation.
2291
2361
  */
2292
2362
  string memo = 27;
2363
+
2364
+ /*
2365
+ A list of selected outpoints that are allocated for channel funding.
2366
+ */
2367
+ repeated OutPoint outpoints = 28;
2293
2368
  }
2294
2369
  message OpenStatusUpdate {
2295
2370
  oneof update {
@@ -221,7 +221,7 @@ module.exports = (args, cbk) => {
221
221
  }
222
222
 
223
223
  const hints = args.routes.map(route => {
224
- return {hop_hints: routeHintFromRoute({route}).hops}
224
+ return {hop_hints: routeHintFromRoute({route}).hops};
225
225
  });
226
226
 
227
227
  return cbk(null, hints);
@@ -7,6 +7,7 @@ const {returnResult} = require('asyncjs-util');
7
7
 
8
8
  const {createChainAddress} = require('./../address');
9
9
  const {isLnd} = require('./../../lnd_requests');
10
+ const {routeHintFromRoute} = require('./../../lnd_requests');
10
11
 
11
12
  const hexAsBuffer = hex => !!hex ? Buffer.from(hex, 'hex') : undefined;
12
13
  const {isArray} = Array;
@@ -41,6 +42,13 @@ const type = 'invoices';
41
42
  [is_including_private_channels]: <Invoice Includes Private Channels Bool>
42
43
  lnd: <Authenticated LND API Object>
43
44
  [mtokens]: <Millitokens String>
45
+ [routes]: [[{
46
+ [base_fee_mtokens]: <Base Routing Fee In Millitokens String>
47
+ [channel]: <Standard Format Channel Id String>
48
+ [cltv_delta]: <CLTV Blocks Delta Number>
49
+ [fee_rate]: <Fee Rate In Millitokens Per Million Number>
50
+ public_key: <Forward Edge Public Key Hex String>
51
+ }]]
44
52
  [tokens]: <Tokens Number>
45
53
  }
46
54
 
@@ -65,6 +73,10 @@ module.exports = (args, cbk) => {
65
73
  return cbk([400, 'ExpectedInvoicesLndToCreateHodlInvoice']);
66
74
  }
67
75
 
76
+ if (!!args.routes && !isArray(args.routes)) {
77
+ return cbk([400, 'ExpectedArrayOfHopHintPathsForRoutes']);
78
+ }
79
+
68
80
  return cbk();
69
81
  },
70
82
 
@@ -80,6 +92,20 @@ module.exports = (args, cbk) => {
80
92
  return createChainAddress({format, lnd: args.lnd}, cbk);
81
93
  }],
82
94
 
95
+ // Determine the route hints
96
+ hints: ['validate', ({}, cbk) => {
97
+ // Exit early when there are no route hints for the invoice
98
+ if (!args.routes) {
99
+ return cbk();
100
+ }
101
+
102
+ const hints = args.routes.map(route => {
103
+ return {hop_hints: routeHintFromRoute({route}).hops};
104
+ });
105
+
106
+ return cbk(null, hints);
107
+ }],
108
+
83
109
  // Generate id if needed
84
110
  invoiceId: ['validate', ({}, cbk) => {
85
111
  if (!!args.id) {
@@ -97,8 +123,9 @@ module.exports = (args, cbk) => {
97
123
  // Add invoice
98
124
  addInvoice: [
99
125
  'addAddress',
126
+ 'hints',
100
127
  'invoiceId',
101
- ({addAddress, invoiceId}, cbk) =>
128
+ ({addAddress, hints, invoiceId}, cbk) =>
102
129
  {
103
130
  const fallbackAddress = !addAddress ? undefined : addAddress.address;
104
131
  const createdAt = new Date();
@@ -117,6 +144,7 @@ module.exports = (args, cbk) => {
117
144
  hash: Buffer.from(invoiceId.id, 'hex'),
118
145
  memo: args.description,
119
146
  private: !!args.is_including_private_channels,
147
+ route_hints: hints || undefined,
120
148
  value: args.tokens || undefined,
121
149
  value_msat: args.mtokens || undefined,
122
150
  },
@@ -6,6 +6,7 @@ const {createChainAddress} = require('./../address');
6
6
  const getInvoice = require('./get_invoice');
7
7
  const {isLnd} = require('./../../lnd_requests');
8
8
  const {mtokensAmount} = require('./../../bolt00');
9
+ const {routeHintFromRoute} = require('./../../lnd_requests');
9
10
 
10
11
  const defaultExpirySec = 60 * 60 * 3;
11
12
  const hexAsBuffer = hex => !!hex ? Buffer.from(hex, 'hex') : undefined;
@@ -36,6 +37,13 @@ const type = 'default';
36
37
  lnd: <Authenticated LND API Object>
37
38
  [secret]: <Payment Preimage Hex String>
38
39
  [mtokens]: <Millitokens String>
40
+ [routes]: [[{
41
+ [base_fee_mtokens]: <Base Routing Fee In Millitokens String>
42
+ [channel]: <Standard Format Channel Id String>
43
+ [cltv_delta]: <CLTV Blocks Delta Number>
44
+ [fee_rate]: <Fee Rate In Millitokens Per Million Number>
45
+ public_key: <Forward Edge Public Key Hex String>
46
+ }]]
39
47
  [tokens]: <Tokens Number>
40
48
  }
41
49
 
@@ -86,6 +94,10 @@ module.exports = (args, cbk) => {
86
94
  }
87
95
  }
88
96
 
97
+ if (!!args.routes && !isArray(args.routes)) {
98
+ return cbk([400, 'ExpectedArrayOfHopHintPathsForRoutes']);
99
+ }
100
+
89
101
  return cbk();
90
102
  },
91
103
 
@@ -101,6 +113,20 @@ module.exports = (args, cbk) => {
101
113
  return createChainAddress({format, lnd: args.lnd}, cbk);
102
114
  }],
103
115
 
116
+ // Determine the route hints
117
+ hints: ['validate', ({}, cbk) => {
118
+ // Exit early when there are no route hints for the invoice
119
+ if (!args.routes) {
120
+ return cbk();
121
+ }
122
+
123
+ const hints = args.routes.map(route => {
124
+ return {hop_hints: routeHintFromRoute({route}).hops};
125
+ });
126
+
127
+ return cbk(null, hints);
128
+ }],
129
+
104
130
  // Determine the value of the invoice
105
131
  mtokens: ['validate', ({}, cbk) => {
106
132
  // Exit early when there are no mtokens
@@ -119,9 +145,10 @@ module.exports = (args, cbk) => {
119
145
  // Add invoice
120
146
  addInvoice: [
121
147
  'addAddress',
148
+ 'hints',
122
149
  'mtokens',
123
150
  'preimage',
124
- ({addAddress, mtokens, preimage}, cbk) =>
151
+ ({addAddress, hints, mtokens, preimage}, cbk) =>
125
152
  {
126
153
  const fallbackAddress = !addAddress ? String() : addAddress.address;
127
154
  const createdAt = new Date();
@@ -137,6 +164,7 @@ module.exports = (args, cbk) => {
137
164
  memo: args.description,
138
165
  private: !!args.is_including_private_channels,
139
166
  r_preimage: preimage || undefined,
167
+ route_hints: hints || undefined,
140
168
  value_msat: mtokens,
141
169
  },
142
170
  (err, response) => {
@@ -8,11 +8,11 @@ const anchors = 'ANCHORS';
8
8
  const defaultMinConfs = 1;
9
9
  const defaultMinHtlcMtokens = '1';
10
10
  const errMemoLength = /^provided memo \(.*\) is of length \d*, exceeds (\d*)$/;
11
+ const {isArray} = Array;
11
12
  const minChannelTokens = 20000;
12
13
  const method = 'openChannel';
13
14
  const type = 'default';
14
15
 
15
-
16
16
  /** Open a new channel.
17
17
 
18
18
  The capacity of the channel is set with local_tokens
@@ -23,6 +23,10 @@ const type = 'default';
23
23
 
24
24
  External funding requires LND compiled with `walletrpc` build tag
25
25
 
26
+ `is_trusted_funding` is not supported on LND 0.15.0 and below and requires
27
+ `--protocol.option-scid-alias` and `--protocol.zero-conf` set on both sides
28
+ as well as a channel open request listener to accept the trusted funding.
29
+
26
30
  `base_fee_mtokens` is not supported on LND 0.15.5 and below
27
31
  `fee_rate` is not supported on LND 0.15.5 and below
28
32
 
@@ -30,9 +34,7 @@ const type = 'default';
30
34
 
31
35
  `description` is not supported on LND 0.16.4 and below
32
36
 
33
- `is_trusted_funding` is not supported on LND 0.15.0 and below and requires
34
- `--protocol.option-scid-alias` and `--protocol.zero-conf` set on both sides
35
- as well as a channel open request listener to accept the trusted funding.
37
+ `inputs` is not supported on LND 0.16.4 and below
36
38
 
37
39
  {
38
40
  [base_fee_mtokens]: <Routing Base Fee Millitokens Charged String>
@@ -41,6 +43,10 @@ const type = 'default';
41
43
  [description]: <Immutable Channel Description String>
42
44
  [fee_rate]: <Routing Fee Rate In Millitokens Per Million Number>
43
45
  [give_tokens]: <Tokens to Gift To Partner Number> // Defaults to zero
46
+ [inputs]: [{
47
+ transaction_id: <Fund With Unspent Transaction Id Hex String>
48
+ transaction_vout: <Fund With Unspent Transaction Output Index Number>
49
+ }]
44
50
  [is_max_funding]: <Use Maximal Chain Funds For Local Funding Bool>
45
51
  [is_private]: <Channel is Private Bool> // Defaults to false
46
52
  [is_trusted_funding]: <Accept Funding as Trusted Bool>
@@ -76,6 +82,10 @@ module.exports = (args, cbk) => {
76
82
  return cbk([400, 'ExpectedLargerChannelSizeForChannelOpen']);
77
83
  }
78
84
 
85
+ if (!!args.inputs && !isArray(args.inputs)) {
86
+ return cbk([400, 'ExpectedArrayOfTransactionOutpointsAsInputs']);
87
+ }
88
+
79
89
  if (!args.partner_public_key) {
80
90
  return cbk([400, 'ExpectedPartnerPublicKeyForChannelOpen']);
81
91
  }
@@ -106,8 +116,28 @@ module.exports = (args, cbk) => {
106
116
  return cbk(null, args.min_confirmations);
107
117
  }],
108
118
 
119
+ // Determine which inputs should be used to fund the channel
120
+ outpoints: ['validate', ({}, cbk) => {
121
+ // Exit early when there are no specific UTXOs to spend
122
+ if (!args.inputs) {
123
+ return cbk();
124
+ }
125
+
126
+ const utxos = args.inputs.map(input => ({
127
+ output_index: input.transaction_vout,
128
+ txid_str: input.transaction_id,
129
+ }));
130
+
131
+ return cbk(null, utxos);
132
+ }],
133
+
109
134
  // Open the channel
110
- openChannel: ['connect', 'minConfs', ({minConfs}, cbk) => {
135
+ openChannel: [
136
+ 'connect',
137
+ 'minConfs',
138
+ 'outpoints',
139
+ ({minConfs, outpoints}, cbk) =>
140
+ {
111
141
  let isAnnounced = false;
112
142
 
113
143
  const options = {
@@ -120,6 +150,7 @@ module.exports = (args, cbk) => {
120
150
  min_confs: minConfs,
121
151
  min_htlc_msat: args.min_htlc_mtokens || defaultMinHtlcMtokens,
122
152
  node_pubkey: Buffer.from(args.partner_public_key, 'hex'),
153
+ outpoints: outpoints || undefined,
123
154
  private: !!args.is_private,
124
155
  remote_csv_delay: args.partner_csv_delay || undefined,
125
156
  spend_unconfirmed: !minConfs,
package/package.json CHANGED
@@ -7,10 +7,10 @@
7
7
  "url": "https://github.com/alexbosworth/lightning/issues"
8
8
  },
9
9
  "dependencies": {
10
- "@grpc/grpc-js": "1.8.19",
10
+ "@grpc/grpc-js": "1.9.0",
11
11
  "@grpc/proto-loader": "0.7.8",
12
12
  "@types/express": "4.17.17",
13
- "@types/node": "20.4.4",
13
+ "@types/node": "20.4.6",
14
14
  "@types/request": "2.48.8",
15
15
  "@types/ws": "8.5.5",
16
16
  "async": "3.2.4",
@@ -26,7 +26,7 @@
26
26
  "invoices": "3.0.0",
27
27
  "psbt": "3.0.0",
28
28
  "tiny-secp256k1": "2.2.3",
29
- "type-fest": "4.0.0"
29
+ "type-fest": "4.1.0"
30
30
  },
31
31
  "description": "Lightning Network client library",
32
32
  "devDependencies": {
@@ -52,11 +52,12 @@
52
52
  },
53
53
  "scripts": {
54
54
  "test": "npx nyc@15.1.0 node --experimental-test-coverage --test && npm run test:types",
55
- "test:types": "tsd"
55
+ "test:types": "tsd",
56
+ "unit-tests": "node --test && npm run test:types"
56
57
  },
57
58
  "tsd": {
58
59
  "directory": "test/typescript"
59
60
  },
60
61
  "types": "index.d.ts",
61
- "version": "9.9.1"
62
+ "version": "9.11.0"
62
63
  }
@@ -121,6 +121,11 @@ const tests = [
121
121
  description: 'A public key is required',
122
122
  error: [400, 'ExpectedPartnerPublicKeyForChannelOpen'],
123
123
  },
124
+ {
125
+ args: makeArgs({inputs: 'inputs'}),
126
+ description: 'A channel is opened with a tx id set',
127
+ error: [400, 'ExpectedArrayOfTransactionOutpointsAsInputs'],
128
+ },
124
129
  {
125
130
  args: makeArgs({
126
131
  public_key: Buffer.alloc(33).toString('hex'),
@@ -129,6 +134,16 @@ const tests = [
129
134
  description: 'A peer is connected before opening',
130
135
  expected: {transaction_id: '04030201', transaction_vout: 0},
131
136
  },
137
+ {
138
+ args: makeArgs({
139
+ inputs: [{
140
+ transaction_id: Buffer.alloc(32).toString('hex'),
141
+ transaction_vout: 0,
142
+ }],
143
+ }),
144
+ description: 'A channel is opened with a tx id set',
145
+ expected: {transaction_id: '04030201', transaction_vout: 0},
146
+ },
132
147
  {
133
148
  args: makeArgs({}),
134
149
  description: 'A channel is opened',