@drift-labs/sdk 2.84.0-beta.4 → 2.84.0-beta.6

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/VERSION CHANGED
@@ -1 +1 @@
1
- 2.84.0-beta.4
1
+ 2.84.0-beta.6
@@ -228,6 +228,16 @@ exports.MainnetSpotMarkets = [
228
228
  precisionExp: numericConstants_1.NINE,
229
229
  launchTs: 1716595200000,
230
230
  },
231
+ {
232
+ symbol: 'USDY',
233
+ marketIndex: 18,
234
+ oracle: new web3_js_1.PublicKey('DiqUGbq5CV8Tjcae1whjrX97qPo6gU7BKAvKNFc2vrX8'),
235
+ oracleSource: __1.OracleSource.SWITCHBOARD,
236
+ mint: new web3_js_1.PublicKey('A1KLoBrKBde8Ty9qtNQUtq3C2ortoC3u7twggz7sEto6'),
237
+ precision: new __1.BN(10).pow(numericConstants_1.SIX),
238
+ precisionExp: numericConstants_1.SIX,
239
+ launchTs: 1718811089000,
240
+ },
231
241
  ];
232
242
  exports.SpotMarkets = {
233
243
  devnet: exports.DevnetSpotMarkets,
@@ -92,7 +92,10 @@ function getVammL2Generator({ marketAccount, oraclePriceData, numOrders, now, to
92
92
  (0, assert_1.assert)(topOfBookQuoteAmounts.length < numOrders);
93
93
  }
94
94
  const updatedAmm = (0, __1.calculateUpdatedAMM)(marketAccount.amm, oraclePriceData);
95
- let [openBids, openAsks] = (0, __1.calculateMarketOpenBidAsk)(updatedAmm.baseAssetReserve, updatedAmm.minBaseAssetReserve, updatedAmm.maxBaseAssetReserve, updatedAmm.orderStepSize);
95
+ const vammFillsDisabled = (0, __1.isOperationPaused)(marketAccount.pausedOperations, __1.PerpOperation.AMM_FILL);
96
+ let [openBids, openAsks] = vammFillsDisabled
97
+ ? [__1.ZERO, __1.ZERO]
98
+ : (0, __1.calculateMarketOpenBidAsk)(updatedAmm.baseAssetReserve, updatedAmm.minBaseAssetReserve, updatedAmm.maxBaseAssetReserve, updatedAmm.orderStepSize);
96
99
  const minOrderSize = marketAccount.amm.minOrderSize;
97
100
  if (openBids.lt(minOrderSize.muln(2))) {
98
101
  openBids = __1.ZERO;
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="bn.js" />
3
3
  import { AnchorProvider, BN, Program, ProgramAccount } from '@coral-xyz/anchor';
4
- import { StateAccount, IWallet, PositionDirection, UserAccount, PerpMarketAccount, OrderParams, Order, SpotMarketAccount, SpotPosition, MakerInfo, TakerInfo, OptionalOrderParams, ReferrerInfo, MarketType, TxParams, SerumV3FulfillmentConfigAccount, ReferrerNameAccount, OrderTriggerCondition, PerpMarketExtendedInfo, UserStatsAccount, PhoenixV1FulfillmentConfigAccount, ModifyOrderPolicy, SwapReduceOnly, SettlePnlMode } from './types';
4
+ import { StateAccount, IWallet, PositionDirection, UserAccount, PerpMarketAccount, OrderParams, Order, SpotMarketAccount, SpotPosition, MakerInfo, TakerInfo, OptionalOrderParams, ReferrerInfo, MarketType, TxParams, SerumV3FulfillmentConfigAccount, ReferrerNameAccount, OrderTriggerCondition, PerpMarketExtendedInfo, UserStatsAccount, PhoenixV1FulfillmentConfigAccount, ModifyOrderPolicy, SwapReduceOnly, SettlePnlMode, SignedTxData, MappedRecord } from './types';
5
5
  import * as anchor from '@coral-xyz/anchor';
6
6
  import { Connection, PublicKey, TransactionSignature, ConfirmOptions, Transaction, TransactionInstruction, AccountMeta, Signer, AddressLookupTableAccount, TransactionVersion, VersionedTransaction, BlockhashWithExpiryBlockHeight } from '@solana/web3.js';
7
7
  import { TokenFaucet } from './tokenFaucet';
@@ -292,6 +292,12 @@ export declare class DriftClient {
292
292
  */
293
293
  openPosition(direction: PositionDirection, amount: BN, marketIndex: number, limitPrice?: BN, subAccountId?: number): Promise<TransactionSignature>;
294
294
  sendSignedTx(tx: Transaction, opts?: ConfirmOptions): Promise<TransactionSignature>;
295
+ prepareMarketOrderTxs(orderParams: OptionalOrderParams, userAccountPublicKey: PublicKey, userAccount: UserAccount, makerInfo?: MakerInfo | MakerInfo[], txParams?: TxParams, bracketOrdersParams?: OptionalOrderParams[], referrerInfo?: ReferrerInfo, cancelExistingOrders?: boolean, settlePnl?: boolean): Promise<{
296
+ cancelExistingOrdersTx?: Transaction | VersionedTransaction;
297
+ settlePnlTx?: Transaction | VersionedTransaction;
298
+ fillTx?: Transaction | VersionedTransaction;
299
+ marketOrderTx: Transaction | VersionedTransaction;
300
+ }>;
295
301
  /**
296
302
  * Sends a market order and returns a signed tx which can fill the order against the vamm, which the caller can use to fill their own order if required.
297
303
  * @param orderParams
@@ -330,11 +336,17 @@ export declare class DriftClient {
330
336
  direction?: PositionDirection;
331
337
  }, placeOrderParams: OrderParams[], txParams?: TxParams, subAccountId?: number): Promise<TransactionSignature>;
332
338
  placeOrders(params: OrderParams[], txParams?: TxParams, subAccountId?: number): Promise<TransactionSignature>;
339
+ preparePlaceOrdersTx(params: OrderParams[], txParams?: TxParams, subAccountId?: number): Promise<{
340
+ placeOrdersTx: anchor.web3.Transaction | anchor.web3.VersionedTransaction;
341
+ }>;
333
342
  getPlaceOrdersIx(params: OptionalOrderParams[], subAccountId?: number): Promise<TransactionInstruction>;
334
343
  fillPerpOrder(userAccountPublicKey: PublicKey, user: UserAccount, order?: Pick<Order, 'marketIndex' | 'orderId'>, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, txParams?: TxParams, fillerPublicKey?: number): Promise<TransactionSignature>;
335
344
  getFillPerpOrderIx(userAccountPublicKey: PublicKey, userAccount: UserAccount, order: Pick<Order, 'marketIndex' | 'orderId'>, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, fillerSubAccountId?: number): Promise<TransactionInstruction>;
336
345
  getRevertFillIx(fillerPublicKey?: PublicKey): Promise<TransactionInstruction>;
337
346
  placeSpotOrder(orderParams: OptionalOrderParams, txParams?: TxParams, subAccountId?: number): Promise<TransactionSignature>;
347
+ preparePlaceSpotOrderTx(orderParams: OptionalOrderParams, txParams?: TxParams, subAccountId?: number): Promise<{
348
+ placeSpotOrderTx: anchor.web3.Transaction | anchor.web3.VersionedTransaction;
349
+ }>;
338
350
  getPlaceSpotOrderIx(orderParams: OptionalOrderParams, subAccountId?: number): Promise<TransactionInstruction>;
339
351
  fillSpotOrder(userAccountPublicKey: PublicKey, user: UserAccount, order?: Order, fulfillmentConfig?: SerumV3FulfillmentConfigAccount | PhoenixV1FulfillmentConfigAccount, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, txParams?: TxParams): Promise<TransactionSignature>;
340
352
  getFillSpotOrderIx(userAccountPublicKey: PublicKey, userAccount: UserAccount, order?: Order, fulfillmentConfig?: SerumV3FulfillmentConfigAccount | PhoenixV1FulfillmentConfigAccount, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, fillerPublicKey?: PublicKey): Promise<TransactionInstruction>;
@@ -447,6 +459,11 @@ export declare class DriftClient {
447
459
  updateUserOpenOrdersCount(userAccountPublicKey: PublicKey, user: UserAccount, txParams?: TxParams, fillerPublicKey?: PublicKey): Promise<TransactionSignature>;
448
460
  getUpdateUserOpenOrdersCountIx(userAccountPublicKey: PublicKey, userAccount: UserAccount, fillerPublicKey?: PublicKey): Promise<TransactionInstruction>;
449
461
  placeAndTakePerpOrder(orderParams: OptionalOrderParams, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, txParams?: TxParams, subAccountId?: number): Promise<TransactionSignature>;
462
+ preparePlaceAndTakePerpOrderWithAdditionalOrders(orderParams: OptionalOrderParams, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, bracketOrdersParams?: OptionalOrderParams[], txParams?: TxParams, subAccountId?: number, cancelExistingOrders?: boolean, settlePnl?: boolean, exitEarlyIfSimFails?: boolean): Promise<{
463
+ placeAndTakeTx: Transaction | VersionedTransaction;
464
+ cancelExistingOrdersTx: Transaction | VersionedTransaction;
465
+ settlePnlTx: Transaction | VersionedTransaction;
466
+ }>;
450
467
  placeAndTakePerpWithAdditionalOrders(orderParams: OptionalOrderParams, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, bracketOrdersParams?: OptionalOrderParams[], txParams?: TxParams, subAccountId?: number, cancelExistingOrders?: boolean, settlePnl?: boolean, exitEarlyIfSimFails?: boolean): Promise<{
451
468
  txSig: TransactionSignature;
452
469
  signedCancelExistingOrdersTx?: Transaction;
@@ -455,6 +472,9 @@ export declare class DriftClient {
455
472
  getPlaceAndTakePerpOrderIx(orderParams: OptionalOrderParams, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, subAccountId?: number): Promise<TransactionInstruction>;
456
473
  placeAndMakePerpOrder(orderParams: OptionalOrderParams, takerInfo: TakerInfo, referrerInfo?: ReferrerInfo, txParams?: TxParams, subAccountId?: number): Promise<TransactionSignature>;
457
474
  getPlaceAndMakePerpOrderIx(orderParams: OptionalOrderParams, takerInfo: TakerInfo, referrerInfo?: ReferrerInfo, subAccountId?: number): Promise<TransactionInstruction>;
475
+ preparePlaceAndTakeSpotOrder(orderParams: OptionalOrderParams, fulfillmentConfig?: SerumV3FulfillmentConfigAccount, makerInfo?: MakerInfo, referrerInfo?: ReferrerInfo, txParams?: TxParams, subAccountId?: number): Promise<{
476
+ placeAndTakeSpotOrderTx: anchor.web3.Transaction | anchor.web3.VersionedTransaction;
477
+ }>;
458
478
  placeAndTakeSpotOrder(orderParams: OptionalOrderParams, fulfillmentConfig?: SerumV3FulfillmentConfigAccount, makerInfo?: MakerInfo, referrerInfo?: ReferrerInfo, txParams?: TxParams, subAccountId?: number): Promise<TransactionSignature>;
459
479
  getPlaceAndTakeSpotOrderIx(orderParams: OptionalOrderParams, fulfillmentConfig?: SerumV3FulfillmentConfigAccount, makerInfo?: MakerInfo, referrerInfo?: ReferrerInfo, subAccountId?: number): Promise<TransactionInstruction>;
460
480
  placeAndMakeSpotOrder(orderParams: OptionalOrderParams, takerInfo: TakerInfo, fulfillmentConfig?: SerumV3FulfillmentConfigAccount, referrerInfo?: ReferrerInfo, txParams?: TxParams, subAccountId?: number): Promise<TransactionSignature>;
@@ -687,8 +707,13 @@ export declare class DriftClient {
687
707
  sendTransaction(tx: Transaction | VersionedTransaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean): Promise<TxSigAndSlot>;
688
708
  buildTransaction(instructions: TransactionInstruction | TransactionInstruction[], txParams?: TxParams, txVersion?: TransactionVersion, lookupTables?: AddressLookupTableAccount[], forceVersionedTransaction?: boolean, recentBlockhash?: BlockhashWithExpiryBlockHeight): Promise<Transaction | VersionedTransaction>;
689
709
  buildBulkTransactions(instructions: (TransactionInstruction | TransactionInstruction[])[], txParams?: TxParams, txVersion?: TransactionVersion, lookupTables?: AddressLookupTableAccount[], forceVersionedTransaction?: boolean): Promise<(Transaction | VersionedTransaction)[]>;
690
- buildAndSignBulkTransactions(instructions: (TransactionInstruction | TransactionInstruction[])[], keys: string[], txParams?: TxParams, txVersion?: TransactionVersion, lookupTables?: AddressLookupTableAccount[], forceVersionedTransaction?: boolean): Promise<{
691
- [key: string]: anchor.web3.Transaction | anchor.web3.VersionedTransaction;
710
+ buildTransactionsMap(instructionsMap: Record<string, TransactionInstruction | TransactionInstruction[]>, txParams?: TxParams, txVersion?: TransactionVersion, lookupTables?: AddressLookupTableAccount[], forceVersionedTransaction?: boolean): Promise<MappedRecord<Record<string, anchor.web3.TransactionInstruction | anchor.web3.TransactionInstruction[]>, anchor.web3.Transaction | anchor.web3.VersionedTransaction>>;
711
+ buildAndSignTransactionsMap(instructionsMap: Record<string, TransactionInstruction | TransactionInstruction[]>, txParams?: TxParams, txVersion?: TransactionVersion, lookupTables?: AddressLookupTableAccount[], forceVersionedTransaction?: boolean): Promise<{
712
+ signedTxMap: Record<string, anchor.web3.Transaction>;
713
+ signedTxData: SignedTxData[];
714
+ } | {
715
+ signedTxMap: MappedRecord<Record<string, anchor.web3.TransactionInstruction | anchor.web3.TransactionInstruction[]>, anchor.web3.Transaction | anchor.web3.VersionedTransaction>;
716
+ signedTxData: SignedTxData[];
692
717
  }>;
693
718
  }
694
719
  export {};
@@ -1510,6 +1510,40 @@ class DriftClient {
1510
1510
  const { txSig } = await this.sendTransaction(tx, undefined, opts !== null && opts !== void 0 ? opts : this.opts, true);
1511
1511
  return txSig;
1512
1512
  }
1513
+ async prepareMarketOrderTxs(orderParams, userAccountPublicKey, userAccount, makerInfo, txParams, bracketOrdersParams = new Array(), referrerInfo, cancelExistingOrders, settlePnl) {
1514
+ const marketIndex = orderParams.marketIndex;
1515
+ const orderId = userAccount.nextOrderId;
1516
+ const ixPromisesForTxs = {
1517
+ cancelExistingOrdersTx: undefined,
1518
+ settlePnlTx: undefined,
1519
+ fillTx: undefined,
1520
+ marketOrderTx: undefined,
1521
+ };
1522
+ const txKeys = Object.keys(ixPromisesForTxs);
1523
+ ixPromisesForTxs.marketOrderTx = this.getPlaceOrdersIx([orderParams, ...bracketOrdersParams], userAccount.subAccountId);
1524
+ /* Cancel open orders in market if requested */
1525
+ if (cancelExistingOrders && (0, types_1.isVariant)(orderParams.marketType, 'perp')) {
1526
+ ixPromisesForTxs.cancelExistingOrdersTx = this.getCancelOrdersIx(orderParams.marketType, orderParams.marketIndex, null, userAccount.subAccountId);
1527
+ }
1528
+ /* Settle PnL after fill if requested */
1529
+ if (settlePnl && (0, types_1.isVariant)(orderParams.marketType, 'perp')) {
1530
+ ixPromisesForTxs.settlePnlTx = this.settlePNLIx(userAccountPublicKey, userAccount, marketIndex);
1531
+ }
1532
+ // use versioned transactions if there is a lookup table account and wallet is compatible
1533
+ if (this.txVersion === 0) {
1534
+ ixPromisesForTxs.fillTx = this.getFillPerpOrderIx(userAccountPublicKey, userAccount, {
1535
+ orderId,
1536
+ marketIndex,
1537
+ }, makerInfo, referrerInfo, userAccount.subAccountId);
1538
+ }
1539
+ const ixs = await Promise.all(Object.values(ixPromisesForTxs));
1540
+ const ixsMap = ixs.reduce((acc, ix, i) => {
1541
+ acc[txKeys[i]] = ix;
1542
+ return acc;
1543
+ }, {});
1544
+ const txsMap = (await this.buildTransactionsMap(ixsMap, txParams));
1545
+ return txsMap;
1546
+ }
1513
1547
  /**
1514
1548
  * Sends a market order and returns a signed tx which can fill the order against the vamm, which the caller can use to fill their own order if required.
1515
1549
  * @param orderParams
@@ -1522,53 +1556,15 @@ class DriftClient {
1522
1556
  * @returns
1523
1557
  */
1524
1558
  async sendMarketOrderAndGetSignedFillTx(orderParams, userAccountPublicKey, userAccount, makerInfo, txParams, bracketOrdersParams = new Array(), referrerInfo, cancelExistingOrders, settlePnl) {
1525
- const marketIndex = orderParams.marketIndex;
1526
- const orderId = userAccount.nextOrderId;
1527
- const ordersIx = await this.getPlaceOrdersIx([orderParams, ...bracketOrdersParams], userAccount.subAccountId);
1528
- const ixsToSign = [];
1529
- const keys = {
1530
- signedCancelExistingOrdersTx: 'signedCancelExistingOrdersTx',
1531
- signedSettlePnlTx: 'signedSettlePnlTx',
1532
- signedFillTx: 'signedFillTx',
1533
- signedMarketOrderTx: 'signedMarketOrderTx',
1534
- };
1535
- /* Cancel open orders in market if requested */
1536
- if (cancelExistingOrders && (0, types_1.isVariant)(orderParams.marketType, 'perp')) {
1537
- ixsToSign.push({
1538
- key: keys.signedCancelExistingOrdersTx,
1539
- ix: await this.getCancelOrdersIx(orderParams.marketType, orderParams.marketIndex, null, userAccount.subAccountId),
1540
- });
1541
- }
1542
- /* Settle PnL after fill if requested */
1543
- if (settlePnl && (0, types_1.isVariant)(orderParams.marketType, 'perp')) {
1544
- ixsToSign.push({
1545
- key: keys.signedSettlePnlTx,
1546
- ix: await this.settlePNLIx(userAccountPublicKey, userAccount, marketIndex),
1547
- });
1548
- }
1549
- // use versioned transactions if there is a lookup table account and wallet is compatible
1550
- if (this.txVersion === 0) {
1551
- ixsToSign.push({
1552
- key: keys.signedFillTx,
1553
- ix: await this.getFillPerpOrderIx(userAccountPublicKey, userAccount, {
1554
- orderId,
1555
- marketIndex,
1556
- }, makerInfo, referrerInfo, userAccount.subAccountId),
1557
- });
1558
- }
1559
- // Apply the latest blockhash to the txs so that we can sign before sending them
1560
- ixsToSign.push({
1561
- key: keys.signedMarketOrderTx,
1562
- ix: ordersIx,
1563
- });
1564
- const signedTransactions = await this.buildAndSignBulkTransactions(ixsToSign.map((ix) => ix.ix), ixsToSign.map((ix) => ix.key), txParams);
1565
- const { txSig, slot } = await this.sendTransaction(signedTransactions[keys.signedMarketOrderTx], [], this.opts, true);
1559
+ const preppedTxs = await this.prepareMarketOrderTxs(orderParams, userAccountPublicKey, userAccount, makerInfo, txParams, bracketOrdersParams, referrerInfo, cancelExistingOrders, settlePnl);
1560
+ const signedTxs = (await this.txHandler.getSignedTransactionMap(preppedTxs, this.wallet)).signedTxMap;
1561
+ const { txSig, slot } = await this.sendTransaction(signedTxs.marketOrderTx, [], this.opts, true);
1566
1562
  this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
1567
1563
  return {
1568
1564
  txSig,
1569
- signedFillTx: signedTransactions === null || signedTransactions === void 0 ? void 0 : signedTransactions[keys.signedFillTx],
1570
- signedCancelExistingOrdersTx: signedTransactions === null || signedTransactions === void 0 ? void 0 : signedTransactions[keys.signedCancelExistingOrdersTx],
1571
- signedSettlePnlTx: signedTransactions === null || signedTransactions === void 0 ? void 0 : signedTransactions[keys.signedSettlePnlTx],
1565
+ signedFillTx: signedTxs.fillTx,
1566
+ signedCancelExistingOrdersTx: signedTxs.cancelExistingOrdersTx,
1567
+ signedSettlePnlTx: signedTxs.settlePnlTx,
1572
1568
  };
1573
1569
  }
1574
1570
  async placePerpOrder(orderParams, txParams, subAccountId) {
@@ -1780,9 +1776,16 @@ class DriftClient {
1780
1776
  return txSig;
1781
1777
  }
1782
1778
  async placeOrders(params, txParams, subAccountId) {
1783
- const { txSig } = await this.sendTransaction(await this.buildTransaction(await this.getPlaceOrdersIx(params, subAccountId), txParams), [], this.opts);
1779
+ const { txSig } = await this.sendTransaction((await this.preparePlaceOrdersTx(params, txParams, subAccountId))
1780
+ .placeOrdersTx, [], this.opts, false);
1784
1781
  return txSig;
1785
1782
  }
1783
+ async preparePlaceOrdersTx(params, txParams, subAccountId) {
1784
+ const tx = await this.buildTransaction(await this.getPlaceOrdersIx(params, subAccountId), txParams);
1785
+ return {
1786
+ placeOrdersTx: tx,
1787
+ };
1788
+ }
1786
1789
  async getPlaceOrdersIx(params, subAccountId) {
1787
1790
  const user = await this.getUserAccountPublicKey(subAccountId);
1788
1791
  const readablePerpMarketIndex = [];
@@ -1893,11 +1896,18 @@ class DriftClient {
1893
1896
  });
1894
1897
  }
1895
1898
  async placeSpotOrder(orderParams, txParams, subAccountId) {
1896
- const { txSig, slot } = await this.sendTransaction(await this.buildTransaction(await this.getPlaceSpotOrderIx(orderParams, subAccountId), txParams), [], this.opts);
1899
+ const { txSig, slot } = await this.sendTransaction((await this.preparePlaceSpotOrderTx(orderParams, txParams, subAccountId))
1900
+ .placeSpotOrderTx, [], this.opts, false);
1897
1901
  this.spotMarketLastSlotCache.set(orderParams.marketIndex, slot);
1898
1902
  this.spotMarketLastSlotCache.set(numericConstants_1.QUOTE_SPOT_MARKET_INDEX, slot);
1899
1903
  return txSig;
1900
1904
  }
1905
+ async preparePlaceSpotOrderTx(orderParams, txParams, subAccountId) {
1906
+ const tx = await this.buildTransaction(await this.getPlaceSpotOrderIx(orderParams, subAccountId), txParams);
1907
+ return {
1908
+ placeSpotOrderTx: tx,
1909
+ };
1910
+ }
1901
1911
  async getPlaceSpotOrderIx(orderParams, subAccountId) {
1902
1912
  orderParams = (0, orderParams_1.getOrderParams)(orderParams, { marketType: types_1.MarketType.SPOT });
1903
1913
  const userAccountPublicKey = await this.getUserAccountPublicKey(subAccountId);
@@ -2500,13 +2510,12 @@ class DriftClient {
2500
2510
  this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
2501
2511
  return txSig;
2502
2512
  }
2503
- async placeAndTakePerpWithAdditionalOrders(orderParams, makerInfo, referrerInfo, bracketOrdersParams = new Array(), txParams, subAccountId, cancelExistingOrders, settlePnl, exitEarlyIfSimFails) {
2513
+ async preparePlaceAndTakePerpOrderWithAdditionalOrders(orderParams, makerInfo, referrerInfo, bracketOrdersParams = new Array(), txParams, subAccountId, cancelExistingOrders, settlePnl, exitEarlyIfSimFails) {
2504
2514
  const placeAndTakeIxs = [];
2505
- const txsToSign = [];
2506
- const keys = {
2507
- placeAndTakeIx: 'placeAndTakeIx',
2508
- cancelExistingOrdersTx: 'cancelExistingOrdersTx',
2509
- settlePnlTx: 'settlePnlTx',
2515
+ const txsToSign = {
2516
+ placeAndTakeTx: undefined,
2517
+ cancelExistingOrdersTx: undefined,
2518
+ settlePnlTx: undefined,
2510
2519
  };
2511
2520
  // Get recent block hash so that we can re-use it for all transactions. Makes this logic run faster with fewer RPC requests
2512
2521
  const recentBlockHash = await this.txHandler.getLatestBlockhashForTransaction();
@@ -2532,29 +2541,20 @@ class DriftClient {
2532
2541
  earlyExitFailedPlaceAndTakeSim = true;
2533
2542
  return;
2534
2543
  }
2535
- txsToSign.push({
2536
- key: keys.placeAndTakeIx,
2537
- tx: await this.buildTransaction(placeAndTakeIxs, {
2538
- ...txParamsWithoutImplicitSimulation,
2539
- computeUnits: simulationResult.computeUnits,
2540
- }, undefined, undefined, undefined, recentBlockHash),
2541
- });
2544
+ txsToSign.placeAndTakeTx = await this.buildTransaction(placeAndTakeIxs, {
2545
+ ...txParamsWithoutImplicitSimulation,
2546
+ computeUnits: simulationResult.computeUnits,
2547
+ }, undefined, undefined, undefined, recentBlockHash);
2542
2548
  }
2543
2549
  else {
2544
- txsToSign.push({
2545
- key: keys.placeAndTakeIx,
2546
- tx: await this.buildTransaction(placeAndTakeIxs, txParams, undefined, undefined, undefined, recentBlockHash),
2547
- });
2550
+ txsToSign.placeAndTakeTx = await this.buildTransaction(placeAndTakeIxs, txParams, undefined, undefined, undefined, recentBlockHash);
2548
2551
  }
2549
2552
  return;
2550
2553
  };
2551
2554
  const prepCancelOrderTx = async () => {
2552
2555
  if (cancelExistingOrders && (0, types_1.isVariant)(orderParams.marketType, 'perp')) {
2553
2556
  const cancelOrdersIx = await this.getCancelOrdersIx(orderParams.marketType, orderParams.marketIndex, null, subAccountId);
2554
- txsToSign.push({
2555
- key: keys.cancelExistingOrdersTx,
2556
- tx: await this.buildTransaction([cancelOrdersIx], txParams, this.txVersion, undefined, undefined, recentBlockHash),
2557
- });
2557
+ txsToSign.cancelExistingOrdersTx = await this.buildTransaction([cancelOrdersIx], txParams, this.txVersion, undefined, undefined, recentBlockHash);
2558
2558
  }
2559
2559
  return;
2560
2560
  };
@@ -2562,10 +2562,7 @@ class DriftClient {
2562
2562
  if (settlePnl && (0, types_1.isVariant)(orderParams.marketType, 'perp')) {
2563
2563
  const userAccountPublicKey = await this.getUserAccountPublicKey(subAccountId);
2564
2564
  const settlePnlIx = await this.settlePNLIx(userAccountPublicKey, this.getUserAccount(subAccountId), orderParams.marketIndex);
2565
- txsToSign.push({
2566
- key: keys.settlePnlTx,
2567
- tx: await this.buildTransaction([settlePnlIx], txParams, this.txVersion, undefined, undefined, recentBlockHash),
2568
- });
2565
+ txsToSign.settlePnlTx = await this.buildTransaction([settlePnlIx], txParams, this.txVersion, undefined, undefined, recentBlockHash);
2569
2566
  }
2570
2567
  return;
2571
2568
  };
@@ -2577,13 +2574,17 @@ class DriftClient {
2577
2574
  if (earlyExitFailedPlaceAndTakeSim) {
2578
2575
  return null;
2579
2576
  }
2580
- const signedTxs = await this.txHandler.getSignedTransactionMap(txsToSign.map((tx) => tx.tx), txsToSign.map((tx) => tx.key), this.provider.wallet);
2581
- const { txSig, slot } = await this.sendTransaction(signedTxs[keys.placeAndTakeIx], [], this.opts, true);
2577
+ return txsToSign;
2578
+ }
2579
+ async placeAndTakePerpWithAdditionalOrders(orderParams, makerInfo, referrerInfo, bracketOrdersParams = new Array(), txParams, subAccountId, cancelExistingOrders, settlePnl, exitEarlyIfSimFails) {
2580
+ const txsToSign = await this.preparePlaceAndTakePerpOrderWithAdditionalOrders(orderParams, makerInfo, referrerInfo, bracketOrdersParams, txParams, subAccountId, cancelExistingOrders, settlePnl, exitEarlyIfSimFails);
2581
+ const signedTxs = (await this.txHandler.getSignedTransactionMap(txsToSign, this.provider.wallet)).signedTxMap;
2582
+ const { txSig, slot } = await this.sendTransaction(signedTxs.placeAndTakeTx, [], this.opts, true);
2582
2583
  this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
2583
2584
  return {
2584
2585
  txSig,
2585
- signedCancelExistingOrdersTx: signedTxs[keys.cancelExistingOrdersTx],
2586
- signedSettlePnlTx: signedTxs[keys.settlePnlTx],
2586
+ signedCancelExistingOrdersTx: signedTxs.cancelExistingOrdersTx,
2587
+ signedSettlePnlTx: signedTxs.settlePnlTx,
2587
2588
  };
2588
2589
  }
2589
2590
  async getPlaceAndTakePerpOrderIx(orderParams, makerInfo, referrerInfo, subAccountId) {
@@ -2684,8 +2685,14 @@ class DriftClient {
2684
2685
  remainingAccounts,
2685
2686
  });
2686
2687
  }
2688
+ async preparePlaceAndTakeSpotOrder(orderParams, fulfillmentConfig, makerInfo, referrerInfo, txParams, subAccountId) {
2689
+ const tx = await this.buildTransaction(await this.getPlaceAndTakeSpotOrderIx(orderParams, fulfillmentConfig, makerInfo, referrerInfo, subAccountId), txParams);
2690
+ return {
2691
+ placeAndTakeSpotOrderTx: tx,
2692
+ };
2693
+ }
2687
2694
  async placeAndTakeSpotOrder(orderParams, fulfillmentConfig, makerInfo, referrerInfo, txParams, subAccountId) {
2688
- const { txSig, slot } = await this.sendTransaction(await this.buildTransaction(await this.getPlaceAndTakeSpotOrderIx(orderParams, fulfillmentConfig, makerInfo, referrerInfo, subAccountId), txParams), [], this.opts);
2695
+ const { txSig, slot } = await this.sendTransaction((await this.preparePlaceAndTakeSpotOrder(orderParams, fulfillmentConfig, makerInfo, referrerInfo, txParams, subAccountId)).placeAndTakeSpotOrderTx, [], this.opts, false);
2689
2696
  this.spotMarketLastSlotCache.set(orderParams.marketIndex, slot);
2690
2697
  this.spotMarketLastSlotCache.set(numericConstants_1.QUOTE_SPOT_MARKET_INDEX, slot);
2691
2698
  return txSig;
@@ -2876,9 +2883,9 @@ class DriftClient {
2876
2883
  oraclePriceOffset: newOraclePriceOffset || null,
2877
2884
  triggerPrice: newTriggerPrice || null,
2878
2885
  triggerCondition: newTriggerCondition || null,
2879
- auctionDuration: auctionDuration || 0,
2880
- auctionStartPrice: auctionStartPrice || numericConstants_1.ZERO,
2881
- auctionEndPrice: auctionEndPrice || numericConstants_1.ZERO,
2886
+ auctionDuration: auctionDuration || null,
2887
+ auctionStartPrice: auctionStartPrice || null,
2888
+ auctionEndPrice: auctionEndPrice || null,
2882
2889
  reduceOnly: reduceOnly != undefined ? reduceOnly : null,
2883
2890
  postOnly: postOnly != undefined ? postOnly : null,
2884
2891
  immediateOrCancel: immediateOrCancel != undefined ? immediateOrCancel : null,
@@ -3658,9 +3665,21 @@ class DriftClient {
3658
3665
  forceVersionedTransaction,
3659
3666
  });
3660
3667
  }
3661
- async buildAndSignBulkTransactions(instructions, keys, txParams, txVersion, lookupTables, forceVersionedTransaction) {
3668
+ async buildTransactionsMap(instructionsMap, txParams, txVersion, lookupTables, forceVersionedTransaction) {
3669
+ return this.txHandler.buildTransactionsMap({
3670
+ instructionsMap,
3671
+ txVersion: txVersion !== null && txVersion !== void 0 ? txVersion : this.txVersion,
3672
+ txParams: txParams !== null && txParams !== void 0 ? txParams : this.txParams,
3673
+ connection: this.connection,
3674
+ preFlightCommitment: this.opts.preflightCommitment,
3675
+ fetchMarketLookupTableAccount: this.fetchMarketLookupTableAccount.bind(this),
3676
+ lookupTables,
3677
+ forceVersionedTransaction,
3678
+ });
3679
+ }
3680
+ async buildAndSignTransactionsMap(instructionsMap, txParams, txVersion, lookupTables, forceVersionedTransaction) {
3662
3681
  return this.txHandler.buildAndSignTransactionMap({
3663
- instructions,
3682
+ instructionsMap,
3664
3683
  txVersion: txVersion !== null && txVersion !== void 0 ? txVersion : this.txVersion,
3665
3684
  txParams: txParams !== null && txParams !== void 0 ? txParams : this.txParams,
3666
3685
  connection: this.connection,
@@ -3668,7 +3687,6 @@ class DriftClient {
3668
3687
  fetchMarketLookupTableAccount: this.fetchMarketLookupTableAccount.bind(this),
3669
3688
  lookupTables,
3670
3689
  forceVersionedTransaction,
3671
- keys,
3672
3690
  });
3673
3691
  }
3674
3692
  }
@@ -8,19 +8,32 @@ const quoteAssetOracleClient_1 = require("../oracles/quoteAssetOracleClient");
8
8
  const anchor_1 = require("@coral-xyz/anchor");
9
9
  const prelaunchOracleClient_1 = require("../oracles/prelaunchOracleClient");
10
10
  const switchboardClient_1 = require("../oracles/switchboardClient");
11
+ const pythPullClient_1 = require("../oracles/pythPullClient");
11
12
  function getOracleClient(oracleSource, connection, program) {
12
13
  if ((0, types_1.isVariant)(oracleSource, 'pyth')) {
13
14
  return new pythClient_1.PythClient(connection);
14
15
  }
16
+ if ((0, types_1.isVariant)(oracleSource, 'pythPull')) {
17
+ return new pythPullClient_1.PythPullClient(connection);
18
+ }
15
19
  if ((0, types_1.isVariant)(oracleSource, 'pyth1K')) {
16
20
  return new pythClient_1.PythClient(connection, new anchor_1.BN(1000));
17
21
  }
22
+ if ((0, types_1.isVariant)(oracleSource, 'pyth1KPull')) {
23
+ return new pythPullClient_1.PythPullClient(connection, new anchor_1.BN(1000));
24
+ }
18
25
  if ((0, types_1.isVariant)(oracleSource, 'pyth1M')) {
19
26
  return new pythClient_1.PythClient(connection, new anchor_1.BN(1000000));
20
27
  }
28
+ if ((0, types_1.isVariant)(oracleSource, 'pyth1MPull')) {
29
+ return new pythPullClient_1.PythPullClient(connection, new anchor_1.BN(1000000));
30
+ }
21
31
  if ((0, types_1.isVariant)(oracleSource, 'pythStableCoin')) {
22
32
  return new pythClient_1.PythClient(connection, undefined, true);
23
33
  }
34
+ if ((0, types_1.isVariant)(oracleSource, 'pythStableCoinPull')) {
35
+ return new pythPullClient_1.PythPullClient(connection, undefined, true);
36
+ }
24
37
  if ((0, types_1.isVariant)(oracleSource, 'switchboard')) {
25
38
  return new switchboardClient_1.SwitchboardClient(connection);
26
39
  }
@@ -9254,6 +9254,18 @@
9254
9254
  },
9255
9255
  {
9256
9256
  "name": "Prelaunch"
9257
+ },
9258
+ {
9259
+ "name": "PythPull"
9260
+ },
9261
+ {
9262
+ "name": "Pyth1KPull"
9263
+ },
9264
+ {
9265
+ "name": "Pyth1MPull"
9266
+ },
9267
+ {
9268
+ "name": "PythStableCoinPull"
9257
9269
  }
9258
9270
  ]
9259
9271
  }
@@ -11992,6 +12004,11 @@
11992
12004
  "code": 6266,
11993
12005
  "name": "OracleStaleForAMM",
11994
12006
  "msg": "OracleStaleForAMM"
12007
+ },
12008
+ {
12009
+ "code": 6267,
12010
+ "name": "UnableToParsePullOracleMessage",
12011
+ "msg": "Unable to parse pull oracle message"
11995
12012
  }
11996
12013
  ]
11997
12014
  }
