@solana/web3.js 1.66.4 → 1.67.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.
@@ -22,6 +22,7 @@ export const enum TransactionStatus {
22
22
  BLOCKHEIGHT_EXCEEDED,
23
23
  PROCESSED,
24
24
  TIMED_OUT,
25
+ NONCE_INVALID,
25
26
  }
26
27
 
27
28
  /**
@@ -145,7 +146,9 @@ export type TransactionCtorFields_DEPRECATED = {
145
146
  export type TransactionCtorFields = TransactionCtorFields_DEPRECATED;
146
147
 
147
148
  /**
148
- * List of Transaction object fields that may be initialized at construction
149
+ * Blockhash-based transactions have a lifetime that are defined by
150
+ * the blockhash they include. Any transaction whose blockhash is
151
+ * too old will be rejected.
149
152
  */
150
153
  export type TransactionBlockhashCtor = {
151
154
  /** The transaction fee payer */
@@ -158,6 +161,18 @@ export type TransactionBlockhashCtor = {
158
161
  lastValidBlockHeight: number;
159
162
  };
160
163
 
164
+ /**
165
+ * Use these options to construct a durable nonce transaction.
166
+ */
167
+ export type TransactionNonceCtor = {
168
+ /** The transaction fee payer */
169
+ feePayer?: PublicKey | null;
170
+ minContextSlot: number;
171
+ nonceInfo: NonceInformation;
172
+ /** One or more signatures */
173
+ signatures?: Array<SignaturePubkeyPair>;
174
+ };
175
+
161
176
  /**
162
177
  * Nonce information to be used to build an offline Transaction.
163
178
  */
@@ -228,6 +243,15 @@ export class Transaction {
228
243
  */
229
244
  nonceInfo?: NonceInformation;
230
245
 
246
+ /**
247
+ * If this is a nonce transaction this represents the minimum slot from which
248
+ * to evaluate if the nonce has advanced when attempting to confirm the
249
+ * transaction. This protects against a case where the transaction confirmation
250
+ * logic loads the nonce account from an old slot and assumes the mismatch in
251
+ * nonce value implies that the nonce has been advanced.
252
+ */
253
+ minNonceContextSlot?: number;
254
+
231
255
  /**
232
256
  * @internal
233
257
  */
@@ -241,6 +265,9 @@ export class Transaction {
241
265
  // Construct a transaction with a blockhash and lastValidBlockHeight
242
266
  constructor(opts?: TransactionBlockhashCtor);
243
267
 
268
+ // Construct a transaction using a durable nonce
269
+ constructor(opts?: TransactionNonceCtor);
270
+
244
271
  /**
245
272
  * @deprecated `TransactionCtorFields` has been deprecated and will be removed in a future version.
246
273
  * Please supply a `TransactionBlockhashCtor` instead.
@@ -251,7 +278,10 @@ export class Transaction {
251
278
  * Construct an empty Transaction
252
279
  */
253
280
  constructor(
254
- opts?: TransactionBlockhashCtor | TransactionCtorFields_DEPRECATED,
281
+ opts?:
282
+ | TransactionBlockhashCtor
283
+ | TransactionNonceCtor
284
+ | TransactionCtorFields_DEPRECATED,
255
285
  ) {
256
286
  if (!opts) {
257
287
  return;
@@ -262,7 +292,13 @@ export class Transaction {
262
292
  if (opts.signatures) {
263
293
  this.signatures = opts.signatures;
264
294
  }
265
- if (Object.prototype.hasOwnProperty.call(opts, 'lastValidBlockHeight')) {
295
+ if (Object.prototype.hasOwnProperty.call(opts, 'nonceInfo')) {
296
+ const {minContextSlot, nonceInfo} = opts as TransactionNonceCtor;
297
+ this.minNonceContextSlot = minContextSlot;
298
+ this.nonceInfo = nonceInfo;
299
+ } else if (
300
+ Object.prototype.hasOwnProperty.call(opts, 'lastValidBlockHeight')
301
+ ) {
266
302
  const {blockhash, lastValidBlockHeight} =
267
303
  opts as TransactionBlockhashCtor;
268
304
  this.recentBlockhash = blockhash;
@@ -3,6 +3,7 @@ import type {Buffer} from 'buffer';
3
3
  import {
4
4
  BlockheightBasedTransactionConfirmationStrategy,
5
5
  Connection,
6
+ DurableNonceTransactionConfirmationStrategy,
6
7
  } from '../connection';
7
8
  import type {TransactionSignature} from '../transaction';
8
9
  import type {ConfirmOptions} from '../connection';
@@ -42,12 +43,14 @@ export async function sendAndConfirmRawTransaction(
42
43
  rawTransaction: Buffer,
43
44
  confirmationStrategyOrConfirmOptions:
44
45
  | BlockheightBasedTransactionConfirmationStrategy
46
+ | DurableNonceTransactionConfirmationStrategy
45
47
  | ConfirmOptions
46
48
  | undefined,
47
49
  maybeConfirmOptions?: ConfirmOptions,
48
50
  ): Promise<TransactionSignature> {
49
51
  let confirmationStrategy:
50
52
  | BlockheightBasedTransactionConfirmationStrategy
53
+ | DurableNonceTransactionConfirmationStrategy
51
54
  | undefined;
52
55
  let options: ConfirmOptions | undefined;
53
56
  if (
@@ -60,6 +63,16 @@ export async function sendAndConfirmRawTransaction(
60
63
  confirmationStrategy =
61
64
  confirmationStrategyOrConfirmOptions as BlockheightBasedTransactionConfirmationStrategy;
62
65
  options = maybeConfirmOptions;
66
+ } else if (
67
+ confirmationStrategyOrConfirmOptions &&
68
+ Object.prototype.hasOwnProperty.call(
69
+ confirmationStrategyOrConfirmOptions,
70
+ 'nonceValue',
71
+ )
72
+ ) {
73
+ confirmationStrategy =
74
+ confirmationStrategyOrConfirmOptions as DurableNonceTransactionConfirmationStrategy;
75
+ options = maybeConfirmOptions;
63
76
  } else {
64
77
  options = confirmationStrategyOrConfirmOptions as
65
78
  | ConfirmOptions
@@ -1,4 +1,4 @@
1
- import {Connection} from '../connection';
1
+ import {Connection, SignatureResult} from '../connection';
2
2
  import {Transaction} from '../transaction';
3
3
  import type {ConfirmOptions} from '../connection';
4
4
  import type {Signer} from '../keypair';
@@ -34,25 +34,46 @@ export async function sendAndConfirmTransaction(
34
34
  sendOptions,
35
35
  );
36
36
 
37
- const status =
37
+ let status: SignatureResult;
38
+ if (
38
39
  transaction.recentBlockhash != null &&
39
40
  transaction.lastValidBlockHeight != null
40
- ? (
41
- await connection.confirmTransaction(
42
- {
43
- signature: signature,
44
- blockhash: transaction.recentBlockhash,
45
- lastValidBlockHeight: transaction.lastValidBlockHeight,
46
- },
47
- options && options.commitment,
48
- )
49
- ).value
50
- : (
51
- await connection.confirmTransaction(
52
- signature,
53
- options && options.commitment,
54
- )
55
- ).value;
41
+ ) {
42
+ status = (
43
+ await connection.confirmTransaction(
44
+ {
45
+ signature: signature,
46
+ blockhash: transaction.recentBlockhash,
47
+ lastValidBlockHeight: transaction.lastValidBlockHeight,
48
+ },
49
+ options && options.commitment,
50
+ )
51
+ ).value;
52
+ } else if (
53
+ transaction.minNonceContextSlot != null &&
54
+ transaction.nonceInfo != null
55
+ ) {
56
+ const {nonceInstruction} = transaction.nonceInfo;
57
+ const nonceAccountPubkey = nonceInstruction.keys[0].pubkey;
58
+ status = (
59
+ await connection.confirmTransaction(
60
+ {
61
+ minContextSlot: transaction.minNonceContextSlot,
62
+ nonceAccountPubkey,
63
+ nonceValue: transaction.nonceInfo.nonce,
64
+ signature,
65
+ },
66
+ options && options.commitment,
67
+ )
68
+ ).value;
69
+ } else {
70
+ status = (
71
+ await connection.confirmTransaction(
72
+ signature,
73
+ options && options.commitment,
74
+ )
75
+ ).value;
76
+ }
56
77
 
57
78
  if (status.err) {
58
79
  throw new Error(