paid-services 3.3.0 → 3.6.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.
Files changed (54) hide show
  1. package/.prettierignore +2 -0
  2. package/CHANGELOG.md +17 -0
  3. package/capacity/accept_capacity_change.js +3 -3
  4. package/capacity/ask_for_change_details.js +34 -1
  5. package/capacity/capacity_change_requests.js +9 -0
  6. package/capacity/change_channel_capacity.js +7 -1
  7. package/capacity/encode_change_request.js +8 -1
  8. package/capacity/fee_for_replacement.js +1 -1
  9. package/capacity/get_capacity_change_requests.js +2 -1
  10. package/capacity/get_capacity_replacement.js +1 -1
  11. package/capacity/initiate_capacity_change.js +5 -5
  12. package/capacity/parse_capacity_change_request.js +8 -1
  13. package/capacity/propose_capacity_change.js +4 -1
  14. package/p2p/service_peer_requests.js +10 -2
  15. package/package.json +10 -9
  16. package/service_types.json +16 -0
  17. package/services/response_for_relay.js +0 -1
  18. package/test/capacity/test_capacity_change_requests.js +1 -0
  19. package/test/capacity/test_encode_change_request.js +5 -0
  20. package/test/capacity/test_parse_capacity_change_request.js +1 -0
  21. package/test/integration/test_accept_capacity_change.js +50 -14
  22. package/test/integration/test_change_channel_capacity.js +7 -1
  23. package/test/integration/test_decrease_channel_capacity.js +16 -7
  24. package/test/integration/test_increase_channel_capacity.js +4 -1
  25. package/test/trades/test_decode_basic_trade.js +40 -0
  26. package/test/trades/test_decode_open_trade.js +50 -0
  27. package/test/trades/test_encode_open_trade.js +35 -0
  28. package/test/trades/test_encode_trade.js +37 -0
  29. package/trades/accept_trade.js +61 -0
  30. package/trades/create_trade.js +149 -37
  31. package/trades/decode_anchored_trade.js +56 -0
  32. package/trades/decode_basic_trade.js +45 -0
  33. package/trades/decode_open_trade.js +69 -0
  34. package/trades/decode_trade.js +48 -66
  35. package/trades/decode_trade_secret.js +89 -0
  36. package/trades/encode_anchored_trade.js +35 -0
  37. package/trades/encode_open_trade.js +89 -0
  38. package/trades/encode_trade.js +48 -33
  39. package/trades/encode_trade_secret.js +50 -0
  40. package/trades/finalize_trade_secret.js +123 -0
  41. package/trades/find_trade.js +339 -0
  42. package/trades/manage_trade.js +61 -39
  43. package/trades/manage_trades.js +209 -2
  44. package/trades/network_from_network_record.js +3 -3
  45. package/trades/network_record_from_network.js +36 -0
  46. package/trades/network_record_from_request.js +2 -1
  47. package/trades/node_as_record.js +98 -0
  48. package/trades/record_as_node.js +113 -0
  49. package/trades/request_trade_by_id.js +95 -0
  50. package/trades/service_anchored_trades.js +181 -0
  51. package/trades/service_open_trade.js +172 -0
  52. package/trades/service_trade_requests.js +255 -0
  53. package/trades/trade_from_invoice.js +51 -0
  54. package/capacity/service_types.json +0 -6
