@solana/web3.js 1.53.0 → 1.55.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.
Files changed (39) hide show
  1. package/lib/index.browser.cjs.js +459 -1825
  2. package/lib/index.browser.cjs.js.map +1 -1
  3. package/lib/index.browser.esm.js +455 -1826
  4. package/lib/index.browser.esm.js.map +1 -1
  5. package/lib/index.cjs.js +462 -1847
  6. package/lib/index.cjs.js.map +1 -1
  7. package/lib/index.d.ts +114 -12
  8. package/lib/index.esm.js +458 -1848
  9. package/lib/index.esm.js.map +1 -1
  10. package/lib/index.iife.js +19272 -25771
  11. package/lib/index.iife.js.map +1 -1
  12. package/lib/index.iife.min.js +8 -5
  13. package/lib/index.iife.min.js.map +1 -1
  14. package/lib/index.native.js +459 -1824
  15. package/lib/index.native.js.map +1 -1
  16. package/package.json +5 -7
  17. package/src/account.ts +18 -9
  18. package/src/connection.ts +11 -9
  19. package/src/keypair.ts +19 -24
  20. package/src/layout.ts +7 -0
  21. package/src/message/index.ts +19 -6
  22. package/src/message/legacy.ts +58 -9
  23. package/src/message/v0.ts +324 -0
  24. package/src/message/versioned.ts +36 -0
  25. package/src/programs/ed25519.ts +2 -2
  26. package/src/programs/secp256k1.ts +6 -5
  27. package/src/programs/vote.ts +21 -0
  28. package/src/publickey.ts +14 -73
  29. package/src/transaction/constants.ts +2 -0
  30. package/src/transaction/index.ts +1 -0
  31. package/src/transaction/legacy.ts +3 -5
  32. package/src/transaction/versioned.ts +105 -0
  33. package/src/utils/ed25519.ts +46 -0
  34. package/src/utils/index.ts +1 -0
  35. package/src/utils/makeWebsocketUrl.ts +22 -16
  36. package/src/utils/secp256k1.ts +18 -0
  37. package/src/validator-info.ts +3 -5
  38. package/src/utils/__forks__/react-native/url-impl.ts +0 -2
  39. package/src/utils/url-impl.ts +0 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solana/web3.js",
3
- "version": "1.53.0",
3
+ "version": "1.55.0",
4
4
  "description": "Solana Javascript API",
5
5
  "keywords": [
6
6
  "api",
@@ -58,7 +58,9 @@
58
58
  },
59
59
  "dependencies": {
60
60
  "@babel/runtime": "^7.12.5",
61
- "@ethersproject/sha2": "^5.5.0",
61
+ "@noble/ed25519": "^1.7.0",
62
+ "@noble/hashes": "^1.1.2",
63
+ "@noble/secp256k1": "^1.6.3",
62
64
  "@solana/buffer-layout": "^4.0.0",
63
65
  "bigint-buffer": "^1.1.5",
64
66
  "bn.js": "^5.0.0",
@@ -69,11 +71,8 @@
69
71
  "jayson": "^3.4.4",
70
72
  "js-sha3": "^0.8.0",
71
73
  "node-fetch": "2",
72
- "react-native-url-polyfill": "^1.3.0",
73
74
  "rpc-websockets": "^7.5.0",
74
- "secp256k1": "^4.0.2",
75
- "superstruct": "^0.14.2",
76
- "tweetnacl": "^1.0.3"
75
+ "superstruct": "^0.14.2"
77
76
  },
