@drift-labs/sdk 2.65.0-beta.0 → 2.65.0-beta.10
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/VERSION +1 -1
- package/lib/adminClient.js +83 -44
- package/lib/constants/spotMarkets.js +1 -0
- package/lib/dlob/orderBookLevels.js +35 -7
- package/lib/driftClient.js +17 -9
- package/lib/jupiter/jupiterClient.js +5 -2
- package/lib/userMap/userMap.d.ts +13 -3
- package/lib/userMap/userMap.js +46 -15
- package/package.json +1 -1
- package/src/adminClient.ts +364 -261
- package/src/constants/spotMarkets.ts +3 -0
- package/src/dlob/orderBookLevels.ts +43 -7
- package/src/driftClient.ts +24 -13
- package/src/jupiter/jupiterClient.ts +8 -3
- package/src/userMap/userMap.ts +79 -26
- package/tests/dlob/test.ts +147 -0
|
@@ -137,6 +137,9 @@ export const MainnetSpotMarkets: SpotMarketConfig[] = [
|
|
|
137
137
|
precision: new BN(10).pow(NINE),
|
|
138
138
|
precisionExp: NINE,
|
|
139
139
|
serumMarket: new PublicKey('DkbVbMhFxswS32xnn1K2UY4aoBugXooBTxdzkWWDWRkH'),
|
|
140
|
+
phoenixMarket: new PublicKey(
|
|
141
|
+
'5LQLfGtqcC5rm2WuGxJf4tjqYmDjsQAbKo2AMLQ8KB7p'
|
|
142
|
+
),
|
|
140
143
|
},
|
|
141
144
|
{
|
|
142
145
|
symbol: 'PYTH',
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
calculateSpreadReserves,
|
|
8
8
|
calculateUpdatedAMM,
|
|
9
9
|
DLOBNode,
|
|
10
|
+
isVariant,
|
|
10
11
|
OraclePriceData,
|
|
11
12
|
PerpMarketAccount,
|
|
12
13
|
PositionDirection,
|
|
@@ -492,6 +493,19 @@ export function uncrossL2(
|
|
|
492
493
|
|
|
493
494
|
let bidIndex = 0;
|
|
494
495
|
let askIndex = 0;
|
|
496
|
+
let maxBid: BN;
|
|
497
|
+
let minAsk: BN;
|
|
498
|
+
|
|
499
|
+
const getPriceAndSetBound = (newPrice: BN, direction: PositionDirection) => {
|
|
500
|
+
if (isVariant(direction, 'long')) {
|
|
501
|
+
maxBid = maxBid ? BN.min(maxBid, newPrice) : newPrice;
|
|
502
|
+
return maxBid;
|
|
503
|
+
} else {
|
|
504
|
+
minAsk = minAsk ? BN.max(minAsk, newPrice) : newPrice;
|
|
505
|
+
return minAsk;
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
|
|
495
509
|
while (bidIndex < bids.length || askIndex < asks.length) {
|
|
496
510
|
const nextBid = cloneL2Level(bids[bidIndex]);
|
|
497
511
|
const nextAsk = cloneL2Level(asks[askIndex]);
|
|
@@ -508,7 +522,7 @@ export function uncrossL2(
|
|
|
508
522
|
continue;
|
|
509
523
|
}
|
|
510
524
|
|
|
511
|
-
if (nextBid.price.
|
|
525
|
+
if (nextBid.price.gte(nextAsk.price)) {
|
|
512
526
|
if (userBids.has(nextBid.price.toString())) {
|
|
513
527
|
newBids.push(nextBid);
|
|
514
528
|
bidIndex++;
|
|
@@ -525,29 +539,51 @@ export function uncrossL2(
|
|
|
525
539
|
nextBid.price.gt(referencePrice) &&
|
|
526
540
|
nextAsk.price.gt(referencePrice)
|
|
527
541
|
) {
|
|
528
|
-
|
|
542
|
+
let newBidPrice = nextAsk.price.sub(grouping);
|
|
543
|
+
newBidPrice = getPriceAndSetBound(newBidPrice, PositionDirection.LONG);
|
|
529
544
|
updateLevels(newBidPrice, nextBid, newBids);
|
|
530
545
|
bidIndex++;
|
|
531
546
|
} else if (
|
|
532
547
|
nextAsk.price.lt(referencePrice) &&
|
|
533
548
|
nextBid.price.lt(referencePrice)
|
|
534
549
|
) {
|
|
535
|
-
|
|
550
|
+
let newAskPrice = nextBid.price.add(grouping);
|
|
551
|
+
newAskPrice = getPriceAndSetBound(newAskPrice, PositionDirection.SHORT);
|
|
536
552
|
updateLevels(newAskPrice, nextAsk, newAsks);
|
|
537
553
|
askIndex++;
|
|
538
554
|
} else {
|
|
539
|
-
|
|
540
|
-
|
|
555
|
+
let newBidPrice = referencePrice.sub(grouping);
|
|
556
|
+
let newAskPrice = referencePrice.add(grouping);
|
|
557
|
+
|
|
558
|
+
newBidPrice = getPriceAndSetBound(newBidPrice, PositionDirection.LONG);
|
|
559
|
+
newAskPrice = getPriceAndSetBound(newAskPrice, PositionDirection.SHORT);
|
|
560
|
+
|
|
541
561
|
updateLevels(newBidPrice, nextBid, newBids);
|
|
542
562
|
updateLevels(newAskPrice, nextAsk, newAsks);
|
|
543
563
|
bidIndex++;
|
|
544
564
|
askIndex++;
|
|
545
565
|
}
|
|
546
566
|
} else {
|
|
547
|
-
|
|
567
|
+
if (minAsk && nextAsk.price.lte(minAsk)) {
|
|
568
|
+
const newAskPrice = getPriceAndSetBound(
|
|
569
|
+
nextAsk.price,
|
|
570
|
+
PositionDirection.SHORT
|
|
571
|
+
);
|
|
572
|
+
updateLevels(newAskPrice, nextAsk, newAsks);
|
|
573
|
+
} else {
|
|
574
|
+
newAsks.push(nextAsk);
|
|
575
|
+
}
|
|
548
576
|
askIndex++;
|
|
549
577
|
|
|
550
|
-
|
|
578
|
+
if (maxBid && nextBid.price.gte(maxBid)) {
|
|
579
|
+
const newBidPrice = getPriceAndSetBound(
|
|
580
|
+
nextBid.price,
|
|
581
|
+
PositionDirection.LONG
|
|
582
|
+
);
|
|
583
|
+
updateLevels(newBidPrice, nextBid, newBids);
|
|
584
|
+
} else {
|
|
585
|
+
newBids.push(nextBid);
|
|
586
|
+
}
|
|
551
587
|
bidIndex++;
|
|
552
588
|
}
|
|
553
589
|
}
|
package/src/driftClient.ts
CHANGED
|
@@ -693,25 +693,36 @@ export class DriftClient {
|
|
|
693
693
|
);
|
|
694
694
|
}
|
|
695
695
|
} else {
|
|
696
|
-
|
|
697
|
-
(await this.getUserAccountsForAuthority(this.wallet.publicKey)) ?? [];
|
|
696
|
+
let userAccounts = [];
|
|
698
697
|
let delegatedAccounts = [];
|
|
699
698
|
|
|
699
|
+
const userAccountsPromise = this.getUserAccountsForAuthority(
|
|
700
|
+
this.wallet.publicKey
|
|
701
|
+
);
|
|
702
|
+
|
|
700
703
|
if (this.includeDelegates) {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
+
const delegatedAccountsPromise = this.getUserAccountsForDelegate(
|
|
705
|
+
this.wallet.publicKey
|
|
706
|
+
);
|
|
707
|
+
[userAccounts, delegatedAccounts] = await Promise.all([
|
|
708
|
+
userAccountsPromise,
|
|
709
|
+
delegatedAccountsPromise,
|
|
710
|
+
]);
|
|
704
711
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
account.subAccountId,
|
|
710
|
-
account.authority,
|
|
711
|
-
account
|
|
712
|
-
));
|
|
712
|
+
!userAccounts && (userAccounts = []);
|
|
713
|
+
!delegatedAccounts && (delegatedAccounts = []);
|
|
714
|
+
} else {
|
|
715
|
+
userAccounts = (await userAccountsPromise) ?? [];
|
|
713
716
|
}
|
|
714
717
|
|
|
718
|
+
const allAccounts = userAccounts.concat(delegatedAccounts);
|
|
719
|
+
const addAllAccountsPromise = allAccounts.map((acc) =>
|
|
720
|
+
this.addUser(acc.subAccountId, acc.authority, acc)
|
|
721
|
+
);
|
|
722
|
+
|
|
723
|
+
const addAllAccountsResults = await Promise.all(addAllAccountsPromise);
|
|
724
|
+
result = addAllAccountsResults.every((res) => !!res);
|
|
725
|
+
|
|
715
726
|
if (this.activeSubAccountId == undefined) {
|
|
716
727
|
this.switchActiveUser(
|
|
717
728
|
userAccounts.concat(delegatedAccounts)[0]?.subAccountId ?? 0,
|
|
@@ -305,9 +305,14 @@ export class JupiterClient {
|
|
|
305
305
|
onlyDirectRoutes: onlyDirectRoutes.toString(),
|
|
306
306
|
maxAccounts: maxAccounts.toString(),
|
|
307
307
|
...(excludeDexes && { excludeDexes: excludeDexes.join(',') }),
|
|
308
|
-
})
|
|
309
|
-
|
|
310
|
-
|
|
308
|
+
});
|
|
309
|
+
if (swapMode === 'ExactOut') {
|
|
310
|
+
params.delete('maxAccounts');
|
|
311
|
+
}
|
|
312
|
+
const quote = await (
|
|
313
|
+
await fetch(`${this.url}/v6/quote?${params.toString()}`)
|
|
314
|
+
).json();
|
|
315
|
+
return quote as QuoteResponse;
|
|
311
316
|
}
|
|
312
317
|
|
|
313
318
|
/**
|
package/src/userMap/userMap.ts
CHANGED
|
@@ -13,9 +13,10 @@ import {
|
|
|
13
13
|
LPRecord,
|
|
14
14
|
StateAccount,
|
|
15
15
|
DLOB,
|
|
16
|
-
OneShotUserAccountSubscriber,
|
|
17
16
|
BN,
|
|
18
17
|
UserSubscriptionConfig,
|
|
18
|
+
DataAndSlot,
|
|
19
|
+
OneShotUserAccountSubscriber,
|
|
19
20
|
} from '..';
|
|
20
21
|
|
|
21
22
|
import {
|
|
@@ -37,17 +38,33 @@ import { decodeUser } from '../decode/user';
|
|
|
37
38
|
export interface UserMapInterface {
|
|
38
39
|
subscribe(): Promise<void>;
|
|
39
40
|
unsubscribe(): Promise<void>;
|
|
40
|
-
addPubkey(
|
|
41
|
+
addPubkey(
|
|
42
|
+
userAccountPublicKey: PublicKey,
|
|
43
|
+
userAccount?: UserAccount,
|
|
44
|
+
slot?: number,
|
|
45
|
+
accountSubscription?: UserSubscriptionConfig
|
|
46
|
+
): Promise<void>;
|
|
41
47
|
has(key: string): boolean;
|
|
42
48
|
get(key: string): User | undefined;
|
|
43
|
-
|
|
49
|
+
getWithSlot(key: string): DataAndSlot<User> | undefined;
|
|
50
|
+
mustGet(
|
|
51
|
+
key: string,
|
|
52
|
+
accountSubscription?: UserSubscriptionConfig
|
|
53
|
+
): Promise<User>;
|
|
54
|
+
mustGetWithSlot(
|
|
55
|
+
key: string,
|
|
56
|
+
accountSubscription?: UserSubscriptionConfig
|
|
57
|
+
): Promise<DataAndSlot<User>>;
|
|
44
58
|
getUserAuthority(key: string): PublicKey | undefined;
|
|
45
59
|
updateWithOrderRecord(record: OrderRecord): Promise<void>;
|
|
46
60
|
values(): IterableIterator<User>;
|
|
61
|
+
valuesWithSlot(): IterableIterator<DataAndSlot<User>>;
|
|
62
|
+
entries(): IterableIterator<[string, User]>;
|
|
63
|
+
entriesWithSlot(): IterableIterator<[string, DataAndSlot<User>]>;
|
|
47
64
|
}
|
|
48
65
|
|
|
49
66
|
export class UserMap implements UserMapInterface {
|
|
50
|
-
private userMap = new Map<string, User
|
|
67
|
+
private userMap = new Map<string, DataAndSlot<User>>();
|
|
51
68
|
driftClient: DriftClient;
|
|
52
69
|
private connection: Connection;
|
|
53
70
|
private commitment: Commitment;
|
|
@@ -140,6 +157,7 @@ export class UserMap implements UserMapInterface {
|
|
|
140
157
|
userAccountPublicKey,
|
|
141
158
|
accountSubscription: accountSubscription ?? {
|
|
142
159
|
type: 'custom',
|
|
160
|
+
// OneShotUserAccountSubscriber used here so we don't load up the RPC with AccountSubscribes
|
|
143
161
|
userAccountSubscriber: new OneShotUserAccountSubscriber(
|
|
144
162
|
this.driftClient.program,
|
|
145
163
|
userAccountPublicKey,
|
|
@@ -150,7 +168,10 @@ export class UserMap implements UserMapInterface {
|
|
|
150
168
|
},
|
|
151
169
|
});
|
|
152
170
|
await user.subscribe(userAccount);
|
|
153
|
-
this.userMap.set(userAccountPublicKey.toString(),
|
|
171
|
+
this.userMap.set(userAccountPublicKey.toString(), {
|
|
172
|
+
data: user,
|
|
173
|
+
slot: slot ?? user.getUserAccountAndSlot()?.slot,
|
|
174
|
+
});
|
|
154
175
|
}
|
|
155
176
|
|
|
156
177
|
public has(key: string): boolean {
|
|
@@ -163,6 +184,9 @@ export class UserMap implements UserMapInterface {
|
|
|
163
184
|
* @returns user User | undefined
|
|
164
185
|
*/
|
|
165
186
|
public get(key: string): User | undefined {
|
|
187
|
+
return this.userMap.get(key)?.data;
|
|
188
|
+
}
|
|
189
|
+
public getWithSlot(key: string): DataAndSlot<User> | undefined {
|
|
166
190
|
return this.userMap.get(key);
|
|
167
191
|
}
|
|
168
192
|
|
|
@@ -183,8 +207,21 @@ export class UserMap implements UserMapInterface {
|
|
|
183
207
|
accountSubscription
|
|
184
208
|
);
|
|
185
209
|
}
|
|
186
|
-
|
|
187
|
-
|
|
210
|
+
return this.userMap.get(key).data;
|
|
211
|
+
}
|
|
212
|
+
public async mustGetWithSlot(
|
|
213
|
+
key: string,
|
|
214
|
+
accountSubscription?: UserSubscriptionConfig
|
|
215
|
+
): Promise<DataAndSlot<User>> {
|
|
216
|
+
if (!this.has(key)) {
|
|
217
|
+
await this.addPubkey(
|
|
218
|
+
new PublicKey(key),
|
|
219
|
+
undefined,
|
|
220
|
+
undefined,
|
|
221
|
+
accountSubscription
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
return this.userMap.get(key);
|
|
188
225
|
}
|
|
189
226
|
|
|
190
227
|
/**
|
|
@@ -193,11 +230,11 @@ export class UserMap implements UserMapInterface {
|
|
|
193
230
|
* @returns authority PublicKey | undefined
|
|
194
231
|
*/
|
|
195
232
|
public getUserAuthority(key: string): PublicKey | undefined {
|
|
196
|
-
const
|
|
197
|
-
if (!
|
|
233
|
+
const user = this.userMap.get(key);
|
|
234
|
+
if (!user) {
|
|
198
235
|
return undefined;
|
|
199
236
|
}
|
|
200
|
-
return
|
|
237
|
+
return user.data.getUserAccount().authority;
|
|
201
238
|
}
|
|
202
239
|
|
|
203
240
|
/**
|
|
@@ -253,10 +290,24 @@ export class UserMap implements UserMapInterface {
|
|
|
253
290
|
}
|
|
254
291
|
}
|
|
255
292
|
|
|
256
|
-
public values(): IterableIterator<User> {
|
|
293
|
+
public *values(): IterableIterator<User> {
|
|
294
|
+
for (const dataAndSlot of this.userMap.values()) {
|
|
295
|
+
yield dataAndSlot.data;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
public valuesWithSlot(): IterableIterator<DataAndSlot<User>> {
|
|
257
299
|
return this.userMap.values();
|
|
258
300
|
}
|
|
259
301
|
|
|
302
|
+
public *entries(): IterableIterator<[string, User]> {
|
|
303
|
+
for (const [key, dataAndSlot] of this.userMap.entries()) {
|
|
304
|
+
yield [key, dataAndSlot.data];
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
public entriesWithSlot(): IterableIterator<[string, DataAndSlot<User>]> {
|
|
308
|
+
return this.userMap.entries();
|
|
309
|
+
}
|
|
310
|
+
|
|
260
311
|
public size(): number {
|
|
261
312
|
return this.userMap.size;
|
|
262
313
|
}
|
|
@@ -269,15 +320,13 @@ export class UserMap implements UserMapInterface {
|
|
|
269
320
|
public getUniqueAuthorities(
|
|
270
321
|
filterCriteria?: UserFilterCriteria
|
|
271
322
|
): PublicKey[] {
|
|
272
|
-
const usersMeetingCriteria = Array.from(this.
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
pass = pass && user.getUserAccount().hasOpenOrder;
|
|
277
|
-
}
|
|
278
|
-
return pass;
|
|
323
|
+
const usersMeetingCriteria = Array.from(this.values()).filter((user) => {
|
|
324
|
+
let pass = true;
|
|
325
|
+
if (filterCriteria && filterCriteria.hasOpenOrders) {
|
|
326
|
+
pass = pass && user.getUserAccount().hasOpenOrder;
|
|
279
327
|
}
|
|
280
|
-
|
|
328
|
+
return pass;
|
|
329
|
+
});
|
|
281
330
|
const userAuths = new Set(
|
|
282
331
|
usersMeetingCriteria.map((user) =>
|
|
283
332
|
user.getUserAccount().authority.toBase58()
|
|
@@ -345,17 +394,17 @@ export class UserMap implements UserMapInterface {
|
|
|
345
394
|
for (const [key, buffer] of programAccountBufferMap.entries()) {
|
|
346
395
|
if (!this.has(key)) {
|
|
347
396
|
const userAccount = this.decode('User', buffer);
|
|
348
|
-
await this.addPubkey(new PublicKey(key), userAccount);
|
|
349
|
-
this.
|
|
397
|
+
await this.addPubkey(new PublicKey(key), userAccount, slot);
|
|
398
|
+
this.get(key).accountSubscriber.updateData(userAccount, slot);
|
|
350
399
|
} else {
|
|
351
400
|
const userAccount = this.decode('User', buffer);
|
|
352
|
-
this.
|
|
401
|
+
this.get(key).accountSubscriber.updateData(userAccount, slot);
|
|
353
402
|
}
|
|
354
403
|
// give event loop a chance to breathe
|
|
355
404
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
356
405
|
}
|
|
357
406
|
|
|
358
|
-
for (const [key, user] of this.
|
|
407
|
+
for (const [key, user] of this.entries()) {
|
|
359
408
|
if (!programAccountBufferMap.has(key)) {
|
|
360
409
|
await user.unsubscribe();
|
|
361
410
|
this.userMap.delete(key);
|
|
@@ -375,7 +424,7 @@ export class UserMap implements UserMapInterface {
|
|
|
375
424
|
public async unsubscribe() {
|
|
376
425
|
await this.subscription.unsubscribe();
|
|
377
426
|
|
|
378
|
-
for (const [key, user] of this.
|
|
427
|
+
for (const [key, user] of this.entries()) {
|
|
379
428
|
await user.unsubscribe();
|
|
380
429
|
this.userMap.delete(key);
|
|
381
430
|
}
|
|
@@ -398,11 +447,15 @@ export class UserMap implements UserMapInterface {
|
|
|
398
447
|
slot: number
|
|
399
448
|
) {
|
|
400
449
|
this.updateLatestSlot(slot);
|
|
401
|
-
if (!this.
|
|
450
|
+
if (!this.has(key)) {
|
|
402
451
|
this.addPubkey(new PublicKey(key), userAccount, slot);
|
|
403
452
|
} else {
|
|
404
|
-
const user = this.
|
|
453
|
+
const user = this.get(key);
|
|
405
454
|
user.accountSubscriber.updateData(userAccount, slot);
|
|
455
|
+
this.userMap.set(key, {
|
|
456
|
+
data: user,
|
|
457
|
+
slot,
|
|
458
|
+
});
|
|
406
459
|
}
|
|
407
460
|
}
|
|
408
461
|
|
package/tests/dlob/test.ts
CHANGED
|
@@ -24,11 +24,32 @@ import {
|
|
|
24
24
|
QUOTE_PRECISION,
|
|
25
25
|
isVariant,
|
|
26
26
|
uncrossL2,
|
|
27
|
+
L2Level,
|
|
27
28
|
} from '../../src';
|
|
28
29
|
|
|
29
30
|
import { mockPerpMarkets, mockSpotMarkets, mockStateAccount } from './helpers';
|
|
30
31
|
import { DLOBOrdersCoder } from '../../src/dlob/DLOBOrders';
|
|
31
32
|
|
|
33
|
+
// Returns true if asks are sorted ascending
|
|
34
|
+
const asksAreSortedAsc = (asks: L2Level[]) => {
|
|
35
|
+
return asks.every((ask, i) => {
|
|
36
|
+
if (i === 0) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
return ask.price.gt(asks[i - 1].price);
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Returns true if asks are sorted descending
|
|
44
|
+
const bidsAreSortedDesc = (bids: L2Level[]) => {
|
|
45
|
+
return bids.every((bid, i) => {
|
|
46
|
+
if (i === 0) {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
return bid.price.lt(bids[i - 1].price);
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
|
|
32
53
|
function insertOrderToDLOB(
|
|
33
54
|
dlob: DLOB,
|
|
34
55
|
userAccount: PublicKey,
|
|
@@ -6592,4 +6613,130 @@ describe('Uncross L2', () => {
|
|
|
6592
6613
|
new BN(1).mul(BASE_PRECISION).toString()
|
|
6593
6614
|
);
|
|
6594
6615
|
});
|
|
6616
|
+
|
|
6617
|
+
it('Handles edge case bide and asks with large cross and an overlapping level', () => {
|
|
6618
|
+
const bids = [
|
|
6619
|
+
'104411000',
|
|
6620
|
+
'103835800',
|
|
6621
|
+
'103826259',
|
|
6622
|
+
'103825000',
|
|
6623
|
+
'103822000',
|
|
6624
|
+
'103821500',
|
|
6625
|
+
'103820283',
|
|
6626
|
+
'103816900',
|
|
6627
|
+
'103816000',
|
|
6628
|
+
'103815121',
|
|
6629
|
+
].map((priceStr) => ({
|
|
6630
|
+
price: new BN(priceStr),
|
|
6631
|
+
size: new BN(1).mul(BASE_PRECISION),
|
|
6632
|
+
sources: { vamm: new BN(1).mul(BASE_PRECISION) },
|
|
6633
|
+
}));
|
|
6634
|
+
|
|
6635
|
+
const asks = [
|
|
6636
|
+
'103822000',
|
|
6637
|
+
'103838354',
|
|
6638
|
+
'103843087',
|
|
6639
|
+
'103843351',
|
|
6640
|
+
'103843880',
|
|
6641
|
+
'103845114',
|
|
6642
|
+
'103846148',
|
|
6643
|
+
'103850100',
|
|
6644
|
+
'103851300',
|
|
6645
|
+
'103854304',
|
|
6646
|
+
].map((priceStr) => ({
|
|
6647
|
+
price: new BN(priceStr),
|
|
6648
|
+
size: new BN(1).mul(BASE_PRECISION),
|
|
6649
|
+
sources: { vamm: new BN(1).mul(BASE_PRECISION) },
|
|
6650
|
+
}));
|
|
6651
|
+
|
|
6652
|
+
expect(asksAreSortedAsc(asks), 'Input asks are ascending').to.be.true;
|
|
6653
|
+
expect(bidsAreSortedDesc(bids), 'Input bids are descending').to.be.true;
|
|
6654
|
+
|
|
6655
|
+
const oraclePrice = new BN('103649895');
|
|
6656
|
+
const oraclePrice5Min = new BN('103285000');
|
|
6657
|
+
const markPrice5Min = new BN('103371000');
|
|
6658
|
+
|
|
6659
|
+
const groupingSize = new BN('100');
|
|
6660
|
+
|
|
6661
|
+
const userAsks = new Set<string>();
|
|
6662
|
+
|
|
6663
|
+
const { bids: newBids, asks: newAsks } = uncrossL2(
|
|
6664
|
+
bids,
|
|
6665
|
+
asks,
|
|
6666
|
+
oraclePrice,
|
|
6667
|
+
oraclePrice5Min,
|
|
6668
|
+
markPrice5Min,
|
|
6669
|
+
groupingSize,
|
|
6670
|
+
new Set<string>(),
|
|
6671
|
+
userAsks
|
|
6672
|
+
);
|
|
6673
|
+
|
|
6674
|
+
expect(asksAreSortedAsc(newAsks), 'Uncrossed asks are ascending').to.be
|
|
6675
|
+
.true;
|
|
6676
|
+
expect(bidsAreSortedDesc(newBids), 'Uncrossed bids are descending').to.be
|
|
6677
|
+
.true;
|
|
6678
|
+
});
|
|
6679
|
+
|
|
6680
|
+
it('Crossing edge case : top bid and ask have a big cross, following ones dont - shouldnt get uncrossed out of order', () => {
|
|
6681
|
+
const bids = [
|
|
6682
|
+
'101825900',
|
|
6683
|
+
'101783900',
|
|
6684
|
+
'101783000',
|
|
6685
|
+
'101782600',
|
|
6686
|
+
'101770700',
|
|
6687
|
+
'101770200',
|
|
6688
|
+
'101749857',
|
|
6689
|
+
'101735900',
|
|
6690
|
+
'101729994',
|
|
6691
|
+
'101726900',
|
|
6692
|
+
].map((priceStr) => ({
|
|
6693
|
+
price: new BN(priceStr),
|
|
6694
|
+
size: new BN(1).mul(BASE_PRECISION),
|
|
6695
|
+
sources: { vamm: new BN(1).mul(BASE_PRECISION) },
|
|
6696
|
+
}));
|
|
6697
|
+
|
|
6698
|
+
const asks = [
|
|
6699
|
+
'101750700',
|
|
6700
|
+
'101790467',
|
|
6701
|
+
'101793400',
|
|
6702
|
+
'101794116',
|
|
6703
|
+
'101798548',
|
|
6704
|
+
'101799532',
|
|
6705
|
+
'101803500',
|
|
6706
|
+
'101820927',
|
|
6707
|
+
'101823900',
|
|
6708
|
+
'101827638',
|
|
6709
|
+
].map((priceStr) => ({
|
|
6710
|
+
price: new BN(priceStr),
|
|
6711
|
+
size: new BN(1).mul(BASE_PRECISION),
|
|
6712
|
+
sources: { vamm: new BN(1).mul(BASE_PRECISION) },
|
|
6713
|
+
}));
|
|
6714
|
+
|
|
6715
|
+
expect(asksAreSortedAsc(asks), 'Input asks are ascending').to.be.true;
|
|
6716
|
+
expect(bidsAreSortedDesc(bids), 'Input bids are descending').to.be.true;
|
|
6717
|
+
|
|
6718
|
+
const oraclePrice = new BN('101711384');
|
|
6719
|
+
const oraclePrice5Min = new BN('101805000');
|
|
6720
|
+
const markPrice5Min = new BN('101867000');
|
|
6721
|
+
|
|
6722
|
+
const groupingSize = new BN('100');
|
|
6723
|
+
|
|
6724
|
+
const userAsks = new Set<string>();
|
|
6725
|
+
|
|
6726
|
+
const { bids: newBids, asks: newAsks } = uncrossL2(
|
|
6727
|
+
bids,
|
|
6728
|
+
asks,
|
|
6729
|
+
oraclePrice,
|
|
6730
|
+
oraclePrice5Min,
|
|
6731
|
+
markPrice5Min,
|
|
6732
|
+
groupingSize,
|
|
6733
|
+
new Set<string>(),
|
|
6734
|
+
userAsks
|
|
6735
|
+
);
|
|
6736
|
+
|
|
6737
|
+
expect(asksAreSortedAsc(newAsks), 'Uncrossed asks are ascending').to.be
|
|
6738
|
+
.true;
|
|
6739
|
+
expect(bidsAreSortedDesc(newBids), 'Uncrossed bids are descending').to.be
|
|
6740
|
+
.true;
|
|
6741
|
+
});
|
|
6595
6742
|
});
|