@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.
package/lib/index.cjs.js CHANGED
@@ -2388,9 +2388,17 @@ function assert (condition, message) {
2388
2388
  }
2389
2389
  }
2390
2390
 
2391
+ exports.TransactionStatus = void 0;
2391
2392
  /**
2392
2393
  * Default (empty) signature
2393
2394
  */
2395
+
2396
+ (function (TransactionStatus) {
2397
+ TransactionStatus[TransactionStatus["BLOCKHEIGHT_EXCEEDED"] = 0] = "BLOCKHEIGHT_EXCEEDED";
2398
+ TransactionStatus[TransactionStatus["PROCESSED"] = 1] = "PROCESSED";
2399
+ TransactionStatus[TransactionStatus["TIMED_OUT"] = 2] = "TIMED_OUT";
2400
+ })(exports.TransactionStatus || (exports.TransactionStatus = {}));
2401
+
2394
2402
  const DEFAULT_SIGNATURE = buffer.Buffer.alloc(SIGNATURE_LENGTH_IN_BYTES).fill(0);
2395
2403
  /**
2396
2404
  * Account metadata used to define instructions
@@ -2481,10 +2489,23 @@ class Transaction {
2481
2489
  this.feePayer = void 0;
2482
2490
  this.instructions = [];
2483
2491
  this.recentBlockhash = void 0;
2492
+ this.lastValidBlockHeight = void 0;
2484
2493
  this.nonceInfo = void 0;
2485
2494
  this._message = void 0;
2486
2495
  this._json = void 0;
2487
- opts && Object.assign(this, opts);
2496
+
2497
+ if (!opts) {
2498
+ return;
2499
+ } else if (Object.prototype.hasOwnProperty.call(opts, 'lastValidBlockHeight')) {
2500
+ const newOpts = opts;
2501
+ Object.assign(this, newOpts);
2502
+ this.recentBlockhash = newOpts.blockhash;
2503
+ this.lastValidBlockHeight = newOpts.lastValidBlockHeight;
2504
+ } else {
2505
+ const oldOpts = opts;
2506
+ Object.assign(this, oldOpts);
2507
+ this.recentBlockhash = oldOpts.recentBlockhash;
2508
+ }
2488
2509
  }
2489
2510
  /**
2490
2511
  * @internal
@@ -3094,7 +3115,11 @@ async function sendAndConfirmTransaction(connection, transaction, signers, optio
3094
3115
  maxRetries: options.maxRetries
3095
3116
  };
3096
3117
  const signature = await connection.sendTransaction(transaction, signers, sendOptions);
3097
- const status = (await connection.confirmTransaction(signature, options && options.commitment)).value;
3118
+ const status = transaction.recentBlockhash != null && transaction.lastValidBlockHeight != null ? (await connection.confirmTransaction({
3119
+ signature: signature,
3120
+ blockhash: transaction.recentBlockhash,
3121
+ lastValidBlockHeight: transaction.lastValidBlockHeight
3122
+ }, options && options.commitment)).value : (await connection.confirmTransaction(signature, options && options.commitment)).value;
3098
3123
 
3099
3124
  if (status.err) {
3100
3125
  throw new Error(`Transaction ${signature} failed (${JSON.stringify(status)})`);
@@ -4494,16 +4519,28 @@ const NUM_SLOTS_PER_SECOND = NUM_TICKS_PER_SECOND / DEFAULT_TICKS_PER_SLOT;
4494
4519
 
4495
4520
  const MS_PER_SLOT = 1000 / NUM_SLOTS_PER_SECOND;
4496
4521
 
4497
- function promiseTimeout(promise, timeoutMs) {
4498
- let timeoutId;
4499
- const timeoutPromise = new Promise(resolve => {
4500
- timeoutId = setTimeout(() => resolve(null), timeoutMs);
4501
- });
4502
- return Promise.race([promise, timeoutPromise]).then(result => {
4503
- clearTimeout(timeoutId);
4504
- return result;
4505
- });
4522
+ class TransactionExpiredBlockheightExceededError extends Error {
4523
+ constructor(signature) {
4524
+ super(`Signature ${signature} has expired: block height exceeded.`);
4525
+ this.signature = void 0;
4526
+ this.signature = signature;
4527
+ }
4528
+
4506
4529
  }
4530
+ Object.defineProperty(TransactionExpiredBlockheightExceededError.prototype, 'name', {
4531
+ value: 'TransactionExpiredBlockheightExceededError'
4532
+ });
4533
+ class TransactionExpiredTimeoutError extends Error {
4534
+ constructor(signature, timeoutSeconds) {
4535
+ 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.`);
4536
+ this.signature = void 0;
4537
+ this.signature = signature;
4538
+ }
4539
+
4540
+ }
4541
+ Object.defineProperty(TransactionExpiredTimeoutError.prototype, 'name', {
4542
+ value: 'TransactionExpiredTimeoutError'
4543
+ });
4507
4544
 
4508
4545
  function makeWebsocketUrl(endpoint) {
4509
4546
  let url = new URL(endpoint);
@@ -5979,67 +6016,124 @@ class Connection {
5979
6016
 
5980
6017
  return res.result;
5981
6018
  }
5982
- /**
5983
- * Confirm the transaction identified by the specified signature.
5984
- */
5985
6019
 
