@solana/web3.js 1.41.7 → 1.41.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
@@ -3082,7 +3103,11 @@ async function sendAndConfirmTransaction(connection, transaction, signers, optio
3082
3103
  maxRetries: options.maxRetries
3083
3104
  };
3084
3105
  const signature = await connection.sendTransaction(transaction, signers, sendOptions);
3085
- const status = (await connection.confirmTransaction(signature, options && options.commitment)).value;
3106
+ const status = transaction.recentBlockhash != null && transaction.lastValidBlockHeight != null ? (await connection.confirmTransaction({
3107
+ signature: signature,
3108
+ blockhash: transaction.recentBlockhash,
3109
+ lastValidBlockHeight: transaction.lastValidBlockHeight
3110
+ }, options && options.commitment)).value : (await connection.confirmTransaction(signature, options && options.commitment)).value;
3086
3111
 
3087
3112
  if (status.err) {
3088
3113
  throw new Error(`Transaction ${signature} failed (${JSON.stringify(status)})`);
@@ -4994,16 +5019,28 @@ const NUM_SLOTS_PER_SECOND = NUM_TICKS_PER_SECOND / DEFAULT_TICKS_PER_SLOT;
4994
5019
 
4995
5020
  const MS_PER_SLOT = 1000 / NUM_SLOTS_PER_SECOND;
4996
5021
 
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
- });
5022
+ class TransactionExpiredBlockheightExceededError extends Error {
5023
+ constructor(signature) {
5024
+ super(`Signature ${signature} has expired: block height exceeded.`);
5025
+ this.signature = void 0;
5026
+ this.signature = signature;
5027
+ }
5028
+
5006
5029
  }
