paid-services 3.7.0 → 3.10.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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Versions
2
2
 
3
+ ## Version 3.10.0
4
+
5
+ - `createAnchoredTrade`: Add method to create an anchored open trade
6
+ - `getAnchoredTrade`: Add method to get an anchored open trade
7
+
8
+ ## Version 3.9.1
9
+
10
+ - `decodeTrade`: Add method to decode a trade-secret
11
+
12
+ ## Version 3.8.0
13
+
14
+ - `encodeTrade`: Add method to encode a trade-secret
15
+ - `serviceAnchoredTrades`: Add method to serve open trade-secrets
16
+
3
17
  ## Version 3.7.0
4
18
 
5
19
  - `changeChannelCapacity`: Add support for decreasing funds into a new channel
package/index.js CHANGED
@@ -1,11 +1,16 @@
1
1
  const {changeChannelCapacity} = require('./capacity');
2
2
  const {confirmServiceUse} = require('./client');
3
+ const {createAnchoredTrade} = require('./trades');
4
+ const {decodeTrade} = require('./trades');
5
+ const {encodeTrade} = require('./trades');
6
+ const {getAnchoredTrade} = require('./trades');
3
7
  const {getServiceSchema} = require('./client');
4
8
  const {getServicesList} = require('./client');
5
9
  const {makePeerRequest} = require('./p2p');
6
10
  const {makeServiceRequest} = require('./client');
7
11
  const {manageTrades} = require('./trades');
8
12
  const {schema} = require('./services');
13
+ const {serviceAnchoredTrades} = require('./trades');
9
14
  const {servicePaidRequests} = require('./server');
10
15
  const {servicePeerRequests} = require('./p2p');
11
16
 
@@ -14,11 +19,16 @@ const serviceIds = schema.types;
14
19
  module.exports = {
15
20
  changeChannelCapacity,
16
21
  confirmServiceUse,
22
+ createAnchoredTrade,
23
+ decodeTrade,
24
+ encodeTrade,
25
+ getAnchoredTrade,
17
26
  getServiceSchema,
18
27
  getServicesList,
19
28
  makePeerRequest,
20
29
  makeServiceRequest,
21
30
  manageTrades,
31
+ serviceAnchoredTrades,
22
32
  serviceIds,
23
33
  servicePaidRequests,
24
34
  servicePeerRequests,
package/package.json CHANGED
@@ -12,8 +12,8 @@
12
12
  "bolt01": "1.2.3",
13
13
  "bolt07": "1.8.0",
14
14
  "invoices": "2.0.3",
15
- "ln-service": "53.4.0",
16
- "ln-sync": "3.6.1"
15
+ "ln-service": "53.5.0",
16
+ "ln-sync": "3.7.0"
17
17
  },
18
18
  "description": "Lightning Paid Services library",
19
19
  "devDependencies": {
@@ -37,8 +37,8 @@
37
37
  "url": "https://github.com/alexbosworth/paid-services.git"
38
38
  },
39
39
  "scripts": {
40
- "integration-tests": "tap --branches=1 --functions=1 --lines=1 --statements=1 -t 180 test/integration/*.js",
40
+ "integration-tests": "tap -j 2 --branches=1 --functions=1 --lines=1 --statements=1 -t 180 test/integration/*.js",
41
41
  "test": "tap --branches=1 --functions=1 --lines=1 --statements=1 -t 60 test/actions/*.js test/capacity/*.js test/client/*.js test/config/*.js test/p2p/*.js test/records/*.js test/respond/*.js test/server/*.js test/server/*.js test/services/*.js test/trades/*.js"
42
42
  },
43
- "version": "3.7.0"
43
+ "version": "3.10.0"
44
44
  }
