@drift-labs/sdk 2.74.0-beta.7 → 2.74.0-beta.9

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 CHANGED
@@ -1 +1 @@
1
- 2.74.0-beta.7
1
+ 2.74.0-beta.9
@@ -83,4 +83,5 @@ export declare class AdminClient extends DriftClient {
83
83
  updateProtocolIfSharesTransferConfig(whitelistedSigners?: PublicKey[], maxTransferPerEpoch?: BN): Promise<TransactionSignature>;
84
84
  initializePrelaunchOracle(perpMarketIndex: number, price?: BN, maxPrice?: BN): Promise<TransactionSignature>;
85
85
  updatePrelaunchOracleParams(perpMarketIndex: number, price?: BN, maxPrice?: BN): Promise<TransactionSignature>;
86
+ deletePrelaunchOracle(perpMarketIndex: number): Promise<TransactionSignature>;
86
87
  }
@@ -1083,5 +1083,18 @@ class AdminClient extends driftClient_1.DriftClient {
1083
1083
  const { txSig } = await this.sendTransaction(tx, [], this.opts);
1084
1084
  return txSig;
1085
1085
  }
1086
+ async deletePrelaunchOracle(perpMarketIndex) {
1087
+ const deletePrelaunchOracleIx = await this.program.instruction.deletePrelaunchOracle(perpMarketIndex, {
1088
+ accounts: {
1089
+ admin: this.wallet.publicKey,
1090
+ state: await this.getStatePublicKey(),
1091
+ prelaunchOracle: await (0, pda_1.getPrelaunchOraclePublicKey)(this.program.programId, perpMarketIndex),
1092
+ perpMarket: await (0, pda_1.getPerpMarketPublicKey)(this.program.programId, perpMarketIndex),
1093
+ },
1094
+ });
1095
+ const tx = await this.buildTransaction(deletePrelaunchOracleIx);
1096
+ const { txSig } = await this.sendTransaction(tx, [], this.opts);
1097
+ return txSig;
1098
+ }
1086
1099
  }
1087
1100
  exports.AdminClient = AdminClient;
@@ -261,6 +261,31 @@ function groupL2Levels(levels, grouping, direction, depth) {
261
261
  }
262
262
  return groupedLevels;
263
263
  }
