paid-services 3.3.0 → 3.4.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 (35) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/capacity/accept_capacity_change.js +3 -3
  3. package/capacity/get_capacity_change_requests.js +1 -1
  4. package/capacity/get_capacity_replacement.js +1 -1
  5. package/capacity/initiate_capacity_change.js +5 -4
  6. package/capacity/propose_capacity_change.js +3 -1
  7. package/p2p/service_peer_requests.js +10 -2
  8. package/package.json +3 -2
  9. package/service_types.json +16 -0
  10. package/test/integration/test_accept_capacity_change.js +50 -13
  11. package/test/integration/test_change_channel_capacity.js +3 -0
  12. package/test/trades/test_decode_basic_trade.js +40 -0
  13. package/test/trades/test_decode_open_trade.js +50 -0
  14. package/test/trades/test_encode_open_trade.js +35 -0
  15. package/test/trades/test_encode_trade.js +37 -0
  16. package/trades/accept_trade.js +52 -0
  17. package/trades/create_trade.js +124 -44
  18. package/trades/decode_basic_trade.js +45 -0
  19. package/trades/decode_open_trade.js +69 -0
  20. package/trades/decode_trade.js +48 -66
  21. package/trades/decode_trade_secret.js +89 -0
  22. package/trades/encode_open_trade.js +89 -0
  23. package/trades/encode_trade.js +48 -33
  24. package/trades/encode_trade_secret.js +50 -0
  25. package/trades/finalize_trade_secret.js +116 -0
  26. package/trades/find_trade.js +314 -0
  27. package/trades/manage_trade.js +46 -35
  28. package/trades/network_from_network_record.js +3 -3
  29. package/trades/network_record_from_network.js +36 -0
  30. package/trades/network_record_from_request.js +2 -1
  31. package/trades/node_as_record.js +98 -0
  32. package/trades/record_as_node.js +113 -0
  33. package/trades/request_trade_by_id.js +89 -0
  34. package/trades/service_trade_requests.js +184 -0
  35. package/capacity/service_types.json +0 -6
