@drift-labs/sdk 2.0.17 → 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/index.d.ts CHANGED
@@ -62,6 +62,7 @@ export * from './constants/spotMarkets';
62
62
  export * from './driftClientConfig';
63
63
  export * from './dlob/DLOB';
64
64
  export * from './dlob/DLOBNode';
65
+ export * from './dlob/DLOBOrders';
65
66
  export * from './dlob/NodeList';
66
67
  export * from './userMap/userMap';
67
68
  export * from './userMap/userStatsMap';
package/lib/index.js CHANGED
@@ -85,6 +85,7 @@ __exportStar(require("./constants/spotMarkets"), exports);
85
85
  __exportStar(require("./driftClientConfig"), exports);
86
86
  __exportStar(require("./dlob/DLOB"), exports);
87
87
  __exportStar(require("./dlob/DLOBNode"), exports);
88
+ __exportStar(require("./dlob/DLOBOrders"), exports);
88
89
  __exportStar(require("./dlob/NodeList"), exports);
89
90
  __exportStar(require("./userMap/userMap"), exports);
90
91
  __exportStar(require("./userMap/userStatsMap"), exports);
package/lib/math/amm.d.ts CHANGED
@@ -38,7 +38,27 @@ export declare function calculateInventoryScale(baseAssetAmountWithAmm: BN, base
38
38
  export declare function calculateEffectiveLeverage(baseSpread: number, quoteAssetReserve: BN, terminalQuoteAssetReserve: BN, pegMultiplier: BN, netBaseAssetAmount: BN, reservePrice: BN, totalFeeMinusDistributions: BN): number;
39
39
  export declare function calculateMaxSpread(marginRatioInitial: number): number;
40
40
  export declare function calculateVolSpreadBN(lastOracleConfPct: BN, reservePrice: BN, markStd: BN, oracleStd: BN, longIntensity: BN, shortIntensity: BN, volume24H: BN): [BN, BN];
41
- export declare function calculateSpreadBN(baseSpread: number, lastOracleReservePriceSpreadPct: BN, lastOracleConfPct: BN, maxSpread: number, quoteAssetReserve: BN, terminalQuoteAssetReserve: BN, pegMultiplier: BN, baseAssetAmountWithAmm: BN, reservePrice: BN, totalFeeMinusDistributions: BN, netRevenueSinceLastFunding: BN, baseAssetReserve: BN, minBaseAssetReserve: BN, maxBaseAssetReserve: BN, markStd: BN, oracleStd: BN, longIntensity: BN, shortIntensity: BN, volume24H: BN): [number, number];
41
+ export declare function calculateSpreadBN(baseSpread: number, lastOracleReservePriceSpreadPct: BN, lastOracleConfPct: BN, maxSpread: number, quoteAssetReserve: BN, terminalQuoteAssetReserve: BN, pegMultiplier: BN, baseAssetAmountWithAmm: BN, reservePrice: BN, totalFeeMinusDistributions: BN, netRevenueSinceLastFunding: BN, baseAssetReserve: BN, minBaseAssetReserve: BN, maxBaseAssetReserve: BN, markStd: BN, oracleStd: BN, longIntensity: BN, shortIntensity: BN, volume24H: BN, returnTerms?: boolean): number[] | {
42
+ longVolSpread: number;
43
+ shortVolSpread: number;
44
+ longSpreadwPS: number;
45
+ shortSpreadwPS: number;
46
+ maxTargetSpread: number;
47
+ inventorySpreadScale: number;
48
+ longSpreadwInvScale: number;
49
+ shortSpreadwInvScale: number;
50
+ effectiveLeverage: number;
51
+ effectiveLeverageCapped: number;
52
+ longSpreadwEL: number;
53
+ shortSpreadwEL: number;
54
+ revenueRetreatAmount: number;
55
+ halfRevenueRetreatAmount: number;
56
+ longSpreadwRevRetreat: number;
57
+ shortSpreadwRevRetreat: number;
58
+ totalSpread: number;
59
+ longSpread: number;
60
+ shortSpread: number;
61
+ };
42
62
  export declare function calculateSpread(amm: AMM, oraclePriceData: OraclePriceData): [number, number];
43
63
  export declare function calculateSpreadReserves(amm: AMM, oraclePriceData: OraclePriceData): {
44
64
  baseAssetReserve: any;
package/lib/math/amm.js CHANGED
@@ -250,8 +250,33 @@ function calculateVolSpreadBN(lastOracleConfPct, reservePrice, markStd, oracleSt
250
250
  return [longVolSpread, shortVolSpread];
251
251
  }
252
252
  exports.calculateVolSpreadBN = calculateVolSpreadBN;
253
- function calculateSpreadBN(baseSpread, lastOracleReservePriceSpreadPct, lastOracleConfPct, maxSpread, quoteAssetReserve, terminalQuoteAssetReserve, pegMultiplier, baseAssetAmountWithAmm, reservePrice, totalFeeMinusDistributions, netRevenueSinceLastFunding, baseAssetReserve, minBaseAssetReserve, maxBaseAssetReserve, markStd, oracleStd, longIntensity, shortIntensity, volume24H) {
253
+ function calculateSpreadBN(baseSpread, lastOracleReservePriceSpreadPct, lastOracleConfPct, maxSpread, quoteAssetReserve, terminalQuoteAssetReserve, pegMultiplier, baseAssetAmountWithAmm, reservePrice, totalFeeMinusDistributions, netRevenueSinceLastFunding, baseAssetReserve, minBaseAssetReserve, maxBaseAssetReserve, markStd, oracleStd, longIntensity, shortIntensity, volume24H, returnTerms = false) {
254
+ (0, assert_1.assert)(Number.isInteger(baseSpread));
255
+ (0, assert_1.assert)(Number.isInteger(maxSpread));
256
+ const spreadTerms = {
257
+ longVolSpread: 0,
258
+ shortVolSpread: 0,
259
+ longSpreadwPS: 0,
260
+ shortSpreadwPS: 0,
261
+ maxTargetSpread: 0,
262
+ inventorySpreadScale: 0,
263
+ longSpreadwInvScale: 0,
264
+ shortSpreadwInvScale: 0,
265
+ effectiveLeverage: 0,
266
+ effectiveLeverageCapped: 0,
267
+ longSpreadwEL: 0,
268
+ shortSpreadwEL: 0,
269
+ revenueRetreatAmount: 0,
270
+ halfRevenueRetreatAmount: 0,
271
+ longSpreadwRevRetreat: 0,
272
+ shortSpreadwRevRetreat: 0,
273
+ totalSpread: 0,
274
+ longSpread: 0,
275
+ shortSpread: 0,
276
+ };
254
277
  const [longVolSpread, shortVolSpread] = calculateVolSpreadBN(lastOracleConfPct, reservePrice, markStd, oracleStd, longIntensity, shortIntensity, volume24H);
278
+ spreadTerms.longVolSpread = longVolSpread.toNumber();
279
+ spreadTerms.shortVolSpread = shortVolSpread.toNumber();
255
280
  let longSpread = Math.max(baseSpread / 2, longVolSpread.toNumber());
256
281
  let shortSpread = Math.max(baseSpread / 2, shortVolSpread.toNumber());
257
282
  if (lastOracleReservePriceSpreadPct.gt(numericConstants_1.ZERO)) {
@@ -262,7 +287,9 @@ function calculateSpreadBN(baseSpread, lastOracleReservePriceSpreadPct, lastOrac
262
287
  longSpread = Math.max(longSpread, lastOracleReservePriceSpreadPct.abs().toNumber() +
263
288
  longVolSpread.toNumber());
264
289
  }
265
- const maxTargetSpread = Math.max(maxSpread, lastOracleReservePriceSpreadPct.abs().toNumber());
290
+ spreadTerms.longSpreadwPS = longSpread;
291
+ spreadTerms.shortSpreadwPS = shortSpread;
292
+ const maxTargetSpread = Math.floor(Math.max(maxSpread, lastOracleReservePriceSpreadPct.abs().toNumber()));
266
293
  const inventorySpreadScale = calculateInventoryScale(baseAssetAmountWithAmm, baseAssetReserve, minBaseAssetReserve, maxBaseAssetReserve, baseAssetAmountWithAmm.gt(numericConstants_1.ZERO) ? longSpread : shortSpread, maxTargetSpread);
267
294
  if (baseAssetAmountWithAmm.gt(numericConstants_1.ZERO)) {
268
295
  longSpread *= inventorySpreadScale;
@@ -270,49 +297,69 @@ function calculateSpreadBN(baseSpread, lastOracleReservePriceSpreadPct, lastOrac
270
297
  else if (baseAssetAmountWithAmm.lt(numericConstants_1.ZERO)) {
271
298
  shortSpread *= inventorySpreadScale;
272
299
  }
300
+ spreadTerms.maxTargetSpread = maxTargetSpread;
301
+ spreadTerms.inventorySpreadScale = inventorySpreadScale;
302
+ spreadTerms.longSpreadwInvScale = longSpread;
303
+ spreadTerms.shortSpreadwInvScale = shortSpread;
273
304
  const MAX_SPREAD_SCALE = 10;
274
305
  if (totalFeeMinusDistributions.gt(numericConstants_1.ZERO)) {
275
306
  const effectiveLeverage = calculateEffectiveLeverage(baseSpread, quoteAssetReserve, terminalQuoteAssetReserve, pegMultiplier, baseAssetAmountWithAmm, reservePrice, totalFeeMinusDistributions);
307
+ spreadTerms.effectiveLeverage = effectiveLeverage;
276
308
  const spreadScale = Math.min(MAX_SPREAD_SCALE, 1 + effectiveLeverage);
309
+ spreadTerms.effectiveLeverageCapped = spreadScale;
277
310
  if (baseAssetAmountWithAmm.gt(numericConstants_1.ZERO)) {
278
311
  longSpread *= spreadScale;
312
+ shortSpread = Math.floor(longSpread);
279
313
  }
280
314
  else {
281
315
  shortSpread *= spreadScale;
316
+ shortSpread = Math.floor(shortSpread);
282
317
  }
283
318
  }
284
319
  else {
285
320
  longSpread *= MAX_SPREAD_SCALE;
286
321
  shortSpread *= MAX_SPREAD_SCALE;
287
322
  }
323
+ spreadTerms.longSpreadwEL = longSpread;
324
+ spreadTerms.shortSpreadwEL = shortSpread;
288
325
  if (netRevenueSinceLastFunding.lt(numericConstants_1.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT)) {
289
- const retreatAmount = Math.min(maxTargetSpread / 10, Math.floor((baseSpread * netRevenueSinceLastFunding.abs().toNumber()) /
326
+ const revenueRetreatAmount = Math.min(maxTargetSpread / 10, Math.floor((baseSpread * netRevenueSinceLastFunding.abs().toNumber()) /
290
327
  numericConstants_1.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT.toNumber()));
291
- const halfRetreatAmount = Math.floor(retreatAmount / 2);
328
+ const halfRevenueRetreatAmount = Math.floor(revenueRetreatAmount / 2);
329
+ spreadTerms.revenueRetreatAmount = revenueRetreatAmount;
330
+ spreadTerms.halfRevenueRetreatAmount = halfRevenueRetreatAmount;
292
331
  if (baseAssetAmountWithAmm.gt(numericConstants_1.ZERO)) {
293
- longSpread += retreatAmount;
294
- shortSpread += halfRetreatAmount;
332
+ longSpread += revenueRetreatAmount;
333
+ shortSpread += halfRevenueRetreatAmount;
295
334
  }
296
335
  else if (baseAssetAmountWithAmm.lt(numericConstants_1.ZERO)) {
297
- longSpread += halfRetreatAmount;
298
- shortSpread += retreatAmount;
336
+ longSpread += halfRevenueRetreatAmount;
337
+ shortSpread += revenueRetreatAmount;
299
338
  }
300
339
  else {
301
- longSpread += halfRetreatAmount;
302
- shortSpread += halfRetreatAmount;
340
+ longSpread += halfRevenueRetreatAmount;
341
+ shortSpread += halfRevenueRetreatAmount;
303
342
  }
304
343
  }
344
+ spreadTerms.longSpreadwRevRetreat = longSpread;
345
+ spreadTerms.shortSpreadwRevRetreat = shortSpread;
305
346
  const totalSpread = longSpread + shortSpread;
306
347
  if (totalSpread > maxTargetSpread) {
307
348
  if (longSpread > shortSpread) {
308
349
  longSpread = Math.ceil((longSpread * maxTargetSpread) / totalSpread);
309
- shortSpread = maxTargetSpread - longSpread;
350
+ shortSpread = Math.floor(maxTargetSpread - longSpread);
310
351
  }
311
352
  else {
312
353
  shortSpread = Math.ceil((shortSpread * maxTargetSpread) / totalSpread);
313
- longSpread = maxTargetSpread - shortSpread;
354
+ longSpread = Math.floor(maxTargetSpread - shortSpread);
314
355
  }
315
356
  }
357
+ spreadTerms.totalSpread = totalSpread;
358
+ spreadTerms.longSpread = longSpread;
359
+ spreadTerms.shortSpread = shortSpread;
360
+ if (returnTerms) {
361
+ return spreadTerms;
362
+ }
316
363
  return [longSpread, shortSpread];
317
364
  }
318
365
  exports.calculateSpreadBN = calculateSpreadBN;
@@ -332,7 +379,9 @@ function calculateSpread(amm, oraclePriceData) {
332
379
  .div(reservePrice);
333
380
  const now = new anchor_1.BN(new Date().getTime() / 1000); //todo
334
381
  const liveOracleStd = (0, oracles_1.calculateLiveOracleStd)(amm, oraclePriceData, now);
335
- const [longSpread, shortSpread] = calculateSpreadBN(amm.baseSpread, targetMarkSpreadPct, confIntervalPct, amm.maxSpread, amm.quoteAssetReserve, amm.terminalQuoteAssetReserve, amm.pegMultiplier, amm.baseAssetAmountWithAmm, reservePrice, amm.totalFeeMinusDistributions, amm.netRevenueSinceLastFunding, amm.baseAssetReserve, amm.minBaseAssetReserve, amm.maxBaseAssetReserve, amm.markStd, liveOracleStd, amm.longIntensityVolume, amm.shortIntensityVolume, amm.volume24H);
382
+ const spreads = calculateSpreadBN(amm.baseSpread, targetMarkSpreadPct, confIntervalPct, amm.maxSpread, amm.quoteAssetReserve, amm.terminalQuoteAssetReserve, amm.pegMultiplier, amm.baseAssetAmountWithAmm, reservePrice, amm.totalFeeMinusDistributions, amm.netRevenueSinceLastFunding, amm.baseAssetReserve, amm.minBaseAssetReserve, amm.maxBaseAssetReserve, amm.markStd, liveOracleStd, amm.longIntensityVolume, amm.shortIntensityVolume, amm.volume24H);
383
+ const longSpread = spreads[0];
384
+ const shortSpread = spreads[1];
336
385
  return [longSpread, shortSpread];
337
386
  }
338
387
  exports.calculateSpread = calculateSpread;
@@ -59,8 +59,7 @@ function calculateLiveOracleTwap(amm, oraclePriceData, now) {
59
59
  const clampedOraclePrice = index_1.BN.min(amm.historicalOracleData.lastOraclePriceTwap.add(clampRange), index_1.BN.max(oraclePriceData.price, amm.historicalOracleData.lastOraclePriceTwap.sub(clampRange)));
60
60
  const newOracleTwap = amm.historicalOracleData.lastOraclePriceTwap
61
61
  .mul(sinceStart)
62
- .add(clampedOraclePrice)
63
- .mul(sinceLastUpdate)
62
+ .add(clampedOraclePrice.mul(sinceLastUpdate))
64
63
  .div(sinceStart.add(sinceLastUpdate));
65
64
  return newOracleTwap;
66
65
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.0.17",
3
+ "version": "2.0.18",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
package/src/index.ts CHANGED
@@ -63,6 +63,7 @@ export * from './constants/spotMarkets';
63
63
  export * from './driftClientConfig';
64
64
  export * from './dlob/DLOB';
65
65
  export * from './dlob/DLOBNode';
66
+ export * from './dlob/DLOBOrders';
66
67
  export * from './dlob/NodeList';
67
68
  export * from './userMap/userMap';
68
69
  export * from './userMap/userStatsMap';
package/src/math/amm.ts CHANGED
@@ -479,8 +479,34 @@ export function calculateSpreadBN(
479
479
  oracleStd: BN,
480
480
  longIntensity: BN,
481
481
  shortIntensity: BN,
482
- volume24H: BN
483
- ): [number, number] {
482
+ volume24H: BN,
483
+ returnTerms = false
484
+ ) {
485
+ assert(Number.isInteger(baseSpread));
486
+ assert(Number.isInteger(maxSpread));
487
+
488
+ const spreadTerms = {
489
+ longVolSpread: 0,
490
+ shortVolSpread: 0,
491
+ longSpreadwPS: 0,
492
+ shortSpreadwPS: 0,
493
+ maxTargetSpread: 0,
494
+ inventorySpreadScale: 0,
495
+ longSpreadwInvScale: 0,
496
+ shortSpreadwInvScale: 0,
497
+ effectiveLeverage: 0,
498
+ effectiveLeverageCapped: 0,
499
+ longSpreadwEL: 0,
500
+ shortSpreadwEL: 0,
501
+ revenueRetreatAmount: 0,
502
+ halfRevenueRetreatAmount: 0,
503
+ longSpreadwRevRetreat: 0,
504
+ shortSpreadwRevRetreat: 0,
505
+ totalSpread: 0,
506
+ longSpread: 0,
507
+ shortSpread: 0,
508
+ };
509
+
484
510
  const [longVolSpread, shortVolSpread] = calculateVolSpreadBN(
485
511
  lastOracleConfPct,
486
512
  reservePrice,
@@ -491,6 +517,9 @@ export function calculateSpreadBN(
491
517
  volume24H
492
518
  );
493
519
 
520
+ spreadTerms.longVolSpread = longVolSpread.toNumber();
521
+ spreadTerms.shortVolSpread = shortVolSpread.toNumber();
522
+
494
523
  let longSpread = Math.max(baseSpread / 2, longVolSpread.toNumber());
495
524
  let shortSpread = Math.max(baseSpread / 2, shortVolSpread.toNumber());
496
525
 
@@ -507,10 +536,11 @@ export function calculateSpreadBN(
507
536
  longVolSpread.toNumber()
508
537
  );
509
538
  }
539
+ spreadTerms.longSpreadwPS = longSpread;
540
+ spreadTerms.shortSpreadwPS = shortSpread;
510
541
 
511
- const maxTargetSpread: number = Math.max(
512
- maxSpread,
513
- lastOracleReservePriceSpreadPct.abs().toNumber()
542
+ const maxTargetSpread: number = Math.floor(
543
+ Math.max(maxSpread, lastOracleReservePriceSpreadPct.abs().toNumber())
514
544
  );
515
545
 
516
546
  const inventorySpreadScale = calculateInventoryScale(
@@ -527,6 +557,10 @@ export function calculateSpreadBN(
527
557
  } else if (baseAssetAmountWithAmm.lt(ZERO)) {
528
558
  shortSpread *= inventorySpreadScale;
529
559
  }
560
+ spreadTerms.maxTargetSpread = maxTargetSpread;
561
+ spreadTerms.inventorySpreadScale = inventorySpreadScale;
562
+ spreadTerms.longSpreadwInvScale = longSpread;
563
+ spreadTerms.shortSpreadwInvScale = shortSpread;
530
564
 
531
565
  const MAX_SPREAD_SCALE = 10;
532
566
  if (totalFeeMinusDistributions.gt(ZERO)) {
@@ -539,53 +573,76 @@ export function calculateSpreadBN(
539
573
  reservePrice,
540
574
  totalFeeMinusDistributions
541
575
  );
576
+ spreadTerms.effectiveLeverage = effectiveLeverage;
577
+
542
578
  const spreadScale = Math.min(MAX_SPREAD_SCALE, 1 + effectiveLeverage);
579
+ spreadTerms.effectiveLeverageCapped = spreadScale;
580
+
543
581
  if (baseAssetAmountWithAmm.gt(ZERO)) {
544
582
  longSpread *= spreadScale;
583
+ shortSpread = Math.floor(longSpread);
545
584
  } else {
546
585
  shortSpread *= spreadScale;
586
+ shortSpread = Math.floor(shortSpread);
547
587
  }
548
588
  } else {
549
589
  longSpread *= MAX_SPREAD_SCALE;
550
590
  shortSpread *= MAX_SPREAD_SCALE;
551
591
  }
552
592
 
593
+ spreadTerms.longSpreadwEL = longSpread;
594
+ spreadTerms.shortSpreadwEL = shortSpread;
595
+
553
596
  if (
554
597
  netRevenueSinceLastFunding.lt(
555
598
  DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT
556
599
  )
557
600
  ) {
558
- const retreatAmount = Math.min(
601
+ const revenueRetreatAmount = Math.min(
559
602
  maxTargetSpread / 10,
560
603
  Math.floor(
561
604
  (baseSpread * netRevenueSinceLastFunding.abs().toNumber()) /
562
605
  DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT.toNumber()
563
606
  )
564
607
  );
565
- const halfRetreatAmount = Math.floor(retreatAmount / 2);
608
+ const halfRevenueRetreatAmount = Math.floor(revenueRetreatAmount / 2);
609
+
610
+ spreadTerms.revenueRetreatAmount = revenueRetreatAmount;
611
+ spreadTerms.halfRevenueRetreatAmount = halfRevenueRetreatAmount;
612
+
566
613
  if (baseAssetAmountWithAmm.gt(ZERO)) {
567
- longSpread += retreatAmount;
568
- shortSpread += halfRetreatAmount;
614
+ longSpread += revenueRetreatAmount;
615
+ shortSpread += halfRevenueRetreatAmount;
569
616
  } else if (baseAssetAmountWithAmm.lt(ZERO)) {
570
- longSpread += halfRetreatAmount;
571
- shortSpread += retreatAmount;
617
+ longSpread += halfRevenueRetreatAmount;
618
+ shortSpread += revenueRetreatAmount;
572
619
  } else {
573
- longSpread += halfRetreatAmount;
574
- shortSpread += halfRetreatAmount;
620
+ longSpread += halfRevenueRetreatAmount;
621
+ shortSpread += halfRevenueRetreatAmount;
575
622
  }
576
623
  }
577
624
 
625
+ spreadTerms.longSpreadwRevRetreat = longSpread;
626
+ spreadTerms.shortSpreadwRevRetreat = shortSpread;
627
+
578
628
  const totalSpread = longSpread + shortSpread;
579
629
  if (totalSpread > maxTargetSpread) {
580
630
  if (longSpread > shortSpread) {
581
631
  longSpread = Math.ceil((longSpread * maxTargetSpread) / totalSpread);
582
- shortSpread = maxTargetSpread - longSpread;
632
+ shortSpread = Math.floor(maxTargetSpread - longSpread);
583
633
  } else {
584
634
  shortSpread = Math.ceil((shortSpread * maxTargetSpread) / totalSpread);
585
- longSpread = maxTargetSpread - shortSpread;
635
+ longSpread = Math.floor(maxTargetSpread - shortSpread);
586
636
  }
587
637
  }
588
638
 
639
+ spreadTerms.totalSpread = totalSpread;
640
+ spreadTerms.longSpread = longSpread;
641
+ spreadTerms.shortSpread = shortSpread;
642
+
643
+ if (returnTerms) {
644
+ return spreadTerms;
645
+ }
589
646
  return [longSpread, shortSpread];
590
647
  }
591
648
 
@@ -617,7 +674,7 @@ export function calculateSpread(
617
674
  const now = new BN(new Date().getTime() / 1000); //todo
618
675
  const liveOracleStd = calculateLiveOracleStd(amm, oraclePriceData, now);
619
676
 
620
- const [longSpread, shortSpread] = calculateSpreadBN(
677
+ const spreads = calculateSpreadBN(
621
678
  amm.baseSpread,
622
679
  targetMarkSpreadPct,
623
680
  confIntervalPct,
@@ -638,6 +695,8 @@ export function calculateSpread(
638
695
  amm.shortIntensityVolume,
639
696
  amm.volume24H
640
697
  );
698
+ const longSpread = spreads[0];
699
+ const shortSpread = spreads[1];
641
700
 
642
701
  return [longSpread, shortSpread];
643
702
  }
@@ -113,8 +113,7 @@ export function calculateLiveOracleTwap(
113
113
 
114
114
  const newOracleTwap = amm.historicalOracleData.lastOraclePriceTwap
115
115
  .mul(sinceStart)
116
- .add(clampedOraclePrice)
117
- .mul(sinceLastUpdate)
116
+ .add(clampedOraclePrice.mul(sinceLastUpdate))
118
117
  .div(sinceStart.add(sinceLastUpdate));
119
118
 
120
119
  return newOracleTwap;
@@ -0,0 +1,178 @@
1
+ import {
2
+ BN,
3
+ PEG_PRECISION, PRICE_PRECISION,
4
+ AMM_RESERVE_PRECISION,
5
+ QUOTE_PRECISION,
6
+ calculateSpreadBN,
7
+ ZERO,
8
+ calculateLiveOracleStd,
9
+ calculateLiveOracleTwap
10
+ } from '../../src';
11
+ import {
12
+ mockPerpMarkets,
13
+ } from '../dlob/helpers';
14
+
15
+ import { assert } from '../../src/assert/assert';
16
+
17
+ class AMMSpreadTerms {
18
+ longVolSpread: number;
19
+ shortVolSpread: number;
20
+ longSpreadwPS: number;
21
+ shortSpreadwPS: number;
22
+ maxTargetSpread: number;
23
+ inventorySpreadScale: number;
24
+ longSpreadwInvScale: number;
25
+ shortSpreadwInvScale: number;
26
+ effectiveLeverage: number;
27
+ effectiveLeverageCapped: number;
28
+ longSpreadwEL: number;
29
+ shortSpreadwEL: number;
30
+ revenueRetreatAmount: number;
31
+ halfRevenueRetreatAmount: number;
32
+ longSpreadwRevRetreat: number;
33
+ shortSpreadwRevRetreat: number;
34
+ totalSpread: number;
35
+ longSpread: number;
36
+ shortSpread: number;
37
+ }
38
+
39
+ describe('AMM Tests', () => {
40
+ it('Various Spreads', () => {
41
+
42
+ const baseSpread: number = .025 * 1e6;
43
+ const lastOracleReservePriceSpreadPct: BN = ZERO;
44
+ const lastOracleConfPct: BN = ZERO;
45
+ const maxSpread: number = .03 * 1e6;
46
+ const quoteAssetReserve: BN = new BN(AMM_RESERVE_PRECISION.toNumber() * 100);
47
+ const terminalQuoteAssetReserve: BN = new BN(AMM_RESERVE_PRECISION.toNumber() * 100);
48
+ const pegMultiplier: BN = new BN(13.455 * PEG_PRECISION.toNumber());
49
+ const baseAssetAmountWithAmm: BN = ZERO;
50
+ const reservePrice: BN = new BN(13.455 * PRICE_PRECISION.toNumber());
51
+ const totalFeeMinusDistributions: BN = new BN(1);
52
+ const netRevenueSinceLastFunding: BN = new BN(QUOTE_PRECISION.toNumber() * 2);
53
+ const baseAssetReserve: BN = new BN(AMM_RESERVE_PRECISION.toNumber() * 100);
54
+ const minBaseAssetReserve: BN = new BN(AMM_RESERVE_PRECISION.toNumber() * 90);
55
+ const maxBaseAssetReserve: BN = new BN(AMM_RESERVE_PRECISION.toNumber() * 110);
56
+ const markStd: BN = new BN(.45 * PRICE_PRECISION.toNumber());
57
+ const oracleStd: BN = new BN(.55 * PRICE_PRECISION.toNumber());
58
+ const longIntensity: BN = new BN(QUOTE_PRECISION.toNumber() * 20);
59
+ const shortIntensity: BN =new BN(QUOTE_PRECISION.toNumber() * 2);
60
+ const volume24H: BN = new BN(QUOTE_PRECISION.toNumber() * 25);
61
+
62
+ const spreads = calculateSpreadBN(
63
+ baseSpread,
64
+ lastOracleReservePriceSpreadPct,
65
+ lastOracleConfPct,
66
+ maxSpread,
67
+ quoteAssetReserve,
68
+ terminalQuoteAssetReserve,
69
+ pegMultiplier,
70
+ baseAssetAmountWithAmm,
71
+ reservePrice,
72
+ totalFeeMinusDistributions,
73
+ netRevenueSinceLastFunding,
74
+ baseAssetReserve,
75
+ minBaseAssetReserve,
76
+ maxBaseAssetReserve,
77
+ markStd,
78
+ oracleStd,
79
+ longIntensity,
80
+ shortIntensity,
81
+ volume24H,
82
+ );
83
+ const l1 = spreads[0];
84
+ const s1 = spreads[1];
85
+
86
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
87
+ // @ts-ignore
88
+ const terms1: AMMSpreadTerms = calculateSpreadBN(
89
+ baseSpread,
90
+ lastOracleReservePriceSpreadPct,
91
+ lastOracleConfPct,
92
+ maxSpread,
93
+ quoteAssetReserve,
94
+ terminalQuoteAssetReserve,
95
+ pegMultiplier,
96
+ baseAssetAmountWithAmm,
97
+ reservePrice,
98
+ totalFeeMinusDistributions,
99
+ netRevenueSinceLastFunding,
100
+ baseAssetReserve,
101
+ minBaseAssetReserve,
102
+ maxBaseAssetReserve,
103
+ markStd,
104
+ oracleStd,
105
+ longIntensity,
106
+ shortIntensity,
107
+ volume24H,
108
+ true
109
+ );
110
+ console.log(terms1);
111
+
112
+ console.log('long/short spread:', l1, s1);
113
+ assert(l1==14864);
114
+ assert(s1==12500);
115
+ assert(l1==terms1.longSpread);
116
+ assert(s1==terms1.shortSpread);
117
+
118
+
119
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
120
+ // @ts-ignore
121
+ const terms2: AMMSpreadTerms = calculateSpreadBN(
122
+ 300,
123
+ new BN(0),
124
+ new BN(484),
125
+ 47500,
126
+ new BN(923807816209694),
127
+ new BN(925117623772584),
128
+ new BN(13731157),
129
+ new BN(-1314027016625),
130
+ new BN(13667686),
131
+ new BN(115876379475),
132
+ new BN(91316628),
133
+ new BN(928097825691666),
134
+ new BN(907979542352912),
135
+ new BN(945977491145601),
136
+ new BN(161188),
137
+ new BN(1459632439),
138
+ new BN(12358265776),
139
+ new BN(72230366233),
140
+ new BN(432067603632),
141
+ true
142
+ );
143
+
144
+ console.log(terms2);
145
+ assert(terms2.effectiveLeverageCapped>=1.0002);
146
+ assert(terms2.inventorySpreadScale==10);
147
+ assert(terms2.longSpread==798);
148
+ assert(terms2.shortSpread==46702);
149
+
150
+ });
151
+
152
+ it('live update functions', () => {
153
+
154
+ const mockAmm = mockPerpMarkets[0].amm;
155
+ const now = new BN(new Date().getTime() / 1000); //todo
156
+
157
+ const oraclePriceData = {
158
+ price: new BN(13.553 * PRICE_PRECISION.toNumber()),
159
+ slot: new BN(68 + 1),
160
+ confidence: new BN(1),
161
+ hasSufficientNumberOfDataPoints: true,
162
+ };
163
+ mockAmm.oracleStd = new BN(.18 * PRICE_PRECISION.toNumber());
164
+ mockAmm.fundingPeriod = new BN(3600);
165
+ mockAmm.historicalOracleData.lastOraclePriceTwap = oraclePriceData.price.mul(new BN(999)).div(new BN(1000));
166
+ mockAmm.historicalOracleData.lastOraclePriceTwapTs = now.sub(new BN(11));
167
+
168
+
169
+ const liveOracleTwap = calculateLiveOracleTwap(mockAmm, oraclePriceData, now);
170
+ console.log('liveOracleTwap:', liveOracleTwap.toNumber());
171
+ assert(liveOracleTwap.eq(new BN(13539488)));
172
+
173
+
174
+ const liveOracleStd = calculateLiveOracleStd(mockAmm, oraclePriceData, now);
175
+ console.log('liveOracleStd:', liveOracleStd.toNumber());
176
+ assert(liveOracleStd.eq(new BN(192962)));
177
+ });
178
+ });
@@ -1,9 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.assert = void 0;
4
- function assert(condition, error) {
5
- if (!condition) {
6
- throw new Error(error || 'Unspecified AssertionError');
7
- }
8
- }
9
- exports.assert = assert;
@@ -1,157 +0,0 @@
1
- 'use strict';
2
- var __awaiter =
3
- (this && this.__awaiter) ||
4
- function (thisArg, _arguments, P, generator) {
5
- function adopt(value) {
6
- return value instanceof P
7
- ? value
8
- : new P(function (resolve) {
9
- resolve(value);
10
- });
11
- }
12
- return new (P || (P = Promise))(function (resolve, reject) {
13
- function fulfilled(value) {
14
- try {
15
- step(generator.next(value));
16
- } catch (e) {
17
- reject(e);
18
- }
19
- }
20
- function rejected(value) {
21
- try {
22
- step(generator['throw'](value));
23
- } catch (e) {
24
- reject(e);
25
- }
26
- }
27
- function step(result) {
28
- result.done
29
- ? resolve(result.value)
30
- : adopt(result.value).then(fulfilled, rejected);
31
- }
32
- step((generator = generator.apply(thisArg, _arguments || [])).next());
33
- });
34
- };
35
- Object.defineProperty(exports, '__esModule', { value: true });
36
- exports.getTokenAddress = void 0;
37
- const anchor_1 = require('@project-serum/anchor');
38
- const __1 = require('..');
39
- const spl_token_1 = require('@solana/spl-token');
40
- const web3_js_1 = require('@solana/web3.js');
41
- const __2 = require('..');
42
- const banks_1 = require('../constants/spotMarkets');
43
- const getTokenAddress = (mintAddress, userPubKey) => {
44
- return spl_token_1.Token.getAssociatedTokenAddress(
45
- new web3_js_1.PublicKey(`ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL`),
46
- spl_token_1.TOKEN_PROGRAM_ID,
47
- new web3_js_1.PublicKey(mintAddress),
48
- new web3_js_1.PublicKey(userPubKey)
49
- );
50
- };
51
- exports.getTokenAddress = getTokenAddress;
52
- const main = () =>
53
- __awaiter(void 0, void 0, void 0, function* () {
54
- // Initialize Drift SDK
55
- const sdkConfig = __2.initialize({ env: 'devnet' });
56
- // Set up the Wallet and Provider
57
- const privateKey = process.env.BOT_PRIVATE_KEY; // stored as an array string
58
- const keypair = web3_js_1.Keypair.fromSecretKey(
59
- Uint8Array.from(JSON.parse(privateKey))
60
- );
61
- const wallet = new __1.Wallet(keypair);
62
- // Set up the Connection
63
- const rpcAddress = process.env.RPC_ADDRESS; // can use: https://api.devnet.solana.com for devnet; https://api.mainnet-beta.solana.com for mainnet;
64
- const connection = new web3_js_1.Connection(rpcAddress);
65
- // Set up the Provider
66
- const provider = new anchor_1.AnchorProvider(
67
- connection,
68
- wallet,
69
- anchor_1.AnchorProvider.defaultOptions()
70
- );
71
- // Check SOL Balance
72
- const lamportsBalance = yield connection.getBalance(wallet.publicKey);
73
- console.log('SOL balance:', lamportsBalance / Math.pow(10, 9));
74
- // Misc. other things to set up
75
- const usdcTokenAddress = yield exports.getTokenAddress(
76
- sdkConfig.USDC_MINT_ADDRESS,
77
- wallet.publicKey.toString()
78
- );
79
- // Set up the Drift Clearing House
80
- const clearingHousePublicKey = new web3_js_1.PublicKey(
81
- sdkConfig.DRIFT_PROGRAM_ID
82
- );
83
- const clearingHouse = new __2.ClearingHouse({
84
- connection,
85
- wallet: provider.wallet,
86
- programID: clearingHousePublicKey,
87
- });
88
- yield clearingHouse.subscribe();
89
- // Set up Clearing House user client
90
- const user = new __2.ClearingHouseUser({
91
- clearingHouse,
92
- userAccountPublicKey: yield clearingHouse.getUserAccountPublicKey(),
93
- });
94
- //// Check if clearing house account exists for the current wallet
95
- const userAccountExists = yield user.exists();
96
- if (!userAccountExists) {
97
- //// Create a Clearing House account by Depositing some USDC ($10,000 in this case)
98
- const depositAmount = new anchor_1.BN(10000).mul(__2.QUOTE_PRECISION);
99
- yield clearingHouse.initializeUserAccountAndDepositCollateral(
100
- depositAmount,
101
- yield exports.getTokenAddress(
102
- usdcTokenAddress.toString(),
103
- wallet.publicKey.toString()
104
- ),
105
- banks_1.SpotMarkets['devnet'][0].marketIndex
106
- );
107
- }
108
- yield user.subscribe();
109
- // Get current price
110
- const solMarketInfo = sdkConfig.PERP_MARKETS.find(
111
- (market) => market.baseAssetSymbol === 'SOL'
112
- );
113
- const currentMarketPrice = __2.calculateMarkPrice(
114
- clearingHouse.getMarketAccount(solMarketInfo.marketIndex),
115
- undefined
116
- );
117
- const formattedPrice = __2.convertToNumber(
118
- currentMarketPrice,
119
- __2.PRICE_PRECISION
120
- );
121
- console.log(`Current Market Price is $${formattedPrice}`);
122
- // Estimate the slippage for a $5000 LONG trade
123
- const solMarketAccount = clearingHouse.getMarketAccount(
124
- solMarketInfo.marketIndex
125
- );
126
- const longAmount = new anchor_1.BN(5000).mul(__2.QUOTE_PRECISION);
127
- const slippage = __2.convertToNumber(
128
- __2.calculateTradeSlippage(
129
- __2.PositionDirection.LONG,
130
- longAmount,
131
- solMarketAccount,
132
- 'quote',
133
- undefined
134
- )[0],
135
- __2.PRICE_PRECISION
136
- );
137
- console.log(
138
- `Slippage for a $5000 LONG on the SOL market would be $${slippage}`
139
- );
140
- // Make a $5000 LONG trade
141
- yield clearingHouse.openPosition(
142
- __2.PositionDirection.LONG,
143
- longAmount,
144
- solMarketInfo.marketIndex
145
- );
146
- console.log(`LONGED $5000 SOL`);
147
- // Reduce the position by $2000
148
- const reduceAmount = new anchor_1.BN(2000).mul(__2.QUOTE_PRECISION);
149
- yield clearingHouse.openPosition(
150
- __2.PositionDirection.SHORT,
151
- reduceAmount,
152
- solMarketInfo.marketIndex
153
- );
154
- // Close the rest of the position
155
- yield clearingHouse.closePosition(solMarketInfo.marketIndex);
156
- });
157
- main();
@@ -1,38 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseTokenAccount = void 0;
4
- const spl_token_1 = require("@solana/spl-token");
5
- const web3_js_1 = require("@solana/web3.js");
6
- function parseTokenAccount(data) {
7
- const accountInfo = spl_token_1.AccountLayout.decode(data);
8
- accountInfo.mint = new web3_js_1.PublicKey(accountInfo.mint);
9
- accountInfo.owner = new web3_js_1.PublicKey(accountInfo.owner);
10
- accountInfo.amount = spl_token_1.u64.fromBuffer(accountInfo.amount);
11
- if (accountInfo.delegateOption === 0) {
12
- accountInfo.delegate = null;
13
- // eslint-disable-next-line new-cap
14
- accountInfo.delegatedAmount = new spl_token_1.u64(0);
15
- }
16
- else {
17
- accountInfo.delegate = new web3_js_1.PublicKey(accountInfo.delegate);
18
- accountInfo.delegatedAmount = spl_token_1.u64.fromBuffer(accountInfo.delegatedAmount);
19
- }
20
- accountInfo.isInitialized = accountInfo.state !== 0;
21
- accountInfo.isFrozen = accountInfo.state === 2;
22
- if (accountInfo.isNativeOption === 1) {
23
- accountInfo.rentExemptReserve = spl_token_1.u64.fromBuffer(accountInfo.isNative);
24
- accountInfo.isNative = true;
25
- }
26
- else {
27
- accountInfo.rentExemptReserve = null;
28
- accountInfo.isNative = false;
29
- }
30
- if (accountInfo.closeAuthorityOption === 0) {
31
- accountInfo.closeAuthority = null;
32
- }
33
- else {
34
- accountInfo.closeAuthority = new web3_js_1.PublicKey(accountInfo.closeAuthority);
35
- }
36
- return accountInfo;
37
- }
38
- exports.parseTokenAccount = parseTokenAccount;
package/src/tx/types.js DELETED
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
package/src/tx/utils.js DELETED
@@ -1,17 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.wrapInTx = void 0;
4
- const web3_js_1 = require("@solana/web3.js");
5
- const COMPUTE_UNITS_DEFAULT = 200000;
6
- function wrapInTx(instruction, computeUnits = 600000 // TODO, requires less code change
7
- ) {
8
- const tx = new web3_js_1.Transaction();
9
- if (computeUnits != COMPUTE_UNITS_DEFAULT) {
10
- tx.add(web3_js_1.ComputeBudgetProgram.requestUnits({
11
- units: computeUnits,
12
- additionalFee: 0,
13
- }));
14
- }
15
- return tx.add(instruction);
16
- }
17
- exports.wrapInTx = wrapInTx;
@@ -1,27 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.findComputeUnitConsumption = void 0;
13
- function findComputeUnitConsumption(programId, connection, txSignature, commitment = 'confirmed') {
14
- return __awaiter(this, void 0, void 0, function* () {
15
- const tx = yield connection.getTransaction(txSignature, { commitment });
16
- const computeUnits = [];
17
- const regex = new RegExp(`Program ${programId.toString()} consumed ([0-9]{0,6}) of ([0-9]{0,7}) compute units`);
18
- tx.meta.logMessages.forEach((logMessage) => {
19
- const match = logMessage.match(regex);
20
- if (match && match[1]) {
21
- computeUnits.push(match[1]);
22
- }
23
- });
24
- return computeUnits;
25
- });
26
- }
27
- exports.findComputeUnitConsumption = findComputeUnitConsumption;
@@ -1,9 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getTokenAddress = void 0;
4
- const spl_token_1 = require("@solana/spl-token");
5
- const web3_js_1 = require("@solana/web3.js");
6
- const getTokenAddress = (mintAddress, userPubKey) => {
7
- return spl_token_1.Token.getAssociatedTokenAddress(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, new web3_js_1.PublicKey(mintAddress), new web3_js_1.PublicKey(userPubKey));
8
- };
9
- exports.getTokenAddress = getTokenAddress;
@@ -1,14 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.promiseTimeout = void 0;
4
- function promiseTimeout(promise, timeoutMs) {
5
- let timeoutId;
6
- const timeoutPromise = new Promise((resolve) => {
7
- timeoutId = setTimeout(() => resolve(null), timeoutMs);
8
- });
9
- return Promise.race([promise, timeoutPromise]).then((result) => {
10
- clearTimeout(timeoutId);
11
- return result;
12
- });
13
- }
14
- exports.promiseTimeout = promiseTimeout;
package/src/util/tps.js DELETED
@@ -1,27 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.estimateTps = void 0;
13
- function estimateTps(programId, connection, failed) {
14
- return __awaiter(this, void 0, void 0, function* () {
15
- let signatures = yield connection.getSignaturesForAddress(programId, undefined, 'finalized');
16
- if (failed) {
17
- signatures = signatures.filter((signature) => signature.err);
18
- }
19
- const numberOfSignatures = signatures.length;
20
- if (numberOfSignatures === 0) {
21
- return 0;
22
- }
23
- return (numberOfSignatures /
24
- (signatures[0].blockTime - signatures[numberOfSignatures - 1].blockTime));
25
- });
26
- }
27
- exports.estimateTps = estimateTps;