@drift-labs/sdk 2.83.0-beta.9 → 2.84.0-beta.1

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.83.0-beta.9
1
+ 2.84.0-beta.1
package/bun.lockb CHANGED
Binary file
@@ -7,10 +7,10 @@ export declare class AdminClient extends DriftClient {
7
7
  initialize(usdcMint: PublicKey, _adminControlsPrices: boolean): Promise<[TransactionSignature]>;
8
8
  initializeSpotMarket(mint: PublicKey, optimalUtilization: number, optimalRate: number, maxRate: number, oracle: PublicKey, oracleSource: OracleSource, initialAssetWeight: number, maintenanceAssetWeight: number, initialLiabilityWeight: number, maintenanceLiabilityWeight: number, imfFactor?: number, liquidatorFee?: number, ifLiquidationFee?: number, activeStatus?: boolean, assetTier?: {
9
9
  collateral: {};
10
- }, scaleInitialAssetWeightStart?: BN, withdrawGuardThreshold?: BN, orderTickSize?: BN, orderStepSize?: BN, ifTotalFactor?: number, name?: string): Promise<TransactionSignature>;
10
+ }, scaleInitialAssetWeightStart?: BN, withdrawGuardThreshold?: BN, orderTickSize?: BN, orderStepSize?: BN, ifTotalFactor?: number, name?: string, marketIndex?: number): Promise<TransactionSignature>;
11
11
  getInitializeSpotMarketIx(mint: PublicKey, optimalUtilization: number, optimalRate: number, maxRate: number, oracle: PublicKey, oracleSource: OracleSource, initialAssetWeight: number, maintenanceAssetWeight: number, initialLiabilityWeight: number, maintenanceLiabilityWeight: number, imfFactor?: number, liquidatorFee?: number, ifLiquidationFee?: number, activeStatus?: boolean, assetTier?: {
12
12
  collateral: {};
13
- }, scaleInitialAssetWeightStart?: BN, withdrawGuardThreshold?: BN, orderTickSize?: BN, orderStepSize?: BN, ifTotalFactor?: number, name?: string): Promise<TransactionInstruction>;
13
+ }, scaleInitialAssetWeightStart?: BN, withdrawGuardThreshold?: BN, orderTickSize?: BN, orderStepSize?: BN, ifTotalFactor?: number, name?: string, marketIndex?: number): Promise<TransactionInstruction>;
14
14
  deleteInitializedSpotMarket(marketIndex: number): Promise<TransactionSignature>;
15
15
  getDeleteInitializedSpotMarketIx(marketIndex: number): Promise<TransactionInstruction>;
16
16
  initializeSerumFulfillmentConfig(marketIndex: number, serumMarket: PublicKey, serumProgram: PublicKey): Promise<TransactionSignature>;
@@ -61,12 +61,11 @@ class AdminClient extends driftClient_1.DriftClient {
61
61
  const { txSig } = await super.sendTransaction(tx, [], this.opts);
62
62
  return [txSig];
63
63
  }