264
+ /**
265
+ * Method to merge bids or asks by price
266
+ */
267
+ const mergeByPrice = (bidsOrAsks) => {
268
+ const merged = new Map();
269
+ for (const level of bidsOrAsks) {
270
+ const key = level.price.toString();
271
+ if (merged.has(key)) {
272
+ const existing = merged.get(key);
273
+ existing.size = existing.size.add(level.size);
274
+ for (const [source, size] of Object.entries(level.sources)) {
275
+ if (existing.sources[source]) {
276
+ existing.sources[source] = existing.sources[source].add(size);
277
+ }
278
+ else {
279
+ existing.sources[source] = size;
280
+ }
281
+ }
282
+ }
283
+ else {
284
+ merged.set(key, cloneL2Level(level));
285
+ }
286
+ }
287
+ return Array.from(merged.values());
288
+ };
264
289
  /**
265
290
  * The purpose of this function is uncross the L2 orderbook by modifying the bid/ask price at the top of the book
266
291
  * This will make the liquidity look worse but more intuitive (users familiar with clob get confused w temporarily
@@ -342,17 +367,17 @@ function uncrossL2(bids, asks, oraclePrice, oracleTwap5Min, markTwap5Min, groupi
342
367
  bidIndex++;
343
368
  continue;
344
369
  }
370
+ if (userBids.has(nextBid.price.toString())) {
371
+ newBids.push(nextBid);
372
+ bidIndex++;
373
+ continue;
374
+ }
375
+ if (userAsks.has(nextAsk.price.toString())) {
376
+ newAsks.push(nextAsk);
377
+ askIndex++;
378
+ continue;
379
+ }
345
380
  if (nextBid.price.gte(nextAsk.price)) {
346
- if (userBids.has(nextBid.price.toString())) {
347
- newBids.push(nextBid);
348
- bidIndex++;
349
- continue;
350
- }
351
- if (userAsks.has(nextAsk.price.toString())) {
352
- newAsks.push(nextAsk);
353
- askIndex++;
354
- continue;
355
- }
356
381
  if (nextBid.price.gt(referencePrice) &&
357
382
  nextAsk.price.gt(referencePrice)) {
358
383
  let newBidPrice = nextAsk.price.sub(grouping);
@@ -397,9 +422,13 @@ function uncrossL2(bids, asks, oraclePrice, oracleTwap5Min, markTwap5Min, groupi
397
422
  bidIndex++;
398
423
  }
399
424
  }
425
+ newBids.sort((a, b) => b.price.cmp(a.price));
426
+ newAsks.sort((a, b) => a.price.cmp(b.price));
427
+ const finalNewBids = mergeByPrice(newBids);
428
+ const finalNewAsks = mergeByPrice(newAsks);
400
429
  return {
401
- bids: newBids,
402
- asks: newAsks,
430
+ bids: finalNewBids,
431
+ asks: finalNewAsks,
403
432
  };
404
433
  }
405
434
  exports.uncrossL2 = uncrossL2;
@@ -9119,6 +9119,9 @@
9119
9119
  {
9120
9120
  "name": "Speculative"
9121
9121
  },
9122
+ {
9123
+ "name": "HighlySpeculative"
9124
+ },
9122
9125
  {
9123
9126
  "name": "Isolated"
9124
9127
  }
@@ -148,12 +148,6 @@ function getMaxPriceDivergenceForFundingRate(market, oracleTwap) {
148
148
  else if ((0, types_1.isVariant)(market.contractTier, 'c')) {
149
149
  return oracleTwap.divn(20);
150
150
  }
151
- else if ((0, types_1.isVariant)(market.contractTier, 'speculative')) {
152
- return oracleTwap.divn(10);
153
- }
154
- else if ((0, types_1.isVariant)(market.contractTier, 'isolated')) {
155
- return oracleTwap.divn(10);
156
- }
157
151
  else {
158
152
  return oracleTwap.divn(10);
159
153
  }
@@ -28,7 +28,7 @@ function getMaxConfidenceIntervalMultiplier(market) {
28
28
  else if ((0, types_1.isVariant)(market.contractTier, 'speculative')) {
29
29
  maxConfidenceIntervalMultiplier = new index_1.BN(10);
30
30
  }
31
- else if ((0, types_1.isVariant)(market.contractTier, 'isolated')) {
31
+ else {
32
32
  maxConfidenceIntervalMultiplier = new index_1.BN(50);
33
33
  }
34
34
  return maxConfidenceIntervalMultiplier;
package/lib/math/tiers.js CHANGED
@@ -15,7 +15,7 @@ function getPerpMarketTierNumber(perpMarket) {
15
15
  else if ((0, types_1.isVariant)(perpMarket.contractTier, 'speculative')) {
16
16
  return 3;
17
17
  }
18
- else if ((0, types_1.isVariant)(perpMarket.contractTier, 'isolated')) {
18
+ else if ((0, types_1.isVariant)(perpMarket.contractTier, 'highlySpeculative')) {
19
19
  return 4;
20
20
  }
21
21
  else {
@@ -17,6 +17,7 @@ class PrelaunchOracleClient {
17
17
  slot: prelaunchOracle.ammLastUpdateSlot,
18
18
  confidence: prelaunchOracle.confidence,
19
19
  hasSufficientNumberOfDataPoints: true,
20
+ maxPrice: prelaunchOracle.maxPrice,
20
21
  };
21
22
  }
22
23
  }
@@ -10,6 +10,7 @@ export type OraclePriceData = {
10
10
  hasSufficientNumberOfDataPoints: boolean;
11
11
  twap?: BN;
12
12
  twapConfidence?: BN;
13
+ maxPrice?: BN;
13
14
  };
14
15
  export type OracleInfo = {
15
16
  publicKey: PublicKey;
package/lib/types.d.ts CHANGED
@@ -80,6 +80,9 @@ export declare class ContractTier {
80
80
  static readonly SPECULATIVE: {
81
81
  speculative: {};
82
82
  };
83
+ static readonly HIGHLY_SPECULATIVE: {
84
+ highlySpeculative: {};
85
+ };
83
86
  static readonly ISOLATED: {
84
87
  isolated: {};
85
88
  };
package/lib/types.js CHANGED
@@ -60,6 +60,7 @@ ContractTier.A = { a: {} };
60
60
  ContractTier.B = { b: {} };
61
61
  ContractTier.C = { c: {} };
62
62
  ContractTier.SPECULATIVE = { speculative: {} };
63
+ ContractTier.HIGHLY_SPECULATIVE = { highlySpeculative: {} };
63
64
  ContractTier.ISOLATED = { isolated: {} };
64
65
  class AssetTier {
65
66
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.74.0-beta.7",
3
+ "version": "2.74.0-beta.9",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -2172,4 +2172,30 @@ export class AdminClient extends DriftClient {
2172
2172
 
2173
2173
  return txSig;
2174
2174
  }
2175
+
2176
+ public async deletePrelaunchOracle(
2177
+ perpMarketIndex: number
2178
+ ): Promise<TransactionSignature> {
2179
+ const deletePrelaunchOracleIx =
2180
+ await this.program.instruction.deletePrelaunchOracle(perpMarketIndex, {
2181
+ accounts: {
2182
+ admin: this.wallet.publicKey,
2183
+ state: await this.getStatePublicKey(),
2184
+ prelaunchOracle: await getPrelaunchOraclePublicKey(
2185
+ this.program.programId,
2186
+ perpMarketIndex
2187
+ ),
2188
+ perpMarket: await getPerpMarketPublicKey(
2189
+ this.program.programId,
2190
+ perpMarketIndex
2191
+ ),
2192
+ },
2193
+ });
2194
+
2195
+ const tx = await this.buildTransaction(deletePrelaunchOracleIx);
2196
+
2197
+ const { txSig } = await this.sendTransaction(tx, [], this.opts);
2198
+
2199
+ return txSig;
2200
+ }
2175
2201
  }
@@ -429,6 +429,30 @@ function groupL2Levels(
429
429
  return groupedLevels;
430
430
  }
431
431
 
432
+ /**
433
+ * Method to merge bids or asks by price
434
+ */
435
+ const mergeByPrice = (bidsOrAsks: L2Level[]) => {
436
+ const merged = new Map<string, L2Level>();
437
+ for (const level of bidsOrAsks) {
438
+ const key = level.price.toString();
439
+ if (merged.has(key)) {
440
+ const existing = merged.get(key);
441
+ existing.size = existing.size.add(level.size);
442
+ for (const [source, size] of Object.entries(level.sources)) {
443
+ if (existing.sources[source]) {
444
+ existing.sources[source] = existing.sources[source].add(size);
445
+ } else {
446
+ existing.sources[source] = size;
447
+ }
448
+ }
449
+ } else {
450
+ merged.set(key, cloneL2Level(level));
451
+ }
452
+ }
453
+ return Array.from(merged.values());
454
+ };
455
+
432
456
  /**
433
457
  * The purpose of this function is uncross the L2 orderbook by modifying the bid/ask price at the top of the book
434
458
  * This will make the liquidity look worse but more intuitive (users familiar with clob get confused w temporarily
@@ -467,8 +491,8 @@ export function uncrossL2(
467
491
  return { bids, asks };
468
492
  }
469
493
 
470
- const newBids = [];
471
- const newAsks = [];
494
+ const newBids: L2Level[] = [];
495
+ const newAsks: L2Level[] = [];
472
496
 
473
497
  const updateLevels = (newPrice: BN, oldLevel: L2Level, levels: L2Level[]) => {
474
498
  if (levels.length > 0 && levels[levels.length - 1].price.eq(newPrice)) {
@@ -528,19 +552,19 @@ export function uncrossL2(
528
552
  continue;
529
553
  }
530
554
 
531
- if (nextBid.price.gte(nextAsk.price)) {
532
- if (userBids.has(nextBid.price.toString())) {
533
- newBids.push(nextBid);
534
- bidIndex++;
535
- continue;
536
- }
555
+ if (userBids.has(nextBid.price.toString())) {
556
+ newBids.push(nextBid);
557
+ bidIndex++;
558
+ continue;
559
+ }
537
560
 
538
- if (userAsks.has(nextAsk.price.toString())) {
539
- newAsks.push(nextAsk);
540
- askIndex++;
541
- continue;
542
- }
561
+ if (userAsks.has(nextAsk.price.toString())) {
562
+ newAsks.push(nextAsk);
563
+ askIndex++;
564
+ continue;
565
+ }
543
566
 
567
+ if (nextBid.price.gte(nextAsk.price)) {
544
568
  if (
545
569
  nextBid.price.gt(referencePrice) &&
546
570
  nextAsk.price.gt(referencePrice)
@@ -594,8 +618,14 @@ export function uncrossL2(
594
618
  }
595
619
  }
596
620
 
621
+ newBids.sort((a, b) => b.price.cmp(a.price));
622
+ newAsks.sort((a, b) => a.price.cmp(b.price));
623
+
624
+ const finalNewBids = mergeByPrice(newBids);
625
+ const finalNewAsks = mergeByPrice(newAsks);
626
+
597
627
  return {
598
- bids: newBids,
599
- asks: newAsks,
628
+ bids: finalNewBids,
629
+ asks: finalNewAsks,
600
630
  };
601
631
  }
@@ -9119,6 +9119,9 @@
9119
9119
  {
9120
9120
  "name": "Speculative"
9121
9121
  },
9122
+ {
9123
+ "name": "HighlySpeculative"
9124
+ },
9122
9125
  {
9123
9126
  "name": "Isolated"
9124
9127
  }
@@ -252,10 +252,6 @@ function getMaxPriceDivergenceForFundingRate(
252
252
  return oracleTwap.divn(33);
253
253
  } else if (isVariant(market.contractTier, 'c')) {
254
254
  return oracleTwap.divn(20);
255
- } else if (isVariant(market.contractTier, 'speculative')) {
256
- return oracleTwap.divn(10);
257
- } else if (isVariant(market.contractTier, 'isolated')) {
258
- return oracleTwap.divn(10);
259
255
  } else {
260
256
  return oracleTwap.divn(10);
261
257
  }
@@ -39,7 +39,7 @@ export function getMaxConfidenceIntervalMultiplier(
39
39
  maxConfidenceIntervalMultiplier = new BN(2);
40
40
  } else if (isVariant(market.contractTier, 'speculative')) {
41
41
  maxConfidenceIntervalMultiplier = new BN(10);
42
- } else if (isVariant(market.contractTier, 'isolated')) {
42
+ } else {
43
43
  maxConfidenceIntervalMultiplier = new BN(50);
44
44
  }
45
45
  return maxConfidenceIntervalMultiplier;
package/src/math/tiers.ts CHANGED
@@ -9,7 +9,7 @@ export function getPerpMarketTierNumber(perpMarket: PerpMarketAccount): number {
9
9
  return 2;
10
10
  } else if (isVariant(perpMarket.contractTier, 'speculative')) {
11
11
  return 3;
12
- } else if (isVariant(perpMarket.contractTier, 'isolated')) {
12
+ } else if (isVariant(perpMarket.contractTier, 'highlySpeculative')) {
13
13
  return 4;
14
14
  } else {
15
15
  return 5;
@@ -31,6 +31,7 @@ export class PrelaunchOracleClient implements OracleClient {
31
31
  slot: prelaunchOracle.ammLastUpdateSlot,
32
32
  confidence: prelaunchOracle.confidence,
33
33
  hasSufficientNumberOfDataPoints: true,
34
+ maxPrice: prelaunchOracle.maxPrice,
34
35
  };
35
36
  }
36
37
  }
@@ -9,6 +9,7 @@ export type OraclePriceData = {
9
9
  hasSufficientNumberOfDataPoints: boolean;
10
10
  twap?: BN;
11
11
  twapConfidence?: BN;
12
+ maxPrice?: BN; // pre-launch markets only
12
13
  };
13
14
 
14
15
  export type OracleInfo = {
package/src/types.ts CHANGED
@@ -58,6 +58,7 @@ export class ContractTier {
58
58
  static readonly B = { b: {} };
59
59
  static readonly C = { c: {} };
60
60
  static readonly SPECULATIVE = { speculative: {} };
61
+ static readonly HIGHLY_SPECULATIVE = { highlySpeculative: {} };
61
62
  static readonly ISOLATED = { isolated: {} };
62
63
  }
63
64
 
@@ -6614,6 +6614,63 @@ describe('Uncross L2', () => {
6614
6614
  );
6615
6615
  });
6616
6616
 
6617
+ it('Handles user crossing bid in second level', () => {
6618
+ const oraclePrice = new BN(190.3843 * PRICE_PRECISION.toNumber());
6619
+ const bids = [
6620
+ [190.59, 2],
6621
+ [190.588, 58.3],
6622
+ [190.5557, 5],
6623
+ [190.5547, 5],
6624
+ [190.5508, 5],
6625
+ [190.541, 2],
6626
+ [190.5099, 49.1],
6627
+ [190.5, 60],
6628
+ ].map(([price, size]) => ({
6629
+ price: new BN(price * PRICE_PRECISION.toNumber()),
6630
+ size: new BN(size * BASE_PRECISION.toNumber()),
6631
+ sources: { vamm: new BN(size * BASE_PRECISION.toNumber()) },
6632
+ }));
6633
+
6634
+ const asks = [
6635
+ [190.5, 86.5],
6636
+ [190.6159, 1],
6637
+ [190.656, 10.5],
6638
+ [190.6561, 1],
6639
+ [190.6585, 5],
6640
+ [190.6595, 5],
6641
+ [190.6596, 5],
6642
+ ].map(([price, size]) => ({
6643
+ price: new BN(price * PRICE_PRECISION.toNumber()),
6644
+ size: new BN(size * BASE_PRECISION.toNumber()),
6645
+ sources: { vamm: new BN(size * BASE_PRECISION.toNumber()) },
6646
+ }));
6647
+
6648
+ expect(asksAreSortedAsc(asks), 'Input asks are ascending').to.be.true;
6649
+ expect(bidsAreSortedDesc(bids), 'Input bids are descending').to.be.true;
6650
+
6651
+ const groupingSize = new BN('100');
6652
+
6653
+ const userBidPrice = new BN(190.588 * PRICE_PRECISION.toNumber());
6654
+ const userBids = new Set<string>([userBidPrice.toString()]);
6655
+
6656
+ const { bids: newBids, asks: newAsks } = uncrossL2(
6657
+ bids,
6658
+ asks,
6659
+ oraclePrice,
6660
+ oraclePrice,
6661
+ oraclePrice,
6662
+ groupingSize,
6663
+ userBids,
6664
+ new Set<string>()
6665
+ );
6666
+
6667
+ expect(asksAreSortedAsc(newAsks), 'Uncrossed asks are ascending').to.be
6668
+ .true;
6669
+ expect(bidsAreSortedDesc(newBids), 'Uncrossed bids are descending').to.be
6670
+ .true;
6671
+ expect(newBids[0].price.toString()).to.equal(userBidPrice.toString());
6672
+ });
6673
+
6617
6674
  it('Handles edge case bide and asks with large cross and an overlapping level', () => {
6618
6675
  const bids = [
6619
6676
  '104411000',