ln-service 57.23.1 → 57.25.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,13 @@
1
1
  # Versions
2
2
 
3
+ ## 57.25.0
4
+
5
+ - Add support for Testnet4
6
+
7
+ ## 57.24.0
8
+
9
+ - `closeChannel`: Add `is_graceful_close` option to wait for pending resolution
10
+
3
11
  ## 57.23.1
4
12
 
5
13
  - Add support for LND 0.18.5
package/README.md CHANGED
@@ -613,10 +613,13 @@ permissions
613
613
 
614
614
  `max_tokens_per_vbyte` is not supported in LND 0.15.0 and below
615
615
 
616
+ `is_graceful_close` is not supported in LND 0.17.5 and below
617
+
616
618
  {
617
619
  [address]: <Request Sending Local Channel Funds To Address String>
618
620
  [id]: <Standard Format Channel Id String>
619
621
  [is_force_close]: <Is Force Close Bool>
622
+ [is_graceful_close]: <Is Waiting For Pending Payments to Coop Close Bool>
620
623
  lnd: <Authenticated LND API Object>
621
624
  [max_tokens_per_vbyte]: <Fail Cooperative Close Above Fee Rate Number>
622
625
  [public_key]: <Peer Public Key String>
package/package.json CHANGED
@@ -8,8 +8,8 @@
8
8
  },
9
9
  "dependencies": {
10
10
  "bolt07": "1.9.4",
11
- "invoices": "3.0.0",
12
- "lightning": "10.23.1",
11
+ "invoices": "4.0.0",
12
+ "lightning": "10.25.0",
13
13
  "macaroon": "3.0.4"
14
14
  },
15
15
  "description": "Interaction helper for your Lightning Network daemon",
@@ -21,16 +21,16 @@
21
21
  "bip32": "4.0.0",
22
22
  "bip66": "2.0.0",
23
23
  "bitcoinjs-lib": "6.1.7",
24
- "bn.js": "5.2.1",
24
+ "bn.js": "5.2.2",
25
25
  "bs58check": "4.0.0",
26
- "ecpair": "2.1.0",
27
- "ln-docker-daemons": "6.0.23",
26
+ "ecpair": "3.0.0",
27
+ "ln-docker-daemons": "6.0.25",
28
28
  "p2tr": "2.0.0",
29
- "portfinder": "1.0.32",
30
- "psbt": "3.0.0",
29
+ "portfinder": "1.0.37",
30
+ "psbt": "4.0.0",
31
31
  "rimraf": "6.0.1",
32
32
  "tiny-secp256k1": "2.2.3",
33
- "uuid": "11.0.5",
33
+ "uuid": "11.1.0",
34
34
  "varuint-bitcoin": "2.0.0"
35
35
  },
36
36
  "engines": {
@@ -51,6 +51,9 @@
51
51
  "url": "https://github.com/alexbosworth/ln-service.git"
52
52
  },
53
53
  "scripts": {
54
+ "integration-test-0.18.5": "DOCKER_LND_VERSION=v0.18.5-beta npm run test",
55
+ "integration-test-0.18.4": "DOCKER_LND_VERSION=v0.18.4-beta npm run test",
56
+ "integration-test-0.18.3": "DOCKER_LND_VERSION=v0.18.3-beta npm run test",
54
57
  "integration-test-0.18.2": "DOCKER_LND_VERSION=v0.18.2-beta npm run test",
55
58
  "integration-test-0.18.1": "DOCKER_LND_VERSION=v0.18.1-beta npm run test",
56
59
  "integration-test-0.18.0": "DOCKER_LND_VERSION=v0.18.0-beta npm run test",
@@ -73,5 +76,5 @@
73
76
  "integration-test-0.14.4": "DOCKER_LND_VERSION=v0.14.4-beta npm run test",
74
77
  "test": "echo $DOCKER_LND_VERSION && node test/runner"
75
78
  },
76
- "version": "57.23.1"
79
+ "version": "57.25.0"
77
80
  }
