ln-service 53.14.1 → 53.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Versions
2
2
 
3
+ ## 53.16.1
4
+
5
+ - `getFailedPayments`, `getPayments`, `getPendingPayments`: Remove
6
+ `confirmed_at` date when a payment is not confirmed, add `created_at` and
7
+ `failed_at` dates for attempt start and attempt failed dates.
8
+
9
+ ## 53.16.0
10
+
11
+ - `beginGroupSigningSession`: Add method to start a MuSig2 signing session
12
+ - `endGroupSigningSession`: Add method to complete a MuSig2 signing session
13
+ - `updateGroupSigningSession`: Add method to add nonces to a MuSig2 session
14
+
15
+ ## 53.15.0
16
+
17
+ - `getRouteToDestination`, `isDestinationPayable`, `pay`,
18
+ `payViaPaymentDetails`, `payViaPaymentRequest`, `probeForRoute`,
19
+ `subscribeToPayViaDetails`, `subscribeToPayViaRequest`,
20
+ `subscribeToProbeForRoute` - add support for pathfinding `confidence`
21
+
3
22
  ## 53.14.1
4
23
 
5
24
  - `signTransaction`: Fix multi-input signing for upcoming Taproot API changes
package/README.md CHANGED
@@ -105,6 +105,7 @@ for `unlocker` methods.
105
105
  - [addExternalSocket](#addexternalsocket) - Advertise a new p2p host:ip address
106
106
  - [addPeer](#addpeer) - Connect to a peer
107
107
  - [authenticatedLndGrpc](#authenticatedlndgrpc) - LND API Object
108
+ - [beginGroupSigningSession](#begingroupsigningsession) - Start MuSig2 session
108
109
  - [broadcastChainTransaction](#broadcastchaintransaction) - Push a chain tx
109
110
  - [cancelHodlInvoice](#cancelhodlinvoice) - Cancel a held or any open invoice
110
111
  - [cancelPendingChannel](#cancelpendingchannel) - Cancel a pending open channel
@@ -132,6 +133,7 @@ for `unlocker` methods.
132
133
  - [disableChannel](#disablechannel) - Disable a channel for outgoing payments
133
134
  - [disconnectWatchtower](#disconnectwatchtower) - Disconnect a watchtower
134
135
  - [enableChannel](#enablechannel) - Enable a channel for outgoing payments
136
+ - [endGroupSigningSession](#endgroupsigningsession) - Complete MuSig2 session
135
137
  - [fundPendingChannels](#fundpendingchannels) - Fund pending open channels
136
138
  - [fundPsbt](#fundpsbt) - Create an unsigned PSBT with funding inputs and
137
139
  spending outputs
@@ -256,6 +258,7 @@ for `unlocker` methods.
256
258
  transaction
257
259
  - [updateColor](#updatecolor) - Update node graph color value
258
260
  - [updateConnectedWatchtower](#updateconnectedwatchtower) - Update watchtower
261
+ - [updateGroupSigningSession](#updategroupsigningsession) - Sign with MuSig2
259
262
  - [updatePathfindingSettings](#updatepathfindingsettings) - Update pathfinding
260
263
  configuration
261
264
  - [updateRoutingFees](#updateroutingfees) - Change routing fees
@@ -277,7 +280,7 @@ for `unlocker` methods.
277
280
  - [ln-accounting](https://npmjs.com/package/ln-accounting) - accounting records
278
281
  - [ln-docker-daemons](https://github.com/alexbosworth/ln-docker-daemons) -
279
282
  run regtest integration tests
280
- - [ln-pathfinding](https://npmjs.com/package/ln-accounting) - pathfinding
283
+ - [ln-pathfinding](https://npmjs.com/package/ln-pathfinding) - pathfinding
281
284
  utilities
282
285
  - [ln-sync](https://www.npmjs.com/package/ln-sync) - metadata helper methods
283
286
  - [probing](https://npmjs.com/package/probing) - payment probing utilities
@@ -380,6 +383,46 @@ const {lnd} = lnService.authenticatedLndGrpc({
380
383
  const wallet = await lnService.getWalletInfo({lnd});
381
384
  ```
382
385
 
386
+ ### beginGroupSigningSession
387
+
388
+ Start a MuSig2 group signing session
389
+
390
+ Requires LND built with `signrpc`, `walletrpc` build tags
391
+
392
+ Requires `address:read`, `signer:generate` permissions
393
+
394
+ This method is not supported in LND 0.14.3 and below
395
+
396
+ {
397
+ lnd: <Authenticated LND API Object>
398
+ [is_key_spend]: <Key Is BIP 86 Key Spend Key Bool>
399
+ key_family: <HD Seed Key Family Number>
400
+ key_index: <Key Index Number>
401
+ public_keys: [<External Public Key Hex String>]
402
+ [root_hash]: <Taproot Script Root Hash Hex String>
403
+ }
404
+
405
+ @returns via cbk or Promise
406
+ {
407
+ external_key: <Final Script or Top Level Public Key Hex String>
408
+ id: <Session Id Hex String>
409
+ [internal_key]: <Internal Top Level Public Key Hex String>
410
+ nonce: <Session Compound Nonces Hex String>
411
+ }
412
+
413
+ Example:
414
+
415
+ ```node
416
+ const {beginGroupSigningSession} = require('ln-service');
417
+
418
+ const session = await beginGroupSigningSession({
419
+ lnd,
420
+ key_family: 0,
421
+ key_index: 0,
422
+ public_keys: [externalPublicKey],
423
+ });
424
+ ```
425
+
383
426
  ### broadcastChainTransaction
384
427
 
385
428
  Publish a raw blockchain transaction to Blockchain network peers
@@ -1118,6 +1161,36 @@ await enableChannel({
1118
1161
  });
1119
1162
  ```
1120
1163
 
1164
+ ### endGroupSigningSession
1165
+
1166
+ Complete a MuSig2 signing session
1167
+
1168
+ Requires LND built with `signrpc` build tag
1169
+
1170
+ Requires `signer:generate` permission
1171
+
1172
+ This method is not supported in LND 0.14.3 and below
1173
+
1174
+ {
1175
+ id: <Session Id Hex String>
1176
+ lnd: <Authenticated LND API Object>
1177
+ [signatures]: [<Combine External Partial Signature Hex String>]
1178
+ }
1179
+
1180
+ @returns via cbk or Promise
1181
+ {
1182
+ [signature]: <Combined Signature Hex String>
1183
+ }
1184
+
1185
+ Example:
1186
+
1187
+ ```node
1188
+ const {endGroupSigningSession} = require('ln-service');
1189
+
1190
+ // Cancel a group signing session
1191
+ await endGroupSigningSession({id, lnd});
1192
+ ```
1193
+
1121
1194
  ### fundPendingChannels
1122
1195
 
1123
1196
  Fund pending channels
@@ -1746,7 +1819,9 @@ Requires `offchain:read` permission
1746
1819
  message: <Error Message String>
1747
1820
  }
1748
1821
  [index]: <Payment Add Index Number>
1749
- [confirmed_at]: <Payment Confirmed At ISO 8601 Date String>
1822
+ [confirmed_at]: <Payment Attempt Succeeded At ISO 8601 Date String>
1823
+ created_at: <Attempt Was Started At ISO 8601 Date String>
1824
+ [failed_at]: <Payment Attempt Failed At ISO 8601 Date String>
1750
1825
  is_confirmed: <Payment Attempt Succeeded Bool>
1751
1826
  is_failed: <Payment Attempt Failed Bool>
1752
1827
  is_pending: <Payment Attempt is Waiting For Resolution Bool>
@@ -2529,6 +2604,9 @@ Requires `offchain:read` permission
2529
2604
  }
2530
2605
  message: <Error Message String>
2531
2606
  }
2607
+ [confirmed_at]: <Payment Attempt Succeeded At ISO 8601 Date String>
2608
+ created_at: <Attempt Was Started At ISO 8601 Date String>
2609
+ [failed_at]: <Payment Attempt Failed At ISO 8601 Date String>
2532
2610
  is_confirmed: <Payment Attempt Succeeded Bool>
2533
2611
  is_failed: <Payment Attempt Failed Bool>
2534
2612
  is_pending: <Payment Attempt is Waiting For Resolution Bool>
@@ -2744,7 +2822,9 @@ Requires `offchain:read` permission
2744
2822
  message: <Error Message String>
2745
2823
  }
2746
2824
  [index]: <Payment Add Index Number>
2747
- [confirmed_at]: <Payment Confirmed At ISO 8601 Date String>
2825
+ [confirmed_at]: <Payment Attempt Succeeded At ISO 8601 Date String>
2826
+ created_at: <Attempt Was Started At ISO 8601 Date String>
2827
+ [failed_at]: <Payment Attempt Failed At ISO 8601 Date String>
2748
2828
  is_confirmed: <Payment Attempt Succeeded Bool>
2749
2829
  is_failed: <Payment Attempt Failed Bool>
2750
2830
  is_pending: <Payment Attempt is Waiting For Resolution Bool>
@@ -2931,8 +3011,11 @@ Call this iteratively after failed route attempts to get new routes
2931
3011
 
2932
3012
  Requires `info:read` permission
2933
3013
 
3014
+ Preferred `confidence` is not supported on LND 0.14.3 and below
3015
+
2934
3016
  {
2935
3017
  [cltv_delta]: <Final CLTV Delta Number>
3018
+ [confidence]: <Preferred Route Confidence Number Out of One Million Number>
2936
3019
  destination: <Final Send Destination Hex Encoded Public Key String>
2937
3020
  [features]: [{
2938
3021
  bit: <Feature Bit Number>
@@ -3331,8 +3414,11 @@ Determine if a payment destination is actually payable by probing it
3331
3414
 
3332
3415
  Requires `offchain:write` permission
3333
3416
 
3417
+ Preferred `confidence` is not supported on LND 0.14.3 and below
3418
+
3334
3419
  {
3335
3420
  [cltv_delta]: <Final CLTV Delta Number>
3421
+ [confidence]: <Preferred Route Confidence Number Out of One Million Number>
3336
3422
  destination: <Pay to Node with Public Key Hex String>
3337
3423
  [incoming_peer]: <Pay Through Specific Final Hop Public Key Hex String>
3338
3424
  lnd: <Authenticated LND API Object>
@@ -3612,7 +3698,10 @@ Requires `offchain:write` permission
3612
3698
 
3613
3699
  `max_path_mtokens` is not supported in LND 0.12.0 or below
3614
3700
 
3701
+ Preferred `confidence` is not supported on LND 0.14.3 and below
3702
+
3615
3703
  {
3704
+ [confidence]: <Preferred Route Confidence Number Out of One Million Number>
3616
3705
  [incoming_peer]: <Pay Through Specific Final Hop Public Key Hex String>
3617
3706
  lnd: <Authenticated LND API Object>
3618
3707
  [max_fee]: <Maximum Additional Fee Tokens To Pay Number>
@@ -3699,8 +3788,11 @@ Requires `offchain:write` permission
3699
3788
 
3700
3789
  `max_path_mtokens` is not supported in LND 0.12.0 or below
3701
3790
 
3791
+ Preferred `confidence` is not supported on LND 0.14.3 and below
3792
+
3702
3793
  {
3703
3794
  [cltv_delta]: <Final CLTV Delta Number>
3795
+ [confidence]: <Preferred Route Confidence Number Out of One Million Number>
3704
3796
  destination: <Destination Public Key String>
3705
3797
  [features]: [{
3706
3798
  bit: <Feature Bit Number>
@@ -3786,7 +3878,10 @@ Requires `offchain:write` permission
3786
3878
 
3787
3879
  `max_path_mtokens` is not supported in LND 0.12.0 or below
3788
3880
 
3881
+ Preferred `confidence` is not supported on LND 0.14.3 and below
3882
+
3789
3883
  {
3884
+ [confidence]: <Preferred Route Confidence Number Out of One Million Number>
3790
3885
  [incoming_peer]: <Pay Through Specific Final Hop Public Key Hex String>
3791
3886
  lnd: <Authenticated LND API Object>
3792
3887
  [max_fee]: <Maximum Fee Tokens To Pay Number>
@@ -3988,8 +4083,11 @@ If `total_mtokens` are specified, a `payment` nonce is required.
3988
4083
 
3989
4084
  Requires `offchain:write` permission
3990
4085
 
4086
+ Preferred `confidence` is not supported on LND 0.14.3 and below
4087
+
3991
4088
  {
3992
4089
  [cltv_delta]: <Final CLTV Delta Number>
4090
+ [confidence]: <Preferred Route Confidence Number Out of One Million Number>
3993
4091
  destination: <Destination Public Key Hex String>
3994
4092
  [features]: [{
3995
4093
  bit: <Feature Bit Number>
@@ -5573,8 +5671,11 @@ Requires `offchain:write` permission
5573
5671
 
5574
5672
  `max_path_mtokens` is not supported in LND 0.12.0 or below
5575
5673
 
5674
+ Preferred `confidence` is not supported on LND 0.14.3 and below
5675
+
5576
5676
  {
5577
5677
  [cltv_delta]: <Final CLTV Delta Number>
5678
+ [confidence]: <Preferred Route Confidence Number Out of One Million Number>
5578
5679
  destination: <Destination Public Key String>
5579
5680
  [features]: [{
5580
5681
  bit: <Feature Bit Number>
@@ -5736,7 +5837,10 @@ Requires `offchain:write` permission
5736
5837
 
5737
5838
  `max_path_mtokens` is not supported in LND 0.12.0 or below
5738
5839
 
5840
+ Preferred `confidence` is not supported on LND 0.14.3 and below
5841
+
5739
5842
  {
5843
+ [confidence]: <Preferred Route Confidence Number Out of One Million Number>
5740
5844
  [incoming_peer]: <Pay Through Specific Final Hop Public Key Hex String>
5741
5845
  lnd: <Authenticated LND API Object>
5742
5846
  [max_fee]: <Maximum Fee Tokens To Pay Number>
@@ -6144,8 +6248,11 @@ Subscribe to a probe attempt
6144
6248
 
6145
6249
  Requires `offchain:write` permission
6146
6250
 
6251
+ Preferred `confidence` is not supported on LND 0.14.3 and below
6252
+
6147
6253
  {
6148
6254
  [cltv_delta]: <Final CLTV Delta Number>
6255
+ [confidence]: <Preferred Route Confidence Number Out of One Million Number>
6149
6256
  destination: <Destination Public Key Hex String>
6150
6257
  [features]: [{
6151
6258
  bit: <Feature Bit Number>
@@ -6734,6 +6841,43 @@ await updateConnectedWatchtower({
6734
6841
  });
6735
6842
  ```
6736
6843
 
6844
+ ### updateGroupSigningSession
6845
+
6846
+ Update a MuSig2 signing session with nonces and generate a partial sig
6847
+
6848
+ All remote nonces are expected to be passed
6849
+
6850
+ Requires LND built with `signrpc` build tag
6851
+
6852
+ Requires `signer:generate` permission
6853
+
6854
+ This method is not supported in LND 0.14.3 and below
6855
+
6856
+ {
6857
+ hash: <Hash to Sign Hex String>
6858
+ id: <MuSig2 Session Id Hex String>
6859
+ lnd: <Authenticated LND API Object>
6860
+ nonces: [<Nonce Hex String>]
6861
+ }
6862
+
6863
+ @returns via cbk or Promise
6864
+ {
6865
+ signature: <Partial Signature Hex String>
6866
+ }
6867
+
6868
+ Example:
6869
+
6870
+ ```node
6871
+ const {updateGroupSigningSession} = require('ln-service');
6872
+
6873
+ const {signature} = await updateGroupSigningSession({
6874
+ lnd,
6875
+ hash: v1TxDigestHash,
6876
+ id: sessionId,
6877
+ nonces: [externalNonce],
6878
+ });
6879
+ ```
6880
+
6737
6881
  ### updatePathfindingSettings
6738
6882
 
6739
6883
  Update current pathfinding settings
package/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const {addExternalSocket} = require('lightning');
2
2
  const {addPeer} = require('lightning');
3
3
  const {authenticatedLndGrpc} = require('lightning');
4
+ const {beginGroupSigningSession} = require('lightning');
4
5
  const {broadcastChainTransaction} = require('lightning');
5
6
  const {cancelHodlInvoice} = require('lightning');
6
7
  const {cancelPendingChannel} = require('lightning');
@@ -25,6 +26,7 @@ const {diffieHellmanComputeSecret} = require('lightning');
25
26
  const {disableChannel} = require('lightning');
26
27
  const {disconnectWatchtower} = require('lightning');
27
28
  const {enableChannel} = require('lightning');
29
+ const {endGroupSigningSession} = require('lightning');
28
30
  const {fundPendingChannels} = require('lightning');
29
31
  const {fundPsbt} = require('lightning');
30
32
  const {getAccessIds} = require('lightning');
@@ -135,6 +137,7 @@ const {updateAlias} = require('lightning');
135
137
  const {updateChainTransaction} = require('lightning');
136
138
  const {updateColor} = require('lightning');
137
139
  const {updateConnectedWatchtower} = require('lightning');
140
+ const {updateGroupSigningSession} = require('lightning');
138
141
  const {updatePathfindingSettings} = require('lightning');
139
142
  const {updateRoutingFees} = require('lightning');
140
143
  const {verifyAccess} = require('lightning');
@@ -147,6 +150,7 @@ module.exports = {
147
150
  addExternalSocket,
148
151
  addPeer,
149
152
  authenticatedLndGrpc,
153
+ beginGroupSigningSession,
150
154
  broadcastChainTransaction,
151
155
  cancelHodlInvoice,
152
156
  cancelPendingChannel,
@@ -171,6 +175,7 @@ module.exports = {
171
175
  disableChannel,
172
176
  disconnectWatchtower,
173
177
  enableChannel,
178
+ endGroupSigningSession,
174
179
  fundPendingChannels,
175
180
  fundPsbt,
176
181
  getAccessIds,
@@ -281,6 +286,7 @@ module.exports = {
281
286
  updateChainTransaction,
282
287
  updateColor,
283
288
  updateConnectedWatchtower,
289
+ updateGroupSigningSession,
284
290
  updatePathfindingSettings,
285
291
  updateRoutingFees,
286
292
  verifyAccess,
package/package.json CHANGED
@@ -9,12 +9,12 @@
9
9
  "dependencies": {
10
10
  "bolt07": "1.8.1",
11
11
  "cors": "2.8.5",
12
- "express": "4.17.3",
12
+ "express": "4.18.1",
13
13
  "invoices": "2.0.6",
14
- "lightning": "5.13.1",
14
+ "lightning": "5.15.1",
15
15
  "macaroon": "3.0.4",
16
16
  "morgan": "1.10.0",
17
- "ws": "8.5.0"
17
+ "ws": "8.6.0"
18
18
  },
19
19
  "description": "Interaction helper for your Lightning Network daemon",
20
20
  "devDependencies": {
@@ -28,7 +28,7 @@
28
28
  "bn.js": "5.2.0",
29
29
  "bs58check": "2.1.2",
30
30
  "ecpair": "2.0.1",
31
- "ln-docker-daemons": "2.2.9",
31
+ "ln-docker-daemons": "2.2.10",
32
32
  "p2tr": "1.3.1",
33
33
  "portfinder": "1.0.28",
34
34
  "psbt": "2.0.1",
@@ -70,5 +70,5 @@
70
70
  "integration-test-0.12.0": "DOCKER_LND_VERSION=v0.12.0-beta npm run test",
71
71
  "test": "echo $DOCKER_LND_VERSION && tap -j 2 --branches=1 --functions=1 --lines=1 --statements=1 -t 200 test/autopilotrpc-integration/*.js test/chainrpc-integration/*.js test/integration/*.js test/invoicesrpc-integration/*.js test/peersrpc-integration/*.js test/routerrpc-integration/*.js test/signerrpc-integration/*.js test/tower_clientrpc-integration/*.js test/tower_serverrpc-integration/*.js test/walletrpc-integration/*.js"
72
72
  },
73
- "version": "53.14.1"
73
+ "version": "53.16.1"
74
74
  }
@@ -66,7 +66,7 @@ test(`Subscribe to chain transactions`, async ({end, equal, fail}) => {
66
66
  .filter(n => !!n.is_outgoing);
67
67
 
68
68
  if (!transaction) {
69
- throw new Error('ExpectedTrnasaction');
69
+ throw new Error('ExpectedTransactionInSubscribeToChainAddressResult');
70
70
  }
71
71
 
72
72
  // Wait for generation to be over
@@ -0,0 +1,440 @@
1
+ const asyncRetry = require('async/retry');
2
+ const {address} = require('bitcoinjs-lib');
3
+ const {controlBlock} = require('p2tr');
4
+ const {createPsbt} = require('psbt');
5
+ const {hashForTree} = require('p2tr');
6
+ const {leafHash} = require('p2tr');
7
+ const {networks} = require('bitcoinjs-lib');
8
+ const {script} = require('bitcoinjs-lib');
9
+ const {spawnLightningCluster} = require('ln-docker-daemons');
10
+ const {test} = require('@alexbosworth/tap');
11
+ const {Transaction} = require('bitcoinjs-lib');
12
+ const {v1OutputScript} = require('p2tr');
13
+
14
+ const {beginGroupSigningSession} = require('./../../');
15
+ const {broadcastChainTransaction} = require('./../../');
16
+ const {createChainAddress} = require('./../../');
17
+ const {endGroupSigningSession} = require('./../../');
18
+ const {fundPsbt} = require('./../../');
19
+ const {getPublicKey} = require('./../../');
20
+ const {getUtxos} = require('./../../');
21
+ const {signPsbt} = require('./../../');
22
+ const {updateGroupSigningSession} = require('./../../');
23
+
24
+ const {compile} = script;
25
+ const count = 100;
26
+ const defaultInternalKey = '0350929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0';
27
+ const {from} = Buffer;
28
+ const {fromHex} = Transaction;
29
+ const hexAsBuffer = hex => Buffer.from(hex, 'hex');
30
+ const interval = 100;
31
+ const OP_CHECKSIG = 172;
32
+ const smallTokens = 2e5;
33
+ const times = 20;
34
+ const {toOutputScript} = address;
35
+ const tokens = 1e6;
36
+
37
+ // Starting a group signing session should result in a new MuSig2 session
38
+ test(`Begin group signing session`, async ({end, equal}) => {
39
+ const {kill, nodes} = await spawnLightningCluster({size: 2});
40
+
41
+ const [{generate, lnd}, target] = nodes;
42
+
43
+ try {
44
+ await beginGroupSigningSession({
45
+ lnd,
46
+ is_key_spend: true,
47
+ key_family: 0,
48
+ key_index: 0,
49
+ public_keys: [Buffer.alloc(33, 2).toString('hex')],
50
+ });
51
+ } catch (err) {
52
+ // On LND 0.14.3 and below, group signing is not supported
53
+ if (err.slice().shift() === 501) {
54
+ await kill({});
55
+
56
+ return end();
57
+ }
58
+
59
+ throw err;
60
+ }
61
+
62
+ // A Taproot script can be funded and spent with MuSig2
63
+ try {
64
+ await generate({count});
65
+
66
+ const controlKey = await getPublicKey({lnd, family: 0});
67
+ const targetKey = await getPublicKey({family: 0, lnd: target.lnd});
68
+
69
+ const controlGroup = await beginGroupSigningSession({
70
+ lnd,
71
+ is_key_spend: true,
72
+ key_family: 0,
73
+ key_index: controlKey.index,
74
+ public_keys: [targetKey.public_key],
75
+ });
76
+
77
+ const targetGroup = await beginGroupSigningSession({
78
+ is_key_spend: true,
79
+ key_family: 0,
80
+ key_index: targetKey.index,
81
+ lnd: target.lnd,
82
+ public_keys: [controlKey.public_key],
83
+ });
84
+
85
+ equal(controlGroup.external_key, targetGroup.external_key, 'Equal e-keys');
86
+ equal(controlGroup.internal_key, targetGroup.internal_key, 'Equal i-keys');
87
+
88
+ const script = Buffer.concat([
89
+ Buffer.from([81]),
90
+ Buffer.from([32]),
91
+ hexAsBuffer(controlGroup.external_key),
92
+ ]);
93
+
94
+ const [utxo] = (await getUtxos({lnd})).utxos.reverse();
95
+
96
+ // Make a PSBT paying to the Taproot output
97
+ const {psbt} = createPsbt({
98
+ outputs: [{tokens, script: script.toString('hex')}],
99
+ utxos: [{id: utxo.transaction_id, vout: utxo.transaction_vout}],
100
+ });
101
+
102
+ // Sign the PSBT
103
+ const signed = await signPsbt({
104
+ lnd,
105
+ psbt: (await fundPsbt({lnd, psbt})).psbt,
106
+ });
107
+
108
+ // Send the tx to the chain
109
+ await broadcastChainTransaction({lnd, transaction: signed.transaction});
110
+
111
+ // Make a new tx that will spend the output back into the wallet
112
+ const tx = new Transaction();
113
+
114
+ // The new tx spends the Taproot output
115
+ tx.addInput(
116
+ fromHex(signed.transaction).getHash(),
117
+ fromHex(signed.transaction).outs.findIndex(n => n.value === tokens)
118
+ );
119
+
120
+ // Make an output to pay back into the wallet
121
+ const chainOutput = toOutputScript(
122
+ (await createChainAddress({lnd})).address,
123
+ networks.regtest
124
+ );
125
+
126
+ // Add output to the pay back transaction
127
+ tx.addOutput(chainOutput, smallTokens);
128
+
129
+ const [hashToSign] = tx.ins.map((input, i) => {
130
+ return tx.hashForWitnessV1(
131
+ i,
132
+ [script],
133
+ [tokens],
134
+ Transaction.SIGHASH_DEFAULT,
135
+ );
136
+ });
137
+
138
+ const controlSign = await updateGroupSigningSession({
139
+ lnd,
140
+ hash: hashToSign.toString('hex'),
141
+ id: controlGroup.id,
142
+ nonces: [targetGroup.nonce],
143
+ });
144
+
145
+ const targetSign = await updateGroupSigningSession({
146
+ hash: hashToSign.toString('hex'),
147
+ id: targetGroup.id,
148
+ lnd: target.lnd,
149
+ nonces: [controlGroup.nonce],
150
+ });
151
+
152
+ await endGroupSigningSession({lnd: target.lnd, id: targetGroup.id});
153
+
154
+ const {signature} = await endGroupSigningSession({
155
+ lnd,
156
+ id: controlGroup.id,
157
+ signatures: [targetSign.signature],
158
+ });
159
+
160
+ // Add the signature to the input
161
+ tx.ins.forEach((input, i) => tx.setWitness(i, [hexAsBuffer(signature)]));
162
+
163
+ await broadcastChainTransaction({lnd, transaction: tx.toHex()});
164
+
165
+ await asyncRetry({interval, times}, async () => {
166
+ await generate({});
167
+
168
+ const {utxos} = await getUtxos({lnd});
169
+
170
+ const utxo = utxos.find(n => n.transaction_id === tx.getId());
171
+
172
+ if (!utxo || !utxo.confirmation_count) {
173
+ throw new Error('ExpectedReceivedTaprootSpend');
174
+ }
175
+ });
176
+ } catch (err) {
177
+ equal(err, null, 'Expected no error');
178
+ }
179
+
180
+ // A Taproot script can be funded and spent with MuSig2 for a script output
181
+ try {
182
+ await generate({count});
183
+
184
+ const controlKey = await getPublicKey({lnd, family: 0});
185
+ const targetKey = await getPublicKey({family: 0, lnd: target.lnd});
186
+ const unusedKey = (await getPublicKey({lnd, family: 805})).public_key;
187
+
188
+ const xOnlyUnused = hexAsBuffer(unusedKey.slice(2));
189
+
190
+ const witnessScript = compile([xOnlyUnused, OP_CHECKSIG]);
191
+
192
+ const branches = [{script: witnessScript.toString('hex')}];
193
+
194
+ const {hash} = hashForTree({branches});
195
+
196
+ const controlGroup = await beginGroupSigningSession({
197
+ lnd,
198
+ key_family: 0,
199
+ key_index: controlKey.index,
200
+ public_keys: [targetKey.public_key],
201
+ root_hash: hash,
202
+ });
203
+
204
+ const targetGroup = await beginGroupSigningSession({
205
+ key_family: 0,
206
+ key_index: targetKey.index,
207
+ lnd: target.lnd,
208
+ public_keys: [controlKey.public_key],
209
+ root_hash: hash,
210
+ });
211
+
212
+ equal(controlGroup.external_key, targetGroup.external_key, 'Equal e-keys');
213
+ equal(controlGroup.internal_key, targetGroup.internal_key, 'Equal i-keys');
214
+
215
+ const script = Buffer.concat([
216
+ from([81]),
217
+ from([32]),
218
+ hexAsBuffer(controlGroup.external_key),
219
+ ]);
220
+
221
+ const [utxo] = (await getUtxos({lnd})).utxos.reverse();
222
+
223
+ // Make a PSBT paying to the Taproot output
224
+ const {psbt} = createPsbt({
225
+ outputs: [{tokens, script: script.toString('hex')}],
226
+ utxos: [{id: utxo.transaction_id, vout: utxo.transaction_vout}],
227
+ });
228
+
229
+ // Sign the PSBT
230
+ const signed = await signPsbt({
231
+ lnd,
232
+ psbt: (await fundPsbt({lnd, psbt})).psbt,
233
+ });
234
+
235
+ // Send the tx to the chain
236
+ await broadcastChainTransaction({lnd, transaction: signed.transaction});
237
+
238
+ // Make a new tx that will spend the output back into the wallet
239
+ const tx = new Transaction();
240
+
241
+ // The new tx spends the Taproot output
242
+ tx.addInput(
243
+ fromHex(signed.transaction).getHash(),
244
+ fromHex(signed.transaction).outs.findIndex(n => n.value === tokens)
245
+ );
246
+
247
+ // Make an output to pay back into the wallet
248
+ const chainOutput = toOutputScript(
249
+ (await createChainAddress({lnd})).address,
250
+ networks.regtest
251
+ );
252
+
253
+ // Add output to the pay back transaction
254
+ tx.addOutput(chainOutput, smallTokens);
255
+
256
+ const [hashToSign] = tx.ins.map((input, i) => {
257
+ return tx.hashForWitnessV1(
258
+ i,
259
+ [script],
260
+ [tokens],
261
+ Transaction.SIGHASH_DEFAULT,
262
+ );
263
+ });
264
+
265
+ const controlSign = await updateGroupSigningSession({
266
+ lnd,
267
+ hash: hashToSign.toString('hex'),
268
+ id: controlGroup.id,
269
+ nonces: [targetGroup.nonce],
270
+ });
271
+
272
+ const targetSign = await updateGroupSigningSession({
273
+ hash: hashToSign.toString('hex'),
274
+ id: targetGroup.id,
275
+ lnd: target.lnd,
276
+ nonces: [controlGroup.nonce],
277
+ });
278
+
279
+ await endGroupSigningSession({lnd: target.lnd, id: targetGroup.id});
280
+
281
+ const {signature} = await endGroupSigningSession({
282
+ lnd,
283
+ id: controlGroup.id,
284
+ signatures: [targetSign.signature],
285
+ });
286
+
287
+ // Add the signature to the input
288
+ tx.ins.forEach((input, i) => tx.setWitness(i, [hexAsBuffer(signature)]));
289
+
290
+ await broadcastChainTransaction({lnd, transaction: tx.toHex()});
291
+
292
+ await asyncRetry({interval, times}, async () => {
293
+ await generate({});
294
+
295
+ const {utxos} = await getUtxos({lnd});
296
+
297
+ const utxo = utxos.find(n => n.transaction_id === tx.getId());
298
+
299
+ if (!utxo || !utxo.confirmation_count) {
300
+ throw new Error('ExpectedReceivedTaprootSpend');
301
+ }
302
+ });
303
+ } catch (err) {
304
+ equal(err, null, 'Expected no error');
305
+ }
306
+
307
+ // A Taproot script can be funded and spent on the script path
308
+ try {
309
+ await generate({count});
310
+
311
+ const controlKey = await getPublicKey({lnd, family: 0});
312
+ const targetKey = await getPublicKey({family: 0, lnd: target.lnd});
313
+
314
+ const controlGroup = await beginGroupSigningSession({
315
+ lnd,
316
+ key_family: 0,
317
+ key_index: controlKey.index,
318
+ public_keys: [targetKey.public_key],
319
+ });
320
+
321
+ const targetGroup = await beginGroupSigningSession({
322
+ key_family: 0,
323
+ key_index: targetKey.index,
324
+ lnd: target.lnd,
325
+ public_keys: [controlKey.public_key],
326
+ });
327
+
328
+ const scriptKey = hexAsBuffer(controlGroup.external_key);
329
+
330
+ const witnessScript = compile([scriptKey, OP_CHECKSIG]);
331
+
332
+ const branches = [{script: witnessScript.toString('hex')}];
333
+
334
+ const {hash} = hashForTree({branches});
335
+
336
+ const output = v1OutputScript({hash, internal_key: defaultInternalKey});
337
+
338
+ const [utxo] = (await getUtxos({lnd})).utxos.reverse();
339
+
340
+ // Make a PSBT paying to the Taproot output
341
+ const {psbt} = createPsbt({
342
+ outputs: [{tokens, script: output.script}],
343
+ utxos: [{id: utxo.transaction_id, vout: utxo.transaction_vout}],
344
+ });
345
+
346
+ // Sign the PSBT
347
+ const signed = await signPsbt({
348
+ lnd,
349
+ psbt: (await fundPsbt({lnd, psbt})).psbt,
350
+ });
351
+
352
+ // Send the tx to the chain
353
+ await broadcastChainTransaction({lnd, transaction: signed.transaction});
354
+
355
+ // Make a new tx that will spend the output back into the wallet
356
+ const tx = new Transaction();
357
+
358
+ // The new tx spends the Taproot output
359
+ tx.addInput(
360
+ fromHex(signed.transaction).getHash(),
361
+ fromHex(signed.transaction).outs.findIndex(n => n.value === tokens)
362
+ );
363
+
364
+ // Make an output to pay back into the wallet
365
+ const chainOutput = toOutputScript(
366
+ (await createChainAddress({lnd})).address,
367
+ networks.regtest
368
+ );
369
+
370
+ // Add output to the pay back transaction
371
+ tx.addOutput(chainOutput, smallTokens);
372
+
373
+ const [hashToSign] = tx.ins.map((input, i) => {
374
+ return tx.hashForWitnessV1(
375
+ i,
376
+ [hexAsBuffer(output.script)],
377
+ [tokens],
378
+ Transaction.SIGHASH_DEFAULT,
379
+ hexAsBuffer(leafHash({script: witnessScript.toString('hex')}).hash),
380
+ );
381
+ });
382
+
383
+ const controlSign = await updateGroupSigningSession({
384
+ lnd,
385
+ hash: hashToSign.toString('hex'),
386
+ id: controlGroup.id,
387
+ nonces: [targetGroup.nonce],
388
+ });
389
+
390
+ const targetSign = await updateGroupSigningSession({
391
+ hash: hashToSign.toString('hex'),
392
+ id: targetGroup.id,
393
+ lnd: target.lnd,
394
+ nonces: [controlGroup.nonce],
395
+ });
396
+
397
+ await endGroupSigningSession({lnd: target.lnd, id: targetGroup.id});
398
+
399
+ const {signature} = await endGroupSigningSession({
400
+ lnd,
401
+ id: controlGroup.id,
402
+ signatures: [targetSign.signature],
403
+ });
404
+
405
+ const {block} = controlBlock({
406
+ external_key: output.external_key,
407
+ leaf_script: witnessScript.toString('hex'),
408
+ script_branches: branches,
409
+ });
410
+
411
+ // Add the signature to the input
412
+ tx.ins.forEach((input, i) => {
413
+ return tx.setWitness(i, [
414
+ hexAsBuffer(signature),
415
+ witnessScript,
416
+ hexAsBuffer(block),
417
+ ]);
418
+ });
419
+
420
+ await broadcastChainTransaction({lnd, transaction: tx.toHex()});
421
+
422
+ await asyncRetry({interval, times}, async () => {
423
+ await generate({});
424
+
425
+ const {utxos} = await getUtxos({lnd});
426
+
427
+ const utxo = utxos.find(n => n.transaction_id === tx.getId());
428
+
429
+ if (!utxo || !utxo.confirmation_count) {
430
+ throw new Error('ExpectedReceivedTaprootSpend');
431
+ }
432
+ });
433
+ } catch (err) {
434
+ equal(err, null, 'Expected no error');
435
+ }
436
+
437
+ await kill({});
438
+
439
+ return end();
440
+ });