paid-services 3.13.2 → 3.14.2
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 +8 -0
- package/p2p/encode_peer_response.js +1 -2
- package/package.json +2 -1
- package/test/trades/test_encode_open_trade.js +48 -0
- package/test/trades/test_encode_trade.js +24 -1
- package/trades/accept_trade.js +83 -33
- package/trades/buy_channel.js +251 -0
- package/trades/buy_preimage.js +3 -2
- package/trades/connect_to_seller.js +183 -0
- package/trades/convert_fiat.js +112 -0
- package/trades/create_anchored_trade.js +22 -13
- package/trades/create_channel_sale.js +181 -77
- package/trades/create_trade.js +115 -20
- package/trades/decode_anchored_trade.js +39 -11
- package/trades/decode_open_trade.js +6 -0
- package/trades/decode_trade.js +16 -4
- package/trades/decode_trade_payment.js +45 -0
- package/trades/encode_anchored_trade.js +25 -5
- package/trades/encode_trade.js +1 -1
- package/trades/encode_trade_payment.js +38 -0
- package/trades/encode_trade_secret.js +1 -1
- package/trades/finalize_trade.js +244 -0
- package/trades/find_trade.js +14 -175
- package/trades/get_anchored_trade.js +10 -6
- package/trades/manage_trade.js +2 -8
- package/trades/manage_trades.js +44 -37
- package/trades/request_trade_by_id.js +3 -18
- package/trades/service_anchored_trades.js +5 -1
- package/trades/service_open_trade.js +24 -17
- package/trades/service_trade_requests.js +51 -31
- package/trades/trade_from_invoice.js +11 -7
- package/trades/finalize_trade_secret.js +0 -158
- package/trades/open_channel.js +0 -60
|
@@ -14,21 +14,22 @@ const uriAsSocket = n => n.substring(67);
|
|
|
14
14
|
/** Service an individual trade
|
|
15
15
|
|
|
16
16
|
{
|
|
17
|
-
[
|
|
18
|
-
[capacity]: <Channel Open Capacity Tokens Number>
|
|
17
|
+
[channel]: <Sell Channel With Capacity Tokens Number>
|
|
19
18
|
channels: [{
|
|
20
19
|
id: <Standard Format Channel Id String>
|
|
21
20
|
partner_public_key: <Node Public Key Hex String>
|
|
22
21
|
}]
|
|
23
|
-
description: <Trade Description String>
|
|
22
|
+
[description]: <Trade Description String>
|
|
24
23
|
expires_at: <Expires At ISO 8601 Date String>
|
|
25
24
|
id: <Trade Anchor Id Hex String>
|
|
26
25
|
lnd: <Authenticated LND API Object>
|
|
27
26
|
logger: <Winston Logger Object>
|
|
28
27
|
network: <Network Name String>
|
|
28
|
+
[price]: <Price Expression String>
|
|
29
29
|
public_key: <Identity Public Key Hex String>
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
request: <Request Function>
|
|
31
|
+
[secret]: <Secret to Sell String>
|
|
32
|
+
[tokens]: <Trade Price Tokens Number>
|
|
32
33
|
uris: [<Node URI String>]
|
|
33
34
|
}
|
|
34
35
|
|
|
@@ -39,12 +40,16 @@ module.exports = (args, cbk) => {
|
|
|
39
40
|
return asyncAuto({
|
|
40
41
|
// Check arguments
|
|
41
42
|
validate: cbk => {
|
|
43
|
+
if (!args.channel && !args.secret) {
|
|
44
|
+
return cbk([400, 'ExpectedSecretOrChannelToSellToServiceTrade']);
|
|
45
|
+
}
|
|
46
|
+
|
|
42
47
|
if (!isArray(args.channels)) {
|
|
43
48
|
return cbk([400, 'ExpectedArrayOfChannelsToServiceTrade']);
|
|
44
49
|
}
|
|
45
50
|
|
|
46
|
-
if (!args.description) {
|
|
47
|
-
return cbk([400, '
|
|
51
|
+
if (!args.channel && !args.description) {
|
|
52
|
+
return cbk([400, 'ExpectedChannelOrDescriptionToServiceTrade']);
|
|
48
53
|
}
|
|
49
54
|
|
|
50
55
|
if (!args.expires_at) {
|
|
@@ -67,16 +72,16 @@ module.exports = (args, cbk) => {
|
|
|
67
72
|
return cbk([400, 'ExpectedNetworkNameToServiceTrade']);
|
|
68
73
|
}
|
|
69
74
|
|
|
70
|
-
if (!args.
|
|
71
|
-
return cbk([400, '
|
|
75
|
+
if (!args.price && !args.tokens) {
|
|
76
|
+
return cbk([400, 'ExpectedTokensOrPriceExpressionToServiceTrade']);
|
|
72
77
|
}
|
|
73
78
|
|
|
74
|
-
if (!args.
|
|
75
|
-
return cbk([400, '
|
|
79
|
+
if (!args.public_key) {
|
|
80
|
+
return cbk([400, 'ExpectedIdentityPublicKeyToServiceTrade']);
|
|
76
81
|
}
|
|
77
82
|
|
|
78
|
-
if (!args.
|
|
79
|
-
return cbk([400, '
|
|
83
|
+
if (!args.request) {
|
|
84
|
+
return cbk([400, 'ExpectedRequestFunctionToServiceTrade']);
|
|
80
85
|
}
|
|
81
86
|
|
|
82
87
|
if (!isArray(args.uris)) {
|
|
@@ -104,15 +109,15 @@ module.exports = (args, cbk) => {
|
|
|
104
109
|
args.logger.info({trade_expiry: new Date(args.expires_at)});
|
|
105
110
|
|
|
106
111
|
const sub = serviceTradeRequests({
|
|
107
|
-
|
|
108
|
-
capacity: args.capacity,
|
|
112
|
+
channel: args.channel,
|
|
109
113
|
description: args.description,
|
|
110
114
|
expires_at: args.expires_at,
|
|
111
115
|
id: args.id,
|
|
112
116
|
lnd: args.lnd,
|
|
113
|
-
|
|
117
|
+
price: args.price,
|
|
118
|
+
request: args.request,
|
|
114
119
|
secret: args.secret,
|
|
115
|
-
tokens:
|
|
120
|
+
tokens: args.tokens,
|
|
116
121
|
});
|
|
117
122
|
|
|
118
123
|
// Someone asked for trade details
|
|
@@ -130,6 +135,8 @@ module.exports = (args, cbk) => {
|
|
|
130
135
|
|
|
131
136
|
sub.on('failure', failure => args.logger.error({failure}));
|
|
132
137
|
|
|
138
|
+
sub.on('opening_channel', opening => args.logger.info({opening}));
|
|
139
|
+
|
|
133
140
|
sub.on('settled', ({to}) => settled.push(to));
|
|
134
141
|
|
|
135
142
|
sub.on('trade', async ({to}) => {
|
|
@@ -6,7 +6,7 @@ const {getInvoice} = require('ln-service');
|
|
|
6
6
|
const {subscribeToInvoice} = require('ln-service');
|
|
7
7
|
|
|
8
8
|
const acceptTrade = require('./accept_trade');
|
|
9
|
-
const
|
|
9
|
+
const finalizeTrade = require('./finalize_trade');
|
|
10
10
|
const {makePeerRequest} = require('./../p2p');
|
|
11
11
|
const {servicePeerRequests} = require('./../p2p');
|
|
12
12
|
const {serviceTypeReceiveChannelSale} = require('./../service_types');
|
|
@@ -14,16 +14,15 @@ const {serviceTypeRequestChannelSale} = require('./../service_types');
|
|
|
14
14
|
const {serviceTypeRequestTrades} = require('./../service_types');
|
|
15
15
|
const {serviceTypeReceiveTrades} = require('./../service_types');
|
|
16
16
|
|
|
17
|
+
const chanDescription = capacity => `${(capacity / 1e8).toFixed(8)} channel`;
|
|
17
18
|
const descRecord = description => ({type: '2', value: description});
|
|
18
|
-
const events =
|
|
19
|
+
const events = 'details end failure opening_channel settled trade'.split(' ');
|
|
19
20
|
const findIdRecord = records => records.find(n => n.type === '0');
|
|
20
21
|
const findRequestIdRecord = records => records.find(n => n.type === '1');
|
|
21
22
|
const hashHexLength = 64;
|
|
22
23
|
const idBackType = '0';
|
|
23
24
|
const idRecord = id => ({type: '1', value: id});
|
|
24
|
-
const msRemainingToTime = time => time - Date.now();
|
|
25
25
|
const postOpenTradeTimeoutMs = 1000 * 30;
|
|
26
|
-
const sellAction = 'sell';
|
|
27
26
|
const sumOf = arr => arr.reduce((sum, n) => sum + n, 0);
|
|
28
27
|
const tradeSecretType = '1';
|
|
29
28
|
const utf8AsHex = utf8 => Buffer.from(utf8).toString('hex');
|
|
@@ -32,15 +31,19 @@ const utf8AsHex = utf8 => Buffer.from(utf8).toString('hex');
|
|
|
32
31
|
|
|
33
32
|
The maximum expiration date is three weeks
|
|
34
33
|
|
|
34
|
+
Either a channel or secret to sell is required
|
|
35
|
+
Either a direct price in tokens or a price expression is required
|
|
36
|
+
|
|
35
37
|
{
|
|
36
|
-
|
|
37
|
-
description: <Trade Description String>
|
|
38
|
+
[channel]: <Sell Channel With Capacity Tokens Number>
|
|
39
|
+
[description]: <Trade Description String>
|
|
38
40
|
expires_at: <Trade Expires At ISO 8601 Date String>
|
|
39
41
|
id: <Trade Id Hex String>
|
|
40
42
|
lnd: <Authenticated LND API Object>
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
[price]: <Trade Price String>
|
|
44
|
+
request: <Request Function>
|
|
45
|
+
[secret]: <Secret Payload String>
|
|
46
|
+
[tokens]: <Trade Price Tokens Number>
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
// Return details
|
|
@@ -56,6 +59,14 @@ const utf8AsHex = utf8 => Buffer.from(utf8).toString('hex');
|
|
|
56
59
|
@event 'failure'
|
|
57
60
|
[<Failure Code Number>, <Failure Code String>]
|
|
58
61
|
|
|
62
|
+
// Traded a channel open
|
|
63
|
+
@event 'opening_channel'
|
|
64
|
+
{
|
|
65
|
+
fee_tokens_per_vbyte: <Chain Fee Rate Number>
|
|
66
|
+
transaction_id: <Channel Funding Transaction Id Hex String>
|
|
67
|
+
transaction_vout: <Channel Funding Transaction Output Index Number>
|
|
68
|
+
}
|
|
69
|
+
|
|
59
70
|
// Received payment
|
|
60
71
|
@event 'settled'
|
|
61
72
|
{
|
|
@@ -72,7 +83,11 @@ const utf8AsHex = utf8 => Buffer.from(utf8).toString('hex');
|
|
|
72
83
|
<Service Event Emitter Object>
|
|
73
84
|
*/
|
|
74
85
|
module.exports = args => {
|
|
75
|
-
if (!args.
|
|
86
|
+
if (!args.channel && !args.secret) {
|
|
87
|
+
throw new Error('ExpectedChannelOrSecretToEncryptToServiceTradeRequests');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!args.channel && !args.description) {
|
|
76
91
|
throw new Error('ExpectedTradeDescriptionToServiceTradeRequests');
|
|
77
92
|
}
|
|
78
93
|
|
|
@@ -88,16 +103,15 @@ module.exports = args => {
|
|
|
88
103
|
throw new Error('ExpectedAuthenticatedLndToServiceTradeRequests');
|
|
89
104
|
}
|
|
90
105
|
|
|
91
|
-
if (!args.
|
|
92
|
-
throw new Error('
|
|
106
|
+
if (!args.price && !args.tokens) {
|
|
107
|
+
throw new Error('ExpectedTokensOrPriceForTradeToServiceTradeRequests');
|
|
93
108
|
}
|
|
94
109
|
|
|
95
|
-
if (!args.
|
|
96
|
-
throw new Error('
|
|
110
|
+
if (!args.request) {
|
|
111
|
+
throw new Error('ExpectedRequestFunctionToServiceTradeRequests');
|
|
97
112
|
}
|
|
98
113
|
|
|
99
114
|
const emitter = new EventEmitter();
|
|
100
|
-
|
|
101
115
|
const holds = [];
|
|
102
116
|
const service = servicePeerRequests({lnd: args.lnd});
|
|
103
117
|
|
|
@@ -129,10 +143,10 @@ module.exports = args => {
|
|
|
129
143
|
// Basic trade description
|
|
130
144
|
const basicTradeRecords = [
|
|
131
145
|
idRecord(args.id),
|
|
132
|
-
descRecord(utf8AsHex(args.description)),
|
|
146
|
+
descRecord(utf8AsHex(args.description || chanDescription(args.channel))),
|
|
133
147
|
];
|
|
134
148
|
|
|
135
|
-
const requestType = !!args.
|
|
149
|
+
const requestType = !!args.channel ?
|
|
136
150
|
serviceTypeRequestChannelSale :
|
|
137
151
|
serviceTypeRequestTrades;
|
|
138
152
|
|
|
@@ -173,7 +187,7 @@ module.exports = args => {
|
|
|
173
187
|
return;
|
|
174
188
|
}
|
|
175
189
|
|
|
176
|
-
const receiveType = args.
|
|
190
|
+
const receiveType = !!args.channel ?
|
|
177
191
|
serviceTypeReceiveChannelSale :
|
|
178
192
|
serviceTypeReceiveTrades;
|
|
179
193
|
|
|
@@ -204,13 +218,15 @@ module.exports = args => {
|
|
|
204
218
|
emitter.emit('trade', ({to: req.from}));
|
|
205
219
|
|
|
206
220
|
// Create a trade secret for the requesting peer and return that
|
|
207
|
-
return
|
|
208
|
-
|
|
221
|
+
return finalizeTrade({
|
|
222
|
+
channel: args.channel,
|
|
209
223
|
description: args.description,
|
|
210
224
|
expires_at: args.expires_at,
|
|
225
|
+
id: args.id,
|
|
211
226
|
is_hold: true,
|
|
212
227
|
lnd: args.lnd,
|
|
213
|
-
|
|
228
|
+
price: args.price,
|
|
229
|
+
request: args.request,
|
|
214
230
|
secret: args.secret,
|
|
215
231
|
to: req.from,
|
|
216
232
|
tokens: args.tokens,
|
|
@@ -219,7 +235,7 @@ module.exports = args => {
|
|
|
219
235
|
if (!!err) {
|
|
220
236
|
emitter.emit('failure', err);
|
|
221
237
|
|
|
222
|
-
return failure([503, '
|
|
238
|
+
return failure([503, 'FailedToFinalizeTrade']);
|
|
223
239
|
}
|
|
224
240
|
|
|
225
241
|
// Create a record for the encoded trade
|
|
@@ -246,36 +262,40 @@ module.exports = args => {
|
|
|
246
262
|
|
|
247
263
|
// Settle the held invoice with the preimage
|
|
248
264
|
return acceptTrade({
|
|
249
|
-
action: args.action,
|
|
250
|
-
capacity: args.capacity,
|
|
251
265
|
cancel: holds.filter(n => n.id !== updated.id).map(n => n.id),
|
|
266
|
+
channel: args.channel,
|
|
267
|
+
from: req.from,
|
|
252
268
|
id: args.id,
|
|
253
269
|
lnd: args.lnd,
|
|
254
|
-
logger: args.logger,
|
|
255
|
-
partner_public_key: req.from,
|
|
256
270
|
secret: res.secret,
|
|
257
271
|
},
|
|
258
|
-
err => {
|
|
272
|
+
(err, res) => {
|
|
259
273
|
if (!!err) {
|
|
260
274
|
return emitter.emit('failure', err);
|
|
261
275
|
}
|
|
262
276
|
|
|
263
277
|
emitter.emit('settled', {to: req.from});
|
|
264
278
|
|
|
279
|
+
if (!!res.opening_channel) {
|
|
280
|
+
emitter.emit('opening_channel', res.opening_channel);
|
|
281
|
+
}
|
|
282
|
+
|
|
265
283
|
return emitter.emit('end', {});
|
|
266
284
|
});
|
|
267
285
|
});
|
|
268
286
|
|
|
269
|
-
// Exit early on channel sale,
|
|
270
|
-
if (args.
|
|
287
|
+
// Exit early on channel sale, make sure a channel can be opened first
|
|
288
|
+
if (!!args.channel) {
|
|
271
289
|
return acceptsChannelOpen({
|
|
272
|
-
capacity: args.
|
|
290
|
+
capacity: args.channel,
|
|
273
291
|
lnd: args.lnd,
|
|
274
292
|
partner_public_key: req.from,
|
|
275
293
|
},
|
|
276
294
|
err => {
|
|
277
295
|
if (!!err) {
|
|
278
|
-
|
|
296
|
+
emitter.emit('failure', [503, 'FailedOpenAttempt', {err}]);
|
|
297
|
+
|
|
298
|
+
return failure([503, 'CannotOpenChannel']);
|
|
279
299
|
}
|
|
280
300
|
|
|
281
301
|
// Return details about the trade
|
|
@@ -16,12 +16,14 @@ const decodeAnchoredTrade = require('./decode_anchored_trade');
|
|
|
16
16
|
@returns
|
|
17
17
|
{
|
|
18
18
|
[trade]: {
|
|
19
|
+
[channel]: <Channel Sale Tokens Number>
|
|
19
20
|
created_at: <Open Trade Created At ISO 8601 Date String>
|
|
20
|
-
description: <Trade Description String>
|
|
21
|
+
[description]: <Trade Description String>
|
|
21
22
|
expires_at: <Trade Expires at ISO 8601 Date String>
|
|
22
23
|
id: <Trade Id Hex String>
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
[price]: <Price Expression String>
|
|
25
|
+
[secret]: <Secret Payload String>
|
|
26
|
+
[tokens]: <Tokens Number>
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
*/
|
|
@@ -30,7 +32,7 @@ module.exports = args => {
|
|
|
30
32
|
return {};
|
|
31
33
|
}
|
|
32
34
|
|
|
33
|
-
if (!!args.is_push
|
|
35
|
+
if (!!args.is_push) {
|
|
34
36
|
return {};
|
|
35
37
|
}
|
|
36
38
|
|
|
@@ -43,12 +45,14 @@ module.exports = args => {
|
|
|
43
45
|
|
|
44
46
|
return {
|
|
45
47
|
trade: {
|
|
48
|
+
channel: trade.channel || undefined,
|
|
46
49
|
created_at: args.created_at,
|
|
47
|
-
description: trade.description,
|
|
50
|
+
description: trade.description || undefined,
|
|
48
51
|
expires_at: args.expires_at,
|
|
49
52
|
id: args.id,
|
|
50
|
-
|
|
51
|
-
|
|
53
|
+
price: trade.price || undefined,
|
|
54
|
+
secret: trade.secret || undefined,
|
|
55
|
+
tokens: args.tokens || undefined,
|
|
52
56
|
},
|
|
53
57
|
};
|
|
54
58
|
};
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
const {createHash} = require('crypto');
|
|
2
|
-
|
|
3
|
-
const asyncAuto = require('async/auto');
|
|
4
|
-
const {createHodlInvoice} = require('ln-service');
|
|
5
|
-
const {createInvoice} = require('ln-service');
|
|
6
|
-
const {getChainFeeRate} = require('ln-service');
|
|
7
|
-
const {returnResult} = require('asyncjs-util');
|
|
8
|
-
|
|
9
|
-
const encodeTradeSecret = require('./encode_trade_secret');
|
|
10
|
-
const encryptTradeSecret = require('./encrypt_trade_secret');
|
|
11
|
-
|
|
12
|
-
const bufferAsHex = buffer => buffer.toString('hex');
|
|
13
|
-
const {ceil} = Math;
|
|
14
|
-
const hexAsBuffer = hex => Buffer.from(hex, 'hex');
|
|
15
|
-
const openSizeVbytes = 250;
|
|
16
|
-
const sellAction = 'sell';
|
|
17
|
-
const sha256 = preimage => createHash('sha256').update(preimage).digest();
|
|
18
|
-
const slowConf = 144;
|
|
19
|
-
const utf8AsHex = utf8 => Buffer.from(utf8, 'utf8').toString('hex');
|
|
20
|
-
|
|
21
|
-
/** Create a trade secret for a node
|
|
22
|
-
|
|
23
|
-
{
|
|
24
|
-
action: <Trade Action String>
|
|
25
|
-
description: <Trade Description String>
|
|
26
|
-
expires_at: <Trade Expires At ISO 8601 Date String>
|
|
27
|
-
is_hold: <Create Hold Invoice Bool>
|
|
28
|
-
lnd: <Authenticated LND API Object>
|
|
29
|
-
logger: <Winston Logger Object>
|
|
30
|
-
secret: <Clear Secret String>
|
|
31
|
-
to: <To Public Key Hex Encoded String>
|
|
32
|
-
tokens: <Price Tokens Number>
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
@returns via cbk or Promise
|
|
36
|
-
{
|
|
37
|
-
id: <Payment Hash Hex String>
|
|
38
|
-
secret: <Hex Encoded Payment Secret String>
|
|
39
|
-
trade: <Hex Encoded Trade String>
|
|
40
|
-
}
|
|
41
|
-
*/
|
|
42
|
-
module.exports = (args, cbk) => {
|
|
43
|
-
return new Promise((resolve, reject) => {
|
|
44
|
-
return asyncAuto({
|
|
45
|
-
// Check arguments
|
|
46
|
-
validate: cbk => {
|
|
47
|
-
if (!args.description) {
|
|
48
|
-
return cbk([400, 'ExpectedDescriptionToFinalizeTradeSecret']);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (!args.expires_at) {
|
|
52
|
-
return cbk([400, 'ExpectedExpiresAtDateToFinalizeTradeSecret']);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (!args.lnd) {
|
|
56
|
-
return cbk([400, 'ExpectedAuthenticatedLndToFinalizeTradeSecret']);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (!args.secret) {
|
|
60
|
-
return cbk([400, 'ExpectedSecretValueToFinalizeTradeSecret']);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (!args.to) {
|
|
64
|
-
return cbk([400, 'ExpectedToPublicKeyToFinalizeTradeSecret']);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (!args.tokens) {
|
|
68
|
-
return cbk([400, 'ExpectedTokensPriceToFinalizeTradeSecret']);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return cbk();
|
|
72
|
-
},
|
|
73
|
-
|
|
74
|
-
// Calculate dynamic sale price for channel sales
|
|
75
|
-
salePrice: ['validate', ({}, cbk) => {
|
|
76
|
-
// Exit early when this is not a channel sale
|
|
77
|
-
if (args.action !== sellAction) {
|
|
78
|
-
return cbk(null, {});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Get a chain fee rate to dynamically price vs the chain cost
|
|
82
|
-
return getChainFeeRate({
|
|
83
|
-
confirmation_target: slowConf,
|
|
84
|
-
lnd: args.lnd,
|
|
85
|
-
},
|
|
86
|
-
(err, res) => {
|
|
87
|
-
if (!!err) {
|
|
88
|
-
return cbk(err);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const chainSurcharge = ceil(res.tokens_per_vbyte * openSizeVbytes);
|
|
92
|
-
|
|
93
|
-
const price = chainSurcharge + args.tokens;
|
|
94
|
-
|
|
95
|
-
args.logger.info({total_channel_sale_cost: price});
|
|
96
|
-
|
|
97
|
-
return cbk(null, {price});
|
|
98
|
-
},
|
|
99
|
-
cbk);
|
|
100
|
-
}],
|
|
101
|
-
|
|
102
|
-
// Encrypt the secret data
|
|
103
|
-
encrypt: ['validate', ({}, cbk) => {
|
|
104
|
-
return encryptTradeSecret({
|
|
105
|
-
lnd: args.lnd,
|
|
106
|
-
secret: utf8AsHex(args.secret),
|
|
107
|
-
to: args.to,
|
|
108
|
-
},
|
|
109
|
-
cbk);
|
|
110
|
-
}],
|
|
111
|
-
|
|
112
|
-
// Create the invoice to purchase the unlocking secret
|
|
113
|
-
createInvoice: ['encrypt', 'salePrice', ({encrypt, salePrice}, cbk) => {
|
|
114
|
-
// Exit early when this is a hold invoice
|
|
115
|
-
if (!!args.is_hold) {
|
|
116
|
-
return createHodlInvoice({
|
|
117
|
-
description: args.description,
|
|
118
|
-
expires_at: args.expires_at,
|
|
119
|
-
id: bufferAsHex(sha256(hexAsBuffer(encrypt.payment_secret))),
|
|
120
|
-
lnd: args.lnd,
|
|
121
|
-
secret: encrypt.payment_secret,
|
|
122
|
-
tokens: salePrice.price || args.tokens,
|
|
123
|
-
},
|
|
124
|
-
cbk);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return createInvoice({
|
|
128
|
-
description: args.description,
|
|
129
|
-
expires_at: args.expires_at,
|
|
130
|
-
lnd: args.lnd,
|
|
131
|
-
secret: encrypt.payment_secret,
|
|
132
|
-
tokens: args.tokens,
|
|
133
|
-
},
|
|
134
|
-
cbk);
|
|
135
|
-
}],
|
|
136
|
-
|
|
137
|
-
// Encode all the trade data into wire format
|
|
138
|
-
encode: ['createInvoice', 'encrypt', ({createInvoice, encrypt}, cbk) => {
|
|
139
|
-
try {
|
|
140
|
-
const {trade} = encodeTradeSecret({
|
|
141
|
-
auth: encrypt.trade_auth_tag,
|
|
142
|
-
payload: encrypt.trade_cipher,
|
|
143
|
-
request: createInvoice.request,
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
return cbk(null, {
|
|
147
|
-
trade,
|
|
148
|
-
id: createInvoice.id,
|
|
149
|
-
secret: encrypt.payment_secret,
|
|
150
|
-
});
|
|
151
|
-
} catch (err) {
|
|
152
|
-
return cbk([500, err.message]);
|
|
153
|
-
}
|
|
154
|
-
}],
|
|
155
|
-
},
|
|
156
|
-
returnResult({reject, resolve, of: 'encode'}, cbk));
|
|
157
|
-
});
|
|
158
|
-
};
|
package/trades/open_channel.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
const asyncAuto = require('async/auto');
|
|
2
|
-
const {getPeers} = require('ln-service');
|
|
3
|
-
const {getChainFeeRate} = require('ln-service');
|
|
4
|
-
const {openChannel} = require('ln-service');
|
|
5
|
-
const {returnResult} = require('asyncjs-util');
|
|
6
|
-
|
|
7
|
-
const slowConf = 144;
|
|
8
|
-
|
|
9
|
-
/** Opens channel on invoice payment
|
|
10
|
-
{
|
|
11
|
-
id: <Partner Public Key Hex String>
|
|
12
|
-
lnd: <Authenticated LND API Object>
|
|
13
|
-
tokens: <Capacity of Channel To Open Tokens Number>
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
@returns via cbk or Promise
|
|
17
|
-
{
|
|
18
|
-
transaction_id: <Funding Transaction Id String>
|
|
19
|
-
transaction_vout: <Funding Transaction Output Index Number>
|
|
20
|
-
}
|
|
21
|
-
*/
|
|
22
|
-
module.exports = ({id, lnd, tokens}, cbk) => {
|
|
23
|
-
return new Promise((resolve, reject) => {
|
|
24
|
-
return asyncAuto({
|
|
25
|
-
// Check arguments
|
|
26
|
-
validate: cbk => {
|
|
27
|
-
if (!id) {
|
|
28
|
-
return cbk([400, 'ExpectedPartnerPublicKeyToOpenNewChannel']);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (!lnd) {
|
|
32
|
-
return cbk([400, 'ExpectedLndObjectToOpenNewChannel']);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (!tokens) {
|
|
36
|
-
return cbk([400, 'ExpectedCapacityToOpenNewChannel']);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return cbk();
|
|
40
|
-
},
|
|
41
|
-
|
|
42
|
-
// Get low fee rate
|
|
43
|
-
getSlowFee: ['validate', ({}, cbk) => {
|
|
44
|
-
return getChainFeeRate({lnd, confirmation_target: slowConf}, cbk);
|
|
45
|
-
}],
|
|
46
|
-
|
|
47
|
-
// Select a peer and open a channel
|
|
48
|
-
openChannel: ['getSlowFee', ({getSlowFee}, cbk) => {
|
|
49
|
-
return openChannel({
|
|
50
|
-
lnd,
|
|
51
|
-
chain_fee_rate: getSlowFee.tokens_per_vbyte,
|
|
52
|
-
local_tokens: tokens,
|
|
53
|
-
partner_public_key: id,
|
|
54
|
-
},
|
|
55
|
-
cbk);
|
|
56
|
-
}],
|
|
57
|
-
},
|
|
58
|
-
returnResult({reject, resolve, of: 'openChannel'}, cbk));
|
|
59
|
-
});
|
|
60
|
-
};
|