@drift-labs/sdk 2.10.0-beta.1 → 2.10.0-beta.2

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/math/amm.js CHANGED
@@ -23,6 +23,7 @@ function calculateOptimalPegAndBudget(amm, oraclePriceData) {
23
23
  const prePegCost = (0, repeg_1.calculateRepegCost)(amm, newPeg);
24
24
  const totalFeeLB = amm.totalExchangeFee.div(new anchor_1.BN(2));
25
25
  const budget = anchor_1.BN.max(numericConstants_1.ZERO, amm.totalFeeMinusDistributions.sub(totalFeeLB));
26
+ let checkLowerBound = true;
26
27
  if (budget.lt(prePegCost)) {
27
28
  const halfMaxPriceSpread = new anchor_1.BN(amm.maxSpread)
28
29
  .div(new anchor_1.BN(2))
@@ -42,19 +43,23 @@ function calculateOptimalPegAndBudget(amm, oraclePriceData) {
42
43
  }
43
44
  newOptimalPeg = calculatePegFromTargetPrice(newTargetPrice, amm.baseAssetReserve, amm.quoteAssetReserve);
44
45
  newBudget = (0, repeg_1.calculateRepegCost)(amm, newOptimalPeg);
46
+ checkLowerBound = false;
45
47
  return [newTargetPrice, newOptimalPeg, newBudget, false];
46
48
  }
49
+ else if (amm.totalFeeMinusDistributions.lt(amm.totalExchangeFee.div(new anchor_1.BN(2)))) {
50
+ checkLowerBound = false;
51
+ }
47
52
  }
48
- return [targetPrice, newPeg, budget, true];
53
+ return [targetPrice, newPeg, budget, checkLowerBound];
49
54
  }
50
55
  exports.calculateOptimalPegAndBudget = calculateOptimalPegAndBudget;
