@solana/web3.js 1.41.9 → 1.43.0

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.
@@ -2376,9 +2376,17 @@ function assert (condition, message) {
2376
2376
  }
2377
2377
  }
2378
2378
 
2379
+ exports.TransactionStatus = void 0;
2379
2380
  /**
2380
2381
  * Default (empty) signature
2381
2382
  */
2383
+
2384
+ (function (TransactionStatus) {
2385
+ TransactionStatus[TransactionStatus["BLOCKHEIGHT_EXCEEDED"] = 0] = "BLOCKHEIGHT_EXCEEDED";
2386
+ TransactionStatus[TransactionStatus["PROCESSED"] = 1] = "PROCESSED";
2387
+ TransactionStatus[TransactionStatus["TIMED_OUT"] = 2] = "TIMED_OUT";
2388
+ })(exports.TransactionStatus || (exports.TransactionStatus = {}));
2389
+
2382
2390
  const DEFAULT_SIGNATURE = buffer.Buffer.alloc(SIGNATURE_LENGTH_IN_BYTES).fill(0);
2383
2391
  /**
2384
2392
  * Account metadata used to define instructions
@@ -2469,10 +2477,23 @@ class Transaction {
2469
2477
  this.feePayer = void 0;
2470
2478
  this.instructions = [];
2471
2479
  this.recentBlockhash = void 0;
2480
+ this.lastValidBlockHeight = void 0;
2472
2481
  this.nonceInfo = void 0;
2473
2482
  this._message = void 0;
2474
2483
  this._json = void 0;
2475
- opts && Object.assign(this, opts);
2484
+
2485
+ if (!opts) {
2486
+ return;
2487
+ } else if (Object.prototype.hasOwnProperty.call(opts, 'lastValidBlockHeight')) {
2488
+ const newOpts = opts;
2489
+ Object.assign(this, newOpts);
2490
+ this.recentBlockhash = newOpts.blockhash;
2491
+ this.lastValidBlockHeight = newOpts.lastValidBlockHeight;
2492
+ } else {
2493
+ const oldOpts = opts;
2494
+ Object.assign(this, oldOpts);
2495
+ this.recentBlockhash = oldOpts.recentBlockhash;
2496
+ }
2476
2497
  }
2477
2498
  /**
2478
2499
  * @internal
@@ -2807,8 +2828,6 @@ class Transaction {
2807
2828
  const message = this._compile();
2808
2829
 
2809
2830
  this._partialSign(message, ...uniqueSigners);
2810
-
2811
- this._verifySignatures(message.serialize(), true);
2812
2831
  }
2813
2832
  /**
2814
2833
  * Partially sign a transaction with the specified accounts. All accounts must
@@ -3082,7 +3101,11 @@ async function sendAndConfirmTransaction(connection, transaction, signers, optio
3082
3101
  maxRetries: options.maxRetries
3083
3102
  };
3084
3103
  const signature = await connection.sendTransaction(transaction, signers, sendOptions);
3085
- const status = (await connection.confirmTransaction(signature, options && options.commitment)).value;
3104
+ const status = transaction.recentBlockhash != null && transaction.lastValidBlockHeight != null ? (await connection.confirmTransaction({
3105
+ signature: signature,
3106
+ blockhash: transaction.recentBlockhash,
3107
+ lastValidBlockHeight: transaction.lastValidBlockHeight
3108
+ }, options && options.commitment)).value : (await connection.confirmTransaction(signature, options && options.commitment)).value;
3086
3109
 
3087
3110
  if (status.err) {
3088
3111
  throw new Error(`Transaction ${signature} failed (${JSON.stringify(status)})`);
@@ -4162,6 +4185,34 @@ class ComputeBudgetInstruction {
4162
4185
  bytes
4163
4186
  };
4164
4187
  }
4188
+ /**
4189
+ * Decode set compute unit limit compute budget instruction and retrieve the instruction params.
4190
+ */
4191
+
4192
+
4193
+ static decodeSetComputeUnitLimit(instruction) {
4194
+ this.checkProgramId(instruction.programId);
4195
+ const {
4196
+ units
4197
+ } = decodeData(COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitLimit, instruction.data);
4198
+ return {
4199
+ units
4200
+ };
4201
+ }
4202
+ /**
4203
+ * Decode set compute unit price compute budget instruction and retrieve the instruction params.
4204
+ */
4205
+
4206
+
4207
+ static decodeSetComputeUnitPrice(instruction) {
4208
+ this.checkProgramId(instruction.programId);
4209
+ const {
4210
+ microLamports
4211
+ } = decodeData(COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitPrice, instruction.data);
4212
+ return {
4213
+ microLamports
4214
+ };
4215
+ }
4165
4216
  /**
4166
4217
  * @internal
4167
4218
  */
