@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.
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
@@ -2819,8 +2840,6 @@ class Transaction {
2819
2840
  const message = this._compile();
2820
2841
 
2821
2842
  this._partialSign(message, ...uniqueSigners);
2822
-
2823
- this._verifySignatures(message.serialize(), true);
2824
2843
  }
2825
2844
  /**
2826
2845
  * Partially sign a transaction with the specified accounts. All accounts must
@@ -3094,7 +3113,11 @@ async function sendAndConfirmTransaction(connection, transaction, signers, optio
3094
3113
  maxRetries: options.maxRetries
3095
3114
  };
3096
3115
  const signature = await connection.sendTransaction(transaction, signers, sendOptions);
3097
- const status = (await connection.confirmTransaction(signature, options && options.commitment)).value;
3116
+ const status = transaction.recentBlockhash != null && transaction.lastValidBlockHeight != null ? (await connection.confirmTransaction({
3117
+ signature: signature,
3118
+ blockhash: transaction.recentBlockhash,
3119
+ lastValidBlockHeight: transaction.lastValidBlockHeight
3120
+ }, options && options.commitment)).value : (await connection.confirmTransaction(signature, options && options.commitment)).value;
3098
3121
 
3099
3122
  if (status.err) {
3100
3123
  throw new Error(`Transaction ${signature} failed (${JSON.stringify(status)})`);
@@ -4174,6 +4197,34 @@ class ComputeBudgetInstruction {
4174
4197
  bytes
4175
4198
  };
4176
4199
  }
4200
+ /**
4201
+ * Decode set compute unit limit compute budget instruction and retrieve the instruction params.
4202
+ */
4203
+
4204
+
4205
+ static decodeSetComputeUnitLimit(instruction) {
4206
+ this.checkProgramId(instruction.programId);
4207
+ const {
4208
+ units
4209
+ } = decodeData(COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitLimit, instruction.data);
4210
+ return {
4211
+ units
4212
+ };
4213
+ }
4214
+ /**
4215
+ * Decode set compute unit price compute budget instruction and retrieve the instruction params.
4216
+ */
4217
+
4218
+
4219
+ static decodeSetComputeUnitPrice(instruction) {
4220
+ this.checkProgramId(instruction.programId);
4221
+ const {
4222
+ microLamports
4223
+ } = decodeData(COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitPrice, instruction.data);
4224
+ return {
4225
+ microLamports
4226
+ };
4227
+ }
4177
4228
  /**
4178
4229
  * @internal
4179
4230
  */
@@ -4202,6 +4253,14 @@ const COMPUTE_BUDGET_INSTRUCTION_LAYOUTS = Object.freeze({
4202
4253
  RequestHeapFrame: {
4203
4254
  index: 1,
4204
4255
  layout: BufferLayout__namespace.struct([BufferLayout__namespace.u8('instruction'), BufferLayout__namespace.u32('bytes')])
4256
+ },
4257
+ SetComputeUnitLimit: {
4258
+ index: 2,
4259
+ layout: BufferLayout__namespace.struct([BufferLayout__namespace.u8('instruction'), BufferLayout__namespace.u32('units')])
4260
+ },
4261
+ SetComputeUnitPrice: {
4262
+ index: 3,
4263
+ layout: BufferLayout__namespace.struct([BufferLayout__namespace.u8('instruction'), bufferLayoutUtils.u64('microLamports')])
4205
4264
  }
4206
4265
  });
