@drift-labs/sdk 2.38.1-beta.1 → 2.38.1-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.
Files changed (54) hide show
  1. package/VERSION +1 -1
  2. package/lib/accounts/fetch.js +2 -2
  3. package/lib/accounts/pollingDriftClientAccountSubscriber.js +2 -14
  4. package/lib/accounts/pollingUserStatsAccountSubscriber.js +2 -2
  5. package/lib/adminClient.d.ts +1 -0
  6. package/lib/adminClient.js +11 -0
  7. package/lib/config.d.ts +1 -0
  8. package/lib/config.js +2 -0
  9. package/lib/driftClient.d.ts +22 -2
  10. package/lib/driftClient.js +101 -15
  11. package/lib/examples/loadDlob.js +3 -1
  12. package/lib/examples/makeTradeExample.js +3 -1
  13. package/lib/idl/drift.json +36 -1
  14. package/lib/index.d.ts +3 -0
  15. package/lib/index.js +3 -0
  16. package/lib/jupiter/jupiterClient.d.ts +197 -0
  17. package/lib/jupiter/jupiterClient.js +48 -3
  18. package/lib/math/spotBalance.d.ts +6 -5
  19. package/lib/math/spotBalance.js +28 -11
  20. package/lib/math/spotMarket.d.ts +1 -1
  21. package/lib/math/spotMarket.js +2 -2
  22. package/lib/math/spotPosition.d.ts +16 -3
  23. package/lib/math/spotPosition.js +53 -9
  24. package/lib/oracles/strictOraclePrice.d.ts +8 -0
  25. package/lib/oracles/strictOraclePrice.js +17 -0
  26. package/lib/priorityFee/priorityFeeSubscriber.d.ts +22 -0
  27. package/lib/priorityFee/priorityFeeSubscriber.js +46 -0
  28. package/lib/tokenFaucet.js +1 -0
  29. package/lib/types.d.ts +4 -0
  30. package/lib/types.js +3 -0
  31. package/lib/user.d.ts +5 -4
  32. package/lib/user.js +71 -105
  33. package/package.json +2 -2
  34. package/src/accounts/fetch.ts +2 -2
  35. package/src/accounts/pollingDriftClientAccountSubscriber.ts +5 -23
  36. package/src/accounts/pollingUserStatsAccountSubscriber.ts +10 -8
  37. package/src/adminClient.ts +23 -0
  38. package/src/config.ts +3 -0
  39. package/src/driftClient.ts +173 -13
  40. package/src/examples/loadDlob.ts +1 -0
  41. package/src/examples/makeTradeExample.ts +1 -0
  42. package/src/idl/drift.json +36 -1
  43. package/src/index.ts +3 -0
  44. package/src/jupiter/jupiterClient.ts +246 -3
  45. package/src/math/spotBalance.ts +37 -11
  46. package/src/math/spotMarket.ts +7 -1
  47. package/src/math/spotPosition.ts +133 -18
  48. package/src/oracles/strictOraclePrice.ts +19 -0
  49. package/src/priorityFee/priorityFeeSubscriber.ts +75 -0
  50. package/src/tokenFaucet.ts +1 -0
  51. package/src/types.ts +4 -0
  52. package/src/user.ts +171 -228
  53. package/tests/dlob/helpers.ts +10 -7
  54. package/tests/user/test.ts +77 -4
