@solana/web3.js 0.0.0-development → 0.0.0-pr-29130

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 (47) hide show
  1. package/README.md +18 -16
  2. package/lib/index.browser.cjs.js +1955 -1660
  3. package/lib/index.browser.cjs.js.map +1 -1
  4. package/lib/index.browser.esm.js +2058 -1770
  5. package/lib/index.browser.esm.js.map +1 -1
  6. package/lib/index.cjs.js +4733 -1870
  7. package/lib/index.cjs.js.map +1 -1
  8. package/lib/index.d.ts +3451 -2821
  9. package/lib/index.esm.js +4761 -1909
  10. package/lib/index.esm.js.map +1 -1
  11. package/lib/index.iife.js +5212 -5553
  12. package/lib/index.iife.js.map +1 -1
  13. package/lib/index.iife.min.js +7 -14
  14. package/lib/index.iife.min.js.map +1 -1
  15. package/lib/index.native.js +1955 -1660
  16. package/lib/index.native.js.map +1 -1
  17. package/package.json +18 -21
  18. package/src/account.ts +19 -10
  19. package/src/bpf-loader.ts +2 -2
  20. package/src/connection.ts +1377 -185
  21. package/src/epoch-schedule.ts +1 -1
  22. package/src/keypair.ts +20 -25
  23. package/src/layout.ts +29 -0
  24. package/src/message/account-keys.ts +79 -0
  25. package/src/message/compiled-keys.ts +165 -0
  26. package/src/message/index.ts +21 -6
  27. package/src/message/legacy.ts +103 -16
  28. package/src/message/v0.ts +496 -0
  29. package/src/message/versioned.ts +36 -0
  30. package/src/nonce-account.ts +7 -3
  31. package/src/programs/address-lookup-table/state.ts +1 -1
  32. package/src/programs/compute-budget.ts +3 -0
  33. package/src/programs/ed25519.ts +2 -2
  34. package/src/programs/secp256k1.ts +5 -7
  35. package/src/programs/vote.ts +109 -2
  36. package/src/publickey.ts +25 -73
  37. package/src/transaction/constants.ts +2 -0
  38. package/src/transaction/expiry-custom-errors.ts +13 -0
  39. package/src/transaction/index.ts +2 -0
  40. package/src/transaction/legacy.ts +46 -9
  41. package/src/transaction/message.ts +140 -0
  42. package/src/transaction/versioned.ts +126 -0
  43. package/src/utils/ed25519.ts +46 -0
  44. package/src/utils/index.ts +1 -0
  45. package/src/utils/send-and-confirm-raw-transaction.ts +13 -0
  46. package/src/utils/send-and-confirm-transaction.ts +53 -19
  47. package/src/agent-manager.ts +0 -44
@@ -26,7 +26,7 @@ function nextPowerOfTwo(n: number) {
26
26
  /**
27
27
  * Epoch schedule
28
28
  * (see https://docs.solana.com/terminology#epoch)
29
- * Can be retrieved with the {@link connection.getEpochSchedule} method
29
+ * Can be retrieved with the {@link Connection.getEpochSchedule} method
30
30
  */
31
31
  export class EpochSchedule {
32
32
  /** The maximum number of slots in each epoch */
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
  /**
@@ -93,6 +88,6 @@ export class Keypair {
93
88
  * The raw secret key for this keypair
94
89
  */
95
90
  get secretKey(): Uint8Array {
96
- return this._keypair.secretKey;
91
+ return new Uint8Array(this._keypair.secretKey);
97
92
  }
98
93
  }
package/src/layout.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import {Buffer} from 'buffer';
2
2
  import * as BufferLayout from '@solana/buffer-layout';
3
3
 
4
+ import {VoteAuthorizeWithSeedArgs} from './programs/vote';
5
+
4
6
  /**
5
7
  * Layout for a public key
6
8
  */
@@ -8,6 +10,13 @@ export const publicKey = (property: string = 'publicKey') => {
8
10
  return BufferLayout.blob(32, property);
9
11
  };
10
12
 
13
+ /**
14
+ * Layout for a signature
15
+ */
16
+ export const signature = (property: string = 'signature') => {
17
+ return BufferLayout.blob(64, property);
18
+ };
19
+
11
20
  /**
12
21
  * Layout for a 64bit unsigned value
13
22
  */
@@ -134,6 +143,23 @@ export const voteInit = (property: string = 'voteInit') => {
134
143
  );
135
144
  };
