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
package/.prettierignore
ADDED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Versions
|
|
2
2
|
|
|
3
|
+
## Version 3.7.0
|
|
4
|
+
|
|
5
|
+
- `changeChannelCapacity`: Add support for decreasing funds into a new channel
|
|
6
|
+
|
|
7
|
+
## Version 3.6.0
|
|
8
|
+
|
|
9
|
+
- `manageTrades`: Add support for persistent open trades
|
|
10
|
+
- `manageTrades`: Add expiration dates to open trades
|
|
11
|
+
- `manageTrades`: Support longer-lived open trade scenarios
|
|
12
|
+
- `manageTrades`: Show final encoded trade when requesting open trade
|
|
13
|
+
- `manageTrades`: Check for RPC signer support before trading
|
|
14
|
+
|
|
15
|
+
## Version 3.5.1
|
|
16
|
+
|
|
17
|
+
- `changeChannelCapacity`: Allow changing private/public status of channel
|
|
18
|
+
|
|
3
19
|
## Version 3.4.0
|
|
4
20
|
|
|
5
21
|
- `changeChannelCapacity`: Fix broken preservation of channel announce status
|
|
@@ -212,6 +212,8 @@ module.exports = ({channel, from, id, increase, lnd, logger}, cbk) => {
|
|
|
212
212
|
return failure([503, 'FailedToParseSignChangeRequest']);
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
+
logger.info({closing_and_reopening_channel: true});
|
|
216
|
+
|
|
215
217
|
// Trigger the replacement flow and sign the unsigned tx
|
|
216
218
|
return getReplacementSignature({
|
|
217
219
|
channel,
|
|
@@ -24,6 +24,8 @@ const minNewLocalBalance = 0;
|
|
|
24
24
|
const nonNegative = n => Math.max(0, n);
|
|
25
25
|
const outputSize = 44;
|
|
26
26
|
const positive = n => Math.max(1, n);
|
|
27
|
+
const privateType = 1;
|
|
28
|
+
const publicType = 0;
|
|
27
29
|
const slowTarget = 1000;
|
|
28
30
|
const sumOf = arr => arr.reduce((sum, n) => sum + n, 0);
|
|
29
31
|
const sumOfTokens = arr => arr.reduce((sum, n) => sum + n.tokens, 0);
|
|
@@ -46,8 +48,9 @@ const weightBuffer = 150;
|
|
|
46
48
|
cltv_delta: <Locktime Delta Number>
|
|
47
49
|
coop_close_address: <Cooperative Close Address String>
|
|
48
50
|
decrease: [{
|
|
49
|
-
address: <Decrease Address String>
|
|
50
|
-
|
|
51
|
+
[address]: <Decrease Address String>
|
|
52
|
+
[node]: <Create Channel with Node With Public Key Hex String>
|
|
53
|
+
[output]: <Output Script Hex String>
|
|
51
54
|
tokens: <Decrease Tokens Number>
|
|
52
55
|
}]
|
|
53
56
|
estimated_capacity: <Estimated Tokens For New Channel Capacity Number>
|
|
@@ -170,6 +173,7 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
170
173
|
const disabled = [
|
|
171
174
|
!!channel.cooperative_close_address,
|
|
172
175
|
!channel.is_active,
|
|
176
|
+
!!channel.pending_payments.length,
|
|
173
177
|
];
|
|
174
178
|
|
|
175
179
|
return {
|
|
@@ -342,7 +346,7 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
342
346
|
return cbk(err);
|
|
343
347
|
}
|
|
344
348
|
|
|
345
|
-
if (decreases.find(n => n.address === res.address)) {
|
|
349
|
+
if (!!res.address && decreases.find(n => n.address === res.address)) {
|
|
346
350
|
return cbk([400, 'ExpectedUniqueAddressForSpend']);
|
|
347
351
|
}
|
|
348
352
|
|
|
@@ -354,11 +358,8 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
354
358
|
return cbk(err);
|
|
355
359
|
}
|
|
356
360
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
.map(({address, output, tokens}) => ({address, output, tokens}));
|
|
360
|
-
|
|
361
|
-
return cbk(null, final);
|
|
361
|
+
// Only include decreases that spend funds
|
|
362
|
+
return cbk(null, decreases.filter(n => !!n.tokens));
|
|
362
363
|
}
|
|
363
364
|
);
|
|
364
365
|
}],
|
|
@@ -395,10 +396,37 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
395
396
|
({amount}) => cbk(null, Number(amount)));
|
|
396
397
|
}],
|
|
397
398
|
|
|
399
|
+
// Confirm or change the announce status of the replacement channel
|
|
400
|
+
askForPublicPrivate: [
|
|
401
|
+
'askForDecrease',
|
|
402
|
+
'askForIncrease',
|
|
403
|
+
'channel',
|
|
404
|
+
({channel}, cbk) =>
|
|
405
|
+
{
|
|
406
|
+
return ask({
|
|
407
|
+
choices: ['Public', 'Private'].map(type => {
|
|
408
|
+
const isPrivate = type === 'Private';
|
|
409
|
+
|
|
410
|
+
// Exit early when the type would be different
|
|
411
|
+
if (isPrivate !== channel.is_private) {
|
|
412
|
+
return type;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return `${type} (keep current status)`;
|
|
416
|
+
}),
|
|
417
|
+
default: channel.is_private ? 'Private' : 'Public',
|
|
418
|
+
message: 'Replacement channel type?',
|
|
419
|
+
name: 'type',
|
|
420
|
+
type: 'list',
|
|
421
|
+
},
|
|
422
|
+
({type}) => cbk(null, {is_private: type === 'Private'}));
|
|
423
|
+
}],
|
|
424
|
+
|
|
398
425
|
// Estimate the chain fee
|
|
399
426
|
estimateChainFee: [
|
|
400
427
|
'askForDecrease',
|
|
401
428
|
'askForIncrease',
|
|
429
|
+
'askForPublicPrivate',
|
|
402
430
|
'channel',
|
|
403
431
|
'getFeeRate',
|
|
404
432
|
({askForDecrease, askForIncrease, channel, getFeeRate}, cbk) =>
|
|
@@ -417,6 +445,7 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
417
445
|
|
|
418
446
|
// Confirm chain fee payment estimate
|
|
419
447
|
confirmFeeEstimate: [
|
|
448
|
+
'askForPublicPrivate',
|
|
420
449
|
'channel',
|
|
421
450
|
'estimateChainFee',
|
|
422
451
|
({channel, estimateChainFee}, cbk) =>
|
|
@@ -437,6 +466,7 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
437
466
|
details: [
|
|
438
467
|
'askForDecrease',
|
|
439
468
|
'askForIncrease',
|
|
469
|
+
'askForPublicPrivate',
|
|
440
470
|
'channel',
|
|
441
471
|
'confirmFeeEstimate',
|
|
442
472
|
'estimateChainFee',
|
|
@@ -444,6 +474,7 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
444
474
|
({
|
|
445
475
|
askForDecrease,
|
|
446
476
|
askForIncrease,
|
|
477
|
+
askForPublicPrivate,
|
|
447
478
|
channel,
|
|
448
479
|
confirmFeeEstimate,
|
|
449
480
|
estimateChainFee,
|
|
@@ -478,6 +509,7 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
478
509
|
channel: channel.id,
|
|
479
510
|
decrease: !!askForDecrease ? sumOfTokens(askForDecrease) : undefined,
|
|
480
511
|
increase: askForIncrease,
|
|
512
|
+
type: askForPublicPrivate.is_private ? privateType : publicType,
|
|
481
513
|
});
|
|
482
514
|
|
|
483
515
|
return cbk(null, {
|
|
@@ -491,7 +523,7 @@ module.exports = ({ask, id, lnd}, cbk) => {
|
|
|
491
523
|
fee_rate: channel.fee_rate,
|
|
492
524
|
id: channel.id,
|
|
493
525
|
increase: askForIncrease,
|
|
494
|
-
is_private:
|
|
526
|
+
is_private: askForPublicPrivate.is_private,
|
|
495
527
|
open_transaction: channel.open_transaction,
|
|
496
528
|
partner_csv_delay: channel.partner_csv_delay,
|
|
497
529
|
partner_public_key: channel.partner_public_key,
|
|
@@ -1,14 +1,28 @@
|
|
|
1
1
|
const {address} = require('bitcoinjs-lib');
|
|
2
2
|
const asyncAuto = require('async/auto');
|
|
3
3
|
const {createChainAddress} = require('ln-service');
|
|
4
|
+
const {getIdentity} = require('ln-service');
|
|
5
|
+
const {acceptsChannelOpen} = require('ln-sync');
|
|
4
6
|
const {getNetwork} = require('ln-sync');
|
|
5
7
|
const {networks} = require('bitcoinjs-lib');
|
|
6
8
|
const {returnResult} = require('asyncjs-util');
|
|
7
9
|
|
|
10
|
+
const proposeChannelOpen = require('./propose_channel_open');
|
|
11
|
+
|
|
12
|
+
const askForChanSize = max => `Capacity of the new channel? (max: ${max})`;
|
|
13
|
+
const askForSendSize = max => `Amount you want to send out? (max: ${max})`;
|
|
8
14
|
const bufferAsHex = buffer => buffer.toString('hex');
|
|
9
15
|
const dust = 550;
|
|
16
|
+
const {isInteger} = Number;
|
|
10
17
|
const isNumber = n => !isNaN(n);
|
|
18
|
+
const isPublicKey = n => !!n && /^0[2-3][0-9A-F]{64}$/i.test(n);
|
|
19
|
+
const minChannelCapacity = 20000;
|
|
20
|
+
const minSpendTokens = 0;
|
|
21
|
+
const openChannelAction = 'open_channel';
|
|
22
|
+
const spendToExternalAddressAction = 'external_spend_funds';
|
|
23
|
+
const spendToInternalAddressAction = 'internal_spend_funds';
|
|
11
24
|
const {toOutputScript} = address;
|
|
25
|
+
const tokensAsBigUnit = tokens => (tokens / 1e8).toFixed(8);
|
|
12
26
|
|
|
13
27
|
/** Ask for details about a decrease
|
|
14
28
|
|
|
@@ -22,6 +36,7 @@ const {toOutputScript} = address;
|
|
|
22
36
|
{
|
|
23
37
|
[address]: <Send Funds to Address String>
|
|
24
38
|
is_final: <Decrease is Final Decrease Bool>
|
|
39
|
+
[node]: <Create Channel with Node With Public Key Hex String>
|
|
25
40
|
[output]: <Output Script Hex String>
|
|
26
41
|
tokens: <Withdraw Tokens Number>
|
|
27
42
|
}
|
|
@@ -46,66 +61,149 @@ module.exports = ({ask, lnd, max}, cbk) => {
|
|
|
46
61
|
return cbk();
|
|
47
62
|
},
|
|
48
63
|
|
|
49
|
-
//
|
|
50
|
-
|
|
64
|
+
// Select the type of decrease
|
|
65
|
+
askForDecreaseType: ['validate', ({}, cbk) => {
|
|
51
66
|
return ask({
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
67
|
+
choices: [
|
|
68
|
+
{
|
|
69
|
+
name: `Send decreased funds to the internal chain wallet`,
|
|
70
|
+
value: spendToInternalAddressAction,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: `Send decreased funds to an external chain address`,
|
|
74
|
+
value: spendToExternalAddressAction,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
disabled: max < minChannelCapacity,
|
|
78
|
+
name: `Spend decreased funds into new channel with another peer`,
|
|
79
|
+
value: openChannelAction,
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
message: 'How do you want to change the channel capacity?',
|
|
83
|
+
name: 'decrease',
|
|
84
|
+
type: 'list',
|
|
85
|
+
},
|
|
86
|
+
({decrease}) => cbk(null, decrease));
|
|
87
|
+
}],
|
|
88
|
+
|
|
89
|
+
// Get the node identity key to make sure a channel open isn't with self
|
|
90
|
+
getIdentity: ['validate', ({}, cbk) => getIdentity({lnd}, cbk)],
|
|
91
|
+
|
|
92
|
+
// Get network name to validate addresses against
|
|
93
|
+
getNetwork: ['validate', ({}, cbk) => getNetwork({lnd}, cbk)],
|
|
94
|
+
|
|
95
|
+
// Ask for the public key of the node to trade with
|
|
96
|
+
askForNodeId: [
|
|
97
|
+
'askForDecreaseType',
|
|
98
|
+
'getIdentity',
|
|
99
|
+
({askForDecreaseType, getIdentity}, cbk) =>
|
|
100
|
+
{
|
|
101
|
+
// Exit early when not opening a new channel
|
|
102
|
+
if (askForDecreaseType !== openChannelAction) {
|
|
103
|
+
return cbk();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return ask({
|
|
107
|
+
name: 'key',
|
|
108
|
+
message: 'Public key of node to open channel with?',
|
|
55
109
|
type: 'input',
|
|
56
110
|
validate: input => {
|
|
57
|
-
if (!
|
|
111
|
+
if (!input) {
|
|
58
112
|
return false;
|
|
59
113
|
}
|
|
60
114
|
|
|
61
|
-
if (
|
|
62
|
-
return
|
|
115
|
+
if (!isPublicKey(input)) {
|
|
116
|
+
return 'Expected public key of node to open channel with';
|
|
63
117
|
}
|
|
64
118
|
|
|
65
|
-
if (
|
|
66
|
-
return
|
|
119
|
+
if (input === getIdentity.public_key) {
|
|
120
|
+
return 'Expected public key of other node';
|
|
67
121
|
}
|
|
68
122
|
|
|
69
123
|
return true;
|
|
70
124
|
},
|
|
71
125
|
},
|
|
72
|
-
({
|
|
126
|
+
({key}) => cbk(null, key));
|
|
73
127
|
}],
|
|
74
128
|
|
|
75
|
-
//
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
askForExternal: ['askForAmount', ({askForAmount}, cbk) => {
|
|
80
|
-
if (!Number(askForAmount)) {
|
|
129
|
+
// Create a decrease address to withdraw funds out to
|
|
130
|
+
createAddress: ['askForDecreaseType', ({askForDecreaseType}, cbk) => {
|
|
131
|
+
// Exit early when there is no need to create an internal address
|
|
132
|
+
if (askForDecreaseType !== spendToInternalAddressAction) {
|
|
81
133
|
return cbk();
|
|
82
134
|
}
|
|
83
135
|
|
|
136
|
+
return createChainAddress({lnd}, cbk);
|
|
137
|
+
}],
|
|
138
|
+
|
|
139
|
+
// Ask for the amount to decrease
|
|
140
|
+
askForAmount: ['askForNodeId', ({askForNodeId}, cbk) => {
|
|
84
141
|
return ask({
|
|
85
|
-
default:
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
142
|
+
default: !askForNodeId ? minSpendTokens : minChannelCapacity,
|
|
143
|
+
message: !askForNodeId ? askForSendSize(max) : askForChanSize(max),
|
|
144
|
+
name: 'amount',
|
|
145
|
+
validate: input => {
|
|
146
|
+
// A numeric input is required
|
|
147
|
+
if (!isNumber(input) || !isInteger(Number(input))) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Zero value is acceptable for a decrease when not opening channel
|
|
152
|
+
if (!askForNodeId && !Number(input)) {
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// On-chain values must always be above dust
|
|
157
|
+
if (!!Number(input) && Number(input) < dust) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Channel opens must always be above the minimum channel size
|
|
162
|
+
if (!!askForNodeId && Number(input) < minChannelCapacity) {
|
|
163
|
+
return `The minimum channel capacity is ${minChannelCapacity}`;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// A decrease cannot spend more funds than are available
|
|
167
|
+
if (!!Number(input) && Number(input) > max) {
|
|
168
|
+
return `The maximum possible to decrease is ${max}`;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return true;
|
|
172
|
+
},
|
|
89
173
|
},
|
|
90
|
-
({
|
|
174
|
+
({amount}) => cbk(null, Number(amount)));
|
|
91
175
|
}],
|
|
92
176
|
|
|
93
177
|
// Ask for an external address
|
|
94
178
|
askForAddress: [
|
|
95
179
|
'askForAmount',
|
|
96
|
-
'
|
|
97
|
-
|
|
180
|
+
'askForDecreaseType',
|
|
181
|
+
'getNetwork',
|
|
182
|
+
({askForAmount, askForDecreaseType, getNetwork}, cbk) =>
|
|
98
183
|
{
|
|
99
|
-
// Exit early when the withdraw address is
|
|
100
|
-
if (
|
|
184
|
+
// Exit early when the withdraw address is not external
|
|
185
|
+
if (askForDecreaseType !== spendToExternalAddressAction) {
|
|
101
186
|
return cbk();
|
|
102
187
|
}
|
|
103
188
|
|
|
104
189
|
return ask({
|
|
105
190
|
name: 'address',
|
|
106
|
-
message: `Address to spend ${askForAmount} to?`,
|
|
191
|
+
message: `Address to spend ${tokensAsBigUnit(askForAmount)} to?`,
|
|
107
192
|
type: 'input',
|
|
108
|
-
validate: input =>
|
|
193
|
+
validate: input => {
|
|
194
|
+
if (!input) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Make sure that the entered address can be derived to an output
|
|
199
|
+
try {
|
|
200
|
+
toOutputScript(input, networks[getNetwork.bitcoinjs]);
|
|
201
|
+
} catch (err) {
|
|
202
|
+
return 'Failed to parse address. Try a standard one?';
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return true;
|
|
206
|
+
},
|
|
109
207
|
},
|
|
110
208
|
({address}) => cbk(null, {address}));
|
|
111
209
|
}],
|
|
@@ -113,31 +211,46 @@ module.exports = ({ask, lnd, max}, cbk) => {
|
|
|
113
211
|
// Ask if this is the last output
|
|
114
212
|
askForAddition: [
|
|
115
213
|
'askForAddress',
|
|
116
|
-
'
|
|
117
|
-
|
|
214
|
+
'askForAmount',
|
|
215
|
+
'askForDecreaseType',
|
|
216
|
+
({askForAmount, askForDecreaseType}, cbk) =>
|
|
118
217
|
{
|
|
119
|
-
// Exit early
|
|
120
|
-
if (
|
|
218
|
+
// Exit early and only ask for addition when decrease is a "spend" type
|
|
219
|
+
if (askForDecreaseType === spendToInternalAddressAction) {
|
|
220
|
+
return cbk();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Exit early when there are no more funds to spend
|
|
224
|
+
if (max - askForAmount < dust) {
|
|
121
225
|
return cbk();
|
|
122
226
|
}
|
|
123
227
|
|
|
124
228
|
return ask({
|
|
125
229
|
default: false,
|
|
126
230
|
name: 'add',
|
|
127
|
-
message: '
|
|
231
|
+
message: 'Spend additional funds from the channel capacity?',
|
|
128
232
|
type: 'confirm',
|
|
129
233
|
},
|
|
130
234
|
({add}) => cbk(null, add));
|
|
131
235
|
}],
|
|
132
236
|
|
|
133
|
-
//
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
237
|
+
// Propose a channel open to confirm the peer will accept the channel
|
|
238
|
+
checkChannelAcceptance: [
|
|
239
|
+
'askForAmount',
|
|
240
|
+
'askForNodeId',
|
|
241
|
+
({askForAmount, askForNodeId}, cbk) =>
|
|
242
|
+
{
|
|
243
|
+
// Exit early if pubkey was not entered
|
|
244
|
+
if (!askForNodeId) {
|
|
137
245
|
return cbk();
|
|
138
246
|
}
|
|
139
247
|
|
|
140
|
-
return
|
|
248
|
+
return proposeChannelOpen({
|
|
249
|
+
lnd,
|
|
250
|
+
capacity: askForAmount,
|
|
251
|
+
id: askForNodeId,
|
|
252
|
+
},
|
|
253
|
+
cbk);
|
|
141
254
|
}],
|
|
142
255
|
|
|
143
256
|
// Final decrease output details
|
|
@@ -145,38 +258,43 @@ module.exports = ({ask, lnd, max}, cbk) => {
|
|
|
145
258
|
'askForAddition',
|
|
146
259
|
'askForAddress',
|
|
147
260
|
'askForAmount',
|
|
261
|
+
'checkChannelAcceptance',
|
|
148
262
|
'createAddress',
|
|
149
263
|
'getNetwork',
|
|
150
264
|
({
|
|
151
265
|
askForAddition,
|
|
152
266
|
askForAddress,
|
|
153
267
|
askForAmount,
|
|
268
|
+
askForNodeId,
|
|
269
|
+
checkChannelAcceptance,
|
|
154
270
|
createAddress,
|
|
155
271
|
getNetwork,
|
|
156
272
|
},
|
|
157
273
|
cbk) =>
|
|
158
274
|
{
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (!address) {
|
|
163
|
-
return cbk(null, {is_final: true, tokens: Number(askForAmount)});
|
|
275
|
+
// Make sure that a channel proposal didn't fail
|
|
276
|
+
if (!!checkChannelAcceptance && !checkChannelAcceptance.is_accepted) {
|
|
277
|
+
return cbk([503, 'RemoteNodeRejectedNewChannelProposal']);
|
|
164
278
|
}
|
|
165
279
|
|
|
166
|
-
//
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
280
|
+
// Exit early when decreasing to a new channel
|
|
281
|
+
if (!!askForNodeId) {
|
|
282
|
+
return cbk(null, {
|
|
283
|
+
is_final: !askForAddition,
|
|
284
|
+
node: askForNodeId,
|
|
285
|
+
tokens: askForAmount,
|
|
286
|
+
});
|
|
171
287
|
}
|
|
172
288
|
|
|
289
|
+
const {address} = (createAddress || askForAddress);
|
|
290
|
+
|
|
173
291
|
const output = toOutputScript(address, networks[getNetwork.bitcoinjs]);
|
|
174
292
|
|
|
175
293
|
return cbk(null, {
|
|
176
294
|
address,
|
|
177
295
|
is_final: !askForAddition,
|
|
178
296
|
output: bufferAsHex(output),
|
|
179
|
-
tokens:
|
|
297
|
+
tokens: askForAmount,
|
|
180
298
|
});
|
|
181
299
|
}],
|
|
182
300
|
},
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const privateAsType = isPrivate => isPrivate ? 1 : 0;
|
|
2
|
+
|
|
1
3
|
/** Map change requests to requests considering local channels
|
|
2
4
|
|
|
3
5
|
{
|
|
@@ -13,6 +15,7 @@
|
|
|
13
15
|
from: <From Node Public Key Id Hex String>
|
|
14
16
|
id: <Change Request Id Hex String>
|
|
15
17
|
[increase]: <Add Capacity Tokens Number>
|
|
18
|
+
[type]: <Intended Replacement Channel Channel Type Flags Number>
|
|
16
19
|
}]
|
|
17
20
|
}
|
|
18
21
|
|
|
@@ -26,6 +29,7 @@
|
|
|
26
29
|
from: <From Node Public Key Id Hex String>
|
|
27
30
|
id: <Change Request Id Hex String>
|
|
28
31
|
[increase]: <Add Capacity Tokens Number>
|
|
32
|
+
[type]: <Change Channel Channel Type Flags Number>
|
|
29
33
|
}]
|
|
30
34
|
}
|
|
31
35
|
*/
|
|
@@ -61,6 +65,10 @@ module.exports = ({channels, requests}) => {
|
|
|
61
65
|
.map(request => {
|
|
62
66
|
const channel = channels.find(chan => chan.id === request.channel);
|
|
63
67
|
|
|
68
|
+
const currentType = privateAsType(channel.is_private);
|
|
69
|
+
|
|
70
|
+
const type = request.type !== undefined && request.type !== currentType;
|
|
71
|
+
|
|
64
72
|
return {
|
|
65
73
|
address: channel.cooperative_close_address,
|
|
66
74
|
capacity: channel.capacity,
|
|
@@ -69,6 +77,7 @@ module.exports = ({channels, requests}) => {
|
|
|
69
77
|
from: channel.partner_public_key,
|
|
70
78
|
id: request.id,
|
|
71
79
|
increase: request.increase,
|
|
80
|
+
type: type ? request.type : undefined,
|
|
72
81
|
};
|
|
73
82
|
});
|
|
74
83
|
|
|
@@ -10,6 +10,7 @@ const acceptCapacityChange = require('./accept_capacity_change');
|
|
|
10
10
|
const getCapacityChangeRequests = require('./get_capacity_change_requests');
|
|
11
11
|
const initiateCapacityChange = require('./initiate_capacity_change');
|
|
12
12
|
|
|
13
|
+
const describeType = type => !(type & 0) ? 'private' : 'public';
|
|
13
14
|
const interval = 10 * 1000;
|
|
14
15
|
const peerName = ({alias, id}) => `${alias} ${id.substring(0, 8)}`.trim();
|
|
15
16
|
const times = 6 * 60 * 6;
|
|
@@ -89,17 +90,22 @@ module.exports = ({ask, delay, lnd, logger}, cbk) => {
|
|
|
89
90
|
|
|
90
91
|
const change = !!request.increase ? 'Increase' : 'Decrease';
|
|
91
92
|
const delta = request.decrease || request.increase;
|
|
93
|
+
const hasType = request.type !== undefined;
|
|
92
94
|
const id = request.channel;
|
|
93
95
|
const peer = peerName(res);
|
|
94
96
|
const size = tokensAsBigUnit(request.capacity);
|
|
95
97
|
|
|
98
|
+
|
|
96
99
|
const action = `${change} capacity ${size} channel ${id}`;
|
|
97
100
|
const by = !!delta ? ` by ${tokensAsBigUnit(delta)}` : '';
|
|
101
|
+
const type = hasType ? describeType(request.type) : '';
|
|
102
|
+
|
|
103
|
+
const changeType = hasType ? ` and make channel ${type}` : '';
|
|
98
104
|
|
|
99
105
|
return ask({
|
|
100
106
|
type: 'confirm',
|
|
101
107
|
name: 'accept',
|
|
102
|
-
message: `${action} with ${peer}${by}?`,
|
|
108
|
+
message: `${action} with ${peer}${by}${changeType}?`,
|
|
103
109
|
},
|
|
104
110
|
({accept}) => {
|
|
105
111
|
if (!accept) {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
const {encodeBigSize} = require('bolt01');
|
|
2
2
|
const {rawChanId} = require('bolt07');
|
|
3
3
|
|
|
4
|
+
const channelFlagsType = '5';
|
|
4
5
|
const channelIdRecordType = '2';
|
|
5
6
|
const decreaseRecordType = '3';
|
|
6
7
|
const increaseRecordType = '4';
|
|
7
8
|
const requestIdRecordType = '1';
|
|
9
|
+
const typeAsHex = type => Buffer.from([type]).toString('hex');
|
|
8
10
|
|
|
9
11
|
/** Encode a request to change a channel capacity
|
|
10
12
|
|
|
@@ -13,6 +15,7 @@ const requestIdRecordType = '1';
|
|
|
13
15
|
[decrease]: <Remove Channel Funds By Tokens Number>
|
|
14
16
|
id: <Request Id Hex String>
|
|
15
17
|
increase: <Add Channel Funds By Tokens Number>
|
|
18
|
+
type: <New Channel Type Number>
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
@returns
|
|
@@ -23,7 +26,7 @@ const requestIdRecordType = '1';
|
|
|
23
26
|
}]
|
|
24
27
|
}
|
|
25
28
|
*/
|
|
26
|
-
module.exports = ({channel, decrease, id, increase}) => {
|
|
29
|
+
module.exports = ({channel, decrease, id, increase, type}) => {
|
|
27
30
|
const records = [
|
|
28
31
|
{
|
|
29
32
|
type: requestIdRecordType,
|
|
@@ -33,6 +36,10 @@ module.exports = ({channel, decrease, id, increase}) => {
|
|
|
33
36
|
type: channelIdRecordType,
|
|
34
37
|
value: rawChanId({channel}).id,
|
|
35
38
|
},
|
|
39
|
+
{
|
|
40
|
+
type: channelFlagsType,
|
|
41
|
+
value: typeAsHex(type),
|
|
42
|
+
},
|
|
36
43
|
];
|
|
37
44
|
|
|
38
45
|
if (!!decrease) {
|
|
@@ -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 = 250;
|
|
17
17
|
const {max} = Math;
|
|
18
18
|
const weightAsVBytes = weight => weight / 4;
|
|
19
19
|
|
|
@@ -24,7 +24,7 @@ const weightAsVBytes = weight => weight / 4;
|
|
|
24
24
|
commit_transaction_fee: <Commit Transaction Fee Tokens Number>
|
|
25
25
|
commit_transaction_weight: <Commit Transaction Weight Units Number>
|
|
26
26
|
decrease: [{
|
|
27
|
-
output: <Output Script Hex String>
|
|
27
|
+
[output]: <Output Script Hex String>
|
|
28
28
|
tokens: <Spend Value to Chain Address Tokens Number>
|
|
29
29
|
}]
|
|
30
30
|
[increase]: <Add Funds Tokens Number>
|
|
@@ -51,16 +51,12 @@ module.exports = args => {
|
|
|
51
51
|
|
|
52
52
|
// Add the decreases as outputs
|
|
53
53
|
args.decrease.forEach(({output, tokens}) => {
|
|
54
|
-
return tx.addOutput(hexAsBuffer(output), tokens);
|
|
54
|
+
return tx.addOutput(hexAsBuffer(output || dummyP2wsh), tokens);
|
|
55
55
|
});
|
|
56
56
|
|
|
57
57
|
// Add an output to represent the new channel output
|
|
58
58
|
tx.addOutput(dummyP2wsh, args.capacity);
|
|
59
59
|
|
|
60
|
-
args.decrease.forEach(({output}) => {
|
|
61
|
-
return tx.addOutput(hexAsBuffer(output), dummyTokens);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
60
|
// Add an input to represent the old channel input
|
|
65
61
|
tx.addInput(dummyHash, dummyVout);
|
|
66
62
|
|