@@ -4190,6 +4241,14 @@ const COMPUTE_BUDGET_INSTRUCTION_LAYOUTS = Object.freeze({
4190
4241
  RequestHeapFrame: {
4191
4242
  index: 1,
4192
4243
  layout: BufferLayout__namespace.struct([BufferLayout__namespace.u8('instruction'), BufferLayout__namespace.u32('bytes')])
4244
+ },
4245
+ SetComputeUnitLimit: {
4246
+ index: 2,
4247
+ layout: BufferLayout__namespace.struct([BufferLayout__namespace.u8('instruction'), BufferLayout__namespace.u32('units')])
4248
+ },
4249
+ SetComputeUnitPrice: {
4250
+ index: 3,
4251
+ layout: BufferLayout__namespace.struct([BufferLayout__namespace.u8('instruction'), bufferLayoutUtils.u64('microLamports')])
4193
4252
  }
4194
4253
  });
4195
4254
  /**
@@ -4226,6 +4285,28 @@ class ComputeBudgetProgram {
4226
4285
  });
4227
4286
  }
4228
4287
 
4288
+ static setComputeUnitLimit(params) {
4289
+ const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitLimit;
4290
+ const data = encodeData(type, params);
4291
+ return new TransactionInstruction({
4292
+ keys: [],
4293
+ programId: this.programId,
4294
+ data
4295
+ });
4296
+ }
4297
+
4298
+ static setComputeUnitPrice(params) {
4299
+ const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitPrice;
4300
+ const data = encodeData(type, {
4301
+ microLamports: BigInt(params.microLamports)
4302
+ });
4303
+ return new TransactionInstruction({
4304
+ keys: [],
4305
+ programId: this.programId,
4306
+ data
4307
+ });
4308
+ }
4309
+
4229
4310
  }
4230
4311
  ComputeBudgetProgram.programId = new PublicKey('ComputeBudget111111111111111111111111111111');
4231
4312
 
@@ -4994,16 +5075,28 @@ const NUM_SLOTS_PER_SECOND = NUM_TICKS_PER_SECOND / DEFAULT_TICKS_PER_SLOT;
4994
5075
 
4995
5076
  const MS_PER_SLOT = 1000 / NUM_SLOTS_PER_SECOND;
4996
5077
 
4997
- function promiseTimeout(promise, timeoutMs) {
4998
- let timeoutId;
4999
- const timeoutPromise = new Promise(resolve => {
5000
- timeoutId = setTimeout(() => resolve(null), timeoutMs);
5001
- });
5002
- return Promise.race([promise, timeoutPromise]).then(result => {
5003
- clearTimeout(timeoutId);
5004
- return result;
5005
- });
5078
+ class TransactionExpiredBlockheightExceededError extends Error {
5079
+ constructor(signature) {
5080
+ super(`Signature ${signature} has expired: block height exceeded.`);
5081
+ this.signature = void 0;
5082
+ this.signature = signature;
5083
+ }
5084
+
5085
+ }
5086
+ Object.defineProperty(TransactionExpiredBlockheightExceededError.prototype, 'name', {
5087
+ value: 'TransactionExpiredBlockheightExceededError'
5088
+ });
5089
+ class TransactionExpiredTimeoutError extends Error {
5090
+ constructor(signature, timeoutSeconds) {
5091
+ super(`Transaction was not confirmed in ${timeoutSeconds.toFixed(2)} seconds. It is ` + 'unknown if it succeeded or failed. Check signature ' + `${signature} using the Solana Explorer or CLI tools.`);
5092
+ this.signature = void 0;
5093
+ this.signature = signature;
5094
+ }
5095
+
5006
5096
  }
5097
+ Object.defineProperty(TransactionExpiredTimeoutError.prototype, 'name', {
5098
+ value: 'TransactionExpiredTimeoutError'
5099
+ });
5007
5100
 
5008
5101
  function makeWebsocketUrl(endpoint) {
5009
5102
  let url = new URL(endpoint);
@@ -5992,7 +6085,7 @@ class Connection {
5992
6085
  this._disableBlockhashCaching = false;
5993
6086
  this._pollingBlockhash = false;
5994
6087
  this._blockhashInfo = {
5995
- recentBlockhash: null,
6088
+ latestBlockhash: null,
5996
6089
  lastFetch: 0,
5997
6090
  transactionSignatures: [],
5998
6091
  simulatedSignatures: []
@@ -6473,67 +6566,124 @@ class Connection {
6473
6566
 
6474
6567
  return res.result;
6475
6568
  }
6476
- /**
6477
- * Confirm the transaction identified by the specified signature.
6478
- */
6479
6569
 