@@ -0,0 +1,86 @@
1
+ const asyncAuto = require('async/auto');
2
+ const {createInvoice} = require('ln-service');
3
+ const {returnResult} = require('asyncjs-util');
4
+
5
+ const encodeAnchoredTrade = require('./encode_anchored_trade');
6
+
7
+ const maxDescriptionLength = 100;
8
+ const maxSecretLength = 100;
9
+
10
+ /** Create an anchored trade
11
+
12
+ {
13
+ description: <Trade Description String>
14
+ expires_at: <Trade Expires at ISO 8601 Date String>
15
+ lnd: <Authenticated LND API Object>
16
+ secret: <Trade Secret String>
17
+ tokens: <Trade Price Tokens Number>
18
+ }
19
+
20
+ @returns via cbk or Promise
21
+ {
22
+ id: <Anchored Trade Id Hex String>
23
+ }
24
+ */
25
+ module.exports = (args, cbk) => {
26
+ return new Promise((resolve, reject) => {
27
+ return asyncAuto({
28
+ // Check arguments
29
+ validate: cbk => {
30
+ if (args.description === undefined) {
31
+ return cbk([400, 'ExpectedTradeDescriptionToCreateAnchoredTrade']);
32
+ }
33
+
34
+ if (args.description.length > maxDescriptionLength) {
35
+ return cbk([400, 'ExpectedShorterTradeDescriptionToCreateTrade']);
36
+ }
37
+
38
+ if (!args.expires_at) {
39
+ return cbk([400, 'ExpectedTradeExpirationDateToCreateTrade']);
40
+ }
41
+
42
+ if (args.expires_at < new Date().toISOString()) {
43
+ return cbk([400, 'ExpectedLaterExpiresAtDateToCreateTrade']);
44
+ }
45
+
46
+ if (!args.lnd) {
47
+ return cbk([400, 'ExpectedAuthenticatedLndToCreateAnchoredTrade']);
48
+ }
49
+
50
+ if (!args.secret) {
51
+ return cbk([400, 'ExpectedTradeSecretToCreateAnchoredTrade']);
52
+ }
53
+
54
+ if (args.secret.length > maxSecretLength) {
55
+ return cbk([400, 'ExpectedShorterTradeSecretToCreateAnchoredTrade']);
56
+ }
57
+
58
+ if (!args.tokens) {
59
+ return cbk([400, 'ExpectedTokensPriceToCreateAnchoredTrade']);
60
+ }
61
+
62
+ return cbk();
63
+ },
64
+
65
+ // Create the trade
66
+ create: ['validate', ({}, cbk) => {
67
+ const {encoded} = encodeAnchoredTrade({
68
+ description: args.description,
69
+ secret: args.secret,
70
+ });
71
+
72
+ return createInvoice({
73
+ description: encoded,
74
+ expires_at: args.expires_at,
75
+ lnd: args.lnd,
76
+ tokens: args.tokens,
77
+ },
78
+ cbk);
79
+ }],
80
+
81
+ // Final trade
82
+ trade: ['create', ({create}, cbk) => cbk(null, {id: create.id})],
83
+ },
84
+ returnResult({reject, resolve, of: 'trade'}, cbk));
85
+ });
86
+ };
@@ -1,11 +1,10 @@
1
1
  const asyncAuto = require('async/auto');
2
- const {createInvoice} = require('ln-service');
3
2
  const {getChannels} = require('ln-service');
4
3
  const {getNetwork} = require('ln-sync');
5
4
  const {getWalletInfo} = require('ln-service');
6
5
  const {returnResult} = require('asyncjs-util');
7
6
 
8
- const encodeAnchoredTrade = require('./encode_anchored_trade');
7
+ const createAnchoredTrade = require('./create_anchored_trade');
9
8
  const finalizeTradeSecret = require('./finalize_trade_secret');
10
9
  const serviceOpenTrade = require('./service_open_trade');
11
10
 
@@ -204,15 +203,11 @@ module.exports = ({ask, lnd, logger}, cbk) => {
204
203
  return cbk();
205
204
  }
206
205
 