4207
4266
  /**
@@ -4238,6 +4297,28 @@ class ComputeBudgetProgram {
4238
4297
  });
4239
4298
  }
4240
4299
 
4300
+ static setComputeUnitLimit(params) {
4301
+ const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitLimit;
4302
+ const data = encodeData(type, params);
4303
+ return new TransactionInstruction({
4304
+ keys: [],
4305
+ programId: this.programId,
4306
+ data
4307
+ });
4308
+ }
4309
+
4310
+ static setComputeUnitPrice(params) {
4311
+ const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitPrice;
4312
+ const data = encodeData(type, {
4313
+ microLamports: BigInt(params.microLamports)
4314
+ });
4315
+ return new TransactionInstruction({
4316
+ keys: [],
4317
+ programId: this.programId,
4318
+ data
4319
+ });
4320
+ }
4321
+
4241
4322
  }
4242
4323
  ComputeBudgetProgram.programId = new PublicKey('ComputeBudget111111111111111111111111111111');
4243
4324
 
@@ -4494,16 +4575,28 @@ const NUM_SLOTS_PER_SECOND = NUM_TICKS_PER_SECOND / DEFAULT_TICKS_PER_SLOT;
4494
4575
 
4495
4576
  const MS_PER_SLOT = 1000 / NUM_SLOTS_PER_SECOND;
4496
4577
 
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
- });
4578
+ class TransactionExpiredBlockheightExceededError extends Error {
4579
+ constructor(signature) {
4580
+ super(`Signature ${signature} has expired: block height exceeded.`);
4581
+ this.signature = void 0;
4582
+ this.signature = signature;
4583
+ }
4584
+
4585
+ }
4586
+ Object.defineProperty(TransactionExpiredBlockheightExceededError.prototype, 'name', {
4587
+ value: 'TransactionExpiredBlockheightExceededError'
4588
+ });
4589
+ class TransactionExpiredTimeoutError extends Error {
4590
+ constructor(signature, timeoutSeconds) {
4591
+ 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.`);
4592
+ this.signature = void 0;
4593
+ this.signature = signature;
4594
+ }
4595
+
4506
4596
  }
4597
+ Object.defineProperty(TransactionExpiredTimeoutError.prototype, 'name', {
4598
+ value: 'TransactionExpiredTimeoutError'
4599
+ });
4507
4600
 
4508
4601
  function makeWebsocketUrl(endpoint) {
4509
4602
  let url = new URL(endpoint);
@@ -5498,7 +5591,7 @@ class Connection {
5498
5591
  this._disableBlockhashCaching = false;
5499
5592
  this._pollingBlockhash = false;
5500
5593
  this._blockhashInfo = {
5501
- recentBlockhash: null,
5594
+ latestBlockhash: null,
5502
5595
  lastFetch: 0,
5503
5596
  transactionSignatures: [],
5504
5597
  simulatedSignatures: []
@@ -5979,67 +6072,124 @@ class Connection {
5979
6072
 
5980
6073
  return res.result;
5981
6074
  }
5982
- /**
5983
- * Confirm the transaction identified by the specified signature.
5984
- */
5985
6075
 