@@ -0,0 +1,121 @@
1
+ const {equal} = require('node:assert').strict;
2
+ const test = require('node:test');
3
+
4
+ const asyncAuto = require('async/auto');
5
+ const asyncRetry = require('async/retry');
6
+ const {cancelHodlInvoice} = require('./../../');
7
+ const {createHodlInvoice} = require('./../../');
8
+ const {getInvoice} = require('./../../');
9
+ const {getChannels} = require('./../../');
10
+ const {getClosedChannels} = require('./../../');
11
+ const {pay} = require('./../../');
12
+ const {setupChannel} = require('ln-docker-daemons');
13
+ const {spawnLightningCluster} = require('ln-docker-daemons');
14
+
15
+ const {closeChannel} = require('./../../');
16
+
17
+ const interval = 100;
18
+ const size = 2;
19
+ const times = 1000;
20
+ const tokens = 10;
21
+
22
+ // Closing a pending payments channel should close the channel after a wait
23
+ test(`Close channel with wait for pending`, async () => {
24
+ const {kill, nodes} = await spawnLightningCluster({size});
25
+
26
+ const [control, target] = nodes;
27
+
28
+ try {
29
+ // Open a channel from control to target
30
+ const channelOpen = await setupChannel({
31
+ generate: control.generate,
32
+ lnd: control.lnd,
33
+ to: target,
34
+ });
35
+
36
+ // Create a hold invoice to create the pending state
37
+ const invoice = await createHodlInvoice({tokens, lnd: target.lnd});
38
+
39
+ await asyncAuto({
40
+ makePayment: async () => {
41
+ // Pay to the hold invoice
42
+ try {
43
+ await pay({lnd: control.lnd, request: invoice.request});
44
+ } catch (err) {
45
+ const [, type] = err;
46
+
47
+ // We expect that it would be canceled back
48
+ equal(type, 'PaymentRejectedByDestination');
49
+ }
50
+ },
51
+
52
+ // Wait for the payment to be held
53
+ lookForPayment: async () => {
54
+ await asyncRetry({interval, times}, async () => {
55
+ const received = await getInvoice({id: invoice.id, lnd: target.lnd});
56
+
57
+ if (!received.is_held) {
58
+ throw new Error('ExpectedPaymentHeld');
59
+ }
60
+ });
61
+ },
62
+
63
+ // Start the closing process
64
+ closeChannel: ['lookForPayment', async () => {
65
+ try {
66
+ await closeChannel({
67
+ id: channelOpen.id,
68
+ is_graceful_close: true,
69
+ lnd: control.lnd,
70
+ });
71
+ } catch (err) {
72
+ const [,, error] = err;
73
+
74
+ const {details} = error.err;
75
+
76
+ // LND 0.17.5 and below do not support graceful closes
77
+ if (details === 'cannot co-op close channel with active htlcs') {
78
+ throw new Error('FeatureUnsupported');
79
+ }
80
+
81
+ throw err;
82
+ }
83
+ }],
84
+
85
+ // Wait for channel to be in closing mode
86
+ confirmClosing: ['lookForPayment', async () => {
87
+ await asyncRetry({interval, times}, async () => {
88
+ const {channels} = await getChannels({lnd: control.lnd});
89
+
90
+ if (!channels.filter(n => !n.is_active).length) {
91
+ throw new Error('ExpectedInactiveChannels');
92
+ }
93
+ });
94
+ }],
95
+
96
+ // Stop the payment to void the pending state
97
+ cancelPayment: ['confirmClosing', async () => {
98
+ await cancelHodlInvoice({id: invoice.id, lnd: target.lnd});
99
+ }],
100
+
101
+ // Confirm that the channel closed cleanly
102
+ confirmClosed: ['cancelPayment', async () => {
103
+ await asyncRetry({interval, times}, async () => {
104
+ const {channels} = await getClosedChannels({lnd: control.lnd});
105
+
106
+ await control.generate({});
107
+
108
+ if (!channels.filter(n => !!n.is_cooperative_close).length) {
109
+ throw new Error('ExpectedCooperativelyClosedChannels');
110
+ }
111
+ });
112
+ }],
113
+ });
114
+ } catch (err) {
115
+ equal(err.message, 'FeatureUnsupported', 'Expected no error');
116
+ } finally {
117
+ await kill({});
118
+ }
119
+
120
+ return;
121
+ });
@@ -194,7 +194,10 @@ test(`Sign a taproot transaction`, async () => {
194
194
 
195
195
  const unusedKey = ecp.makeRandom({network: networks.regtest});
196
196
 
197
- const witnessScript = compile([unusedKey.publicKey.slice(1), OP_CHECKSIG]);
197
+ const witnessScript = compile([
198
+ Buffer.from(unusedKey.publicKey).slice(1),
199
+ OP_CHECKSIG,
200
+ ]);
198
201
 
199
202
  const branches = [{script: witnessScript}];
200
203
 
@@ -273,6 +276,9 @@ test(`Sign a taproot transaction`, async () => {
273
276
  }
274
277
  });
275
278
  } catch (err) {
279
+ console.log("ERR", err);
280
+ await kill({});
281
+
276
282
  equal(err, null, 'Expected no error');
277
283
  }
