paid-services 4.3.5 → 5.0.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 +13 -0
- package/LICENSE +1 -1
- package/groups/assemble_channel_group.js +12 -9
- package/groups/coordinate_channel_group.js +11 -5
- package/groups/create_group_channel.js +17 -1
- package/groups/join_channel_group.js +1 -0
- package/groups/join_group_channel.js +5 -1
- package/groups/p2p/find_group_partners.js +2 -1
- package/groups/p2p/peer_with_partners.js +30 -4
- package/package.json +4 -4
- package/swaps/complete_on_to_off_swap.js +1 -0
- package/test/integration/test_group_noninteractive.js +14 -16
- package/test/integration/test_request_swap_out.js +19 -0
- package/test/integration/test_sign_capacity_replacement.js +3 -1
- package/test/integration/test_swap_with_claim_path.js +21 -0
- package/test/integration/test_swap_with_refund_path.js +12 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Versions
|
|
2
2
|
|
|
3
|
+
## Version 5.0.1
|
|
4
|
+
|
|
5
|
+
- `createGroupChannel`, `joinGroupChannel`, `manageGroupJoin`: Double check
|
|
6
|
+
open channel acceptance when peering
|
|
7
|
+
|
|
8
|
+
## Version 5.0.0
|
|
9
|
+
|
|
10
|
+
- 'createGroupChannel': Repeatedly broadcast chain transaction
|
|
11
|
+
|
|
12
|
+
### Breaking Changes
|
|
13
|
+
|
|
14
|
+
- node.js 14 is no longer supported, node.js 16+ required
|
|
15
|
+
|
|
3
16
|
## Version 4.3.5
|
|
4
17
|
|
|
5
18
|
- `createGroupChannel`: Show members that are present
|
package/LICENSE
CHANGED
|
@@ -47,7 +47,6 @@ const times = 2 * 60 * 10;
|
|
|
47
47
|
// Open is publishing
|
|
48
48
|
@event 'broadcasting'
|
|
49
49
|
{
|
|
50
|
-
id: <Transaction Id Hex String>
|
|
51
50
|
transaction: <Transaction Hex String>
|
|
52
51
|
}
|
|
53
52
|
|
|
@@ -105,16 +104,20 @@ module.exports = ({capacity, count, ecp, identity, lnd, members, rate}) => {
|
|
|
105
104
|
coordinator.events.once('joined', async ({ids}) => {
|
|
106
105
|
emitter.emit('filled', {ids});
|
|
107
106
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
107
|
+
try {
|
|
108
|
+
// Exit early when this is a pair group
|
|
109
|
+
if (count === minGroupCount) {
|
|
110
|
+
const [outbound] = ids.filter(n => n !== identity);
|
|
112
111
|
|
|
113
|
-
|
|
112
|
+
await peerWithPartners({capacity, lnd, outbound});
|
|
114
113
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
return coordinator.connected();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const {inbound, outbound} = coordinator.partners(identity);
|
|
118
|
+
|
|
119
|
+
// Connect to the inbound and outbound partners
|
|
120
|
+
await peerWithPartners({capacity, inbound, lnd, outbound});
|
|
118
121
|
|
|
119
122
|
// Register as connected
|
|
120
123
|
return coordinator.connected();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const asyncAuto = require('async/auto');
|
|
2
2
|
const asyncMap = require('async/map');
|
|
3
|
+
const {broadcastTransaction} = require('ln-sync');
|
|
3
4
|
const {getIdentity} = require('ln-service');
|
|
4
5
|
const {getNodeAlias} = require('ln-sync');
|
|
5
6
|
const {returnResult} = require('asyncjs-util');
|
|
@@ -8,6 +9,7 @@ const tinysecp = require('tiny-secp256k1');
|
|
|
8
9
|
const askForGroupDetails = require('./ask_for_group_details');
|
|
9
10
|
const assembleChannelGroup = require('./assemble_channel_group');
|
|
10
11
|
|
|
12
|
+
const descriptionForGroup = 'group channel open';
|
|
11
13
|
const join = arr => arr.join(', ');
|
|
12
14
|
const niceName = ({alias, id}) => `${alias} ${id}`.trim();
|
|
13
15
|
|
|
@@ -20,10 +22,6 @@ const niceName = ({alias, id}) => `${alias} ${id}`.trim();
|
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
@returns via cbk or Promise
|
|
23
|
-
{
|
|
24
|
-
id: <Transaction Id Hex String>
|
|
25
|
-
transaction: <Raw Transaction Hex String>
|
|
26
|
-
}
|
|
27
25
|
*/
|
|
28
26
|
module.exports = ({ask, lnd, logger}, cbk) => {
|
|
29
27
|
return new Promise((resolve, reject) => {
|
|
@@ -107,7 +105,15 @@ module.exports = ({ask, lnd, logger}, cbk) => {
|
|
|
107
105
|
coordinate.events.once('broadcast', broadcast => {
|
|
108
106
|
coordinate.events.removeAllListeners();
|
|
109
107
|
|
|
110
|
-
|
|
108
|
+
logger.info({transaction_id: broadcast.id});
|
|
109
|
+
|
|
110
|
+
return broadcastTransaction({
|
|
111
|
+
lnd,
|
|
112
|
+
logger,
|
|
113
|
+
description: descriptionForGroup,
|
|
114
|
+
transaction: broadcast.transaction,
|
|
115
|
+
},
|
|
116
|
+
cbk);
|
|
111
117
|
});
|
|
112
118
|
|
|
113
119
|
coordinate.events.once('error', err => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const asyncAuto = require('async/auto');
|
|
2
2
|
const asyncMap = require('async/map');
|
|
3
|
+
const {broadcastTransaction} = require('ln-sync');
|
|
3
4
|
const {getChainBalance} = require('ln-service');
|
|
4
5
|
const {getIdentity} = require('ln-service');
|
|
5
6
|
const {getMethods} = require('ln-service');
|
|
@@ -9,6 +10,7 @@ const tinysecp = require('tiny-secp256k1');
|
|
|
9
10
|
|
|
10
11
|
const assembleChannelGroup = require('./assemble_channel_group');
|
|
11
12
|
|
|
13
|
+
const descriptionForGroup = 'group channel open';
|
|
12
14
|
const halfOf = n => n / 2;
|
|
13
15
|
const {isArray} = Array;
|
|
14
16
|
const isPublicKey = n => !!n && /^0[2-3][0-9A-F]{64}$/i.test(n);
|
|
@@ -214,7 +216,21 @@ module.exports = (args, cbk) => {
|
|
|
214
216
|
coordinate.events.once('broadcast', broadcast => {
|
|
215
217
|
coordinate.events.removeAllListeners();
|
|
216
218
|
|
|
217
|
-
|
|
219
|
+
args.logger.info({transaction_id: broadcast.id});
|
|
220
|
+
|
|
221
|
+
return broadcastTransaction({
|
|
222
|
+
description: descriptionForGroup,
|
|
223
|
+
lnd: args.lnd,
|
|
224
|
+
logger: args.logger,
|
|
225
|
+
transaction: broadcast.transaction,
|
|
226
|
+
},
|
|
227
|
+
err => {
|
|
228
|
+
if (!!err) {
|
|
229
|
+
return cbk(err);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return cbk(null, {transaction_id: broadcast.id});
|
|
233
|
+
});
|
|
218
234
|
});
|
|
219
235
|
|
|
220
236
|
coordinate.events.once('error', err => {
|
|
@@ -80,7 +80,11 @@ module.exports = (args, cbk) => {
|
|
|
80
80
|
({getJoinDetails}, cbk) =>
|
|
81
81
|
{
|
|
82
82
|
if (getJoinDetails.rate > args.max_rate) {
|
|
83
|
-
return cbk([
|
|
83
|
+
return cbk([
|
|
84
|
+
400,
|
|
85
|
+
'ExpectedHigherMaxFeeRateToJoinGroup',
|
|
86
|
+
{needed_max_fee_rate: getJoinDetails.rate},
|
|
87
|
+
]);
|
|
84
88
|
}
|
|
85
89
|
|
|
86
90
|
args.logger.info({waiting_for_other_members: true});
|
|
@@ -21,13 +21,14 @@ const typeGroupChannelId = '1';
|
|
|
21
21
|
|
|
22
22
|
{
|
|
23
23
|
coordinator: <Group Coordinator Identity Public Key Hex String>
|
|
24
|
+
count: <Group Member Count Number>
|
|
24
25
|
id: <Group Identifier Hex String>
|
|
25
26
|
lnd: <Authenticated LND API Object>
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
@returns via cbk or Promise
|
|
29
30
|
{
|
|
30
|
-
inbound: <Inbound Peer Public Key Identity Hex String>
|
|
31
|
+
[inbound]: <Inbound Peer Public Key Identity Hex String>
|
|
31
32
|
outbound: <Outbound Peer Public Key Identity Hex String>
|
|
32
33
|
}
|
|
33
34
|
*/
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const {acceptsChannelOpen} = require('ln-sync');
|
|
1
2
|
const asyncAuto = require('async/auto');
|
|
2
3
|
const asyncRetry = require('async/retry');
|
|
3
4
|
const {connectPeer} = require('ln-sync');
|
|
@@ -9,20 +10,21 @@ const times = 2 * 60 * 30;
|
|
|
9
10
|
/** Peer up with group channel partners
|
|
10
11
|
|
|
11
12
|
{
|
|
12
|
-
|
|
13
|
+
capacity: <Channel Capacity Tokens Number>
|
|
14
|
+
[inbound]: <Inbound Identity Public Key Hex String>
|
|
13
15
|
lnd: <Authenticated LND API Object>
|
|
14
16
|
outbound: <Outbound Identity Public Key Hex String>
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
@returns via cbk or Promise
|
|
18
20
|
*/
|
|
19
|
-
module.exports = ({inbound, lnd, outbound}, cbk) => {
|
|
21
|
+
module.exports = ({capacity, inbound, lnd, outbound}, cbk) => {
|
|
20
22
|
return new Promise((resolve, reject) => {
|
|
21
23
|
return asyncAuto({
|
|
22
24
|
// Check arguments
|
|
23
25
|
validate: cbk => {
|
|
24
|
-
if (!
|
|
25
|
-
return cbk([400, '
|
|
26
|
+
if (!capacity) {
|
|
27
|
+
return cbk([400, 'ExpectedChannelCapacityToPeerWithPartners']);
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
if (!lnd) {
|
|
@@ -38,6 +40,11 @@ module.exports = ({inbound, lnd, outbound}, cbk) => {
|
|
|
38
40
|
|
|
39
41
|
// Attempt connecting to the inbound peer
|
|
40
42
|
connectInbound: ['validate', ({}, cbk) => {
|
|
43
|
+
// Exit early when there is no inbound peer
|
|
44
|
+
if (!inbound) {
|
|
45
|
+
return cbk();
|
|
46
|
+
}
|
|
47
|
+
|
|
41
48
|
return asyncRetry({interval, times}, cbk => {
|
|
42
49
|
return connectPeer({lnd, id: inbound}, cbk);
|
|
43
50
|
},
|
|
@@ -51,6 +58,25 @@ module.exports = ({inbound, lnd, outbound}, cbk) => {
|
|
|
51
58
|
},
|
|
52
59
|
cbk);
|
|
53
60
|
}],
|
|
61
|
+
|
|
62
|
+
// Test if outbound peer would accept a channel
|
|
63
|
+
getAcceptance: ['connectOutbound', ({}, cbk) => {
|
|
64
|
+
return acceptsChannelOpen({
|
|
65
|
+
capacity,
|
|
66
|
+
lnd,
|
|
67
|
+
partner_public_key: outbound,
|
|
68
|
+
},
|
|
69
|
+
cbk);
|
|
70
|
+
}],
|
|
71
|
+
|
|
72
|
+
// Check that the proposal would be accepted
|
|
73
|
+
checkAcceptance: ['getAcceptance', ({getAcceptance}, cbk) => {
|
|
74
|
+
if (!getAcceptance.is_accepted) {
|
|
75
|
+
return cbk([503, 'PeerRejectedChanOpenRequest', {peer: outbound}]);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return cbk();
|
|
79
|
+
}],
|
|
54
80
|
},
|
|
55
81
|
returnResult({reject, resolve}, cbk));
|
|
56
82
|
});
|
package/package.json
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"ecpair": "2.1.0",
|
|
17
17
|
"goldengate": "12.0.5",
|
|
18
18
|
"invoices": "2.2.3",
|
|
19
|
-
"ln-service": "
|
|
19
|
+
"ln-service": "56.1.0",
|
|
20
20
|
"ln-sync": "4.3.2",
|
|
21
21
|
"psbt": "2.7.2",
|
|
22
22
|
"p2tr": "1.3.3",
|
|
@@ -25,12 +25,12 @@
|
|
|
25
25
|
"description": "Lightning Paid Services library",
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@alexbosworth/tap": "15.0.12",
|
|
28
|
-
"ln-docker-daemons": "
|
|
28
|
+
"ln-docker-daemons": "5.0.1",
|
|
29
29
|
"mock-lnd": "1.4.4",
|
|
30
30
|
"secp256k1": "5.0.0"
|
|
31
31
|
},
|
|
32
32
|
"engines": {
|
|
33
|
-
"node": ">=
|
|
33
|
+
"node": ">=16"
|
|
34
34
|
},
|
|
35
35
|
"keywords": [
|
|
36
36
|
"lightning",
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"integration-tests": "tap -j 2 --branches=1 --functions=1 --lines=1 --statements=1 -t 180 test/integration/*.js",
|
|
48
48
|
"test": "tap --branches=1 --functions=1 --lines=1 --statements=1 -t 60 test/actions/*.js test/balanced/*.js test/capacity/*.js test/client/*.js test/config/*.js test/p2p/*.js test/records/*.js test/respond/*.js test/server/*.js test/swaps/*.js test/services/*.js test/trades/*.js"
|
|
49
49
|
},
|
|
50
|
-
"version": "
|
|
50
|
+
"version": "5.0.1"
|
|
51
51
|
}
|
|
@@ -584,6 +584,7 @@ module.exports = (args, cbk) => {
|
|
|
584
584
|
const vout = tx.outs.findIndex(n => n.script.equals(script));
|
|
585
585
|
|
|
586
586
|
args.emitter.emit('update', {
|
|
587
|
+
funding_transaction: signFunding.transaction,
|
|
587
588
|
funding_transaction_id: id,
|
|
588
589
|
funding_transaction_vout: vout,
|
|
589
590
|
});
|
|
@@ -81,12 +81,25 @@ test(`Setup joint channel group`, async ({end, equal, strictSame}) => {
|
|
|
81
81
|
capacity,
|
|
82
82
|
count: nodes.length,
|
|
83
83
|
lnd: control.lnd,
|
|
84
|
-
logger: {info: line => createLog.push(line)},
|
|
84
|
+
logger: {info: line => {createLog.push(line)}},
|
|
85
85
|
members: [],
|
|
86
86
|
rate: feeRate,
|
|
87
87
|
});
|
|
88
88
|
},
|
|
89
89
|
|
|
90
|
+
// Make blocks to activate the channel
|
|
91
|
+
generate: async () => {
|
|
92
|
+
await asyncRetry({interval, times}, async () => {
|
|
93
|
+
await generate({});
|
|
94
|
+
|
|
95
|
+
const {channels} = await getChannels({lnd, is_active: true});
|
|
96
|
+
|
|
97
|
+
if (!channels.length) {
|
|
98
|
+
throw new Error('ExpectedChannelActivation');
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
|
|
90
103
|
// Join the group
|
|
91
104
|
join: async () => {
|
|
92
105
|
return await asyncRetry({interval, times}, async () => {
|
|
@@ -108,21 +121,6 @@ test(`Setup joint channel group`, async ({end, equal, strictSame}) => {
|
|
|
108
121
|
|
|
109
122
|
const ids = [group.join.transaction_id, group.create.transaction_id];
|
|
110
123
|
|
|
111
|
-
// Finished, wait for the channels to activate
|
|
112
|
-
await generate({count});
|
|
113
|
-
|
|
114
|
-
const {getPendingChannels} = require('ln-service');
|
|
115
|
-
|
|
116
|
-
await asyncRetry({interval, times}, async () => {
|
|
117
|
-
await generate({});
|
|
118
|
-
|
|
119
|
-
const {channels} = await getChannels({lnd, is_active: true});
|
|
120
|
-
|
|
121
|
-
if (!channels.length) {
|
|
122
|
-
throw new Error('ExpectedChannelActivation');
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
|
|
126
124
|
strictSame(ids.length, nodes.length, 'Got tx ids');
|
|
127
125
|
} catch (err) {
|
|
128
126
|
strictSame(err, null, 'Expected no failure');
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const asyncRetry = require('async/retry');
|
|
2
|
+
const {broadcastChainTransaction} = require('ln-service');
|
|
2
3
|
const {createChainAddress} = require('ln-service');
|
|
3
4
|
const {createInvoice} = require('ln-service');
|
|
4
5
|
const {getChannelBalance} = require('ln-service');
|
|
@@ -79,6 +80,16 @@ test(`Start offchain swap`, async ({end, equal, strictSame}) => {
|
|
|
79
80
|
await target.generate({count: maturity});
|
|
80
81
|
}
|
|
81
82
|
|
|
83
|
+
// Make sure control can pay off chain to target
|
|
84
|
+
{
|
|
85
|
+
await asyncRetry({interval, times}, async () => {
|
|
86
|
+
return await pay({
|
|
87
|
+
lnd,
|
|
88
|
+
request: (await createInvoice({tokens, lnd: target.lnd})).request,
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
82
93
|
// Collect request messages
|
|
83
94
|
const messages = [];
|
|
84
95
|
|
|
@@ -116,6 +127,14 @@ test(`Start offchain swap`, async ({end, equal, strictSame}) => {
|
|
|
116
127
|
lnd: target.lnd,
|
|
117
128
|
logger: {
|
|
118
129
|
info: async message => {
|
|
130
|
+
// Make sure that target gets the funding transaction
|
|
131
|
+
if (message.funding_transaction) {
|
|
132
|
+
await broadcastChainTransaction({
|
|
133
|
+
lnd: target.lnd,
|
|
134
|
+
transaction: message.funding_transaction,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
119
138
|
if (!!message.response) {
|
|
120
139
|
return cbk({response: message.response});
|
|
121
140
|
}
|
|
@@ -71,8 +71,9 @@ test(`Sign capacity replacement`, async ({end, equal, strictSame}) => {
|
|
|
71
71
|
// Close the channel
|
|
72
72
|
const channelClose = await closeChannel({
|
|
73
73
|
lnd,
|
|
74
|
-
id: channel.id,
|
|
75
74
|
is_force_close: true,
|
|
75
|
+
transaction_id: channel.transaction_id,
|
|
76
|
+
transaction_vout: channel.transaction_vout,
|
|
76
77
|
});
|
|
77
78
|
|
|
78
79
|
// Find the open tx
|
|
@@ -124,6 +125,7 @@ test(`Sign capacity replacement`, async ({end, equal, strictSame}) => {
|
|
|
124
125
|
});
|
|
125
126
|
|
|
126
127
|
await broadcastChainTransaction({transaction, lnd});
|
|
128
|
+
await broadcastChainTransaction({transaction, lnd: target.lnd});
|
|
127
129
|
|
|
128
130
|
await generate({count: maturity});
|
|
129
131
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const asyncRetry = require('async/retry');
|
|
2
|
+
const {broadcastChainTransaction} = require('ln-service');
|
|
2
3
|
const {createChainAddress} = require('ln-service');
|
|
3
4
|
const {createInvoice} = require('ln-service');
|
|
4
5
|
const {getChannelBalance} = require('ln-service');
|
|
@@ -52,6 +53,18 @@ test(`Swap with claim path`, async ({end, equal, strictSame}) => {
|
|
|
52
53
|
});
|
|
53
54
|
});
|
|
54
55
|
|
|
56
|
+
// Make sure control can pay off chain to target
|
|
57
|
+
{
|
|
58
|
+
await asyncRetry({interval, times}, async () => {
|
|
59
|
+
await generate({});
|
|
60
|
+
|
|
61
|
+
return await pay({
|
|
62
|
+
lnd,
|
|
63
|
+
request: (await createInvoice({tokens, lnd: target.lnd})).request,
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
55
68
|
await asyncRetry({interval, times}, async () => {
|
|
56
69
|
const {channels} = await getChannels({lnd, is_active: true});
|
|
57
70
|
|
|
@@ -116,6 +129,14 @@ test(`Swap with claim path`, async ({end, equal, strictSame}) => {
|
|
|
116
129
|
lnd: target.lnd,
|
|
117
130
|
logger: {
|
|
118
131
|
info: async message => {
|
|
132
|
+
// Make sure that target gets the funding transaction
|
|
133
|
+
if (message.funding_transaction) {
|
|
134
|
+
await broadcastChainTransaction({
|
|
135
|
+
lnd: target.lnd,
|
|
136
|
+
transaction: message.funding_transaction,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
119
140
|
if (!!message.response) {
|
|
120
141
|
return cbk({response: message.response});
|
|
121
142
|
}
|
|
@@ -84,6 +84,18 @@ test(`Timeout a swap`, async ({end, equal, strictSame}) => {
|
|
|
84
84
|
await target.generate({count: maturity});
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
// Make sure control can pay off chain to target
|
|
88
|
+
{
|
|
89
|
+
await asyncRetry({interval, times}, async () => {
|
|
90
|
+
await generate({});
|
|
91
|
+
|
|
92
|
+
return await pay({
|
|
93
|
+
lnd,
|
|
94
|
+
request: (await createInvoice({tokens, lnd: target.lnd})).request,
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
87
99
|
// Collect request messages
|
|
88
100
|
const messages = [];
|
|
89
101
|
|