6570
+ // eslint-disable-next-line no-dupe-class-members
6571
+ async confirmTransaction(strategy, commitment) {
6572
+ let rawSignature;
6573
+
6574
+ if (typeof strategy == 'string') {
6575
+ rawSignature = strategy;
6576
+ } else {
6577
+ const config = strategy;
6578
+ rawSignature = config.signature;
6579
+ }
6480
6580
 
6481
- async confirmTransaction(signature, commitment) {
6482
6581
  let decodedSignature;
6483
6582
 
6484
6583
  try {
6485
- decodedSignature = bs58__default["default"].decode(signature);
6584
+ decodedSignature = bs58__default["default"].decode(rawSignature);
6486
6585
  } catch (err) {
6487
- throw new Error('signature must be base58 encoded: ' + signature);
6586
+ throw new Error('signature must be base58 encoded: ' + rawSignature);
6488
6587
  }
6489
6588
 
6490
6589
  assert(decodedSignature.length === 64, 'signature has invalid length');
6491
- const start = Date.now();
6492
6590
  const subscriptionCommitment = commitment || this.commitment;
6591
+ let timeoutId;
6493
6592
  let subscriptionId;
6494
- let response = null;
6495
- const confirmPromise = new Promise((resolve, reject) => {
6593
+ let done = false;
6594
+ const confirmationPromise = new Promise((resolve, reject) => {
6496
6595
  try {
6497
- subscriptionId = this.onSignature(signature, (result, context) => {
6596
+ subscriptionId = this.onSignature(rawSignature, (result, context) => {
6498
6597
  subscriptionId = undefined;
6499
- response = {
6598
+ const response = {
6500
6599
  context,
6501
6600
  value: result
6502
6601
  };
6503
- resolve(null);
6602
+ done = true;
6603
+ resolve({
6604
+ __type: exports.TransactionStatus.PROCESSED,
6605
+ response
6606
+ });
6504
6607
  }, subscriptionCommitment);
6505
6608
  } catch (err) {
6506
6609
  reject(err);
6507
6610
  }
6508
6611
  });
6509
- let timeoutMs = this._confirmTransactionInitialTimeout || 60 * 1000;
6510
-
6511
- switch (subscriptionCommitment) {
6512
- case 'processed':
6513
- case 'recent':
6514
- case 'single':
6515
- case 'confirmed':
6516
- case 'singleGossip':
6517
- {
6518
- timeoutMs = this._confirmTransactionInitialTimeout || 30 * 1000;
6519
- break;
6612
+
6613
+ const checkBlockHeight = async () => {
6614
+ try {
6615
+ const blockHeight = await this.getBlockHeight(commitment);
6616
+ return blockHeight;
6617
+ } catch (_e) {
6618
+ return -1;
6619
+ }
6620
+ };
6621
+
6622
+ const expiryPromise = new Promise(resolve => {
6623
+ if (typeof strategy === 'string') {
6624
+ let timeoutMs = this._confirmTransactionInitialTimeout || 60 * 1000;
6625
+
6626
+ switch (subscriptionCommitment) {
6627
+ case 'processed':
6628
+ case 'recent':
6629
+ case 'single':
6630
+ case 'confirmed':
6631
+ case 'singleGossip':
6632
+ {
6633
+ timeoutMs = this._confirmTransactionInitialTimeout || 30 * 1000;
6634
+ break;
6635
+ }
6520
6636
  }
6521
- }
6637
+
6638
+ timeoutId = setTimeout(() => resolve({
6639
+ __type: exports.TransactionStatus.TIMED_OUT,
6640
+ timeoutMs
6641
+ }), timeoutMs);
6642
+ } else {
6643
+ let config = strategy;
6644
+
6645
+ (async () => {
6646
+ let currentBlockHeight = await checkBlockHeight();
6647
+ if (done) return;
6648
+
6649
+ while (currentBlockHeight <= config.lastValidBlockHeight) {
6650
+ await sleep(1000);
6651
+ if (done) return;
6652
+ currentBlockHeight = await checkBlockHeight();
6653
+ if (done) return;
6654
+ }
6655
+
6656
+ resolve({
6657
+ __type: exports.TransactionStatus.BLOCKHEIGHT_EXCEEDED
6658
+ });
6659
+ })();
6660
+ }
6661
+ });
6662
+ let result;
6522
6663
 
6523
6664
  try {
6524
- await promiseTimeout(confirmPromise, timeoutMs);
6665
+ const outcome = await Promise.race([confirmationPromise, expiryPromise]);
6666
+
6667
+ switch (outcome.__type) {
6668
+ case exports.TransactionStatus.BLOCKHEIGHT_EXCEEDED:
6669
+ throw new TransactionExpiredBlockheightExceededError(rawSignature);
6670
+
6671
+ case exports.TransactionStatus.PROCESSED:
6672
+ result = outcome.response;
6673
+ break;
6674
+
6675
+ case exports.TransactionStatus.TIMED_OUT:
6676
+ throw new TransactionExpiredTimeoutError(rawSignature, outcome.timeoutMs / 1000);
6677
+ }
6525
6678
  } finally {
6679
+ clearTimeout(timeoutId);
6680
+
6526
6681
  if (subscriptionId) {
6527
6682
  this.removeSignatureListener(subscriptionId);
6528
6683
  }
6529
6684
  }
6530
6685
 
6531
- if (response === null) {
6532
- const duration = (Date.now() - start) / 1000;
6533
- throw new Error(`Transaction was not confirmed in ${duration.toFixed(2)} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools.`);
6534
- }
6535
-
6536
- return response;
6686
+ return result;
6537
6687
  }
6538
6688
  /**
6539
6689
  * Return the list of nodes that are currently participating in the cluster
@@ -6898,7 +7048,7 @@ class Connection {
6898
7048
  }
6899
7049
  /**
6900
7050
  * Fetch the latest blockhash from the cluster
6901
- * @return {Promise<{blockhash: Blockhash, lastValidBlockHeight: number}>}
7051
+ * @return {Promise<BlockhashWithExpiryBlockHeight>}
6902
7052
  */
6903
7053
 
6904
7054
 
@@ -6912,7 +7062,7 @@ class Connection {
6912
7062
  }
6913
7063
  /**
6914
7064
  * Fetch the latest blockhash from the cluster
6915
- * @return {Promise<{blockhash: Blockhash, lastValidBlockHeight: number}>}
7065
+ * @return {Promise<BlockhashWithExpiryBlockHeight>}
6916
7066
  */
6917
7067
 
6918
7068
 
@@ -7495,7 +7645,7 @@ class Connection {
7495
7645
  */
7496
7646
 
7497
7647
 
7498
- async _recentBlockhash(disableCache) {
7648
+ async _blockhashWithExpiryBlockHeight(disableCache) {
7499
7649
  if (!disableCache) {
7500
7650
  // Wait for polling to finish
7501
7651
  while (this._pollingBlockhash) {
@@ -7506,8 +7656,8 @@ class Connection {
7506
7656
 
7507
7657
  const expired = timeSinceFetch >= BLOCKHASH_CACHE_TIMEOUT_MS;
7508
7658
 
7509
- if (this._blockhashInfo.recentBlockhash !== null && !expired) {
7510
- return this._blockhashInfo.recentBlockhash;
7659
+ if (this._blockhashInfo.latestBlockhash !== null && !expired) {
7660
+ return this._blockhashInfo.latestBlockhash;
7511
7661
  }
7512
7662
  }
7513
7663
 
@@ -7523,20 +7673,20 @@ class Connection {
7523
7673
 
7524
7674
  try {
7525
7675
  const startTime = Date.now();
7676
+ const cachedLatestBlockhash = this._blockhashInfo.latestBlockhash;
7677
+ const cachedBlockhash = cachedLatestBlockhash ? cachedLatestBlockhash.blockhash : null;
7526
7678
 
7527
7679
  for (let i = 0; i < 50; i++) {
7528
- const {
7529
- blockhash
7530
- } = await this.getRecentBlockhash('finalized');
7680
+ const latestBlockhash = await this.getLatestBlockhash('finalized');
7531
7681
 
7532
- if (this._blockhashInfo.recentBlockhash != blockhash) {
7682
+ if (cachedBlockhash !== latestBlockhash.blockhash) {
7533
7683
  this._blockhashInfo = {
7534
- recentBlockhash: blockhash,
7684
+ latestBlockhash,
7535
7685
  lastFetch: Date.now(),
7536
7686
  transactionSignatures: [],
7537
7687
  simulatedSignatures: []
7538
7688
  };
7539
- return blockhash;
7689
+ return latestBlockhash;
7540
7690
  } // Sleep for approximately half a slot
7541
7691
 
7542
7692
 
@@ -7558,13 +7708,11 @@ class Connection {
7558
7708
 
7559
7709
  if (transactionOrMessage instanceof Transaction) {
7560
7710
  let originalTx = transactionOrMessage;
7561
- transaction = new Transaction({
7562
- recentBlockhash: originalTx.recentBlockhash,
7563
- nonceInfo: originalTx.nonceInfo,
7564
- feePayer: originalTx.feePayer,
7565
- signatures: [...originalTx.signatures]
7566
- });
7711
+ transaction = new Transaction();
7712
+ transaction.feePayer = originalTx.feePayer;
7567
7713
  transaction.instructions = transactionOrMessage.instructions;
7714
+ transaction.nonceInfo = originalTx.nonceInfo;
7715
+ transaction.signatures = originalTx.signatures;
7568
7716
  } else {
7569
7717
  transaction = Transaction.populate(transactionOrMessage); // HACK: this function relies on mutating the populated transaction
7570
7718
 
@@ -7577,7 +7725,9 @@ class Connection {
7577
7725
  let disableCache = this._disableBlockhashCaching;
7578
7726
 
7579
7727
  for (;;) {
7580
- transaction.recentBlockhash = await this._recentBlockhash(disableCache);
7728
+ const latestBlockhash = await this._blockhashWithExpiryBlockHeight(disableCache);
7729
+ transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
7730
+ transaction.recentBlockhash = latestBlockhash.blockhash;
7581
7731
  if (!signers) break;
7582
7732
  transaction.sign(...signers);
7583
7733
 
@@ -7661,7 +7811,9 @@ class Connection {
7661
7811
  let disableCache = this._disableBlockhashCaching;
7662
7812
 
7663
7813
  for (;;) {
7664
- transaction.recentBlockhash = await this._recentBlockhash(disableCache);
7814
+ const latestBlockhash = await this._blockhashWithExpiryBlockHeight(disableCache);
7815
+ transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
7816
+ transaction.recentBlockhash = latestBlockhash.blockhash;
7665
7817
  transaction.sign(...signers);
7666
7818
 
7667
7819
  if (!transaction.signature) {
@@ -10102,16 +10254,36 @@ VoteProgram.space = 3731;
10102
10254
  *
10103
10255
  * @param {Connection} connection
10104
10256
  * @param {Buffer} rawTransaction
10257
+ * @param {BlockheightBasedTransactionConfirmationStrategy} confirmationStrategy
10105
10258
  * @param {ConfirmOptions} [options]
10106
10259
  * @returns {Promise<TransactionSignature>}
10107
10260
  */
10108
- async function sendAndConfirmRawTransaction(connection, rawTransaction, options) {
10261
+
10262
+ /**
10263
+ * @deprecated Calling `sendAndConfirmRawTransaction()` without a `confirmationStrategy`
10264
+ * is no longer supported and will be removed in a future version.
10265
+ */
10266
+ // eslint-disable-next-line no-redeclare
10267
+ // eslint-disable-next-line no-redeclare
10268
+ async function sendAndConfirmRawTransaction(connection, rawTransaction, confirmationStrategyOrConfirmOptions, maybeConfirmOptions) {
10269
+ let confirmationStrategy;
10270
+ let options;
10271
+
10272
+ if (confirmationStrategyOrConfirmOptions && Object.prototype.hasOwnProperty.call(confirmationStrategyOrConfirmOptions, 'lastValidBlockHeight')) {
10273
+ confirmationStrategy = confirmationStrategyOrConfirmOptions;
10274
+ options = maybeConfirmOptions;
10275
+ } else {
10276
+ options = confirmationStrategyOrConfirmOptions;
10277
+ }
10278
+
10109
10279
  const sendOptions = options && {
10110
10280
  skipPreflight: options.skipPreflight,
10111
10281
  preflightCommitment: options.preflightCommitment || options.commitment
10112
10282
  };
10113
10283
  const signature = await connection.sendRawTransaction(rawTransaction, sendOptions);
10114
- const status = (await connection.confirmTransaction(signature, options && options.commitment)).value;
10284
+ const commitment = options && options.commitment;
10285
+ const confirmationPromise = confirmationStrategy ? connection.confirmTransaction(confirmationStrategy, commitment) : connection.confirmTransaction(signature, commitment);
10286
+ const status = (await confirmationPromise).value;
10115
10287
 
10116
10288
  if (status.err) {
10117
10289
  throw new Error(`Raw transaction ${signature} failed (${JSON.stringify(status)})`);