@drift-labs/sdk 2.0.15 → 2.0.17

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.
@@ -0,0 +1,245 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "name": "dlob",
4
+ "instructions": [],
5
+ "accounts": [],
6
+ "types": [
7
+ {
8
+ "name": "DLOBOrders",
9
+ "type": {
10
+ "vec": {
11
+ "defined": "DLOBOrder"
12
+ }
13
+ }
14
+ },
15
+ {
16
+ "name": "DLOBOrder",
17
+ "type": {
18
+ "kind": "struct",
19
+ "fields": [
20
+ {
21
+ "name": "user",
22
+ "type": "publicKey"
23
+ },
24
+ {
25
+ "name": "order",
26
+ "type": {
27
+ "defined": "Order"
28
+ }
29
+ }
30
+ ]
31
+ }
32
+ },
33
+ {
34
+ "name": "Order",
35
+ "type": {
36
+ "kind": "struct",
37
+ "fields": [
38
+ {
39
+ "name": "slot",
40
+ "type": "u64"
41
+ },
42
+ {
43
+ "name": "price",
44
+ "type": "u64"
45
+ },
46
+ {
47
+ "name": "baseAssetAmount",
48
+ "type": "u64"
49
+ },
50
+ {
51
+ "name": "baseAssetAmountFilled",
52
+ "type": "u64"
53
+ },
54
+ {
55
+ "name": "quoteAssetAmountFilled",
56
+ "type": "u64"
57
+ },
58
+ {
59
+ "name": "triggerPrice",
60
+ "type": "u64"
61
+ },
62
+ {
63
+ "name": "auctionStartPrice",
64
+ "type": "u64"
65
+ },
66
+ {
67
+ "name": "auctionEndPrice",
68
+ "type": "u64"
69
+ },
70
+ {
71
+ "name": "maxTs",
72
+ "type": "i64"
73
+ },
74
+ {
75
+ "name": "oraclePriceOffset",
76
+ "type": "i32"
77
+ },
78
+ {
79
+ "name": "orderId",
80
+ "type": "u32"
81
+ },
82
+ {
83
+ "name": "marketIndex",
84
+ "type": "u16"
85
+ },
86
+ {
87
+ "name": "status",
88
+ "type": {
89
+ "defined": "OrderStatus"
90
+ }
91
+ },
92
+ {
93
+ "name": "orderType",
94
+ "type": {
95
+ "defined": "OrderType"
96
+ }
97
+ },
98
+ {
99
+ "name": "marketType",
100
+ "type": {
101
+ "defined": "MarketType"
102
+ }
103
+ },
104
+ {
105
+ "name": "userOrderId",
106
+ "type": "u8"
107
+ },
108
+ {
109
+ "name": "existingPositionDirection",
110
+ "type": {
111
+ "defined": "PositionDirection"
112
+ }
113
+ },
114
+ {
115
+ "name": "direction",
116
+ "type": {
117
+ "defined": "PositionDirection"
118
+ }
119
+ },
120
+ {
121
+ "name": "reduceOnly",
122
+ "type": "bool"
123
+ },
124
+ {
125
+ "name": "postOnly",
126
+ "type": "bool"
127
+ },
128
+ {
129
+ "name": "immediateOrCancel",
130
+ "type": "bool"
131
+ },
132
+ {
133
+ "name": "triggerCondition",
134
+ "type": {
135
+ "defined": "OrderTriggerCondition"
136
+ }
137
+ },
138
+ {
139
+ "name": "auctionDuration",
140
+ "type": "u8"
141
+ },
142
+ {
143
+ "name": "padding",
144
+ "type": {
145
+ "array": [
146
+ "u8",
147
+ 3
148
+ ]
149
+ }
150
+ }
151
+ ]
152
+ }
153
+ },
154
+ {
155
+ "name": "OrderStatus",
156
+ "type": {
157
+ "kind": "enum",
158
+ "variants": [
159
+ {
160
+ "name": "Init"
161
+ },
162
+ {
163
+ "name": "Open"
164
+ },
165
+ {
166
+ "name": "Filled"
167
+ },
168
+ {
169
+ "name": "Canceled"
170
+ }
171
+ ]
172
+ }
173
+ },
174
+ {
175
+ "name": "OrderType",
176
+ "type": {
177
+ "kind": "enum",
178
+ "variants": [
179
+ {
180
+ "name": "Market"
181
+ },
182
+ {
183
+ "name": "Limit"
184
+ },
185
+ {
186
+ "name": "TriggerMarket"
187
+ },
188
+ {
189
+ "name": "TriggerLimit"
190
+ }
191
+ ]
192
+ }
193
+ },
194
+ {
195
+ "name": "OrderTriggerCondition",
196
+ "type": {
197
+ "kind": "enum",
198
+ "variants": [
199
+ {
200
+ "name": "Above"
201
+ },
202
+ {
203
+ "name": "Below"
204
+ },
205
+ {
206
+ "name": "TriggeredAbove"
207
+ },
208
+ {
209
+ "name": "TriggeredBelow"
210
+ }
211
+ ]
212
+ }
213
+ },
214
+ {
215
+ "name": "MarketType",
216
+ "type": {
217
+ "kind": "enum",
218
+ "variants": [
219
+ {
220
+ "name": "Spot"
221
+ },
222
+ {
223
+ "name": "Perp"
224
+ }
225
+ ]
226
+ }
227
+ },
228
+ {
229
+ "name": "PositionDirection",
230
+ "type": {
231
+ "kind": "enum",
232
+ "variants": [
233
+ {
234
+ "name": "Long"
235
+ },
236
+ {
237
+ "name": "Short"
238
+ }
239
+ ]
240
+ }
241
+ }
242
+ ],
243
+ "events": [],
244
+ "errors": []
245
+ }
@@ -8519,6 +8519,11 @@
8519
8519
  "code": 6221,