@@ -0,0 +1,18 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="bn.js" />
3
+ import { Connection, PublicKey } from '@solana/web3.js';
4
+ import { OracleClient, OraclePriceData } from './types';
5
+ import { BN, Program } from '@coral-xyz/anchor';
6
+ import { PythSolanaReceiverProgram } from '@pythnetwork/pyth-solana-receiver';
7
+ import { PriceUpdateAccount } from '@pythnetwork/pyth-solana-receiver/lib/PythSolanaReceiver';
8
+ export declare class PythPullClient implements OracleClient {
9
+ private connection;
10
+ private multiple;
11
+ private stableCoin;
12
+ readonly receiver: Program<PythSolanaReceiverProgram>;
13
+ readonly decodeFunc: (name: string, data: Buffer) => PriceUpdateAccount;
14
+ constructor(connection: Connection, multiple?: BN, stableCoin?: boolean);
15
+ getOraclePriceData(pricePublicKey: PublicKey): Promise<OraclePriceData>;
16
+ getOraclePriceDataFromBuffer(buffer: Buffer): OraclePriceData;
17
+ }
18
+ export declare function convertPythPrice(price: BN, exponent: number, multiple: BN): BN;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.convertPythPrice = exports.PythPullClient = void 0;
4
+ const web3_js_1 = require("@solana/web3.js");
5
+ const anchor_1 = require("@coral-xyz/anchor");
6
+ const numericConstants_1 = require("../constants/numericConstants");
7
+ const pyth_solana_receiver_1 = require("@pythnetwork/pyth-solana-receiver");
8
+ const __1 = require("..");
9
+ class PythPullClient {
10
+ constructor(connection, multiple = numericConstants_1.ONE, stableCoin = false) {
11
+ this.connection = connection;
12
+ this.multiple = multiple;
13
+ this.stableCoin = stableCoin;
14
+ const provider = new anchor_1.AnchorProvider(this.connection,
15
+ //@ts-ignore
16
+ new __1.Wallet(new web3_js_1.Keypair()), {
17
+ commitment: connection.commitment,
18
+ });
19
+ this.receiver = new anchor_1.Program(pyth_solana_receiver_1.pythSolanaReceiverIdl, pyth_solana_receiver_1.DEFAULT_RECEIVER_PROGRAM_ID, provider);
20
+ this.decodeFunc =
21
+ this.receiver.account.priceUpdateV2.coder.accounts.decodeUnchecked.bind(this.receiver.account.priceUpdateV2.coder.accounts);
22
+ }
23
+ async getOraclePriceData(pricePublicKey) {
24
+ const accountInfo = await this.connection.getAccountInfo(pricePublicKey);
25
+ return this.getOraclePriceDataFromBuffer(accountInfo.data);
26
+ }
27
+ getOraclePriceDataFromBuffer(buffer) {
28
+ const message = this.decodeFunc('priceUpdateV2', buffer);
29
+ const priceData = message.priceMessage;
30
+ const confidence = convertPythPrice(priceData.conf, priceData.exponent, this.multiple);
31
+ let price = convertPythPrice(priceData.price, priceData.exponent, this.multiple);
32
+ if (this.stableCoin) {
33
+ price = getStableCoinPrice(price, confidence);
34
+ }
35
+ return {
36
+ price,
37
+ slot: message.postedSlot,
38
+ confidence,
39
+ twap: convertPythPrice(priceData.price, priceData.exponent, this.multiple),
40
+ twapConfidence: convertPythPrice(priceData.price, priceData.exponent, this.multiple),
41
+ hasSufficientNumberOfDataPoints: true,
42
+ };
43
+ }
44
+ }
45
+ exports.PythPullClient = PythPullClient;
46
+ function convertPythPrice(price, exponent, multiple) {
47
+ exponent = Math.abs(exponent);
48
+ const pythPrecision = numericConstants_1.TEN.pow(new anchor_1.BN(exponent).abs()).div(multiple);
49
+ return price.mul(numericConstants_1.PRICE_PRECISION).div(pythPrecision);
50
+ }
51
+ exports.convertPythPrice = convertPythPrice;
52
+ const fiveBPS = new anchor_1.BN(500);
53
+ function getStableCoinPrice(price, confidence) {
54
+ if (price.sub(numericConstants_1.QUOTE_PRECISION).abs().lt(anchor_1.BN.min(confidence, fiveBPS))) {
55
+ return numericConstants_1.QUOTE_PRECISION;
56
+ }
57
+ else {
58
+ return price;
59
+ }
60
+ }
@@ -1,5 +1,5 @@
1
1
  import { AddressLookupTableAccount, BlockhashWithExpiryBlockHeight, Commitment, ConfirmOptions, Connection, Signer, Transaction, TransactionInstruction, TransactionVersion, VersionedTransaction } from '@solana/web3.js';