5030
+ Object.defineProperty(TransactionExpiredBlockheightExceededError.prototype, 'name', {
5031
+ value: 'TransactionExpiredBlockheightExceededError'
5032
+ });
5033
+ class TransactionExpiredTimeoutError extends Error {
5034
+ constructor(signature, timeoutSeconds) {
5035
+ 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.`);
5036
+ this.signature = void 0;
5037
+ this.signature = signature;
5038
+ }
5039
+
5040
+ }
5041
+ Object.defineProperty(TransactionExpiredTimeoutError.prototype, 'name', {
5042
+ value: 'TransactionExpiredTimeoutError'
5043
+ });
5007
5044
 
5008
5045
  function makeWebsocketUrl(endpoint) {
5009
5046
  let url = new URL(endpoint);
@@ -6473,67 +6510,124 @@ class Connection {
6473
6510
 
6474
6511
  return res.result;
6475
6512
  }
6476
- /**
6477
- * Confirm the transaction identified by the specified signature.
6478
- */
6479
6513
 
6514
+ // eslint-disable-next-line no-dupe-class-members
6515
+ async confirmTransaction(strategy, commitment) {
6516
+ let rawSignature;
6517
+
6518
+ if (typeof strategy == 'string') {
6519
+ rawSignature = strategy;
6520
+ } else {
6521
+ const config = strategy;
6522
+ rawSignature = config.signature;
6523
+ }
6480
6524
 
6481
- async confirmTransaction(signature, commitment) {
6482
6525
  let decodedSignature;
6483
6526
 
6484
6527
  try {
6485
- decodedSignature = bs58__default["default"].decode(signature);
6528
+ decodedSignature = bs58__default["default"].decode(rawSignature);
6486
6529
  } catch (err) {
6487
- throw new Error('signature must be base58 encoded: ' + signature);
6530
+ throw new Error('signature must be base58 encoded: ' + rawSignature);
6488
6531
  }
6489
6532
 
6490
6533
  assert(decodedSignature.length === 64, 'signature has invalid length');
6491
- const start = Date.now();
6492
6534
  const subscriptionCommitment = commitment || this.commitment;
6535
+ let timeoutId;
6493
6536
  let subscriptionId;
6494
- let response = null;
6495
- const confirmPromise = new Promise((resolve, reject) => {
6537
+ let done = false;
6538
+ const confirmationPromise = new Promise((resolve, reject) => {
6496
6539
  try {
6497
- subscriptionId = this.onSignature(signature, (result, context) => {
6540
+ subscriptionId = this.onSignature(rawSignature, (result, context) => {
6498
6541
  subscriptionId = undefined;
6499
- response = {
6542
+ const response = {
6500
6543
  context,
6501
6544
  value: result
6502
6545
  };
6503
- resolve(null);
6546
+ done = true;
6547
+ resolve({
6548
+ __type: exports.TransactionStatus.PROCESSED,
6549
+ response
6550
+ });
6504
6551
  }, subscriptionCommitment);
6505
6552
  } catch (err) {
6506
6553
  reject(err);
6507
6554
  }
6508
6555
  });
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;
6556
+
6557
+ const checkBlockHeight = async () => {
6558
+ try {
6559
+ const blockHeight = await this.getBlockHeight(commitment);
6560
+ return blockHeight;
6561
+ } catch (_e) {
6562
+ return -1;
6563
+ }
6564
+ };
6565
+
6566
+ const expiryPromise = new Promise(resolve => {
6567
+ if (typeof strategy === 'string') {
6568
+ let timeoutMs = this._confirmTransactionInitialTimeout || 60 * 1000;
6569
+
6570
+ switch (subscriptionCommitment) {
6571
+ case 'processed':
6572
+ case 'recent':
6573
+ case 'single':
6574
+ case 'confirmed':
6575
+ case 'singleGossip':
6576
+ {
6577
+ timeoutMs = this._confirmTransactionInitialTimeout || 30 * 1000;
6578
+ break;
6579
+ }
6520
6580
  }
6521
- }
6581
+
6582
+ timeoutId = setTimeout(() => resolve({
6583
+ __type: exports.TransactionStatus.TIMED_OUT,
6584
+ timeoutMs
6585
+ }), timeoutMs);
6586
+ } else {
6587
+ let config = strategy;
6588
+
6589
+ (async () => {
6590
+ let currentBlockHeight = await checkBlockHeight();
6591
+ if (done) return;
6592
+
6593
+ while (currentBlockHeight <= config.lastValidBlockHeight) {
6594
+ await sleep(1000);
6595
+ if (done) return;
6596
+ currentBlockHeight = await checkBlockHeight();
6597
+ if (done) return;
6598
+ }
6599
+
6600
+ resolve({
6601
+ __type: exports.TransactionStatus.BLOCKHEIGHT_EXCEEDED
6602
+ });
6603
+ })();
6604
+ }
6605
+ });
6606
+ let result;
6522
6607
 
6523
6608
  try {
6524
- await promiseTimeout(confirmPromise, timeoutMs);
6609
+ const outcome = await Promise.race([confirmationPromise, expiryPromise]);
6610
+
6611
+ switch (outcome.__type) {
6612
+ case exports.TransactionStatus.BLOCKHEIGHT_EXCEEDED:
6613
+ throw new TransactionExpiredBlockheightExceededError(rawSignature);
6614
+
6615
+ case exports.TransactionStatus.PROCESSED:
6616
+ result = outcome.response;
6617
+ break;
6618
+
6619
+ case exports.TransactionStatus.TIMED_OUT:
6620
+ throw new TransactionExpiredTimeoutError(rawSignature, outcome.timeoutMs / 1000);
6621
+ }
6525
6622
  } finally {
6623
+ clearTimeout(timeoutId);
6624
+
6526
6625
  if (subscriptionId) {
6527
6626
  this.removeSignatureListener(subscriptionId);
6528
6627
  }
6529
6628
  }
6530
6629
 
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;
6630
+ return result;
6537
6631
  }
6538
6632
  /**
6539
6633
  * Return the list of nodes that are currently participating in the cluster
@@ -7761,6 +7855,7 @@ class Connection {
7761
7855
 
7762
7856
 
7763
7857
  _wsOnError(err) {
7858
+ this._rpcWebSocketConnected = false;
7764
7859
  console.error('ws error:', err.message);
7765
7860
  }
7766
7861
  /**
@@ -7769,6 +7864,7 @@ class Connection {
7769
7864
 
7770
7865
 
7771
7866
  _wsOnClose(code) {
7867
+ this._rpcWebSocketConnected = false;
7772
7868
  this._rpcWebSocketGeneration++;
7773
7869
 
7774
7870
  if (this._rpcWebSocketHeartbeat) {