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.
- package/CHANGELOG.md +5 -0
- package/capacity/accept_capacity_change.js +3 -3
- package/capacity/get_capacity_change_requests.js +1 -1
- package/capacity/get_capacity_replacement.js +1 -1
- package/capacity/initiate_capacity_change.js +5 -4
- package/capacity/propose_capacity_change.js +3 -1
- package/p2p/service_peer_requests.js +10 -2
- package/package.json +3 -2
- package/service_types.json +16 -0
- package/test/integration/test_accept_capacity_change.js +50 -13
- package/test/integration/test_change_channel_capacity.js +3 -0
- package/test/trades/test_decode_basic_trade.js +40 -0
- package/test/trades/test_decode_open_trade.js +50 -0
- package/test/trades/test_encode_open_trade.js +35 -0
- package/test/trades/test_encode_trade.js +37 -0
- package/trades/accept_trade.js +52 -0
- package/trades/create_trade.js +124 -44
- package/trades/decode_basic_trade.js +45 -0
- package/trades/decode_open_trade.js +69 -0
- package/trades/decode_trade.js +48 -66
- package/trades/decode_trade_secret.js +89 -0
- package/trades/encode_open_trade.js +89 -0
- package/trades/encode_trade.js +48 -33
- package/trades/encode_trade_secret.js +50 -0
- package/trades/finalize_trade_secret.js +116 -0
- package/trades/find_trade.js +314 -0
- package/trades/manage_trade.js +46 -35
- package/trades/network_from_network_record.js +3 -3
- package/trades/network_record_from_network.js +36 -0
- package/trades/network_record_from_request.js +2 -1
- package/trades/node_as_record.js +98 -0
- package/trades/record_as_node.js +113 -0
- package/trades/request_trade_by_id.js +89 -0
- package/trades/service_trade_requests.js +184 -0
- 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
|
+
};
|