64
- async initializeSpotMarket(mint, optimalUtilization, optimalRate, maxRate, oracle, oracleSource, initialAssetWeight, maintenanceAssetWeight, initialLiabilityWeight, maintenanceLiabilityWeight, imfFactor = 0, liquidatorFee = 0, ifLiquidationFee = 0, activeStatus = true, assetTier = types_1.AssetTier.COLLATERAL, scaleInitialAssetWeightStart = numericConstants_1.ZERO, withdrawGuardThreshold = numericConstants_1.ZERO, orderTickSize = numericConstants_1.ONE, orderStepSize = numericConstants_1.ONE, ifTotalFactor = 0, name = userName_1.DEFAULT_MARKET_NAME) {
65
- const spotMarketIndex = this.getStateAccount().numberOfSpotMarkets;
66
- const initializeIx = await this.getInitializeSpotMarketIx(mint, optimalUtilization, optimalRate, maxRate, oracle, oracleSource, initialAssetWeight, maintenanceAssetWeight, initialLiabilityWeight, maintenanceLiabilityWeight, imfFactor, liquidatorFee, ifLiquidationFee, activeStatus, assetTier, scaleInitialAssetWeightStart, withdrawGuardThreshold, orderTickSize, orderStepSize, ifTotalFactor, name);
64
+ async initializeSpotMarket(mint, optimalUtilization, optimalRate, maxRate, oracle, oracleSource, initialAssetWeight, maintenanceAssetWeight, initialLiabilityWeight, maintenanceLiabilityWeight, imfFactor = 0, liquidatorFee = 0, ifLiquidationFee = 0, activeStatus = true, assetTier = types_1.AssetTier.COLLATERAL, scaleInitialAssetWeightStart = numericConstants_1.ZERO, withdrawGuardThreshold = numericConstants_1.ZERO, orderTickSize = numericConstants_1.ONE, orderStepSize = numericConstants_1.ONE, ifTotalFactor = 0, name = userName_1.DEFAULT_MARKET_NAME, marketIndex) {
65
+ const spotMarketIndex = marketIndex !== null && marketIndex !== void 0 ? marketIndex : this.getStateAccount().numberOfSpotMarkets;
66
+ const initializeIx = await this.getInitializeSpotMarketIx(mint, optimalUtilization, optimalRate, maxRate, oracle, oracleSource, initialAssetWeight, maintenanceAssetWeight, initialLiabilityWeight, maintenanceLiabilityWeight, imfFactor, liquidatorFee, ifLiquidationFee, activeStatus, assetTier, scaleInitialAssetWeightStart, withdrawGuardThreshold, orderTickSize, orderStepSize, ifTotalFactor, name, marketIndex);
67
67
  const tx = await this.buildTransaction(initializeIx);
68
68
  const { txSig } = await this.sendTransaction(tx, [], this.opts);
69
- // const { txSig } = await this.sendTransaction(initializeTx, [], this.opts);
70
69
  await this.accountSubscriber.addSpotMarket(spotMarketIndex);
71
70
  await this.accountSubscriber.addOracle({
72
71
  source: oracleSource,
@@ -75,8 +74,8 @@ class AdminClient extends driftClient_1.DriftClient {
75
74
  await this.accountSubscriber.setSpotOracleMap();
76
75
  return txSig;
77
76
  }
78
- async getInitializeSpotMarketIx(mint, optimalUtilization, optimalRate, maxRate, oracle, oracleSource, initialAssetWeight, maintenanceAssetWeight, initialLiabilityWeight, maintenanceLiabilityWeight, imfFactor = 0, liquidatorFee = 0, ifLiquidationFee = 0, activeStatus = true, assetTier = types_1.AssetTier.COLLATERAL, scaleInitialAssetWeightStart = numericConstants_1.ZERO, withdrawGuardThreshold = numericConstants_1.ZERO, orderTickSize = numericConstants_1.ONE, orderStepSize = numericConstants_1.ONE, ifTotalFactor = 0, name = userName_1.DEFAULT_MARKET_NAME) {
79
- const spotMarketIndex = this.getStateAccount().numberOfSpotMarkets;
77
+ async getInitializeSpotMarketIx(mint, optimalUtilization, optimalRate, maxRate, oracle, oracleSource, initialAssetWeight, maintenanceAssetWeight, initialLiabilityWeight, maintenanceLiabilityWeight, imfFactor = 0, liquidatorFee = 0, ifLiquidationFee = 0, activeStatus = true, assetTier = types_1.AssetTier.COLLATERAL, scaleInitialAssetWeightStart = numericConstants_1.ZERO, withdrawGuardThreshold = numericConstants_1.ZERO, orderTickSize = numericConstants_1.ONE, orderStepSize = numericConstants_1.ONE, ifTotalFactor = 0, name = userName_1.DEFAULT_MARKET_NAME, marketIndex) {
78
+ const spotMarketIndex = marketIndex !== null && marketIndex !== void 0 ? marketIndex : this.getStateAccount().numberOfSpotMarkets;
80
79
  const spotMarket = await (0, pda_1.getSpotMarketPublicKey)(this.program.programId, spotMarketIndex);
81
80
  const spotMarketVault = await (0, pda_1.getSpotMarketVaultPublicKey)(this.program.programId, spotMarketIndex);
82
81
  const insuranceFundVault = await (0, pda_1.getInsuranceFundVaultPublicKey)(this.program.programId, spotMarketIndex);
@@ -184,7 +183,7 @@ class AdminClient extends driftClient_1.DriftClient {
184
183
  while (this.getStateAccount().numberOfMarkets <= currentPerpMarketIndex) {
185
184
  await this.fetchAccounts();
186
185
  }
187
- await this.accountSubscriber.addPerpMarket(currentPerpMarketIndex);
186
+ await this.accountSubscriber.addPerpMarket(marketIndex);
188
187
  await this.accountSubscriber.addOracle({
189
188
  source: oracleSource,
190
189
  publicKey: priceOracle,
@@ -193,8 +192,7 @@ class AdminClient extends driftClient_1.DriftClient {
193
192
  return txSig;
194
193
  }
195
194
  async getInitializePerpMarketIx(marketIndex, priceOracle, baseAssetReserve, quoteAssetReserve, periodicity, pegMultiplier = numericConstants_1.PEG_PRECISION, oracleSource = types_1.OracleSource.PYTH, contractTier = types_1.ContractTier.SPECULATIVE, marginRatioInitial = 2000, marginRatioMaintenance = 500, liquidatorFee = 0, ifLiquidatorFee = 10000, imfFactor = 0, activeStatus = true, baseSpread = 0, maxSpread = 142500, maxOpenInterest = numericConstants_1.ZERO, maxRevenueWithdrawPerPeriod = numericConstants_1.ZERO, quoteMaxInsurance = numericConstants_1.ZERO, orderStepSize = numericConstants_1.BASE_PRECISION.divn(10000), orderTickSize = numericConstants_1.PRICE_PRECISION.divn(100000), minOrderSize = numericConstants_1.BASE_PRECISION.divn(10000), concentrationCoefScale = numericConstants_1.ONE, curveUpdateIntensity = 0, ammJitIntensity = 0, name = userName_1.DEFAULT_MARKET_NAME) {
196
- const currentPerpMarketIndex = this.getStateAccount().numberOfMarkets;
197
- const perpMarketPublicKey = await (0, pda_1.getPerpMarketPublicKey)(this.program.programId, currentPerpMarketIndex);
195
+ const perpMarketPublicKey = await (0, pda_1.getPerpMarketPublicKey)(this.program.programId, marketIndex);
198
196
  const nameBuffer = (0, userName_1.encodeName)(name);
199
197
  return await this.program.instruction.initializePerpMarket(marketIndex, baseAssetReserve, quoteAssetReserve, periodicity, pegMultiplier, oracleSource, contractTier, marginRatioInitial, marginRatioMaintenance, liquidatorFee, ifLiquidatorFee, imfFactor, activeStatus, baseSpread, maxSpread, maxOpenInterest, maxRevenueWithdrawPerPeriod, quoteMaxInsurance, orderStepSize, orderTickSize, minOrderSize, concentrationCoefScale, curveUpdateIntensity, ammJitIntensity, nameBuffer, {
200
198
  accounts: {
@@ -566,6 +566,26 @@ exports.MainnetPerpMarkets = [
566
566
  launchTs: 1716595200000,
567
567
  oracleSource: __1.OracleSource.SWITCHBOARD,
568
568
  },
569
+ {
570
+ fullName: 'Sanctum',
571
+ category: ['LST', 'Solana'],
572
+ symbol: 'CLOUD-PERP',
573
+ baseAssetSymbol: 'CLOUD',
574
+ marketIndex: 31,
575
+ oracle: new web3_js_1.PublicKey('C7UxgCodaEy4yqwTe3a4QXfsG7LnpMGGQdEqaxDae4b8'),
576
+ launchTs: 1717597648000,
577
+ oracleSource: __1.OracleSource.Prelaunch,
578
+ },
579
+ {
580
+ fullName: 'IO',
581
+ category: ['DePIN', 'Solana'],
582
+ symbol: 'IO-PERP',
583
+ baseAssetSymbol: 'IO',
584
+ marketIndex: 32,
585
+ oracle: new web3_js_1.PublicKey('5sAqMGidMtztNFdUukyguz6jMFS8DvTmSUr4p5u5zsSg'),
586
+ launchTs: 1718021389000,
587
+ oracleSource: __1.OracleSource.Prelaunch,
588
+ },
569
589
  ];
570
590
  exports.PerpMarkets = {
571
591
  devnet: exports.DevnetPerpMarkets,
@@ -31,7 +31,7 @@ type OrderBookCallback = () => void;
31
31
  * Receives a DLOBNode and is expected to return true if the node should
32
32
  * be taken into account when generating, or false otherwise.
33
33
  *
34
- * Currently used in getRestingLimitBids and getRestingLimitAsks.
34
+ * Currently used in functions that rely on getBestNode
35
35
  */
36
36
  export type DLOBFilterFcn = (node: DLOBNode) => boolean;
37
37
  export type NodeToFill = {
@@ -79,13 +79,13 @@ export declare class DLOB {
79
79
  findNodesCrossingFallbackLiquidity(marketType: MarketType, slot: number, oraclePriceData: OraclePriceData, nodeGenerator: Generator<DLOBNode>, doesCross: (nodePrice: BN | undefined) => boolean, minAuctionDuration: number): NodeToFill[];
80
80
  findExpiredNodesToFill(marketIndex: number, ts: number, marketType: MarketType): NodeToFill[];
81
81
  findJitAuctionNodesToFill(marketIndex: number, slot: number, oraclePriceData: OraclePriceData, marketType: MarketType): NodeToFill[];
82
- getTakingBids(marketIndex: number, marketType: MarketType, slot: number, oraclePriceData: OraclePriceData): Generator<DLOBNode>;
83
- getTakingAsks(marketIndex: number, marketType: MarketType, slot: number, oraclePriceData: OraclePriceData): Generator<DLOBNode>;
82
+ getTakingBids(marketIndex: number, marketType: MarketType, slot: number, oraclePriceData: OraclePriceData, filterFcn?: DLOBFilterFcn): Generator<DLOBNode>;
83
+ getTakingAsks(marketIndex: number, marketType: MarketType, slot: number, oraclePriceData: OraclePriceData, filterFcn?: DLOBFilterFcn): Generator<DLOBNode>;
84
84
  private getBestNode;
85
85
  getRestingLimitAsks(marketIndex: number, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData, filterFcn?: DLOBFilterFcn): Generator<DLOBNode>;
86
86
  getRestingLimitBids(marketIndex: number, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData, filterFcn?: DLOBFilterFcn): Generator<DLOBNode>;
87
- getAsks(marketIndex: number, fallbackAsk: BN | undefined, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData): Generator<DLOBNode>;
88
- getBids(marketIndex: number, fallbackBid: BN | undefined, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData): Generator<DLOBNode>;
87
+ getAsks(marketIndex: number, fallbackAsk: BN | undefined, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData, filterFcn?: DLOBFilterFcn): Generator<DLOBNode>;
88
+ getBids(marketIndex: number, fallbackBid: BN | undefined, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData, filterFcn?: DLOBFilterFcn): Generator<DLOBNode>;
89
89
  findCrossingRestingLimitOrders(marketIndex: number, slot: number, marketType: MarketType, oraclePriceData: OraclePriceData): NodeToFill[];
90
90
  determineMakerAndTaker(askNode: DLOBNode, bidNode: DLOBNode): {
91
91
  takerNode: DLOBNode;
package/lib/dlob/DLOB.js CHANGED
@@ -565,7 +565,7 @@ class DLOB {
565
565
  }
566
566
  return nodesToFill;
567
567
  }
568
- *getTakingBids(marketIndex, marketType, slot, oraclePriceData) {
568
+ *getTakingBids(marketIndex, marketType, slot, oraclePriceData, filterFcn) {
569
569
  const marketTypeStr = (0, __1.getVariant)(marketType);
570
570
  const orderLists = this.orderLists.get(marketTypeStr).get(marketIndex);
571
571
  if (!orderLists) {
@@ -578,9 +578,9 @@ class DLOB {
578
578
  ];
579
579
  yield* this.getBestNode(generatorList, oraclePriceData, slot, (bestNode, currentNode) => {
580
580
  return bestNode.order.slot.lt(currentNode.order.slot);
581
- });
581
+ }, filterFcn);
582
582
  }
583
- *getTakingAsks(marketIndex, marketType, slot, oraclePriceData) {
583
+ *getTakingAsks(marketIndex, marketType, slot, oraclePriceData, filterFcn) {
584
584
  const marketTypeStr = (0, __1.getVariant)(marketType);
585
585
  const orderLists = this.orderLists.get(marketTypeStr).get(marketIndex);
586
586
  if (!orderLists) {
@@ -593,7 +593,7 @@ class DLOB {
593
593
  ];
594
594
  yield* this.getBestNode(generatorList, oraclePriceData, slot, (bestNode, currentNode) => {
595
595
  return bestNode.order.slot.lt(currentNode.order.slot);
596
- });
596
+ }, filterFcn);
597
597
  }
598
598
  *getBestNode(generatorList, oraclePriceData, slot, compareFcn, filterFcn) {
599
599
  const generators = generatorList.map((generator) => {
@@ -675,7 +675,7 @@ class DLOB {
675
675
  .gt(currentNode.getPrice(oraclePriceData, slot));
676
676
  }, filterFcn);
677
677
  }
678
- *getAsks(marketIndex, fallbackAsk, slot, marketType, oraclePriceData) {
678
+ *getAsks(marketIndex, fallbackAsk, slot, marketType, oraclePriceData, filterFcn) {
679
679
  if ((0, __1.isVariant)(marketType, 'spot') && !oraclePriceData) {
680
680
  throw new Error('Must provide OraclePriceData to get spot asks');
681
681
  }
@@ -706,9 +706,9 @@ class DLOB {
706
706
  return bestNode
707
707
  .getPrice(oraclePriceData, slot)
708
708
  .lt(currentNode.getPrice(oraclePriceData, slot));
709
- });
709
+ }, filterFcn);
710
710
  }
711
- *getBids(marketIndex, fallbackBid, slot, marketType, oraclePriceData) {
711
+ *getBids(marketIndex, fallbackBid, slot, marketType, oraclePriceData, filterFcn) {
712
712
  if ((0, __1.isVariant)(marketType, 'spot') && !oraclePriceData) {
713
713
  throw new Error('Must provide OraclePriceData to get spot bids');
714
714
  }
@@ -739,7 +739,7 @@ class DLOB {
739
739
  return bestNode
740
740
  .getPrice(oraclePriceData, slot)
741
741
  .gt(currentNode.getPrice(oraclePriceData, slot));
742
- });
742
+ }, filterFcn);
743
743
  }
744
744
  findCrossingRestingLimitOrders(marketIndex, slot, marketType, oraclePriceData) {
745
745
  const nodesToFill = new Array();
@@ -593,7 +593,7 @@ export declare class DriftClient {
593
593
  settleeUserAccount: UserAccount;
594
594
  }[], marketIndexes: number[], opts?: {
595
595
  filterInvalidMarkets?: boolean;
596
- }): Promise<TransactionSignature>;
596
+ }, txParams?: TxParams): Promise<TransactionSignature>;
597
597
  getSettlePNLsIxs(users: {
598
598
  settleeUserAccountPublicKey: PublicKey;
599
599
  settleeUserAccount: UserAccount;
@@ -685,7 +685,7 @@ export declare class DriftClient {
685
685
  private handlePreSignedTransaction;
686
686
  private isVersionedTransaction;
687
687
  sendTransaction(tx: Transaction | VersionedTransaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions, preSigned?: boolean): Promise<TxSigAndSlot>;
688
- buildTransaction(instructions: TransactionInstruction | TransactionInstruction[], txParams?: TxParams, txVersion?: TransactionVersion, lookupTables?: AddressLookupTableAccount[], forceVersionedTransaction?: boolean, recentBlockHash?: BlockhashWithExpiryBlockHeight): Promise<Transaction | VersionedTransaction>;
688
+ buildTransaction(instructions: TransactionInstruction | TransactionInstruction[], txParams?: TxParams, txVersion?: TransactionVersion, lookupTables?: AddressLookupTableAccount[], forceVersionedTransaction?: boolean, recentBlockhash?: BlockhashWithExpiryBlockHeight): Promise<Transaction | VersionedTransaction>;
689
689
  buildBulkTransactions(instructions: (TransactionInstruction | TransactionInstruction[])[], txParams?: TxParams, txVersion?: TransactionVersion, lookupTables?: AddressLookupTableAccount[], forceVersionedTransaction?: boolean): Promise<(Transaction | VersionedTransaction)[]>;
690
690
  buildAndSignBulkTransactions(instructions: (TransactionInstruction | TransactionInstruction[])[], keys: string[], txParams?: TxParams, txVersion?: TransactionVersion, lookupTables?: AddressLookupTableAccount[], forceVersionedTransaction?: boolean): Promise<{
691
691
  [key: string]: anchor.web3.Transaction | anchor.web3.VersionedTransaction;
@@ -2949,7 +2949,7 @@ class DriftClient {
2949
2949
  remainingAccounts,
2950
2950
  });
2951
2951
  }
2952
- async settlePNLs(users, marketIndexes, opts) {
2952
+ async settlePNLs(users, marketIndexes, opts, txParams) {
2953
2953
  const filterInvalidMarkets = opts === null || opts === void 0 ? void 0 : opts.filterInvalidMarkets;
2954
2954
  // # Filter market indexes by markets with valid oracle
2955
2955
  const marketIndexToSettle = filterInvalidMarkets
@@ -2969,7 +2969,7 @@ class DriftClient {
2969
2969
  }
2970
2970
  // # Settle filtered market indexes
2971
2971
  const ixs = await this.getSettlePNLsIxs(users, marketIndexToSettle);
2972
- const tx = await this.buildTransaction(ixs, {
2972
+ const tx = await this.buildTransaction(ixs, txParams !== null && txParams !== void 0 ? txParams : {
2973
2973
  computeUnits: 1400000,
2974
2974
  });
2975
2975
  const { txSig } = await this.sendTransaction(tx, [], this.opts);
@@ -3633,7 +3633,7 @@ class DriftClient {
3633
3633
  return this.txSender.send(tx, additionalSigners, opts, preSigned);
3634
3634
  }
3635
3635
  }
3636
- async buildTransaction(instructions, txParams, txVersion, lookupTables, forceVersionedTransaction, recentBlockHash) {
3636
+ async buildTransaction(instructions, txParams, txVersion, lookupTables, forceVersionedTransaction, recentBlockhash) {
3637
3637
  return this.txHandler.buildTransaction({
3638
3638
  instructions,
3639
3639
  txVersion: txVersion !== null && txVersion !== void 0 ? txVersion : this.txVersion,
@@ -3643,7 +3643,7 @@ class DriftClient {
3643
3643
  fetchMarketLookupTableAccount: this.fetchMarketLookupTableAccount.bind(this),
3644
3644
  lookupTables,
3645
3645
  forceVersionedTransaction,
3646
- recentBlockHash,
3646
+ recentBlockhash,
3647
3647
  });
3648
3648
  }
3649
3649
  async buildBulkTransactions(instructions, txParams, txVersion, lookupTables, forceVersionedTransaction) {
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.82.0",
2
+ "version": "2.83.0",
3
3
  "name": "drift",
4
4
  "instructions": [
5
5
  {
@@ -69,7 +69,7 @@ function getAuctionPriceForOracleOffsetAuction(order, slot, oraclePrice) {
69
69
  const deltaDenominator = new _1.BN(order.auctionDuration);
70
70
  const deltaNumerator = _1.BN.min(slotsElapsed, deltaDenominator);
71
71
  if (deltaDenominator.eq(_1.ZERO)) {
72
- return oraclePrice.add(order.auctionEndPrice);
72
+ return _1.BN.max(oraclePrice.add(order.auctionEndPrice), _1.ONE);
73
73
  }
74
74
  let priceOffsetDelta;
75
75
  if ((0, types_1.isVariant)(order.direction, 'long')) {
@@ -91,7 +91,7 @@ function getAuctionPriceForOracleOffsetAuction(order, slot, oraclePrice) {
91
91
  else {
92
92
  priceOffset = order.auctionStartPrice.sub(priceOffsetDelta);
93
93
  }
94
- return oraclePrice.add(priceOffset);
94
+ return _1.BN.max(oraclePrice.add(priceOffset), _1.ONE);
95
95
  }
96
96
  exports.getAuctionPriceForOracleOffsetAuction = getAuctionPriceForOracleOffsetAuction;
97
97
  function deriveOracleAuctionParams({ direction, oraclePrice, auctionStartPrice, auctionEndPrice, limitPrice, }) {
@@ -102,7 +102,7 @@ function getLimitPrice(order, oraclePriceData, slot, fallbackPrice) {
102
102
  limitPrice = (0, auction_1.getAuctionPrice)(order, slot, oraclePriceData.price);
103
103
  }
104
104
  else if (order.oraclePriceOffset !== 0) {
105
- limitPrice = oraclePriceData.price.add(new anchor_1.BN(order.oraclePriceOffset));
105
+ limitPrice = anchor_1.BN.max(oraclePriceData.price.add(new anchor_1.BN(order.oraclePriceOffset)), numericConstants_1.ONE);
106
106
  }
107
107
  else if (order.price.eq(numericConstants_1.ZERO)) {
108
108
  limitPrice = fallbackPrice;
@@ -10,7 +10,7 @@ export type TxBuildingProps = {
10
10
  lookupTables?: AddressLookupTableAccount[];
11
11
  forceVersionedTransaction?: boolean;
12
12
  txParams?: TxParams;
13
- recentBlockHash?: BlockhashWithExpiryBlockHeight;
13
+ recentBlockhash?: BlockhashWithExpiryBlockHeight;
14
14
  wallet?: IWallet;
15
15
  };
16
16
  /**
@@ -63,7 +63,7 @@ export declare class TxHandler {
63
63
  private getTxSigFromSignedTx;
64
64
  private getBlockhashFromSignedTx;
65
65
  private signTx;
66
- signVersionedTx(tx: VersionedTransaction, additionalSigners: Array<Signer>, recentBlockHash?: BlockhashWithExpiryBlockHeight, wallet?: IWallet): Promise<VersionedTransaction>;
66
+ signVersionedTx(tx: VersionedTransaction, additionalSigners: Array<Signer>, recentBlockhash?: BlockhashWithExpiryBlockHeight, wallet?: IWallet): Promise<VersionedTransaction>;
67
67
  private handleSignedTxData;
68
68
  /**
69
69
  * Gets transaction params with extra processing applied, like using the simulated compute units or using a dynamically calculated compute unit price.
@@ -102,7 +102,7 @@ export declare class TxHandler {
102
102
  * @param commitment
103
103
  * @returns
104
104
  */
105
- buildTransactionMap(txsToSign: (Transaction | undefined)[], keys: string[], wallet?: IWallet, commitment?: Commitment, recentBlockHash?: BlockhashWithExpiryBlockHeight): Promise<{
105
+ buildTransactionMap(txsToSign: (Transaction | undefined)[], keys: string[], wallet?: IWallet, commitment?: Commitment, recentBlockhash?: BlockhashWithExpiryBlockHeight): Promise<{
106
106
  [key: string]: Transaction | VersionedTransaction;
107
107
  }>;
108
108
  /**
@@ -113,7 +113,7 @@ export declare class TxHandler {
113
113
  * @param commitment
114
114
  * @returns
115
115
  */
116
- getPreparedAndSignedLegacyTransactionMap(txsToSign: (Transaction | undefined)[], keys: string[], wallet?: IWallet, commitment?: Commitment, recentBlockHash?: BlockhashWithExpiryBlockHeight): Promise<{
116
+ getPreparedAndSignedLegacyTransactionMap(txsToSign: (Transaction | undefined)[], keys: string[], wallet?: IWallet, commitment?: Commitment, recentBlockhash?: BlockhashWithExpiryBlockHeight): Promise<{
117
117
  [key: string]: Transaction | VersionedTransaction;
118
118
  }>;
119
119
  /**
@@ -8,6 +8,12 @@ const web3_js_1 = require("@solana/web3.js");
8
8
  const txParamProcessor_1 = require("./txParamProcessor");
9
9
  const bs58_1 = __importDefault(require("bs58"));
10
10
  const computeUnits_1 = require("../util/computeUnits");
11
+ /**
12
+ * Explanation for SIGNATURE_BLOCK_AND_EXPIRY:
13
+ *
14
+ * When the whileValidTxSender waits for confirmation of a given transaction, it needs the last available blockheight and blockhash used in the signature to do so. For pre-signed transactions, these values aren't attached to the transaction object by default. For a "scrappy" workaround which doesn't break backwards compatibility, the SIGNATURE_BLOCK_AND_EXPIRY property is simply attached to the transaction objects as they are created or signed in this handler despite a mismatch in the typescript types. If the values are attached to the transaction when they reach the whileValidTxSender, it can opt-in to use these values.
15
+ */
16
+ const DEV_TRY_FORCE_TX_TIMEOUTS = false;
11
17
  exports.COMPUTE_UNITS_DEFAULT = 200000;
12
18
  /**
13
19
  * This class is responsible for creating and signing transactions.
@@ -68,6 +74,8 @@ class TxHandler {
68
74
  tx.recentBlockhash = recentBlockhash.blockhash;
69
75
  this.addHashAndExpiryToLookup(recentBlockhash);
70
76
  const signedTx = await this.signTx(tx, additionalSigners);
77
+ // @ts-ignore
78
+ signedTx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
71
79
  return signedTx;
72
80
  }
73
81
  isVersionedTransaction(tx) {
@@ -110,12 +118,14 @@ class TxHandler {
110
118
  ]);
111
119
  return signedTx;
112
120
  }
113
- async signVersionedTx(tx, additionalSigners, recentBlockHash, wallet) {
121
+ async signVersionedTx(tx, additionalSigners, recentBlockhash, wallet) {
114
122
  var _a;
115
123
  [wallet] = this.getProps(wallet);
116
- if (recentBlockHash) {
117
- tx.message.recentBlockhash = recentBlockHash.blockhash;
118
- this.addHashAndExpiryToLookup(recentBlockHash);
124
+ if (recentBlockhash) {
125
+ tx.message.recentBlockhash = recentBlockhash.blockhash;
126
+ this.addHashAndExpiryToLookup(recentBlockhash);
127
+ // @ts-ignore
128
+ tx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
119
129
  }
120
130
  additionalSigners === null || additionalSigners === void 0 ? void 0 : additionalSigners.filter((s) => s !== undefined).forEach((kp) => {
121
131
  tx.sign([kp]);
@@ -186,8 +196,8 @@ class TxHandler {
186
196
  });
187
197
  return processedTxParams;
188
198
  }
189
- _generateVersionedTransaction(recentBlockHash, message) {
190
- this.addHashAndExpiryToLookup(recentBlockHash);
199
+ _generateVersionedTransaction(recentBlockhash, message) {
200
+ this.addHashAndExpiryToLookup(recentBlockhash);
191
201
  return new web3_js_1.VersionedTransaction(message);
192
202
  }
193
203
  generateLegacyVersionedTransaction(recentBlockhash, ixs, wallet) {
@@ -197,7 +207,10 @@ class TxHandler {
197
207
  recentBlockhash: recentBlockhash.blockhash,
198
208
  instructions: ixs,
199
209
  }).compileToLegacyMessage();
200
- return this._generateVersionedTransaction(recentBlockhash, message);
210
+ const tx = this._generateVersionedTransaction(recentBlockhash, message);
211
+ // @ts-ignore
212
+ tx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
213
+ return tx;
201
214
  }
202
215
  generateVersionedTransaction(recentBlockhash, ixs, lookupTableAccounts, wallet) {
203
216
  [wallet] = this.getProps(wallet);
@@ -206,7 +219,10 @@ class TxHandler {
206
219
  recentBlockhash: recentBlockhash.blockhash,
207
220
  instructions: ixs,
208
221
  }).compileToV0Message(lookupTableAccounts);
209
- return this._generateVersionedTransaction(recentBlockhash, message);
222
+ const tx = this._generateVersionedTransaction(recentBlockhash, message);
223
+ // @ts-ignore
224
+ tx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
225
+ return tx;
210
226
  }
211
227
  generateLegacyTransaction(ixs) {
212
228
  return new web3_js_1.Transaction().add(...ixs);
@@ -218,14 +234,14 @@ class TxHandler {
218
234
  */
219
235
  async buildBulkTransactions(props) {
220
236
  var _a;
221
- const recentBlockHash = (_a = props === null || props === void 0 ? void 0 : props.recentBlockHash) !== null && _a !== void 0 ? _a : (await this.getLatestBlockhashForTransaction());
237
+ const recentBlockhash = (_a = props === null || props === void 0 ? void 0 : props.recentBlockhash) !== null && _a !== void 0 ? _a : (await this.getLatestBlockhashForTransaction());
222
238
  return await Promise.all(props.instructions.map((ix) => {
223
239
  if (!ix)
224
240
  return undefined;
225
241
  return this.buildTransaction({
226
242
  ...props,
227
243
  instructions: ix,
228
- recentBlockHash,
244
+ recentBlockhash,
229
245
  });
230
246
  }));
231
247
  }
@@ -267,17 +283,22 @@ class TxHandler {
267
283
  }));
268
284
  }
269
285
  const computeUnitsPrice = baseTxParams === null || baseTxParams === void 0 ? void 0 : baseTxParams.computeUnitsPrice;
270
- if (computeUnitsPrice > 0 && !hasSetComputeUnitPriceIx) {
286
+ if (process.env.DEV_TRY_FORCE_TX_TIMEOUTS || DEV_TRY_FORCE_TX_TIMEOUTS) {
287
+ allIx.push(web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({
288
+ microLamports: 0,
289
+ }));
290
+ }
291
+ else if (computeUnitsPrice > 0 && !hasSetComputeUnitPriceIx) {
271
292
  allIx.push(web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({
272
293
  microLamports: computeUnitsPrice,
273
294
  }));
274
295
  }
275
296
  allIx.push(...instructionsArray);
276
- const recentBlockHash = (_a = props === null || props === void 0 ? void 0 : props.recentBlockHash) !== null && _a !== void 0 ? _a : (await this.getLatestBlockhashForTransaction());
297
+ const recentBlockhash = (_a = props === null || props === void 0 ? void 0 : props.recentBlockhash) !== null && _a !== void 0 ? _a : (await this.getLatestBlockhashForTransaction());
277
298
  // # Create and return Transaction
278
299
  if (txVersion === 'legacy') {
279
300
  if (forceVersionedTransaction) {
280
- return this.generateLegacyVersionedTransaction(recentBlockHash, allIx);
301
+ return this.generateLegacyVersionedTransaction(recentBlockhash, allIx);
281
302
  }
282
303
  else {
283
304
  return this.generateLegacyTransaction(allIx);
@@ -288,7 +309,7 @@ class TxHandler {
288
309
  lookupTables = lookupTables
289
310
  ? [...lookupTables, marketLookupTable]
290
311
  : [marketLookupTable];
291
- return this.generateVersionedTransaction(recentBlockHash, allIx, lookupTables);
312
+ return this.generateVersionedTransaction(recentBlockhash, allIx, lookupTables);
292
313
  }
293
314
  }
294
315
  wrapInTx(instruction, computeUnits = 600000, computeUnitsPrice = 0) {
@@ -298,7 +319,12 @@ class TxHandler {
298
319
  units: computeUnits,
299
320
  }));
300
321
  }
301
- if (computeUnitsPrice != 0) {
322
+ if (process.env.DEV_TRY_FORCE_TX_TIMEOUTS || DEV_TRY_FORCE_TX_TIMEOUTS) {
323
+ tx.add(web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({
324
+ microLamports: 0,
325
+ }));
326
+ }
327
+ else if (computeUnitsPrice != 0) {
302
328
  tx.add(web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({
303
329
  microLamports: computeUnitsPrice,
304
330
  }));
@@ -313,17 +339,19 @@ class TxHandler {
313
339
  * @param commitment
314
340
  * @returns
315
341
  */
316
- async buildTransactionMap(txsToSign, keys, wallet, commitment, recentBlockHash) {
342
+ async buildTransactionMap(txsToSign, keys, wallet, commitment, recentBlockhash) {
317
343
  var _a, _b;
318
- recentBlockHash = recentBlockHash
319
- ? recentBlockHash
344
+ recentBlockhash = recentBlockhash
345
+ ? recentBlockhash
320
346
  : await this.getLatestBlockhashForTransaction();
321
- this.addHashAndExpiryToLookup(recentBlockHash);
347
+ this.addHashAndExpiryToLookup(recentBlockhash);
322
348
  for (const tx of txsToSign) {
323
349
  if (!tx)
324
350
  continue;
325
- tx.recentBlockhash = recentBlockHash.blockhash;
351
+ tx.recentBlockhash = recentBlockhash.blockhash;
326
352
  tx.feePayer = (_a = wallet === null || wallet === void 0 ? void 0 : wallet.publicKey) !== null && _a !== void 0 ? _a : (_b = this.wallet) === null || _b === void 0 ? void 0 : _b.publicKey;
353
+ // @ts-ignore
354
+ tx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
327
355
  }
328
356
  return this.getSignedTransactionMap(txsToSign, keys, wallet);
329
357
  }
@@ -335,17 +363,19 @@ class TxHandler {
335
363
  * @param commitment
336
364
  * @returns
337
365
  */
338
- async getPreparedAndSignedLegacyTransactionMap(txsToSign, keys, wallet, commitment, recentBlockHash) {
366
+ async getPreparedAndSignedLegacyTransactionMap(txsToSign, keys, wallet, commitment, recentBlockhash) {
339
367
  var _a, _b;
340
- recentBlockHash = recentBlockHash
341
- ? recentBlockHash
368
+ recentBlockhash = recentBlockhash
369
+ ? recentBlockhash
342
370
  : await this.getLatestBlockhashForTransaction();
343
- this.addHashAndExpiryToLookup(recentBlockHash);
371
+ this.addHashAndExpiryToLookup(recentBlockhash);
344
372
  for (const tx of txsToSign) {
345
373
  if (!tx)
346
374
  continue;
347
- tx.recentBlockhash = recentBlockHash.blockhash;
375
+ tx.recentBlockhash = recentBlockhash.blockhash;
348
376
  tx.feePayer = (_a = wallet === null || wallet === void 0 ? void 0 : wallet.publicKey) !== null && _a !== void 0 ? _a : (_b = this.wallet) === null || _b === void 0 ? void 0 : _b.publicKey;
377
+ // @ts-ignore
378
+ tx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
349
379
  }
350
380
  return this.getSignedTransactionMap(txsToSign, keys, wallet);
351
381
  }
@@ -370,11 +400,19 @@ class TxHandler {
370
400
  }
371
401
  });
372
402
  (_a = this.preSignedCb) === null || _a === void 0 ? void 0 : _a.call(this);
373
- const signedTxs = await wallet.signAllTransactions(txsToSign
403
+ const filteredTxs = txsToSign
374
404
  .map((tx) => {
375
405
  return tx;
376
406
  })
377
- .filter((tx) => tx !== undefined));
407
+ .filter((tx) => tx !== undefined);
408
+ const signedTxs = await wallet.signAllTransactions(filteredTxs);
409
+ signedTxs.forEach((signedTx, index) => {
410
+ var _a;
411
+ // @ts-ignore
412
+ signedTx.SIGNATURE_BLOCK_AND_EXPIRY =
413
+ // @ts-ignore
414
+ (_a = txsToSign[index]) === null || _a === void 0 ? void 0 : _a.SIGNATURE_BLOCK_AND_EXPIRY;
415
+ });
378
416
  this.handleSignedTxData(signedTxs.map((signedTx) => {
379
417
  return {
380
418
  txSig: this.getTxSigFromSignedTx(signedTx),
@@ -394,9 +432,9 @@ class TxHandler {
394
432
  */
395
433
  async buildAndSignTransactionMap(props) {
396
434
  const transactions = await this.buildBulkTransactions(props);
397
- const preppedTransactions = props.txVersion === 'legacy'
435
+ const preppedTransactions = await (props.txVersion === 'legacy'
398
436
  ? this.getPreparedAndSignedLegacyTransactionMap(transactions, props.keys, props.wallet, props.preFlightCommitment)
399
- : this.getSignedTransactionMap(transactions, props.keys, props.wallet);
437
+ : this.getSignedTransactionMap(transactions, props.keys, props.wallet));
400
438
  return preppedTransactions;
401
439
  }
402
440
  }
@@ -8,6 +8,7 @@ const anchor_1 = require("@coral-xyz/anchor");
8
8
  const baseTxSender_1 = require("./baseTxSender");
9
9
  const bs58_1 = __importDefault(require("bs58"));
10
10
  const DEFAULT_RETRY = 2000;
11
+ const VALID_BLOCK_HEIGHT_OFFSET = -150; // This is a bit of weirdness but the lastValidBlockHeight value returned from connection.getLatestBlockhash is always 300 blocks ahead of the current block, even though the transaction actually expires after 150 blocks. This accounts for that so that we can at least accuractely estimate the transaction expiry.
11
12
  class WhileValidTxSender extends baseTxSender_1.BaseTxSender {
12
13
  constructor({ connection, wallet, opts = { ...anchor_1.AnchorProvider.defaultOptions(), maxRetries: 0 }, retrySleep = DEFAULT_RETRY, additionalConnections = new Array(), additionalTxSenderCallbacks = [], blockhashCommitment = 'finalized', txHandler, }) {
13
14
  super({
@@ -37,16 +38,28 @@ class WhileValidTxSender extends baseTxSender_1.BaseTxSender {
37
38
  if (!preSigned) {
38
39
  signedTx = await this.txHandler.prepareTx(tx, additionalSigners, undefined, opts, false, latestBlockhash);
39
40
  }
41
+ // See SIGNATURE_BLOCK_AND_EXPIRY explanation in txHandler.ts if this is confusing
42
+ // @ts-ignore
43
+ if (preSigned && tx.SIGNATURE_BLOCK_AND_EXPIRY) {
44
+ // @ts-ignore
45
+ latestBlockhash = tx.SIGNATURE_BLOCK_AND_EXPIRY;
46
+ }
40
47
  // handle subclass-specific side effects
41
48
  const txSig = bs58_1.default.encode(((_a = signedTx.signatures[0]) === null || _a === void 0 ? void 0 : _a.signature) || signedTx.signatures[0]);
42
49
  this.untilValid.set(txSig, latestBlockhash);
43
50
  return signedTx;
44
51
  }
45
52
  async sendVersionedTransaction(tx, additionalSigners, opts, preSigned) {
46
- const latestBlockhash = await this.txHandler.getLatestBlockhashForTransaction();
53
+ let latestBlockhash = await this.txHandler.getLatestBlockhashForTransaction();
47
54
  let signedTx;
48
55
  if (preSigned) {
49
56
  signedTx = tx;
57
+ // See SIGNATURE_BLOCK_AND_EXPIRY explanation in txHandler.ts if this is confusing
58
+ // @ts-ignore
59
+ if (tx.SIGNATURE_BLOCK_AND_EXPIRY) {
60
+ // @ts-ignore
61
+ latestBlockhash = tx.SIGNATURE_BLOCK_AND_EXPIRY;
62
+ }
50
63
  // @ts-ignore
51
64
  }
52
65
  else if (this.wallet.payer) {
@@ -102,7 +115,7 @@ class WhileValidTxSender extends baseTxSender_1.BaseTxSender {
102
115
  const { blockhash, lastValidBlockHeight } = this.untilValid.get(txid);
103
116
  const result = await this.connection.confirmTransaction({
104
117
  signature: txid,
105
- lastValidBlockHeight,
118
+ lastValidBlockHeight: lastValidBlockHeight + VALID_BLOCK_HEIGHT_OFFSET,
106
119
  blockhash,
107
120
  }, opts.commitment);
108
121
  await this.checkConfirmationResultForError(txid, result);
@@ -29,6 +29,7 @@ export declare class UserMap implements UserMapInterface {
29
29
  private stateAccountUpdateCallback;
30
30
  private decode;
31
31
  private mostRecentSlot;
32
+ private syncConfig;
32
33
  private syncPromise?;
33
34
  private syncPromiseResolver;
34
35
  /**
@@ -78,6 +79,8 @@ export declare class UserMap implements UserMapInterface {
78
79
  */
79
80
  getUniqueAuthorities(filterCriteria?: UserFilterCriteria): PublicKey[];
80
81
  sync(): Promise<void>;
82
+ private defaultSync;
83
+ private paginatedSync;
81
84
  unsubscribe(): Promise<void>;
82
85
  updateUserAccount(key: string, userAccount: UserAccount, slot: number): Promise<void>;
83
86
  updateLatestSlot(slot: number): void;