@solana/web3.js 0.0.0-next → 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 (74) hide show
  1. package/README.md +24 -25
  2. package/lib/index.browser.cjs.js +4583 -4238
  3. package/lib/index.browser.cjs.js.map +1 -1
  4. package/lib/index.browser.esm.js +4565 -4238
  5. package/lib/index.browser.esm.js.map +1 -1
  6. package/lib/index.cjs.js +7072 -3604
  7. package/lib/index.cjs.js.map +1 -1
  8. package/lib/index.d.ts +3516 -2420
  9. package/lib/index.esm.js +7046 -3601
  10. package/lib/index.esm.js.map +1 -1
  11. package/lib/index.iife.js +22171 -27053
  12. package/lib/index.iife.js.map +1 -1
  13. package/lib/index.iife.min.js +8 -33
  14. package/lib/index.iife.min.js.map +1 -1
  15. package/lib/index.native.js +10407 -0
  16. package/lib/index.native.js.map +1 -0
  17. package/package.json +36 -36
  18. package/src/__forks__/browser/fetch-impl.ts +4 -0
  19. package/src/__forks__/react-native/fetch-impl.ts +4 -0
  20. package/src/account-data.ts +39 -0
  21. package/src/account.ts +20 -11
  22. package/src/bpf-loader.ts +2 -2
  23. package/src/connection.ts +2303 -635
  24. package/src/epoch-schedule.ts +1 -1
  25. package/src/errors.ts +41 -0
  26. package/src/fee-calculator.ts +2 -0
  27. package/src/fetch-impl.ts +13 -0
  28. package/src/index.ts +3 -10
  29. package/src/keypair.ts +20 -25
  30. package/src/layout.ts +45 -4
  31. package/src/loader.ts +3 -3
  32. package/src/message/account-keys.ts +79 -0
  33. package/src/message/compiled-keys.ts +165 -0
  34. package/src/message/index.ts +47 -0
  35. package/src/{message.ts → message/legacy.ts} +95 -40
  36. package/src/message/v0.ts +496 -0
  37. package/src/message/versioned.ts +36 -0
  38. package/src/nonce-account.ts +8 -4
  39. package/src/programs/address-lookup-table/index.ts +435 -0
  40. package/src/programs/address-lookup-table/state.ts +84 -0
  41. package/src/programs/compute-budget.ts +281 -0
  42. package/src/{ed25519-program.ts → programs/ed25519.ts} +6 -6
  43. package/src/programs/index.ts +7 -0
  44. package/src/{secp256k1-program.ts → programs/secp256k1.ts} +15 -16
  45. package/src/{stake-program.ts → programs/stake.ts} +7 -7
  46. package/src/{system-program.ts → programs/system.ts} +55 -18
  47. package/src/{vote-program.ts → programs/vote.ts} +137 -9
  48. package/src/publickey.ts +37 -79
  49. package/src/transaction/constants.ts +12 -0
  50. package/src/transaction/expiry-custom-errors.ts +48 -0
  51. package/src/transaction/index.ts +5 -0
  52. package/src/{transaction.ts → transaction/legacy.ts} +162 -67
  53. package/src/transaction/message.ts +140 -0
  54. package/src/transaction/versioned.ts +126 -0
  55. package/src/{util → utils}/assert.ts +0 -0
  56. package/src/utils/bigint.ts +43 -0
  57. package/src/{util → utils}/borsh-schema.ts +0 -0
  58. package/src/{util → utils}/cluster.ts +0 -0
  59. package/src/utils/ed25519.ts +46 -0
  60. package/src/utils/index.ts +5 -0
  61. package/src/utils/makeWebsocketUrl.ts +26 -0
  62. package/src/{util → utils}/promise-timeout.ts +0 -0
  63. package/src/utils/secp256k1.ts +18 -0
  64. package/src/utils/send-and-confirm-raw-transaction.ts +105 -0
  65. package/src/utils/send-and-confirm-transaction.ts +98 -0
  66. package/src/{util → utils}/shortvec-encoding.ts +0 -0
  67. package/src/{util → utils}/sleep.ts +0 -0
  68. package/src/{util → utils}/to-buffer.ts +0 -0
  69. package/src/validator-info.ts +4 -6
  70. package/src/vote-account.ts +1 -1
  71. package/src/agent-manager.ts +0 -44
  72. package/src/util/send-and-confirm-raw-transaction.ts +0 -46
  73. package/src/util/send-and-confirm-transaction.ts +0 -50
  74. package/src/util/url.ts +0 -18
