capitalisk-dex 18.3.2 → 18.3.4

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/trade-engine.js CHANGED
@@ -1,416 +1,416 @@
1
- const BigOrderBook = require('big-order-book');
2
- const crypto = require('crypto');
3
- const { mapListFields } = require('./utils');
4
-
5
- const EMPTY_ORDER_BOOK_HASH = '0000000000000000000000000000000000000000';
6
- const emptyGenerator = function * () {};
7
-
8
- class TradeEngine {
9
- constructor(options) {
10
- this.baseCurrency = options.baseCurrency;
11
- this.quoteCurrency = options.quoteCurrency;
12
- this.baseOrderHeightExpiry = options.baseOrderHeightExpiry;
13
- this.quoteOrderHeightExpiry = options.quoteOrderHeightExpiry;
14
- this.baseMinPartialTake = options.baseMinPartialTake;
15
- this.quoteMinPartialTake = options.quoteMinPartialTake;
16
- this.market = `${this.quoteCurrency}/${this.baseCurrency}`;
17
- this.orderBook = new BigOrderBook({
18
- minPartialTakeValue: this.baseMinPartialTake,
19
- minPartialTakeSize: this.quoteMinPartialTake,
20
- priceDecimalPrecision: options.priceDecimalPrecision
21
- });
22
-
23
- this._askMap = new Map();
24
- this._bidMap = new Map();
25
- this._orderMap = new Map();
26
- this._sourceWalletOrderMap = new Map();
27
-
28
- this.orderBookHash = EMPTY_ORDER_BOOK_HASH;
29
-
30
- this._resetProcessedHeightsInfo();
31
- }
32
-
33
- _sha1(string) {
34
- return crypto.createHash('sha1').update(string).digest('hex');
35
- }
36
-
37
- _resetProcessedHeightsInfo() {
38
- this.lastProcessedHeightsInfo = {
39
- [this.baseCurrency]: {
40
- height: 0,
41
- orderIds: new Set()
42
- },
43
- [this.quoteCurrency]: {
44
- height: 0,
45
- orderIds: new Set()
46
- }
47
- };
48
- }
49
-
50
- _orderComparator(a, b) {
51
- if (a.expiryHeight > b.expiryHeight) {
52
- return 1;
53
- }
54
- if (a.expiryHeight < b.expiryHeight) {
55
- return -1;
56
- }
57
- if (a.id > b.id) {
58
- return 1;
59
- }
60
- if (a.id < b.id) {
61
- return -1;
62
- }
63
- return 0;
64
- }
65
-
66
- expireBidOrders(heightThreshold) {
67
- let expiredOrders = [];
68
- for (let [orderId, order] of this._bidMap) {
69
- if (order.expiryHeight > heightThreshold) {
70
- break;
71
- }
72
- expiredOrders.push(order);
73
- this._removeFromOrderBook(orderId);
74
- this._bidMap.delete(orderId);
75
- this._orderMap.delete(orderId);
76
- this._removeFromWalletOrderMap(order.sourceWalletAddress, orderId);
77
- }
78
- return expiredOrders.sort((a, b) => this._orderComparator(a, b));
79
- }
80
-
81
- expireAskOrders(heightThreshold) {
82
- let expiredOrders = [];
83
- for (let [orderId, order] of this._askMap) {
84
- if (order.expiryHeight > heightThreshold) {
85
- break;
86
- }
87
- expiredOrders.push(order);
88
- this._removeFromOrderBook(orderId);
89
- this._askMap.delete(orderId);
90
- this._orderMap.delete(orderId);
91
- this._removeFromWalletOrderMap(order.sourceWalletAddress, orderId);
92
- }
93
- return expiredOrders.sort((a, b) => this._orderComparator(a, b));
94
- }
95
-
96
- wasOrderProcessed(orderId, orderSourceChain, orderHeight) {
97
- let lastChainProcessedHeightInfo = this.lastProcessedHeightsInfo[orderSourceChain];
98
- let topChainHeight = lastChainProcessedHeightInfo.height;
99
-
100
- return orderHeight < topChainHeight || lastChainProcessedHeightInfo.orderIds.has(orderId);
101
- }
102
-
103
- trackProcessedOrder(order) {
104
- let lastChainProcessedHeightInfo = this.lastProcessedHeightsInfo[order.sourceChain];
105
- let topChainHeight = lastChainProcessedHeightInfo.height;
106
- if (order.height > topChainHeight) {
107
- lastChainProcessedHeightInfo.height = order.height;
108
- lastChainProcessedHeightInfo.orderIds = new Set([order.id]);
109
- } else if (order.height < topChainHeight) {
110
- let error = new Error(
111
- `Could not process order with ID ${
112
- order.id
113
- } because it was below the last processed height of ${
114
- topChainHeight
115
- } for the chain ${order.sourceChain}`
116
- );
117
- error.name = 'HeightAlreadyProcessedError';
118
- throw error;
119
- } else {
120
- if (lastChainProcessedHeightInfo.orderIds.has(order.id)) {
121
- let error = new Error(
122
- `Could not process order with ID ${
123
- order.id
124
- } because it was already processed`
125
- );
126
- error.name = 'OrderAlreadyProcessedError';
127
- throw error;
128
- }
129
- lastChainProcessedHeightInfo.orderIds.add(order.id);
130
- }
131
- }
132
-
133
- addOrder(order) {
134
- this.trackProcessedOrder(order);
135
-
136
- let existingOrder = this.orderBook.has(order.id);
137
-
138
- if (existingOrder) {
139
- let error = new Error(`An order with ID ${order.id} already exists`);
140
- error.name = 'DuplicateOrderError';
141
- throw error;
142
- }
143
-
144
- let orderHeightExpiry;
145
- if (order.sourceChain === this.quoteCurrency) {
146
- orderHeightExpiry = this.quoteOrderHeightExpiry;
147
- } else {
148
- orderHeightExpiry = this.baseOrderHeightExpiry;
149
- }
150
-
151
- let newOrder = {};
152
- newOrder.id = order.id;
153
- newOrder.side = order.side;
154
- if (order.size != null) {
155
- newOrder.size = order.size;
156
- }
157
- if (order.value != null) {
158
- newOrder.value = order.value;
159
- }
160
- if (order.price != null) {
161
- newOrder.price = order.price;
162
- }
163
- newOrder.type = order.type;
164
- newOrder.targetChain = order.targetChain;
165
- newOrder.targetWalletAddress = order.targetWalletAddress;
166
- newOrder.senderAddress = order.senderAddress;
167
- newOrder.sourceChain = order.sourceChain;
168
- newOrder.sourceChainAmount = order.sourceChainAmount;
169
- newOrder.sourceWalletAddress = order.sourceWalletAddress;
170
- newOrder.height = order.height;
171
- newOrder.expiryHeight = order.height + orderHeightExpiry;
172
- newOrder.timestamp = order.timestamp;
173
-
174
- let result = this._addToOrderBook(newOrder);
175
-
176
- result.makers.forEach((makerOrder) => {
177
- if (makerOrder.side === 'ask') {
178
- if (makerOrder.sizeRemaining <= 0n) {
179
- this._askMap.delete(makerOrder.id);
180
- this._orderMap.delete(makerOrder.id);
181
- this._removeFromWalletOrderMap(makerOrder.sourceWalletAddress, makerOrder.id);
182
- }
183
- } else {
184
- if (makerOrder.valueRemaining <= 0n) {
185
- this._bidMap.delete(makerOrder.id);
186
- this._orderMap.delete(makerOrder.id);
187
- this._removeFromWalletOrderMap(makerOrder.sourceWalletAddress, makerOrder.id);
188
- }
189
- }
190
- });
191
-
192
- if (newOrder.type !== 'market') {
193
- if (newOrder.side === 'ask') {
194
- if (result.taker.sizeRemaining > 0n) {
195
- this._askMap.set(newOrder.id, newOrder);
196
- this._orderMap.set(newOrder.id, newOrder);
197
- this._addToWalletOrderMap(newOrder);
198
- }
199
- } else if (result.taker.valueRemaining > 0n) {
200
- this._bidMap.set(newOrder.id, newOrder);
201
- this._orderMap.set(newOrder.id, newOrder);
202
- this._addToWalletOrderMap(newOrder);
203
- }
204
- }
205
-
206
- return result;
207
- }
208
-
209
- _addToWalletOrderMap(order) {
210
- if (!this._sourceWalletOrderMap.has(order.sourceWalletAddress)) {
211
- this._sourceWalletOrderMap.set(order.sourceWalletAddress, new Map());
212
- }
213
- let orderMap = this._sourceWalletOrderMap.get(order.sourceWalletAddress);
214
- orderMap.set(order.id, order);
215
- }
216
-
217
- _removeFromWalletOrderMap(sourceWalletAddress, orderId) {
218
- let orderMap = this._sourceWalletOrderMap.get(sourceWalletAddress);
219
- if (orderMap) {
220
- let result = orderMap.delete(orderId);
221
- if (!orderMap.size) {
222
- this._sourceWalletOrderMap.delete(sourceWalletAddress);
223
- }
224
- return result;
225
- }
226
- return false;
227
- }
228
-
229
- getSourceWalletOrderIterator(sourceWalletAddress) {
230
- let orderMap = this._sourceWalletOrderMap.get(sourceWalletAddress);
231
- return orderMap ? orderMap.values() : emptyGenerator();
232
- }
233
-
234
- *getSourceWalletBidIterator(sourceWalletAddress) {
235
- let orderIterator = this.getSourceWalletOrderIterator(sourceWalletAddress);
236
- for (let order of orderIterator) {
237
- if (order.side === 'bid') {
238
- yield order;
239
- }
240
- }
241
- }
242
-
243
- *getSourceWalletAskIterator(sourceWalletAddress) {
244
- let orderIterator = this.getSourceWalletOrderIterator(sourceWalletAddress);
245
- for (let order of orderIterator) {
246
- if (order.side === 'ask') {
247
- yield order;
248
- }
249
- }
250
- }
251
-
252
- getOrder(orderId) {
253
- return this._orderMap.get(orderId);
254
- }
255
-
256
- addCloseOrder(order) {
257
- this.trackProcessedOrder(order);
258
-
259
- let targetOrderId = order.orderIdToClose;
260
- let targetOrder = this.getOrder(targetOrderId);
261
- if (!targetOrder) {
262
- throw new Error(
263
- `An order with ID ${targetOrderId} could not be found`
264
- );
265
- }
266
-
267
- let result = this._removeFromOrderBook(targetOrderId);
268
- if (targetOrder.side === 'ask') {
269
- this._askMap.delete(targetOrderId);
270
- } else {
271
- this._bidMap.delete(targetOrderId);
272
- }
273
- this._orderMap.delete(targetOrderId);
274
- this._removeFromWalletOrderMap(targetOrder.sourceWalletAddress, targetOrderId);
275
- return result;
276
- }
277
-
278
- peekBids() {
279
- return this.orderBook.getMaxBid();
280
- }
281
-
282
- peekAsks() {
283
- return this.orderBook.getMinAsk();
284
- }
285
-
286
- getBidIteratorFromMin() {
287
- return this.orderBook.getBidIteratorFromMin();
288
- }
289
-
290
- getBidIteratorFromMax() {
291
- return this.orderBook.getBidIteratorFromMax();
292
- }
293
-
294
- getAskIteratorFromMin() {
295
- return this.orderBook.getAskIteratorFromMin();
296
- }
297
-
298
- getAskIteratorFromMax() {
299
- return this.orderBook.getAskIteratorFromMax();
300
- }
301
-
302
- getBidLevelIteratorFromMin() {
303
- return this.orderBook.getBidLevelIteratorFromMin();
304
- }
305
-
306
- getBidLevelIteratorFromMax() {
307
- return this.orderBook.getBidLevelIteratorFromMax();
308
- }
309
-
310
- getAskLevelIteratorFromMin() {
311
- return this.orderBook.getAskLevelIteratorFromMin();
312
- }
313
-
314
- getAskLevelIteratorFromMax() {
315
- return this.orderBook.getAskLevelIteratorFromMax();
316
- }
317
-
318
- getOrderIterator() {
319
- return this._orderMap.values();
320
- }
321
-
322
- getBids() {
323
- return [...this.getBidIteratorFromMax()];
324
- }
325
-
326
- getAsks() {
327
- return [...this.getAskIteratorFromMin()];
328
- }
329
-
330
- getOrders() {
331
- return [...this.getOrderIterator()];
332
- }
333
-
334
- getSnapshot() {
335
- let askLimitOrders = mapListFields(this.getAsks(), {
336
- size: String,
337
- sizeRemaining: String,
338
- lastSizeTaken: String,
339
- lastValueTaken: String,
340
- sourceChainAmount: String
341
- });
342
- let bidLimitOrders = mapListFields(this.getBids(), {
343
- value: String,
344
- valueRemaining: String,
345
- lastSizeTaken: String,
346
- lastValueTaken: String,
347
- sourceChainAmount: String
348
- });
349
- return {
350
- orderBookHash: this.orderBookHash,
351
- askLimitOrders,
352
- bidLimitOrders
353
- };
354
- }
355
-
356
- _addToOrderBook(order) {
357
- this.orderBookHash = this._sha1(`${this.orderBookHash}+${order.id}`);
358
- return this.orderBook.add(order);
359
- }
360
-
361
- _removeFromOrderBook(orderId) {
362
- this.orderBookHash = this._sha1(`${this.orderBookHash}-${orderId}`);
363
- return this.orderBook.remove(orderId);
364
- }
365
-
366
- setSnapshot(snapshot) {
367
- this.clear();
368
- snapshot.askLimitOrders.sort((a, b) => {
369
- if (a.expiryHeight > b.expiryHeight) {
370
- return 1;
371
- }
372
- if (a.expiryHeight < b.expiryHeight) {
373
- return -1;
374
- }
375
- return 0;
376
- });
377
- snapshot.bidLimitOrders.sort((a, b) => {
378
- if (a.expiryHeight > b.expiryHeight) {
379
- return 1;
380
- }
381
- if (a.expiryHeight < b.expiryHeight) {
382
- return -1;
383
- }
384
- return 0;
385
- });
386
- snapshot.askLimitOrders.forEach((order) => {
387
- let newOrder = {...order};
388
- this._addToOrderBook(newOrder);
389
- this._askMap.set(newOrder.id, newOrder);
390
- this._orderMap.set(newOrder.id, newOrder);
391
- this._addToWalletOrderMap(newOrder);
392
- });
393
- snapshot.bidLimitOrders.forEach((order) => {
394
- let newOrder = {...order};
395
- this._addToOrderBook(newOrder);
396
- this._bidMap.set(newOrder.id, newOrder);
397
- this._orderMap.set(newOrder.id, newOrder);
398
- this._addToWalletOrderMap(newOrder);
399
- });
400
- if (snapshot.orderBookHash) {
401
- this.orderBookHash = snapshot.orderBookHash
402
- }
403
- }
404
-
405
- clear() {
406
- this.orderBookHash = EMPTY_ORDER_BOOK_HASH;
407
- this._resetProcessedHeightsInfo();
408
- this._askMap.clear();
409
- this._bidMap.clear();
410
- this._orderMap.clear();
411
- this._sourceWalletOrderMap.clear();
412
- this.orderBook.clear();
413
- }
414
- }
415
-
416
- module.exports = TradeEngine;
1
+ const BigOrderBook = require('big-order-book');
2
+ const crypto = require('crypto');
3
+ const { mapListFields } = require('./utils');
4
+
5
+ const EMPTY_ORDER_BOOK_HASH = '0000000000000000000000000000000000000000';
6
+ const emptyGenerator = function * () {};
7
+
8
+ class TradeEngine {
9
+ constructor(options) {
10
+ this.baseCurrency = options.baseCurrency;
11
+ this.quoteCurrency = options.quoteCurrency;
12
+ this.baseOrderHeightExpiry = options.baseOrderHeightExpiry;
13
+ this.quoteOrderHeightExpiry = options.quoteOrderHeightExpiry;
14
+ this.baseMinPartialTake = options.baseMinPartialTake;
15
+ this.quoteMinPartialTake = options.quoteMinPartialTake;
16
+ this.market = `${this.quoteCurrency}/${this.baseCurrency}`;
17
+ this.orderBook = new BigOrderBook({
18
+ minPartialTakeValue: this.baseMinPartialTake,
19
+ minPartialTakeSize: this.quoteMinPartialTake,
20
+ priceDecimalPrecision: options.priceDecimalPrecision
21
+ });
22
+
23
+ this._askMap = new Map();
24
+ this._bidMap = new Map();
25
+ this._orderMap = new Map();
26
+ this._sourceWalletOrderMap = new Map();
27
+
28
+ this.orderBookHash = EMPTY_ORDER_BOOK_HASH;
29
+
30
+ this._resetProcessedHeightsInfo();
31
+ }
32
+
33
+ _sha1(string) {
34
+ return crypto.createHash('sha1').update(string).digest('hex');
35
+ }
36
+
37
+ _resetProcessedHeightsInfo() {
38
+ this.lastProcessedHeightsInfo = {
39
+ [this.baseCurrency]: {
40
+ height: 0,
41
+ orderIds: new Set()
42
+ },
43
+ [this.quoteCurrency]: {
44
+ height: 0,
45
+ orderIds: new Set()
46
+ }
47
+ };
48
+ }
49
+
50
+ _orderComparator(a, b) {
51
+ if (a.expiryHeight > b.expiryHeight) {
52
+ return 1;
53
+ }
54
+ if (a.expiryHeight < b.expiryHeight) {
55
+ return -1;
56
+ }
57
+ if (a.id > b.id) {
58
+ return 1;
59
+ }
60
+ if (a.id < b.id) {
61
+ return -1;
62
+ }
63
+ return 0;
64
+ }
65
+
66
+ expireBidOrders(heightThreshold) {
67
+ let expiredOrders = [];
68
+ for (let [orderId, order] of this._bidMap) {
69
+ if (order.expiryHeight > heightThreshold) {
70
+ break;
71
+ }
72
+ expiredOrders.push(order);
73
+ this._removeFromOrderBook(orderId);
74
+ this._bidMap.delete(orderId);
75
+ this._orderMap.delete(orderId);
76
+ this._removeFromWalletOrderMap(order.sourceWalletAddress, orderId);
77
+ }
78
+ return expiredOrders.sort((a, b) => this._orderComparator(a, b));
79
+ }
80
+
81
+ expireAskOrders(heightThreshold) {
82
+ let expiredOrders = [];
83
+ for (let [orderId, order] of this._askMap) {
84
+ if (order.expiryHeight > heightThreshold) {
85
+ break;
86
+ }
87
+ expiredOrders.push(order);
88
+ this._removeFromOrderBook(orderId);
89
+ this._askMap.delete(orderId);
90
+ this._orderMap.delete(orderId);
91
+ this._removeFromWalletOrderMap(order.sourceWalletAddress, orderId);
92
+ }
93
+ return expiredOrders.sort((a, b) => this._orderComparator(a, b));
94
+ }
95
+
96
+ wasOrderProcessed(orderId, orderSourceChain, orderHeight) {
97
+ let lastChainProcessedHeightInfo = this.lastProcessedHeightsInfo[orderSourceChain];
98
+ let topChainHeight = lastChainProcessedHeightInfo.height;
99
+
100
+ return orderHeight < topChainHeight || lastChainProcessedHeightInfo.orderIds.has(orderId);
101
+ }
102
+
103
+ trackProcessedOrder(order) {
104
+ let lastChainProcessedHeightInfo = this.lastProcessedHeightsInfo[order.sourceChain];
105
+ let topChainHeight = lastChainProcessedHeightInfo.height;
106
+ if (order.height > topChainHeight) {
107
+ lastChainProcessedHeightInfo.height = order.height;
108
+ lastChainProcessedHeightInfo.orderIds = new Set([order.id]);
109
+ } else if (order.height < topChainHeight) {
110
+ let error = new Error(
111
+ `Could not process order with ID ${
112
+ order.id
113
+ } because it was below the last processed height of ${
114
+ topChainHeight
115
+ } for the chain ${order.sourceChain}`
116
+ );
117
+ error.name = 'HeightAlreadyProcessedError';
118
+ throw error;
119
+ } else {
120
+ if (lastChainProcessedHeightInfo.orderIds.has(order.id)) {
121
+ let error = new Error(
122
+ `Could not process order with ID ${
123
+ order.id
124
+ } because it was already processed`
125
+ );
126
+ error.name = 'OrderAlreadyProcessedError';
127
+ throw error;
128
+ }
129
+ lastChainProcessedHeightInfo.orderIds.add(order.id);
130
+ }
131
+ }
132
+
133
+ addOrder(order) {
134
+ this.trackProcessedOrder(order);
135
+
136
+ let existingOrder = this.orderBook.has(order.id);
137
+
138
+ if (existingOrder) {
139
+ let error = new Error(`An order with ID ${order.id} already exists`);
140
+ error.name = 'DuplicateOrderError';
141
+ throw error;
142
+ }
143
+
144
+ let orderHeightExpiry;
145
+ if (order.sourceChain === this.quoteCurrency) {
146
+ orderHeightExpiry = this.quoteOrderHeightExpiry;
147
+ } else {
148
+ orderHeightExpiry = this.baseOrderHeightExpiry;
149
+ }
150
+
151
+ let newOrder = {};
152
+ newOrder.id = order.id;
153
+ newOrder.side = order.side;
154
+ if (order.size != null) {
155
+ newOrder.size = order.size;
156
+ }
157
+ if (order.value != null) {
158
+ newOrder.value = order.value;
159
+ }
160
+ if (order.price != null) {
161
+ newOrder.price = order.price;
162
+ }
163
+ newOrder.type = order.type;
164
+ newOrder.targetChain = order.targetChain;
165
+ newOrder.targetWalletAddress = order.targetWalletAddress;
166
+ newOrder.senderAddress = order.senderAddress;
167
+ newOrder.sourceChain = order.sourceChain;
168
+ newOrder.sourceChainAmount = order.sourceChainAmount;
169
+ newOrder.sourceWalletAddress = order.sourceWalletAddress;
170
+ newOrder.height = order.height;
171
+ newOrder.expiryHeight = order.height + orderHeightExpiry;
172
+ newOrder.timestamp = order.timestamp;
173
+
174
+ let result = this._addToOrderBook(newOrder);
175
+
176
+ result.makers.forEach((makerOrder) => {
177
+ if (makerOrder.side === 'ask') {
178
+ if (makerOrder.sizeRemaining <= 0n) {
179
+ this._askMap.delete(makerOrder.id);
180
+ this._orderMap.delete(makerOrder.id);
181
+ this._removeFromWalletOrderMap(makerOrder.sourceWalletAddress, makerOrder.id);
182
+ }
183
+ } else {
184
+ if (makerOrder.valueRemaining <= 0n) {
185
+ this._bidMap.delete(makerOrder.id);
186
+ this._orderMap.delete(makerOrder.id);
187
+ this._removeFromWalletOrderMap(makerOrder.sourceWalletAddress, makerOrder.id);
188
+ }
189
+ }
190
+ });
191
+
192
+ if (newOrder.type !== 'market') {
193
+ if (newOrder.side === 'ask') {
194
+ if (result.taker.sizeRemaining > 0n) {
195
+ this._askMap.set(newOrder.id, newOrder);
196
+ this._orderMap.set(newOrder.id, newOrder);
197
+ this._addToWalletOrderMap(newOrder);
198
+ }
199
+ } else if (result.taker.valueRemaining > 0n) {
200
+ this._bidMap.set(newOrder.id, newOrder);
201
+ this._orderMap.set(newOrder.id, newOrder);
202
+ this._addToWalletOrderMap(newOrder);
203
+ }
204
+ }
205
+
206
+ return result;
207
+ }
208
+
209
+ _addToWalletOrderMap(order) {
210
+ if (!this._sourceWalletOrderMap.has(order.sourceWalletAddress)) {
211
+ this._sourceWalletOrderMap.set(order.sourceWalletAddress, new Map());
212
+ }
213
+ let orderMap = this._sourceWalletOrderMap.get(order.sourceWalletAddress);
214
+ orderMap.set(order.id, order);
215
+ }
216
+
217
+ _removeFromWalletOrderMap(sourceWalletAddress, orderId) {
218
+ let orderMap = this._sourceWalletOrderMap.get(sourceWalletAddress);
219
+ if (orderMap) {
220
+ let result = orderMap.delete(orderId);
221
+ if (!orderMap.size) {
222
+ this._sourceWalletOrderMap.delete(sourceWalletAddress);
223
+ }
224
+ return result;
225
+ }
226
+ return false;
227
+ }
228
+
229
+ getSourceWalletOrderIterator(sourceWalletAddress) {
230
+ let orderMap = this._sourceWalletOrderMap.get(sourceWalletAddress);
231
+ return orderMap ? orderMap.values() : emptyGenerator();
232
+ }
233
+
234
+ *getSourceWalletBidIterator(sourceWalletAddress) {
235
+ let orderIterator = this.getSourceWalletOrderIterator(sourceWalletAddress);
236
+ for (let order of orderIterator) {
237
+ if (order.side === 'bid') {
238
+ yield order;
239
+ }
240
+ }
241
+ }
242
+
243
+ *getSourceWalletAskIterator(sourceWalletAddress) {
244
+ let orderIterator = this.getSourceWalletOrderIterator(sourceWalletAddress);
245
+ for (let order of orderIterator) {
246
+ if (order.side === 'ask') {
247
+ yield order;
248
+ }
249
+ }
250
+ }
251
+
252
+ getOrder(orderId) {
253
+ return this._orderMap.get(orderId);
254
+ }
255
+
256
+ addCloseOrder(order) {
257
+ this.trackProcessedOrder(order);
258
+
259
+ let targetOrderId = order.orderIdToClose;
260
+ let targetOrder = this.getOrder(targetOrderId);
261
+ if (!targetOrder) {
262
+ throw new Error(
263
+ `An order with ID ${targetOrderId} could not be found`
264
+ );
265
+ }
266
+
267
+ let result = this._removeFromOrderBook(targetOrderId);
268
+ if (targetOrder.side === 'ask') {
269
+ this._askMap.delete(targetOrderId);
270
+ } else {
271
+ this._bidMap.delete(targetOrderId);
272
+ }
273
+ this._orderMap.delete(targetOrderId);
274
+ this._removeFromWalletOrderMap(targetOrder.sourceWalletAddress, targetOrderId);
275
+ return result;
276
+ }
277
+
278
+ peekBids() {
279
+ return this.orderBook.getMaxBid();
280
+ }
281
+
282
+ peekAsks() {
283
+ return this.orderBook.getMinAsk();
284
+ }
285
+
286
+ getBidIteratorFromMin() {
287
+ return this.orderBook.getBidIteratorFromMin();
288
+ }
289
+
290
+ getBidIteratorFromMax() {
291
+ return this.orderBook.getBidIteratorFromMax();
292
+ }
293
+
294
+ getAskIteratorFromMin() {
295
+ return this.orderBook.getAskIteratorFromMin();
296
+ }
297
+
298
+ getAskIteratorFromMax() {
299
+ return this.orderBook.getAskIteratorFromMax();
300
+ }
301
+
302
+ getBidLevelIteratorFromMin() {
303
+ return this.orderBook.getBidLevelIteratorFromMin();
304
+ }
305
+
306
+ getBidLevelIteratorFromMax() {
307
+ return this.orderBook.getBidLevelIteratorFromMax();
308
+ }
309
+
310
+ getAskLevelIteratorFromMin() {
311
+ return this.orderBook.getAskLevelIteratorFromMin();
312
+ }
313
+
314
+ getAskLevelIteratorFromMax() {
315
+ return this.orderBook.getAskLevelIteratorFromMax();
316
+ }
317
+
318
+ getOrderIterator() {
319
+ return this._orderMap.values();
320
+ }
321
+
322
+ getBids() {
323
+ return [...this.getBidIteratorFromMax()];
324
+ }
325
+
326
+ getAsks() {
327
+ return [...this.getAskIteratorFromMin()];
328
+ }
329
+
330
+ getOrders() {
331
+ return [...this.getOrderIterator()];
332
+ }
333
+
334
+ getSnapshot() {
335
+ let askLimitOrders = mapListFields(this.getAsks(), {
336
+ size: String,
337
+ sizeRemaining: String,
338
+ lastSizeTaken: String,
339
+ lastValueTaken: String,
340
+ sourceChainAmount: String
341
+ });
342
+ let bidLimitOrders = mapListFields(this.getBids(), {
343
+ value: String,
344
+ valueRemaining: String,
345
+ lastSizeTaken: String,
346
+ lastValueTaken: String,
347
+ sourceChainAmount: String
348
+ });
349
+ return {
350
+ orderBookHash: this.orderBookHash,
351
+ askLimitOrders,
352
+ bidLimitOrders
353
+ };
354
+ }
355
+
356
+ _addToOrderBook(order) {
357
+ this.orderBookHash = this._sha1(`${this.orderBookHash}+${order.id}`);
358
+ return this.orderBook.add(order);
359
+ }
360
+
361
+ _removeFromOrderBook(orderId) {
362
+ this.orderBookHash = this._sha1(`${this.orderBookHash}-${orderId}`);
363
+ return this.orderBook.remove(orderId);
364
+ }
365
+
366
+ setSnapshot(snapshot) {
367
+ this.clear();
368
+ snapshot.askLimitOrders.sort((a, b) => {
369
+ if (a.expiryHeight > b.expiryHeight) {
370
+ return 1;
371
+ }
372
+ if (a.expiryHeight < b.expiryHeight) {
373
+ return -1;
374
+ }
375
+ return 0;
376
+ });
377
+ snapshot.bidLimitOrders.sort((a, b) => {
378
+ if (a.expiryHeight > b.expiryHeight) {
379
+ return 1;
380
+ }
381
+ if (a.expiryHeight < b.expiryHeight) {
382
+ return -1;
383
+ }
384
+ return 0;
385
+ });
386
+ snapshot.askLimitOrders.forEach((order) => {
387
+ let newOrder = {...order};
388
+ this._addToOrderBook(newOrder);
389
+ this._askMap.set(newOrder.id, newOrder);
390
+ this._orderMap.set(newOrder.id, newOrder);
391
+ this._addToWalletOrderMap(newOrder);
392
+ });
393
+ snapshot.bidLimitOrders.forEach((order) => {
394
+ let newOrder = {...order};
395
+ this._addToOrderBook(newOrder);
396
+ this._bidMap.set(newOrder.id, newOrder);
397
+ this._orderMap.set(newOrder.id, newOrder);
398
+ this._addToWalletOrderMap(newOrder);
399
+ });
400
+ if (snapshot.orderBookHash) {
401
+ this.orderBookHash = snapshot.orderBookHash
402
+ }
403
+ }
404
+
405
+ clear() {
406
+ this.orderBookHash = EMPTY_ORDER_BOOK_HASH;
407
+ this._resetProcessedHeightsInfo();
408
+ this._askMap.clear();
409
+ this._bidMap.clear();
410
+ this._orderMap.clear();
411
+ this._sourceWalletOrderMap.clear();
412
+ this.orderBook.clear();
413
+ }
414
+ }
415
+
416
+ module.exports = TradeEngine;