paid-services 3.4.0 → 3.7.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/.prettierignore +2 -0
- package/CHANGELOG.md +16 -0
- package/capacity/accept_capacity_change.js +2 -0
- package/capacity/ask_for_change_details.js +41 -9
- package/capacity/ask_for_decrease.js +167 -49
- package/capacity/capacity_change_requests.js +9 -0
- package/capacity/change_channel_capacity.js +7 -1
- package/capacity/encode_change_request.js +8 -1
- package/capacity/fee_for_replacement.js +3 -7
- package/capacity/get_capacity_change_requests.js +1 -0
- package/capacity/get_capacity_replacement.js +56 -7
- package/capacity/initiate_capacity_change.js +1 -2
- package/capacity/parse_capacity_change_request.js +8 -1
- package/capacity/propose_capacity_change.js +208 -92
- package/capacity/propose_channel_open.js +54 -0
- package/package.json +9 -9
- package/services/response_for_relay.js +0 -1
- package/test/capacity/test_capacity_change_requests.js +1 -0
- package/test/capacity/test_encode_change_request.js +5 -0
- package/test/capacity/test_parse_capacity_change_request.js +1 -0
- package/test/integration/test_accept_capacity_change.js +3 -4
- package/test/integration/test_change_channel_capacity.js +8 -1
- package/test/integration/test_decrease_channel_capacity.js +23 -8
- package/test/integration/test_increase_channel_capacity.js +4 -1
- package/test/integration/test_split_channel_capacity.js +241 -0
- package/trades/accept_trade.js +12 -3
- package/trades/create_trade.js +82 -50
- package/trades/decode_anchored_trade.js +56 -0
- package/trades/encode_anchored_trade.js +35 -0
- package/trades/finalize_trade_secret.js +7 -0
- package/trades/find_trade.js +28 -3
- package/trades/manage_trade.js +15 -4
- package/trades/manage_trades.js +209 -2
- package/trades/request_trade_by_id.js +7 -1
- package/trades/service_anchored_trades.js +181 -0
- package/trades/service_open_trade.js +172 -0
- package/trades/service_trade_requests.js +106 -35
- package/trades/trade_from_invoice.js +51 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const {acceptsChannelOpen} = require('ln-sync');
|
|
2
|
+
const asyncAuto = require('async/auto');
|
|
3
|
+
const {connectPeer} = require('ln-sync');
|
|
4
|
+
const {returnResult} = require('asyncjs-util');
|
|
5
|
+
|
|
6
|
+
/** Check that a channel open would be accepted by a node
|
|
7
|
+
|
|
8
|
+
{
|
|
9
|
+
capacity: <Capacity Tokens Number>
|
|
10
|
+
id: <Node Identity Public Key Hex String>
|
|
11
|
+
lnd: <Authenticated LND API Object>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@returns via cbk or Promise
|
|
15
|
+
{
|
|
16
|
+
is_accepted: <Channel Proposal Is Accepted Bool>
|
|
17
|
+
}
|
|
18
|
+
*/
|
|
19
|
+
module.exports = ({capacity, id, lnd}, cbk) => {
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
return asyncAuto({
|
|
22
|
+
// Check arguments
|
|
23
|
+
validate: cbk => {
|
|
24
|
+
if (!capacity) {
|
|
25
|
+
return cbk([400, 'ExpectedCapacityTokensToProposeChannelOpen']);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!id) {
|
|
29
|
+
return cbk([400, 'ExpectedNodePublicKeyToProposeChannelOpen']);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!lnd) {
|
|
33
|
+
return cbk([400, 'ExpectedAuthenticatedLndToProposeChannelOpen']);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return cbk();
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
// Connect to the peer
|
|
40
|
+
connect: ['validate', ({}, cbk) => connectPeer({id, lnd}, cbk)],
|
|
41
|
+
|
|
42
|
+
// Propose a channel open to check acceptance
|
|
43
|
+
checkAccept: ['connect', ({}, cbk) => {
|
|
44
|
+
return acceptsChannelOpen({
|
|
45
|
+
capacity,
|
|
46
|
+
lnd,
|
|
47
|
+
partner_public_key: id,
|
|
48
|
+
},
|
|
49
|
+
cbk);
|
|
50
|
+
}],
|
|
51
|
+
},
|
|
52
|
+
returnResult({reject, resolve, of: 'checkAccept'}, cbk));
|
|
53
|
+
});
|
|
54
|
+
};
|
package/package.json
CHANGED
|
@@ -7,20 +7,20 @@
|
|
|
7
7
|
"url": "https://github.com/alexbosworth/paid-services/issues"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"async": "3.2.
|
|
11
|
-
"asyncjs-util": "1.2.
|
|
10
|
+
"async": "3.2.3",
|
|
11
|
+
"asyncjs-util": "1.2.8",
|
|
12
12
|
"bolt01": "1.2.3",
|
|
13
13
|
"bolt07": "1.8.0",
|
|
14
|
-
"invoices": "2.0.
|
|
15
|
-
"ln-service": "53.
|
|
16
|
-
"ln-sync": "3.6.
|
|
14
|
+
"invoices": "2.0.3",
|
|
15
|
+
"ln-service": "53.4.0",
|
|
16
|
+
"ln-sync": "3.6.1"
|
|
17
17
|
},
|
|
18
18
|
"description": "Lightning Paid Services library",
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@alexbosworth/tap": "15.0.10",
|
|
21
|
-
"ln-docker-daemons": "2.
|
|
21
|
+
"ln-docker-daemons": "2.2.0",
|
|
22
22
|
"mock-lnd": "1.4.1",
|
|
23
|
-
"secp256k1": "4.0.
|
|
23
|
+
"secp256k1": "4.0.3"
|
|
24
24
|
},
|
|
25
25
|
"engines": {
|
|
26
26
|
"node": ">=12.20"
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"url": "https://github.com/alexbosworth/paid-services.git"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
|
-
"integration-tests": "tap --branches=1 --functions=1 --lines=1 --statements=1 -t
|
|
40
|
+
"integration-tests": "tap --branches=1 --functions=1 --lines=1 --statements=1 -t 180 test/integration/*.js",
|
|
41
41
|
"test": "tap --branches=1 --functions=1 --lines=1 --statements=1 -t 60 test/actions/*.js test/capacity/*.js test/client/*.js test/config/*.js test/p2p/*.js test/records/*.js test/respond/*.js test/server/*.js test/server/*.js test/services/*.js test/trades/*.js"
|
|
42
42
|
},
|
|
43
|
-
"version": "3.
|
|
43
|
+
"version": "3.7.0"
|
|
44
44
|
}
|
|
@@ -18,7 +18,6 @@ const defaultProbeTimeoutMs = 1000 * 60 * 5;
|
|
|
18
18
|
const expiresAt = () => new Date(Date.now() + 1000 * 60 * 30).toISOString();
|
|
19
19
|
const interval = 1000 * 60 * 10;
|
|
20
20
|
const rateDivisor = BigInt(1e6);
|
|
21
|
-
const sumOf = arr => arr.reduce((sum, n) => BigInt(n) + n, BigInt(0));
|
|
22
21
|
const text = 'Relay payment request created';
|
|
23
22
|
const times = 12;
|
|
24
23
|
|
|
@@ -8,6 +8,7 @@ const makeArgs = overrides => {
|
|
|
8
8
|
decrease: 0,
|
|
9
9
|
id: Buffer.alloc(32).toString('hex'),
|
|
10
10
|
increase: undefined,
|
|
11
|
+
type: 1,
|
|
11
12
|
};
|
|
12
13
|
|
|
13
14
|
Object.keys(overrides).forEach(k => args[k] = overrides[k]);
|
|
@@ -29,6 +30,10 @@ const tests = [
|
|
|
29
30
|
type: '2',
|
|
30
31
|
value: '0000000000000000',
|
|
31
32
|
},
|
|
33
|
+
{
|
|
34
|
+
type: '5',
|
|
35
|
+
value: '01',
|
|
36
|
+
},
|
|
32
37
|
],
|
|
33
38
|
},
|
|
34
39
|
},
|
|
@@ -32,7 +32,6 @@ const maturity = 100;
|
|
|
32
32
|
const proposeCapacityChange = propose;
|
|
33
33
|
const signCapacityReplacement = method;
|
|
34
34
|
const size = 2;
|
|
35
|
-
const sumOf = arr => arr.reduce((sum, n) => sum + n, 0);
|
|
36
35
|
const times = 2000;
|
|
37
36
|
const {toOutputScript} = address;
|
|
38
37
|
const weightAsVBytes = n => Math.ceil(n / 4);
|
|
@@ -61,15 +60,15 @@ test(`Accept capacity replacement`, async ({end, equal, strictSame}) => {
|
|
|
61
60
|
|
|
62
61
|
// Wait for the channel to be active
|
|
63
62
|
const channel = await asyncRetry({interval, times}, async () => {
|
|
64
|
-
const [channel] = (await getChannels({lnd
|
|
63
|
+
const [channel] = (await getChannels({lnd})).channels;
|
|
65
64
|
|
|
66
|
-
if (!!channel) {
|
|
65
|
+
if (!!channel && !!channel.is_active) {
|
|
67
66
|
return channel;
|
|
68
67
|
}
|
|
69
68
|
|
|
70
69
|
await generate({});
|
|
71
70
|
|
|
72
|
-
throw new Error('
|
|
71
|
+
throw new Error('ExpectedInitialChannelActivation');
|
|
73
72
|
});
|
|
74
73
|
|
|
75
74
|
// Find the open tx
|
|
@@ -27,7 +27,6 @@ const log = () => {};
|
|
|
27
27
|
const maturity = 100;
|
|
28
28
|
const size = 2;
|
|
29
29
|
const slow = 5000;
|
|
30
|
-
const sumOf = arr => arr.reduce((sum, n) => sum + n, 0);
|
|
31
30
|
const times = 2000;
|
|
32
31
|
const {toOutputScript} = address;
|
|
33
32
|
const weightAsVBytes = n => Math.ceil(n / 4);
|
|
@@ -88,6 +87,10 @@ test(`Accept capacity replacement`, async ({end, equal, strictSame}) => {
|
|
|
88
87
|
return cbk({amount: '0'});
|
|
89
88
|
}
|
|
90
89
|
|
|
90
|
+
if (args.name === 'decrease') {
|
|
91
|
+
return cbk({decrease: 'internal_spend_funds'});
|
|
92
|
+
}
|
|
93
|
+
|
|
91
94
|
if (args.name === 'direction') {
|
|
92
95
|
return cbk({direction: 'decrease'});
|
|
93
96
|
}
|
|
@@ -104,6 +107,10 @@ test(`Accept capacity replacement`, async ({end, equal, strictSame}) => {
|
|
|
104
107
|
return cbk({query: target.id});
|
|
105
108
|
}
|
|
106
109
|
|
|
110
|
+
if (args.name === 'type') {
|
|
111
|
+
return cbk({type: args.default});
|
|
112
|
+
}
|
|
113
|
+
|
|
107
114
|
throw new Error('UnknownQueryNameForInitiator');
|
|
108
115
|
},
|
|
109
116
|
logger: {error: log, info: log},
|
|
@@ -27,7 +27,6 @@ const logger = {error: () => {}, info: () => {}};
|
|
|
27
27
|
const maturity = 100;
|
|
28
28
|
const size = 2;
|
|
29
29
|
const slow = 3000;
|
|
30
|
-
const sumOf = arr => arr.reduce((sum, n) => sum + n, 0);
|
|
31
30
|
const times = 2000;
|
|
32
31
|
const {toOutputScript} = address;
|
|
33
32
|
const weightAsVBytes = n => Math.ceil(n / 4);
|
|
@@ -47,11 +46,13 @@ test(`Decrease capacity replacement`, async ({end, equal, strictSame}) => {
|
|
|
47
46
|
|
|
48
47
|
try {
|
|
49
48
|
// Open up a new channel
|
|
50
|
-
const channelOpen = await
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
const channelOpen = await asyncRetry({interval, times}, async () => {
|
|
50
|
+
return await openChannel({
|
|
51
|
+
lnd,
|
|
52
|
+
local_tokens: capacity,
|
|
53
|
+
partner_public_key: target.id,
|
|
54
|
+
partner_socket: target.socket,
|
|
55
|
+
});
|
|
55
56
|
});
|
|
56
57
|
|
|
57
58
|
// Wait for the channel to be active
|
|
@@ -88,6 +89,10 @@ test(`Decrease capacity replacement`, async ({end, equal, strictSame}) => {
|
|
|
88
89
|
return cbk({amount: '200000'});
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
if (args.name === 'decrease') {
|
|
93
|
+
return cbk({decrease: 'internal_spend_funds'});
|
|
94
|
+
}
|
|
95
|
+
|
|
91
96
|
if (args.name === 'direction') {
|
|
92
97
|
return cbk({direction: 'decrease'});
|
|
93
98
|
}
|
|
@@ -116,6 +121,10 @@ test(`Decrease capacity replacement`, async ({end, equal, strictSame}) => {
|
|
|
116
121
|
return cbk({query: target.id});
|
|
117
122
|
}
|
|
118
123
|
|
|
124
|
+
if (args.name === 'type') {
|
|
125
|
+
return cbk({type: 'Private'});
|
|
126
|
+
}
|
|
127
|
+
|
|
119
128
|
throw new Error('UnexpectedQueryNameForProposingSide');
|
|
120
129
|
},
|
|
121
130
|
});
|
|
@@ -124,7 +133,9 @@ test(`Decrease capacity replacement`, async ({end, equal, strictSame}) => {
|
|
|
124
133
|
// Wait to see the inbound proposal
|
|
125
134
|
waitForProposal: async () => {
|
|
126
135
|
await asyncRetry({interval, times}, async () => {
|
|
127
|
-
const {requests} = await getCapacityChangeRequests({
|
|
136
|
+
const {requests} = await getCapacityChangeRequests({
|
|
137
|
+
lnd: target.lnd,
|
|
138
|
+
});
|
|
128
139
|
|
|
129
140
|
if (!requests.length) {
|
|
130
141
|
throw new Error('FailedToFindChangeRequest');
|
|
@@ -159,7 +170,9 @@ test(`Decrease capacity replacement`, async ({end, equal, strictSame}) => {
|
|
|
159
170
|
interval: slow,
|
|
160
171
|
},
|
|
161
172
|
async () => {
|
|
162
|
-
const
|
|
173
|
+
const {channels} = await getChannels({lnd, is_active: true});
|
|
174
|
+
|
|
175
|
+
const [channel] = channels.filter(n => n.capacity < capacity);
|
|
163
176
|
|
|
164
177
|
await generate({});
|
|
165
178
|
|
|
@@ -167,6 +180,8 @@ test(`Decrease capacity replacement`, async ({end, equal, strictSame}) => {
|
|
|
167
180
|
throw new Error('ExpectedChannelActivation');
|
|
168
181
|
}
|
|
169
182
|
|
|
183
|
+
equal(channel.is_private, true, 'Channel is changed to private');
|
|
184
|
+
|
|
170
185
|
{
|
|
171
186
|
const {policies} = await getChannel({lnd, id: channel.id});
|
|
172
187
|
|
|
@@ -26,7 +26,6 @@ const interval = 10;
|
|
|
26
26
|
const logger = {error: () => {}, info: () => {}};
|
|
27
27
|
const maturity = 100;
|
|
28
28
|
const size = 2;
|
|
29
|
-
const sumOf = arr => arr.reduce((sum, n) => sum + n, 0);
|
|
30
29
|
const times = 2000;
|
|
31
30
|
const {toOutputScript} = address;
|
|
32
31
|
const weightAsVBytes = n => Math.ceil(n / 4);
|
|
@@ -111,6 +110,10 @@ test(`Accept capacity replacement`, async ({end, equal, strictSame}) => {
|
|
|
111
110
|
return cbk({query: target.id});
|
|
112
111
|
}
|
|
113
112
|
|
|
113
|
+
if (args.name === 'type') {
|
|
114
|
+
return cbk({type: args.default});
|
|
115
|
+
}
|
|
116
|
+
|
|
114
117
|
throw new Error('UnexpectedQueryNameForProposingSide');
|
|
115
118
|
},
|
|
116
119
|
});
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
const {addPeer} = require('ln-service');
|
|
2
|
+
const {address} = require('bitcoinjs-lib');
|
|
3
|
+
const asyncAuto = require('async/auto');
|
|
4
|
+
const asyncMap = require('async/map');
|
|
5
|
+
const asyncRetry = require('async/retry');
|
|
6
|
+
const {broadcastChainTransaction} = require('ln-service');
|
|
7
|
+
const {closeChannel} = require('ln-service');
|
|
8
|
+
const {createChainAddress} = require('ln-service');
|
|
9
|
+
const {getChainTransactions} = require('ln-service');
|
|
10
|
+
const {getChannel} = require('ln-service');
|
|
11
|
+
const {getChannels} = require('ln-service');
|
|
12
|
+
const {getNetwork} = require('ln-sync');
|
|
13
|
+
const {networks} = require('bitcoinjs-lib');
|
|
14
|
+
const {openChannel} = require('ln-service');
|
|
15
|
+
const {spawnLightningCluster} = require('ln-docker-daemons');
|
|
16
|
+
const {test} = require('@alexbosworth/tap');
|
|
17
|
+
const {Transaction} = require('bitcoinjs-lib');
|
|
18
|
+
|
|
19
|
+
const {changeChannelCapacity} = require('./../../capacity');
|
|
20
|
+
const {getCapacityChangeRequests} = require('./../../capacity');
|
|
21
|
+
|
|
22
|
+
const bufferAsHex = buffer => buffer.toString('hex');
|
|
23
|
+
const capacity = 1e6;
|
|
24
|
+
const {fromHex} = Transaction;
|
|
25
|
+
const id = Buffer.alloc(32).toString('hex');
|
|
26
|
+
const interval = 10;
|
|
27
|
+
const logger = {error: () => {}, info: () => {}};
|
|
28
|
+
const maturity = 100;
|
|
29
|
+
const size = 3;
|
|
30
|
+
const slow = 3000;
|
|
31
|
+
const splitCapacity = 200000;
|
|
32
|
+
const sumOf = arr => arr.reduce((sum, n) => sum + n, 0);
|
|
33
|
+
const times = 2000;
|
|
34
|
+
const {toOutputScript} = address;
|
|
35
|
+
const weightAsVBytes = n => Math.ceil(n / 4);
|
|
36
|
+
|
|
37
|
+
// A capacity replacement proposal should be counter signed and accepted
|
|
38
|
+
test(`Decrease capacity replacement`, async ({end, equal, strictSame}) => {
|
|
39
|
+
const {kill, nodes} = await spawnLightningCluster({size});
|
|
40
|
+
|
|
41
|
+
const [control, target, remote] = nodes;
|
|
42
|
+
|
|
43
|
+
const {generate, lnd} = control;
|
|
44
|
+
|
|
45
|
+
const network = networks[(await getNetwork({lnd})).bitcoinjs];
|
|
46
|
+
|
|
47
|
+
// Make some funds
|
|
48
|
+
await generate({count: maturity});
|
|
49
|
+
|
|
50
|
+
// Add remote as a peer
|
|
51
|
+
await addPeer({lnd, public_key: remote.id, socket: remote.socket});
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
// Open up a new channel
|
|
55
|
+
const channelOpen = await asyncRetry({interval, times}, async () => {
|
|
56
|
+
return await openChannel({
|
|
57
|
+
lnd,
|
|
58
|
+
local_tokens: capacity,
|
|
59
|
+
partner_public_key: target.id,
|
|
60
|
+
partner_socket: target.socket,
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Wait for the channel to be active
|
|
65
|
+
const channel = await asyncRetry({interval, times}, async () => {
|
|
66
|
+
const [channel] = (await getChannels({lnd, is_active: true})).channels;
|
|
67
|
+
|
|
68
|
+
if (!channel) {
|
|
69
|
+
await generate({});
|
|
70
|
+
|
|
71
|
+
throw new Error('ExpectedChannelActivation');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const {policies} = await getChannel({lnd, id: channel.id});
|
|
75
|
+
|
|
76
|
+
const noPolicy = policies.find(n => !n.cltv_delta);
|
|
77
|
+
|
|
78
|
+
if (!!channel && !noPolicy) {
|
|
79
|
+
return channel;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
await generate({});
|
|
83
|
+
|
|
84
|
+
throw new Error('ExpectedChannelActivation');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
await asyncAuto({
|
|
88
|
+
// Propose the channel
|
|
89
|
+
propose: async () => {
|
|
90
|
+
await changeChannelCapacity({
|
|
91
|
+
lnd,
|
|
92
|
+
logger,
|
|
93
|
+
ask: (args, cbk) => {
|
|
94
|
+
if (args.name === 'add') {
|
|
95
|
+
return cbk({add: false});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (args.name === 'amount') {
|
|
99
|
+
return cbk({amount: splitCapacity});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (args.name === 'decrease') {
|
|
103
|
+
return cbk({decrease: 'open_channel'});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (args.name === 'direction') {
|
|
107
|
+
return cbk({direction: 'decrease'});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (args.name === 'internal') {
|
|
111
|
+
return cbk({internal: true});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (args.name === 'key') {
|
|
115
|
+
return cbk({key: remote.id});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (args.name === 'ok') {
|
|
119
|
+
return cbk({ok: true});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (args.name === 'proceed') {
|
|
123
|
+
return cbk({proceed: true});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (args.name === 'rate') {
|
|
127
|
+
return cbk({rate: args.default});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (args.name === 'spend') {
|
|
131
|
+
return cbk({spend: false});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (args.name === 'query') {
|
|
135
|
+
return cbk({query: target.id});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (args.name === 'type') {
|
|
139
|
+
return cbk({type: 'Private'});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
throw new Error('UnexpectedQueryNameForProposingSide');
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
// Wait to see the inbound proposal
|
|
148
|
+
waitForProposal: async () => {
|
|
149
|
+
await asyncRetry({interval, times}, async () => {
|
|
150
|
+
const {requests} = await getCapacityChangeRequests({
|
|
151
|
+
lnd: target.lnd,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
if (!requests.length) {
|
|
155
|
+
throw new Error('FailedToFindChangeRequest');
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
// Accept the channel
|
|
161
|
+
accept: ['waitForProposal', async ({}) => {
|
|
162
|
+
await changeChannelCapacity({
|
|
163
|
+
logger,
|
|
164
|
+
ask: (args, cbk) => {
|
|
165
|
+
if (args.name === 'accept') {
|
|
166
|
+
return cbk({accept: true});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (args.name === 'ok') {
|
|
170
|
+
return cbk({ok: true});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
throw new Error('UnexpectedQueryNameForAcceptingSide');
|
|
174
|
+
},
|
|
175
|
+
lnd: target.lnd,
|
|
176
|
+
});
|
|
177
|
+
}],
|
|
178
|
+
|
|
179
|
+
// Generate to confirm the change
|
|
180
|
+
generate: ['waitForProposal', async ({}) => {
|
|
181
|
+
// Wait for the new channel to be active
|
|
182
|
+
const recreated = await asyncRetry({
|
|
183
|
+
times,
|
|
184
|
+
interval: slow,
|
|
185
|
+
},
|
|
186
|
+
async () => {
|
|
187
|
+
const {channels} = await getChannels({lnd, is_active: true});
|
|
188
|
+
|
|
189
|
+
const [channel] = channels
|
|
190
|
+
.filter(n => n.is_private)
|
|
191
|
+
.filter(n => n.capacity < capacity);
|
|
192
|
+
|
|
193
|
+
await generate({});
|
|
194
|
+
|
|
195
|
+
if (!channel) {
|
|
196
|
+
throw new Error('ExpectedChannelActivation');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const channelWithRemote = channels.find(channel => {
|
|
200
|
+
return channel.partner_public_key === remote.id;
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
equal(channelWithRemote.capacity, splitCapacity, 'Remote created');
|
|
204
|
+
|
|
205
|
+
{
|
|
206
|
+
const {policies} = await getChannel({lnd, id: channel.id});
|
|
207
|
+
|
|
208
|
+
const noPolicy = policies.find(n => !n.cltv_delta);
|
|
209
|
+
|
|
210
|
+
if (!!noPolicy) {
|
|
211
|
+
throw new Error('ExpectedChannelPolicy');
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
{
|
|
216
|
+
const {policies} = await getChannel({
|
|
217
|
+
id: channel.id,
|
|
218
|
+
lnd: target.lnd,
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const noPolicy = policies.find(n => !n.cltv_delta);
|
|
222
|
+
|
|
223
|
+
if (!!noPolicy) {
|
|
224
|
+
throw new Error('ExpectedChannelPolicy');
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
return;
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
return;
|
|
232
|
+
}],
|
|
233
|
+
});
|
|
234
|
+
} catch (err) {
|
|
235
|
+
strictSame(err, null, 'Expected no failure');
|
|
236
|
+
} finally {
|
|
237
|
+
await kill({});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return end();
|
|
241
|
+
});
|
package/trades/accept_trade.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const asyncAuto = require('async/auto');
|
|
2
2
|
const asyncEach = require('async/each');
|
|
3
3
|
const {cancelHodlInvoice} = require('ln-service');
|
|
4
|
+
const {getInvoice} = require('ln-service');
|
|
4
5
|
const {returnResult} = require('asyncjs-util');
|
|
5
6
|
const {settleHodlInvoice} = require('ln-service');
|
|
6
7
|
|
|
@@ -10,13 +11,14 @@ const {isArray} = Array;
|
|
|
10
11
|
|
|
11
12
|
{
|
|
12
13
|
cancel: [<Alternative Invoice Id Hex String>]
|
|
14
|
+
id: <Trade Id Hex String>
|
|
13
15
|
lnd: <Authenticated LND API Object>
|
|
14
16
|
secret: <Invoice to Settle Preimage Hex String>
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
@returns via cbk or Promise
|
|
18
20
|
*/
|
|
19
|
-
module.exports = ({cancel, lnd, secret}, cbk) => {
|
|
21
|
+
module.exports = ({cancel, id, lnd, secret}, cbk) => {
|
|
20
22
|
return new Promise((resolve, reject) => {
|
|
21
23
|
return asyncAuto({
|
|
22
24
|
// Check arguments
|
|
@@ -25,6 +27,10 @@ module.exports = ({cancel, lnd, secret}, cbk) => {
|
|
|
25
27
|
return cbk([400, 'ExpectedArrayOfIdsToCancelToAcceptTrade']);
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
if (!id) {
|
|
31
|
+
return cbk([400, 'ExpectedAnchorTradeIdToAcceptTrade']);
|
|
32
|
+
}
|
|
33
|
+
|
|
28
34
|
if (!lnd) {
|
|
29
35
|
return cbk([400, 'ExpectedAuthenticatedLndToAcceptTrade']);
|
|
30
36
|
}
|
|
@@ -36,9 +42,12 @@ module.exports = ({cancel, lnd, secret}, cbk) => {
|
|
|
36
42
|
return cbk();
|
|
37
43
|
},
|
|
38
44
|
|
|
45
|
+
// Fetch the anchor invoice to make sure it's still open
|
|
46
|
+
getAnchor: ['validate', ({}, cbk) => getInvoice({id, lnd}, cbk)],
|
|
47
|
+
|
|
39
48
|
// Cancel alternative invoices so that only one resolves as settled
|
|
40
|
-
cancel: ['
|
|
41
|
-
return asyncEach(cancel, (id, cbk) => {
|
|
49
|
+
cancel: ['getAnchor', ({}, cbk) => {
|
|
50
|
+
return asyncEach([].concat(cancel).concat(id), (id, cbk) => {
|
|
42
51
|
return cancelHodlInvoice({id, lnd}, cbk);
|
|
43
52
|
},
|
|
44
53
|
cbk);
|