@@ -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/errors.ts CHANGED
@@ -7,3 +7,44 @@ export class SendTransactionError extends Error {
7
7
  this.logs = logs;
8
8
  }
9
9
  }
10
+
11
+ // Keep in sync with client/src/rpc_custom_errors.rs
12
+ // Typescript `enums` thwart tree-shaking. See https://bargsten.org/jsts/enums/
13
+ export const SolanaJSONRPCErrorCode = {
14
+ JSON_RPC_SERVER_ERROR_BLOCK_CLEANED_UP: -32001,
15
+ JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE: -32002,
16
+ JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE: -32003,
17
+ JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE: -32004,
18
+ JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY: -32005,
19
+ JSON_RPC_SERVER_ERROR_TRANSACTION_PRECOMPILE_VERIFICATION_FAILURE: -32006,
20
+ JSON_RPC_SERVER_ERROR_SLOT_SKIPPED: -32007,
21
+ JSON_RPC_SERVER_ERROR_NO_SNAPSHOT: -32008,
22
+ JSON_RPC_SERVER_ERROR_LONG_TERM_STORAGE_SLOT_SKIPPED: -32009,
23
+ JSON_RPC_SERVER_ERROR_KEY_EXCLUDED_FROM_SECONDARY_INDEX: -32010,
24
+ JSON_RPC_SERVER_ERROR_TRANSACTION_HISTORY_NOT_AVAILABLE: -32011,
25
+ JSON_RPC_SCAN_ERROR: -32012,
26
+ JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_LEN_MISMATCH: -32013,
27
+ JSON_RPC_SERVER_ERROR_BLOCK_STATUS_NOT_AVAILABLE_YET: -32014,
28
+ JSON_RPC_SERVER_ERROR_UNSUPPORTED_TRANSACTION_VERSION: -32015,
29
+ JSON_RPC_SERVER_ERROR_MIN_CONTEXT_SLOT_NOT_REACHED: -32016,
30
+ } as const;
31
+ export type SolanaJSONRPCErrorCodeEnum =
32
+ typeof SolanaJSONRPCErrorCode[keyof typeof SolanaJSONRPCErrorCode];
33
+
34
+ export class SolanaJSONRPCError extends Error {
35
+ code: SolanaJSONRPCErrorCodeEnum | unknown;
36
+ data?: any;
37
+ constructor(
38
+ {
39
+ code,
40
+ message,
41
+ data,
42
+ }: Readonly<{code: unknown; message: string; data?: any}>,
43
+ customMessage?: string,
44
+ ) {
45
+ super(customMessage != null ? `${customMessage}: ${message}` : message);
46
+ this.code = code;
47
+ this.data = data;
48
+ this.name = 'SolanaJSONRPCError';
49
+ }
50
+ }
@@ -9,6 +9,8 @@ export const FeeCalculatorLayout = BufferLayout.nu64('lamportsPerSignature');
9
9
 
10
10
  /**
11
11
  * Calculator for transaction fees.
12
+ *
13
+ * @deprecated Deprecated since Solana v1.8.0.
12
14
  */
