ln-service 53.14.0 → 53.16.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,22 @@
|
|
|
1
1
|
# Versions
|
|
2
2
|
|
|
3
|
+
## 53.16.0
|
|
4
|
+
|
|
5
|
+
- `beginGroupSigningSession`: Add method to start a MuSig2 signing session
|
|
6
|
+
- `endGroupSigningSession`: Add method to complete a MuSig2 signing session
|
|
7
|
+
- `updateGroupSigningSession`: Add method to add nonces to a MuSig2 session
|
|
8
|
+
|
|
9
|
+
## 53.15.0
|
|
10
|
+
|
|
11
|
+
- `getRouteToDestination`, `isDestinationPayable`, `pay`,
|
|
12
|
+
`payViaPaymentDetails`, `payViaPaymentRequest`, `probeForRoute`,
|
|
13
|
+
`subscribeToPayViaDetails`, `subscribeToPayViaRequest`,
|
|
14
|
+
`subscribeToProbeForRoute` - add support for pathfinding `confidence`
|
|
15
|
+
|
|
16
|
+
## 53.14.1
|
|
17
|
+
|
|
18
|
+
- `signTransaction`: Fix multi-input signing for upcoming Taproot API changes
|
|
19
|
+
|
|
3
20
|
## 53.14.0
|
|
4
21
|
|
|
5
22
|
- `addExternalSocket`: Add method to add a socket to graph announcements
|
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-
|
|
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
|
|
@@ -2931,8 +3004,11 @@ Call this iteratively after failed route attempts to get new routes
|
|
|
2931
3004
|
|
|
2932
3005
|
Requires `info:read` permission
|
|
2933
3006
|
|
|
3007
|
+
Preferred `confidence` is not supported on LND 0.14.3 and below
|
|
3008
|
+
|
|
2934
3009
|
{
|
|
2935
3010
|
[cltv_delta]: <Final CLTV Delta Number>
|
|
3011
|
+
[confidence]: <Preferred Route Confidence Number Out of One Million Number>
|
|
2936
3012
|
destination: <Final Send Destination Hex Encoded Public Key String>
|
|
2937
3013
|
[features]: [{
|
|
2938
3014
|
bit: <Feature Bit Number>
|
|
@@ -3331,8 +3407,11 @@ Determine if a payment destination is actually payable by probing it
|
|
|
3331
3407
|
|
|
3332
3408
|
Requires `offchain:write` permission
|
|
3333
3409
|
|
|
3410
|
+
Preferred `confidence` is not supported on LND 0.14.3 and below
|
|
3411
|
+
|
|
3334
3412
|
{
|
|
3335
3413
|
[cltv_delta]: <Final CLTV Delta Number>
|
|
3414
|
+
[confidence]: <Preferred Route Confidence Number Out of One Million Number>
|
|
3336
3415
|
destination: <Pay to Node with Public Key Hex String>
|
|
3337
3416
|
[incoming_peer]: <Pay Through Specific Final Hop Public Key Hex String>
|
|
3338
3417
|
lnd: <Authenticated LND API Object>
|
|
@@ -3612,7 +3691,10 @@ Requires `offchain:write` permission
|
|
|
3612
3691
|
|
|
3613
3692
|
`max_path_mtokens` is not supported in LND 0.12.0 or below
|
|
3614
3693
|
|
|
3694
|
+
Preferred `confidence` is not supported on LND 0.14.3 and below
|
|
3695
|
+
|
|
3615
3696
|
{
|
|
3697
|
+
[confidence]: <Preferred Route Confidence Number Out of One Million Number>
|
|
3616
3698
|
[incoming_peer]: <Pay Through Specific Final Hop Public Key Hex String>
|
|
3617
3699
|
lnd: <Authenticated LND API Object>
|
|
3618
3700
|
[max_fee]: <Maximum Additional Fee Tokens To Pay Number>
|
|
@@ -3699,8 +3781,11 @@ Requires `offchain:write` permission
|
|
|
3699
3781
|
|
|
3700
3782
|
`max_path_mtokens` is not supported in LND 0.12.0 or below
|
|
3701
3783
|
|
|
3784
|
+
Preferred `confidence` is not supported on LND 0.14.3 and below
|
|
3785
|
+
|
|
3702
3786
|
{
|
|
3703
3787
|
[cltv_delta]: <Final CLTV Delta Number>
|
|
3788
|
+
[confidence]: <Preferred Route Confidence Number Out of One Million Number>
|
|
3704
3789
|
destination: <Destination Public Key String>
|
|
3705
3790
|
[features]: [{
|
|
3706
3791
|
bit: <Feature Bit Number>
|
|
@@ -3786,7 +3871,10 @@ Requires `offchain:write` permission
|
|
|
3786
3871
|
|
|
3787
3872
|
`max_path_mtokens` is not supported in LND 0.12.0 or below
|
|
3788
3873
|
|
|
3874
|
+
Preferred `confidence` is not supported on LND 0.14.3 and below
|
|
3875
|
+
|
|
3789
3876
|
{
|
|
3877
|
+
[confidence]: <Preferred Route Confidence Number Out of One Million Number>
|
|
3790
3878
|
[incoming_peer]: <Pay Through Specific Final Hop Public Key Hex String>
|
|
3791
3879
|
lnd: <Authenticated LND API Object>
|
|
3792
3880
|
[max_fee]: <Maximum Fee Tokens To Pay Number>
|
|
@@ -3988,8 +4076,11 @@ If `total_mtokens` are specified, a `payment` nonce is required.
|
|
|
3988
4076
|
|
|
3989
4077
|
Requires `offchain:write` permission
|
|
3990
4078
|
|
|
4079
|
+
Preferred `confidence` is not supported on LND 0.14.3 and below
|
|
4080
|
+
|
|
3991
4081
|
{
|
|
3992
4082
|
[cltv_delta]: <Final CLTV Delta Number>
|
|
4083
|
+
[confidence]: <Preferred Route Confidence Number Out of One Million Number>
|
|
3993
4084
|
destination: <Destination Public Key Hex String>
|
|
3994
4085
|
[features]: [{
|
|
3995
4086
|
bit: <Feature Bit Number>
|
|
@@ -5573,8 +5664,11 @@ Requires `offchain:write` permission
|
|
|
5573
5664
|
|
|
5574
5665
|
`max_path_mtokens` is not supported in LND 0.12.0 or below
|
|
5575
5666
|
|
|
5667
|
+
Preferred `confidence` is not supported on LND 0.14.3 and below
|
|
5668
|
+
|
|
5576
5669
|
{
|
|
5577
5670
|
[cltv_delta]: <Final CLTV Delta Number>
|
|
5671
|
+
[confidence]: <Preferred Route Confidence Number Out of One Million Number>
|
|
5578
5672
|
destination: <Destination Public Key String>
|
|
5579
5673
|
[features]: [{
|
|
5580
5674
|
bit: <Feature Bit Number>
|
|
@@ -5736,7 +5830,10 @@ Requires `offchain:write` permission
|
|
|
5736
5830
|
|
|
5737
5831
|
`max_path_mtokens` is not supported in LND 0.12.0 or below
|
|
5738
5832
|
|
|
5833
|
+
Preferred `confidence` is not supported on LND 0.14.3 and below
|
|
5834
|
+
|
|
5739
5835
|
{
|
|
5836
|
+
[confidence]: <Preferred Route Confidence Number Out of One Million Number>
|
|
5740
5837
|
[incoming_peer]: <Pay Through Specific Final Hop Public Key Hex String>
|
|
5741
5838
|
lnd: <Authenticated LND API Object>
|
|
5742
5839
|
[max_fee]: <Maximum Fee Tokens To Pay Number>
|
|
@@ -6144,8 +6241,11 @@ Subscribe to a probe attempt
|
|
|
6144
6241
|
|
|
6145
6242
|
Requires `offchain:write` permission
|
|
6146
6243
|
|
|
6244
|
+
Preferred `confidence` is not supported on LND 0.14.3 and below
|
|
6245
|
+
|
|
6147
6246
|
{
|
|
6148
6247
|
[cltv_delta]: <Final CLTV Delta Number>
|
|
6248
|
+
[confidence]: <Preferred Route Confidence Number Out of One Million Number>
|
|
6149
6249
|
destination: <Destination Public Key Hex String>
|
|
6150
6250
|
[features]: [{
|
|
6151
6251
|
bit: <Feature Bit Number>
|
|
@@ -6734,6 +6834,43 @@ await updateConnectedWatchtower({
|
|
|
6734
6834
|
});
|
|
6735
6835
|
```
|
|
6736
6836
|
|
|
6837
|
+
### updateGroupSigningSession
|
|
6838
|
+
|
|
6839
|
+
Update a MuSig2 signing session with nonces and generate a partial sig
|
|
6840
|
+
|
|
6841
|
+
All remote nonces are expected to be passed
|
|
6842
|
+
|
|
6843
|
+
Requires LND built with `signrpc` build tag
|
|
6844
|
+
|
|
6845
|
+
Requires `signer:generate` permission
|
|
6846
|
+
|
|
6847
|
+
This method is not supported in LND 0.14.3 and below
|
|
6848
|
+
|
|
6849
|
+
{
|
|
6850
|
+
hash: <Hash to Sign Hex String>
|
|
6851
|
+
id: <MuSig2 Session Id Hex String>
|
|
6852
|
+
lnd: <Authenticated LND API Object>
|
|
6853
|
+
nonces: [<Nonce Hex String>]
|
|
6854
|
+
}
|
|
6855
|
+
|
|
6856
|
+
@returns via cbk or Promise
|
|
6857
|
+
{
|
|
6858
|
+
signature: <Partial Signature Hex String>
|
|
6859
|
+
}
|
|
6860
|
+
|
|
6861
|
+
Example:
|
|
6862
|
+
|
|
6863
|
+
```node
|
|
6864
|
+
const {updateGroupSigningSession} = require('ln-service');
|
|
6865
|
+
|
|
6866
|
+
const {signature} = await updateGroupSigningSession({
|
|
6867
|
+
lnd,
|
|
6868
|
+
hash: v1TxDigestHash,
|
|
6869
|
+
id: sessionId,
|
|
6870
|
+
nonces: [externalNonce],
|
|
6871
|
+
});
|
|
6872
|
+
```
|
|
6873
|
+
|
|
6737
6874
|
### updatePathfindingSettings
|
|
6738
6875
|
|
|
6739
6876
|
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.
|
|
12
|
+
"express": "4.18.1",
|
|
13
13
|
"invoices": "2.0.6",
|
|
14
|
-
"lightning": "5.
|
|
14
|
+
"lightning": "5.15.0",
|
|
15
15
|
"macaroon": "3.0.4",
|
|
16
16
|
"morgan": "1.10.0",
|
|
17
|
-
"ws": "8.
|
|
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.
|
|
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.
|
|
73
|
+
"version": "53.16.0"
|
|
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('
|
|
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
|
+
});
|