@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/src/dlob/DLOB.ts
CHANGED
|
@@ -17,17 +17,18 @@ import {
|
|
|
17
17
|
PerpMarketAccount,
|
|
18
18
|
OraclePriceData,
|
|
19
19
|
SlotSubscriber,
|
|
20
|
-
UserMapInterface,
|
|
21
20
|
MarketTypeStr,
|
|
22
21
|
StateAccount,
|
|
23
22
|
isMarketOrder,
|
|
24
23
|
mustBeTriggered,
|
|
25
24
|
isTriggered,
|
|
26
25
|
getLimitPrice,
|
|
26
|
+
UserMap,
|
|
27
27
|
} from '..';
|
|
28
28
|
import { PublicKey } from '@solana/web3.js';
|
|
29
29
|
import { DLOBNode, DLOBNodeType, TriggerOrderNode } from '..';
|
|
30
30
|
import { ammPaused, exchangePaused, fillPaused } from '../math/exchangeStatus';
|
|
31
|
+
import { DLOBOrders } from './DLOBOrders';
|
|
31
32
|
|
|
32
33
|
export type MarketNodeLists = {
|
|
33
34
|
limit: {
|
|
@@ -62,87 +63,14 @@ export type NodeToTrigger = {
|
|
|
62
63
|
export class DLOB {
|
|
63
64
|
openOrders = new Map<MarketTypeStr, Set<string>>();
|
|
64
65
|
orderLists = new Map<MarketTypeStr, Map<number, MarketNodeLists>>();
|
|
65
|
-
stateAccount: StateAccount;
|
|
66
|
-
marketIndexToAccount = new Map<
|
|
67
|
-
MarketTypeStr,
|
|
68
|
-
Map<number, PerpMarketAccount | SpotMarketAccount>
|
|
69
|
-
>();
|
|
70
|
-
|
|
71
|
-
userMap: UserMapInterface;
|
|
72
|
-
silent = false;
|
|
73
|
-
initialized = false;
|
|
74
66
|
|
|
75
|
-
|
|
76
|
-
*
|
|
77
|
-
* @param perpMarkets The perp markets to maintain a DLOB for
|
|
78
|
-
* @param spotMarkets The spot markets to maintain a DLOB for
|
|
79
|
-
* @param userMap map of all users
|
|
80
|
-
* @param silent set to true to prevent logging on inserts and removals
|
|
81
|
-
*/
|
|
82
|
-
public constructor(
|
|
83
|
-
perpMarkets: PerpMarketAccount[],
|
|
84
|
-
spotMarkets: SpotMarketAccount[],
|
|
85
|
-
stateAccount: StateAccount,
|
|
86
|
-
userMap: UserMapInterface,
|
|
87
|
-
silent?: boolean
|
|
88
|
-
) {
|
|
89
|
-
this.stateAccount = stateAccount;
|
|
90
|
-
this.userMap = userMap;
|
|
91
|
-
this.silent = silent;
|
|
67
|
+
initialized = false;
|
|
92
68
|
|
|
69
|
+
public constructor() {
|
|
93
70
|
this.openOrders.set('perp', new Set<string>());
|
|
94
71
|
this.openOrders.set('spot', new Set<string>());
|
|
95
72
|
this.orderLists.set('perp', new Map<number, MarketNodeLists>());
|
|
96
73
|
this.orderLists.set('spot', new Map<number, MarketNodeLists>());
|
|
97
|
-
this.marketIndexToAccount.set('perp', new Map<number, PerpMarketAccount>());
|
|
98
|
-
this.marketIndexToAccount.set('spot', new Map<number, SpotMarketAccount>());
|
|
99
|
-
|
|
100
|
-
for (const market of perpMarkets) {
|
|
101
|
-
const marketIndex = market.marketIndex;
|
|
102
|
-
this.marketIndexToAccount.get('perp').set(marketIndex, market);
|
|
103
|
-
|
|
104
|
-
this.orderLists.get('perp').set(marketIndex, {
|
|
105
|
-
limit: {
|
|
106
|
-
ask: new NodeList('limit', 'asc'),
|
|
107
|
-
bid: new NodeList('limit', 'desc'),
|
|
108
|
-
},
|
|
109
|
-
floatingLimit: {
|
|
110
|
-
ask: new NodeList('floatingLimit', 'asc'),
|
|
111
|
-
bid: new NodeList('floatingLimit', 'desc'),
|
|
112
|
-
},
|
|
113
|
-
market: {
|
|
114
|
-
ask: new NodeList('market', 'asc'),
|
|
115
|
-
bid: new NodeList('market', 'asc'), // always sort ascending for market orders
|
|
116
|
-
},
|
|
117
|
-
trigger: {
|
|
118
|
-
above: new NodeList('trigger', 'asc'),
|
|
119
|
-
below: new NodeList('trigger', 'desc'),
|
|
120
|
-
},
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
for (const market of spotMarkets) {
|
|
124
|
-
const marketIndex = market.marketIndex;
|
|
125
|
-
this.marketIndexToAccount.get('spot').set(marketIndex, market);
|
|
126
|
-
|
|
127
|
-
this.orderLists.get('spot').set(marketIndex, {
|
|
128
|
-
limit: {
|
|
129
|
-
ask: new NodeList('limit', 'asc'),
|
|
130
|
-
bid: new NodeList('limit', 'desc'),
|
|
131
|
-
},
|
|
132
|
-
floatingLimit: {
|
|
133
|
-
ask: new NodeList('floatingLimit', 'asc'),
|
|
134
|
-
bid: new NodeList('floatingLimit', 'desc'),
|
|
135
|
-
},
|
|
136
|
-
market: {
|
|
137
|
-
ask: new NodeList('market', 'asc'),
|
|
138
|
-
bid: new NodeList('market', 'asc'), // always sort ascending for market orders
|
|
139
|
-
},
|
|
140
|
-
trigger: {
|
|
141
|
-
above: new NodeList('trigger', 'asc'),
|
|
142
|
-
below: new NodeList('trigger', 'desc'),
|
|
143
|
-
},
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
74
|
}
|
|
147
75
|
|
|
148
76
|
public clear() {
|
|
@@ -164,11 +92,6 @@ export class DLOB {
|
|
|
164
92
|
}
|
|
165
93
|
}
|
|
166
94
|
this.orderLists.clear();
|
|
167
|
-
|
|
168
|
-
for (const marketType of this.marketIndexToAccount.keys()) {
|
|
169
|
-
this.marketIndexToAccount.get(marketType).clear();
|
|
170
|
-
}
|
|
171
|
-
this.marketIndexToAccount.clear();
|
|
172
95
|
}
|
|
173
96
|
|
|
174
97
|
/**
|
|
@@ -176,13 +99,13 @@ export class DLOB {
|
|
|
176
99
|
*
|
|
177
100
|
* @returns a promise that resolves when the DLOB is initialized
|
|
178
101
|
*/
|
|
179
|
-
public async
|
|
102
|
+
public async initFromUserMap(userMap: UserMap): Promise<boolean> {
|
|
180
103
|
if (this.initialized) {
|
|
181
104
|
return false;
|
|
182
105
|
}
|
|
183
106
|
|
|
184
|
-
// initialize the dlob with the user map
|
|
185
|
-
for (const user of
|
|
107
|
+
// initialize the dlob with the user map
|
|
108
|
+
for (const user of userMap.values()) {
|
|
186
109
|
const userAccount = user.getUserAccount();
|
|
187
110
|
const userAccountPubkey = user.getUserAccountPublicKey();
|
|
188
111
|
|
|
@@ -195,6 +118,19 @@ export class DLOB {
|
|
|
195
118
|
return true;
|
|
196
119
|
}
|
|
197
120
|
|
|
121
|
+
public initFromOrders(dlobOrders: DLOBOrders): boolean {
|
|
122
|
+
if (this.initialized) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
for (const { user, order } of dlobOrders) {
|
|
127
|
+
this.insertOrder(order, user);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
this.initialized = true;
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
|
|
198
134
|
public insertOrder(
|
|
199
135
|
order: Order,
|
|
200
136
|
userAccount: PublicKey,
|
|
@@ -206,23 +142,43 @@ export class DLOB {
|
|
|
206
142
|
|
|
207
143
|
const marketType = getVariant(order.marketType) as MarketTypeStr;
|
|
208
144
|
|
|
145
|
+
if (!this.orderLists.get(marketType).has(order.marketIndex)) {
|
|
146
|
+
this.addOrderList(marketType, order.marketIndex);
|
|
147
|
+
}
|
|
148
|
+
|
|
209
149
|
if (isVariant(order.status, 'open')) {
|
|
210
150
|
this.openOrders
|
|
211
151
|
.get(marketType)
|
|
212
152
|
.add(getOrderSignature(order.orderId, userAccount));
|
|
213
153
|
}
|
|
214
|
-
this.getListForOrder(order)?.insert(
|
|
215
|
-
order,
|
|
216
|
-
marketType,
|
|
217
|
-
this.marketIndexToAccount.get(marketType).get(order.marketIndex),
|
|
218
|
-
userAccount
|
|
219
|
-
);
|
|
154
|
+
this.getListForOrder(order)?.insert(order, marketType, userAccount);
|
|
220
155
|
|
|
221
156
|
if (onInsert) {
|
|
222
157
|
onInsert();
|
|
223
158
|
}
|
|
224
159
|
}
|
|
225
160
|
|
|
161
|
+
addOrderList(marketType: MarketTypeStr, marketIndex: number): void {
|
|
162
|
+
this.orderLists.get(marketType).set(marketIndex, {
|
|
163
|
+
limit: {
|
|
164
|
+
ask: new NodeList('limit', 'asc'),
|
|
165
|
+
bid: new NodeList('limit', 'desc'),
|
|
166
|
+
},
|
|
167
|
+
floatingLimit: {
|
|
168
|
+
ask: new NodeList('floatingLimit', 'asc'),
|
|
169
|
+
bid: new NodeList('floatingLimit', 'desc'),
|
|
170
|
+
},
|
|
171
|
+
market: {
|
|
172
|
+
ask: new NodeList('market', 'asc'),
|
|
173
|
+
bid: new NodeList('market', 'asc'), // always sort ascending for market orders
|
|
174
|
+
},
|
|
175
|
+
trigger: {
|
|
176
|
+
above: new NodeList('trigger', 'asc'),
|
|
177
|
+
below: new NodeList('trigger', 'desc'),
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
226
182
|
public trigger(
|
|
227
183
|
order: Order,
|
|
228
184
|
userAccount: PublicKey,
|
|
@@ -238,12 +194,7 @@ export class DLOB {
|
|
|
238
194
|
.trigger[isVariant(order.triggerCondition, 'above') ? 'above' : 'below'];
|
|
239
195
|
triggerList.remove(order, userAccount);
|
|
240
196
|
|
|
241
|
-
this.getListForOrder(order)?.insert(
|
|
242
|
-
order,
|
|
243
|
-
marketType,
|
|
244
|
-
this.marketIndexToAccount.get(marketType).get(order.marketIndex),
|
|
245
|
-
userAccount
|
|
246
|
-
);
|
|
197
|
+
this.getListForOrder(order)?.insert(order, marketType, userAccount);
|
|
247
198
|
if (onTrigger) {
|
|
248
199
|
onTrigger();
|
|
249
200
|
}
|
|
@@ -289,17 +240,15 @@ export class DLOB {
|
|
|
289
240
|
slot: number,
|
|
290
241
|
ts: number,
|
|
291
242
|
marketType: MarketType,
|
|
292
|
-
oraclePriceData: OraclePriceData
|
|
243
|
+
oraclePriceData: OraclePriceData,
|
|
244
|
+
stateAccount: StateAccount,
|
|
245
|
+
marketAccount: PerpMarketAccount | SpotMarketAccount
|
|
293
246
|
): NodeToFill[] {
|
|
294
|
-
|
|
295
|
-
.get(getVariant(marketType) as MarketTypeStr)
|
|
296
|
-
.get(marketIndex);
|
|
297
|
-
|
|
298
|
-
if (fillPaused(this.stateAccount, marketAccount)) {
|
|
247
|
+
if (fillPaused(stateAccount, marketAccount)) {
|
|
299
248
|
return [];
|
|
300
249
|
}
|
|
301
250
|
|
|
302
|
-
const isAmmPaused = ammPaused(
|
|
251
|
+
const isAmmPaused = ammPaused(stateAccount, marketAccount);
|
|
303
252
|
|
|
304
253
|
const marketOrderNodesToFill: Array<NodeToFill> =
|
|
305
254
|
this.findMarketNodesToFill(
|
|
@@ -517,17 +466,9 @@ export class DLOB {
|
|
|
517
466
|
);
|
|
518
467
|
|
|
519
468
|
for (const makerNode of makerNodeGenerator) {
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
)
|
|
523
|
-
const askUserAuthority = this.userMap.getUserAuthority(
|
|
524
|
-
takerNode.userAccount.toString()
|
|
525
|
-
);
|
|
526
|
-
|
|
527
|
-
// Can't match orders from the same authority
|
|
528
|
-
const sameAuthority = bidUserAuthority.equals(askUserAuthority);
|
|
529
|
-
|
|
530
|
-
if (sameAuthority) {
|
|
469
|
+
// Can't match orders from the same user
|
|
470
|
+
const sameUser = takerNode.userAccount.equals(makerNode.userAccount);
|
|
471
|
+
if (sameUser) {
|
|
531
472
|
continue;
|
|
532
473
|
}
|
|
533
474
|
|
|
@@ -701,10 +642,12 @@ export class DLOB {
|
|
|
701
642
|
marketType: MarketType
|
|
702
643
|
): Generator<DLOBNode> {
|
|
703
644
|
const marketTypeStr = getVariant(marketType) as MarketTypeStr;
|
|
704
|
-
const
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
645
|
+
const orderLists = this.orderLists.get(marketTypeStr).get(marketIndex);
|
|
646
|
+
if (!orderLists) {
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
const generator = orderLists.market.bid.getGenerator();
|
|
708
651
|
for (const marketBidNode of generator) {
|
|
709
652
|
if (marketBidNode.isBaseFilled()) {
|
|
710
653
|
continue;
|
|
@@ -718,10 +661,12 @@ export class DLOB {
|
|
|
718
661
|
marketType: MarketType
|
|
719
662
|
): Generator<DLOBNode> {
|
|
720
663
|
const marketTypeStr = getVariant(marketType) as MarketTypeStr;
|
|
721
|
-
const
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
664
|
+
const orderLists = this.orderLists.get(marketTypeStr).get(marketIndex);
|
|
665
|
+
if (!orderLists) {
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
const generator = orderLists.market.ask.getGenerator();
|
|
725
670
|
for (const marketAskNode of generator) {
|
|
726
671
|
if (marketAskNode.isBaseFilled()) {
|
|
727
672
|
continue;
|
|
@@ -782,17 +727,6 @@ export class DLOB {
|
|
|
782
727
|
continue;
|
|
783
728
|
}
|
|
784
729
|
|
|
785
|
-
// skip order if user is being liquidated/bankrupt
|
|
786
|
-
if (bestGenerator.next.value.userAccount !== undefined) {
|
|
787
|
-
const user = this.userMap.get(
|
|
788
|
-
bestGenerator.next.value.userAccount.toString()
|
|
789
|
-
);
|
|
790
|
-
if (user?.isBeingLiquidated()) {
|
|
791
|
-
bestGenerator.next = bestGenerator.generator.next();
|
|
792
|
-
continue;
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
|
|
796
730
|
yield bestGenerator.next.value;
|
|
797
731
|
bestGenerator.next = bestGenerator.generator.next();
|
|
798
732
|
} else {
|
|
@@ -813,6 +747,10 @@ export class DLOB {
|
|
|
813
747
|
const marketTypeStr = getVariant(marketType) as MarketTypeStr;
|
|
814
748
|
const nodeLists = this.orderLists.get(marketTypeStr).get(marketIndex);
|
|
815
749
|
|
|
750
|
+
if (!nodeLists) {
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
|
|
816
754
|
const generatorList = [
|
|
817
755
|
nodeLists.limit.ask.getGenerator(),
|
|
818
756
|
nodeLists.floatingLimit.ask.getGenerator(),
|
|
@@ -841,6 +779,10 @@ export class DLOB {
|
|
|
841
779
|
const marketTypeStr = getVariant(marketType) as MarketTypeStr;
|
|
842
780
|
const nodeLists = this.orderLists.get(marketTypeStr).get(marketIndex);
|
|
843
781
|
|
|
782
|
+
if (!nodeLists) {
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
|
|
844
786
|
const generatorList = [
|
|
845
787
|
nodeLists.limit.bid.getGenerator(),
|
|
846
788
|
nodeLists.floatingLimit.bid.getGenerator(),
|
|
@@ -949,16 +891,9 @@ export class DLOB {
|
|
|
949
891
|
const bidOrder = bidNode.order;
|
|
950
892
|
const askOrder = askNode.order;
|
|
951
893
|
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
)
|
|
955
|
-
const askUserAuthority = this.userMap.getUserAuthority(
|
|
956
|
-
askNode.userAccount.toString()
|
|
957
|
-
);
|
|
958
|
-
|
|
959
|
-
// Can't match orders from the same authority
|
|
960
|
-
const sameAuthority = bidUserAuthority.equals(askUserAuthority);
|
|
961
|
-
if (sameAuthority || (bidOrder.postOnly && askOrder.postOnly)) {
|
|
894
|
+
// Can't match orders from the same user
|
|
895
|
+
const sameUser = bidNode.userAccount.equals(askNode.userAccount);
|
|
896
|
+
if (sameUser || (bidOrder.postOnly && askOrder.postOnly)) {
|
|
962
897
|
continue;
|
|
963
898
|
}
|
|
964
899
|
|
|
@@ -1074,9 +1009,10 @@ export class DLOB {
|
|
|
1074
1009
|
marketIndex: number,
|
|
1075
1010
|
slot: number,
|
|
1076
1011
|
oraclePrice: BN,
|
|
1077
|
-
marketType: MarketType
|
|
1012
|
+
marketType: MarketType,
|
|
1013
|
+
stateAccount: StateAccount
|
|
1078
1014
|
): NodeToTrigger[] {
|
|
1079
|
-
if (exchangePaused(
|
|
1015
|
+
if (exchangePaused(stateAccount)) {
|
|
1080
1016
|
return [];
|
|
1081
1017
|
}
|
|
1082
1018
|
|
|
@@ -1216,4 +1152,88 @@ export class DLOB {
|
|
|
1216
1152
|
);
|
|
1217
1153
|
}
|
|
1218
1154
|
}
|
|
1155
|
+
|
|
1156
|
+
public getDLOBOrders(): DLOBOrders {
|
|
1157
|
+
let dlobOrders: DLOBOrders = [];
|
|
1158
|
+
|
|
1159
|
+
for (const [marketIndex, nodeLists] of this.orderLists.get('perp')) {
|
|
1160
|
+
dlobOrders = dlobOrders.concat(
|
|
1161
|
+
this.getOrdersForMarket(marketIndex, MarketType.PERP, nodeLists)
|
|
1162
|
+
);
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
for (const [marketIndex, nodeLists] of this.orderLists.get('spot')) {
|
|
1166
|
+
dlobOrders = dlobOrders.concat(
|
|
1167
|
+
this.getOrdersForMarket(marketIndex, MarketType.SPOT, nodeLists)
|
|
1168
|
+
);
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
return dlobOrders;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
getOrdersForMarket(
|
|
1175
|
+
marketIndex: number,
|
|
1176
|
+
marketType: MarketType,
|
|
1177
|
+
nodeLists: MarketNodeLists
|
|
1178
|
+
): DLOBOrders {
|
|
1179
|
+
const orders: { user: PublicKey; order: Order }[] = [];
|
|
1180
|
+
|
|
1181
|
+
for (const node of nodeLists.limit.bid.getGenerator()) {
|
|
1182
|
+
orders.push({
|
|
1183
|
+
user: node.userAccount,
|
|
1184
|
+
order: node.order,
|
|
1185
|
+
});
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
for (const node of nodeLists.limit.ask.getGenerator()) {
|
|
1189
|
+
orders.push({
|
|
1190
|
+
user: node.userAccount,
|
|
1191
|
+
order: node.order,
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
for (const node of nodeLists.market.bid.getGenerator()) {
|
|
1196
|
+
orders.push({
|
|
1197
|
+
user: node.userAccount,
|
|
1198
|
+
order: node.order,
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
for (const node of nodeLists.market.ask.getGenerator()) {
|
|
1203
|
+
orders.push({
|
|
1204
|
+
user: node.userAccount,
|
|
1205
|
+
order: node.order,
|
|
1206
|
+
});
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
for (const node of nodeLists.floatingLimit.bid.getGenerator()) {
|
|
1210
|
+
orders.push({
|
|
1211
|
+
user: node.userAccount,
|
|
1212
|
+
order: node.order,
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
for (const node of nodeLists.floatingLimit.ask.getGenerator()) {
|
|
1217
|
+
orders.push({
|
|
1218
|
+
user: node.userAccount,
|
|
1219
|
+
order: node.order,
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
for (const node of nodeLists.trigger.below.getGenerator()) {
|
|
1224
|
+
orders.push({
|
|
1225
|
+
user: node.userAccount,
|
|
1226
|
+
order: node.order,
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
for (const node of nodeLists.trigger.above.getGenerator()) {
|
|
1231
|
+
orders.push({
|
|
1232
|
+
user: node.userAccount,
|
|
1233
|
+
order: node.order,
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
return orders;
|
|
1238
|
+
}
|
|
1219
1239
|
}
|
package/src/dlob/DLOBNode.ts
CHANGED
|
@@ -4,8 +4,6 @@ import {
|
|
|
4
4
|
convertToNumber,
|
|
5
5
|
getLimitPrice,
|
|
6
6
|
isVariant,
|
|
7
|
-
SpotMarketAccount,
|
|
8
|
-
PerpMarketAccount,
|
|
9
7
|
PRICE_PRECISION,
|
|
10
8
|
OraclePriceData,
|
|
11
9
|
Order,
|
|
@@ -21,24 +19,17 @@ export interface DLOBNode {
|
|
|
21
19
|
isBaseFilled(): boolean;
|
|
22
20
|
haveFilled: boolean;
|
|
23
21
|
userAccount: PublicKey | undefined;
|
|
24
|
-
market: SpotMarketAccount | PerpMarketAccount;
|
|
25
22
|
}
|
|
26
23
|
|
|
27
24
|
export abstract class OrderNode implements DLOBNode {
|
|
28
25
|
order: Order;
|
|
29
|
-
market: SpotMarketAccount | PerpMarketAccount;
|
|
30
26
|
userAccount: PublicKey;
|
|
31
27
|
sortValue: BN;
|
|
32
28
|
haveFilled = false;
|
|
33
29
|
haveTrigger = false;
|
|
34
30
|
|
|
35
|
-
constructor(
|
|
36
|
-
order: Order,
|
|
37
|
-
market: SpotMarketAccount | PerpMarketAccount,
|
|
38
|
-
userAccount: PublicKey
|
|
39
|
-
) {
|
|
31
|
+
constructor(order: Order, userAccount: PublicKey) {
|
|
40
32
|
this.order = order;
|
|
41
|
-
this.market = market;
|
|
42
33
|
this.userAccount = userAccount;
|
|
43
34
|
this.sortValue = this.getSortValue(order);
|
|
44
35
|
}
|
|
@@ -137,18 +128,17 @@ export type DLOBNodeType =
|
|
|
137
128
|
export function createNode<T extends DLOBNodeType>(
|
|
138
129
|
nodeType: T,
|
|
139
130
|
order: Order,
|
|
140
|
-
market: SpotMarketAccount | PerpMarketAccount,
|
|
141
131
|
userAccount: PublicKey
|
|
142
132
|
): DLOBNodeMap[T] {
|
|
143
133
|
switch (nodeType) {
|
|
144
134
|
case 'floatingLimit':
|
|
145
|
-
return new FloatingLimitOrderNode(order,
|
|
135
|
+
return new FloatingLimitOrderNode(order, userAccount);
|
|
146
136
|
case 'limit':
|
|
147
|
-
return new LimitOrderNode(order,
|
|
137
|
+
return new LimitOrderNode(order, userAccount);
|
|
148
138
|
case 'market':
|
|
149
|
-
return new MarketOrderNode(order,
|
|
139
|
+
return new MarketOrderNode(order, userAccount);
|
|
150
140
|
case 'trigger':
|
|
151
|
-
return new TriggerOrderNode(order,
|
|
141
|
+
return new TriggerOrderNode(order, userAccount);
|
|
152
142
|
default:
|
|
153
143
|
throw Error(`Unknown DLOBNode type ${nodeType}`);
|
|
154
144
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { PublicKey } from '@solana/web3.js';
|
|
2
|
+
import { Idl } from '@project-serum/anchor';
|
|
3
|
+
import { IdlCoder } from '@project-serum/anchor/dist/cjs/coder/borsh/idl';
|
|
4
|
+
import dlobIDL from './dlobIdl.json';
|
|
5
|
+
import { Order } from '../types';
|
|
6
|
+
|
|
7
|
+
export type DLOBOrder = { user: PublicKey; order: Order };
|
|
8
|
+
|
|
9
|
+
export type DLOBOrders = DLOBOrder[];
|
|
10
|
+
|
|
11
|
+
export class DLOBOrdersCoder {
|
|
12
|
+
public constructor(private idl: Idl) {}
|
|
13
|
+
|
|
14
|
+
static create(): DLOBOrdersCoder {
|
|
15
|
+
return new DLOBOrdersCoder(dlobIDL as Idl);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public encode(dlobOrders: DLOBOrders): Buffer {
|
|
19
|
+
const layout = IdlCoder.fieldLayout(
|
|
20
|
+
{
|
|
21
|
+
type: {
|
|
22
|
+
vec: {
|
|
23
|
+
defined: 'DLOBOrder',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
this.idl.types
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const size = 150 * dlobOrders.length;
|
|
31
|
+
const buffer = Buffer.alloc(size);
|
|
32
|
+
const len = layout.encode(dlobOrders, buffer);
|
|
33
|
+
return buffer.slice(0, len);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public decode(buffer: Buffer): DLOBOrders {
|
|
37
|
+
const layout = IdlCoder.fieldLayout(
|
|
38
|
+
{
|
|
39
|
+
type: {
|
|
40
|
+
vec: {
|
|
41
|
+
defined: 'DLOBOrder',
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
this.idl.types
|
|
46
|
+
);
|
|
47
|
+
return layout.decode(buffer) as DLOBOrders;
|
|
48
|
+
}
|
|
49
|
+
}
|
package/src/dlob/NodeList.ts
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BN,
|
|
3
|
-
isVariant,
|
|
4
|
-
MarketTypeStr,
|
|
5
|
-
Order,
|
|
6
|
-
PerpMarketAccount,
|
|
7
|
-
SpotMarketAccount,
|
|
8
|
-
} from '..';
|
|
1
|
+
import { BN, isVariant, MarketTypeStr, Order } from '..';
|
|
9
2
|
import { PublicKey } from '@solana/web3.js';
|
|
10
3
|
import { createNode, DLOBNode, DLOBNodeMap } from './DLOBNode';
|
|
11
4
|
|
|
@@ -43,20 +36,13 @@ export class NodeList<NodeType extends keyof DLOBNodeMap>
|
|
|
43
36
|
public insert(
|
|
44
37
|
order: Order,
|
|
45
38
|
marketType: MarketTypeStr,
|
|
46
|
-
market: PerpMarketAccount | SpotMarketAccount,
|
|
47
39
|
userAccount: PublicKey
|
|
48
40
|
): void {
|
|
49
41
|
if (isVariant(order.status, 'init')) {
|
|
50
42
|
return;
|
|
51
43
|
}
|
|
52
44
|
|
|
53
|
-
|
|
54
|
-
market = market as SpotMarketAccount;
|
|
55
|
-
} else if (marketType === 'perp') {
|
|
56
|
-
market = market as PerpMarketAccount;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const newNode = createNode(this.nodeType, order, market, userAccount);
|
|
45
|
+
const newNode = createNode(this.nodeType, order, userAccount);
|
|
60
46
|
|
|
61
47
|
const orderSignature = getOrderSignature(order.orderId, userAccount);
|
|
62
48
|
if (this.nodeMap.has(orderSignature)) {
|
|
@@ -187,7 +173,6 @@ export function* getVammNodeGenerator(
|
|
|
187
173
|
getPrice: () => price,
|
|
188
174
|
isVammNode: () => true,
|
|
189
175
|
order: undefined,
|
|
190
|
-
market: undefined,
|
|
191
176
|
userAccount: undefined,
|
|
192
177
|
isBaseFilled: () => false,
|
|
193
178
|
haveFilled: false,
|