6076
+ // eslint-disable-next-line no-dupe-class-members
6077
+ async confirmTransaction(strategy, commitment) {
6078
+ let rawSignature;
6079
+
6080
+ if (typeof strategy == 'string') {
6081
+ rawSignature = strategy;
6082
+ } else {
6083
+ const config = strategy;
6084
+ rawSignature = config.signature;
6085
+ }
5986
6086
 
5987
- async confirmTransaction(signature, commitment) {
5988
6087
  let decodedSignature;
5989
6088
 
5990
6089
  try {
5991
- decodedSignature = bs58__default["default"].decode(signature);
6090
+ decodedSignature = bs58__default["default"].decode(rawSignature);
5992
6091
  } catch (err) {
5993
- throw new Error('signature must be base58 encoded: ' + signature);
6092
+ throw new Error('signature must be base58 encoded: ' + rawSignature);
5994
6093
  }
5995
6094
 
5996
6095
  assert(decodedSignature.length === 64, 'signature has invalid length');
5997
- const start = Date.now();
5998
6096
  const subscriptionCommitment = commitment || this.commitment;
6097
+ let timeoutId;
5999
6098
  let subscriptionId;
6000
- let response = null;
6001
- const confirmPromise = new Promise((resolve, reject) => {
6099
+ let done = false;
6100
+ const confirmationPromise = new Promise((resolve, reject) => {
6002
6101
  try {
6003
- subscriptionId = this.onSignature(signature, (result, context) => {
6102
+ subscriptionId = this.onSignature(rawSignature, (result, context) => {
6004
6103
  subscriptionId = undefined;
6005
- response = {
6104
+ const response = {
6006
6105
  context,
6007
6106
  value: result
6008
6107
  };
6009
- resolve(null);
6108
+ done = true;
6109
+ resolve({
6110
+ __type: exports.TransactionStatus.PROCESSED,
6111
+ response
6112
+ });
6010
6113
  }, subscriptionCommitment);
6011
6114
  } catch (err) {
6012
6115
  reject(err);
6013
6116
  }
6014
6117
  });
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;
6118
+
6119
+ const checkBlockHeight = async () => {
6120
+ try {
6121
+ const blockHeight = await this.getBlockHeight(commitment);
6122
+ return blockHeight;
6123
+ } catch (_e) {
6124
+ return -1;
6125
+ }
6126
+ };
6127
+
6128
+ const expiryPromise = new Promise(resolve => {
6129
+ if (typeof strategy === 'string') {
6130
+ let timeoutMs = this._confirmTransactionInitialTimeout || 60 * 1000;
6131
+
6132
+ switch (subscriptionCommitment) {
6133
+ case 'processed':
6134
+ case 'recent':
6135
+ case 'single':
6136
+ case 'confirmed':
6137
+ case 'singleGossip':
6138
+ {
6139
+ timeoutMs = this._confirmTransactionInitialTimeout || 30 * 1000;
6140
+ break;
6141
+ }
6026
6142
  }
6027
- }
6143
+
6144
+ timeoutId = setTimeout(() => resolve({
6145
+ __type: exports.TransactionStatus.TIMED_OUT,
6146
+ timeoutMs
6147
+ }), timeoutMs);
6148
+ } else {
6149
+ let config = strategy;
6150
+
6151
+ (async () => {
6152
+ let currentBlockHeight = await checkBlockHeight();
6153
+ if (done) return;
6154
+
6155
+ while (currentBlockHeight <= config.lastValidBlockHeight) {
6156
+ await sleep(1000);
6157
+ if (done) return;
6158
+ currentBlockHeight = await checkBlockHeight();
6159
+ if (done) return;
6160
+ }
6161
+
6162
+ resolve({
6163
+ __type: exports.TransactionStatus.BLOCKHEIGHT_EXCEEDED
6164
+ });
6165
+ })();
6166
+ }
6167
+ });
6168
+ let result;
6028
6169
 
6029
6170
  try {
6030
- await promiseTimeout(confirmPromise, timeoutMs);
6171
+ const outcome = await Promise.race([confirmationPromise, expiryPromise]);
6172
+
6173
+ switch (outcome.__type) {
6174
+ case exports.TransactionStatus.BLOCKHEIGHT_EXCEEDED:
6175
+ throw new TransactionExpiredBlockheightExceededError(rawSignature);
6176
+
6177
+ case exports.TransactionStatus.PROCESSED:
6178
+ result = outcome.response;
6179
+ break;
6180
+
6181
+ case exports.TransactionStatus.TIMED_OUT:
6182
+ throw new TransactionExpiredTimeoutError(rawSignature, outcome.timeoutMs / 1000);
6183
+ }
6031
6184
  } finally {
6185
+ clearTimeout(timeoutId);
6186
+
6032
6187
  if (subscriptionId) {
6033
6188
  this.removeSignatureListener(subscriptionId);
6034
6189
  }
6035
6190
  }
6036
6191
 
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;
6192
+ return result;
6043
6193
  }
6044
6194
  /**
6045
6195
  * Return the list of nodes that are currently participating in the cluster
@@ -6404,7 +6554,7 @@ class Connection {
6404
6554
  }
6405
6555
  /**
6406
6556
  * Fetch the latest blockhash from the cluster
6407
- * @return {Promise<{blockhash: Blockhash, lastValidBlockHeight: number}>}
6557
+ * @return {Promise<BlockhashWithExpiryBlockHeight>}
6408
6558
  */
6409
6559
 
6410
6560
 
@@ -6418,7 +6568,7 @@ class Connection {
6418
6568
  }
6419
6569
  /**
6420
6570
  * Fetch the latest blockhash from the cluster
6421
- * @return {Promise<{blockhash: Blockhash, lastValidBlockHeight: number}>}
6571
+ * @return {Promise<BlockhashWithExpiryBlockHeight>}
6422
6572
  */
6423
6573
 
6424
6574
 
@@ -7001,7 +7151,7 @@ class Connection {
7001
7151
  */
7002
7152
 
7003
7153
 
7004
- async _recentBlockhash(disableCache) {
7154
+ async _blockhashWithExpiryBlockHeight(disableCache) {
7005
7155
  if (!disableCache) {
7006
7156
  // Wait for polling to finish
7007
7157
  while (this._pollingBlockhash) {
@@ -7012,8 +7162,8 @@ class Connection {
7012
7162
 
7013
7163
  const expired = timeSinceFetch >= BLOCKHASH_CACHE_TIMEOUT_MS;
7014
7164
 
7015
- if (this._blockhashInfo.recentBlockhash !== null && !expired) {
7016
- return this._blockhashInfo.recentBlockhash;
7165
+ if (this._blockhashInfo.latestBlockhash !== null && !expired) {
7166
+ return this._blockhashInfo.latestBlockhash;
7017
7167
  }
7018
7168
  }
7019
7169
 
@@ -7029,20 +7179,20 @@ class Connection {
7029
7179
 
7030
7180
  try {
7031
7181
  const startTime = Date.now();
7182
+ const cachedLatestBlockhash = this._blockhashInfo.latestBlockhash;
7183
+ const cachedBlockhash = cachedLatestBlockhash ? cachedLatestBlockhash.blockhash : null;
7032
7184
 
7033
7185
  for (let i = 0; i < 50; i++) {
7034
- const {
7035
- blockhash
7036
- } = await this.getRecentBlockhash('finalized');
7186
+ const latestBlockhash = await this.getLatestBlockhash('finalized');
7037
7187
 
7038
- if (this._blockhashInfo.recentBlockhash != blockhash) {
7188
+ if (cachedBlockhash !== latestBlockhash.blockhash) {
7039
7189
  this._blockhashInfo = {
7040
- recentBlockhash: blockhash,
7190
+ latestBlockhash,
7041
7191
  lastFetch: Date.now(),
7042
7192
  transactionSignatures: [],
7043
7193
  simulatedSignatures: []
7044
7194
  };
7045
- return blockhash;
7195
+ return latestBlockhash;
7046
7196
  } // Sleep for approximately half a slot
7047
7197
 
7048
7198
 
@@ -7064,13 +7214,11 @@ class Connection {
7064
7214
 
7065
7215
  if (transactionOrMessage instanceof Transaction) {
7066
7216
  let originalTx = transactionOrMessage;
7067
- transaction = new Transaction({
7068
- recentBlockhash: originalTx.recentBlockhash,
7069
- nonceInfo: originalTx.nonceInfo,
7070
- feePayer: originalTx.feePayer,
7071
- signatures: [...originalTx.signatures]
7072
- });
7217
+ transaction = new Transaction();
7218
+ transaction.feePayer = originalTx.feePayer;
7073
7219
  transaction.instructions = transactionOrMessage.instructions;
7220
+ transaction.nonceInfo = originalTx.nonceInfo;
7221
+ transaction.signatures = originalTx.signatures;
7074
7222
  } else {
7075
7223
  transaction = Transaction.populate(transactionOrMessage); // HACK: this function relies on mutating the populated transaction
7076
7224
 
@@ -7083,7 +7231,9 @@ class Connection {
7083
7231
  let disableCache = this._disableBlockhashCaching;
7084
7232
 
7085
7233
  for (;;) {
7086
- transaction.recentBlockhash = await this._recentBlockhash(disableCache);
7234
+ const latestBlockhash = await this._blockhashWithExpiryBlockHeight(disableCache);
7235
+ transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
7236
+ transaction.recentBlockhash = latestBlockhash.blockhash;
7087
7237
  if (!signers) break;
7088
7238
  transaction.sign(...signers);
7089
7239
 
@@ -7167,7 +7317,9 @@ class Connection {
7167
7317
  let disableCache = this._disableBlockhashCaching;
7168
7318
 
7169
7319
  for (;;) {
7170
- transaction.recentBlockhash = await this._recentBlockhash(disableCache);
7320
+ const latestBlockhash = await this._blockhashWithExpiryBlockHeight(disableCache);
7321
+ transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
7322
+ transaction.recentBlockhash = latestBlockhash.blockhash;
7171
7323
  transaction.sign(...signers);
7172
7324
 
7173
7325
  if (!transaction.signature) {
@@ -9608,16 +9760,36 @@ VoteProgram.space = 3731;
9608
9760
  *
9609
9761
  * @param {Connection} connection
9610
9762
  * @param {Buffer} rawTransaction
9763
+ * @param {BlockheightBasedTransactionConfirmationStrategy} confirmationStrategy
9611
9764
  * @param {ConfirmOptions} [options]
9612
9765
  * @returns {Promise<TransactionSignature>}
9613
9766
  */
9614
- async function sendAndConfirmRawTransaction(connection, rawTransaction, options) {
9767
+
9768
+ /**
9769
+ * @deprecated Calling `sendAndConfirmRawTransaction()` without a `confirmationStrategy`
9770
+ * is no longer supported and will be removed in a future version.
9771
+ */
9772
+ // eslint-disable-next-line no-redeclare
9773
+ // eslint-disable-next-line no-redeclare
9774
+ async function sendAndConfirmRawTransaction(connection, rawTransaction, confirmationStrategyOrConfirmOptions, maybeConfirmOptions) {
9775
+ let confirmationStrategy;
9776
+ let options;
9777
+
9778
+ if (confirmationStrategyOrConfirmOptions && Object.prototype.hasOwnProperty.call(confirmationStrategyOrConfirmOptions, 'lastValidBlockHeight')) {
9779
+ confirmationStrategy = confirmationStrategyOrConfirmOptions;
9780
+ options = maybeConfirmOptions;
9781
+ } else {
9782
+ options = confirmationStrategyOrConfirmOptions;
9783
+ }
9784
+
9615
9785
  const sendOptions = options && {
9616
9786
  skipPreflight: options.skipPreflight,
9617
9787
  preflightCommitment: options.preflightCommitment || options.commitment
9618
9788
  };
9619
9789
  const signature = await connection.sendRawTransaction(rawTransaction, sendOptions);
9620
- const status = (await connection.confirmTransaction(signature, options && options.commitment)).value;
9790
+ const commitment = options && options.commitment;
9791
+ const confirmationPromise = confirmationStrategy ? connection.confirmTransaction(confirmationStrategy, commitment) : connection.confirmTransaction(signature, commitment);
9792
+ const status = (await confirmationPromise).value;
9621
9793
 
9622
9794
  if (status.err) {
9623
9795
  throw new Error(`Raw transaction ${signature} failed (${JSON.stringify(status)})`);