@solana/web3.js 1.41.10 → 1.43.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solana/web3.js",
3
- "version": "1.41.10",
3
+ "version": "1.43.1",
4
4
  "description": "Solana Javascript API",
5
5
  "keywords": [
6
6
  "api",
@@ -59,7 +59,7 @@
59
59
  "@babel/runtime": "^7.12.5",
60
60
  "@ethersproject/sha2": "^5.5.0",
61
61
  "@solana/buffer-layout": "^4.0.0",
62
- "@solana/buffer-layout-utils": "^0.2.0",
62
+ "bigint-buffer": "^1.1.5",
63
63
  "bn.js": "^5.0.0",
64
64
  "borsh": "^0.7.0",
65
65
  "bs58": "^4.0.1",
@@ -110,7 +110,7 @@
110
110
  "eslint": "^7.19.0",
111
111
  "eslint-config-prettier": "^8.0.0",
112
112
  "eslint-plugin-import": "2.26.0",
113
- "eslint-plugin-mocha": "^9.0.0",
113
+ "eslint-plugin-mocha": "^10.0.4",
114
114
  "eslint-plugin-prettier": "^4.0.0",
115
115
  "esm": "^3.2.25",
116
116
  "http-server": "^14.0.0",
@@ -8,6 +8,7 @@ import {
8
8
  } from './instruction';
9
9
  import {PublicKey} from './publickey';
10
10
  import {TransactionInstruction} from './transaction';
11
+ import {u64} from './util/bigint';
11
12
 
12
13
  /**
13
14
  * Compute Budget Instruction class
@@ -76,6 +77,34 @@ export class ComputeBudgetInstruction {
76
77
  return {bytes};
77
78
  }
78
79
 
80
+ /**
81
+ * Decode set compute unit limit compute budget instruction and retrieve the instruction params.
82
+ */
83
+ static decodeSetComputeUnitLimit(
84
+ instruction: TransactionInstruction,
85
+ ): SetComputeUnitLimitParams {
86
+ this.checkProgramId(instruction.programId);
87
+ const {units} = decodeData(
88
+ COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitLimit,
89
+ instruction.data,
90
+ );
91
+ return {units};
92
+ }
93
+
94
+ /**
95
+ * Decode set compute unit price compute budget instruction and retrieve the instruction params.
96
+ */
97
+ static decodeSetComputeUnitPrice(
98
+ instruction: TransactionInstruction,
99
+ ): SetComputeUnitPriceParams {
100
+ this.checkProgramId(instruction.programId);
101
+ const {microLamports} = decodeData(
102
+ COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitPrice,
103
+ instruction.data,
104
+ );
105
+ return {microLamports};
106
+ }
107
+
79
108
  /**
80
109
  * @internal
81
110
  */
@@ -96,11 +125,18 @@ export type ComputeBudgetInstructionType =
96
125
  // It would be preferable for this type to be `keyof ComputeBudgetInstructionInputData`
97
126
  // but Typedoc does not transpile `keyof` expressions.
98
127
  // See https://github.com/TypeStrong/typedoc/issues/1894
99
- 'RequestUnits' | 'RequestHeapFrame';
128
+ | 'RequestUnits'
129
+ | 'RequestHeapFrame'
130
+ | 'SetComputeUnitLimit'
131
+ | 'SetComputeUnitPrice';
100
132
 
101
133
  type ComputeBudgetInstructionInputData = {
102
134
  RequestUnits: IInstructionInputData & Readonly<RequestUnitsParams>;
103
135
  RequestHeapFrame: IInstructionInputData & Readonly<RequestHeapFrameParams>;
136
+ SetComputeUnitLimit: IInstructionInputData &
137
+ Readonly<SetComputeUnitLimitParams>;
138
+ SetComputeUnitPrice: IInstructionInputData &
139
+ Readonly<SetComputeUnitPriceParams>;
104
140
  };
105
141
 
106
142
  /**
@@ -109,8 +145,7 @@ type ComputeBudgetInstructionInputData = {
109
145
  export interface RequestUnitsParams {
110
146
  /** Units to request for transaction-wide compute */
111
147
  units: number;
112
-
113
- /** Additional fee to pay */
148
+ /** Prioritization fee lamports */
114
149
  additionalFee: number;
115
150
  }