@@ -0,0 +1,181 @@
1
+ const EventEmitter = require('events');
2
+
3
+ const asyncUntil = require('async/until');
4
+ const {getInvoices} = require('ln-service');
5
+ const {subscribeToInvoice} = require('ln-service');
6
+ const {subscribeToInvoices} = require('ln-service');
7
+
8
+ const decodeAnchoredTrade = require('./decode_anchored_trade');
9
+ const serviceTradeRequests = require('./service_trade_requests');
10
+ const tradeFromInvoice = require('./trade_from_invoice');
11
+
12
+ const defaultInvoicesLimit = 100;
13
+ const events = ['details', 'error', 'failure', 'settled', 'trade'];
14
+ const fromNow = date => new Date(date) - new Date();
15
+ const {keys} = Object;
16
+
17
+ /** Service trades represented by anchored invoices
18
+
19
+ {
20
+ lnd: <Authenticated LND API Object>
21
+ }
22
+
23
+ // Returned details
24
+ @event 'details'
25
+ {
26
+ to: <Public Key Id Hex String>
27
+ }
28
+
29
+ // Terminal failure
30
+ @event 'error'
31
+ <Error Object>
32
+
33
+ // Encountered a failure
34
+ @event 'failure'
35
+ [<Failure Code Number>, <Failure Code String>]
36
+
37
+ // Received payment
38
+ @event 'settled'
39
+ {
40
+ description: <Trade Description String>
41
+ id: <Trade Id Hex String>
42
+ secret: <Secret Payload String>
43
+ to: <Public Key Id Hex String>
44
+ tokens: <Tokens Number>
45
+ }
46
+
47
+ // Starting service for trade
48
+ @event 'start'
49
+ {
50
+ description: <Trade Description String>
51
+ expires_at: <Trade Expires at ISO 8601 Date String>
52
+ id: <Trade Id Hex String>
53
+ secret: <Secret Payload String>
54
+ tokens: <Tokens Number>
55
+ }
56
+
57
+ // Return finalized trade
58
+ @event 'trade'
59
+ {
60
+ to: <Public Key Id Hex String>
61
+ }
62
+
63
+ @returns
64
+ <EventEmitter Object>
65
+ */
66
+ module.exports = ({lnd}) => {
67
+ const emitter = new EventEmitter();
68
+ const listening = {};
69
+ const paging = {};
70
+
71
+ // Service a trade until it's paid or canceled
72
+ const serviceTrade = trade => {
73
+ // Exit early when already listening to this trade
74
+ if (!!listening[trade.id]) {
75
+ return;
76
+ }
77
+
78
+ const sub = serviceTradeRequests({
79
+ lnd,
80
+ description: trade.description,
81
+ expires_at: trade.expires_at,
82
+ id: trade.id,
83
+ secret: trade.secret,
84
+ tokens: trade.tokens,
85
+ });
86
+
87
+ // Pick up the trade to service
88
+ emitter.emit('start', {
89
+ description: trade.description,
90
+ expires_at: trade.expires_at,
91
+ id: trade.id,
92
+ secret: trade.secret,
93
+ tokens: trade.tokens,
94
+ });
95
+
96
+ // Settled a trade
97
+ sub.on('settled', ({to}) => {
98
+ return emitter.emit('settled', {
99
+ to,
100
+ id: trade.id,
101
+ description: trade.description,
102
+ secret: trade.secret,
103
+ tokens: trade.tokens,
104
+ });
105
+ });
106
+
107
+ // Remember this listener to avoid double-listening to the same trade
108
+ listening[trade.id] = sub;
109
+
110
+ sub.on('details', ({to}) => emitter.emit('details', {to, id: trade.id}));
111
+ sub.on('failure', err => emitter.emit('failure', {err, id: trade.id}));
112
+ sub.on('trade', ({to}) => emitter.emit('trade', {to, id: trade.id}));
113
+
114
+ sub.once('end', () => sub.removeAllListeners());
115
+
116
+ const invoiceUpdates = subscribeToInvoice({lnd, id: trade.id});
117
+
118
+ invoiceUpdates.on('invoice_updated', updated => {
119
+ if (!updated.is_canceled) {
120
+ return;
121
+ }
122
+
123
+ return invoiceUpdates.removeAllListeners();
124
+ });
125
+
126
+ return;
127
+ };
128
+
129
+ // Listen for any new invoices that represent anchored trades
130
+ const sub = subscribeToInvoices({lnd});
131
+
132
+ // Listen for new trades to appear
133
+ sub.on('invoice_updated', invoice => {
134
+ const {trade} = tradeFromInvoice(invoice);
135
+
136
+ // Exit early when there is no anchored trade found in the description
137
+ if (!trade) {
138
+ return;
139
+ }
140
+
141
+ return serviceTrade(trade);
142
+ });
143
+
144
+ // Find open anchored trades
145
+ asyncUntil(
146
+ cbk => cbk(null, paging.token === false),
147
+ cbk => {
148
+ return getInvoices({
149
+ lnd,
150
+ is_unconfirmed: true,
151
+ limit: !paging.token ? defaultInvoicesLimit : undefined,
152
+ token: paging.token,
153
+ },
154
+ (err, res) => {
155
+ if (!!err) {
156
+ emitter.emit(err);
157
+
158
+ // Stop listening to all invoices
159
+ sub.removeAllListeners();
160
+
161
+ // Stop listening to all anchor invoices
162
+ keys(listening).forEach(id => listening[id].removeAllListeners());
163
+
164
+ return;
165
+ }
166
+
167
+ paging.token = res.next || false;
168
+
169
+ res.invoices
170
+ .map(tradeFromInvoice)
171
+ .map(n => n.trade)
172
+ .filter(n => !!n)
173
+ .forEach(serviceTrade);
174
+
175
+ return cbk();
176
+ });
177
+ }
178
+ );
179
+
180
+ return emitter;
181
+ };
@@ -0,0 +1,172 @@
1
+ const asyncAuto = require('async/auto');
2
+ const {getNodeAlias} = require('ln-sync');
3
+ const {returnResult} = require('asyncjs-util');
4
+
5
+ const encodeOpenTrade = require('./encode_open_trade');
6
+ const serviceTradeRequests = require('./service_trade_requests');
7
+
8
+ const asNumber = n => parseFloat(n, 10);
9
+ const {isArray} = Array;
10
+ const nodeName = (alias, id) => `${alias} ${id}`;
11
+ const slowTradeDate = () => new Date(Date.now() + (86400000*15)).toISOString();
12
+ const uriAsSocket = n => n.substring(67);
13
+
14
+ /** Service an individual trade
15
+
16
+ {
17
+ channels: [{
18
+ id: <Standard Format Channel Id String>
19
+ partner_public_key: <Node Public Key Hex String>
20
+ }]
21
+ description: <Trade Description String>
22
+ expires_at: <Expires At ISO 8601 Date String>
23
+ id: <Trade Anchor Id Hex String>
24
+ lnd: <Authenticated LND API Object>
25
+ logger: <Winston Logger Object>
26
+ network: <Network Name String>
27
+ public_key: <Identity Public Key Hex String>
28
+ secret: <Secret to Sell String>
29
+ tokens: <Trade Price Tokens Number>
30
+ uris: [<Node URI String>]
31
+ }
32
+
33
+ @returns via cbk or Promise
34
+ */
35
+ module.exports = (args, cbk) => {
36
+ return new Promise((resolve, reject) => {
37
+ return asyncAuto({
38
+ // Check arguments
39
+ validate: cbk => {
40
+ if (!isArray(args.channels)) {
41
+ return cbk([400, 'ExpectedArrayOfChannelsToServiceTrade']);
42
+ }
43
+
44
+ if (!args.description) {
45
+ return cbk([400, 'ExpectedDescriptionToServiceTrade']);
46
+ }
47
+
48
+ if (!args.expires_at) {
49
+ return cbk([400, 'ExpectedExpiresAtDateToServiceTrade']);
50
+ }
51
+
52
+ if (!args.id) {
53
+ return cbk([400, 'ExpectedTradeAnchorIdToServiceTrade']);
54
+ }
55
+
56
+ if (!args.lnd) {
57
+ return cbk([400, 'ExpectedAuthenticatedLndToServiceTrade']);
58
+ }
59
+
60
+ if (!args.logger) {
61
+ return cbk([400, 'ExpectedWinstonLoggerToServiceTrade']);
62
+ }
63
+
64
+ if (!args.network) {
65
+ return cbk([400, 'ExpectedNetworkNameToServiceTrade']);
66
+ }
67
+
68
+ if (!args.public_key) {
69
+ return cbk([400, 'ExpectedIdentityPublicKeyToServiceTrade']);
70
+ }
71
+
72
+ if (!args.secret) {
73
+ return cbk([400, 'ExpectedSecretToSellToServiceTrade']);
74
+ }
75
+
76
+ if (!args.tokens) {
77
+ return cbk([400, 'ExpectedTokensPriceToServiceTrade']);
78
+ }
79
+
80
+ if (!isArray(args.uris)) {
81
+ return cbk([400, 'ExpectedArrayOfNodeSocketUrisToServiceTrade']);
82
+ }
83
+
84
+ return cbk();
85
+ },
86
+
87
+ // Serve the trade
88
+ serve: ['validate', ({}, cbk) => {
89
+ const isSlowTrade = args.expires_at > slowTradeDate();
90
+ const settled = [];
91
+
92
+ // Encode the open trade details to give out
93
+ const openTrade = encodeOpenTrade({
94
+ network: args.network,
95
+ nodes: [{
96
+ channels: isSlowTrade ? [] : args.channels,
97
+ id: args.public_key,
98
+ sockets: !args.channels.length ? args.uris.map(uriAsSocket) : [],
99
+ }],
100
+ });
101
+
102
+ args.logger.info({trade_expiry: new Date(args.expires_at)});
103
+
104
+ const sub = serviceTradeRequests({
105
+ description: args.description,
106
+ expires_at: args.expires_at,
107
+ id: args.id,
108
+ lnd: args.lnd,
109
+ secret: args.secret,
110
+ tokens: asNumber(args.tokens),
111
+ });
112
+
113
+ // Someone asked for trade details
114
+ sub.on('details', async ({to}) => {
115
+ try {
116
+ const {alias, id} = await getNodeAlias({id: to, lnd: args.lnd});
117
+
118
+ const toName = nodeName(alias, id);
119
+
120
+ return args.logger.info({return_trade_info_to: toName});
121
+ } catch (err) {
122
+ return args.logger.error({err});
123
+ }
124
+ });
125
+
126
+ sub.on('failure', failure => args.logger.error({failure}));
127
+
128
+ sub.on('settled', ({to}) => settled.push(to));
129
+
130
+ sub.on('trade', async ({to}) => {
131
+ try {
132
+ const {alias, id} = await getNodeAlias({id: to, lnd: args.lnd});
133
+
134
+ const toName = nodeName(alias, id);
135
+
136
+ return args.logger.info({make_trade_invoice_for: toName});
137
+ } catch (err) {
138
+ return args.logger.error({err});
139
+ }
140
+ });
141
+
142
+ // Show the trade details blob
143
+ return args.logger.info({
144
+ waiting_for_trade_request_to: openTrade.trade,
145
+ });
146
+
147
+ // Wait for the trade to end
148
+ sub.once('end', async () => {
149
+ try {
150
+ const [to] = settled;
151
+
152
+ // Exit early when there was no settlement
153
+ if (!to) {
154
+ args.logger.info({trade_ended: true});
155
+
156
+ return cbk();
157
+ }
158
+
159
+ const {alias, id} = await getNodeAlias({id: to, lnd: args.lnd});
160
+
161
+ args.logger.info({finished_trade_with: nodeName(alias, id)});
162
+ } catch (err) {
163
+ args.logger.error({err});
164
+ } finally {
165
+ return cbk();
166
+ }
167
+ });
168
+ }],
169
+ },
170
+ returnResult({reject, resolve}, cbk));
171
+ });
172
+ };
@@ -0,0 +1,255 @@
1
+ const EventEmitter = require('events');
2
+ const {randomBytes} = require('crypto');
3
+
4
+ const {getInvoice} = require('ln-service');
5
+ const {subscribeToInvoice} = require('ln-service');
6
+
7
+ const acceptTrade = require('./accept_trade');
8
+ const finalizeTradeSecret = require('./finalize_trade_secret');
9
+ const {makePeerRequest} = require('./../p2p');
10
+ const {servicePeerRequests} = require('./../p2p');
11
+ const {serviceTypeRequestTrades} = require('./../service_types');
12
+ const {serviceTypeReceiveTrades} = require('./../service_types');
13
+
14
+ const descRecord = description => ({type: '2', value: description});
15
+ const events = ['details', 'end', 'failure', 'settled', 'trade'];
16
+ const findIdRecord = records => records.find(n => n.type === '0');
17
+ const findRequestIdRecord = records => records.find(n => n.type === '1');
18
+ const hashHexLength = 64;
19
+ const idBackType = '0';
20
+ const idRecord = id => ({type: '1', value: id});
21
+ const msRemainingToTime = time => time - Date.now();
22
+ const postOpenTradeTimeoutMs = 1000 * 30;
23
+ const sumOf = arr => arr.reduce((sum, n) => sum + n, 0);
24
+ const tradeSecretType = '1';
25
+ const utf8AsHex = utf8 => Buffer.from(utf8).toString('hex');
26
+
27
+ /** Service requests for an open trade
28
+
29
+ The maximum expiration date is three weeks
30
+
31
+ {
32
+ description: <Trade Description String>
33
+ expires_at: <Trade Expires At ISO 8601 Date String>
34
+ id: <Trade Id Hex String>
35
+ lnd: <Authenticated LND API Object>
36
+ secret: <Secret Payload String>
37
+ tokens: <Tokens Number>
38
+ }
39
+
40
+ // Return details
41
+ @event 'details'
42
+ {
43
+ to: <Public Key Id Hex String>
44
+ }
45
+
46
+ // Service ended
47
+ @event 'end'
48
+
49
+ // Encountered a failure
50
+ @event 'failure'
51
+ [<Failure Code Number>, <Failure Code String>]
52
+
53
+ // Received payment
54
+ @event 'settled'
55
+ {
56
+ to: <Public Key Id Hex String>
57
+ }
58
+
59
+ // Return finalized trade
60
+ @event 'trade'
61
+ {
62
+ to: <Public Key Id Hex String>
63
+ }
64
+
65
+ @returns
66
+ <Service Event Emitter Object>
67
+ */
68
+ module.exports = args => {
69
+ if (!args.description) {
70
+ throw new Error('ExpectedTradeDescriptionToServiceTradeRequests');
71
+ }
72
+
73
+ if (!args.id) {
74
+ throw new Error('ExpectedTradeIdToServiceTradeRequests');
75
+ }
76
+
77
+ if (args.id.length !== hashHexLength) {
78
+ throw new Error('ExpectedShorterRequestIdValueToServiceTradeRequests');
79
+ }
80
+
81
+ if (!args.lnd) {
82
+ throw new Error('ExpectedAuthenticatedLndToServiceTradeRequests');
83
+ }
84
+
85
+ if (!args.secret) {
86
+ throw new Error('ExpectedSecretToEncryptToServiceTradeRequests');
87
+ }
88
+
89
+ if (!args.tokens) {
90
+ throw new Error('ExpectedTokensPriceForTradeToServiceTradeRequests');
91
+ }
92
+
93
+ const emitter = new EventEmitter();
94
+
95
+ const holds = [];
96
+ const service = servicePeerRequests({lnd: args.lnd});
97
+
98
+ // Stop the service when there are no more listeners
99
+ emitter.on('removeListener', () => {
100
+ // Exit early when there are still listeners on an event
101
+ if (!!sumOf(events.map(n => emitter.listenerCount(n)))) {
102
+ return;
103
+ }
104
+
105
+ return service.stop({});
106
+ });
107
+
108
+ const sub = subscribeToInvoice({id: args.id, lnd: args.lnd});
109
+
110
+ sub.on('invoice_updated', invoice => {
111
+ if (!invoice.is_canceled) {
112
+ return;
113
+ }
114
+
115
+ holds.forEach(n => n.sub.removeAllListeners());
116
+
117
+ return service.stop({});
118
+ });
119
+
120
+ // Notify when the service ends
121
+ service.end(() => emitter.emit('end', {}));
122
+
123
+ // Basic trade description
124
+ const basicTradeRecords = [
125
+ idRecord(args.id),
126
+ descRecord(utf8AsHex(args.description)),
127
+ ];
128
+
129
+ // Wait for a request for the open trade
130
+ service.request({type: serviceTypeRequestTrades}, (req, res) => {
131
+ const {failure, success} = res;
132
+ const requestTradeId = findIdRecord(req.records);
133
+
134
+ // Exit early when the trade requested is unrelated
135
+ if (!!requestTradeId && requestTradeId.value !== args.id) {
136
+ return;
137
+ }
138
+
139
+ const requestIdRecord = findRequestIdRecord(req.records);
140
+
141
+ // A trade request either is for a specific trade or has a pingback id
142
+ if (!requestTradeId && !requestIdRecord) {
143
+ return emitter.emit('failure', [400, 'ExpectedRequestTradeOrRequestId']);
144
+ }
145
+
146
+ // Exit early when the trade is expired
147
+ if (args.expires_at < new Date().toISOString()) {
148
+ service.stop({});
149
+
150
+ return;
151
+ }
152
+
153
+ // Exit early and ping peer with trade when this is an open ended query
154
+ if (!requestTradeId) {
155
+ emitter.emit('details', {to: req.from});
156
+
157
+ const reqIdRecord = {type: idBackType, value: requestIdRecord.value};
158
+
159
+ const records = [].concat(basicTradeRecords).concat(reqIdRecord);
160
+
161
+ return getInvoice({id: args.id, lnd: args.lnd}, (err, res) => {
162
+ if (!!err || !!res.is_canceled) {
163
+ return;
164
+ }
165
+
166
+ // Ping the node with trade details
167
+ return makePeerRequest({
168
+ records,
169
+ lnd: args.lnd,
170
+ timeout: postOpenTradeTimeoutMs,
171
+ to: req.from,
172
+ type: serviceTypeReceiveTrades,
173
+ },
174
+ err => {
175
+ if (!!err) {
176
+ failure([503, 'FailedToDeliverTradeInfo']);
177
+
178
+ return emitter.emit(
179
+ 'failure',
180
+ [503, 'FailedToDeliverTradeInfo', {err}]
181
+ );
182
+ }
183
+
184
+ return success({});
185
+ });
186
+ });
187
+ }
188
+
189
+ // Make a finalized trade secret for the peer
190
+ emitter.emit('trade', ({to: req.from}));
191
+
192
+ // Create a trade secret for the requesting peer and return that
193
+ return finalizeTradeSecret({
194
+ description: args.description,
195
+ expires_at: args.expires_at,
196
+ is_hold: true,
197
+ lnd: args.lnd,
198
+ secret: args.secret,
199
+ to: req.from,
200
+ tokens: args.tokens,
201
+ },
202
+ (err, res) => {
203
+ if (!!err) {
204
+ emitter.emit('failure', err);
205
+
206
+ return failure([503, 'FailedToFinalizeTradeSecret']);
207
+ }
208
+
209
+ // Create a record for the encoded trade
210
+ const record = {type: tradeSecretType, value: res.trade};
211
+
212
+ // Add hold invoice to set of held invoices, only one should settle
213
+ const sub = subscribeToInvoice({id: res.id, lnd: args.lnd});
214
+
215
+ // Add sub to list of holds
216
+ holds.push({sub, id: res.id});
217
+
218
+ // Wait for the invoice to be paid
219
+ sub.on('invoice_updated', updated => {
220
+ // Exit early when the payment is not held yet
221
+ if (!updated.is_held) {
222
+ return;
223
+ }
224
+
225
+ // Do not accept any more bids
226
+ service.stop({});
227
+
228
+ // Stop listening to invoice events
229
+ holds.forEach(hold => hold.sub.removeAllListeners());
230
+
231
+ // Settle the held invoice with the preimage
232
+ return acceptTrade({
233
+ cancel: holds.filter(n => n.id !== updated.id).map(n => n.id),
234
+ id: args.id,
235
+ lnd: args.lnd,
236
+ secret: res.secret,
237
+ },
238
+ err => {
239
+ if (!!err) {
240
+ return emitter.emit('failure', err);
241
+ }
242
+
243
+ emitter.emit('settled', {to: req.from});
244
+
245
+ return emitter.emit('end', {});
246
+ });
247
+ });
248
+
249
+ // Return details about the trade
250
+ return success({records: [record]});
251
+ });
252
+ });
253
+
254
+ return emitter;
255
+ };
@@ -0,0 +1,51 @@
1
+ const decodeAnchoredTrade = require('./decode_anchored_trade');
2
+
3
+ /** Derive open trade details from an invoice
4
+
5
+ {
6
+ description: <Invoice Description String>
7
+ id: <Invoice Id Hex String>
8
+ expires_at: <Invoice Expiration ISO 8601 Date String>
9
+ [is_canceled]: <Invoice is Canceled Bool>
10
+ is_confirmed: <Invoice is Confirmed Bool>
11
+ [is_push]: <Invoice is Push Payment Bool>
12
+ tokens: <Invoiced Amount Number>
13
+ }
14
+
15
+ @returns
16
+ {
17
+ [trade]: {
18
+ description: <Trade Description String>
19
+ expires_at: <Trade Expires at ISO 8601 Date String>
20
+ id: <Trade Id Hex String>
21
+ secret: <Secret Payload String>
22
+ tokens: <Tokens Number>
23
+ }
24
+ }
25
+ */
26
+ module.exports = args => {
27
+ if (!args.description || !!args.is_canceled || !!args.is_confirmed) {
28
+ return {};
29
+ }
30
+
31
+ if (!!args.is_push || !args.tokens) {
32
+ return {};
33
+ }
34
+
35
+ const {trade} = decodeAnchoredTrade({encoded: args.description});
36
+
37
+ // Exit early when the invoice doesn't match an anchored trade
38
+ if (!trade) {
39
+ return {};
40
+ }
41
+
42
+ return {
43
+ trade: {
44
+ description: trade.description,
45
+ expires_at: args.expires_at,
46
+ id: args.id,
47
+ secret: trade.secret,
48
+ tokens: args.tokens,
49
+ },
50
+ };
51
+ };
@@ -1,6 +0,0 @@
1
- {
2
- "serviceTypeAcceptCapacityChange": "8050002",
3
- "serviceTypeChangeCapacity": "8050001",
4
- "serviceTypeSignCapacityChange": "805004",
5
- "serviceTypeWaitOnConfirmation": "8050003"
6
- }