@drift-labs/sdk 2.54.0-beta.1 → 2.54.0-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 (44) hide show
  1. package/VERSION +1 -1
  2. package/lib/accounts/pollingInsuranceFundStakeAccountSubscriber.js +0 -1
  3. package/lib/constants/perpMarkets.js +20 -0
  4. package/lib/driftClient.d.ts +8 -2
  5. package/lib/driftClient.js +95 -20
  6. package/lib/events/webSocketLogProvider.js +3 -0
  7. package/lib/idl/drift.json +7 -1
  8. package/lib/jupiter/jupiterClient.d.ts +6 -0
  9. package/lib/jupiter/jupiterClient.js +2 -2
  10. package/lib/math/funding.js +24 -1
  11. package/lib/math/oracles.js +2 -2
  12. package/lib/math/superStake.d.ts +51 -0
  13. package/lib/math/superStake.js +10 -2
  14. package/lib/priorityFee/averageOverSlotsStrategy.d.ts +0 -5
  15. package/lib/priorityFee/averageOverSlotsStrategy.js +1 -13
  16. package/lib/priorityFee/maxOverSlotsStrategy.d.ts +0 -5
  17. package/lib/priorityFee/maxOverSlotsStrategy.js +1 -13
  18. package/lib/priorityFee/priorityFeeSubscriber.d.ts +5 -4
  19. package/lib/priorityFee/priorityFeeSubscriber.js +15 -21
  20. package/lib/tx/baseTxSender.js +2 -2
  21. package/lib/tx/retryTxSender.js +4 -21
  22. package/lib/tx/utils.d.ts +5 -1
  23. package/lib/tx/utils.js +20 -1
  24. package/lib/userMap/userMap.js +4 -0
  25. package/package.json +1 -1
  26. package/src/accounts/pollingInsuranceFundStakeAccountSubscriber.ts +0 -1
  27. package/src/constants/perpMarkets.ts +20 -0
  28. package/src/driftClient.ts +197 -39
  29. package/src/events/webSocketLogProvider.ts +11 -2
  30. package/src/idl/drift.json +7 -1
  31. package/src/jupiter/jupiterClient.ts +8 -2
  32. package/src/math/funding.ts +28 -1
  33. package/src/math/oracles.ts +2 -2
  34. package/src/math/superStake.ts +60 -1
  35. package/src/priorityFee/averageOverSlotsStrategy.ts +1 -16
  36. package/src/priorityFee/maxOverSlotsStrategy.ts +1 -16
  37. package/src/priorityFee/priorityFeeSubscriber.ts +22 -26
  38. package/src/tx/baseTxSender.ts +3 -2
  39. package/src/tx/retryTxSender.ts +5 -23
  40. package/src/tx/utils.ts +32 -0
  41. package/src/userMap/userMap.ts +3 -0
  42. package/tests/amm/test.ts +275 -2
  43. package/tests/dlob/test.ts +2 -2
  44. package/tests/tx/priorityFeeStrategy.ts +2 -2
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.54.0-beta.1
1
+ 2.54.0-beta.10
@@ -22,7 +22,6 @@ class PollingInsuranceFundStakeAccountSubscriber {
22
22
  };
23
23
  }
24
24
  await this.addToAccountLoader();
25
- await this.fetchIfUnloaded();
26
25
  if (this.doesAccountExist()) {
27
26
  this.eventEmitter.emit('update');
28
27
  }
@@ -224,6 +224,16 @@ exports.DevnetPerpMarkets = [
224
224
  launchTs: 1703173331000,
225
225
  oracleSource: __1.OracleSource.PYTH,
226
226
  },
227
+ {
228
+ fullName: 'AVAX',
229
+ category: ['Rollup', 'Infra'],
230
+ symbol: 'AVAX-PERP',
231
+ baseAssetSymbol: 'AVAX',
232
+ marketIndex: 22,
233
+ oracle: new web3_js_1.PublicKey('FVb5h1VmHPfVb1RfqZckchq18GxRv4iKt8T4eVTQAqdz'),
234
+ launchTs: 1704209558000,
235
+ oracleSource: __1.OracleSource.PYTH,
236
+ },
227
237
  ];