116
151
 
@@ -122,6 +157,22 @@ export type RequestHeapFrameParams = {
122
157
  bytes: number;
123
158
  };
124
159
 
160
+ /**
161
+ * Set compute unit limit instruction params
162
+ */
163
+ export interface SetComputeUnitLimitParams {
164
+ /** Transaction-wide compute unit limit */
165
+ units: number;
166
+ }
167
+
168
+ /**
169
+ * Set compute unit price instruction params
170
+ */
171
+ export interface SetComputeUnitPriceParams {
172
+ /** Transaction compute unit price used for prioritization fees */
173
+ microLamports: number | bigint;
174
+ }
175
+
125
176
  /**
126
177
  * An enumeration of valid ComputeBudget InstructionType's
127
178
  * @internal
@@ -147,6 +198,18 @@ export const COMPUTE_BUDGET_INSTRUCTION_LAYOUTS = Object.freeze<{
147
198
  ComputeBudgetInstructionInputData['RequestHeapFrame']
148
199
  >([BufferLayout.u8('instruction'), BufferLayout.u32('bytes')]),
149
200
  },
201
+ SetComputeUnitLimit: {
202
+ index: 2,
203
+ layout: BufferLayout.struct<
204
+ ComputeBudgetInstructionInputData['SetComputeUnitLimit']
205
+ >([BufferLayout.u8('instruction'), BufferLayout.u32('units')]),
206
+ },
207
+ SetComputeUnitPrice: {
208
+ index: 3,
209
+ layout: BufferLayout.struct<
210
+ ComputeBudgetInstructionInputData['SetComputeUnitPrice']
211
+ >([BufferLayout.u8('instruction'), u64('microLamports')]),
212
+ },
150
213
  });
151
214
 
152
215
  /**
@@ -186,4 +249,30 @@ export class ComputeBudgetProgram {
186
249
  data,
187
250
  });
188
251
  }
252
+
253
+ static setComputeUnitLimit(
254
+ params: SetComputeUnitLimitParams,
255
+ ): TransactionInstruction {
256
+ const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitLimit;
257
+ const data = encodeData(type, params);
258
+ return new TransactionInstruction({
259
+ keys: [],
260
+ programId: this.programId,
261
+ data,
262
+ });
263
+ }
264
+
265
+ static setComputeUnitPrice(
266
+ params: SetComputeUnitPriceParams,
267
+ ): TransactionInstruction {
268
+ const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitPrice;
269
+ const data = encodeData(type, {
270
+ microLamports: BigInt(params.microLamports),
271
+ });
272
+ return new TransactionInstruction({
273
+ keys: [],
274
+ programId: this.programId,
275
+ data,
276
+ });
277
+ }
189
278
  }
package/src/connection.ts CHANGED
@@ -284,15 +284,18 @@ export type RpcResponseAndContext<T> = {
284
284
  value: T;
285
285
  };
286
286
 
287
+ export type BlockhashWithExpiryBlockHeight = Readonly<{
288
+ blockhash: Blockhash;
289
+ lastValidBlockHeight: number;
290
+ }>;
291
+
287
292
  /**
288
293
  * A strategy for confirming transactions that uses the last valid
289
294
  * block height for a given blockhash to check for transaction expiration.
290
295
  */
291
- export type BlockheightBasedTransactionConfimationStrategy = {
296
+ export type BlockheightBasedTransactionConfirmationStrategy = {
292
297
  signature: TransactionSignature;
293
- blockhash: Blockhash;
294
- lastValidBlockHeight: number;
295
- };
298
+ } & BlockhashWithExpiryBlockHeight;
296
299
 
297
300
  /**
298
301
  * @internal
@@ -2218,12 +2221,12 @@ export class Connection {
2218
2221
  /** @internal */ _disableBlockhashCaching: boolean = false;