8520
8520
  "name": "SpotFulfillmentConfigDisabled",
8521
8521
  "msg": "Spot Fulfullment Config Disabled"
8522
+ },
8523
+ {
8524
+ "code": 6222,
8525
+ "name": "InvalidMaker",
8526
+ "msg": "Invalid Maker"
8522
8527
  }
8523
8528
  ]
8524
8529
  }
package/src/math/amm.ts CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  PRICE_DIV_PEG,
13
13
  PERCENTAGE_PRECISION,
14
14
  BASE_PRECISION,
15
+ DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT,
15
16
  } from '../constants/numericConstants';
16
17
  import {
17
18
  AMM,
@@ -190,11 +191,15 @@ export function calculateUpdatedAMMSpreadReserves(
190
191
  oraclePriceData: OraclePriceData
191
192
  ): { baseAssetReserve: BN; quoteAssetReserve: BN; sqrtK: BN; newPeg: BN } {
192
193
  const newAmm = calculateUpdatedAMM(amm, oraclePriceData);
193
- const dirReserves = calculateSpreadReserves(
194
+ const [shortReserves, longReserves] = calculateSpreadReserves(
194
195
  newAmm,
195
- direction,
196
196
  oraclePriceData
197
197
  );
198
+
199
+ const dirReserves = isVariant(direction, 'long')
200
+ ? longReserves
201
+ : shortReserves;
202
+
198
203
  const result = {
199
204
  baseAssetReserve: dirReserves.baseAssetReserve,
200
205
  quoteAssetReserve: dirReserves.quoteAssetReserve,
@@ -217,14 +222,8 @@ export function calculateBidAskPrice(
217
222
  newAmm = amm;
218
223
  }
219
224
 
220
- const askReserves = calculateSpreadReserves(
225
+ const [bidReserves, askReserves] = calculateSpreadReserves(
221
226
  newAmm,
222
- PositionDirection.LONG,
223
- oraclePriceData
224
- );
225
- const bidReserves = calculateSpreadReserves(
226
- newAmm,
227
- PositionDirection.SHORT,
228
227
  oraclePriceData
229
228
  );
230
229
 
@@ -431,11 +430,12 @@ export function calculateVolSpreadBN(
431
430
  const marketAvgStdPct = markStd
432
431
  .add(oracleStd)
433
432
  .mul(PERCENTAGE_PRECISION)
434
- .div(reservePrice.mul(new BN(2)));
433
+ .div(reservePrice)
434
+ .div(new BN(2));
435
435
  const volSpread = BN.max(lastOracleConfPct, marketAvgStdPct.div(new BN(2)));
436
436
 
437
+ const clampMin = PERCENTAGE_PRECISION.div(new BN(100));
437
438
  const clampMax = PERCENTAGE_PRECISION.mul(new BN(16)).div(new BN(10));
438
- const clampMin = PERCENTAGE_PRECISION.div(new BN(10));
439
439
 
440
440
  const longVolSpreadFactor = clampBN(
441
441
  longIntensity.mul(PERCENTAGE_PRECISION).div(BN.max(ONE, volume24H)),
@@ -471,6 +471,7 @@ export function calculateSpreadBN(
471
471
  baseAssetAmountWithAmm: BN,
472
472
  reservePrice: BN,
473
473
  totalFeeMinusDistributions: BN,
474
+ netRevenueSinceLastFunding: BN,
474
475
  baseAssetReserve: BN,
475
476
  minBaseAssetReserve: BN,
476
477
  maxBaseAssetReserve: BN,
@@ -527,18 +528,17 @@ export function calculateSpreadBN(
527
528
  shortSpread *= inventorySpreadScale;
528
529
  }
529
530
 
530
- const effectiveLeverage = calculateEffectiveLeverage(
531
- baseSpread,
532
- quoteAssetReserve,
533
- terminalQuoteAssetReserve,
534
- pegMultiplier,
535
- baseAssetAmountWithAmm,
536
- reservePrice,
537
- totalFeeMinusDistributions
538
- );
539
-
540
531
  const MAX_SPREAD_SCALE = 10;
541
532
  if (totalFeeMinusDistributions.gt(ZERO)) {
533
+ const effectiveLeverage = calculateEffectiveLeverage(
534
+ baseSpread,
535
+ quoteAssetReserve,
536
+ terminalQuoteAssetReserve,
537
+ pegMultiplier,
538
+ baseAssetAmountWithAmm,
539
+ reservePrice,
540
+ totalFeeMinusDistributions
541
+ );
542
542
  const spreadScale = Math.min(MAX_SPREAD_SCALE, 1 + effectiveLeverage);
543
543
  if (baseAssetAmountWithAmm.gt(ZERO)) {
544
544
  longSpread *= spreadScale;
@@ -550,13 +550,38 @@ export function calculateSpreadBN(
550
550
  shortSpread *= MAX_SPREAD_SCALE;
551
551
  }
552
552
 
553
+ if (
554
+ netRevenueSinceLastFunding.lt(
555
+ DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT
556
+ )
557
+ ) {
558
+ const retreatAmount = Math.min(
559
+ maxTargetSpread / 10,
560
+ Math.floor(
561
+ (baseSpread * netRevenueSinceLastFunding.abs().toNumber()) /
562
+ DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT.toNumber()
563
+ )
564
+ );
565
+ const halfRetreatAmount = Math.floor(retreatAmount / 2);
566
+ if (baseAssetAmountWithAmm.gt(ZERO)) {
567
+ longSpread += retreatAmount;
568
+ shortSpread += halfRetreatAmount;
569
+ } else if (baseAssetAmountWithAmm.lt(ZERO)) {
570
+ longSpread += halfRetreatAmount;
571
+ shortSpread += retreatAmount;
572
+ } else {
573
+ longSpread += halfRetreatAmount;
574
+ shortSpread += halfRetreatAmount;
575
+ }
576
+ }
577
+
553
578
  const totalSpread = longSpread + shortSpread;
554
579
  if (totalSpread > maxTargetSpread) {
555
580
  if (longSpread > shortSpread) {
556
- longSpread = Math.min(longSpread, maxTargetSpread);
581
+ longSpread = Math.ceil((longSpread * maxTargetSpread) / totalSpread);
557
582
  shortSpread = maxTargetSpread - longSpread;
558
583
  } else {
559
- shortSpread = Math.min(shortSpread, maxTargetSpread);
584
+ shortSpread = Math.ceil((shortSpread * maxTargetSpread) / totalSpread);
560
585
  longSpread = maxTargetSpread - shortSpread;
561
586
  }
562
587
  }
@@ -566,11 +591,10 @@ export function calculateSpreadBN(
566
591
 
567
592
  export function calculateSpread(
568
593
  amm: AMM,
569
- direction: PositionDirection,
570
594
  oraclePriceData: OraclePriceData
571
- ): number {
595
+ ): [number, number] {
572
596
  if (amm.baseSpread == 0 || amm.curveUpdateIntensity == 0) {
573
- return amm.baseSpread / 2;
597
+ return [amm.baseSpread / 2, amm.baseSpread / 2];
574
598
  }
575
599
 
576
600
  const reservePrice = calculatePrice(
@@ -604,6 +628,7 @@ export function calculateSpread(
604
628
  amm.baseAssetAmountWithAmm,
605
629
  reservePrice,
606
630
  amm.totalFeeMinusDistributions,
631
+ amm.netRevenueSinceLastFunding,
607
632
  amm.baseAssetReserve,
608
633
  amm.minBaseAssetReserve,
609
634
  amm.maxBaseAssetReserve,
@@ -614,50 +639,59 @@ export function calculateSpread(
614
639
  amm.volume24H
615
640
  );
616
641
 
617
- let spread: number;
618
-
619
- if (isVariant(direction, 'long')) {
620
- spread = longSpread;
621
- } else {
622
- spread = shortSpread;
623
- }
624
-
625
- return spread;
642
+ return [longSpread, shortSpread];
626
643
  }
627
644
 
628
645
  export function calculateSpreadReserves(
629
646
  amm: AMM,
630
- direction: PositionDirection,
631
647
  oraclePriceData: OraclePriceData
632
- ): {
633
- baseAssetReserve: BN;
634
- quoteAssetReserve: BN;
635
- } {
636
- const spread = calculateSpread(amm, direction, oraclePriceData);
648
+ ) {
649
+ function calculateSpreadReserve(
650
+ spread: number,
651
+ direction: PositionDirection,
652
+ amm: AMM
653
+ ): {
654
+ baseAssetReserve;
655
+ quoteAssetReserve;
656
+ } {
657
+ if (spread === 0) {
658
+ return {
659
+ baseAssetReserve: amm.baseAssetReserve,
660
+ quoteAssetReserve: amm.quoteAssetReserve,
661
+ };
662
+ }
663
+
664
+ const quoteAssetReserveDelta = amm.quoteAssetReserve.div(
665
+ BID_ASK_SPREAD_PRECISION.div(new BN(spread / 2))
666
+ );
667
+
668
+ let quoteAssetReserve;
669
+ if (isVariant(direction, 'long')) {
670
+ quoteAssetReserve = amm.quoteAssetReserve.add(quoteAssetReserveDelta);
671
+ } else {
672
+ quoteAssetReserve = amm.quoteAssetReserve.sub(quoteAssetReserveDelta);
673
+ }
637
674
 
638
- if (spread === 0) {
675
+ const baseAssetReserve = amm.sqrtK.mul(amm.sqrtK).div(quoteAssetReserve);
639
676
  return {
640
- baseAssetReserve: amm.baseAssetReserve,
641
- quoteAssetReserve: amm.quoteAssetReserve,
677
+ baseAssetReserve,
678
+ quoteAssetReserve,
642
679
  };
643
680
  }
644
681
 
645
- const quoteAsserReserveDelta = amm.quoteAssetReserve.div(
646
- BID_ASK_SPREAD_PRECISION.div(new BN(spread / 2))
682
+ const [longSpread, shortSpread] = calculateSpread(amm, oraclePriceData);
683
+ const askReserves = calculateSpreadReserve(
684
+ longSpread,
685
+ PositionDirection.LONG,
686
+ amm
687
+ );
688
+ const bidReserves = calculateSpreadReserve(
689
+ shortSpread,
690
+ PositionDirection.SHORT,
691
+ amm
647
692
  );
648
693
 
649
- let quoteAssetReserve;
650
- if (isVariant(direction, 'long')) {
651
- quoteAssetReserve = amm.quoteAssetReserve.add(quoteAsserReserveDelta);
652
- } else {
653
- quoteAssetReserve = amm.quoteAssetReserve.sub(quoteAsserReserveDelta);
654
- }
655
-
656
- const baseAssetReserve = amm.sqrtK.mul(amm.sqrtK).div(quoteAssetReserve);
657
- return {
658
- baseAssetReserve,
659
- quoteAssetReserve,
660
- };
694
+ return [bidReserves, askReserves];
661
695
  }
662
696
 
663
697
  /**
@@ -749,12 +783,14 @@ export function calculateMaxBaseAssetAmountToTrade(
749
783
  .div(PEG_PRECISION);
750
784
 
751
785
  const newBaseAssetReserve = squareRootBN(newBaseAssetReserveSquared);
752
-
753
- const baseAssetReserveBefore = calculateSpreadReserves(
786
+ const [shortSpreadReserves, longSpreadReserves] = calculateSpreadReserves(
754
787
  amm,
755
- direction,
756
788
  oraclePriceData
757
- ).baseAssetReserve;
789
+ );
790
+
791
+ const baseAssetReserveBefore: BN = isVariant(direction, 'long')
792
+ ? longSpreadReserves.baseAssetReserve
793
+ : shortSpreadReserves.baseAssetReserve;
758
794
 
759
795
  if (newBaseAssetReserve.gt(baseAssetReserveBefore)) {
760
796
  return [
package/src/math/utils.ts CHANGED
@@ -4,7 +4,7 @@ export function clampBN(x: BN, min: BN, max: BN): BN {
4
4
  return BN.max(min, BN.min(x, max));
5
5
  }
6
6
 
7
- export const squareRootBN = (n, closeness = new BN(1)) => {
7
+ export const squareRootBN = (n, closeness = new BN(1)): BN => {
8
8
  // Assuming the sqrt of n as n only
9
9
  let x = n;
10
10