228
238
  exports.MainnetPerpMarkets = [
229
239
  {
@@ -446,6 +456,16 @@ exports.MainnetPerpMarkets = [
446
456
  launchTs: 1703173331000,
447
457
  oracleSource: __1.OracleSource.PYTH,
448
458
  },
459
+ {
460
+ fullName: 'AVAX',
461
+ category: ['Rollup', 'Infra'],
462
+ symbol: 'AVAX-PERP',
463
+ baseAssetSymbol: 'AVAX',
464
+ marketIndex: 22,
465
+ oracle: new web3_js_1.PublicKey('Ax9ujW5B9oqcv59N8m6f1BpTBq2rGeGaBcpKjC5UYsXU'),
466
+ launchTs: 1704209558000,
467
+ oracleSource: __1.OracleSource.PYTH,
468
+ },
449
469
  ];
450
470
  exports.PerpMarkets = {
451
471
  devnet: exports.DevnetPerpMarkets,
@@ -284,10 +284,11 @@ export declare class DriftClient {
284
284
  * @param cancelExistingOrders - Builds and returns an extra transaciton to cancel the existing orders in the same perp market. Intended use is to auto-cancel TP/SL orders when closing a position. Ignored if orderParams.marketType is not MarketType.PERP
285
285
  * @returns
286
286
  */
287
- sendMarketOrderAndGetSignedFillTx(orderParams: OptionalOrderParams, userAccountPublicKey: PublicKey, userAccount: UserAccount, makerInfo?: MakerInfo | MakerInfo[], txParams?: TxParams, bracketOrdersParams?: OptionalOrderParams[], referrerInfo?: ReferrerInfo, cancelExistingOrders?: boolean): Promise<{
287
+ sendMarketOrderAndGetSignedFillTx(orderParams: OptionalOrderParams, userAccountPublicKey: PublicKey, userAccount: UserAccount, makerInfo?: MakerInfo | MakerInfo[], txParams?: TxParams, bracketOrdersParams?: OptionalOrderParams[], referrerInfo?: ReferrerInfo, cancelExistingOrders?: boolean, settlePnl?: boolean): Promise<{
288
288
  txSig: TransactionSignature;
289
289
  signedFillTx?: Transaction;
290
290
  signedCancelExistingOrdersTx?: Transaction;
291
+ signedSettlePnlTx?: Transaction;
291
292
  }>;
292
293
  placePerpOrder(orderParams: OptionalOrderParams, txParams?: TxParams, subAccountId?: number): Promise<TransactionSignature>;
293
294
  getPlacePerpOrderIx(orderParams: OptionalOrderParams, subAccountId?: number): Promise<TransactionInstruction>;
@@ -310,7 +311,7 @@ export declare class DriftClient {
310
311
  direction?: PositionDirection;
311
312
  }, placeOrderParams: OrderParams[], txParams?: TxParams, subAccountId?: number): Promise<TransactionSignature>;
312
313
  placeOrders(params: OrderParams[], txParams?: TxParams, subAccountId?: number): Promise<TransactionSignature>;
313
- getPlaceOrdersIx(params: OrderParams[], subAccountId?: number): Promise<TransactionInstruction>;
314
+ getPlaceOrdersIx(params: OptionalOrderParams[], subAccountId?: number): Promise<TransactionInstruction>;
314
315
  fillPerpOrder(userAccountPublicKey: PublicKey, user: UserAccount, order?: Pick<Order, 'marketIndex' | 'orderId'>, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, txParams?: TxParams, fillerPublicKey?: number): Promise<TransactionSignature>;
315
316
  getFillPerpOrderIx(userAccountPublicKey: PublicKey, userAccount: UserAccount, order: Pick<Order, 'marketIndex' | 'orderId'>, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, fillerSubAccountId?: number): Promise<TransactionInstruction>;
316
317
  getRevertFillIx(fillerPublicKey?: PublicKey): Promise<TransactionInstruction>;
@@ -427,6 +428,11 @@ export declare class DriftClient {
427
428
  updateUserOpenOrdersCount(userAccountPublicKey: PublicKey, user: UserAccount, txParams?: TxParams, fillerPublicKey?: PublicKey): Promise<TransactionSignature>;
428
429
  getUpdateUserOpenOrdersCountIx(userAccountPublicKey: PublicKey, userAccount: UserAccount, fillerPublicKey?: PublicKey): Promise<TransactionInstruction>;
429
430
  placeAndTakePerpOrder(orderParams: OptionalOrderParams, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, txParams?: TxParams, subAccountId?: number): Promise<TransactionSignature>;
431
+ placeAndTakePerpWithAdditionalOrders(orderParams: OptionalOrderParams, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, bracketOrdersParams?: OptionalOrderParams[], txParams?: TxParams, subAccountId?: number, cancelExistingOrders?: boolean, settlePnl?: boolean): Promise<{
432
+ txSig: TransactionSignature;
433
+ signedCancelExistingOrdersTx?: Transaction;
434
+ signedSettlePnlTx?: Transaction;
435
+ }>;
430
436
  getPlaceAndTakePerpOrderIx(orderParams: OptionalOrderParams, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, subAccountId?: number): Promise<TransactionInstruction>;
431
437
  placeAndMakePerpOrder(orderParams: OptionalOrderParams, takerInfo: TakerInfo, referrerInfo?: ReferrerInfo, txParams?: TxParams, subAccountId?: number): Promise<TransactionSignature>;
432
438
  getPlaceAndMakePerpOrderIx(orderParams: OptionalOrderParams, takerInfo: TakerInfo, referrerInfo?: ReferrerInfo, subAccountId?: number): Promise<TransactionInstruction>;
@@ -1419,35 +1419,47 @@ class DriftClient {
1419
1419
  * @param cancelExistingOrders - Builds and returns an extra transaciton to cancel the existing orders in the same perp market. Intended use is to auto-cancel TP/SL orders when closing a position. Ignored if orderParams.marketType is not MarketType.PERP
1420
1420
  * @returns
1421
1421
  */
1422
- async sendMarketOrderAndGetSignedFillTx(orderParams, userAccountPublicKey, userAccount, makerInfo, txParams, bracketOrdersParams = new Array(), referrerInfo, cancelExistingOrders) {
1422
+ async sendMarketOrderAndGetSignedFillTx(orderParams, userAccountPublicKey, userAccount, makerInfo, txParams, bracketOrdersParams = new Array(), referrerInfo, cancelExistingOrders, settlePnl) {
1423
1423
  const marketIndex = orderParams.marketIndex;
1424
1424
  const orderId = userAccount.nextOrderId;
1425
- const bracketOrderIxs = [];
1426
- const placePerpOrderIx = await this.getPlacePerpOrderIx(orderParams, userAccount.subAccountId);
1427
- for (const bracketOrderParams of bracketOrdersParams) {
1428
- const placeBracketOrderIx = await this.getPlacePerpOrderIx(bracketOrderParams, userAccount.subAccountId);
1429
- bracketOrderIxs.push(placeBracketOrderIx);
1430
- }
1431
- let cancelOrdersIx;
1425
+ const ordersIx = await this.getPlaceOrdersIx([orderParams, ...bracketOrdersParams], userAccount.subAccountId);
1426
+ /* Cancel open orders in market if requested */
1432
1427
  let cancelExistingOrdersTx;
1433
1428
  if (cancelExistingOrders && (0, types_1.isVariant)(orderParams.marketType, 'perp')) {
1434
- cancelOrdersIx = await this.getCancelOrdersIx(orderParams.marketType, orderParams.marketIndex, null, userAccount.subAccountId);
1429
+ const cancelOrdersIx = await this.getCancelOrdersIx(orderParams.marketType, orderParams.marketIndex, null, userAccount.subAccountId);
1435
1430
  //@ts-ignore
1436
1431
  cancelExistingOrdersTx = await this.buildTransaction([cancelOrdersIx], txParams, this.txVersion);
1437
1432
  }
1433
+ /* Settle PnL after fill if requested */
1434
+ let settlePnlTx;
1435
+ if (settlePnl && (0, types_1.isVariant)(orderParams.marketType, 'perp')) {
1436
+ const settlePnlIx = await this.settlePNLIx(userAccountPublicKey, userAccount, marketIndex);
1437
+ //@ts-ignore
1438
+ settlePnlTx = await this.buildTransaction([settlePnlIx], txParams, this.txVersion);
1439
+ }
1438
1440
  // use versioned transactions if there is a lookup table account and wallet is compatible
1439
1441
  if (this.txVersion === 0) {
1440
- const versionedMarketOrderTx = await this.buildTransaction([placePerpOrderIx].concat(bracketOrderIxs), txParams, 0);
1442
+ const versionedMarketOrderTx = await this.buildTransaction(ordersIx, txParams, 0);
1441
1443
  const fillPerpOrderIx = await this.getFillPerpOrderIx(userAccountPublicKey, userAccount, {
1442
1444
  orderId,
1443
1445
  marketIndex,
1444
1446
  }, makerInfo, referrerInfo, userAccount.subAccountId);
1445
1447
  const versionedFillTx = await this.buildTransaction([fillPerpOrderIx], txParams, 0);
1446
- const [signedVersionedMarketOrderTx, signedVersionedFillTx, signedCancelExistingOrdersTx,] = await this.provider.wallet.signAllTransactions([
1448
+ const allPossibleTxs = [
1447
1449
  versionedMarketOrderTx,
1448
1450
  versionedFillTx,
1449
1451
  cancelExistingOrdersTx,
1450
- ].filter((tx) => tx !== undefined));
1452
+ settlePnlTx,
1453
+ ];
1454
+ const txKeys = [
1455
+ 'signedVersionedMarketOrderTx',
1456
+ 'signedVersionedFillTx',
1457
+ 'signedCancelExistingOrdersTx',
1458
+ 'signedSettlePnlTx',
1459
+ ];
1460
+ const { signedVersionedMarketOrderTx, signedVersionedFillTx, signedCancelExistingOrdersTx, signedSettlePnlTx, } = await (0, utils_1.getSignedTransactionMap)(
1461
+ //@ts-ignore
1462
+ this.provider.wallet, allPossibleTxs, txKeys);
1451
1463
  const { txSig, slot } = await this.txSender.sendRawTransaction(signedVersionedMarketOrderTx.serialize(), this.opts);
1452
1464
  this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
1453
1465
  return {
@@ -1456,13 +1468,12 @@ class DriftClient {
1456
1468
  signedFillTx: signedVersionedFillTx,
1457
1469
  // @ts-ignore
1458
1470
  signedCancelExistingOrdersTx,
1471
+ // @ts-ignore
1472
+ signedSettlePnlTx,
1459
1473
  };
1460
1474
  }
1461
1475
  else {
1462
- const marketOrderTx = (0, utils_1.wrapInTx)(placePerpOrderIx, txParams === null || txParams === void 0 ? void 0 : txParams.computeUnits, txParams === null || txParams === void 0 ? void 0 : txParams.computeUnitsPrice);
1463
- if (bracketOrderIxs.length > 0) {
1464
- marketOrderTx.add(...bracketOrderIxs);
1465
- }
1476
+ const marketOrderTx = (0, utils_1.wrapInTx)(ordersIx, txParams === null || txParams === void 0 ? void 0 : txParams.computeUnits, txParams === null || txParams === void 0 ? void 0 : txParams.computeUnitsPrice);
1466
1477
  // Apply the latest blockhash to the txs so that we can sign before sending them
1467
1478
  const currentBlockHash = (await this.connection.getLatestBlockhash('finalized')).blockhash;
1468
1479
  marketOrderTx.recentBlockhash = currentBlockHash;
@@ -1471,10 +1482,33 @@ class DriftClient {
1471
1482
  cancelExistingOrdersTx.recentBlockhash = currentBlockHash;
1472
1483
  cancelExistingOrdersTx.feePayer = userAccount.authority;
1473
1484
  }
1474
- const [signedMarketOrderTx, signedCancelExistingOrdersTx] = await this.provider.wallet.signAllTransactions([marketOrderTx, cancelExistingOrdersTx].filter((tx) => tx !== undefined));
1485
+ if (settlePnlTx) {
1486
+ settlePnlTx.recentBlockhash = currentBlockHash;
1487
+ settlePnlTx.feePayer = userAccount.authority;
1488
+ }
1489
+ const allPossibleTxs = [
1490
+ marketOrderTx,
1491
+ cancelExistingOrdersTx,
1492
+ settlePnlTx,
1493
+ ];
1494
+ const txKeys = [
1495
+ 'signedMarketOrderTx',
1496
+ 'signedCancelExistingOrdersTx',
1497
+ 'signedSettlePnlTx',
1498
+ ];
1499
+ const { signedMarketOrderTx, signedCancelExistingOrdersTx, signedSettlePnlTx, } = await (0, utils_1.getSignedTransactionMap)(
1500
+ //@ts-ignore
1501
+ this.provider.wallet, allPossibleTxs, txKeys);
1475
1502
  const { txSig, slot } = await this.sendTransaction(signedMarketOrderTx, [], this.opts, true);
1476
1503
  this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
1477
- return { txSig, signedFillTx: undefined, signedCancelExistingOrdersTx };
1504
+ return {
1505
+ txSig,
1506
+ signedFillTx: undefined,
1507
+ //@ts-ignore
1508
+ signedCancelExistingOrdersTx,
1509
+ //@ts-ignore
1510
+ signedSettlePnlTx,
1511
+ };
1478
1512
  }
1479
1513
  }
1480
1514
  async placePerpOrder(orderParams, txParams, subAccountId) {
@@ -1708,7 +1742,8 @@ class DriftClient {
1708
1742
  readableSpotMarketIndexes,
1709
1743
  useMarketLastSlotCache: true,
1710
1744
  });
1711
- return await this.program.instruction.placeOrders(params, {
1745
+ const formattedParams = params.map((item) => (0, orderParams_1.getOrderParams)(item));
1746
+ return await this.program.instruction.placeOrders(formattedParams, {
1712
1747
  accounts: {
1713
1748
  state: await this.getStatePublicKey(),
1714
1749
  user,
@@ -2168,7 +2203,6 @@ class DriftClient {
2168
2203
  slippageBps,
2169
2204
  swapMode,
2170
2205
  onlyDirectRoutes,
2171
- excludeDexes: ['Raydium CLMM'], // temp exclude to workaround bug with raydium clmm
2172
2206
  });
2173
2207
  quote = fetchedQuote;
2174
2208
  }
@@ -2412,6 +2446,47 @@ class DriftClient {
2412
2446
  this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
2413
2447
  return txSig;
2414
2448
  }
2449
+ async placeAndTakePerpWithAdditionalOrders(orderParams, makerInfo, referrerInfo, bracketOrdersParams = new Array(), txParams, subAccountId, cancelExistingOrders, settlePnl) {
2450
+ let cancelExistingOrdersTx;
2451
+ if (cancelExistingOrders && (0, types_1.isVariant)(orderParams.marketType, 'perp')) {
2452
+ const cancelOrdersIx = await this.getCancelOrdersIx(orderParams.marketType, orderParams.marketIndex, null, subAccountId);
2453
+ //@ts-ignore
2454
+ cancelExistingOrdersTx = await this.buildTransaction([cancelOrdersIx], txParams, this.txVersion);
2455
+ }
2456
+ /* Settle PnL after fill if requested */
2457
+ let settlePnlTx;
2458
+ if (settlePnl && (0, types_1.isVariant)(orderParams.marketType, 'perp')) {
2459
+ const userAccountPublicKey = await this.getUserAccountPublicKey(subAccountId);
2460
+ const settlePnlIx = await this.settlePNLIx(userAccountPublicKey, this.getUserAccount(subAccountId), orderParams.marketIndex);
2461
+ //@ts-ignore
2462
+ settlePnlTx = await this.buildTransaction([settlePnlIx], txParams, this.txVersion);
2463
+ }
2464
+ const ixs = [];
2465
+ const placeAndTakeIx = await this.getPlaceAndTakePerpOrderIx(orderParams, makerInfo, referrerInfo, subAccountId);
2466
+ ixs.push(placeAndTakeIx);
2467
+ if (bracketOrdersParams.length > 0) {
2468
+ const bracketOrdersIx = await this.getPlaceOrdersIx(bracketOrdersParams, subAccountId);
2469
+ ixs.push(bracketOrdersIx);
2470
+ }
2471
+ const placeAndTakeTx = await this.buildTransaction(ixs, txParams);
2472
+ const allPossibleTxs = [
2473
+ placeAndTakeTx,
2474
+ cancelExistingOrdersTx,
2475
+ settlePnlTx,
2476
+ ];
2477
+ const txKeys = [
2478
+ 'signedPlaceAndTakeTx',
2479
+ 'signedCancelExistingOrdersTx',
2480
+ 'signedSettlePnlTx',
2481
+ ];
2482
+ const { signedPlaceAndTakeTx, signedCancelExistingOrdersTx, signedSettlePnlTx, } = await (0, utils_1.getSignedTransactionMap)(
2483
+ //@ts-ignore
2484
+ this.provider.wallet, allPossibleTxs, txKeys);
2485
+ const { txSig, slot } = await this.sendTransaction(signedPlaceAndTakeTx, [], this.opts, true);
2486
+ this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
2487
+ //@ts-ignore
2488
+ return { txSig, signedCancelExistingOrdersTx, signedSettlePnlTx };
2489
+ }
2415
2490
  async getPlaceAndTakePerpOrderIx(orderParams, makerInfo, referrerInfo, subAccountId) {
2416
2491
  orderParams = (0, orderParams_1.getOrderParams)(orderParams, { marketType: types_1.MarketType.PERP });
2417
2492
  const userStatsPublicKey = await this.getUserStatsAccountPublicKey();
@@ -44,6 +44,9 @@ class WebSocketLogProvider {
44
44
  }
45
45
  this.reconnectAttempts = 0;
46
46
  }
47
+ if (logs.err !== null) {
48
+ return;
49
+ }
47
50
  callback(logs.signature, ctx.slot, logs.logs, undefined);
48
51
  }, this.commitment);
49
52
  }
@@ -8524,7 +8524,13 @@
8524
8524
  "kind": "enum",
8525
8525
  "variants": [
8526
8526
  {
8527
- "name": "Standard"
8527
+ "name": "Standard",
8528
+ "fields": [
8529
+ {
8530
+ "name": "track_open_orders_fraction",
8531
+ "type": "bool"
8532
+ }
8533
+ ]
8528
8534
  },
8529
8535
  {
8530
8536
  "name": "Liquidation",
@@ -195,6 +195,12 @@ export interface QuoteResponse {
195
195
  * @memberof QuoteResponse
196
196
  */
197
197
  timeTaken?: number;
198
+ /**
199
+ *
200
+ * @type {string}
201
+ * @memberof QuoteResponse
202
+ */
203
+ error?: string;
198
204
  }
199
205
  export declare class JupiterClient {
200
206
  url: string;
@@ -44,7 +44,7 @@ class JupiterClient {
44
44
  * @param onlyDirectRoutes whether to only return direct routes
45
45
  */
46
46
  async getQuote({ inputMint, outputMint, amount, maxAccounts = 50, // 50 is an estimated amount with buffer
47
- slippageBps = 50, swapMode = 'ExactIn', onlyDirectRoutes = false, excludeDexes = [], }) {
47
+ slippageBps = 50, swapMode = 'ExactIn', onlyDirectRoutes = false, excludeDexes, }) {
48
48
  const params = new URLSearchParams({
49
49
  inputMint: inputMint.toString(),
50
50
  outputMint: outputMint.toString(),
@@ -53,7 +53,7 @@ class JupiterClient {
53
53
  swapMode,
54
54
  onlyDirectRoutes: onlyDirectRoutes.toString(),
55
55
  maxAccounts: maxAccounts.toString(),
56
- excludeDexes: excludeDexes.join(','),
56
+ ...(excludeDexes && { excludeDexes: excludeDexes.join(',') }),
57
57
  }).toString();
58
58
  const quote = await (await (0, node_fetch_1.default)(`${this.url}/v6/quote?${params}`)).json();
59
59
  return quote;
@@ -6,6 +6,7 @@ const numericConstants_1 = require("../constants/numericConstants");
6
6
  const types_1 = require("../types");
7
7
  const amm_1 = require("./amm");
8
8
  const oracles_1 = require("./oracles");
9
+ const utils_1 = require("./utils");
9
10
  function calculateLiveMarkTwap(market, oraclePriceData, markPrice, now, period = new anchor_1.BN(3600)) {
10
11
  now = now || new anchor_1.BN((Date.now() / 1000).toFixed(0));
11
12
  const lastMarkTwapWithMantissa = market.amm.lastMarkPriceTwap;
@@ -73,7 +74,9 @@ async function calculateAllEstimatedFundingRate(market, oraclePriceData, markPri
73
74
  // }
74
75
  const twapSpread = markTwap.sub(oracleTwap);
75
76
  const twapSpreadWithOffset = twapSpread.add(oracleTwap.abs().div(numericConstants_1.FUNDING_RATE_OFFSET_DENOMINATOR));
76
- const twapSpreadPct = twapSpreadWithOffset
77
+ const maxSpread = getMaxPriceDivergenceForFundingRate(market, oracleTwap);
78
+ const clampedSpreadWithOffset = (0, utils_1.clampBN)(twapSpreadWithOffset, maxSpread.mul(new anchor_1.BN(-1)), maxSpread);
79
+ const twapSpreadPct = clampedSpreadWithOffset
77
80
  .mul(numericConstants_1.PRICE_PRECISION)
78
81
  .mul(new anchor_1.BN(100))
79
82
  .div(oracleTwap);
@@ -135,6 +138,26 @@ async function calculateAllEstimatedFundingRate(market, oraclePriceData, markPri
135
138
  return [markTwap, oracleTwap, lowerboundEst, cappedAltEst, interpEst];
136
139
  }
137
140
  exports.calculateAllEstimatedFundingRate = calculateAllEstimatedFundingRate;
141
+ function getMaxPriceDivergenceForFundingRate(market, oracleTwap) {
142
+ if ((0, types_1.isVariant)(market.contractTier, 'a')) {
143
+ return oracleTwap.divn(33);
144
+ }
145
+ else if ((0, types_1.isVariant)(market.contractTier, 'b')) {
146
+ return oracleTwap.divn(33);
147
+ }
148
+ else if ((0, types_1.isVariant)(market.contractTier, 'c')) {
149
+ return oracleTwap.divn(20);
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
+ else {
158
+ return oracleTwap.divn(10);
159
+ }
160
+ }
138
161
  /**
139
162
  *
140
163
  * @param market
@@ -25,8 +25,8 @@ function isOracleValid(amm, oraclePriceData, oracleGuardRails, slot) {
25
25
  .mul(numericConstants_1.BID_ASK_SPREAD_PRECISION)
26
26
  .div(oraclePriceData.price)
27
27
  .gt(oracleGuardRails.validity.confidenceIntervalMaxSize);
28
- const oracleIsStale = oraclePriceData.slot
29
- .sub(new index_1.BN(slot))
28
+ const oracleIsStale = new index_1.BN(slot)
29
+ .sub(oraclePriceData.slot)
30
30
  .gt(oracleGuardRails.validity.slotsBeforeStaleForAmm);
31
31
  return !(!oraclePriceData.hasSufficientNumberOfDataPoints ||
32
32
  oracleIsStale ||
@@ -111,6 +111,57 @@ export type JITO_SOL_METRICS_ENDPOINT_RESPONSE = {
111
111
  };
112
112
  };
113
113
  export declare function fetchJitoSolMetrics(): Promise<JITO_SOL_METRICS_ENDPOINT_RESPONSE>;
114
+ export type MSOL_METRICS_ENDPOINT_RESPONSE = {
115
+ total_active_balance: number;
116
+ available_reserve_balance: number;
117
+ emergency_cooling_down: number;
118
+ tvl_sol: number;
119
+ msol_directed_stake_sol: number;
120
+ msol_directed_stake_msol: number;
121
+ mnde_total_supply: number;
122
+ mnde_circulating_supply: number;
123
+ validators_count: number;
124
+ stake_accounts: number;
125
+ staking_sol_cap: number;
126
+ m_sol_price: number;
127
+ avg_staking_apy: number;
128
+ msol_price_apy_14d: number;
129
+ msol_price_apy_30d: number;
130
+ msol_price_apy_90d: number;
131
+ msol_price_apy_365d: number;
132
+ reserve_pda: number;
133
+ treasury_m_sol_amount: number;
134
+ m_sol_mint_supply: number;
135
+ m_sol_supply_state: number;
136
+ liq_pool_sol: number;
137
+ liq_pool_m_sol: number;
138
+ liq_pool_value: number;
139
+ liq_pool_token_supply: number;
140
+ liq_pool_token_price: number;
141
+ liq_pool_target: number;
142
+ liq_pool_min_fee: number;
143
+ liq_pool_max_fee: number;
144
+ liq_pool_current_fee: number;
145
+ liq_pool_treasury_cut: number;
146
+ liq_pool_cap: number;
147
+ total_cooling_down: number;
148
+ last_stake_delta_epoch: number;
149
+ circulating_ticket_count: number;
150
+ circulating_ticket_balance: number;
151
+ reward_fee_bp: number;
152
+ lido_staking: number;
153
+ lido_st_sol_price: number;
154
+ lido_stsol_price_apy_14d: number;
155
+ lido_stsol_price_apy_30d: number;
156
+ lido_stsol_price_apy_90d: number;
157
+ lido_stsol_price_apy_365d: number;
158
+ stake_delta: number;
159
+ bot_balance: number;
160
+ treasury_farm_claim_mnde_balance: number;
161
+ last_3_epochs_avg_duration_hs: number;
162
+ mnde_votes_validators: number;
163
+ };
164
+ export declare const fetchMSolMetrics: () => Promise<MSOL_METRICS_ENDPOINT_RESPONSE>;
114
165
  export declare function calculateSolEarned({ marketIndex, user, depositRecords, }: {
115
166
  marketIndex: number;
116
167
  user: User;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.calculateEstimatedSuperStakeLiquidationPrice = exports.calculateSolEarned = exports.fetchJitoSolMetrics = exports.findBestLstSuperStakeIxs = exports.findBestJitoSolSuperStakeIxs = exports.findBestMSolSuperStakeIxs = exports.findBestSuperStakeIxs = exports.fetchBSolDriftEmissions = exports.fetchBSolMetrics = void 0;
6
+ exports.calculateEstimatedSuperStakeLiquidationPrice = exports.calculateSolEarned = exports.fetchMSolMetrics = exports.fetchJitoSolMetrics = exports.findBestLstSuperStakeIxs = exports.findBestJitoSolSuperStakeIxs = exports.findBestMSolSuperStakeIxs = exports.findBestSuperStakeIxs = exports.fetchBSolDriftEmissions = exports.fetchBSolMetrics = void 0;
7
7
  const web3_js_1 = require("@solana/web3.js");
8
8
  const marinade_1 = require("../marinade");
9
9
  const anchor_1 = require("@coral-xyz/anchor");
@@ -194,6 +194,12 @@ async function fetchJitoSolMetrics() {
194
194
  return data;
195
195
  }
196
196
  exports.fetchJitoSolMetrics = fetchJitoSolMetrics;
197
+ const fetchMSolMetrics = async () => {
198
+ const res = await (0, node_fetch_1.default)('https://api2.marinade.finance/metrics_json');
199
+ const data = await res.json();
200
+ return data;
201
+ };
202
+ exports.fetchMSolMetrics = fetchMSolMetrics;
197
203
  const getJitoSolHistoricalPriceMap = async (timestamps) => {
198
204
  try {
199
205
  const data = await fetchJitoSolMetrics();
@@ -227,7 +233,9 @@ async function calculateSolEarned({ marketIndex, user, depositRecords, }) {
227
233
  const now = Date.now() / 1000;
228
234
  const timestamps = [
229
235
  now,
230
- ...depositRecords.map((r) => r.ts.toNumber()),
236
+ ...depositRecords
237
+ .filter((r) => r.marketIndex === marketIndex)
238
+ .map((r) => r.ts.toNumber()),
231
239
  ];
232
240
  let lstRatios = new Map();
233
241
  const getMsolPrice = async (timestamp) => {
@@ -1,10 +1,5 @@
1
1
  import { PriorityFeeStrategy } from './types';
2
2
  export declare class AverageOverSlotsStrategy implements PriorityFeeStrategy {
3
- private lookbackSlots;
4
- /**
5
- * @param lookbackSlots The number of slots to look back from the max slot in the sample
6
- */
7
- constructor(lookbackSlots?: number);
8
3
  calculate(samples: {
9
4
  slot: number;
10
5
  prioritizationFee: number;
@@ -2,27 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AverageOverSlotsStrategy = void 0;
4
4
  class AverageOverSlotsStrategy {
5
- /**
6
- * @param lookbackSlots The number of slots to look back from the max slot in the sample
7
- */
8
- constructor(lookbackSlots = 10) {
9
- this.lookbackSlots = lookbackSlots;
10
- }
11
5
  calculate(samples) {
12
6
  if (samples.length === 0) {
13
7
  return 0;
14
8
  }
15
- const stopSlot = samples[0].slot - this.lookbackSlots;
16
9
  let runningSumFees = 0;
17
- let countFees = 0;
18
10
  for (let i = 0; i < samples.length; i++) {
19
- if (samples[i].slot <= stopSlot) {
20
- return runningSumFees / countFees;
21
- }
22
11
  runningSumFees += samples[i].prioritizationFee;
23
- countFees++;
24
12
  }
25
- return runningSumFees / countFees;
13
+ return runningSumFees / samples.length;
26
14
  }
27
15
  }
28
16
  exports.AverageOverSlotsStrategy = AverageOverSlotsStrategy;
@@ -1,10 +1,5 @@
1
1
  import { PriorityFeeStrategy } from './types';
2
2
  export declare class MaxOverSlotsStrategy implements PriorityFeeStrategy {
3
- private lookbackSlots;
4
- /**
5
- * @param lookbackSlots The number of slots to look back from the max slot in the sample
6
- */
7
- constructor(lookbackSlots?: number);
8
3
  calculate(samples: {
9
4
  slot: number;
10
5
  prioritizationFee: number;
@@ -2,26 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MaxOverSlotsStrategy = void 0;
4
4
  class MaxOverSlotsStrategy {
5
- /**
6
- * @param lookbackSlots The number of slots to look back from the max slot in the sample
7
- */
8
- constructor(lookbackSlots = 10) {
9
- this.lookbackSlots = lookbackSlots;
10
- }
11
5
  calculate(samples) {
12
6
  if (samples.length === 0) {
13
7
  return 0;
14
8
  }
15
9
  // Assuming samples are sorted in descending order of slot.
16
- const stopSlot = samples[0].slot - this.lookbackSlots;
17
10
  let currMaxFee = samples[0].prioritizationFee;
18
11
  for (let i = 0; i < samples.length; i++) {
19
- if (samples[i].slot <= stopSlot) {
20
- return currMaxFee;
21
- }
22
- if (samples[i].prioritizationFee > currMaxFee) {
23
- currMaxFee = samples[i].prioritizationFee;
24
- }
12
+ currMaxFee = Math.max(samples[i].prioritizationFee, currMaxFee);
25
13
  }
26
14
  return currMaxFee;
27
15
  }
@@ -9,13 +9,17 @@ export declare class PriorityFeeSubscriber {
9
9
  customStrategy?: PriorityFeeStrategy;
10
10
  averageStrategy: AverageOverSlotsStrategy;
11
11
  maxStrategy: MaxOverSlotsStrategy;
12
+ lookbackDistance: number;
12
13
  intervalId?: ReturnType<typeof setTimeout>;
13
14
  latestPriorityFee: number;
14
- lastStrategyResult: number;
15
15
  lastCustomStrategyResult: number;
16
16
  lastAvgStrategyResult: number;
17
17
  lastMaxStrategyResult: number;
18
18
  lastSlotSeen: number;
19
+ /**
20
+ * @param props
21
+ * customStrategy : strategy to return the priority fee to use based on recent samples. defaults to AVERAGE.
22
+ */
19
23
  constructor({ connection, frequencyMs, addresses, customStrategy, slotsToCheck, }: {
20
24
  connection: Connection;
21
25
  frequencyMs: number;
@@ -23,9 +27,6 @@ export declare class PriorityFeeSubscriber {
23
27
  customStrategy?: PriorityFeeStrategy;
24
28
  slotsToCheck?: number;
25
29
  });
26
- get avgPriorityFee(): number;
27
- get maxPriorityFee(): number;
28
- get customPriorityFee(): number;
29
30
  subscribe(): Promise<void>;
30
31
  load(): Promise<void>;
31
32
  unsubscribe(): Promise<void>;
@@ -4,11 +4,14 @@ exports.PriorityFeeSubscriber = void 0;
4
4
  const averageOverSlotsStrategy_1 = require("./averageOverSlotsStrategy");
5
5
  const maxOverSlotsStrategy_1 = require("./maxOverSlotsStrategy");
6
6
  class PriorityFeeSubscriber {
7
+ /**
8
+ * @param props
9
+ * customStrategy : strategy to return the priority fee to use based on recent samples. defaults to AVERAGE.
10
+ */
7
11
  constructor({ connection, frequencyMs, addresses, customStrategy, slotsToCheck = 10, }) {
8
12
  this.averageStrategy = new averageOverSlotsStrategy_1.AverageOverSlotsStrategy();
9
13
  this.maxStrategy = new maxOverSlotsStrategy_1.MaxOverSlotsStrategy();
10
14
  this.latestPriorityFee = 0;
11
- this.lastStrategyResult = 0;
12
15
  this.lastCustomStrategyResult = 0;
13
16
  this.lastAvgStrategyResult = 0;
14
17
  this.lastMaxStrategyResult = 0;
@@ -16,25 +19,13 @@ class PriorityFeeSubscriber {
16
19
  this.connection = connection;
17
20
  this.frequencyMs = frequencyMs;
18
21
  this.addresses = addresses;
19
- if (slotsToCheck) {
20
- this.averageStrategy = new averageOverSlotsStrategy_1.AverageOverSlotsStrategy(slotsToCheck);
21
- this.maxStrategy = new maxOverSlotsStrategy_1.MaxOverSlotsStrategy(slotsToCheck);
22
+ if (!customStrategy) {
23
+ this.customStrategy = new averageOverSlotsStrategy_1.AverageOverSlotsStrategy();
22
24
  }
23
- if (customStrategy) {
25
+ else {
24
26
  this.customStrategy = customStrategy;
25
27
  }
26
- }
27
- get avgPriorityFee() {
28
- return Math.floor(this.lastAvgStrategyResult);
29
- }
30
- get maxPriorityFee() {
31
- return Math.floor(this.lastMaxStrategyResult);
32
- }
33
- get customPriorityFee() {
34
- if (!this.customStrategy) {
35
- console.error('Custom strategy not set');
36
- }
37
- return Math.floor(this.lastCustomStrategyResult);
28
+ this.lookbackDistance = slotsToCheck;
38
29
  }
39
30
  async subscribe() {
40
31
  if (this.intervalId) {
@@ -45,19 +36,22 @@ class PriorityFeeSubscriber {
45
36
  async load() {
46
37
  // @ts-ignore
47
38
  const rpcJSONResponse = await this.connection._rpcRequest('getRecentPrioritizationFees', [this.addresses]);
48
- // getRecentPrioritizationFees returns results unsorted
49
39
  const results = rpcJSONResponse === null || rpcJSONResponse === void 0 ? void 0 : rpcJSONResponse.result;
50
40
  if (!results.length)
51
41
  return;
42
+ // # Sort and filter results based on the slot lookback setting
52
43
  const descResults = results.sort((a, b) => b.slot - a.slot);
53
44
  const mostRecentResult = descResults[0];
45
+ const cutoffSlot = mostRecentResult.slot - this.lookbackDistance;
46
+ const resultsToUse = descResults.filter((result) => result.slot >= cutoffSlot);
47
+ // # Handle results
54
48
  this.latestPriorityFee = mostRecentResult.prioritizationFee;
55
49
  this.lastSlotSeen = mostRecentResult.slot;
56
- this.lastAvgStrategyResult = this.averageStrategy.calculate(descResults);
57
- this.lastMaxStrategyResult = this.maxStrategy.calculate(descResults);
50
+ this.lastAvgStrategyResult = this.averageStrategy.calculate(resultsToUse);
51
+ this.lastMaxStrategyResult = this.maxStrategy.calculate(resultsToUse);
58
52
  if (this.customStrategy) {
59
53
  this.lastCustomStrategyResult =
60
- this.customStrategy.calculate(descResults);
54
+ this.customStrategy.calculate(resultsToUse);
61
55
  }
62
56
  }
63
57
  async unsubscribe() {