@@ -21,12 +21,18 @@ export function castNumberToSpotPrecision(
21
21
 
22
22
  export function calculateSpotMarketMarginRatio(
23
23
  market: SpotMarketAccount,
24
+ oraclePrice: BN,
24
25
  marginCategory: MarginCategory,
25
26
  size: BN,
26
27
  balanceType: SpotBalanceType
27
28
  ): number {
28
29
  if (isVariant(balanceType, 'deposit')) {
29
- const assetWeight = calculateAssetWeight(size, market, marginCategory);
30
+ const assetWeight = calculateAssetWeight(
31
+ size,
32
+ oraclePrice,
33
+ market,
34
+ marginCategory
35
+ );
30
36
  return MARGIN_PRECISION.sub(assetWeight).toNumber();
31
37
  } else {
32
38
  const liabilityWeight = calculateLiabilityWeight(
@@ -1,22 +1,38 @@
1
- import { SpotMarketAccount, SpotPosition } from '../types';
2
- import { ZERO } from '../constants/numericConstants';
1
+ import { MarginCategory, SpotMarketAccount, SpotPosition } from '../types';
2
+ import {
3
+ SPOT_MARKET_WEIGHT_PRECISION,
4
+ ZERO,
5
+ } from '../constants/numericConstants';
3
6
  import { BN } from '@coral-xyz/anchor';
4
7
  import {
8
+ calculateAssetWeight,
9
+ calculateLiabilityWeight,
5
10
  getSignedTokenAmount,
11
+ getStrictTokenValue,
6
12
  getTokenAmount,
7
13
  getTokenValue,
8
14
  } from './spotBalance';
9
- import { OraclePriceData } from '../oracles/types';
15
+ import { StrictOraclePrice } from '../oracles/strictOraclePrice';
10
16
 
11
17
  export function isSpotPositionAvailable(position: SpotPosition): boolean {
12
18
  return position.scaledBalance.eq(ZERO) && position.openOrders === 0;
13
19
  }
14
20
 
21
+ export type OrderFillSimulation = {
22
+ tokenAmount: BN;
23
+ ordersValue: BN;
24
+ tokenValue: BN;
25
+ weight: BN;
26
+ weightedTokenValue: BN;
27
+ freeCollateralContribution;
28
+ };
29
+
15
30
  export function getWorstCaseTokenAmounts(
16
31
  spotPosition: SpotPosition,
17
32
  spotMarketAccount: SpotMarketAccount,
18
- oraclePriceData: OraclePriceData
19
- ): [BN, BN] {
33
+ strictOraclePrice: StrictOraclePrice,
34
+ marginCategory: MarginCategory
35
+ ): OrderFillSimulation {
20
36
  const tokenAmount = getSignedTokenAmount(
21
37
  getTokenAmount(
22
38
  spotPosition.scaledBalance,
@@ -26,22 +42,121 @@ export function getWorstCaseTokenAmounts(
26
42
  spotPosition.balanceType
27
43
  );
28
44
 
29
- const tokenAmountAllBidsFill = tokenAmount.add(spotPosition.openBids);
30
- const tokenAmountAllAsksFill = tokenAmount.add(spotPosition.openAsks);
45
+ const tokenValue = getStrictTokenValue(
46
+ tokenAmount,
47
+ spotMarketAccount.decimals,
48
+ strictOraclePrice
49
+ );
31
50
 
32
- if (tokenAmountAllBidsFill.abs().gt(tokenAmountAllAsksFill.abs())) {
33
- const worstCaseQuoteTokenAmount = getTokenValue(
34
- spotPosition.openBids.neg(),
35
- spotMarketAccount.decimals,
36
- oraclePriceData
51
+ if (spotPosition.openBids.eq(ZERO) && spotPosition.openAsks.eq(ZERO)) {
52
+ const { weight, weightedTokenValue } = calculateWeightedTokenValue(
53
+ tokenAmount,
54
+ tokenValue,
55
+ strictOraclePrice.current,
56
+ spotMarketAccount,
57
+ marginCategory
37
58
  );
38
- return [tokenAmountAllBidsFill, worstCaseQuoteTokenAmount];
59
+ return {
60
+ tokenAmount,
61
+ ordersValue: ZERO,
62
+ tokenValue,
63
+ weight,
64
+ weightedTokenValue,
65
+ freeCollateralContribution: weightedTokenValue,
66
+ };
67
+ }
68
+
69
+ const bidsSimulation = simulateOrderFill(
70
+ tokenAmount,
71
+ tokenValue,
72
+ spotPosition.openBids,
73
+ strictOraclePrice,
74
+ spotMarketAccount,
75
+ marginCategory
76
+ );
77
+ const asksSimulation = simulateOrderFill(
78
+ tokenAmount,
79
+ tokenValue,
80
+ spotPosition.openAsks,
81
+ strictOraclePrice,
82
+ spotMarketAccount,
83
+ marginCategory
84
+ );
85
+
86
+ if (
87
+ asksSimulation.freeCollateralContribution.lt(
88
+ bidsSimulation.freeCollateralContribution
89
+ )
90
+ ) {
91
+ return asksSimulation;
39
92
  } else {
40
- const worstCaseQuoteTokenAmount = getTokenValue(
41
- spotPosition.openAsks.neg(),
42
- spotMarketAccount.decimals,
43
- oraclePriceData
93
+ return bidsSimulation;
94
+ }
95
+ }
96
+
97
+ export function calculateWeightedTokenValue(
98
+ tokenAmount: BN,
99
+ tokenValue: BN,
100
+ oraclePrice: BN,
101
+ spotMarket: SpotMarketAccount,
102
+ marginCategory: MarginCategory
103
+ ): { weight: BN; weightedTokenValue: BN } {
104
+ let weight: BN;
105
+ if (tokenValue.gte(ZERO)) {
106
+ weight = calculateAssetWeight(
107
+ tokenAmount,
108
+ oraclePrice,
109
+ spotMarket,
110
+ marginCategory
111
+ );
112
+ } else {
113
+ weight = calculateLiabilityWeight(
114
+ tokenAmount.abs(),
115
+ spotMarket,
116
+ marginCategory
44
117
  );
45
- return [tokenAmountAllAsksFill, worstCaseQuoteTokenAmount];
46
118
  }
119
+
120
+ return {
121
+ weight: weight,
122
+ weightedTokenValue: tokenValue
123
+ .mul(weight)
124
+ .div(SPOT_MARKET_WEIGHT_PRECISION),
125
+ };
126
+ }
127
+
128
+ export function simulateOrderFill(
129
+ tokenAmount: BN,
130
+ tokenValue: BN,
131
+ openOrders: BN,
132
+ strictOraclePrice: StrictOraclePrice,
133
+ spotMarket: SpotMarketAccount,
134
+ marginCategory: MarginCategory
135
+ ): OrderFillSimulation {
136
+ const ordersValue = getTokenValue(openOrders.neg(), spotMarket.decimals, {
137
+ price: strictOraclePrice.max(),
138
+ });
139
+ const tokenAmountAfterFill = tokenAmount.add(openOrders);
140
+ const tokenValueAfterFill = tokenValue.add(ordersValue.neg());
141
+
142
+ const { weight, weightedTokenValue: weightedTokenValueAfterFill } =
143
+ calculateWeightedTokenValue(
144
+ tokenAmountAfterFill,
145
+ tokenValueAfterFill,
146
+ strictOraclePrice.current,
147
+ spotMarket,
148
+ marginCategory
149
+ );
150
+
151
+ const freeCollateralContribution =
152
+ weightedTokenValueAfterFill.add(ordersValue);
153
+
154
+ return {
155
+ tokenAmount: tokenAmountAfterFill,
156
+ ordersValue: ordersValue,
157
+ tokenValue: tokenValueAfterFill,
158
+ weight,
159
+ weightedTokenValue: weightedTokenValueAfterFill,
160
+ freeCollateralContribution,
161
+ };
47
162
  }
@@ -0,0 +1,19 @@
1
+ import { BN } from '@coral-xyz/anchor';
2
+
3
+ export class StrictOraclePrice {
4
+ current: BN;
5
+ twap?: BN;
6
+
7
+ constructor(current: BN, twap?: BN) {
8
+ this.current = current;
9
+ this.twap = twap;
10
+ }
11
+
12
+ public max(): BN {
13
+ return this.twap ? BN.max(this.twap, this.current) : this.current;
14
+ }
15
+
16
+ public min(): BN {
17
+ return this.twap ? BN.min(this.twap, this.current) : this.current;
18
+ }
19
+ }
@@ -0,0 +1,75 @@
1
+ import { Connection, PublicKey } from '@solana/web3.js';
2
+
3
+ export class PriorityFeeSubscriber {
4
+ connection: Connection;
5
+ frequencyMs: number;
6
+ addresses: PublicKey[];
7
+ slotsToCheck: number;
8
+
9
+ intervalId?: NodeJS.Timer;
10
+
11
+ latestPriorityFee = 0;
12
+ // avg of last {slotsToCheck} slots
13
+ avgPriorityFee = 0;
14
+ // max of last {slotsToCheck} slots
15
+ maxPriorityFee = 0;
16
+ lastSlotSeen = 0;
17
+
18
+ public constructor({
19
+ connection,
20
+ frequencyMs,
21
+ addresses,
22
+ slotsToCheck = 10,
23
+ }: {
24
+ connection: Connection;
25
+ frequencyMs: number;
26
+ addresses: PublicKey[];
27
+ slotsToCheck?: number;
28
+ }) {
29
+ this.connection = connection;
30
+ this.frequencyMs = frequencyMs;
31
+ this.addresses = addresses;
32
+ this.slotsToCheck = slotsToCheck;
33
+ }
34
+
35
+ public async subscribe(): Promise<void> {
36
+ if (this.intervalId) {
37
+ return;
38
+ }
39
+
40
+ this.intervalId = setInterval(this.load.bind(this), this.frequencyMs);
41
+ }
42
+
43
+ public async load(): Promise<void> {
44
+ // @ts-ignore
45
+ const rpcJSONResponse: any = await this.connection._rpcRequest(
46
+ 'getRecentPrioritizationFees',
47
+ [this.addresses]
48
+ );
49
+
50
+ const descResults: { slot: number; prioritizationFee: number }[] =
51
+ rpcJSONResponse?.result
52
+ ?.sort((a, b) => b.slot - a.slot)
53
+ ?.slice(0, this.slotsToCheck) ?? [];
54
+
55
+ if (!descResults?.length) return;
56
+
57
+ const mostRecentResult = descResults[0];
58
+ this.latestPriorityFee = mostRecentResult.prioritizationFee;
59
+ this.lastSlotSeen = mostRecentResult.slot;
60
+ this.avgPriorityFee =
61
+ descResults.reduce((a, b) => {
62
+ return a + b.prioritizationFee;
63
+ }, 0) / descResults.length;
64
+ this.maxPriorityFee = Math.max(
65
+ ...descResults.map((result) => result.prioritizationFee)
66
+ );
67
+ }
68
+
69
+ public async unsubscribe(): Promise<void> {
70
+ if (this.intervalId) {
71
+ clearInterval(this.intervalId);
72
+ this.intervalId = undefined;
73
+ }
74
+ }
75
+ }
@@ -38,6 +38,7 @@ export class TokenFaucet {
38
38
  this.connection = connection;
39
39
  this.wallet = wallet;
40
40
  this.opts = opts || AnchorProvider.defaultOptions();
41
+ // @ts-ignore
41
42
  const provider = new AnchorProvider(connection, wallet, this.opts);
42
43
  this.provider = provider;
43
44
  this.program = new Program(tokenFaucet as Idl, programId, provider);
package/src/types.ts CHANGED
@@ -155,6 +155,9 @@ export class OrderActionExplanation {
155
155
  static readonly ORDER_FILLED_WITH_SERUM = {
156
156
  orderFillWithSerum: {},
157
157
  };
158
+ static readonly ORDER_FILLED_WITH_PHOENIX = {
159
+ orderFillWithPhoenix: {},
160
+ };
158
161
  static readonly REDUCE_ONLY_ORDER_INCREASED_POSITION = {
159
162
  reduceOnlyOrderIncreasedPosition: {},
160
163
  };
@@ -652,6 +655,7 @@ export type SpotMarketAccount = {
652
655
  maintenanceLiabilityWeight: number;
653
656
  liquidatorFee: number;
654
657
  imfFactor: number;
658
+ scaleInitialAssetWeightStart: BN;
655
659
 
656
660
  withdrawGuardThreshold: BN;
657
661
  depositTokenTwap: BN;