@@ -0,0 +1,184 @@
1
+ const EventEmitter = require('events');
2
+ const {randomBytes} = require('crypto');
3
+
4
+ const {subscribeToInvoice} = require('ln-service');
5
+
6
+ const acceptTrade = require('./accept_trade');
7
+ const finalizeTradeSecret = require('./finalize_trade_secret');
8
+ const {makePeerRequest} = require('./../p2p');
9
+ const {servicePeerRequests} = require('./../p2p');
10
+ const {serviceTypeRequestTrades} = require('./../service_types');
11
+ const {serviceTypeReceiveTrades} = require('./../service_types');
12
+
13
+ const descRecord = description => ({type: '2', value: description});
14
+ const findIdRecord = records => records.find(n => n.type === '0');
15
+ const findRequestIdRecord = records => records.find(n => n.type === '1');
16
+ const idBackType = '0';
17
+ const idRecord = id => ({type: '1', value: id});
18
+ const makeEphemeralTradeId = () => randomBytes(32).toString('hex');
19
+ const postOpenTradeTimeoutMs = 1000 * 30;
20
+ const tradeSecretType = '1';
21
+ const utf8AsHex = utf8 => Buffer.from(utf8).toString('hex');
22
+
23
+ /** Service requests for an open trade
24
+
25
+ {
26
+ description: <Trade Description String>
27
+ lnd: <Authenticated LND API Object>
28
+ secret: <Secret Payload String>
29
+ tokens: <Tokens Number>
30
+ }
31
+
32
+ // Service ended
33
+ @event 'end'
34
+
35
+ // Encountered a failure
36
+ @event 'failure'
37
+ [<Failure Code Number>, <Failure Code String>]
38
+
39
+ // Return details
40
+ @event 'details'
41
+ {
42
+ to: <Public Key Id Hex String>
43
+ }
44
+
45
+ // Received payment
46
+ @event 'settled'
47
+ {
48
+ to: <Public Key Id Hex String>
49
+ }
50
+
51
+ // Return finalized trade
52
+ @event 'trade'
53
+ {
54
+ to: <Public Key Id Hex String>
55
+ }
56
+
57
+ @returns
58
+ <Service Event Emitter Object>
59
+ */
60
+ module.exports = ({description, lnd, secret, tokens}) => {
61
+ const emitter = new EventEmitter();
62
+
63
+ const holds = [];
64
+ const id = makeEphemeralTradeId();
65
+ const service = servicePeerRequests({lnd});
66
+
67
+ // Notify when the service ends
68
+ service.end(() => emitter.emit('end', {}));
69
+
70
+ // Basic trade description
71
+ const basicTradeRecords = [idRecord(id), descRecord(utf8AsHex(description))];
72
+
73
+ // Wait for a request for the open trade
74
+ service.request({type: serviceTypeRequestTrades}, (req, res) => {
75
+ const {failure, success} = res;
76
+ const requestTradeId = findIdRecord(req.records);
77
+
78
+ // Exit early when the trade requested is unrelated
79
+ if (!!requestTradeId && requestTradeId.value !== id) {
80
+ return;
81
+ }
82
+
83
+ const requestIdRecord = findRequestIdRecord(req.records);
84
+
85
+ // A trade request either is for a specific trade or has a pingback id
86
+ if (!requestTradeId && !requestIdRecord) {
87
+ return emitter.emit('failure', [400, 'ExpectedRequestTradeOrRequestId']);
88
+ }
89
+
90
+ // Exit early and ping peer with trade when this is an open ended query
91
+ if (!requestTradeId) {
92
+ emitter.emit('details', {to: req.from});
93
+
94
+ const reqIdRecord = {type: idBackType, value: requestIdRecord.value};
95
+
96
+ const records = [].concat(basicTradeRecords).concat(reqIdRecord);
97
+
98
+ // Ping the node with trade details
99
+ return makePeerRequest({
100
+ lnd,
101
+ records,
102
+ timeout: postOpenTradeTimeoutMs,
103
+ to: req.from,
104
+ type: serviceTypeReceiveTrades,
105
+ },
106
+ err => {
107
+ if (!!err) {
108
+ failure([503, 'FailedToDeliverTradeInfo']);
109
+
110
+ return emitter.emit(
111
+ 'failure',
112
+ [503, 'FailedToDeliverTradeInfo', {err}]
113
+ );
114
+ }
115
+
116
+ return success({});
117
+ });
118
+ }
119
+
120
+ // Make a finalized trade secret for the peer
121
+ emitter.emit('trade', ({to: req.from}));
122
+
123
+ // Create a trade secret for the requesting peer and return that
124
+ return finalizeTradeSecret({
125
+ description,
126
+ lnd,
127
+ secret,
128
+ tokens,
129
+ is_hold: true,
130
+ to: req.from,
131
+ },
132
+ (err, res) => {
133
+ if (!!err) {
134
+ emitter.emit('failure', err);
135
+
136
+ return failure([503, 'FailedToFinalizeTradeSecret']);
137
+ }
138
+
139
+ // Create a record for the encoded trade
140
+ const record = {type: tradeSecretType, value: res.trade};
141
+
142
+ // Add hold invoice to set of held invoices, only one should settle
143
+ const sub = subscribeToInvoice({lnd, id: res.id});
144
+
145
+ // Add sub to list of holds
146
+ holds.push({sub, id: res.id});
147
+
148
+ // Wait for the invoice to be paid
149
+ sub.on('invoice_updated', updated => {
150
+ // Exit early when the payment is not held yet
151
+ if (!updated.is_held) {
152
+ return;
153
+ }
154
+
155
+ // Do not accept any more bids
156
+ service.stop({});
157
+
158
+ // Stop listening to invoice events
159
+ holds.forEach(hold => hold.sub.removeAllListeners());
160
+
161
+ // Settle the held invoice with the preimage
162
+ return acceptTrade({
163
+ lnd,
164
+ cancel: holds.filter(n => n.id !== updated.id).map(n => n.id),
165
+ secret: res.secret,
166
+ },
167
+ err => {
168
+ if (!!err) {
169
+ return emitter.emit('failure', err);
170
+ }
171
+
172
+ emitter.emit('settled', {to: req.from});
173
+
174
+ return emitter.emit('end', {});
175
+ });
176
+ });
177
+
178
+ // Return details about the trade
179
+ return success({records: [record]});
180
+ });
181
+ });
182
+
183
+ return emitter;
184
+ };
@@ -1,6 +0,0 @@
1
- {
2
- "serviceTypeAcceptCapacityChange": "8050002",
3
- "serviceTypeChangeCapacity": "8050001",
4
- "serviceTypeSignCapacityChange": "805004",
5
- "serviceTypeWaitOnConfirmation": "8050003"
6
- }