2
- import { DriftClientMetricsEvents, IWallet, TxParams } from '../types';
2
+ import { DriftClientMetricsEvents, IWallet, MappedRecord, SignedTxData, TxParams } from '../types';
3
3
  export declare const COMPUTE_UNITS_DEFAULT = 200000;
4
4
  export type TxBuildingProps = {
5
5
  instructions: TransactionInstruction | TransactionInstruction[];
@@ -61,6 +61,7 @@ export declare class TxHandler {
61
61
  */
62
62
  prepareTx(tx: Transaction, additionalSigners: Array<Signer>, wallet?: IWallet, confirmationOpts?: ConfirmOptions, preSigned?: boolean, recentBlockhash?: BlockhashWithExpiryBlockHeight): Promise<Transaction>;
63
63
  private isVersionedTransaction;
64
+ private isLegacyTransaction;
64
65
  private getTxSigFromSignedTx;
65
66
  private getBlockhashFromSignedTx;
66
67
  private signTx;
@@ -75,7 +76,7 @@ export declare class TxHandler {
75
76
  private _generateVersionedTransaction;
76
77
  generateLegacyVersionedTransaction(recentBlockhash: BlockhashWithExpiryBlockHeight, ixs: TransactionInstruction[], wallet?: IWallet): VersionedTransaction;
77
78
  generateVersionedTransaction(recentBlockhash: BlockhashWithExpiryBlockHeight, ixs: TransactionInstruction[], lookupTableAccounts: AddressLookupTableAccount[], wallet?: IWallet): VersionedTransaction;
78
- generateLegacyTransaction(ixs: TransactionInstruction[]): Transaction;
79
+ generateLegacyTransaction(ixs: TransactionInstruction[], recentBlockhash?: BlockhashWithExpiryBlockHeight): Transaction;
79
80
  /**
80
81
  * Accepts multiple instructions and builds a transaction for each. Prevents needing to spam RPC with requests for the same blockhash.
81
82
  * @param props
@@ -96,46 +97,48 @@ export declare class TxHandler {
96
97
  buildTransaction(props: TxBuildingProps): Promise<Transaction | VersionedTransaction>;
97
98
  wrapInTx(instruction: TransactionInstruction, computeUnits?: number, computeUnitsPrice?: number): Transaction;
98
99
  /**
99
- * Build a map of transactions from an array of instructions for multiple transactions.
100
+ * Get a map of signed and prepared transactions from an array of legacy transactions
100
101
  * @param txsToSign
101
102
  * @param keys
102
103
  * @param wallet
103
104
  * @param commitment
104
105
  * @returns
105
106
  */
106
- buildTransactionMap(txsToSign: (Transaction | undefined)[], keys: string[], wallet?: IWallet, commitment?: Commitment, recentBlockhash?: BlockhashWithExpiryBlockHeight): Promise<{
107
- [key: string]: Transaction | VersionedTransaction;
107
+ getPreparedAndSignedLegacyTransactionMap<T extends Record<string, Transaction | undefined>>(txsMap: T, wallet?: IWallet, commitment?: Commitment, recentBlockhash?: BlockhashWithExpiryBlockHeight): Promise<{
108
+ signedTxMap: T;
109
+ signedTxData: SignedTxData[];
108
110
  }>;
109
111
  /**
110
- * Get a map of signed and prepared transactions from an array of legacy transactions
112
+ * Get a map of signed transactions from an array of transactions to sign.
111
113
  * @param txsToSign
112
114
  * @param keys
113
115
  * @param wallet
114
- * @param commitment
115
116
  * @returns
116
117
  */
117
- getPreparedAndSignedLegacyTransactionMap(txsToSign: (Transaction | undefined)[], keys: string[], wallet?: IWallet, commitment?: Commitment, recentBlockhash?: BlockhashWithExpiryBlockHeight): Promise<{
118
- [key: string]: Transaction | VersionedTransaction;
118
+ getSignedTransactionMap<T extends Record<string, Transaction | VersionedTransaction | undefined>>(txsToSignMap: T, wallet?: IWallet): Promise<{
119
+ signedTxMap: T;
120
+ signedTxData: SignedTxData[];
119
121
  }>;
120
122
  /**
121
- * Get a map of signed transactions from an array of transactions to sign.
122
- * @param txsToSign
123
- * @param keys
124
- * @param wallet
123
+ * Accepts multiple instructions and builds a transaction for each. Prevents needing to spam RPC with requests for the same blockhash.
124
+ * @param props
125
125
  * @returns
126
126
  */
127
- getSignedTransactionMap(txsToSign: (Transaction | VersionedTransaction | undefined)[], keys: string[], wallet?: IWallet): Promise<{
128
- [key: string]: Transaction | VersionedTransaction | undefined;
129
- }>;
127
+ buildTransactionsMap<T extends Record<string, TransactionInstruction | TransactionInstruction[]>>(props: Omit<TxBuildingProps, 'instructions'> & {
128
+ instructionsMap: T;
129
+ }): Promise<MappedRecord<T, Transaction | VersionedTransaction>>;
130
130
  /**
131
131
  * Builds and signs transactions from a given array of instructions for multiple transactions.
132
132
  * @param props
133
133
  * @returns
134
134
  */
135
- buildAndSignTransactionMap(props: Omit<TxBuildingProps, 'instructions'> & {
136
- keys: string[];
137
- instructions: (TransactionInstruction | TransactionInstruction[])[];
135
+ buildAndSignTransactionMap<T extends Record<string, TransactionInstruction | TransactionInstruction[]>>(props: Omit<TxBuildingProps, 'instructions'> & {
136
+ instructionsMap: T;
138
137
  }): Promise<{
139
- [key: string]: Transaction | VersionedTransaction;
138
+ signedTxMap: Record<string, Transaction>;
139
+ signedTxData: SignedTxData[];
140
+ } | {
141
+ signedTxMap: MappedRecord<T, Transaction | VersionedTransaction>;
142
+ signedTxData: SignedTxData[];
140
143
  }>;
141
144
  }