136
145
 
146
+ /**
147
+ * Layout for a VoteAuthorizeWithSeedArgs object
148
+ */
149
+ export const voteAuthorizeWithSeedArgs = (
150
+ property: string = 'voteAuthorizeWithSeedArgs',
151
+ ) => {
152
+ return BufferLayout.struct<VoteAuthorizeWithSeedArgs>(
153
+ [
154
+ BufferLayout.u32('voteAuthorizationType'),
155
+ publicKey('currentAuthorityDerivedKeyOwnerPubkey'),
156
+ rustString('currentAuthorityDerivedKeySeed'),
157
+ publicKey('newAuthorized'),
158
+ ],
159
+ property,
160
+ );
161
+ };
162
+
137
163
  export function getAlloc(type: any, fields: any): number {
138
164
  const getItemAlloc = (item: any): number => {
139
165
  if (item.span >= 0) {
@@ -145,6 +171,9 @@ export function getAlloc(type: any, fields: any): number {
145
171
  if (Array.isArray(field)) {
146
172
  return field.length * getItemAlloc(item.elementLayout);
147
173
  }
174
+ } else if ('fields' in item) {
175
+ // This is a `Structure` whose size needs to be recursively measured.
176
+ return getAlloc({layout: item}, fields[item.property]);
148
177
  }
149
178
  // Couldn't determine allocated size of layout
150
179
  return 0;
@@ -0,0 +1,79 @@
1
+ import {LoadedAddresses} from '../connection';
2
+ import {PublicKey} from '../publickey';
3
+ import {TransactionInstruction} from '../transaction';
4
+ import {MessageCompiledInstruction} from './index';
5
+
6
+ export type AccountKeysFromLookups = LoadedAddresses;
7
+
8
+ export class MessageAccountKeys {
9
+ staticAccountKeys: Array<PublicKey>;
10
+ accountKeysFromLookups?: AccountKeysFromLookups;
11
+
12
+ constructor(
13
+ staticAccountKeys: Array<PublicKey>,
14
+ accountKeysFromLookups?: AccountKeysFromLookups,
15
+ ) {
16
+ this.staticAccountKeys = staticAccountKeys;
17
+ this.accountKeysFromLookups = accountKeysFromLookups;
18
+ }
19
+
20
+ keySegments(): Array<Array<PublicKey>> {
21
+ const keySegments = [this.staticAccountKeys];
22
+ if (this.accountKeysFromLookups) {
23
+ keySegments.push(this.accountKeysFromLookups.writable);
24
+ keySegments.push(this.accountKeysFromLookups.readonly);
25
+ }
26
+ return keySegments;
27
+ }
28
+
29
+ get(index: number): PublicKey | undefined {
30
+ for (const keySegment of this.keySegments()) {
31
+ if (index < keySegment.length) {
32
+ return keySegment[index];
33
+ } else {
34
+ index -= keySegment.length;
35
+ }
36
+ }
37
+ return;
38
+ }
39
+
40
+ get length(): number {
41
+ return this.keySegments().flat().length;
42
+ }
43
+
44
+ compileInstructions(
45
+ instructions: Array<TransactionInstruction>,
46
+ ): Array<MessageCompiledInstruction> {
47
+ // Bail early if any account indexes would overflow a u8
48
+ const U8_MAX = 255;
49
+ if (this.length > U8_MAX + 1) {
50
+ throw new Error('Account index overflow encountered during compilation');
51
+ }
52
+
53
+ const keyIndexMap = new Map();
54
+ this.keySegments()
55
+ .flat()
56
+ .forEach((key, index) => {
57
+ keyIndexMap.set(key.toBase58(), index);
58
+ });
59
+
60
+ const findKeyIndex = (key: PublicKey) => {
61
+ const keyIndex = keyIndexMap.get(key.toBase58());
62
+ if (keyIndex === undefined)
63
+ throw new Error(
64
+ 'Encountered an unknown instruction account key during compilation',
65
+ );
66
+ return keyIndex;
67
+ };
68
+
69
+ return instructions.map((instruction): MessageCompiledInstruction => {
70
+ return {
71
+ programIdIndex: findKeyIndex(instruction.programId),
72
+ accountKeyIndexes: instruction.keys.map(meta =>
73
+ findKeyIndex(meta.pubkey),
74
+ ),
75
+ data: instruction.data,
76
+ };
77
+ });
78
+ }
79
+ }
@@ -0,0 +1,165 @@
1
+ import {MessageHeader, MessageAddressTableLookup} from './index';
2
+ import {AccountKeysFromLookups} from './account-keys';
3
+ import {AddressLookupTableAccount} from '../programs';
4
+ import {TransactionInstruction} from '../transaction';
5
+ import assert from '../utils/assert';
6
+ import {PublicKey} from '../publickey';
7
+
8
+ export type CompiledKeyMeta = {
9
+ isSigner: boolean;
10
+ isWritable: boolean;
11
+ isInvoked: boolean;
12
+ };
13
+
14
+ type KeyMetaMap = Map<string, CompiledKeyMeta>;
15
+
16
+ export class CompiledKeys {
17
+ payer: PublicKey;
18
+ keyMetaMap: KeyMetaMap;
19
+
20
+ constructor(payer: PublicKey, keyMetaMap: KeyMetaMap) {
21
+ this.payer = payer;
22
+ this.keyMetaMap = keyMetaMap;
23
+ }
24
+
25
+ static compile(
26
+ instructions: Array<TransactionInstruction>,
27
+ payer: PublicKey,
28
+ ): CompiledKeys {
29
+ const keyMetaMap: KeyMetaMap = new Map();
30
+ const getOrInsertDefault = (pubkey: PublicKey): CompiledKeyMeta => {
31
+ const address = pubkey.toBase58();
32
+ let keyMeta = keyMetaMap.get(address);
33
+ if (keyMeta === undefined) {
34
+ keyMeta = {
35
+ isSigner: false,
36
+ isWritable: false,
37
+ isInvoked: false,
38
+ };
39
+ keyMetaMap.set(address, keyMeta);
40
+ }
41
+ return keyMeta;
42
+ };
43
+
44
+ const payerKeyMeta = getOrInsertDefault(payer);
45
+ payerKeyMeta.isSigner = true;
46
+ payerKeyMeta.isWritable = true;
47
+
48
+ for (const ix of instructions) {
49
+ getOrInsertDefault(ix.programId).isInvoked = true;
50
+ for (const accountMeta of ix.keys) {
51
+ const keyMeta = getOrInsertDefault(accountMeta.pubkey);
52
+ keyMeta.isSigner ||= accountMeta.isSigner;
53
+ keyMeta.isWritable ||= accountMeta.isWritable;
54
+ }
55
+ }
56
+
57
+ return new CompiledKeys(payer, keyMetaMap);
58
+ }
59
+
60
+ getMessageComponents(): [MessageHeader, Array<PublicKey>] {
61
+ const mapEntries = [...this.keyMetaMap.entries()];
62
+ assert(mapEntries.length <= 256, 'Max static account keys length exceeded');
63
+
64
+ const writableSigners = mapEntries.filter(
65
+ ([, meta]) => meta.isSigner && meta.isWritable,
66
+ );
67
+ const readonlySigners = mapEntries.filter(
68
+ ([, meta]) => meta.isSigner && !meta.isWritable,
69
+ );
70
+ const writableNonSigners = mapEntries.filter(
71
+ ([, meta]) => !meta.isSigner && meta.isWritable,
72
+ );
73
+ const readonlyNonSigners = mapEntries.filter(
74
+ ([, meta]) => !meta.isSigner && !meta.isWritable,
75
+ );
76
+
77
+ const header: MessageHeader = {
78
+ numRequiredSignatures: writableSigners.length + readonlySigners.length,
79
+ numReadonlySignedAccounts: readonlySigners.length,
80
+ numReadonlyUnsignedAccounts: readonlyNonSigners.length,
81
+ };
82
+
83
+ // sanity checks
84
+ {
85
+ assert(
86
+ writableSigners.length > 0,
87
+ 'Expected at least one writable signer key',
88
+ );
89
+ const [payerAddress] = writableSigners[0];
90
+ assert(
91
+ payerAddress === this.payer.toBase58(),
92
+ 'Expected first writable signer key to be the fee payer',
93
+ );
94
+ }
95
+
96
+ const staticAccountKeys = [
97
+ ...writableSigners.map(([address]) => new PublicKey(address)),
98
+ ...readonlySigners.map(([address]) => new PublicKey(address)),
99
+ ...writableNonSigners.map(([address]) => new PublicKey(address)),
100
+ ...readonlyNonSigners.map(([address]) => new PublicKey(address)),
101
+ ];
102
+
103
+ return [header, staticAccountKeys];
104
+ }
105
+
106
+ extractTableLookup(
107
+ lookupTable: AddressLookupTableAccount,
108
+ ): [MessageAddressTableLookup, AccountKeysFromLookups] | undefined {
109
+ const [writableIndexes, drainedWritableKeys] =
110
+ this.drainKeysFoundInLookupTable(
111
+ lookupTable.state.addresses,
112
+ keyMeta =>
113
+ !keyMeta.isSigner && !keyMeta.isInvoked && keyMeta.isWritable,
114
+ );
115
+ const [readonlyIndexes, drainedReadonlyKeys] =
116
+ this.drainKeysFoundInLookupTable(
117
+ lookupTable.state.addresses,
118
+ keyMeta =>
119
+ !keyMeta.isSigner && !keyMeta.isInvoked && !keyMeta.isWritable,
120
+ );
121
+
122
+ // Don't extract lookup if no keys were found
123
+ if (writableIndexes.length === 0 && readonlyIndexes.length === 0) {
124
+ return;
125
+ }
126
+
127
+ return [
128
+ {
129
+ accountKey: lookupTable.key,
130
+ writableIndexes,
131
+ readonlyIndexes,
132
+ },
133
+ {
134
+ writable: drainedWritableKeys,
135
+ readonly: drainedReadonlyKeys,
136
+ },
137
+ ];
138
+ }
139
+
140
+ /** @internal */
141
+ private drainKeysFoundInLookupTable(
142
+ lookupTableEntries: Array<PublicKey>,
143
+ keyMetaFilter: (keyMeta: CompiledKeyMeta) => boolean,
144
+ ): [Array<number>, Array<PublicKey>] {
145
+ const lookupTableIndexes = new Array();
146
+ const drainedKeys = new Array();
147
+
148
+ for (const [address, keyMeta] of this.keyMetaMap.entries()) {
149
+ if (keyMetaFilter(keyMeta)) {
150
+ const key = new PublicKey(address);
151
+ const lookupTableIndex = lookupTableEntries.findIndex(entry =>
152
+ entry.equals(key),
153
+ );
154
+ if (lookupTableIndex >= 0) {
155
+ assert(lookupTableIndex < 256, 'Max lookup table index exceeded');
156
+ lookupTableIndexes.push(lookupTableIndex);
157
+ drainedKeys.push(key);
158
+ this.keyMetaMap.delete(address);
159
+ }
160
+ }
161
+ }
162
+
163
+ return [lookupTableIndexes, drainedKeys];
164
+ }
165
+ }
@@ -1,4 +1,10 @@
1
+ import {PublicKey} from '../publickey';
2
+
3
+ export * from './account-keys';
4
+ // note: compiled-keys is internal and doesn't need to be exported
1
5
  export * from './legacy';
6
+ export * from './versioned';
7
+ export * from './v0';
2
8
 
3
9
  /**
4
10
  * The message header, identifying signed and read-only account
@@ -15,18 +21,27 @@ export type MessageHeader = {
15
21
  numReadonlyUnsignedAccounts: number;
16
22
  };
17
23
 
24
+ /**
25
+ * An address table lookup used to load additional accounts
26
+ */
27
+ export type MessageAddressTableLookup = {
28
+ accountKey: PublicKey;
29
+ writableIndexes: Array<number>;
30
+ readonlyIndexes: Array<number>;
31
+ };
32
+
18
33
  /**
19
34
  * An instruction to execute by a program
20
35
  *
21
36
  * @property {number} programIdIndex
22
- * @property {number[]} accounts
23
- * @property {string} data
37
+ * @property {number[]} accountKeyIndexes
38
+ * @property {Uint8Array} data
24
39
  */
25
- export type CompiledInstruction = {
40
+ export type MessageCompiledInstruction = {
26
41
  /** Index into the transaction keys array indicating the program account that executes this instruction */
27
42
  programIdIndex: number;
28
43
  /** 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;
44
+ accountKeyIndexes: number[];
45
+ /** The program input data */
46
+ data: Uint8Array;
32
47
  };
@@ -5,10 +5,33 @@ import * as BufferLayout from '@solana/buffer-layout';
5
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
+ import {TransactionInstruction} from '../transaction';
17
+ import {CompiledKeys} from './compiled-keys';
18
+ import {MessageAccountKeys} from './account-keys';
19
+
20
+ /**
21
+ * An instruction to execute by a program
22
+ *
23
+ * @property {number} programIdIndex
24
+ * @property {number[]} accounts
25
+ * @property {string} data
26
+ */
27
+ export type CompiledInstruction = {
28
+ /** Index into the transaction keys array indicating the program account that executes this instruction */
29
+ programIdIndex: number;
30
+ /** Ordered indices into the transaction keys array indicating which accounts to pass to the program */
31
+ accounts: number[];
32
+ /** The program input data encoded as base 58 */
33
+ data: string;
34
+ };
12
35
 
13
36
  /**
14
37
  * Message constructor arguments
@@ -17,13 +40,19 @@ export type MessageArgs = {
17
40
  /** The message header, identifying signed and read-only `accountKeys` */
18
41
  header: MessageHeader;
19
42
  /** All the account keys used by this transaction */
20
- accountKeys: string[];
43
+ accountKeys: string[] | PublicKey[];
21
44
  /** The hash of a recent ledger block */
22
45
  recentBlockhash: Blockhash;
23
46
  /** Instructions that will be executed in sequence and committed in one atomic transaction if all succeed. */
24
47
  instructions: CompiledInstruction[];
25
48
  };
26
49
 
50
+ export type CompileLegacyArgs = {
51
+ payerKey: PublicKey;
52
+ instructions: Array<TransactionInstruction>;
53
+ recentBlockhash: Blockhash;
54
+ };
55
+
27
56
  /**
28
57
  * List of instructions to be processed atomically
29
58
  */
@@ -51,19 +80,68 @@ export class Message {
51
80
  );
52
81
  }
53
82
 
83
+ get version(): 'legacy' {
84
+ return 'legacy';
85
+ }
86
+
87
+ get staticAccountKeys(): Array<PublicKey> {
88
+ return this.accountKeys;
89
+ }
90
+
91
+ get compiledInstructions(): Array<MessageCompiledInstruction> {
92
+ return this.instructions.map(
93
+ (ix): MessageCompiledInstruction => ({
94
+ programIdIndex: ix.programIdIndex,
95
+ accountKeyIndexes: ix.accounts,
96
+ data: bs58.decode(ix.data),
97
+ }),
98
+ );
99
+ }
100
+
101
+ get addressTableLookups(): Array<MessageAddressTableLookup> {
102
+ return [];
103
+ }
104
+
105
+ getAccountKeys(): MessageAccountKeys {
106
+ return new MessageAccountKeys(this.staticAccountKeys);
107
+ }
108
+
109
+ static compile(args: CompileLegacyArgs): Message {
110
+ const compiledKeys = CompiledKeys.compile(args.instructions, args.payerKey);
111
+ const [header, staticAccountKeys] = compiledKeys.getMessageComponents();
112
+ const accountKeys = new MessageAccountKeys(staticAccountKeys);
113
+ const instructions = accountKeys.compileInstructions(args.instructions).map(
114
+ (ix: MessageCompiledInstruction): CompiledInstruction => ({
115
+ programIdIndex: ix.programIdIndex,
116
+ accounts: ix.accountKeyIndexes,
117
+ data: bs58.encode(ix.data),
118
+ }),
119
+ );
120
+ return new Message({
121
+ header,
122
+ accountKeys: staticAccountKeys,
123
+ recentBlockhash: args.recentBlockhash,
124
+ instructions,
125
+ });
126
+ }
127
+
54
128
  isAccountSigner(index: number): boolean {
55
129
  return index < this.header.numRequiredSignatures;
56
130
  }
57
131
 
58
132
  isAccountWritable(index: number): boolean {
59
- return (
60
- index <
61
- this.header.numRequiredSignatures -
62
- this.header.numReadonlySignedAccounts ||
63
- (index >= this.header.numRequiredSignatures &&
64
- index <
65
- this.accountKeys.length - this.header.numReadonlyUnsignedAccounts)
66
- );
133
+ const numSignedAccounts = this.header.numRequiredSignatures;
134
+ if (index >= this.header.numRequiredSignatures) {
135
+ const unsignedAccountIndex = index - numSignedAccounts;
136
+ const numUnsignedAccounts = this.accountKeys.length - numSignedAccounts;
137
+ const numWritableUnsignedAccounts =
138
+ numUnsignedAccounts - this.header.numReadonlyUnsignedAccounts;
139
+ return unsignedAccountIndex < numWritableUnsignedAccounts;
140
+ } else {
141
+ const numWritableSignedAccounts =
142
+ numSignedAccounts - this.header.numReadonlySignedAccounts;
143
+ return index < numWritableSignedAccounts;
144
+ }
67
145
  }
68
146
 
69
147
  isProgramId(index: number): boolean {
@@ -190,16 +268,25 @@ export class Message {
190
268
  // Slice up wire data
191
269
  let byteArray = [...buffer];
192
270
 
193
- const numRequiredSignatures = byteArray.shift() as number;
194
- const numReadonlySignedAccounts = byteArray.shift() as number;
195
- const numReadonlyUnsignedAccounts = byteArray.shift() as number;
271
+ const numRequiredSignatures = byteArray.shift()!;
272
+ if (
273
+ numRequiredSignatures !==
274
+ (numRequiredSignatures & VERSION_PREFIX_MASK)
275
+ ) {
276
+ throw new Error(
277
+ 'Versioned messages must be deserialized with VersionedMessage.deserialize()',
278
+ );
279
+ }
280
+
281
+ const numReadonlySignedAccounts = byteArray.shift()!;
282
+ const numReadonlyUnsignedAccounts = byteArray.shift()!;
196
283
 
197
284
  const accountCount = shortvec.decodeLength(byteArray);
198
285
  let accountKeys = [];
199
286
  for (let i = 0; i < accountCount; i++) {
200
287
  const account = byteArray.slice(0, PUBLIC_KEY_LENGTH);
201
288
  byteArray = byteArray.slice(PUBLIC_KEY_LENGTH);
202
- accountKeys.push(bs58.encode(Buffer.from(account)));
289
+ accountKeys.push(new PublicKey(Buffer.from(account)));
203
290
  }
204
291
 
205
292
  const recentBlockhash = byteArray.slice(0, PUBLIC_KEY_LENGTH);
@@ -208,7 +295,7 @@ export class Message {
208
295
  const instructionCount = shortvec.decodeLength(byteArray);
209
296
  let instructions: CompiledInstruction[] = [];
210
297
  for (let i = 0; i < instructionCount; i++) {
211
- const programIdIndex = byteArray.shift() as number;
298
+ const programIdIndex = byteArray.shift()!;
212
299
  const accountCount = shortvec.decodeLength(byteArray);
213
300
  const accounts = byteArray.slice(0, accountCount);
214
301
  byteArray = byteArray.slice(accountCount);