278
284
 
@@ -128,14 +128,20 @@ test(`Fund PSBT`, async () => {
128
128
  const keyPair2 = ecp.makeRandom({network: networks.regtest});
129
129
  const unusedKey = ecp.makeRandom({network: networks.regtest});
130
130
 
131
- const witnessScript = compile([unusedKey.publicKey.slice(1), OP_CHECKSIG]);
131
+ const witnessScript = compile([
132
+ from(unusedKey.publicKey).slice(1),
133
+ OP_CHECKSIG,
134
+ ]);
132
135
 
133
136
  const branches = [{script: witnessScript}];
134
137
 
135
138
  const {hash} = hashForTree({branches});
136
139
 
137
140
  // Create a combined key using public key material
138
- const combinedPoint = pointAdd(keyPair1.publicKey, keyPair2.publicKey);
141
+ const combinedPoint = pointAdd(
142
+ from(keyPair1.publicKey),
143
+ from(keyPair2.publicKey)
144
+ );
139
145
 
140
146
  const output = v1OutputScript({
141
147
  hash,
@@ -187,7 +193,10 @@ test(`Fund PSBT`, async () => {
187
193
  });
188
194
 
189
195
  // Ready for private key combining
190
- const combinedKey = privateAdd(keyPair1.privateKey, keyPair2.privateKey);
196
+ const combinedKey = privateAdd(
197
+ from(keyPair1.privateKey),
198
+ from(keyPair2.privateKey)
199
+ );
191
200
 
192
201
  const signedInput = signHash({
193
202
  hash,
@@ -224,7 +233,10 @@ test(`Fund PSBT`, async () => {
224
233
 
225
234
  const keyPair = ecp.makeRandom({network: networks.regtest});
226
235
 
227
- const witnessScript = compile([keyPair.publicKey.slice(1), OP_CHECKSIG]);
236
+ const witnessScript = compile([
237
+ from(keyPair.publicKey.slice(1)),
238
+ OP_CHECKSIG,
239
+ ]);
228
240
 
229
241
  const branches = [{script: witnessScript}];
230
242
 
@@ -277,7 +289,7 @@ test(`Fund PSBT`, async () => {
277
289
  );
278
290
  });
279
291
 
280
- const signature = from(signSchnorr(hashToSign, keyPair.privateKey));
292
+ const signature = from(signSchnorr(hashToSign, from(keyPair.privateKey)));
281
293
 
282
294
  const {block} = controlBlock({
283
295
  external_key: output.external_key,
@@ -308,7 +320,11 @@ test(`Fund PSBT`, async () => {
308
320
  }
309
321
  });
310
322
  } catch (err) {
323
+ await kill({});
324
+
311
325
  equal(err, null, 'Expected no error');
326
+
327
+ return;
312
328
  }
313
329
 
314
330
  // A Taproot output should be funded for a regular key spend
@@ -318,7 +334,7 @@ test(`Fund PSBT`, async () => {
318
334
  const keyPair = ecp.makeRandom({network: networks.regtest});
319
335
 
320
336
  const output = v1OutputScript({
321
- internal_key: keyPair.publicKey.toString('hex'),
337
+ internal_key: from(keyPair.publicKey).toString('hex'),
322
338
  });
323
339
 
324
340
  const outputScript = hexAsBuffer(output.script);
@@ -368,8 +384,8 @@ test(`Fund PSBT`, async () => {
368
384
  });
369
385
 
370
386
  const signedInput = signHash({
371
- private_key: keyPair.privateKey.toString('hex'),
372
- public_key: keyPair.publicKey.toString('hex'),
387
+ private_key: from(keyPair.privateKey).toString('hex'),
388
+ public_key: from(keyPair.publicKey).toString('hex'),
373
389
  sign_hash: hashToSign.toString('hex'),
374
390
  });
375
391