@drift-labs/sdk 2.84.0-beta.0 → 2.84.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.84.0-beta.0
1
+ 2.84.0-beta.2
package/bun.lockb CHANGED
Binary file
@@ -576,6 +576,16 @@ exports.MainnetPerpMarkets = [
576
576
  launchTs: 1717597648000,
577
577
  oracleSource: __1.OracleSource.Prelaunch,
578
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
+ },
579
589
  ];
580
590
  exports.PerpMarkets = {
581
591
  devnet: exports.DevnetPerpMarkets,
@@ -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;
@@ -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) {
@@ -9208,7 +9208,7 @@
9208
9208
  "name": "Standard",
9209
9209
  "fields": [
9210
9210
  {
9211
- "name": "track_open_orders_fraction",
9211
+ "name": "trackOpenOrdersFraction",
9212
9212
  "type": "bool"
9213
9213
  }
9214
9214
  ]
@@ -9217,7 +9217,7 @@
9217
9217
  "name": "Liquidation",
9218
9218
  "fields": [
9219
9219
  {
9220
- "name": "market_to_track_margin_requirement",
9220
+ "name": "marketToTrackMarginRequirement",
9221
9221
  "type": {
9222
9222
  "option": {
9223
9223
  "defined": "MarketIdentifier"
@@ -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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drift-labs/sdk",
3
- "version": "2.84.0-beta.0",
3
+ "version": "2.84.0-beta.2",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "author": "crispheaney",
@@ -34,7 +34,7 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
- "@coral-xyz/anchor": "0.28.1-beta.2",
37
+ "@coral-xyz/anchor": "0.29.0",
38
38
  "@ellipsis-labs/phoenix-sdk": "^1.4.2",
39
39
  "@project-serum/serum": "^0.13.38",
40
40
  "@pythnetwork/client": "2.5.3",
@@ -587,6 +587,16 @@ export const MainnetPerpMarkets: PerpMarketConfig[] = [
587
587
  launchTs: 1717597648000,
588
588
  oracleSource: OracleSource.Prelaunch,
589
589
  },
590
+ {
591
+ fullName: 'IO',
592
+ category: ['DePIN', 'Solana'],
593
+ symbol: 'IO-PERP',
594
+ baseAssetSymbol: 'IO',
595
+ marketIndex: 32,
596
+ oracle: new PublicKey('5sAqMGidMtztNFdUukyguz6jMFS8DvTmSUr4p5u5zsSg'),
597
+ launchTs: 1718021389000,
598
+ oracleSource: OracleSource.Prelaunch,
599
+ },
590
600
  ];
591
601
 
592
602
  export const PerpMarkets: { [key in DriftEnv]: PerpMarketConfig[] } = {
@@ -6778,7 +6778,7 @@ export class DriftClient {
6778
6778
  txVersion?: TransactionVersion,
6779
6779
  lookupTables?: AddressLookupTableAccount[],
6780
6780
  forceVersionedTransaction?: boolean,
6781
- recentBlockHash?: BlockhashWithExpiryBlockHeight
6781
+ recentBlockhash?: BlockhashWithExpiryBlockHeight
6782
6782
  ): Promise<Transaction | VersionedTransaction> {
6783
6783
  return this.txHandler.buildTransaction({
6784
6784
  instructions,
@@ -6790,7 +6790,7 @@ export class DriftClient {
6790
6790
  this.fetchMarketLookupTableAccount.bind(this),
6791
6791
  lookupTables,
6792
6792
  forceVersionedTransaction,
6793
- recentBlockHash,
6793
+ recentBlockhash,
6794
6794
  });
6795
6795
  }
6796
6796
 
@@ -9208,7 +9208,7 @@
9208
9208
  "name": "Standard",
9209
9209
  "fields": [
9210
9210
  {
9211
- "name": "track_open_orders_fraction",
9211
+ "name": "trackOpenOrdersFraction",
9212
9212
  "type": "bool"
9213
9213
  }
9214
9214
  ]
@@ -9217,7 +9217,7 @@
9217
9217
  "name": "Liquidation",
9218
9218
  "fields": [
9219
9219
  {
9220
- "name": "market_to_track_margin_requirement",
9220
+ "name": "marketToTrackMarginRequirement",
9221
9221
  "type": {
9222
9222
  "option": {
9223
9223
  "defined": "MarketIdentifier"
@@ -25,6 +25,14 @@ import {
25
25
  } from '../types';
26
26
  import { containsComputeUnitIxs } from '../util/computeUnits';
27
27
 
28
+ /**
29
+ * Explanation for SIGNATURE_BLOCK_AND_EXPIRY:
30
+ *
31
+ * 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.
32
+ */
33
+
34
+ const DEV_TRY_FORCE_TX_TIMEOUTS = false;
35
+
28
36
  export const COMPUTE_UNITS_DEFAULT = 200_000;
29
37
 
30
38
  export type TxBuildingProps = {
@@ -36,7 +44,7 @@ export type TxBuildingProps = {
36
44
  lookupTables?: AddressLookupTableAccount[];
37
45
  forceVersionedTransaction?: boolean;
38
46
  txParams?: TxParams;
39
- recentBlockHash?: BlockhashWithExpiryBlockHeight;
47
+ recentBlockhash?: BlockhashWithExpiryBlockHeight;
40
48
  wallet?: IWallet;
41
49
  };
42
50
 
@@ -139,6 +147,9 @@ export class TxHandler {
139
147
 
140
148
  const signedTx = await this.signTx(tx, additionalSigners);
141
149
 
150
+ // @ts-ignore
151
+ signedTx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
152
+
142
153
  return signedTx;
143
154
  }
144
155
 
@@ -202,15 +213,18 @@ export class TxHandler {
202
213
  public async signVersionedTx(
203
214
  tx: VersionedTransaction,
204
215
  additionalSigners: Array<Signer>,
205
- recentBlockHash?: BlockhashWithExpiryBlockHeight,
216
+ recentBlockhash?: BlockhashWithExpiryBlockHeight,
206
217
  wallet?: IWallet
207
218
  ): Promise<VersionedTransaction> {
208
219
  [wallet] = this.getProps(wallet);
209
220
 
210
- if (recentBlockHash) {
211
- tx.message.recentBlockhash = recentBlockHash.blockhash;
221
+ if (recentBlockhash) {
222
+ tx.message.recentBlockhash = recentBlockhash.blockhash;
212
223
 
213
- this.addHashAndExpiryToLookup(recentBlockHash);
224
+ this.addHashAndExpiryToLookup(recentBlockhash);
225
+
226
+ // @ts-ignore
227
+ tx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
214
228
  }
215
229
 
216
230
  additionalSigners
@@ -305,10 +319,10 @@ export class TxHandler {
305
319
  }
306
320
 
307
321
  private _generateVersionedTransaction(
308
- recentBlockHash: BlockhashWithExpiryBlockHeight,
322
+ recentBlockhash: BlockhashWithExpiryBlockHeight,
309
323
  message: Message | MessageV0
310
324
  ) {
311
- this.addHashAndExpiryToLookup(recentBlockHash);
325
+ this.addHashAndExpiryToLookup(recentBlockhash);
312
326
 
313
327
  return new VersionedTransaction(message);
314
328
  }
@@ -326,7 +340,12 @@ export class TxHandler {
326
340
  instructions: ixs,
327
341
  }).compileToLegacyMessage();
328
342
 
329
- return this._generateVersionedTransaction(recentBlockhash, message);
343
+ const tx = this._generateVersionedTransaction(recentBlockhash, message);
344
+
345
+ // @ts-ignore
346
+ tx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
347
+
348
+ return tx;
330
349
  }
331
350
 
332
351
  public generateVersionedTransaction(
@@ -343,7 +362,12 @@ export class TxHandler {
343
362
  instructions: ixs,
344
363
  }).compileToV0Message(lookupTableAccounts);
345
364
 
346
- return this._generateVersionedTransaction(recentBlockhash, message);
365
+ const tx = this._generateVersionedTransaction(recentBlockhash, message);
366
+
367
+ // @ts-ignore
368
+ tx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
369
+
370
+ return tx;
347
371
  }
348
372
 
349
373
  public generateLegacyTransaction(ixs: TransactionInstruction[]) {
@@ -360,8 +384,8 @@ export class TxHandler {
360
384
  instructions: (TransactionInstruction | TransactionInstruction[])[];
361
385
  }
362
386
  ) {
363
- const recentBlockHash =
364
- props?.recentBlockHash ?? (await this.getLatestBlockhashForTransaction());
387
+ const recentBlockhash =
388
+ props?.recentBlockhash ?? (await this.getLatestBlockhashForTransaction());
365
389
 
366
390
  return await Promise.all(
367
391
  props.instructions.map((ix) => {
@@ -369,7 +393,7 @@ export class TxHandler {
369
393
  return this.buildTransaction({
370
394
  ...props,
371
395
  instructions: ix,
372
- recentBlockHash,
396
+ recentBlockhash,
373
397
  });
374
398
  })
375
399
  );
@@ -433,7 +457,13 @@ export class TxHandler {
433
457
 
434
458
  const computeUnitsPrice = baseTxParams?.computeUnitsPrice;
435
459
 
436
- if (computeUnitsPrice > 0 && !hasSetComputeUnitPriceIx) {
460
+ if (process.env.DEV_TRY_FORCE_TX_TIMEOUTS || DEV_TRY_FORCE_TX_TIMEOUTS) {
461
+ allIx.push(
462
+ ComputeBudgetProgram.setComputeUnitPrice({
463
+ microLamports: 0,
464
+ })
465
+ );
466
+ } else if (computeUnitsPrice > 0 && !hasSetComputeUnitPriceIx) {
437
467
  allIx.push(
438
468
  ComputeBudgetProgram.setComputeUnitPrice({
439
469
  microLamports: computeUnitsPrice,
@@ -443,13 +473,13 @@ export class TxHandler {
443
473
 
444
474
  allIx.push(...instructionsArray);
445
475
 
446
- const recentBlockHash =
447
- props?.recentBlockHash ?? (await this.getLatestBlockhashForTransaction());
476
+ const recentBlockhash =
477
+ props?.recentBlockhash ?? (await this.getLatestBlockhashForTransaction());
448
478
 
449
479
  // # Create and return Transaction
450
480
  if (txVersion === 'legacy') {
451
481
  if (forceVersionedTransaction) {
452
- return this.generateLegacyVersionedTransaction(recentBlockHash, allIx);
482
+ return this.generateLegacyVersionedTransaction(recentBlockhash, allIx);
453
483
  } else {
454
484
  return this.generateLegacyTransaction(allIx);
455
485
  }
@@ -461,7 +491,7 @@ export class TxHandler {
461
491
  : [marketLookupTable];
462
492
 
463
493
  return this.generateVersionedTransaction(
464
- recentBlockHash,
494
+ recentBlockhash,
465
495
  allIx,
466
496
  lookupTables
467
497
  );
@@ -482,7 +512,13 @@ export class TxHandler {
482
512
  );
483
513
  }
484
514
 
485
- if (computeUnitsPrice != 0) {
515
+ if (process.env.DEV_TRY_FORCE_TX_TIMEOUTS || DEV_TRY_FORCE_TX_TIMEOUTS) {
516
+ tx.add(
517
+ ComputeBudgetProgram.setComputeUnitPrice({
518
+ microLamports: 0,
519
+ })
520
+ );
521
+ } else if (computeUnitsPrice != 0) {
486
522
  tx.add(
487
523
  ComputeBudgetProgram.setComputeUnitPrice({
488
524
  microLamports: computeUnitsPrice,
@@ -506,18 +542,21 @@ export class TxHandler {
506
542
  keys: string[],
507
543
  wallet?: IWallet,
508
544
  commitment?: Commitment,
509
- recentBlockHash?: BlockhashWithExpiryBlockHeight
545
+ recentBlockhash?: BlockhashWithExpiryBlockHeight
510
546
  ) {
511
- recentBlockHash = recentBlockHash
512
- ? recentBlockHash
547
+ recentBlockhash = recentBlockhash
548
+ ? recentBlockhash
513
549
  : await this.getLatestBlockhashForTransaction();
514
550
 
515
- this.addHashAndExpiryToLookup(recentBlockHash);
551
+ this.addHashAndExpiryToLookup(recentBlockhash);
516
552
 
517
553
  for (const tx of txsToSign) {
518
554
  if (!tx) continue;
519
- tx.recentBlockhash = recentBlockHash.blockhash;
555
+ tx.recentBlockhash = recentBlockhash.blockhash;
520
556
  tx.feePayer = wallet?.publicKey ?? this.wallet?.publicKey;
557
+
558
+ // @ts-ignore
559
+ tx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
521
560
  }
522
561
 
523
562
  return this.getSignedTransactionMap(txsToSign, keys, wallet);
@@ -536,18 +575,21 @@ export class TxHandler {
536
575
  keys: string[],
537
576
  wallet?: IWallet,
538
577
  commitment?: Commitment,
539
- recentBlockHash?: BlockhashWithExpiryBlockHeight
578
+ recentBlockhash?: BlockhashWithExpiryBlockHeight
540
579
  ) {
541
- recentBlockHash = recentBlockHash
542
- ? recentBlockHash
580
+ recentBlockhash = recentBlockhash
581
+ ? recentBlockhash
543
582
  : await this.getLatestBlockhashForTransaction();
544
583
 
545
- this.addHashAndExpiryToLookup(recentBlockHash);
584
+ this.addHashAndExpiryToLookup(recentBlockhash);
546
585
 
547
586
  for (const tx of txsToSign) {
548
587
  if (!tx) continue;
549
- tx.recentBlockhash = recentBlockHash.blockhash;
588
+ tx.recentBlockhash = recentBlockhash.blockhash;
550
589
  tx.feePayer = wallet?.publicKey ?? this.wallet?.publicKey;
590
+
591
+ // @ts-ignore
592
+ tx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
551
593
  }
552
594
 
553
595
  return this.getSignedTransactionMap(txsToSign, keys, wallet);
@@ -584,13 +626,20 @@ export class TxHandler {
584
626
 
585
627
  this.preSignedCb?.();
586
628
 
587
- const signedTxs = await wallet.signAllTransactions(
588
- txsToSign
589
- .map((tx) => {
590
- return tx as Transaction;
591
- })
592
- .filter((tx) => tx !== undefined)
593
- );
629
+ const filteredTxs = txsToSign
630
+ .map((tx) => {
631
+ return tx as Transaction;
632
+ })
633
+ .filter((tx) => tx !== undefined);
634
+
635
+ const signedTxs = await wallet.signAllTransactions(filteredTxs);
636
+
637
+ signedTxs.forEach((signedTx, index) => {
638
+ // @ts-ignore
639
+ signedTx.SIGNATURE_BLOCK_AND_EXPIRY =
640
+ // @ts-ignore
641
+ txsToSign[index]?.SIGNATURE_BLOCK_AND_EXPIRY;
642
+ });
594
643
 
595
644
  this.handleSignedTxData(
596
645
  signedTxs.map((signedTx) => {
@@ -622,15 +671,14 @@ export class TxHandler {
622
671
  ) {
623
672
  const transactions = await this.buildBulkTransactions(props);
624
673
 
625
- const preppedTransactions =
626
- props.txVersion === 'legacy'
627
- ? this.getPreparedAndSignedLegacyTransactionMap(
628
- transactions as Transaction[],
629
- props.keys,
630
- props.wallet,
631
- props.preFlightCommitment
632
- )
633
- : this.getSignedTransactionMap(transactions, props.keys, props.wallet);
674
+ const preppedTransactions = await (props.txVersion === 'legacy'
675
+ ? this.getPreparedAndSignedLegacyTransactionMap(
676
+ transactions as Transaction[],
677
+ props.keys,
678
+ props.wallet,
679
+ props.preFlightCommitment
680
+ )
681
+ : this.getSignedTransactionMap(transactions, props.keys, props.wallet));
634
682
 
635
683
  return preppedTransactions;
636
684
  }
@@ -15,6 +15,8 @@ import { IWallet } from '../types';
15
15
 
16
16
  const DEFAULT_RETRY = 2000;
17
17
 
18
+ 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.
19
+
18
20
  type ResolveReference = {
19
21
  resolve?: () => void;
20
22
  };
@@ -93,6 +95,13 @@ export class WhileValidTxSender extends BaseTxSender {
93
95
  );
94
96
  }
95
97
 
98
+ // See SIGNATURE_BLOCK_AND_EXPIRY explanation in txHandler.ts if this is confusing
99
+ // @ts-ignore
100
+ if (preSigned && tx.SIGNATURE_BLOCK_AND_EXPIRY) {
101
+ // @ts-ignore
102
+ latestBlockhash = tx.SIGNATURE_BLOCK_AND_EXPIRY;
103
+ }
104
+
96
105
  // handle subclass-specific side effects
97
106
  const txSig = bs58.encode(
98
107
  signedTx.signatures[0]?.signature || signedTx.signatures[0]
@@ -108,12 +117,20 @@ export class WhileValidTxSender extends BaseTxSender {
108
117
  opts?: ConfirmOptions,
109
118
  preSigned?: boolean
110
119
  ): Promise<TxSigAndSlot> {
111
- const latestBlockhash =
120
+ let latestBlockhash =
112
121
  await this.txHandler.getLatestBlockhashForTransaction();
113
122
 
114
123
  let signedTx;
115
124
  if (preSigned) {
116
125
  signedTx = tx;
126
+
127
+ // See SIGNATURE_BLOCK_AND_EXPIRY explanation in txHandler.ts if this is confusing
128
+ // @ts-ignore
129
+ if (tx.SIGNATURE_BLOCK_AND_EXPIRY) {
130
+ // @ts-ignore
131
+ latestBlockhash = tx.SIGNATURE_BLOCK_AND_EXPIRY;
132
+ }
133
+
117
134
  // @ts-ignore
118
135
  } else if (this.wallet.payer) {
119
136
  tx.message.recentBlockhash = latestBlockhash.blockhash;
@@ -185,7 +202,8 @@ export class WhileValidTxSender extends BaseTxSender {
185
202
  const result = await this.connection.confirmTransaction(
186
203
  {
187
204
  signature: txid,
188
- lastValidBlockHeight,
205
+ lastValidBlockHeight:
206
+ lastValidBlockHeight + VALID_BLOCK_HEIGHT_OFFSET,
189
207
  blockhash,
190
208
  },
191
209
  opts.commitment