13
15
  export interface FeeCalculator {
14
16
  /** Cost in lamports to validate a signature. */
@@ -0,0 +1,13 @@
1
+ import * as nodeFetch from 'node-fetch';
2
+
3
+ export * from 'node-fetch';
4
+ export default async function (
5
+ input: nodeFetch.RequestInfo,
6
+ init?: nodeFetch.RequestInit,
7
+ ): Promise<nodeFetch.Response> {
8
+ const processedInput =
9
+ typeof input === 'string' && input.slice(0, 2) === '//'
10
+ ? 'https:' + input
11
+ : input;
12
+ return await nodeFetch.default(processedInput, init);
13
+ }
package/src/index.ts CHANGED
@@ -4,26 +4,19 @@ export * from './bpf-loader-deprecated';
4
4
  export * from './bpf-loader';
5
5
  export * from './connection';
6
6
  export * from './epoch-schedule';
7
- export * from './ed25519-program';
7
+ export * from './errors';
8
8
  export * from './fee-calculator';
9
9
  export * from './keypair';
10
10
  export * from './loader';
11
11
  export * from './message';
12
12
  export * from './nonce-account';
13
+ export * from './programs';
13
14
  export * from './publickey';
14
- export * from './stake-program';
15
- export * from './system-program';
16
- export * from './secp256k1-program';
17
15
  export * from './transaction';
18
16
  export * from './validator-info';
19
17
  export * from './vote-account';
20
- export * from './vote-program';
21
18
  export * from './sysvar';
22
- export * from './errors';
23
- export * from './util/borsh-schema';
24
- export * from './util/send-and-confirm-transaction';
25
- export * from './util/send-and-confirm-raw-transaction';
26
- export * from './util/cluster';
19
+ export * from './utils';
27
20
 
28
21
  /**
29
22
  * There are 1-billion lamports in one SOL
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,14 +143,46 @@ 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
- let alloc = 0;
139
- type.layout.fields.forEach((item: any) => {
164
+ const getItemAlloc = (item: any): number => {
140
165
  if (item.span >= 0) {
141
- alloc += item.span;
166
+ return item.span;
142
167
  } else if (typeof item.alloc === 'function') {
143
- alloc += item.alloc(fields[item.property]);
168
+ return item.alloc(fields[item.property]);
169
+ } else if ('count' in item && 'elementLayout' in item) {
170
+ const field = fields[item.property];
171
+ if (Array.isArray(field)) {
172
+ return field.length * getItemAlloc(item.elementLayout);
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]);
144
177
  }
178
+ // Couldn't determine allocated size of layout
179
+ return 0;
180
+ };
181
+
182
+ let alloc = 0;
183
+ type.layout.fields.forEach((item: any) => {
184
+ alloc += getItemAlloc(item);
145
185
  });
186
+
146
187
  return alloc;
147
188
  }
package/src/loader.ts CHANGED
@@ -4,11 +4,11 @@ import * as BufferLayout from '@solana/buffer-layout';
4
4
  import {PublicKey} from './publickey';
5
5
  import {Transaction, PACKET_DATA_SIZE} from './transaction';
6
6
  import {SYSVAR_RENT_PUBKEY} from './sysvar';
7
- import {sendAndConfirmTransaction} from './util/send-and-confirm-transaction';
8
- import {sleep} from './util/sleep';
7
+ import {sendAndConfirmTransaction} from './utils/send-and-confirm-transaction';
8
+ import {sleep} from './utils/sleep';
9
9
  import type {Connection} from './connection';
10
10
  import type {Signer} from './keypair';
11
- import {SystemProgram} from './system-program';
11
+ import {SystemProgram} from './programs/system';
12
12
  import {IInstructionInputData} from './instruction';
13
13
 
14
14
  // Keep program chunks under PACKET_DATA_SIZE, leaving enough room for the
@@ -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
+ }
@@ -0,0 +1,47 @@
1
+ import {PublicKey} from '../publickey';
2
+
3
+ export * from './account-keys';
4
+ // note: compiled-keys is internal and doesn't need to be exported
5
+ export * from './legacy';
6
+ export * from './versioned';
7
+ export * from './v0';
8
+
9
+ /**
10
+ * The message header, identifying signed and read-only account
11
+ */
12
+ export type MessageHeader = {
13
+ /**
14
+ * The number of signatures required for this message to be considered valid. The
15
+ * signatures must match the first `numRequiredSignatures` of `accountKeys`.
16
+ */
17
+ numRequiredSignatures: number;
18
+ /** The last `numReadonlySignedAccounts` of the signed keys are read-only accounts */
19
+ numReadonlySignedAccounts: number;
20
+ /** The last `numReadonlySignedAccounts` of the unsigned keys are read-only accounts */
21
+ numReadonlyUnsignedAccounts: number;
22
+ };
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
+
33
+ /**
34
+ * An instruction to execute by a program
35
+ *
36
+ * @property {number} programIdIndex
37
+ * @property {number[]} accountKeyIndexes
38
+ * @property {Uint8Array} data
39
+ */
40
+ export type MessageCompiledInstruction = {
41
+ /** Index into the transaction keys array indicating the program account that executes this instruction */
42
+ programIdIndex: number;
43
+ /** Ordered indices into the transaction keys array indicating which accounts to pass to the program */
44
+ accountKeyIndexes: number[];
45
+ /** The program input data */
46
+ data: Uint8Array;
47
+ };