51
56
  function calculateNewAmm(amm, oraclePriceData) {
52
57
  let pKNumer = new anchor_1.BN(1);
53
58
  let pKDenom = new anchor_1.BN(1);
54
- const [targetPrice, _newPeg, budget, checkLowerBound] = calculateOptimalPegAndBudget(amm, oraclePriceData);
59
+ const [targetPrice, _newPeg, budget, _checkLowerBound] = calculateOptimalPegAndBudget(amm, oraclePriceData);
55
60
  let prePegCost = (0, repeg_1.calculateRepegCost)(amm, _newPeg);
56
61
  let newPeg = _newPeg;
57
- if (prePegCost.gt(budget) && checkLowerBound) {
62
+ if (prePegCost.gte(budget) && prePegCost.gt(numericConstants_1.ZERO)) {
58
63
  [pKNumer, pKDenom] = [new anchor_1.BN(999), new anchor_1.BN(1000)];
59
64
  const deficitMadeup = (0, repeg_1.calculateAdjustKCost)(amm, pKNumer, pKDenom);
60
65
  (0, assert_1.assert)(deficitMadeup.lte(new anchor_1.BN(0)));
@@ -76,7 +81,7 @@ function calculateNewAmm(amm, oraclePriceData) {
76
81
  }
77
82
  exports.calculateNewAmm = calculateNewAmm;
78
83
  function calculateUpdatedAMM(amm, oraclePriceData) {
79
- if (amm.curveUpdateIntensity == 0) {
84
+ if (amm.curveUpdateIntensity == 0 || oraclePriceData === undefined) {
80
85
  return amm;
81
86
  }
82
87
  const newAmm = Object.assign({}, amm);
@@ -325,8 +330,12 @@ function calculateSpreadBN(baseSpread, lastOracleReservePriceSpreadPct, lastOrac
325
330
  spreadTerms.longSpreadwEL = longSpread;
326
331
  spreadTerms.shortSpreadwEL = shortSpread;
327
332
  if (netRevenueSinceLastFunding.lt(numericConstants_1.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT)) {
328
- const revenueRetreatAmount = Math.min(maxTargetSpread / 10, Math.floor((baseSpread * netRevenueSinceLastFunding.abs().toNumber()) /
329
- numericConstants_1.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT.abs().toNumber()));
333
+ const maxRetreat = maxTargetSpread / 10;
334
+ let revenueRetreatAmount = maxRetreat;
335
+ if (netRevenueSinceLastFunding.gte(numericConstants_1.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT.mul(new anchor_1.BN(1000)))) {
336
+ revenueRetreatAmount = Math.min(maxRetreat, Math.floor((baseSpread * netRevenueSinceLastFunding.abs().toNumber()) /
337
+ numericConstants_1.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT.abs().toNumber()));
338
+ }
330
339
  const halfRevenueRetreatAmount = Math.floor(revenueRetreatAmount / 2);
331
340
  spreadTerms.revenueRetreatAmount = revenueRetreatAmount;
332
341
  spreadTerms.halfRevenueRetreatAmount = halfRevenueRetreatAmount;
@@ -53,7 +53,7 @@ function isOracleTooDivergent(amm, oraclePriceData, oracleGuardRails, now) {
53
53
  }
54
54
  exports.isOracleTooDivergent = isOracleTooDivergent;
55
55
  function calculateLiveOracleTwap(amm, oraclePriceData, now) {
56
- const sinceLastUpdate = now.sub(amm.historicalOracleData.lastOraclePriceTwapTs);
56
+ const sinceLastUpdate = index_1.BN.max(numericConstants_1.ONE, now.sub(amm.historicalOracleData.lastOraclePriceTwapTs));
57
57
  const sinceStart = index_1.BN.max(numericConstants_1.ZERO, amm.fundingPeriod.sub(sinceLastUpdate));
58
58
  const clampRange = amm.historicalOracleData.lastOraclePriceTwap.div(new index_1.BN(3));
59
59
  const clampedOraclePrice = index_1.BN.min(amm.historicalOracleData.lastOraclePriceTwap.add(clampRange), index_1.BN.max(oraclePriceData.price, amm.historicalOracleData.lastOraclePriceTwap.sub(clampRange)));
@@ -65,7 +65,7 @@ function calculateLiveOracleTwap(amm, oraclePriceData, now) {
65
65
  }
66
66
  exports.calculateLiveOracleTwap = calculateLiveOracleTwap;
67
67
  function calculateLiveOracleStd(amm, oraclePriceData, now) {
68
- const sinceLastUpdate = now.sub(amm.historicalOracleData.lastOraclePriceTwapTs);
68
+ const sinceLastUpdate = index_1.BN.max(numericConstants_1.ONE, now.sub(amm.historicalOracleData.lastOraclePriceTwapTs));
69
69
  const sinceStart = index_1.BN.max(numericConstants_1.ZERO, amm.fundingPeriod.sub(sinceLastUpdate));
70
70
  const liveOracleTwap = calculateLiveOracleTwap(amm, oraclePriceData, now);
71
71
  const priceDeltaVsTwap = oraclePriceData.price.sub(liveOracleTwap).abs();
@@ -19,4 +19,4 @@ export declare function calculateAdjustKCost(amm: AMM, numerator: BN, denomenato
19
19
  export declare function calculateRepegCost(amm: AMM, newPeg: BN): BN;
20
20
  export declare function calculateBudgetedKBN(x: BN, y: BN, budget: BN, Q: BN, d: BN): [BN, BN];
21
21
  export declare function calculateBudgetedK(amm: AMM, cost: BN): [BN, BN];
22
- export declare function calculateBudgetedPeg(amm: AMM, cost: BN, targetPrice: BN): BN;
22
+ export declare function calculateBudgetedPeg(amm: AMM, budget: BN, targetPrice: BN): BN;
package/lib/math/repeg.js CHANGED
@@ -20,16 +20,46 @@ function calculateAdjustKCost(amm, numerator, denomenator) {
20
20
  const quoteScale = y.mul(d).mul(Q); //.div(AMM_RESERVE_PRECISION);
21
21
  const p = numerator.mul(numericConstants_1.PRICE_PRECISION).div(denomenator);
22
22
  const cost = quoteScale
23
+ .mul(numericConstants_1.PERCENTAGE_PRECISION)
24
+ .mul(numericConstants_1.PERCENTAGE_PRECISION)
23
25
  .div(x.add(d))
24
26
  .sub(quoteScale
25
27
  .mul(p)
28
+ .mul(numericConstants_1.PERCENTAGE_PRECISION)
29
+ .mul(numericConstants_1.PERCENTAGE_PRECISION)
26
30
  .div(numericConstants_1.PRICE_PRECISION)
27
31
  .div(x.mul(p).div(numericConstants_1.PRICE_PRECISION).add(d)))
32
+ .div(numericConstants_1.PERCENTAGE_PRECISION)
33
+ .div(numericConstants_1.PERCENTAGE_PRECISION)
28
34
  .div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO)
29
35
  .div(numericConstants_1.PEG_PRECISION);
30
36
  return cost.mul(new anchor_1.BN(-1));
31
37
  }
32
38
  exports.calculateAdjustKCost = calculateAdjustKCost;
39
+ // /**
40
+ // * Helper function calculating adjust k cost
41
+ // * @param amm
42
+ // * @param numerator
43
+ // * @param denomenator
44
+ // * @returns cost : Precision QUOTE_ASSET_PRECISION
45
+ // */
46
+ // export function calculateAdjustKCost2(
47
+ // amm: AMM,
48
+ // numerator: BN,
49
+ // denomenator: BN
50
+ // ): BN {
51
+ // // const k = market.amm.sqrtK.mul(market.amm.sqrtK);
52
+ // const directionToClose = amm.baseAssetAmountWithAmm.gt(ZERO)
53
+ // ? PositionDirection.SHORT
54
+ // : PositionDirection.LONG;
55
+ // const [newQuoteAssetReserve, _newBaseAssetReserve] =
56
+ // calculateAmmReservesAfterSwap(
57
+ // amm,
58
+ // 'base',
59
+ // amm.baseAssetAmountWithAmm.abs(),
60
+ // getSwapDirection('base', directionToClose)
61
+ // );
62
+ // }
33
63
  /**
34
64
  * Helper function calculating adjust pegMultiplier (repeg) cost
35
65
  *
@@ -107,31 +137,28 @@ function calculateBudgetedK(amm, cost) {
107
137
  return [numerator, denominator];
108
138
  }
109
139
  exports.calculateBudgetedK = calculateBudgetedK;
110
- function calculateBudgetedPeg(amm, cost, targetPrice) {
111
- // wolframalpha.com
112
- // (1/(x+d) - p/(x*p+d))*y*d*Q = C solve for p
113
- // p = (d(y*d*Q - C(x+d))) / (C*x(x+d) + y*y*d*Q)
114
- // todo: assumes k = x * y
115
- // otherwise use: (y(1-p) + (kp^2/(x*p+d)) - k/(x+d)) * Q = C solve for p
140
+ function calculateBudgetedPeg(amm, budget, targetPrice) {
141
+ let perPegCost = amm.quoteAssetReserve
142
+ .sub(amm.terminalQuoteAssetReserve)
143
+ .div(numericConstants_1.AMM_RESERVE_PRECISION.div(numericConstants_1.PRICE_PRECISION));
144
+ if (perPegCost.gt(numericConstants_1.ZERO)) {
145
+ perPegCost = perPegCost.add(numericConstants_1.ONE);
146
+ }
147
+ else if (perPegCost.lt(numericConstants_1.ZERO)) {
148
+ perPegCost = perPegCost.sub(numericConstants_1.ONE);
149
+ }
116
150
  const targetPeg = targetPrice
117
151
  .mul(amm.baseAssetReserve)
118
152
  .div(amm.quoteAssetReserve)
119
153
  .div(numericConstants_1.PRICE_DIV_PEG);
120
- const k = amm.sqrtK.mul(amm.sqrtK);
121
- const x = amm.baseAssetReserve;
122
- const y = amm.quoteAssetReserve;
123
- const d = amm.baseAssetAmountWithAmm;
124
- const Q = amm.pegMultiplier;
125
- const C = cost.mul(new anchor_1.BN(-1));
126
- const deltaQuoteAssetReserves = y.sub(k.div(x.add(d)));
127
- const pegChangeDirection = targetPeg.sub(Q);
128
- const useTargetPeg = (deltaQuoteAssetReserves.lt(numericConstants_1.ZERO) && pegChangeDirection.gt(numericConstants_1.ZERO)) ||
129
- (deltaQuoteAssetReserves.gt(numericConstants_1.ZERO) && pegChangeDirection.lt(numericConstants_1.ZERO));
130
- if (deltaQuoteAssetReserves.eq(numericConstants_1.ZERO) || useTargetPeg) {
154
+ const pegChangeDirection = targetPeg.sub(amm.pegMultiplier);
155
+ const useTargetPeg = (perPegCost.lt(numericConstants_1.ZERO) && pegChangeDirection.gt(numericConstants_1.ZERO)) ||
156
+ (perPegCost.gt(numericConstants_1.ZERO) && pegChangeDirection.lt(numericConstants_1.ZERO));
157
+ if (perPegCost.eq(numericConstants_1.ZERO) || useTargetPeg) {
131
158
  return targetPeg;
132
159
  }
133
- const deltaPegMultiplier = C.mul(numericConstants_1.PRICE_PRECISION).div(deltaQuoteAssetReserves.div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO));
134
- const newPeg = Q.sub(deltaPegMultiplier.mul(numericConstants_1.PEG_PRECISION).div(numericConstants_1.PRICE_PRECISION));
160
+ const budgetDeltaPeg = budget.mul(numericConstants_1.PEG_PRECISION).div(perPegCost);
161
+ const newPeg = anchor_1.BN.max(numericConstants_1.ONE, amm.pegMultiplier.add(budgetDeltaPeg));
135
162
  return newPeg;
136
163
  }
137
164
  exports.calculateBudgetedPeg = calculateBudgetedPeg;
@@ -0,0 +1,8 @@
1
+ import { AdminClient } from './adminClient';
2
+ import { ConfirmOptions, Signer, Transaction } from '@solana/web3.js';
3
+ import { TxSigAndSlot } from './tx/types';
4
+ import { DriftClientConfig } from './driftClientConfig';
5
+ export declare class TestClient extends AdminClient {
6
+ constructor(config: DriftClientConfig);
7
+ sendTransaction(tx: Transaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean): Promise<TxSigAndSlot>;
8
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TestClient = void 0;
4
+ const adminClient_1 = require("./adminClient");
5
+ class TestClient extends adminClient_1.AdminClient {
6
+ constructor(config) {
7
+ if (config.accountSubscription.type !== 'polling') {
8
+ throw new Error('Test client must be polling');
9
+ }
10
+ super(config);
11
+ }
12
+ async sendTransaction(tx, additionalSigners, opts, preSigned) {
13
+ const { txSig, slot } = await super.sendTransaction(tx, additionalSigners, opts, preSigned);
14
+ let lastFetchedSlot = this.accountSubscriber.accountLoader.mostRecentSlot;
15
+ while (lastFetchedSlot < slot) {
16
+ await this.fetchAccounts();
17
+ lastFetchedSlot = this.accountSubscriber.accountLoader.mostRecentSlot;
18
+ }
19
+ return { txSig, slot };
20
+ }
21
+ }
22
+ exports.TestClient = TestClient;
package/lib/user.d.ts CHANGED
@@ -29,6 +29,7 @@ export declare class User {
29
29
  fetchAccounts(): Promise<void>;
30
30
  unsubscribe(): Promise<void>;
31
31
  getUserAccount(): UserAccount;
32
+ forceGetUserAccount(): Promise<UserAccount>;
32
33
  getUserAccountAndSlot(): DataAndSlot<UserAccount> | undefined;
33
34
  /**
34
35
  * Gets the user's current position for a given perp market. If the user has no position returns undefined
package/lib/user.js CHANGED
@@ -52,6 +52,10 @@ class User {
52
52
  getUserAccount() {
53
53
  return this.accountSubscriber.getUserAccountAndSlot().data;
54
54
  }
55
+ async forceGetUserAccount() {
56
+ await this.fetchAccounts();
57
+ return this.accountSubscriber.getUserAccountAndSlot().data;
58
+ }
55
59
  getUserAccountAndSlot() {
56
60
  return this.accountSubscriber.getUserAccountAndSlot();
57
61
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.10.0-beta.1",
3
+ "version": "2.10.0-beta.2",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -340,21 +340,44 @@ export class PollingDriftClientAccountSubscriber
340
340
  }
341
341
 
342
342
  async addSpotMarket(marketIndex: number): Promise<boolean> {
343
+ const marketPublicKey = await getSpotMarketPublicKey(
344
+ this.program.programId,
345
+ marketIndex
346
+ );
347
+
348
+ if (this.accountsToPoll.has(marketPublicKey.toString())) {
349
+ return true;
350
+ }
351
+
343
352
  await this.addSpotMarketAccountToPoll(marketIndex);
344
- const accountToPoll = this.accountsToPoll.get(marketIndex.toString());
353
+
354
+ const accountToPoll = this.accountsToPoll.get(marketPublicKey.toString());
355
+
345
356
  await this.addAccountToAccountLoader(accountToPoll);
346
357
  return true;
347
358
  }
348
359
 
349
360
  async addPerpMarket(marketIndex: number): Promise<boolean> {
361
+ const marketPublicKey = await getPerpMarketPublicKey(
362
+ this.program.programId,
363
+ marketIndex
364
+ );
365
+
366
+ if (this.accountsToPoll.has(marketPublicKey.toString())) {
367
+ return true;
368
+ }
369
+
350
370
  await this.addPerpMarketAccountToPoll(marketIndex);
351
- const accountToPoll = this.accountsToPoll.get(marketIndex.toString());
371
+ const accountToPoll = this.accountsToPoll.get(marketPublicKey.toString());
352
372
  await this.addAccountToAccountLoader(accountToPoll);
353
373
  return true;
354
374
  }
355
375
 
356
376
  async addOracle(oracleInfo: OracleInfo): Promise<boolean> {
357
- if (oracleInfo.publicKey.equals(PublicKey.default)) {
377
+ if (
378
+ oracleInfo.publicKey.equals(PublicKey.default) ||
379
+ this.oraclesToPoll.has(oracleInfo.publicKey.toString())
380
+ ) {
358
381
  return true;
359
382
  }
360
383