paid-services 3.10.0 → 3.11.4
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 +4 -0
- package/capacity/accept_capacity_change.js +7 -1
- package/capacity/ask_for_change_details.js +101 -19
- package/capacity/ask_to_select_change.js +109 -0
- package/capacity/capacity_change_requests.js +2 -0
- package/capacity/change_channel_capacity.js +44 -43
- package/capacity/describe_capacity_change.js +38 -0
- package/capacity/encode_change_request.js +17 -3
- package/capacity/fee_for_replacement.js +1 -1
- package/capacity/get_capacity_change_requests.js +1 -0
- package/capacity/get_capacity_replacement.js +20 -1
- package/capacity/get_replacement_signature.js +8 -3
- package/capacity/initiate_capacity_change.js +18 -3
- package/capacity/interim_replacement_psbt.js +2 -0
- package/capacity/parse_capacity_change_request.js +30 -8
- package/capacity/propose_capacity_change.js +32 -13
- package/package.json +7 -5
- package/test/capacity/test_capacity_change_requests.js +1 -0
- package/test/capacity/test_encode_change_request.js +4 -0
- package/test/integration/test_accept_capacity_change.js +21 -6
- package/test/integration/test_change_channel_capacity.js +10 -6
- package/test/integration/test_decrease_channel_capacity.js +2 -0
- package/test/integration/test_increase_channel_capacity.js +2 -0
- package/test/integration/test_move_channel_capacity.js +230 -0
- package/test/integration/test_split_channel_capacity.js +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -32,6 +32,7 @@ const openTxType = '1';
|
|
|
32
32
|
[increase]: <Increase Tokens Number>
|
|
33
33
|
lnd: <Authenticated LND API Object>
|
|
34
34
|
logger: <Winston Logger Object>
|
|
35
|
+
to: <Expect Channel from Public Key Hex String>
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
@returns via cbk or Promise
|
|
@@ -43,7 +44,7 @@ const openTxType = '1';
|
|
|
43
44
|
transaction_vout: <Replacement Channel Transaction Output Index Number>
|
|
44
45
|
}
|
|
45
46
|
*/
|
|
46
|
-
module.exports = ({channel, from, id, increase, lnd, logger}, cbk) => {
|
|
47
|
+
module.exports = ({channel, from, id, increase, lnd, logger, to}, cbk) => {
|
|
47
48
|
return new Promise((resolve, reject) => {
|
|
48
49
|
return asyncAuto({
|
|
49
50
|
// Check arguments
|
|
@@ -68,6 +69,10 @@ module.exports = ({channel, from, id, increase, lnd, logger}, cbk) => {
|
|
|
68
69
|
return cbk([400, 'ExpectedLoggerObjectToAcceptCapacityChange']);
|
|
69
70
|
}
|
|
70
71
|
|
|
72
|
+
if (!to) {
|
|
73
|
+
return cbk([400, 'ExpectedToPublicKeyToAcceptCapacityChange']);
|
|
74
|
+
}
|
|
75
|
+
|
|
71
76
|
return cbk();
|
|
72
77
|
},
|
|
73
78
|
|
|
@@ -219,6 +224,7 @@ module.exports = ({channel, from, id, increase, lnd, logger}, cbk) => {
|
|
|
219
224
|
channel,
|
|
220
225
|
lnd,
|
|
221
226
|
output,
|
|
227
|
+
to,
|
|
222
228
|
id: parameters.id,
|
|
223
229
|
unsigned: parseSignCapacityRequest(parameters).unsigned,
|
|
224
230
|
vout: parameters.vout,
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
const asyncAuto = require('async/auto');
|
|
2
2
|
const asyncUntil = require('async/until');
|
|
3
|
+
const {connectPeer} = require('ln-sync');
|
|
3
4
|
const {findKey} = require('ln-sync');
|
|
4
5
|
const {getChainFeeRate} = require('ln-service');
|
|
5
6
|
const {getChainTransactions} = require('ln-service');
|
|
6
7
|
const {getChannel} = require('ln-service');
|
|
7
8
|
const {getChannels} = require('ln-service');
|
|
9
|
+
const {getNodeAlias} = require('ln-sync');
|
|
8
10
|
const {getPeers} = require('ln-service');
|
|
9
11
|
const {returnResult} = require('asyncjs-util');
|
|
10
12
|
const {sendMessageToPeer} = require('ln-service');
|
|
@@ -16,6 +18,7 @@ const feeForReplacement = require('./fee_for_replacement');
|
|
|
16
18
|
const {ceil} = Math;
|
|
17
19
|
const dust = 550;
|
|
18
20
|
const dustBuffer = 750;
|
|
21
|
+
const {isArray} = Array;
|
|
19
22
|
const isNumber = n => !isNaN(n);
|
|
20
23
|
const largeChannelsBit = 19;
|
|
21
24
|
const maxSats = 21e6 * 1e8;
|
|
@@ -40,6 +43,11 @@ const weightBuffer = 150;
|
|
|
40
43
|
ask: <Ask Function>
|
|
41
44
|
id: <Request Identifier Hex String>
|
|
42
45
|
lnd: <Authenticated LND API Object>
|
|
46
|
+
nodes: [{
|
|
47
|
+
lnd: <Potential Move Node LND API Object>
|
|
48
|
+
node_name: <Potential Move Node Name String>
|
|
49
|
+
public_key: <Potential Move Node Public Key Hex String>
|
|
50
|
+
}]
|
|
43
51
|
}
|
|
44
52
|
|
|
45
53
|
@returns via cbk or Promise
|
|
@@ -59,6 +67,8 @@ const weightBuffer = 150;
|
|
|
59
67
|
id: <Standard Format Channel Id String>
|
|
60
68
|
increase: <Channel Capacity Increase Tokens Number>
|
|
61
69
|
is_private: <Channel is Private Bool>
|
|
70
|
+
[open_from]: <Open Replacement Channel From Node with Public Key String>
|
|
71
|
+
open_lnd: <Open Replacement Channel with LND API Object>
|
|
62
72
|
[open_transaction]: <Channel Open Transaction Hex String>
|
|
63
73
|
partner_csv_delay: <Peer CSV Delay Number>
|
|
64
74
|
partner_public_key: <Node to Ask For Capacity Change Public Key Hex String>
|
|
@@ -70,7 +80,7 @@ const weightBuffer = 150;
|
|
|
70
80
|
transaction_id: <Channel Funding Transaction Id Hex String>
|
|
71
81
|
}
|
|
72
82
|
*/
|
|
73
|
-
module.exports = ({ask, id, lnd}, cbk) => {
|
|
83
|
+
module.exports = ({ask, id, lnd, nodes}, cbk) => {
|
|
74
84
|
return new Promise((resolve, reject) => {
|
|
75
85
|
return asyncAuto({
|
|
76
86
|
// Check arguments
|
|
@@ -87,6 +97,10 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
87
97
|
return cbk([400, 'ExpectedLndToAskForChangeDetails']);
|
|
88
98
|
}
|
|
89
99
|
|
|
100
|
+
if (!isArray(nodes)) {
|
|
101
|
+
return cbk([400, 'ExpectedArrayOfPotentialMoveNodesToAskForChange']);
|
|
102
|
+
}
|
|
103
|
+
|
|
90
104
|
return cbk();
|
|
91
105
|
},
|
|
92
106
|
|
|
@@ -112,7 +126,7 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
112
126
|
return getChainFeeRate({lnd, confirmation_target: slowTarget}, cbk);
|
|
113
127
|
}],
|
|
114
128
|
|
|
115
|
-
// Find the public key or alias entered
|
|
129
|
+
// Find the node with the public key or alias entered
|
|
116
130
|
findKey: [
|
|
117
131
|
'askForPeer',
|
|
118
132
|
'getChannels',
|
|
@@ -126,6 +140,11 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
126
140
|
cbk);
|
|
127
141
|
}],
|
|
128
142
|
|
|
143
|
+
// Get the alias of the peer
|
|
144
|
+
getAlias: ['findKey', ({findKey}, cbk) => {
|
|
145
|
+
return getNodeAlias({lnd, id: findKey.public_key}, cbk);
|
|
146
|
+
}],
|
|
147
|
+
|
|
129
148
|
// Send a test message to the selected peer to confirm they are connected
|
|
130
149
|
testPeer: ['findKey', 'getChannels', ({findKey, getChannels}, cbk) => {
|
|
131
150
|
const hasPeer = !!getChannels.channels.find(channel => {
|
|
@@ -190,7 +209,7 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
190
209
|
return ask({
|
|
191
210
|
choices,
|
|
192
211
|
loop: false,
|
|
193
|
-
message: 'Channel to change
|
|
212
|
+
message: 'Channel to change?',
|
|
194
213
|
name: 'id',
|
|
195
214
|
type: 'list',
|
|
196
215
|
},
|
|
@@ -294,20 +313,32 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
294
313
|
}],
|
|
295
314
|
|
|
296
315
|
// Choose whether to add or remove coins
|
|
297
|
-
askForDirection: ['channel', ({channel}, cbk) => {
|
|
316
|
+
askForDirection: ['channel', 'getAlias', ({channel, getAlias}, cbk) => {
|
|
317
|
+
const {alias} = getAlias;
|
|
318
|
+
|
|
319
|
+
const choices = [
|
|
320
|
+
{
|
|
321
|
+
disabled: !channel.max_increase_tokens,
|
|
322
|
+
name: `Increase capacity (currently ${channel.capacity})`,
|
|
323
|
+
value: 'increase',
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
disabled: !channel.max_decrease_tokens,
|
|
327
|
+
name: `Decrease capacity (limit ${channel.max_decrease_tokens})`,
|
|
328
|
+
value: 'decrease',
|
|
329
|
+
},
|
|
330
|
+
];
|
|
331
|
+
|
|
332
|
+
if (!!nodes.filter(n => n.public_key !== getAlias.id).length) {
|
|
333
|
+
choices.push({
|
|
334
|
+
disabled: !channel.max_decrease_tokens,
|
|
335
|
+
name: `Move the channel with ${alias} to another of your nodes?`,
|
|
336
|
+
value: 'migrate',
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
|
|
298
340
|
return ask({
|
|
299
|
-
choices
|
|
300
|
-
{
|
|
301
|
-
disabled: !channel.max_increase_tokens,
|
|
302
|
-
name: `Increase capacity (currently ${channel.capacity})`,
|
|
303
|
-
value: 'increase',
|
|
304
|
-
},
|
|
305
|
-
{
|
|
306
|
-
disabled: !channel.max_decrease_tokens,
|
|
307
|
-
name: `Decrease capacity (limit ${channel.max_decrease_tokens})`,
|
|
308
|
-
value: 'decrease',
|
|
309
|
-
},
|
|
310
|
-
],
|
|
341
|
+
choices,
|
|
311
342
|
message: 'How do you want to change the channel capacity?',
|
|
312
343
|
name: 'direction',
|
|
313
344
|
type: 'list',
|
|
@@ -315,6 +346,51 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
315
346
|
({direction}) => cbk(null, direction));
|
|
316
347
|
}],
|
|
317
348
|
|
|
349
|
+
// Ask for migration
|
|
350
|
+
askForMigration: [
|
|
351
|
+
'askForDirection',
|
|
352
|
+
'channel',
|
|
353
|
+
({askForDirection, channel}, cbk) =>
|
|
354
|
+
{
|
|
355
|
+
// Exit early if not decrease or no saved nodes
|
|
356
|
+
if (askForDirection !== 'migrate') {
|
|
357
|
+
return cbk();
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const peer = channel.partner_public_key;
|
|
361
|
+
|
|
362
|
+
const potentialNodes = nodes.filter(n => n.public_key !== peer);
|
|
363
|
+
|
|
364
|
+
return ask({
|
|
365
|
+
choices: potentialNodes.map((node, i) => ({
|
|
366
|
+
name: `${node.node_name} ${node.public_key}`,
|
|
367
|
+
value: i,
|
|
368
|
+
})),
|
|
369
|
+
message: 'Move channel to?',
|
|
370
|
+
name: 'migration',
|
|
371
|
+
type: 'list',
|
|
372
|
+
},
|
|
373
|
+
({migration}) => cbk(null, potentialNodes[migration]));
|
|
374
|
+
}],
|
|
375
|
+
|
|
376
|
+
// Add peer from migrating node
|
|
377
|
+
connect: [
|
|
378
|
+
'askForMigration',
|
|
379
|
+
'findKey',
|
|
380
|
+
({askForMigration, findKey}, cbk) =>
|
|
381
|
+
{
|
|
382
|
+
// Exit early if its there is no migration
|
|
383
|
+
if (!askForMigration) {
|
|
384
|
+
return cbk();
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return connectPeer({
|
|
388
|
+
id: findKey.public_key,
|
|
389
|
+
lnd: askForMigration.lnd,
|
|
390
|
+
},
|
|
391
|
+
cbk);
|
|
392
|
+
}],
|
|
393
|
+
|
|
318
394
|
// Ask for how much to decrease
|
|
319
395
|
askForDecrease: [
|
|
320
396
|
'askForDirection',
|
|
@@ -400,6 +476,7 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
400
476
|
askForPublicPrivate: [
|
|
401
477
|
'askForDecrease',
|
|
402
478
|
'askForIncrease',
|
|
479
|
+
'askForMigration',
|
|
403
480
|
'channel',
|
|
404
481
|
({channel}, cbk) =>
|
|
405
482
|
{
|
|
@@ -452,12 +529,10 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
452
529
|
{
|
|
453
530
|
const {fee} = estimateChainFee;
|
|
454
531
|
|
|
455
|
-
const pay = `Pay estimated on-chain channel replacement fee: ${fee}`;
|
|
456
|
-
|
|
457
532
|
return ask({
|
|
458
533
|
type: 'confirm',
|
|
459
534
|
name: 'proceed',
|
|
460
|
-
message:
|
|
535
|
+
message: `Pay estimated channel replacement chain-fee: ${fee}?`,
|
|
461
536
|
},
|
|
462
537
|
({proceed}) => cbk(null, proceed));
|
|
463
538
|
}],
|
|
@@ -466,16 +541,20 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
466
541
|
details: [
|
|
467
542
|
'askForDecrease',
|
|
468
543
|
'askForIncrease',
|
|
544
|
+
'askForMigration',
|
|
469
545
|
'askForPublicPrivate',
|
|
470
546
|
'channel',
|
|
547
|
+
'connect',
|
|
471
548
|
'confirmFeeEstimate',
|
|
472
549
|
'estimateChainFee',
|
|
473
550
|
'getTx',
|
|
474
551
|
({
|
|
475
552
|
askForDecrease,
|
|
476
553
|
askForIncrease,
|
|
554
|
+
askForMigration,
|
|
477
555
|
askForPublicPrivate,
|
|
478
556
|
channel,
|
|
557
|
+
connect,
|
|
479
558
|
confirmFeeEstimate,
|
|
480
559
|
estimateChainFee,
|
|
481
560
|
getTx,
|
|
@@ -509,6 +588,7 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
509
588
|
channel: channel.id,
|
|
510
589
|
decrease: !!askForDecrease ? sumOfTokens(askForDecrease) : undefined,
|
|
511
590
|
increase: askForIncrease,
|
|
591
|
+
to: !!askForMigration ? askForMigration.public_key : undefined,
|
|
512
592
|
type: askForPublicPrivate.is_private ? privateType : publicType,
|
|
513
593
|
});
|
|
514
594
|
|
|
@@ -524,6 +604,8 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
524
604
|
id: channel.id,
|
|
525
605
|
increase: askForIncrease,
|
|
526
606
|
is_private: askForPublicPrivate.is_private,
|
|
607
|
+
open_from: !!askForMigration ? askForMigration.public_key : null,
|
|
608
|
+
open_lnd: !!askForMigration ? askForMigration.lnd : lnd,
|
|
527
609
|
open_transaction: channel.open_transaction,
|
|
528
610
|
partner_csv_delay: channel.partner_csv_delay,
|
|
529
611
|
partner_public_key: channel.partner_public_key,
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
const asyncAuto = require('async/auto');
|
|
2
|
+
const {getNodeAlias} = require('ln-sync');
|
|
3
|
+
const {returnResult} = require('asyncjs-util');
|
|
4
|
+
|
|
5
|
+
const describeCapacityChange = require('./describe_capacity_change');
|
|
6
|
+
|
|
7
|
+
/** Ask to select a change
|
|
8
|
+
|
|
9
|
+
{
|
|
10
|
+
ask: <Inquirer Ask Function>
|
|
11
|
+
[address]: <Cooperative Close Address String>
|
|
12
|
+
capacity: <Channel Capacity Tokens Number>
|
|
13
|
+
channel: <Change Channel Id String>
|
|
14
|
+
[decrease]: <Capacity Change Decrease Tokens Number>
|
|
15
|
+
from_id: <Peer Public Key Hex String>
|
|
16
|
+
[increase]: <Capacity Change Increase Tokens Number>
|
|
17
|
+
lnd: <Authenticated LND API Object>
|
|
18
|
+
[to_id]: <Node Public Key Hex String>
|
|
19
|
+
[type]: <Channel Type String>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@returns via cbk or Promise
|
|
23
|
+
{
|
|
24
|
+
is_selected: <Request to Change Channel is Selected Bool>
|
|
25
|
+
}
|
|
26
|
+
*/
|
|
27
|
+
module.exports = (args, cbk) => {
|
|
28
|
+
return new Promise((resolve, reject) => {
|
|
29
|
+
return asyncAuto({
|
|
30
|
+
// Check arguments
|
|
31
|
+
validate: cbk => {
|
|
32
|
+
if (!args.ask) {
|
|
33
|
+
return cbk([400, 'ExpectedAskFunctionToAskToSelectChange']);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!args.capacity) {
|
|
37
|
+
return cbk([400, 'ExpectedChannelCapacityToAskToSelectChange']);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!args.channel) {
|
|
41
|
+
return cbk([400, 'ExpectedChannelIdToAskToSelectAChangeFor']);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (!args.from_id) {
|
|
45
|
+
return cbk([400, 'ExpectedChannelPartnerPublicKeyToSelectChange']);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!args.lnd) {
|
|
49
|
+
return cbk([400, 'ExpectedLndApiToAskToSelectChange']);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return cbk();
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
// Get the peer alias
|
|
56
|
+
getPeerAlias: ['validate', ({}, cbk) => {
|
|
57
|
+
return getNodeAlias({id: args.from_id, lnd: args.lnd}, cbk);
|
|
58
|
+
}],
|
|
59
|
+
|
|
60
|
+
// Get the alias of the node to move to
|
|
61
|
+
getNodeAlias: ['validate', ({}, cbk) => {
|
|
62
|
+
// Exit early when there is no new node to move to
|
|
63
|
+
if (!args.to_id) {
|
|
64
|
+
return cbk(null, {});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return getNodeAlias({id: args.to_id, lnd: args.lnd}, cbk);
|
|
68
|
+
}],
|
|
69
|
+
|
|
70
|
+
// Confirm acceptance of the change
|
|
71
|
+
confirm: [
|
|
72
|
+
'getNodeAlias',
|
|
73
|
+
'getPeerAlias',
|
|
74
|
+
({getNodeAlias, getPeerAlias}, cbk) =>
|
|
75
|
+
{
|
|
76
|
+
const message = describeCapacityChange({
|
|
77
|
+
capacity: args.capacity,
|
|
78
|
+
channel: args.channel,
|
|
79
|
+
decrease: args.decrease,
|
|
80
|
+
from_alias: getPeerAlias.alias,
|
|
81
|
+
from_id: args.from_id,
|
|
82
|
+
increase: args.increase,
|
|
83
|
+
to_alias: getNodeAlias.alias,
|
|
84
|
+
to_id: args.to_id,
|
|
85
|
+
type: args.type,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
return args.ask({
|
|
89
|
+
message,
|
|
90
|
+
name: 'accept',
|
|
91
|
+
type: 'confirm',
|
|
92
|
+
},
|
|
93
|
+
({accept}) => {
|
|
94
|
+
if (!accept) {
|
|
95
|
+
return cbk(null, {is_selected: false});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Fail changing when cooperative_close_address is set
|
|
99
|
+
if (!!args.address && !args.increase) {
|
|
100
|
+
return cbk([400, 'ChannelHasLockedCoopCloseAddressSet']);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return cbk(null, {is_selected: true});
|
|
104
|
+
});
|
|
105
|
+
}],
|
|
106
|
+
},
|
|
107
|
+
returnResult({reject, resolve, of: 'confirm'}, cbk));
|
|
108
|
+
});
|
|
109
|
+
};
|
|
@@ -29,6 +29,7 @@ const privateAsType = isPrivate => isPrivate ? 1 : 0;
|
|
|
29
29
|
from: <From Node Public Key Id Hex String>
|
|
30
30
|
id: <Change Request Id Hex String>
|
|
31
31
|
[increase]: <Add Capacity Tokens Number>
|
|
32
|
+
[to]: <Switch Channel to Node with Identity Public Key Hex String>
|
|
32
33
|
[type]: <Change Channel Channel Type Flags Number>
|
|
33
34
|
}]
|
|
34
35
|
}
|
|
@@ -77,6 +78,7 @@ module.exports = ({channels, requests}) => {
|
|
|
77
78
|
from: channel.partner_public_key,
|
|
78
79
|
id: request.id,
|
|
79
80
|
increase: request.increase,
|
|
81
|
+
to: request.to,
|
|
80
82
|
type: type ? request.type : undefined,
|
|
81
83
|
};
|
|
82
84
|
});
|
|
@@ -2,20 +2,17 @@ const asyncAuto = require('async/auto');
|
|
|
2
2
|
const asyncDetectSeries = require('async/detectSeries');
|
|
3
3
|
const asyncRetry = require('async/retry');
|
|
4
4
|
const {getIdentity} = require('ln-service');
|
|
5
|
-
const {getNodeAlias} = require('ln-sync');
|
|
6
5
|
const {returnResult} = require('asyncjs-util');
|
|
7
6
|
const {updateChannelFee} = require('ln-sync');
|
|
8
7
|
|
|
9
8
|
const acceptCapacityChange = require('./accept_capacity_change');
|
|
9
|
+
const askToSelectChange = require('./ask_to_select_change');
|
|
10
10
|
const getCapacityChangeRequests = require('./get_capacity_change_requests');
|
|
11
11
|
const initiateCapacityChange = require('./initiate_capacity_change');
|
|
12
12
|
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const peerName = ({alias, id}) => `${alias} ${id.substring(0, 8)}`.trim();
|
|
13
|
+
const interval = 1000 * 10;
|
|
14
|
+
const {isArray} = Array;
|
|
16
15
|
const times = 6 * 60 * 6;
|
|
17
|
-
const tokensAsBigUnit = tokens => (tokens / 1e8).toFixed(8);
|
|
18
|
-
const waitForCloseInterval = 1000 * 3;
|
|
19
16
|
|
|
20
17
|
/** Change a channel's capacity
|
|
21
18
|
|
|
@@ -24,9 +21,14 @@ const waitForCloseInterval = 1000 * 3;
|
|
|
24
21
|
[delay]: <Wait Time For Incoming Capacity Requests Milliseconds Number>
|
|
25
22
|
lnd: <Authenticated LND API Object>
|
|
26
23
|
logger: <Winston Logger Object>
|
|
24
|
+
[nodes]: [{
|
|
25
|
+
lnd: <Authenticated LND API Object>
|
|
26
|
+
named: <Node Named String.
|
|
27
|
+
public_key: <Node Identity Public Key Hex String>
|
|
28
|
+
}]
|
|
27
29
|
}
|
|
28
30
|
*/
|
|
29
|
-
module.exports = ({ask, delay, lnd, logger}, cbk) => {
|
|
31
|
+
module.exports = ({ask, delay, lnd, logger, nodes}, cbk) => {
|
|
30
32
|
return new Promise((resolve, reject) => {
|
|
31
33
|
return asyncAuto({
|
|
32
34
|
// Check arguments
|
|
@@ -43,6 +45,10 @@ module.exports = ({ask, delay, lnd, logger}, cbk) => {
|
|
|
43
45
|
return cbk([400, 'ExpectedLoggerObjectToChangeCapacity']);
|
|
44
46
|
}
|
|
45
47
|
|
|
48
|
+
if (!!nodes && !isArray(nodes)) {
|
|
49
|
+
return cbk([400, 'ExpectedArrayOfControlledNodesToChangeCapacity']);
|
|
50
|
+
}
|
|
51
|
+
|
|
46
52
|
return cbk();
|
|
47
53
|
},
|
|
48
54
|
|
|
@@ -83,42 +89,24 @@ module.exports = ({ask, delay, lnd, logger}, cbk) => {
|
|
|
83
89
|
({waitForProposal}, cbk) =>
|
|
84
90
|
{
|
|
85
91
|
return asyncDetectSeries(waitForProposal.requests, (request, cbk) => {
|
|
86
|
-
return
|
|
92
|
+
return askToSelectChange({
|
|
93
|
+
ask,
|
|
94
|
+
lnd,
|
|
95
|
+
address: request.address,
|
|
96
|
+
capacity: request.capacity,
|
|
97
|
+
channel: request.channel,
|
|
98
|
+
decrease: request.decrease,
|
|
99
|
+
from_id: request.from,
|
|
100
|
+
increase: request.increase,
|
|
101
|
+
to_id: request.to,
|
|
102
|
+
type: request.type,
|
|
103
|
+
},
|
|
104
|
+
(err, res) => {
|
|
87
105
|
if (!!err) {
|
|
88
106
|
return cbk(err);
|
|
89
107
|
}
|
|
90
108
|
|
|
91
|
-
|
|
92
|
-
const delta = request.decrease || request.increase;
|
|
93
|
-
const hasType = request.type !== undefined;
|
|
94
|
-
const id = request.channel;
|
|
95
|
-
const peer = peerName(res);
|
|
96
|
-
const size = tokensAsBigUnit(request.capacity);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const action = `${change} capacity ${size} channel ${id}`;
|
|
100
|
-
const by = !!delta ? ` by ${tokensAsBigUnit(delta)}` : '';
|
|
101
|
-
const type = hasType ? describeType(request.type) : '';
|
|
102
|
-
|
|
103
|
-
const changeType = hasType ? ` and make channel ${type}` : '';
|
|
104
|
-
|
|
105
|
-
return ask({
|
|
106
|
-
type: 'confirm',
|
|
107
|
-
name: 'accept',
|
|
108
|
-
message: `${action} with ${peer}${by}${changeType}?`,
|
|
109
|
-
},
|
|
110
|
-
({accept}) => {
|
|
111
|
-
if (!accept) {
|
|
112
|
-
return cbk(null, false);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Fail changing when cooperative_close_address is set
|
|
116
|
-
if (!!request.address && !!request.increase) {
|
|
117
|
-
return cbk([400, 'ChannelHasLockedCoopCloseAddressSet']);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return cbk(null, true);
|
|
121
|
-
});
|
|
109
|
+
return cbk(null, res.is_selected);
|
|
122
110
|
});
|
|
123
111
|
},
|
|
124
112
|
cbk);
|
|
@@ -138,17 +126,30 @@ module.exports = ({ask, delay, lnd, logger}, cbk) => {
|
|
|
138
126
|
from: askToSelectChange.from,
|
|
139
127
|
id: askToSelectChange.id,
|
|
140
128
|
increase: askToSelectChange.increase,
|
|
129
|
+
to: askToSelectChange.to || askToSelectChange.from,
|
|
141
130
|
},
|
|
142
131
|
cbk);
|
|
143
132
|
}],
|
|
144
133
|
|
|
145
134
|
// Initiate a capacity change
|
|
146
|
-
initiateChange: [
|
|
135
|
+
initiateChange: [
|
|
136
|
+
'askToSelectChange',
|
|
137
|
+
'getIdentity',
|
|
138
|
+
({askToSelectChange, getIdentity}, cbk) =>
|
|
139
|
+
{
|
|
147
140
|
if (!!askToSelectChange) {
|
|
148
141
|
return cbk();
|
|
149
142
|
}
|
|
150
143
|
|
|
151
|
-
return initiateCapacityChange({
|
|
144
|
+
return initiateCapacityChange({
|
|
145
|
+
ask,
|
|
146
|
+
lnd,
|
|
147
|
+
logger,
|
|
148
|
+
nodes: (nodes || []).filter(node => {
|
|
149
|
+
return node.public_key !== getIdentity.public_key;
|
|
150
|
+
}),
|
|
151
|
+
},
|
|
152
|
+
cbk);
|
|
152
153
|
}],
|
|
153
154
|
|
|
154
155
|
// Reset the channel routing policies
|
|
@@ -164,11 +165,11 @@ module.exports = ({ask, delay, lnd, logger}, cbk) => {
|
|
|
164
165
|
|
|
165
166
|
return asyncRetry({interval, times}, cbk => {
|
|
166
167
|
return updateChannelFee({
|
|
167
|
-
lnd,
|
|
168
168
|
base_fee_mtokens: policy.base_fee_mtokens,
|
|
169
169
|
cltv_delta: policy.cltv_delta,
|
|
170
170
|
fee_rate: policy.fee_rate,
|
|
171
|
-
from: getIdentity.public_key,
|
|
171
|
+
from: policy.open_from || getIdentity.public_key,
|
|
172
|
+
lnd: policy.open_lnd || lnd,
|
|
172
173
|
transaction_id: policy.transaction_id,
|
|
173
174
|
transaction_vout: policy.transaction_vout,
|
|
174
175
|
},
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const describeType = type => !(type & 1) ? 'private' : 'public';
|
|
2
|
+
const peerName = ({alias, id}) => `${alias} ${id.substring(0, 8)}`.trim();
|
|
3
|
+
const tokensAsBigUnit = tokens => (tokens / 1e8).toFixed(8);
|
|
4
|
+
|
|
5
|
+
/** Describe a capacity change
|
|
6
|
+
|
|
7
|
+
{
|
|
8
|
+
capacity: <Channel Capacity Tokens Number>
|
|
9
|
+
channel: <Change Channel Id String>
|
|
10
|
+
[decrease]: <Capacity Change Decrease Tokens Number>
|
|
11
|
+
from_alias: <Peer Alias String>
|
|
12
|
+
from_id: <Peer Public Key Hex String>
|
|
13
|
+
[increase]: <Capacity Change Increase Tokens Number>
|
|
14
|
+
[to_alias]: <Node Alias String>
|
|
15
|
+
[to_id]: <Node Public Key Hex String>
|
|
16
|
+
[type]: <Channel Type String>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@returns
|
|
20
|
+
<Capacity Change Description String>
|
|
21
|
+
*/
|
|
22
|
+
module.exports = args => {
|
|
23
|
+
const change = !!args.increase ? 'Increase' : 'Decrease';
|
|
24
|
+
const delta = args.decrease || args.increase;
|
|
25
|
+
const hasType = args.type !== undefined;
|
|
26
|
+
const newPeer = peerName({alias: args.to_alias, id: args.to_id || ''});
|
|
27
|
+
const peer = peerName({alias: args.from_alias, id: args.from_id});
|
|
28
|
+
const size = tokensAsBigUnit(args.capacity);
|
|
29
|
+
|
|
30
|
+
const action = `${change} capacity ${size} channel ${args.channel}`;
|
|
31
|
+
const by = !!delta ? ` by ${tokensAsBigUnit(delta)}` : '';
|
|
32
|
+
const move = !!args.to_id ? ` and move channel to ${newPeer}` : '';
|
|
33
|
+
const type = hasType ? describeType(args.type) : '';
|
|
34
|
+
|
|
35
|
+
const changeType = hasType ? ` and make channel ${type}` : '';
|
|
36
|
+
|
|
37
|
+
return `${action} with ${peer}${by}${move}${changeType}?`;
|
|
38
|
+
};
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
const {encodeBigSize} = require('bolt01');
|
|
2
|
+
const {encodeTlvRecord} = require('bolt01');
|
|
2
3
|
const {rawChanId} = require('bolt07');
|
|
3
4
|
|
|
4
5
|
const channelFlagsType = '5';
|
|
5
6
|
const channelIdRecordType = '2';
|
|
7
|
+
const currentVersion = '1';
|
|
6
8
|
const decreaseRecordType = '3';
|
|
7
9
|
const increaseRecordType = '4';
|
|
10
|
+
const migrateRecordType = '6';
|
|
8
11
|
const requestIdRecordType = '1';
|
|
9
12
|
const typeAsHex = type => Buffer.from([type]).toString('hex');
|
|
13
|
+
const versionRecordType = '0';
|
|
10
14
|
|
|
11
15
|
/** Encode a request to change a channel capacity
|
|
12
16
|
|
|
@@ -15,6 +19,7 @@ const typeAsHex = type => Buffer.from([type]).toString('hex');
|
|
|
15
19
|
[decrease]: <Remove Channel Funds By Tokens Number>
|
|
16
20
|
id: <Request Id Hex String>
|
|
17
21
|
increase: <Add Channel Funds By Tokens Number>
|
|
22
|
+
[to]: <Move Channel to Different Node with Public Key Hex String>
|
|
18
23
|
type: <New Channel Type Number>
|
|
19
24
|
}
|
|
20
25
|
|
|
@@ -26,8 +31,12 @@ const typeAsHex = type => Buffer.from([type]).toString('hex');
|
|
|
26
31
|
}]
|
|
27
32
|
}
|
|
28
33
|
*/
|
|
29
|
-
module.exports = ({channel, decrease, id, increase, type}) => {
|
|
34
|
+
module.exports = ({channel, decrease, id, increase, to, type}) => {
|
|
30
35
|
const records = [
|
|
36
|
+
{
|
|
37
|
+
type: versionRecordType,
|
|
38
|
+
value: encodeBigSize({number: currentVersion}).encoded,
|
|
39
|
+
},
|
|
31
40
|
{
|
|
32
41
|
type: requestIdRecordType,
|
|
33
42
|
value: id,
|
|
@@ -42,21 +51,26 @@ module.exports = ({channel, decrease, id, increase, type}) => {
|
|
|
42
51
|
},
|
|
43
52
|
];
|
|
44
53
|
|
|
54
|
+
// Add a record reflecting the decrease in the capacity
|
|
45
55
|
if (!!decrease) {
|
|
46
|
-
// Add a record reflecting the decrease in the capacity
|
|
47
56
|
records.push({
|
|
48
57
|
type: decreaseRecordType,
|
|
49
58
|
value: encodeBigSize({number: decrease.toString()}).encoded,
|
|
50
59
|
});
|
|
51
60
|
}
|
|
52
61
|
|
|
62
|
+
// Add a record reflecting the increase in the capacity
|
|
53
63
|
if (!!increase) {
|
|
54
|
-
// Add a record reflecting the increase in the capacity
|
|
55
64
|
records.push({
|
|
56
65
|
type: increaseRecordType,
|
|
57
66
|
value: encodeBigSize({number: increase.toString()}).encoded,
|
|
58
67
|
});
|
|
59
68
|
}
|
|
60
69
|
|
|
70
|
+
// Add a record reflecting the migration of channel to a different peer
|
|
71
|
+
if (!!to) {
|
|
72
|
+
records.push({type: migrateRecordType, value: to});
|
|
73
|
+
}
|
|
74
|
+
|
|
61
75
|
return {records};
|
|
62
76
|
};
|
|
@@ -13,7 +13,7 @@ const dummySignature = Buffer.alloc(74);
|
|
|
13
13
|
const dummyTokens = 0;
|
|
14
14
|
const dummyVout = 0;
|
|
15
15
|
const hexAsBuffer = hex => Buffer.from(hex, 'hex');
|
|
16
|
-
const increaseBuffer =
|
|
16
|
+
const increaseBuffer = 500;
|
|
17
17
|
const {max} = Math;
|
|
18
18
|
const weightAsVBytes = weight => weight / 4;
|
|
19
19
|
|
|
@@ -28,6 +28,7 @@ const waitForRequestsTimeoutMs = 5000;
|
|
|
28
28
|
from: <From Node Public Key Id Hex String>
|
|
29
29
|
id: <Change Request Id Hex String>
|
|
30
30
|
[increase]: <Add Capacity Tokens Number>
|
|
31
|
+
[to]: <Switch Channel to Node with Identity Public Key Hex String>
|
|
31
32
|
[type]: <Intended Replacement Channel Channel Type Flags Number>
|
|
32
33
|
}]
|
|
33
34
|
}
|