@drift-labs/sdk 2.65.0-beta.4 → 2.65.0-beta.5
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/dlob/orderBookLevels.js +34 -6
- package/lib/userMap/userMap.d.ts +2 -2
- package/lib/userMap/userMap.js +2 -1
- package/package.json +1 -1
- package/src/dlob/orderBookLevels.ts +42 -6
- package/src/userMap/userMap.ts +9 -3
- package/tests/dlob/test.ts +63 -0
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.65.0-beta.
|
|
1
|
+
2.65.0-beta.5
|
|
@@ -311,6 +311,18 @@ function uncrossL2(bids, asks, oraclePrice, oracleTwap5Min, markTwap5Min, groupi
|
|
|
311
311
|
const referencePrice = oraclePrice.add(markTwap5Min.sub(oracleTwap5Min));
|
|
312
312
|
let bidIndex = 0;
|
|
313
313
|
let askIndex = 0;
|
|
314
|
+
let maxBid;
|
|
315
|
+
let minAsk;
|
|
316
|
+
const getPriceAndSetBound = (newPrice, direction) => {
|
|
317
|
+
if ((0, __1.isVariant)(direction, 'long')) {
|
|
318
|
+
maxBid = maxBid ? __1.BN.min(maxBid, newPrice) : newPrice;
|
|
319
|
+
return maxBid;
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
minAsk = minAsk ? __1.BN.max(minAsk, newPrice) : newPrice;
|
|
323
|
+
return minAsk;
|
|
324
|
+
}
|
|
325
|
+
};
|
|
314
326
|
while (bidIndex < bids.length || askIndex < asks.length) {
|
|
315
327
|
const nextBid = cloneL2Level(bids[bidIndex]);
|
|
316
328
|
const nextAsk = cloneL2Level(asks[askIndex]);
|
|
@@ -337,19 +349,23 @@ function uncrossL2(bids, asks, oraclePrice, oracleTwap5Min, markTwap5Min, groupi
|
|
|
337
349
|
}
|
|
338
350
|
if (nextBid.price.gt(referencePrice) &&
|
|
339
351
|
nextAsk.price.gt(referencePrice)) {
|
|
340
|
-
|
|
352
|
+
let newBidPrice = nextAsk.price.sub(grouping);
|
|
353
|
+
newBidPrice = getPriceAndSetBound(newBidPrice, __1.PositionDirection.LONG);
|
|
341
354
|
updateLevels(newBidPrice, nextBid, newBids);
|
|
342
355
|
bidIndex++;
|
|
343
356
|
}
|
|
344
357
|
else if (nextAsk.price.lt(referencePrice) &&
|
|
345
358
|
nextBid.price.lt(referencePrice)) {
|
|
346
|
-
|
|
359
|
+
let newAskPrice = nextBid.price.add(grouping);
|
|
360
|
+
newAskPrice = getPriceAndSetBound(newAskPrice, __1.PositionDirection.SHORT);
|
|
347
361
|
updateLevels(newAskPrice, nextAsk, newAsks);
|
|
348
362
|
askIndex++;
|
|
349
363
|
}
|
|
350
364
|
else {
|
|
351
|
-
|
|
352
|
-
|
|
365
|
+
let newBidPrice = referencePrice.sub(grouping);
|
|
366
|
+
let newAskPrice = referencePrice.add(grouping);
|
|
367
|
+
newBidPrice = getPriceAndSetBound(newBidPrice, __1.PositionDirection.LONG);
|
|
368
|
+
newAskPrice = getPriceAndSetBound(newAskPrice, __1.PositionDirection.SHORT);
|
|
353
369
|
updateLevels(newBidPrice, nextBid, newBids);
|
|
354
370
|
updateLevels(newAskPrice, nextAsk, newAsks);
|
|
355
371
|
bidIndex++;
|
|
@@ -357,9 +373,21 @@ function uncrossL2(bids, asks, oraclePrice, oracleTwap5Min, markTwap5Min, groupi
|
|
|
357
373
|
}
|
|
358
374
|
}
|
|
359
375
|
else {
|
|
360
|
-
|
|
376
|
+
if (minAsk && nextAsk.price.lte(minAsk)) {
|
|
377
|
+
const newAskPrice = getPriceAndSetBound(nextAsk.price, __1.PositionDirection.SHORT);
|
|
378
|
+
updateLevels(newAskPrice, nextAsk, newAsks);
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
newAsks.push(nextAsk);
|
|
382
|
+
}
|
|
361
383
|
askIndex++;
|
|
362
|
-
|
|
384
|
+
if (maxBid && nextBid.price.gte(maxBid)) {
|
|
385
|
+
const newBidPrice = getPriceAndSetBound(nextBid.price, __1.PositionDirection.LONG);
|
|
386
|
+
updateLevels(newBidPrice, nextBid, newBids);
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
newBids.push(nextBid);
|
|
390
|
+
}
|
|
363
391
|
bidIndex++;
|
|
364
392
|
}
|
|
365
393
|
}
|
package/lib/userMap/userMap.d.ts
CHANGED
|
@@ -8,8 +8,8 @@ export interface UserMapInterface {
|
|
|
8
8
|
has(key: string): boolean;
|
|
9
9
|
get(key: string): User | undefined;
|
|
10
10
|
getWithSlot(key: string): DataAndSlot<User> | undefined;
|
|
11
|
-
mustGet(key: string): Promise<User>;
|
|
12
|
-
mustGetWithSlot(key: string): Promise<DataAndSlot<User>>;
|
|
11
|
+
mustGet(key: string, accountSubscription?: UserSubscriptionConfig): Promise<User>;
|
|
12
|
+
mustGetWithSlot(key: string, accountSubscription?: UserSubscriptionConfig): Promise<DataAndSlot<User>>;
|
|
13
13
|
getUserAuthority(key: string): PublicKey | undefined;
|
|
14
14
|
updateWithOrderRecord(record: OrderRecord): Promise<void>;
|
|
15
15
|
values(): IterableIterator<User>;
|
package/lib/userMap/userMap.js
CHANGED
|
@@ -73,6 +73,7 @@ class UserMap {
|
|
|
73
73
|
await this.subscription.subscribe();
|
|
74
74
|
}
|
|
75
75
|
async addPubkey(userAccountPublicKey, userAccount, slot, accountSubscription) {
|
|
76
|
+
var _a;
|
|
76
77
|
const user = new __1.User({
|
|
77
78
|
driftClient: this.driftClient,
|
|
78
79
|
userAccountPublicKey,
|
|
@@ -84,7 +85,7 @@ class UserMap {
|
|
|
84
85
|
await user.subscribe(userAccount);
|
|
85
86
|
this.userMap.set(userAccountPublicKey.toString(), {
|
|
86
87
|
data: user,
|
|
87
|
-
slot: slot !== null &&
|
|
88
|
+
slot: (_a = user.getUserAccountAndSlot().slot) !== null && _a !== void 0 ? _a : -1,
|
|
88
89
|
});
|
|
89
90
|
}
|
|
90
91
|
has(key) {
|
package/package.json
CHANGED
|
@@ -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]);
|
|
@@ -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/userMap/userMap.ts
CHANGED
|
@@ -42,8 +42,14 @@ export interface UserMapInterface {
|
|
|
42
42
|
has(key: string): boolean;
|
|
43
43
|
get(key: string): User | undefined;
|
|
44
44
|
getWithSlot(key: string): DataAndSlot<User> | undefined;
|
|
45
|
-
mustGet(
|
|
46
|
-
|
|
45
|
+
mustGet(
|
|
46
|
+
key: string,
|
|
47
|
+
accountSubscription?: UserSubscriptionConfig
|
|
48
|
+
): Promise<User>;
|
|
49
|
+
mustGetWithSlot(
|
|
50
|
+
key: string,
|
|
51
|
+
accountSubscription?: UserSubscriptionConfig
|
|
52
|
+
): Promise<DataAndSlot<User>>;
|
|
47
53
|
getUserAuthority(key: string): PublicKey | undefined;
|
|
48
54
|
updateWithOrderRecord(record: OrderRecord): Promise<void>;
|
|
49
55
|
values(): IterableIterator<User>;
|
|
@@ -158,7 +164,7 @@ export class UserMap implements UserMapInterface {
|
|
|
158
164
|
await user.subscribe(userAccount);
|
|
159
165
|
this.userMap.set(userAccountPublicKey.toString(), {
|
|
160
166
|
data: user,
|
|
161
|
-
slot: slot ?? -1,
|
|
167
|
+
slot: user.getUserAccountAndSlot().slot ?? -1,
|
|
162
168
|
});
|
|
163
169
|
}
|
|
164
170
|
|
package/tests/dlob/test.ts
CHANGED
|
@@ -6677,4 +6677,67 @@ describe('Uncross L2', () => {
|
|
|
6677
6677
|
expect(asksAreSortedAsc(newAsks), "Uncrossed asks are ascending").to.be.true;
|
|
6678
6678
|
expect(bidsAreSortedDesc(newBids), "Uncrossed bids are descending").to.be.true;
|
|
6679
6679
|
});
|
|
6680
|
+
|
|
6681
|
+
it('Crossing edge case : top bid and ask have a big cross, following ones dont - shouldnt get uncrossed out of order', () => {
|
|
6682
|
+
const bids = [
|
|
6683
|
+
"101825900",
|
|
6684
|
+
"101783900",
|
|
6685
|
+
"101783000",
|
|
6686
|
+
"101782600",
|
|
6687
|
+
"101770700",
|
|
6688
|
+
"101770200",
|
|
6689
|
+
"101749857",
|
|
6690
|
+
"101735900",
|
|
6691
|
+
"101729994",
|
|
6692
|
+
"101726900",
|
|
6693
|
+
].map(priceStr => (
|
|
6694
|
+
{
|
|
6695
|
+
price: new BN(priceStr),
|
|
6696
|
+
size: new BN(1).mul(BASE_PRECISION),
|
|
6697
|
+
sources: { vamm: new BN(1).mul(BASE_PRECISION) },
|
|
6698
|
+
}
|
|
6699
|
+
));
|
|
6700
|
+
|
|
6701
|
+
const asks = [
|
|
6702
|
+
"101750700",
|
|
6703
|
+
"101790467",
|
|
6704
|
+
"101793400",
|
|
6705
|
+
"101794116",
|
|
6706
|
+
"101798548",
|
|
6707
|
+
"101799532",
|
|
6708
|
+
"101803500",
|
|
6709
|
+
"101820927",
|
|
6710
|
+
"101823900",
|
|
6711
|
+
"101827638",
|
|
6712
|
+
].map(priceStr => ({
|
|
6713
|
+
price: new BN(priceStr),
|
|
6714
|
+
size: new BN(1).mul(BASE_PRECISION),
|
|
6715
|
+
sources: { vamm: new BN(1).mul(BASE_PRECISION) },
|
|
6716
|
+
}));
|
|
6717
|
+
|
|
6718
|
+
expect(asksAreSortedAsc(asks), "Input asks are ascending").to.be.true;
|
|
6719
|
+
expect(bidsAreSortedDesc(bids), "Input bids are descending").to.be.true;
|
|
6720
|
+
|
|
6721
|
+
const oraclePrice = new BN("101711384");
|
|
6722
|
+
const oraclePrice5Min = new BN("101805000");
|
|
6723
|
+
const markPrice5Min = new BN("101867000");
|
|
6724
|
+
|
|
6725
|
+
const groupingSize = new BN("100");
|
|
6726
|
+
|
|
6727
|
+
const userAsks = new Set<string>();
|
|
6728
|
+
|
|
6729
|
+
const { bids: newBids, asks: newAsks } = uncrossL2(
|
|
6730
|
+
bids,
|
|
6731
|
+
asks,
|
|
6732
|
+
oraclePrice,
|
|
6733
|
+
oraclePrice5Min,
|
|
6734
|
+
markPrice5Min,
|
|
6735
|
+
groupingSize,
|
|
6736
|
+
new Set<string>(),
|
|
6737
|
+
userAsks
|
|
6738
|
+
);
|
|
6739
|
+
|
|
6740
|
+
expect(asksAreSortedAsc(newAsks), "Uncrossed asks are ascending").to.be.true;
|
|
6741
|
+
expect(bidsAreSortedDesc(newBids), "Uncrossed bids are descending").to.be.true;
|
|
6742
|
+
});
|
|
6680
6743
|
});
|