2219
2222
  /** @internal */ _pollingBlockhash: boolean = false;
2220
2223
  /** @internal */ _blockhashInfo: {
2221
- recentBlockhash: Blockhash | null;
2224
+ latestBlockhash: BlockhashWithExpiryBlockHeight | null;
2222
2225
  lastFetch: number;
2223
2226
  simulatedSignatures: Array<string>;
2224
2227
  transactionSignatures: Array<string>;
2225
2228
  } = {
2226
- recentBlockhash: null,
2229
+ latestBlockhash: null,
2227
2230
  lastFetch: 0,
2228
2231
  transactionSignatures: [],
2229
2232
  simulatedSignatures: [],
@@ -2839,7 +2842,7 @@ export class Connection {
2839
2842
  }
2840
2843
 
2841
2844
  confirmTransaction(
2842
- strategy: BlockheightBasedTransactionConfimationStrategy,
2845
+ strategy: BlockheightBasedTransactionConfirmationStrategy,
2843
2846
  commitment?: Commitment,
2844
2847
  ): Promise<RpcResponseAndContext<SignatureResult>>;
2845
2848
 
@@ -2853,7 +2856,7 @@ export class Connection {
2853
2856
  // eslint-disable-next-line no-dupe-class-members
2854
2857
  async confirmTransaction(
2855
2858
  strategy:
2856
- | BlockheightBasedTransactionConfimationStrategy
2859
+ | BlockheightBasedTransactionConfirmationStrategy
2857
2860
  | TransactionSignature,
2858
2861
  commitment?: Commitment,
2859
2862
  ): Promise<RpcResponseAndContext<SignatureResult>> {
@@ -2862,7 +2865,8 @@ export class Connection {
2862
2865
  if (typeof strategy == 'string') {
2863
2866
  rawSignature = strategy;
2864
2867
  } else {
2865
- const config = strategy as BlockheightBasedTransactionConfimationStrategy;
2868
+ const config =
2869
+ strategy as BlockheightBasedTransactionConfirmationStrategy;
2866
2870
  rawSignature = config.signature;
2867
2871
  }
2868
2872
 
@@ -2939,7 +2943,8 @@ export class Connection {
2939
2943
  timeoutMs,
2940
2944
  );
2941
2945
  } else {
2942
- let config = strategy as BlockheightBasedTransactionConfimationStrategy;
2946
+ let config =
2947
+ strategy as BlockheightBasedTransactionConfirmationStrategy;
2943
2948
  (async () => {
2944
2949
  let currentBlockHeight = await checkBlockHeight();
2945
2950
  if (done) return;
@@ -3322,11 +3327,11 @@ export class Connection {
3322
3327
 
3323
3328
  /**
3324
3329
  * Fetch the latest blockhash from the cluster
3325
- * @return {Promise<{blockhash: Blockhash, lastValidBlockHeight: number}>}
3330
+ * @return {Promise<BlockhashWithExpiryBlockHeight>}
3326
3331
  */
3327
3332
  async getLatestBlockhash(
3328
3333
  commitment?: Commitment,
3329
- ): Promise<{blockhash: Blockhash; lastValidBlockHeight: number}> {
3334
+ ): Promise<BlockhashWithExpiryBlockHeight> {
3330
3335
  try {
3331
3336
  const res = await this.getLatestBlockhashAndContext(commitment);
3332
3337
  return res.value;
@@ -3337,13 +3342,11 @@ export class Connection {
3337
3342
 
3338
3343
  /**
3339
3344
  * Fetch the latest blockhash from the cluster
3340
- * @return {Promise<{blockhash: Blockhash, lastValidBlockHeight: number}>}
3345
+ * @return {Promise<BlockhashWithExpiryBlockHeight>}
3341
3346
  */
3342
3347
  async getLatestBlockhashAndContext(
3343
3348
  commitment?: Commitment,
3344
- ): Promise<
3345
- RpcResponseAndContext<{blockhash: Blockhash; lastValidBlockHeight: number}>
3346
- > {
3349
+ ): Promise<RpcResponseAndContext<BlockhashWithExpiryBlockHeight>> {
3347
3350
  const args = this._buildArgs([], commitment);
3348
3351
  const unsafeRes = await this._rpcRequest('getLatestBlockhash', args);
3349
3352
  const res = create(unsafeRes, GetLatestBlockhashRpcResult);
@@ -3989,7 +3992,9 @@ export class Connection {
3989
3992
  /**
3990
3993
  * @internal
3991
3994
  */
3992
- async _recentBlockhash(disableCache: boolean): Promise<Blockhash> {
3995
+ async _blockhashWithExpiryBlockHeight(
3996
+ disableCache: boolean,
3997
+ ): Promise<BlockhashWithExpiryBlockHeight> {
3993
3998
  if (!disableCache) {
3994
3999
  // Wait for polling to finish
3995
4000
  while (this._pollingBlockhash) {
@@ -3997,8 +4002,8 @@ export class Connection {
3997
4002
  }
3998
4003
  const timeSinceFetch = Date.now() - this._blockhashInfo.lastFetch;
3999
4004
  const expired = timeSinceFetch >= BLOCKHASH_CACHE_TIMEOUT_MS;
4000
- if (this._blockhashInfo.recentBlockhash !== null && !expired) {
4001
- return this._blockhashInfo.recentBlockhash;
4005
+ if (this._blockhashInfo.latestBlockhash !== null && !expired) {
4006
+ return this._blockhashInfo.latestBlockhash;
4002
4007
  }
4003
4008
  }
4004
4009
 
@@ -4008,21 +4013,25 @@ export class Connection {
4008
4013
  /**
4009
4014
  * @internal
4010
4015
  */
4011
- async _pollNewBlockhash(): Promise<Blockhash> {
4016
+ async _pollNewBlockhash(): Promise<BlockhashWithExpiryBlockHeight> {
4012
4017
  this._pollingBlockhash = true;
4013
4018
  try {
4014
4019
  const startTime = Date.now();
4020
+ const cachedLatestBlockhash = this._blockhashInfo.latestBlockhash;
4021
+ const cachedBlockhash = cachedLatestBlockhash
4022
+ ? cachedLatestBlockhash.blockhash
4023
+ : null;
4015
4024
  for (let i = 0; i < 50; i++) {
4016
- const {blockhash} = await this.getRecentBlockhash('finalized');
4025
+ const latestBlockhash = await this.getLatestBlockhash('finalized');
4017
4026
 
4018
- if (this._blockhashInfo.recentBlockhash != blockhash) {
4027
+ if (cachedBlockhash !== latestBlockhash.blockhash) {
4019
4028
  this._blockhashInfo = {
4020
- recentBlockhash: blockhash,
4029
+ latestBlockhash,
4021
4030
  lastFetch: Date.now(),
4022
4031
  transactionSignatures: [],
4023
4032
  simulatedSignatures: [],
4024
4033
  };
4025
- return blockhash;
4034
+ return latestBlockhash;
4026
4035
  }
4027
4036
 
4028
4037
  // Sleep for approximately half a slot
@@ -4048,13 +4057,11 @@ export class Connection {
4048
4057
  let transaction;
4049
4058
  if (transactionOrMessage instanceof Transaction) {
4050
4059
  let originalTx: Transaction = transactionOrMessage;
4051
- transaction = new Transaction({
4052
- recentBlockhash: originalTx.recentBlockhash,
4053
- nonceInfo: originalTx.nonceInfo,
4054
- feePayer: originalTx.feePayer,
4055
- signatures: [...originalTx.signatures],
4056
- });
4060
+ transaction = new Transaction();
4061
+ transaction.feePayer = originalTx.feePayer;
4057
4062
  transaction.instructions = transactionOrMessage.instructions;
4063
+ transaction.nonceInfo = originalTx.nonceInfo;
4064
+ transaction.signatures = originalTx.signatures;
4058
4065
  } else {
4059
4066
  transaction = Transaction.populate(transactionOrMessage);
4060
4067
  // HACK: this function relies on mutating the populated transaction
@@ -4066,7 +4073,11 @@ export class Connection {
4066
4073
  } else {
4067
4074
  let disableCache = this._disableBlockhashCaching;
4068
4075
  for (;;) {
4069
- transaction.recentBlockhash = await this._recentBlockhash(disableCache);
4076
+ const latestBlockhash = await this._blockhashWithExpiryBlockHeight(
4077
+ disableCache,
4078
+ );
4079
+ transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
4080
+ transaction.recentBlockhash = latestBlockhash.blockhash;
4070
4081
 
4071
4082
  if (!signers) break;
4072
4083
 
@@ -4154,7 +4165,11 @@ export class Connection {
4154
4165
  } else {
4155
4166
  let disableCache = this._disableBlockhashCaching;
4156
4167
  for (;;) {
4157
- transaction.recentBlockhash = await this._recentBlockhash(disableCache);
4168
+ const latestBlockhash = await this._blockhashWithExpiryBlockHeight(
4169
+ disableCache,
4170
+ );
4171
+ transaction.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
4172
+ transaction.recentBlockhash = latestBlockhash.blockhash;
4158
4173
  transaction.sign(...signers);
4159
4174
  if (!transaction.signature) {
4160
4175
  throw new Error('!signature'); // should never happen
@@ -1,5 +1,4 @@
1
1
  import * as BufferLayout from '@solana/buffer-layout';
2
- import {u64} from '@solana/buffer-layout-utils';
3
2
 
4
3
  import {
5
4
  encodeData,
@@ -13,6 +12,7 @@ import {PublicKey} from './publickey';
13
12
  import {SYSVAR_RECENT_BLOCKHASHES_PUBKEY, SYSVAR_RENT_PUBKEY} from './sysvar';
14
13
  import {Transaction, TransactionInstruction} from './transaction';
15
14
  import {toBuffer} from './util/to-buffer';
15
+ import {u64} from './util/bigint';
16
16
 
17
17
  /**
18
18
  * Create account system transaction params
@@ -599,7 +599,6 @@ export class Transaction {
599
599
 
600
600
  const message = this._compile();
601
601
  this._partialSign(message, ...uniqueSigners);
602
- this._verifySignatures(message.serialize(), true);
603
602
  }
604
603
 
605
604
  /**
@@ -0,0 +1,43 @@
1
+ import {Buffer} from 'buffer';
2
+ import {blob, Layout} from '@solana/buffer-layout';
3
+ import {toBigIntLE, toBufferLE} from 'bigint-buffer';
4
+
5
+ interface EncodeDecode<T> {
6
+ decode(buffer: Buffer, offset?: number): T;
7
+ encode(src: T, buffer: Buffer, offset?: number): number;
8
+ }
9
+
10
+ const encodeDecode = <T>(layout: Layout<T>): EncodeDecode<T> => {
11
+ const decode = layout.decode.bind(layout);
12
+ const encode = layout.encode.bind(layout);
13
+ return {decode, encode};
14
+ };
15
+
16
+ const bigInt =
17
+ (length: number) =>
18
+ (property?: string): Layout<bigint> => {
19
+ const layout = blob(length, property);
20
+ const {encode, decode} = encodeDecode(layout);
21
+
22
+ const bigIntLayout = layout as Layout<unknown> as Layout<bigint>;
23
+
24
+ bigIntLayout.decode = (buffer: Buffer, offset: number) => {
25
+ const src = decode(buffer, offset);
26
+ return toBigIntLE(Buffer.from(src));
27
+ };
28
+
29
+ bigIntLayout.encode = (bigInt: bigint, buffer: Buffer, offset: number) => {
30
+ const src = toBufferLE(bigInt, length);
31
+ return encode(src, buffer, offset);
32
+ };
33
+
34
+ return bigIntLayout;
35
+ };
36
+
37
+ export const u64 = bigInt(8);
38
+
39
+ export const u128 = bigInt(16);
40
+
41
+ export const u192 = bigInt(24);
42
+
43
+ export const u256 = bigInt(32);
@@ -1,6 +1,9 @@
1
1
  import type {Buffer} from 'buffer';
2
2
 
3
- import {Connection} from '../connection';
3
+ import {
4
+ BlockheightBasedTransactionConfirmationStrategy,
5
+ Connection,
6
+ } from '../connection';
4
7
  import type {TransactionSignature} from '../transaction';
5
8
  import type {ConfirmOptions} from '../connection';
6
9
 
@@ -11,14 +14,57 @@ import type {ConfirmOptions} from '../connection';
11
14
  *
12
15
  * @param {Connection} connection
13
16
  * @param {Buffer} rawTransaction
17
+ * @param {BlockheightBasedTransactionConfirmationStrategy} confirmationStrategy
14
18
  * @param {ConfirmOptions} [options]
15
19
  * @returns {Promise<TransactionSignature>}
16
20
  */
17
21
  export async function sendAndConfirmRawTransaction(
18
22
  connection: Connection,
19
23
  rawTransaction: Buffer,
24
+ confirmationStrategy: BlockheightBasedTransactionConfirmationStrategy,
20
25
  options?: ConfirmOptions,
26
+ ): Promise<TransactionSignature>;
27
+
28
+ /**
29
+ * @deprecated Calling `sendAndConfirmRawTransaction()` without a `confirmationStrategy`
30
+ * is no longer supported and will be removed in a future version.
31
+ */
32
+ // eslint-disable-next-line no-redeclare
33
+ export async function sendAndConfirmRawTransaction(
34
+ connection: Connection,
35
+ rawTransaction: Buffer,
36
+ options?: ConfirmOptions,
37
+ ): Promise<TransactionSignature>;
38
+
39
+ // eslint-disable-next-line no-redeclare
40
+ export async function sendAndConfirmRawTransaction(
41
+ connection: Connection,
42
+ rawTransaction: Buffer,
43
+ confirmationStrategyOrConfirmOptions:
44
+ | BlockheightBasedTransactionConfirmationStrategy
45
+ | ConfirmOptions
46
+ | undefined,
47
+ maybeConfirmOptions?: ConfirmOptions,
21
48
  ): Promise<TransactionSignature> {
49
+ let confirmationStrategy:
50
+ | BlockheightBasedTransactionConfirmationStrategy
51
+ | undefined;
52
+ let options: ConfirmOptions | undefined;
53
+ if (
54
+ confirmationStrategyOrConfirmOptions &&
55
+ Object.prototype.hasOwnProperty.call(
56
+ confirmationStrategyOrConfirmOptions,
57
+ 'lastValidBlockHeight',
58
+ )
59
+ ) {
60
+ confirmationStrategy =
61
+ confirmationStrategyOrConfirmOptions as BlockheightBasedTransactionConfirmationStrategy;
62
+ options = maybeConfirmOptions;
63
+ } else {
64
+ options = confirmationStrategyOrConfirmOptions as
65
+ | ConfirmOptions
66
+ | undefined;
67
+ }
22
68
  const sendOptions = options && {
23
69
  skipPreflight: options.skipPreflight,
24
70
  preflightCommitment: options.preflightCommitment || options.commitment,
@@ -29,12 +75,11 @@ export async function sendAndConfirmRawTransaction(
29
75
  sendOptions,
30
76
  );
31
77
 
32
- const status = (
33
- await connection.confirmTransaction(
34
- signature,
35
- options && options.commitment,
36
- )
37
- ).value;
78
+ const commitment = options && options.commitment;
79
+ const confirmationPromise = confirmationStrategy
80
+ ? connection.confirmTransaction(confirmationStrategy, commitment)
81
+ : connection.confirmTransaction(signature, commitment);
82
+ const status = (await confirmationPromise).value;
38
83
 
39
84
  if (status.err) {
40
85
  throw new Error(