207
- const {encoded} = encodeAnchoredTrade({
208
- description: askForDescription.description,
209
- secret: askForSecret.secret,
210
- });
211
-
212
- return createInvoice({
206
+ return createAnchoredTrade({
213
207
  lnd,
214
- description: encoded,
208
+ description: askForDescription.description,
215
209
  expires_at: futureDate(daysAsMs(askForExpiration.days)),
210
+ secret: askForSecret.secret,
216
211
  tokens: asNumber(askForPrice.tokens),
217
212
  },
218
213
  cbk);
@@ -5,6 +5,7 @@ const asyncAuto = require('async/auto');
5
5
  const asyncDetect = require('async/detect');
6
6
  const asyncDetectSeries = require('async/detectSeries');
7
7
  const asyncMap = require('async/map');
8
+ const asyncReflect = require('async/reflect');
8
9
  const {getChannel} = require('ln-service');
9
10
  const {getNode} = require('ln-service');
10
11
  const {getPeers} = require('ln-service');
@@ -206,19 +207,19 @@ module.exports = ({ask, id, identity, lnd, logger, nodes}, cbk) => {
206
207
  }],
207
208
 
208
209
  // Request a specific trade
209
- requestTrade: ['to', ({to}, cbk) => {
210
+ requestTrade: ['to', asyncReflect(({to}, cbk) => {
210
211
  // Exit early when this is an open ended trade request with no id
211
212
  if (!id) {
212
213
  return cbk();
213
214
  }
214
215
 
215
216
  return requestTradeById({id, lnd, to}, cbk);
216
- }],
217
+ })],
217
218
 
218
219
  // Request an inventory of trades
219
- requestTrades: ['to', ({to}, cbk) => {
220
- // Exit early when this is a trade request for a specific id
221
- if (!!id) {
220
+ requestTrades: ['requestTrade', 'to', ({requestTrade, to}, cbk) => {
221
+ // Exit early when there was a successful request for a specific id
222
+ if (!!requestTrade.value) {
222
223
  return cbk();
223
224
  }
224
225
 
@@ -285,7 +286,7 @@ module.exports = ({ask, id, identity, lnd, logger, nodes}, cbk) => {
285
286
  ({requestTrade, requestTrades}, cbk) =>
286
287
  {
287
288
  // Exit early when the trade was already selected
288
- if (!!requestTrade) {
289
+ if (!!requestTrade.value) {
289
290
  return cbk();
290
291
  }
291
292
 
@@ -331,7 +332,7 @@ module.exports = ({ask, id, identity, lnd, logger, nodes}, cbk) => {
331
332
  'requestTrade',
332
333
  ({fetchSelectedTrade, requestTrade}, cbk) =>
333
334
  {
334
- return cbk(null, fetchSelectedTrade || requestTrade);
335
+ return cbk(null, fetchSelectedTrade || requestTrade.value);
335
336
  }],
336
337
  },
337
338
  returnResult({reject, resolve, of: 'trade'}, cbk));
@@ -0,0 +1,72 @@
1
+ const asyncAuto = require('async/auto');
2
+ const asyncReflect = require('async/reflect');
3
+ const {getInvoice} = require('ln-service');
4
+ const {returnResult} = require('asyncjs-util');
5
+
6
+ const decodeAnchoredTrade = require('./decode_anchored_trade');
7
+
8
+ /** Get anchored trade
9
+
10
+ {
11
+ id: <Trade Id Hex String>
12
+ lnd: <Authenticated LND API Object>
13
+ }
14
+
15
+ @returns via cbk or Promise
16
+ {
17
+ [trade]: {
18
+ description: <Trade Description String>
19
+ expires_at: <Trade Expires at ISO 8601 Date String>
20
+ secret: <Trade Secret String>
21
+ tokens: <Trade Price Tokens Number>
22
+ }
23
+ }
24
+ */
25
+ module.exports = ({id, lnd}, cbk) => {
26
+ return new Promise((resolve, reject) => {
27
+ return asyncAuto({
28
+ // Check arguments
29
+ validate: cbk => {
30
+ if (!id) {
31
+ return cbk([400, 'ExpectedIdToGetAnchoredTrade']);
32
+ }
33
+
34
+ if (!lnd) {
35
+ return cbk([400, 'ExpectedLndToGetAnchoredTrade']);
36
+ }
37
+
38
+ return cbk();
39
+ },
40
+
41
+ // Get invoice
42
+ getInvoice: ['validate', asyncReflect(({}, cbk) => {
43
+ return getInvoice({id, lnd}, cbk);
44
+ })],
45
+
46
+ // Decode trade details
47
+ decode: ['getInvoice', ({getInvoice}, cbk) => {
48
+ if (!getInvoice.value) {
49
+ return cbk(null, {});
50
+ }
51
+
52
+ const encoded = getInvoice.value.description;
53
+
54
+ const {trade} = decodeAnchoredTrade({encoded});
55
+
56
+ if (!trade) {
57
+ return cbk([400, 'ExpectedAnchoredTradeData']);
58
+ }
59
+
60
+ return cbk(null, {
61
+ trade: {
62
+ description: trade.description,
63
+ expires_at: getInvoice.value.expires_at,
64
+ secret: trade.secret,
65
+ tokens: getInvoice.value.tokens,
66
+ },
67
+ });
68
+ }],
69
+ },
70
+ returnResult({reject, resolve, of: 'decode'}, cbk));
71
+ });
72
+ };
package/trades/index.js CHANGED
@@ -1,3 +1,15 @@
1
+ const createAnchoredTrade = require('./create_anchored_trade');
2
+ const decodeTrade = require('./decode_trade');
3
+ const encodeTrade = require('./encode_trade');
4
+ const getAnchoredTrade = require('./get_anchored_trade');
1
5
  const manageTrades = require('./manage_trades');
6
+ const serviceAnchoredTrades = require('./service_anchored_trades');
2
7
 
3
- module.exports = {manageTrades};
8
+ module.exports = {
9
+ createAnchoredTrade,
10
+ decodeTrade,
11
+ encodeTrade,
12
+ getAnchoredTrade,
13
+ manageTrades,
14
+ serviceAnchoredTrades,
15
+ };
@@ -13,6 +13,7 @@ const defaultInvoicesLimit = 100;
13
13
  const events = ['details', 'error', 'failure', 'settled', 'trade'];
14
14
  const fromNow = date => new Date(date) - new Date();
15
15
  const {keys} = Object;
16
+ const sumOf = arr => arr.reduce((sum, n) => sum + n, 0);
16
17
 
17
18
  /** Service trades represented by anchored invoices
18
19
 
@@ -47,6 +48,7 @@ const {keys} = Object;
47
48
  // Starting service for trade
48
49
  @event 'start'
49
50
  {
51
+ created_at: <Open Trade Created At ISO 8601 Date String>
50
52
  description: <Trade Description String>
51
53
  expires_at: <Trade Expires at ISO 8601 Date String>
52
54
  id: <Trade Id Hex String>
@@ -86,6 +88,7 @@ module.exports = ({lnd}) => {
86
88
 
87
89
  // Pick up the trade to service
88
90
  emitter.emit('start', {
91
+ created_at: trade.created_at,
89
92
  description: trade.description,
90
93
  expires_at: trade.expires_at,
91
94
  id: trade.id,
@@ -129,6 +132,28 @@ module.exports = ({lnd}) => {
129
132
  // Listen for any new invoices that represent anchored trades
130
133
  const sub = subscribeToInvoices({lnd});
131
134
 
135
+ // Stop servicing all trades
136
+ const stopService = () => {
137
+ // Stop paging in progress
138
+ paging.token = false;
139
+
140
+ // Stop listening to all invoices
141
+ sub.removeAllListeners();
142
+
143
+ // Stop listening to all anchor invoices
144
+ return keys(listening).forEach(id => listening[id].removeAllListeners());
145
+ };
146
+
147
+ // Stop the service when there are no more listeners
148
+ emitter.on('removeListener', () => {
149
+ // Exit early when there are still listeners on an event
150
+ if (!!sumOf(events.map(n => emitter.listenerCount(n)))) {
151
+ return;
152
+ }
153
+
154
+ return stopService();
155
+ });
156
+
132
157
  // Listen for new trades to appear
133
158
  sub.on('invoice_updated', invoice => {
134
159
  const {trade} = tradeFromInvoice(invoice);
@@ -155,13 +180,13 @@ module.exports = ({lnd}) => {
155
180
  if (!!err) {
156
181
  emitter.emit(err);
157
182
 
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());
183
+ // Stop the service
184
+ return stopService();
185
+ }
163
186
 
164
- return;
187
+ // Exit early when paging is already stopped
188
+ if (paging.token === false) {
189
+ return cbk();
165
190
  }
166
191
 
167
192
  paging.token = res.next || false;
@@ -3,6 +3,7 @@ const decodeAnchoredTrade = require('./decode_anchored_trade');
3
3
  /** Derive open trade details from an invoice
4
4
 
5
5
  {
6
+ created_at: <Invoice Created At ISO 8601 Date String>
6
7
  description: <Invoice Description String>
7
8
  id: <Invoice Id Hex String>
8
9
  expires_at: <Invoice Expiration ISO 8601 Date String>
@@ -15,6 +16,7 @@ const decodeAnchoredTrade = require('./decode_anchored_trade');
15
16
  @returns
16
17
  {
17
18
  [trade]: {
19
+ created_at: <Open Trade Created At ISO 8601 Date String>
18
20
  description: <Trade Description String>
19
21
  expires_at: <Trade Expires at ISO 8601 Date String>
20
22
  id: <Trade Id Hex String>
@@ -41,6 +43,7 @@ module.exports = args => {
41
43
 
42
44
  return {
43
45
  trade: {
46
+ created_at: args.created_at,
44
47
  description: trade.description,
45
48
  expires_at: args.expires_at,
46
49
  id: args.id,