78
77
  "devDependencies": {
79
78
  "@babel/core": "^7.12.13",
@@ -101,7 +100,6 @@
101
100
  "@types/mz": "^2.7.3",
102
101
  "@types/node": "^17.0.24",
103
102
  "@types/node-fetch": "2",
104
- "@types/secp256k1": "^4.0.1",
105
103
  "@types/sinon": "^10.0.0",
106
104
  "@types/sinon-chai": "^3.2.8",
107
105
  "@typescript-eslint/eslint-plugin": "^4.14.2",
package/src/account.ts CHANGED
@@ -1,7 +1,6 @@
1
- import nacl from 'tweetnacl';
2
- import type {SignKeyPair as KeyPair} from 'tweetnacl';
3
- import type {Buffer} from 'buffer';
1
+ import {Buffer} from 'buffer';
4
2
 
3
+ import {generatePrivateKey, getPublicKey} from './utils/ed25519';
5
4
  import {toBuffer} from './utils/to-buffer';
6
5
  import {PublicKey} from './publickey';
7
6
 
@@ -12,7 +11,9 @@ import {PublicKey} from './publickey';
12
11
  */
13
12
  export class Account {
14
13
  /** @internal */
15
- _keypair: KeyPair;
14
+ private _publicKey: Buffer;
15
+ /** @internal */
16
+ private _secretKey: Buffer;
16
17
 
17
18
  /**
18
19
  * Create a new Account object
@@ -24,9 +25,15 @@ export class Account {
24
25
  */
25
26
  constructor(secretKey?: Buffer | Uint8Array | Array<number>) {
26
27
  if (secretKey) {
27
- this._keypair = nacl.sign.keyPair.fromSecretKey(toBuffer(secretKey));
28
+ const secretKeyBuffer = toBuffer(secretKey);
29
+ if (secretKey.length !== 64) {
30
+ throw new Error('bad secret key size');
31
+ }
32
+ this._publicKey = secretKeyBuffer.slice(32, 64);
33
+ this._secretKey = secretKeyBuffer.slice(0, 32);
28
34
  } else {
29
- this._keypair = nacl.sign.keyPair();
35
+ this._secretKey = toBuffer(generatePrivateKey());
36
+ this._publicKey = toBuffer(getPublicKey(this._secretKey));
30
37
  }
31
38
  }
32
39
 
@@ -34,13 +41,15 @@ export class Account {
34
41
  * The public key for this account
35
42
  */
36
43
  get publicKey(): PublicKey {
37
- return new PublicKey(this._keypair.publicKey);
44
+ return new PublicKey(this._publicKey);
38
45
  }
39
46
 
40
47
  /**
41
- * The **unencrypted** secret key for this account
48
+ * The **unencrypted** secret key for this account. The first 32 bytes
49
+ * is the private scalar and the last 32 bytes is the public key.
50
+ * Read more: https://blog.mozilla.org/warner/2011/11/29/ed25519-keys/
42
51
  */
43
52
  get secretKey(): Buffer {
44
- return toBuffer(this._keypair.secretKey);
53
+ return Buffer.concat([this._secretKey, this._publicKey], 64);
45
54
  }
46
55
  }
package/src/connection.ts CHANGED
@@ -43,7 +43,6 @@ import {
43
43
  TransactionExpiredTimeoutError,
44
44
  } from './transaction/expiry-custom-errors';
45
45
  import {makeWebsocketUrl} from './utils/makeWebsocketUrl';
46
- import {URL} from './utils/url-impl';
47
46
  import type {Blockhash} from './blockhash';
48
47
  import type {FeeCalculator} from './fee-calculator';
49
48
  import type {TransactionSignature} from './transaction';
@@ -305,6 +304,14 @@ export type BlockheightBasedTransactionConfirmationStrategy = {
305
304
  signature: TransactionSignature;
306
305
  } & BlockhashWithExpiryBlockHeight;
307
306
 
307
+ /* @internal */
308
+ function assertEndpointUrl(putativeUrl: string) {
309
+ if (/^https?:/.test(putativeUrl) === false) {
310
+ throw new TypeError('Endpoint URL must start with `http:` or `https:`.');
311
+ }
312
+ return putativeUrl;
313
+ }
314
+
308
315
  /** @internal */
309
316
  function extractCommitmentFromConfig<TConfig>(
310
317
  commitmentOrConfig?: Commitment | ({commitment?: Commitment} & TConfig),
@@ -1117,7 +1124,6 @@ export type PerfSample = {
1117
1124
 
1118
1125
  function createRpcClient(
1119
1126
  url: string,
1120
- useHttps: boolean,
1121
1127
  httpHeaders?: HttpHeaders,
1122
1128
  customFetch?: FetchFn,
1123
1129
  fetchMiddleware?: FetchMiddleware,
@@ -1126,7 +1132,7 @@ function createRpcClient(
1126
1132
  const fetch = customFetch ? customFetch : fetchImpl;
1127
1133
  let agentManager: AgentManager | undefined;
1128
1134
  if (!process.env.BROWSER) {
1129
- agentManager = new AgentManager(useHttps);
1135
+ agentManager = new AgentManager(url.startsWith('https:') /* useHttps */);
1130
1136
  }
1131
1137
 
1132
1138
  let fetchWithMiddleware: FetchFn | undefined;
@@ -2493,9 +2499,6 @@ export class Connection {
2493
2499
  endpoint: string,
2494
2500
  commitmentOrConfig?: Commitment | ConnectionConfig,
2495
2501
  ) {
2496
- let url = new URL(endpoint);
2497
- const useHttps = url.protocol === 'https:';
2498
-
2499
2502
  let wsEndpoint;
2500
2503
  let httpHeaders;
2501
2504
  let fetch;
@@ -2514,12 +2517,11 @@ export class Connection {
2514
2517
  disableRetryOnRateLimit = commitmentOrConfig.disableRetryOnRateLimit;
2515
2518
  }
2516
2519
 
2517
- this._rpcEndpoint = endpoint;
2520
+ this._rpcEndpoint = assertEndpointUrl(endpoint);
2518
2521
  this._rpcWsEndpoint = wsEndpoint || makeWebsocketUrl(endpoint);
2519
2522
 
2520
2523
  this._rpcClient = createRpcClient(
2521
- url.toString(),
2522
- useHttps,
2524
+ endpoint,
2523
2525
  httpHeaders,
2524
2526
  fetch,
2525
2527
  fetchMiddleware,
package/src/keypair.ts CHANGED
@@ -1,5 +1,4 @@
1
- import nacl from 'tweetnacl';
2
-
1
+ import {generateKeypair, getPublicKey, Ed25519Keypair} from './utils/ed25519';
3
2
  import {PublicKey} from './publickey';
4
3
 
5
4
  /**
@@ -10,14 +9,6 @@ export interface Signer {
10
9
  secretKey: Uint8Array;
11
10
  }
12
11
 
13
- /**
14
- * Ed25519 Keypair
15
- */
16
- export interface Ed25519Keypair {
17
- publicKey: Uint8Array;
18
- secretKey: Uint8Array;
19
- }
20
-
21
12
  /**
22
13
  * An account keypair used for signing transactions.
23
14
  */
@@ -31,18 +22,14 @@ export class Keypair {
31
22
  * @param keypair ed25519 keypair
32
23
  */
33
24
  constructor(keypair?: Ed25519Keypair) {
34
- if (keypair) {
35
- this._keypair = keypair;
36
- } else {
37
- this._keypair = nacl.sign.keyPair();
38
- }
25
+ this._keypair = keypair ?? generateKeypair();
39
26
  }
40
27
 
41
28
  /**
42
29
  * Generate a new random keypair
43
30
  */
44
31
  static generate(): Keypair {
45
- return new Keypair(nacl.sign.keyPair());
32
+ return new Keypair(generateKeypair());
46
33
  }
47
34
 
48
35
  /**
@@ -61,16 +48,20 @@ export class Keypair {
61
48
  secretKey: Uint8Array,
62
49
  options?: {skipValidation?: boolean},
63
50
  ): Keypair {
64
- const keypair = nacl.sign.keyPair.fromSecretKey(secretKey);
51
+ if (secretKey.byteLength !== 64) {
52
+ throw new Error('bad secret key size');
53
+ }
54
+ const publicKey = secretKey.slice(32, 64);
65
55
  if (!options || !options.skipValidation) {
66
- const encoder = new TextEncoder();
67
- const signData = encoder.encode('@solana/web3.js-validation-v1');
68
- const signature = nacl.sign.detached(signData, keypair.secretKey);
69
- if (!nacl.sign.detached.verify(signData, signature, keypair.publicKey)) {
70
- throw new Error('provided secretKey is invalid');
56
+ const privateScalar = secretKey.slice(0, 32);
57
+ const computedPublicKey = getPublicKey(privateScalar);
58
+ for (let ii = 0; ii < 32; ii++) {
59
+ if (publicKey[ii] !== computedPublicKey[ii]) {
60
+ throw new Error('provided secretKey is invalid');
61
+ }
71
62
  }
72
63
  }
73
- return new Keypair(keypair);
64
+ return new Keypair({publicKey, secretKey});
74
65
  }
75
66
 
76
67
  /**
@@ -79,7 +70,11 @@ export class Keypair {
79
70
  * @param seed seed byte array
80
71
  */
81
72
  static fromSeed(seed: Uint8Array): Keypair {
82
- return new Keypair(nacl.sign.keyPair.fromSeed(seed));
73
+ const publicKey = getPublicKey(seed);
74
+ const secretKey = new Uint8Array(64);
75
+ secretKey.set(seed);
76
+ secretKey.set(publicKey, 32);
77
+ return new Keypair({publicKey, secretKey});
83
78
  }
84
79
 
85
80
  /**
package/src/layout.ts CHANGED
@@ -8,6 +8,13 @@ export const publicKey = (property: string = 'publicKey') => {
8
8
  return BufferLayout.blob(32, property);
9
9
  };
10
10
 
11
+ /**
12
+ * Layout for a signature
13
+ */
14
+ export const signature = (property: string = 'signature') => {
15
+ return BufferLayout.blob(64, property);
16
+ };
17
+
11
18
  /**
12
19
  * Layout for a 64bit unsigned value
13
20
  */
@@ -1,4 +1,8 @@
1
+ import {PublicKey} from '../publickey';
2
+
1
3
  export * from './legacy';
4
+ export * from './versioned';
5
+ export * from './v0';
2
6
 
3
7
  /**
4
8
  * The message header, identifying signed and read-only account
@@ -15,18 +19,27 @@ export type MessageHeader = {
15
19
  numReadonlyUnsignedAccounts: number;
16
20
  };
17
21
 
22
+ /**
23
+ * An address table lookup used to load additional accounts
24
+ */
25
+ export type MessageAddressTableLookup = {
26
+ accountKey: PublicKey;
27
+ writableIndexes: Array<number>;
28
+ readonlyIndexes: Array<number>;
29
+ };
30
+
18
31
  /**
19
32
  * An instruction to execute by a program
20
33
  *
21
34
  * @property {number} programIdIndex
22
- * @property {number[]} accounts
23
- * @property {string} data
35
+ * @property {number[]} accountKeyIndexes
36
+ * @property {Uint8Array} data
24
37
  */
25
- export type CompiledInstruction = {
38
+ export type MessageCompiledInstruction = {
26
39
  /** Index into the transaction keys array indicating the program account that executes this instruction */
27
40
  programIdIndex: number;
28
41
  /** Ordered indices into the transaction keys array indicating which accounts to pass to the program */
29
- accounts: number[];
30
- /** The program input data encoded as base 58 */
31
- data: string;
42
+ accountKeyIndexes: number[];
43
+ /** The program input data */
44
+ data: Uint8Array;
32
45
  };
@@ -2,13 +2,33 @@ import bs58 from 'bs58';
2
2
  import {Buffer} from 'buffer';
3
3
  import * as BufferLayout from '@solana/buffer-layout';
4
4
 
5
- import {PublicKey} from '../publickey';
5
+ import {PublicKey, PUBLIC_KEY_LENGTH} from '../publickey';
6
6
  import type {Blockhash} from '../blockhash';
7
7
  import * as Layout from '../layout';
8
- import {PACKET_DATA_SIZE} from '../transaction/constants';
8
+ import {PACKET_DATA_SIZE, VERSION_PREFIX_MASK} from '../transaction/constants';
9
9
  import * as shortvec from '../utils/shortvec-encoding';
10
10
  import {toBuffer} from '../utils/to-buffer';
11
- import {CompiledInstruction, MessageHeader} from './index';
11
+ import {
12
+ MessageHeader,
13
+ MessageAddressTableLookup,
14
+ MessageCompiledInstruction,
15
+ } from './index';
16
+
17
+ /**
18
+ * An instruction to execute by a program
19
+ *
20
+ * @property {number} programIdIndex
21
+ * @property {number[]} accounts
22
+ * @property {string} data
23
+ */
24
+ export type CompiledInstruction = {
25
+ /** Index into the transaction keys array indicating the program account that executes this instruction */
26
+ programIdIndex: number;
27
+ /** Ordered indices into the transaction keys array indicating which accounts to pass to the program */
28
+ accounts: number[];
29
+ /** The program input data encoded as base 58 */
30
+ data: string;
31
+ };
12
32
 
13
33
  /**
14
34
  * Message constructor arguments
@@ -24,8 +44,6 @@ export type MessageArgs = {
24
44
  instructions: CompiledInstruction[];
25
45
  };
26
46
 
27
- const PUBKEY_LENGTH = 32;
28
-
29
47
  /**
30
48
  * List of instructions to be processed atomically
31
49
  */
@@ -53,6 +71,28 @@ export class Message {
53
71
  );
54
72
  }
55
73
 
74
+ get version(): 'legacy' {
75
+ return 'legacy';
76
+ }
77
+
78
+ get staticAccountKeys(): Array<PublicKey> {
79
+ return this.accountKeys;
80
+ }
81
+
82
+ get compiledInstructions(): Array<MessageCompiledInstruction> {
83
+ return this.instructions.map(
84
+ (ix): MessageCompiledInstruction => ({
85
+ programIdIndex: ix.programIdIndex,
86
+ accountKeyIndexes: ix.accounts,
87
+ data: bs58.decode(ix.data),
88
+ }),
89
+ );
90
+ }
91
+
92
+ get addressTableLookups(): Array<MessageAddressTableLookup> {
93
+ return [];
94
+ }
95
+
56
96
  isAccountSigner(index: number): boolean {
57
97
  return index < this.header.numRequiredSignatures;
58
98
  }
@@ -193,19 +233,28 @@ export class Message {
193
233
  let byteArray = [...buffer];
194
234
 
195
235
  const numRequiredSignatures = byteArray.shift() as number;
236
+ if (
237
+ numRequiredSignatures !==
238
+ (numRequiredSignatures & VERSION_PREFIX_MASK)
239
+ ) {
240
+ throw new Error(
241
+ 'Versioned messages must be deserialized with VersionedMessage.deserialize()',
242
+ );
243
+ }
244
+
196
245
  const numReadonlySignedAccounts = byteArray.shift() as number;
197
246
  const numReadonlyUnsignedAccounts = byteArray.shift() as number;
198
247
 
199
248
  const accountCount = shortvec.decodeLength(byteArray);
200
249
  let accountKeys = [];
201
250
  for (let i = 0; i < accountCount; i++) {
202
- const account = byteArray.slice(0, PUBKEY_LENGTH);
203
- byteArray = byteArray.slice(PUBKEY_LENGTH);
251
+ const account = byteArray.slice(0, PUBLIC_KEY_LENGTH);
252
+ byteArray = byteArray.slice(PUBLIC_KEY_LENGTH);
204
253
  accountKeys.push(bs58.encode(Buffer.from(account)));
205
254
  }
206
255
 
207
- const recentBlockhash = byteArray.slice(0, PUBKEY_LENGTH);
208
- byteArray = byteArray.slice(PUBKEY_LENGTH);
256
+ const recentBlockhash = byteArray.slice(0, PUBLIC_KEY_LENGTH);
257
+ byteArray = byteArray.slice(PUBLIC_KEY_LENGTH);
209
258
 
210
259
  const instructionCount = shortvec.decodeLength(byteArray);
211
260
  let instructions: CompiledInstruction[] = [];