6020
+ // eslint-disable-next-line no-dupe-class-members
6021
+ async confirmTransaction(strategy, commitment) {
6022
+ let rawSignature;
6023
+
6024
+ if (typeof strategy == 'string') {
6025
+ rawSignature = strategy;
6026
+ } else {
6027
+ const config = strategy;
6028
+ rawSignature = config.signature;
6029
+ }
5986
6030
 
5987
- async confirmTransaction(signature, commitment) {
5988
6031
  let decodedSignature;
5989
6032
 
5990
6033
  try {
5991
- decodedSignature = bs58__default["default"].decode(signature);
6034
+ decodedSignature = bs58__default["default"].decode(rawSignature);
5992
6035
  } catch (err) {
5993
- throw new Error('signature must be base58 encoded: ' + signature);
6036
+ throw new Error('signature must be base58 encoded: ' + rawSignature);
5994
6037
  }
5995
6038
 
5996
6039
  assert(decodedSignature.length === 64, 'signature has invalid length');
5997
- const start = Date.now();
5998
6040
  const subscriptionCommitment = commitment || this.commitment;
6041
+ let timeoutId;
5999
6042
  let subscriptionId;
6000
- let response = null;
6001
- const confirmPromise = new Promise((resolve, reject) => {
6043
+ let done = false;
6044
+ const confirmationPromise = new Promise((resolve, reject) => {
6002
6045
  try {
6003
- subscriptionId = this.onSignature(signature, (result, context) => {
6046
+ subscriptionId = this.onSignature(rawSignature, (result, context) => {
6004
6047
  subscriptionId = undefined;
6005
- response = {
6048
+ const response = {
6006
6049
  context,
6007
6050
  value: result
6008
6051
  };
6009
- resolve(null);
6052
+ done = true;
6053
+ resolve({
6054
+ __type: exports.TransactionStatus.PROCESSED,
6055
+ response
6056
+ });
6010
6057
  }, subscriptionCommitment);
6011
6058
  } catch (err) {
6012
6059
  reject(err);
6013
6060
  }
6014
6061
  });
6015
- let timeoutMs = this._confirmTransactionInitialTimeout || 60 * 1000;
6016
-
6017
- switch (subscriptionCommitment) {
6018
- case 'processed':
6019
- case 'recent':
6020
- case 'single':
6021
- case 'confirmed':
6022
- case 'singleGossip':
6023
- {
6024
- timeoutMs = this._confirmTransactionInitialTimeout || 30 * 1000;
6025
- break;
6062
+
6063
+ const checkBlockHeight = async () => {
6064
+ try {
6065
+ const blockHeight = await this.getBlockHeight(commitment);
6066
+ return blockHeight;
6067
+ } catch (_e) {
6068
+ return -1;
6069
+ }
6070
+ };
6071
+
6072
+ const expiryPromise = new Promise(resolve => {
6073
+ if (typeof strategy === 'string') {
6074
+ let timeoutMs = this._confirmTransactionInitialTimeout || 60 * 1000;
6075
+
6076
+ switch (subscriptionCommitment) {
6077
+ case 'processed':
6078
+ case 'recent':
6079
+ case 'single':
6080
+ case 'confirmed':
6081
+ case 'singleGossip':
6082
+ {
6083
+ timeoutMs = this._confirmTransactionInitialTimeout || 30 * 1000;
6084
+ break;
6085
+ }
6026
6086
  }
6027
- }
6087
+
6088
+ timeoutId = setTimeout(() => resolve({
6089
+ __type: exports.TransactionStatus.TIMED_OUT,
6090
+ timeoutMs
6091
+ }), timeoutMs);
6092
+ } else {
6093
+ let config = strategy;
6094
+
6095
+ (async () => {
6096
+ let currentBlockHeight = await checkBlockHeight();
6097
+ if (done) return;
6098
+
6099
+ while (currentBlockHeight <= config.lastValidBlockHeight) {
6100
+ await sleep(1000);
6101
+ if (done) return;
6102
+ currentBlockHeight = await checkBlockHeight();
6103
+ if (done) return;
6104
+ }
6105
+
6106
+ resolve({
6107
+ __type: exports.TransactionStatus.BLOCKHEIGHT_EXCEEDED
6108
+ });
6109
+ })();
6110
+ }
6111
+ });
6112
+ let result;
6028
6113
 
6029
6114
  try {
6030
- await promiseTimeout(confirmPromise, timeoutMs);
6115
+ const outcome = await Promise.race([confirmationPromise, expiryPromise]);
6116
+
6117
+ switch (outcome.__type) {
6118
+ case exports.TransactionStatus.BLOCKHEIGHT_EXCEEDED:
6119
+ throw new TransactionExpiredBlockheightExceededError(rawSignature);
6120
+
6121
+ case exports.TransactionStatus.PROCESSED:
6122
+ result = outcome.response;
6123
+ break;
6124
+
6125
+ case exports.TransactionStatus.TIMED_OUT:
6126
+ throw new TransactionExpiredTimeoutError(rawSignature, outcome.timeoutMs / 1000);
6127
+ }
6031
6128
  } finally {
6129
+ clearTimeout(timeoutId);
6130
+
6032
6131
  if (subscriptionId) {
6033
6132
  this.removeSignatureListener(subscriptionId);
6034
6133
  }
6035
6134
  }
6036
6135
 
6037
- if (response === null) {
6038
- const duration = (Date.now() - start) / 1000;
6039
- 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.`);
6040
- }
6041
-
6042
- return response;
6136
+ return result;
6043
6137
  }
6044
6138
  /**
6045
6139
  * Return the list of nodes that are currently participating in the cluster
@@ -7267,6 +7361,7 @@ class Connection {
7267
7361
 
7268
7362
 
7269
7363
  _wsOnError(err) {
7364
+ this._rpcWebSocketConnected = false;
7270
7365
  console.error('ws error:', err.message);
7271
7366
  }
7272
7367
  /**
@@ -7275,6 +7370,7 @@ class Connection {
7275
7370
 
7276
7371
 
7277
7372
  _wsOnClose(code) {
7373
+ this._rpcWebSocketConnected = false;
7278
7374
  this._rpcWebSocketGeneration++;
7279
7375
 
7280
7376
  if (this._rpcWebSocketHeartbeat) {