@drift-labs/sdk 2.0.16 → 2.0.18
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/lib/dlob/DLOB.d.ts +10 -16
- package/lib/dlob/DLOB.js +128 -102
- package/lib/dlob/DLOBNode.d.ts +3 -5
- package/lib/dlob/DLOBNode.js +6 -7
- package/lib/dlob/DLOBOrders.d.ts +16 -0
- package/lib/dlob/DLOBOrders.js +40 -0
- package/lib/dlob/NodeList.d.ts +2 -2
- package/lib/dlob/NodeList.js +2 -9
- package/lib/dlob/dlobIdl.json +245 -0
- package/lib/idl/drift.json +5 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/math/amm.d.ts +21 -1
- package/lib/math/amm.js +62 -13
- package/lib/math/oracles.js +1 -2
- package/package.json +1 -1
- package/src/dlob/DLOB.ts +165 -145
- package/src/dlob/DLOBNode.ts +5 -15
- package/src/dlob/DLOBOrders.ts +49 -0
- package/src/dlob/NodeList.ts +2 -17
- package/src/dlob/dlobIdl.json +245 -0
- package/src/idl/drift.json +5 -0
- package/src/index.ts +1 -0
- package/src/math/amm.ts +75 -16
- package/src/math/oracles.ts +1 -2
- package/tests/amm/test.ts +178 -0
- package/tests/dlob/test.ts +305 -645
- package/src/assert/assert.js +0 -9
- package/src/examples/makeTradeExample.js +0 -157
- package/src/token/index.js +0 -38
- package/src/tx/types.js +0 -2
- package/src/tx/utils.js +0 -17
- package/src/util/computeUnits.js +0 -27
- package/src/util/getTokenAddress.js +0 -9
- package/src/util/promiseTimeout.js +0 -14
- package/src/util/tps.js +0 -27
package/lib/dlob/DLOB.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/// <reference types="bn.js" />
|
|
2
2
|
import { NodeList } from './NodeList';
|
|
3
|
-
import { MarketType, BN, DriftClient, Order, SpotMarketAccount, PerpMarketAccount, OraclePriceData, SlotSubscriber,
|
|
3
|
+
import { MarketType, BN, DriftClient, Order, SpotMarketAccount, PerpMarketAccount, OraclePriceData, SlotSubscriber, MarketTypeStr, StateAccount, UserMap } from '..';
|
|
4
4
|
import { PublicKey } from '@solana/web3.js';
|
|
5
5
|
import { DLOBNode, TriggerOrderNode } from '..';
|
|
6
|
+
import { DLOBOrders } from './DLOBOrders';
|
|
6
7
|
export declare type MarketNodeLists = {
|
|
7
8
|
limit: {
|
|
8
9
|
ask: NodeList<'limit'>;
|
|
@@ -32,30 +33,21 @@ export declare type NodeToTrigger = {
|
|
|
32
33
|
export declare class DLOB {
|
|
33
34
|
openOrders: Map<MarketTypeStr, Set<string>>;
|
|
34
35
|
orderLists: Map<MarketTypeStr, Map<number, MarketNodeLists>>;
|
|
35
|
-
stateAccount: StateAccount;
|
|
36
|
-
marketIndexToAccount: Map<MarketTypeStr, Map<number, PerpMarketAccount | SpotMarketAccount>>;
|
|
37
|
-
userMap: UserMapInterface;
|
|
38
|
-
silent: boolean;
|
|
39
36
|
initialized: boolean;
|
|
40
|
-
|
|
41
|
-
*
|
|
42
|
-
* @param perpMarkets The perp markets to maintain a DLOB for
|
|
43
|
-
* @param spotMarkets The spot markets to maintain a DLOB for
|
|
44
|
-
* @param userMap map of all users
|
|
45
|
-
* @param silent set to true to prevent logging on inserts and removals
|
|
46
|
-
*/
|
|
47
|
-
constructor(perpMarkets: PerpMarketAccount[], spotMarkets: SpotMarketAccount[], stateAccount: StateAccount, userMap: UserMapInterface, silent?: boolean);
|
|
37
|
+
constructor();
|
|
48
38
|
clear(): void;
|
|
49
39
|
/**
|
|
50
40
|
* initializes a new DLOB instance
|
|
51
41
|
*
|
|
52
42
|
* @returns a promise that resolves when the DLOB is initialized
|
|
53
43
|
*/
|
|
54
|
-
|
|
44
|
+
initFromUserMap(userMap: UserMap): Promise<boolean>;
|
|
45
|
+
initFromOrders(dlobOrders: DLOBOrders): boolean;
|
|
55
46
|
insertOrder(order: Order, userAccount: PublicKey, onInsert?: OrderBookCallback): void;
|
|
47
|
+
addOrderList(marketType: MarketTypeStr, marketIndex: number): void;
|
|
56
48
|
trigger(order: Order, userAccount: PublicKey, onTrigger?: OrderBookCallback): void;
|
|
57
49
|
getListForOrder(order: Order): NodeList<any> | undefined;
|
|
58
|
-
findNodesToFill(marketIndex: number, fallbackBid: BN | undefined, fallbackAsk: BN | undefined, slot: number, ts: number, marketType: MarketType, oraclePriceData: OraclePriceData): NodeToFill[];
|
|
50
|
+
findNodesToFill(marketIndex: number, fallbackBid: BN | undefined, fallbackAsk: BN | undefined, slot: number, ts: number, marketType: MarketType, oraclePriceData: OraclePriceData, stateAccount: StateAccount, marketAccount: PerpMarketAccount | SpotMarketAccount): NodeToFill[];
|
|
59
51
|
findLimitOrderNodesToFill(marketIndex: number, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData, isAmmPaused: boolean, fallbackAsk: BN | undefined, fallbackBid: BN | undefined): NodeToFill[];
|
|
60
52
|
findMarketNodesToFill(marketIndex: number, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData, isAmmPaused: boolean, fallbackAsk: BN | undefined, fallbackBid?: BN | undefined): NodeToFill[];
|
|
61
53
|
findMarketNodesCrossingLimitNodes(marketIndex: number, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData, takerNodeGenerator: Generator<DLOBNode>, makerNodeGeneratorFn: (marketIndex: number, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData) => Generator<DLOBNode>, doesCross: (takerPrice: BN | undefined, makerPrice: BN) => boolean): NodeToFill[];
|
|
@@ -76,7 +68,9 @@ export declare class DLOB {
|
|
|
76
68
|
};
|
|
77
69
|
getBestAsk(marketIndex: number, fallbackAsk: BN | undefined, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData): BN;
|
|
78
70
|
getBestBid(marketIndex: number, fallbackBid: BN | undefined, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData): BN;
|
|
79
|
-
findNodesToTrigger(marketIndex: number, slot: number, oraclePrice: BN, marketType: MarketType): NodeToTrigger[];
|
|
71
|
+
findNodesToTrigger(marketIndex: number, slot: number, oraclePrice: BN, marketType: MarketType, stateAccount: StateAccount): NodeToTrigger[];
|
|
80
72
|
printTopOfOrderLists(sdkConfig: any, driftClient: DriftClient, slotSubscriber: SlotSubscriber, marketIndex: number, marketType: MarketType): void;
|
|
73
|
+
getDLOBOrders(): DLOBOrders;
|
|
74
|
+
getOrdersForMarket(marketIndex: number, marketType: MarketType, nodeLists: MarketNodeLists): DLOBOrders;
|
|
81
75
|
}
|
|
82
76
|
export {};
|
package/lib/dlob/DLOB.js
CHANGED
|
@@ -5,72 +5,14 @@ const NodeList_1 = require("./NodeList");
|
|
|
5
5
|
const __1 = require("..");
|
|
6
6
|
const exchangeStatus_1 = require("../math/exchangeStatus");
|
|
7
7
|
class DLOB {
|
|
8
|
-
|
|
9
|
-
*
|
|
10
|
-
* @param perpMarkets The perp markets to maintain a DLOB for
|
|
11
|
-
* @param spotMarkets The spot markets to maintain a DLOB for
|
|
12
|
-
* @param userMap map of all users
|
|
13
|
-
* @param silent set to true to prevent logging on inserts and removals
|
|
14
|
-
*/
|
|
15
|
-
constructor(perpMarkets, spotMarkets, stateAccount, userMap, silent) {
|
|
8
|
+
constructor() {
|
|
16
9
|
this.openOrders = new Map();
|
|
17
10
|
this.orderLists = new Map();
|
|
18
|
-
this.marketIndexToAccount = new Map();
|
|
19
|
-
this.silent = false;
|
|
20
11
|
this.initialized = false;
|
|
21
|
-
this.stateAccount = stateAccount;
|
|
22
|
-
this.userMap = userMap;
|
|
23
|
-
this.silent = silent;
|
|
24
12
|
this.openOrders.set('perp', new Set());
|
|
25
13
|
this.openOrders.set('spot', new Set());
|
|
26
14
|
this.orderLists.set('perp', new Map());
|
|
27
15
|
this.orderLists.set('spot', new Map());
|
|
28
|
-
this.marketIndexToAccount.set('perp', new Map());
|
|
29
|
-
this.marketIndexToAccount.set('spot', new Map());
|
|
30
|
-
for (const market of perpMarkets) {
|
|
31
|
-
const marketIndex = market.marketIndex;
|
|
32
|
-
this.marketIndexToAccount.get('perp').set(marketIndex, market);
|
|
33
|
-
this.orderLists.get('perp').set(marketIndex, {
|
|
34
|
-
limit: {
|
|
35
|
-
ask: new NodeList_1.NodeList('limit', 'asc'),
|
|
36
|
-
bid: new NodeList_1.NodeList('limit', 'desc'),
|
|
37
|
-
},
|
|
38
|
-
floatingLimit: {
|
|
39
|
-
ask: new NodeList_1.NodeList('floatingLimit', 'asc'),
|
|
40
|
-
bid: new NodeList_1.NodeList('floatingLimit', 'desc'),
|
|
41
|
-
},
|
|
42
|
-
market: {
|
|
43
|
-
ask: new NodeList_1.NodeList('market', 'asc'),
|
|
44
|
-
bid: new NodeList_1.NodeList('market', 'asc'), // always sort ascending for market orders
|
|
45
|
-
},
|
|
46
|
-
trigger: {
|
|
47
|
-
above: new NodeList_1.NodeList('trigger', 'asc'),
|
|
48
|
-
below: new NodeList_1.NodeList('trigger', 'desc'),
|
|
49
|
-
},
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
for (const market of spotMarkets) {
|
|
53
|
-
const marketIndex = market.marketIndex;
|
|
54
|
-
this.marketIndexToAccount.get('spot').set(marketIndex, market);
|
|
55
|
-
this.orderLists.get('spot').set(marketIndex, {
|
|
56
|
-
limit: {
|
|
57
|
-
ask: new NodeList_1.NodeList('limit', 'asc'),
|
|
58
|
-
bid: new NodeList_1.NodeList('limit', 'desc'),
|
|
59
|
-
},
|
|
60
|
-
floatingLimit: {
|
|
61
|
-
ask: new NodeList_1.NodeList('floatingLimit', 'asc'),
|
|
62
|
-
bid: new NodeList_1.NodeList('floatingLimit', 'desc'),
|
|
63
|
-
},
|
|
64
|
-
market: {
|
|
65
|
-
ask: new NodeList_1.NodeList('market', 'asc'),
|
|
66
|
-
bid: new NodeList_1.NodeList('market', 'asc'), // always sort ascending for market orders
|
|
67
|
-
},
|
|
68
|
-
trigger: {
|
|
69
|
-
above: new NodeList_1.NodeList('trigger', 'asc'),
|
|
70
|
-
below: new NodeList_1.NodeList('trigger', 'desc'),
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
16
|
}
|
|
75
17
|
clear() {
|
|
76
18
|
for (const marketType of this.openOrders.keys()) {
|
|
@@ -90,22 +32,18 @@ class DLOB {
|
|
|
90
32
|
}
|
|
91
33
|
}
|
|
92
34
|
this.orderLists.clear();
|
|
93
|
-
for (const marketType of this.marketIndexToAccount.keys()) {
|
|
94
|
-
this.marketIndexToAccount.get(marketType).clear();
|
|
95
|
-
}
|
|
96
|
-
this.marketIndexToAccount.clear();
|
|
97
35
|
}
|
|
98
36
|
/**
|
|
99
37
|
* initializes a new DLOB instance
|
|
100
38
|
*
|
|
101
39
|
* @returns a promise that resolves when the DLOB is initialized
|
|
102
40
|
*/
|
|
103
|
-
async
|
|
41
|
+
async initFromUserMap(userMap) {
|
|
104
42
|
if (this.initialized) {
|
|
105
43
|
return false;
|
|
106
44
|
}
|
|
107
|
-
// initialize the dlob with the user map
|
|
108
|
-
for (const user of
|
|
45
|
+
// initialize the dlob with the user map
|
|
46
|
+
for (const user of userMap.values()) {
|
|
109
47
|
const userAccount = user.getUserAccount();
|
|
110
48
|
const userAccountPubkey = user.getUserAccountPublicKey();
|
|
111
49
|
for (const order of userAccount.orders) {
|
|
@@ -115,22 +53,55 @@ class DLOB {
|
|
|
115
53
|
this.initialized = true;
|
|
116
54
|
return true;
|
|
117
55
|
}
|
|
56
|
+
initFromOrders(dlobOrders) {
|
|
57
|
+
if (this.initialized) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
for (const { user, order } of dlobOrders) {
|
|
61
|
+
this.insertOrder(order, user);
|
|
62
|
+
}
|
|
63
|
+
this.initialized = true;
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
118
66
|
insertOrder(order, userAccount, onInsert) {
|
|
119
67
|
var _a;
|
|
120
68
|
if ((0, __1.isVariant)(order.status, 'init')) {
|
|
121
69
|
return;
|
|
122
70
|
}
|
|
123
71
|
const marketType = (0, __1.getVariant)(order.marketType);
|
|
72
|
+
if (!this.orderLists.get(marketType).has(order.marketIndex)) {
|
|
73
|
+
this.addOrderList(marketType, order.marketIndex);
|
|
74
|
+
}
|
|
124
75
|
if ((0, __1.isVariant)(order.status, 'open')) {
|
|
125
76
|
this.openOrders
|
|
126
77
|
.get(marketType)
|
|
127
78
|
.add((0, NodeList_1.getOrderSignature)(order.orderId, userAccount));
|
|
128
79
|
}
|
|
129
|
-
(_a = this.getListForOrder(order)) === null || _a === void 0 ? void 0 : _a.insert(order, marketType,
|
|
80
|
+
(_a = this.getListForOrder(order)) === null || _a === void 0 ? void 0 : _a.insert(order, marketType, userAccount);
|
|
130
81
|
if (onInsert) {
|
|
131
82
|
onInsert();
|
|
132
83
|
}
|
|
133
84
|
}
|
|
85
|
+
addOrderList(marketType, marketIndex) {
|
|
86
|
+
this.orderLists.get(marketType).set(marketIndex, {
|
|
87
|
+
limit: {
|
|
88
|
+
ask: new NodeList_1.NodeList('limit', 'asc'),
|
|
89
|
+
bid: new NodeList_1.NodeList('limit', 'desc'),
|
|
90
|
+
},
|
|
91
|
+
floatingLimit: {
|
|
92
|
+
ask: new NodeList_1.NodeList('floatingLimit', 'asc'),
|
|
93
|
+
bid: new NodeList_1.NodeList('floatingLimit', 'desc'),
|
|
94
|
+
},
|
|
95
|
+
market: {
|
|
96
|
+
ask: new NodeList_1.NodeList('market', 'asc'),
|
|
97
|
+
bid: new NodeList_1.NodeList('market', 'asc'), // always sort ascending for market orders
|
|
98
|
+
},
|
|
99
|
+
trigger: {
|
|
100
|
+
above: new NodeList_1.NodeList('trigger', 'asc'),
|
|
101
|
+
below: new NodeList_1.NodeList('trigger', 'desc'),
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
}
|
|
134
105
|
trigger(order, userAccount, onTrigger) {
|
|
135
106
|
var _a;
|
|
136
107
|
if ((0, __1.isVariant)(order.status, 'init')) {
|
|
@@ -140,7 +111,7 @@ class DLOB {
|
|
|
140
111
|
const triggerList = this.orderLists.get(marketType).get(order.marketIndex)
|
|
141
112
|
.trigger[(0, __1.isVariant)(order.triggerCondition, 'above') ? 'above' : 'below'];
|
|
142
113
|
triggerList.remove(order, userAccount);
|
|
143
|
-
(_a = this.getListForOrder(order)) === null || _a === void 0 ? void 0 : _a.insert(order, marketType,
|
|
114
|
+
(_a = this.getListForOrder(order)) === null || _a === void 0 ? void 0 : _a.insert(order, marketType, userAccount);
|
|
144
115
|
if (onTrigger) {
|
|
145
116
|
onTrigger();
|
|
146
117
|
}
|
|
@@ -173,14 +144,11 @@ class DLOB {
|
|
|
173
144
|
}
|
|
174
145
|
return this.orderLists.get(marketType).get(order.marketIndex)[type][subType];
|
|
175
146
|
}
|
|
176
|
-
findNodesToFill(marketIndex, fallbackBid, fallbackAsk, slot, ts, marketType, oraclePriceData) {
|
|
177
|
-
|
|
178
|
-
.get((0, __1.getVariant)(marketType))
|
|
179
|
-
.get(marketIndex);
|
|
180
|
-
if ((0, exchangeStatus_1.fillPaused)(this.stateAccount, marketAccount)) {
|
|
147
|
+
findNodesToFill(marketIndex, fallbackBid, fallbackAsk, slot, ts, marketType, oraclePriceData, stateAccount, marketAccount) {
|
|
148
|
+
if ((0, exchangeStatus_1.fillPaused)(stateAccount, marketAccount)) {
|
|
181
149
|
return [];
|
|
182
150
|
}
|
|
183
|
-
const isAmmPaused = (0, exchangeStatus_1.ammPaused)(
|
|
151
|
+
const isAmmPaused = (0, exchangeStatus_1.ammPaused)(stateAccount, marketAccount);
|
|
184
152
|
const marketOrderNodesToFill = this.findMarketNodesToFill(marketIndex, slot, marketType, oraclePriceData, isAmmPaused, fallbackAsk, fallbackBid);
|
|
185
153
|
const limitOrderNodesToFill = this.findLimitOrderNodesToFill(marketIndex, slot, marketType, oraclePriceData, isAmmPaused, fallbackAsk, fallbackBid);
|
|
186
154
|
// get expired market nodes
|
|
@@ -254,11 +222,9 @@ class DLOB {
|
|
|
254
222
|
for (const takerNode of takerNodeGenerator) {
|
|
255
223
|
const makerNodeGenerator = makerNodeGeneratorFn(marketIndex, slot, marketType, oraclePriceData);
|
|
256
224
|
for (const makerNode of makerNodeGenerator) {
|
|
257
|
-
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
const sameAuthority = bidUserAuthority.equals(askUserAuthority);
|
|
261
|
-
if (sameAuthority) {
|
|
225
|
+
// Can't match orders from the same user
|
|
226
|
+
const sameUser = takerNode.userAccount.equals(makerNode.userAccount);
|
|
227
|
+
if (sameUser) {
|
|
262
228
|
continue;
|
|
263
229
|
}
|
|
264
230
|
const makerPrice = makerNode.getPrice(oraclePriceData, slot);
|
|
@@ -374,10 +340,11 @@ class DLOB {
|
|
|
374
340
|
}
|
|
375
341
|
*getMarketBids(marketIndex, marketType) {
|
|
376
342
|
const marketTypeStr = (0, __1.getVariant)(marketType);
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
343
|
+
const orderLists = this.orderLists.get(marketTypeStr).get(marketIndex);
|
|
344
|
+
if (!orderLists) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
const generator = orderLists.market.bid.getGenerator();
|
|
381
348
|
for (const marketBidNode of generator) {
|
|
382
349
|
if (marketBidNode.isBaseFilled()) {
|
|
383
350
|
continue;
|
|
@@ -387,10 +354,11 @@ class DLOB {
|
|
|
387
354
|
}
|
|
388
355
|
*getMarketAsks(marketIndex, marketType) {
|
|
389
356
|
const marketTypeStr = (0, __1.getVariant)(marketType);
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
357
|
+
const orderLists = this.orderLists.get(marketTypeStr).get(marketIndex);
|
|
358
|
+
if (!orderLists) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
const generator = orderLists.market.ask.getGenerator();
|
|
394
362
|
for (const marketAskNode of generator) {
|
|
395
363
|
if (marketAskNode.isBaseFilled()) {
|
|
396
364
|
continue;
|
|
@@ -435,14 +403,6 @@ class DLOB {
|
|
|
435
403
|
bestGenerator.next = bestGenerator.generator.next();
|
|
436
404
|
continue;
|
|
437
405
|
}
|
|
438
|
-
// skip order if user is being liquidated/bankrupt
|
|
439
|
-
if (bestGenerator.next.value.userAccount !== undefined) {
|
|
440
|
-
const user = this.userMap.get(bestGenerator.next.value.userAccount.toString());
|
|
441
|
-
if (user === null || user === void 0 ? void 0 : user.isBeingLiquidated()) {
|
|
442
|
-
bestGenerator.next = bestGenerator.generator.next();
|
|
443
|
-
continue;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
406
|
yield bestGenerator.next.value;
|
|
447
407
|
bestGenerator.next = bestGenerator.generator.next();
|
|
448
408
|
}
|
|
@@ -457,6 +417,9 @@ class DLOB {
|
|
|
457
417
|
}
|
|
458
418
|
const marketTypeStr = (0, __1.getVariant)(marketType);
|
|
459
419
|
const nodeLists = this.orderLists.get(marketTypeStr).get(marketIndex);
|
|
420
|
+
if (!nodeLists) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
460
423
|
const generatorList = [
|
|
461
424
|
nodeLists.limit.ask.getGenerator(),
|
|
462
425
|
nodeLists.floatingLimit.ask.getGenerator(),
|
|
@@ -471,6 +434,9 @@ class DLOB {
|
|
|
471
434
|
}
|
|
472
435
|
const marketTypeStr = (0, __1.getVariant)(marketType);
|
|
473
436
|
const nodeLists = this.orderLists.get(marketTypeStr).get(marketIndex);
|
|
437
|
+
if (!nodeLists) {
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
474
440
|
const generatorList = [
|
|
475
441
|
nodeLists.limit.bid.getGenerator(),
|
|
476
442
|
nodeLists.floatingLimit.bid.getGenerator(),
|
|
@@ -523,11 +489,9 @@ class DLOB {
|
|
|
523
489
|
}
|
|
524
490
|
const bidOrder = bidNode.order;
|
|
525
491
|
const askOrder = askNode.order;
|
|
526
|
-
|
|
527
|
-
const
|
|
528
|
-
|
|
529
|
-
const sameAuthority = bidUserAuthority.equals(askUserAuthority);
|
|
530
|
-
if (sameAuthority || (bidOrder.postOnly && askOrder.postOnly)) {
|
|
492
|
+
// Can't match orders from the same user
|
|
493
|
+
const sameUser = bidNode.userAccount.equals(askNode.userAccount);
|
|
494
|
+
if (sameUser || (bidOrder.postOnly && askOrder.postOnly)) {
|
|
531
495
|
continue;
|
|
532
496
|
}
|
|
533
497
|
const { takerNode, makerNode } = this.determineMakerAndTaker(askNode, bidNode);
|
|
@@ -590,8 +554,8 @@ class DLOB {
|
|
|
590
554
|
.next()
|
|
591
555
|
.value.getPrice(oraclePriceData, slot);
|
|
592
556
|
}
|
|
593
|
-
findNodesToTrigger(marketIndex, slot, oraclePrice, marketType) {
|
|
594
|
-
if ((0, exchangeStatus_1.exchangePaused)(
|
|
557
|
+
findNodesToTrigger(marketIndex, slot, oraclePrice, marketType, stateAccount) {
|
|
558
|
+
if ((0, exchangeStatus_1.exchangePaused)(stateAccount)) {
|
|
595
559
|
return [];
|
|
596
560
|
}
|
|
597
561
|
const nodesToTrigger = [];
|
|
@@ -671,5 +635,67 @@ class DLOB {
|
|
|
671
635
|
console.log(` Bid`, (0, __1.convertToNumber)(bestBid, __1.PRICE_PRECISION).toFixed(3), `(${bidSpread.toFixed(4)}%)`);
|
|
672
636
|
}
|
|
673
637
|
}
|
|
638
|
+
getDLOBOrders() {
|
|
639
|
+
let dlobOrders = [];
|
|
640
|
+
for (const [marketIndex, nodeLists] of this.orderLists.get('perp')) {
|
|
641
|
+
dlobOrders = dlobOrders.concat(this.getOrdersForMarket(marketIndex, __1.MarketType.PERP, nodeLists));
|
|
642
|
+
}
|
|
643
|
+
for (const [marketIndex, nodeLists] of this.orderLists.get('spot')) {
|
|
644
|
+
dlobOrders = dlobOrders.concat(this.getOrdersForMarket(marketIndex, __1.MarketType.SPOT, nodeLists));
|
|
645
|
+
}
|
|
646
|
+
return dlobOrders;
|
|
647
|
+
}
|
|
648
|
+
getOrdersForMarket(marketIndex, marketType, nodeLists) {
|
|
649
|
+
const orders = [];
|
|
650
|
+
for (const node of nodeLists.limit.bid.getGenerator()) {
|
|
651
|
+
orders.push({
|
|
652
|
+
user: node.userAccount,
|
|
653
|
+
order: node.order,
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
for (const node of nodeLists.limit.ask.getGenerator()) {
|
|
657
|
+
orders.push({
|
|
658
|
+
user: node.userAccount,
|
|
659
|
+
order: node.order,
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
for (const node of nodeLists.market.bid.getGenerator()) {
|
|
663
|
+
orders.push({
|
|
664
|
+
user: node.userAccount,
|
|
665
|
+
order: node.order,
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
for (const node of nodeLists.market.ask.getGenerator()) {
|
|
669
|
+
orders.push({
|
|
670
|
+
user: node.userAccount,
|
|
671
|
+
order: node.order,
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
for (const node of nodeLists.floatingLimit.bid.getGenerator()) {
|
|
675
|
+
orders.push({
|
|
676
|
+
user: node.userAccount,
|
|
677
|
+
order: node.order,
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
for (const node of nodeLists.floatingLimit.ask.getGenerator()) {
|
|
681
|
+
orders.push({
|
|
682
|
+
user: node.userAccount,
|
|
683
|
+
order: node.order,
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
for (const node of nodeLists.trigger.below.getGenerator()) {
|
|
687
|
+
orders.push({
|
|
688
|
+
user: node.userAccount,
|
|
689
|
+
order: node.order,
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
for (const node of nodeLists.trigger.above.getGenerator()) {
|
|
693
|
+
orders.push({
|
|
694
|
+
user: node.userAccount,
|
|
695
|
+
order: node.order,
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
return orders;
|
|
699
|
+
}
|
|
674
700
|
}
|
|
675
701
|
exports.DLOB = DLOB;
|
package/lib/dlob/DLOBNode.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="bn.js" />
|
|
2
|
-
import { BN,
|
|
2
|
+
import { BN, OraclePriceData, Order } from '..';
|
|
3
3
|
import { PublicKey } from '@solana/web3.js';
|
|
4
4
|
export interface DLOBNode {
|
|
5
5
|
getPrice(oraclePriceData: OraclePriceData, slot: number): BN;
|
|
@@ -8,16 +8,14 @@ export interface DLOBNode {
|
|
|
8
8
|
isBaseFilled(): boolean;
|
|
9
9
|
haveFilled: boolean;
|
|
10
10
|
userAccount: PublicKey | undefined;
|
|
11
|
-
market: SpotMarketAccount | PerpMarketAccount;
|
|
12
11
|
}
|
|
13
12
|
export declare abstract class OrderNode implements DLOBNode {
|
|
14
13
|
order: Order;
|
|
15
|
-
market: SpotMarketAccount | PerpMarketAccount;
|
|
16
14
|
userAccount: PublicKey;
|
|
17
15
|
sortValue: BN;
|
|
18
16
|
haveFilled: boolean;
|
|
19
17
|
haveTrigger: boolean;
|
|
20
|
-
constructor(order: Order,
|
|
18
|
+
constructor(order: Order, userAccount: PublicKey);
|
|
21
19
|
abstract getSortValue(order: Order): BN;
|
|
22
20
|
getLabel(): string;
|
|
23
21
|
getPrice(oraclePriceData: OraclePriceData, slot: number): BN;
|
|
@@ -51,4 +49,4 @@ export declare type DLOBNodeMap = {
|
|
|
51
49
|
trigger: TriggerOrderNode;
|
|
52
50
|
};
|
|
53
51
|
export declare type DLOBNodeType = 'limit' | 'floatingLimit' | 'market' | ('trigger' & keyof DLOBNodeMap);
|
|
54
|
-
export declare function createNode<T extends DLOBNodeType>(nodeType: T, order: Order,
|
|
52
|
+
export declare function createNode<T extends DLOBNodeType>(nodeType: T, order: Order, userAccount: PublicKey): DLOBNodeMap[T];
|
package/lib/dlob/DLOBNode.js
CHANGED
|
@@ -4,11 +4,10 @@ exports.createNode = exports.TriggerOrderNode = exports.MarketOrderNode = export
|
|
|
4
4
|
const __1 = require("..");
|
|
5
5
|
const NodeList_1 = require("./NodeList");
|
|
6
6
|
class OrderNode {
|
|
7
|
-
constructor(order,
|
|
7
|
+
constructor(order, userAccount) {
|
|
8
8
|
this.haveFilled = false;
|
|
9
9
|
this.haveTrigger = false;
|
|
10
10
|
this.order = order;
|
|
11
|
-
this.market = market;
|
|
12
11
|
this.userAccount = userAccount;
|
|
13
12
|
this.sortValue = this.getSortValue(order);
|
|
14
13
|
}
|
|
@@ -60,16 +59,16 @@ class TriggerOrderNode extends OrderNode {
|
|
|
60
59
|
}
|
|
61
60
|
}
|
|
62
61
|
exports.TriggerOrderNode = TriggerOrderNode;
|
|
63
|
-
function createNode(nodeType, order,
|
|
62
|
+
function createNode(nodeType, order, userAccount) {
|
|
64
63
|
switch (nodeType) {
|
|
65
64
|
case 'floatingLimit':
|
|
66
|
-
return new FloatingLimitOrderNode(order,
|
|
65
|
+
return new FloatingLimitOrderNode(order, userAccount);
|
|
67
66
|
case 'limit':
|
|
68
|
-
return new LimitOrderNode(order,
|
|
67
|
+
return new LimitOrderNode(order, userAccount);
|
|
69
68
|
case 'market':
|
|
70
|
-
return new MarketOrderNode(order,
|
|
69
|
+
return new MarketOrderNode(order, userAccount);
|
|
71
70
|
case 'trigger':
|
|
72
|
-
return new TriggerOrderNode(order,
|
|
71
|
+
return new TriggerOrderNode(order, userAccount);
|
|
73
72
|
default:
|
|
74
73
|
throw Error(`Unknown DLOBNode type ${nodeType}`);
|
|
75
74
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { PublicKey } from '@solana/web3.js';
|
|
3
|
+
import { Idl } from '@project-serum/anchor';
|
|
4
|
+
import { Order } from '../types';
|
|
5
|
+
export declare type DLOBOrder = {
|
|
6
|
+
user: PublicKey;
|
|
7
|
+
order: Order;
|
|
8
|
+
};
|
|
9
|
+
export declare type DLOBOrders = DLOBOrder[];
|
|
10
|
+
export declare class DLOBOrdersCoder {
|
|
11
|
+
private idl;
|
|
12
|
+
constructor(idl: Idl);
|
|
13
|
+
static create(): DLOBOrdersCoder;
|
|
14
|
+
encode(dlobOrders: DLOBOrders): Buffer;
|
|
15
|
+
decode(buffer: Buffer): DLOBOrders;
|
|
16
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DLOBOrdersCoder = void 0;
|
|
7
|
+
const idl_1 = require("@project-serum/anchor/dist/cjs/coder/borsh/idl");
|
|
8
|
+
const dlobIdl_json_1 = __importDefault(require("./dlobIdl.json"));
|
|
9
|
+
class DLOBOrdersCoder {
|
|
10
|
+
constructor(idl) {
|
|
11
|
+
this.idl = idl;
|
|
12
|
+
}
|
|
13
|
+
static create() {
|
|
14
|
+
return new DLOBOrdersCoder(dlobIdl_json_1.default);
|
|
15
|
+
}
|
|
16
|
+
encode(dlobOrders) {
|
|
17
|
+
const layout = idl_1.IdlCoder.fieldLayout({
|
|
18
|
+
type: {
|
|
19
|
+
vec: {
|
|
20
|
+
defined: 'DLOBOrder',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
}, this.idl.types);
|
|
24
|
+
const size = 150 * dlobOrders.length;
|
|
25
|
+
const buffer = Buffer.alloc(size);
|
|
26
|
+
const len = layout.encode(dlobOrders, buffer);
|
|
27
|
+
return buffer.slice(0, len);
|
|
28
|
+
}
|
|
29
|
+
decode(buffer) {
|
|
30
|
+
const layout = idl_1.IdlCoder.fieldLayout({
|
|
31
|
+
type: {
|
|
32
|
+
vec: {
|
|
33
|
+
defined: 'DLOBOrder',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
}, this.idl.types);
|
|
37
|
+
return layout.decode(buffer);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.DLOBOrdersCoder = DLOBOrdersCoder;
|
package/lib/dlob/NodeList.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="bn.js" />
|
|
2
|
-
import { BN, MarketTypeStr, Order
|
|
2
|
+
import { BN, MarketTypeStr, Order } from '..';
|
|
3
3
|
import { PublicKey } from '@solana/web3.js';
|
|
4
4
|
import { DLOBNode, DLOBNodeMap } from './DLOBNode';
|
|
5
5
|
export declare type SortDirection = 'asc' | 'desc';
|
|
@@ -15,7 +15,7 @@ export declare class NodeList<NodeType extends keyof DLOBNodeMap> implements DLO
|
|
|
15
15
|
nodeMap: Map<string, DLOBNodeMap[NodeType]>;
|
|
16
16
|
constructor(nodeType: NodeType, sortDirection: SortDirection);
|
|
17
17
|
clear(): void;
|
|
18
|
-
insert(order: Order, marketType: MarketTypeStr,
|
|
18
|
+
insert(order: Order, marketType: MarketTypeStr, userAccount: PublicKey): void;
|
|
19
19
|
prependNode(currentNode: DLOBNodeMap[NodeType], newNode: DLOBNodeMap[NodeType]): boolean;
|
|
20
20
|
update(order: Order, userAccount: PublicKey): void;
|
|
21
21
|
remove(order: Order, userAccount: PublicKey): void;
|
package/lib/dlob/NodeList.js
CHANGED
|
@@ -19,17 +19,11 @@ class NodeList {
|
|
|
19
19
|
this.length = 0;
|
|
20
20
|
this.nodeMap.clear();
|
|
21
21
|
}
|
|
22
|
-
insert(order, marketType,
|
|
22
|
+
insert(order, marketType, userAccount) {
|
|
23
23
|
if ((0, __1.isVariant)(order.status, 'init')) {
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
26
|
-
|
|
27
|
-
market = market;
|
|
28
|
-
}
|
|
29
|
-
else if (marketType === 'perp') {
|
|
30
|
-
market = market;
|
|
31
|
-
}
|
|
32
|
-
const newNode = (0, DLOBNode_1.createNode)(this.nodeType, order, market, userAccount);
|
|
26
|
+
const newNode = (0, DLOBNode_1.createNode)(this.nodeType, order, userAccount);
|
|
33
27
|
const orderSignature = getOrderSignature(order.orderId, userAccount);
|
|
34
28
|
if (this.nodeMap.has(orderSignature)) {
|
|
35
29
|
return;
|
|
@@ -135,7 +129,6 @@ function* getVammNodeGenerator(price) {
|
|
|
135
129
|
getPrice: () => price,
|
|
136
130
|
isVammNode: () => true,
|
|
137
131
|
order: undefined,
|
|
138
|
-
market: undefined,
|
|
139
132
|
userAccount: undefined,
|
|
140
133
|
isBaseFilled: () => false,
|
|
141
134
|
haveFilled: false,
|