@solana/transactions 2.0.0-experimental.2bae733 → 2.0.0-experimental.2e0ae95

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 (71) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +276 -5
  3. package/dist/index.browser.cjs +644 -285
  4. package/dist/index.browser.cjs.map +1 -1
  5. package/dist/index.browser.js +623 -287
  6. package/dist/index.browser.js.map +1 -1
  7. package/dist/index.native.js +623 -287
  8. package/dist/index.native.js.map +1 -1
  9. package/dist/index.node.cjs +644 -285
  10. package/dist/index.node.cjs.map +1 -1
  11. package/dist/index.node.js +623 -287
  12. package/dist/index.node.js.map +1 -1
  13. package/dist/types/accounts.d.ts +3 -3
  14. package/dist/types/accounts.d.ts.map +1 -0
  15. package/dist/types/blockhash.d.ts +7 -1
  16. package/dist/types/blockhash.d.ts.map +1 -0
  17. package/dist/types/compilable-transaction.d.ts +7 -0
  18. package/dist/types/compilable-transaction.d.ts.map +1 -0
  19. package/dist/types/compile-address-table-lookups.d.ts +3 -3
  20. package/dist/types/compile-address-table-lookups.d.ts.map +1 -0
  21. package/dist/types/compile-header.d.ts +1 -1
  22. package/dist/types/compile-header.d.ts.map +1 -0
  23. package/dist/types/compile-instructions.d.ts +2 -2
  24. package/dist/types/compile-instructions.d.ts.map +1 -0
  25. package/dist/types/compile-lifetime-token.d.ts +1 -1
  26. package/dist/types/compile-lifetime-token.d.ts.map +1 -0
  27. package/dist/types/compile-static-accounts.d.ts +3 -3
  28. package/dist/types/compile-static-accounts.d.ts.map +1 -0
  29. package/dist/types/compile-transaction.d.ts +10 -0
  30. package/dist/types/compile-transaction.d.ts.map +1 -0
  31. package/dist/types/create-transaction.d.ts +1 -1
  32. package/dist/types/create-transaction.d.ts.map +1 -0
  33. package/dist/types/decompile-transaction.d.ts +13 -0
  34. package/dist/types/decompile-transaction.d.ts.map +1 -0
  35. package/dist/types/durable-nonce.d.ts +23 -10
  36. package/dist/types/durable-nonce.d.ts.map +1 -0
  37. package/dist/types/fee-payer.d.ts +6 -5
  38. package/dist/types/fee-payer.d.ts.map +1 -0
  39. package/dist/types/index.d.ts +13 -7
  40. package/dist/types/index.d.ts.map +1 -0
  41. package/dist/types/instructions.d.ts +4 -2
  42. package/dist/types/instructions.d.ts.map +1 -0
  43. package/dist/types/message.d.ts +6 -10
  44. package/dist/types/message.d.ts.map +1 -0
  45. package/dist/types/serializers/address-table-lookup.d.ts +5 -3
  46. package/dist/types/serializers/address-table-lookup.d.ts.map +1 -0
  47. package/dist/types/serializers/header.d.ts +5 -3
  48. package/dist/types/serializers/header.d.ts.map +1 -0
  49. package/dist/types/serializers/index.d.ts +3 -0
  50. package/dist/types/serializers/index.d.ts.map +1 -0
  51. package/dist/types/serializers/instruction.d.ts +5 -3
  52. package/dist/types/serializers/instruction.d.ts.map +1 -0
  53. package/dist/types/serializers/message.d.ts +5 -5
  54. package/dist/types/serializers/message.d.ts.map +1 -0
  55. package/dist/types/serializers/transaction-version.d.ts +5 -5
  56. package/dist/types/serializers/transaction-version.d.ts.map +1 -0
  57. package/dist/types/serializers/transaction.d.ts +10 -0
  58. package/dist/types/serializers/transaction.d.ts.map +1 -0
  59. package/dist/types/signatures.d.ts +10 -7
  60. package/dist/types/signatures.d.ts.map +1 -0
  61. package/dist/types/types.d.ts +13 -13
  62. package/dist/types/types.d.ts.map +1 -0
  63. package/dist/types/unsigned-transaction.d.ts +4 -0
  64. package/dist/types/unsigned-transaction.d.ts.map +1 -0
  65. package/dist/types/wire-transaction.d.ts +6 -0
  66. package/dist/types/wire-transaction.d.ts.map +1 -0
  67. package/package.json +21 -40
  68. package/dist/index.development.js +0 -1188
  69. package/dist/index.development.js.map +0 -1
  70. package/dist/index.production.min.js +0 -15
  71. package/dist/types/serializers/unimplemented.d.ts +0 -3
@@ -1,77 +1,88 @@
1
- import { getBase58EncodedAddressFromPublicKey, signBytes, getBase58EncodedAddressComparator, getBase58EncodedAddressCodec } from '@solana/keys';
2
- import { struct, mapSerializer, array, shortU16, string, base58, u8, bytes } from '@metaplex-foundation/umi-serializers';
1
+ import { SolanaError, SOLANA_ERROR__TRANSACTION_EXPECTED_BLOCKHASH_LIFETIME, SOLANA_ERROR__TRANSACTION_EXPECTED_NONCE_LIFETIME, SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_FEE_PAYER_MISSING, SOLANA_ERROR__TRANSACTION_SIGNATURE_NOT_COMPUTABLE, SOLANA_ERROR__TRANSACTION_MISSING_SIGNATURES, SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_ADDRESS_LOOKUP_TABLE_CONTENTS_MISSING, SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_ADDRESS_LOOKUP_TABLE_INDEX_OUT_OF_RANGE, SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_INSTRUCTION_PROGRAM_ADDRESS_NOT_FOUND, SOLANA_ERROR__TRANSACTION_INVOKED_PROGRAMS_MUST_NOT_BE_WRITABLE, SOLANA_ERROR__TRANSACTION_INVOKED_PROGRAMS_CANNOT_PAY_FEES, SOLANA_ERROR__TRANSACTION_VERSION_NUMBER_OUT_OF_RANGE } from '@solana/errors';
2
+ import { getBase58Decoder, getBase64Decoder, getStringEncoder, getBase58Encoder, getStringDecoder } from '@solana/codecs-strings';
3
+ import { getAddressFromPublicKey, assertIsAddress, getAddressComparator, getAddressEncoder, getAddressDecoder } from '@solana/addresses';
4
+ import { pipe } from '@solana/functional';
5
+ import { createEncoder, mapDecoder, combineCodec, mapEncoder, createDecoder } from '@solana/codecs-core';
6
+ import { getStructDecoder, getArrayDecoder, getBytesDecoder, getStructEncoder, getArrayEncoder, getBytesEncoder } from '@solana/codecs-data-structures';
7
+ import { getShortU16Decoder, getShortU16Encoder, getU8Encoder, getU8Decoder } from '@solana/codecs-numbers';
8
+ import { signBytes } from '@solana/keys';
3
9
 
4
- // ../build-scripts/env-shim.ts
5
- var __DEV__ = /* @__PURE__ */ (() => process["env"].NODE_ENV === "development")();
6
-
7
- // src/create-transaction.ts
8
- function createTransaction({
9
- version
10
- }) {
11
- const out = {
12
- instructions: [],
13
- version
14
- };
15
- Object.freeze(out);
16
- return out;
10
+ // src/blockhash.ts
11
+ var base58Encoder;
12
+ function assertIsBlockhash(putativeBlockhash) {
13
+ if (!base58Encoder)
14
+ base58Encoder = getBase58Encoder();
15
+ try {
16
+ if (
17
+ // Lowest value (32 bytes of zeroes)
18
+ putativeBlockhash.length < 32 || // Highest value (32 bytes of 255)
19
+ putativeBlockhash.length > 44
20
+ ) {
21
+ throw new Error("Expected input string to decode to a byte array of length 32.");
22
+ }
23
+ const bytes = base58Encoder.encode(putativeBlockhash);
24
+ const numBytes = bytes.byteLength;
25
+ if (numBytes !== 32) {
26
+ throw new Error(`Expected input string to decode to a byte array of length 32. Actual length: ${numBytes}`);
27
+ }
28
+ } catch (e) {
29
+ throw new Error(`\`${putativeBlockhash}\` is not a blockhash`, {
30
+ cause: e
31
+ });
32
+ }
17
33
  }
18
34
 
19
- // src/fee-payer.ts
20
- function setTransactionFeePayer(feePayer, transaction) {
21
- if ("feePayer" in transaction && feePayer === transaction.feePayer) {
22
- return transaction;
23
- }
24
- let out;
35
+ // src/unsigned-transaction.ts
36
+ function getUnsignedTransaction(transaction) {
25
37
  if ("signatures" in transaction) {
26
38
  const {
27
39
  signatures: _,
28
40
  // eslint-disable-line @typescript-eslint/no-unused-vars
29
41
  ...unsignedTransaction
30
42
  } = transaction;
31
- out = {
32
- ...unsignedTransaction,
33
- feePayer
34
- };
43
+ return unsignedTransaction;
35
44
  } else {
36
- out = {
37
- ...transaction,
38
- feePayer
39
- };
45
+ return transaction;
40
46
  }
41
- Object.freeze(out);
42
- return out;
43
47
  }
44
48
 
45
- // src/instructions.ts
46
- function replaceInstructions(transaction, nextInstructions) {
47
- let out;
48
- if ("signatures" in transaction) {
49
- const {
50
- signatures: _,
51
- // eslint-disable-line @typescript-eslint/no-unused-vars
52
- ...unsignedTransaction
53
- } = transaction;
54
- out = {
55
- ...unsignedTransaction,
56
- instructions: nextInstructions
57
- };
58
- } else {
59
- out = {
60
- ...transaction,
61
- instructions: nextInstructions
62
- };
49
+ // src/blockhash.ts
50
+ function isTransactionWithBlockhashLifetime(transaction) {
51
+ const lifetimeConstraintShapeMatches = "lifetimeConstraint" in transaction && typeof transaction.lifetimeConstraint.blockhash === "string" && typeof transaction.lifetimeConstraint.lastValidBlockHeight === "bigint";
52
+ if (!lifetimeConstraintShapeMatches)
53
+ return false;
54
+ try {
55
+ assertIsBlockhash(transaction.lifetimeConstraint.blockhash);
56
+ return true;
57
+ } catch {
58
+ return false;
63
59
  }
64
- return out;
65
60
  }
66
- function appendTransactionInstruction(instruction, transaction) {
67
- const nextInstructions = [...transaction.instructions, instruction];
68
- const out = replaceInstructions(transaction, nextInstructions);
61
+ function assertIsTransactionWithBlockhashLifetime(transaction) {
62
+ if (!isTransactionWithBlockhashLifetime(transaction)) {
63
+ throw new SolanaError(SOLANA_ERROR__TRANSACTION_EXPECTED_BLOCKHASH_LIFETIME);
64
+ }
65
+ }
66
+ function setTransactionLifetimeUsingBlockhash(blockhashLifetimeConstraint, transaction) {
67
+ if ("lifetimeConstraint" in transaction && transaction.lifetimeConstraint.blockhash === blockhashLifetimeConstraint.blockhash && transaction.lifetimeConstraint.lastValidBlockHeight === blockhashLifetimeConstraint.lastValidBlockHeight) {
68
+ return transaction;
69
+ }
70
+ const out = {
71
+ ...getUnsignedTransaction(transaction),
72
+ lifetimeConstraint: blockhashLifetimeConstraint
73
+ };
69
74
  Object.freeze(out);
70
75
  return out;
71
76
  }
72
- function prependTransactionInstruction(instruction, transaction) {
73
- const nextInstructions = [instruction, ...transaction.instructions];
74
- const out = replaceInstructions(transaction, nextInstructions);
77
+
78
+ // src/create-transaction.ts
79
+ function createTransaction({
80
+ version
81
+ }) {
82
+ const out = {
83
+ instructions: [],
84
+ version
85
+ };
75
86
  Object.freeze(out);
76
87
  return out;
77
88
  }
@@ -98,6 +109,271 @@ function isWritableRole(role) {
98
109
  function mergeRoles(roleA, roleB) {
99
110
  return roleA | roleB;
100
111
  }
112
+ var RECENT_BLOCKHASHES_SYSVAR_ADDRESS = "SysvarRecentB1ockHashes11111111111111111111";
113
+ var SYSTEM_PROGRAM_ADDRESS = "11111111111111111111111111111111";
114
+ function assertIsDurableNonceTransaction(transaction) {
115
+ if (!isDurableNonceTransaction(transaction)) {
116
+ throw new SolanaError(SOLANA_ERROR__TRANSACTION_EXPECTED_NONCE_LIFETIME);
117
+ }
118
+ }
119
+ function createAdvanceNonceAccountInstruction(nonceAccountAddress, nonceAuthorityAddress) {
120
+ return {
121
+ accounts: [
122
+ { address: nonceAccountAddress, role: AccountRole.WRITABLE },
123
+ {
124
+ address: RECENT_BLOCKHASHES_SYSVAR_ADDRESS,
125
+ role: AccountRole.READONLY
126
+ },
127
+ { address: nonceAuthorityAddress, role: AccountRole.READONLY_SIGNER }
128
+ ],
129
+ data: new Uint8Array([4, 0, 0, 0]),
130
+ programAddress: SYSTEM_PROGRAM_ADDRESS
131
+ };
132
+ }
133
+ function isAdvanceNonceAccountInstruction(instruction) {
134
+ return instruction.programAddress === SYSTEM_PROGRAM_ADDRESS && // Test for `AdvanceNonceAccount` instruction data
135
+ instruction.data != null && isAdvanceNonceAccountInstructionData(instruction.data) && // Test for exactly 3 accounts
136
+ instruction.accounts?.length === 3 && // First account is nonce account address
137
+ instruction.accounts[0].address != null && instruction.accounts[0].role === AccountRole.WRITABLE && // Second account is recent blockhashes sysvar
138
+ instruction.accounts[1].address === RECENT_BLOCKHASHES_SYSVAR_ADDRESS && instruction.accounts[1].role === AccountRole.READONLY && // Third account is nonce authority account
139
+ instruction.accounts[2].address != null && isSignerRole(instruction.accounts[2].role);
140
+ }
141
+ function isAdvanceNonceAccountInstructionData(data) {
142
+ return data.byteLength === 4 && data[0] === 4 && data[1] === 0 && data[2] === 0 && data[3] === 0;
143
+ }
144
+ function isDurableNonceTransaction(transaction) {
145
+ return "lifetimeConstraint" in transaction && typeof transaction.lifetimeConstraint.nonce === "string" && transaction.instructions[0] != null && isAdvanceNonceAccountInstruction(transaction.instructions[0]);
146
+ }
147
+ function isAdvanceNonceAccountInstructionForNonce(instruction, nonceAccountAddress, nonceAuthorityAddress) {
148
+ return instruction.accounts[0].address === nonceAccountAddress && instruction.accounts[2].address === nonceAuthorityAddress;
149
+ }
150
+ function setTransactionLifetimeUsingDurableNonce({
151
+ nonce,
152
+ nonceAccountAddress,
153
+ nonceAuthorityAddress
154
+ }, transaction) {
155
+ let newInstructions;
156
+ const firstInstruction = transaction.instructions[0];
157
+ if (firstInstruction && isAdvanceNonceAccountInstruction(firstInstruction)) {
158
+ if (isAdvanceNonceAccountInstructionForNonce(firstInstruction, nonceAccountAddress, nonceAuthorityAddress)) {
159
+ if (isDurableNonceTransaction(transaction) && transaction.lifetimeConstraint.nonce === nonce) {
160
+ return transaction;
161
+ } else {
162
+ newInstructions = [firstInstruction, ...transaction.instructions.slice(1)];
163
+ }
164
+ } else {
165
+ newInstructions = [
166
+ createAdvanceNonceAccountInstruction(nonceAccountAddress, nonceAuthorityAddress),
167
+ ...transaction.instructions.slice(1)
168
+ ];
169
+ }
170
+ } else {
171
+ newInstructions = [
172
+ createAdvanceNonceAccountInstruction(nonceAccountAddress, nonceAuthorityAddress),
173
+ ...transaction.instructions
174
+ ];
175
+ }
176
+ const out = {
177
+ ...getUnsignedTransaction(transaction),
178
+ instructions: newInstructions,
179
+ lifetimeConstraint: {
180
+ nonce
181
+ }
182
+ };
183
+ Object.freeze(out);
184
+ return out;
185
+ }
186
+
187
+ // src/fee-payer.ts
188
+ function setTransactionFeePayer(feePayer, transaction) {
189
+ if ("feePayer" in transaction && feePayer === transaction.feePayer) {
190
+ return transaction;
191
+ }
192
+ const out = {
193
+ ...getUnsignedTransaction(transaction),
194
+ feePayer
195
+ };
196
+ Object.freeze(out);
197
+ return out;
198
+ }
199
+
200
+ // src/instructions.ts
201
+ function appendTransactionInstruction(instruction, transaction) {
202
+ return appendTransactionInstructions([instruction], transaction);
203
+ }
204
+ function appendTransactionInstructions(instructions, transaction) {
205
+ const out = {
206
+ ...getUnsignedTransaction(transaction),
207
+ instructions: [...transaction.instructions, ...instructions]
208
+ };
209
+ Object.freeze(out);
210
+ return out;
211
+ }
212
+ function prependTransactionInstruction(instruction, transaction) {
213
+ return prependTransactionInstructions([instruction], transaction);
214
+ }
215
+ function prependTransactionInstructions(instructions, transaction) {
216
+ const out = {
217
+ ...getUnsignedTransaction(transaction),
218
+ instructions: [...instructions, ...transaction.instructions]
219
+ };
220
+ Object.freeze(out);
221
+ return out;
222
+ }
223
+
224
+ // src/decompile-transaction.ts
225
+ function getAccountMetas(message) {
226
+ const { header } = message;
227
+ const numWritableSignerAccounts = header.numSignerAccounts - header.numReadonlySignerAccounts;
228
+ const numWritableNonSignerAccounts = message.staticAccounts.length - header.numSignerAccounts - header.numReadonlyNonSignerAccounts;
229
+ const accountMetas = [];
230
+ let accountIndex = 0;
231
+ for (let i = 0; i < numWritableSignerAccounts; i++) {
232
+ accountMetas.push({
233
+ address: message.staticAccounts[accountIndex],
234
+ role: AccountRole.WRITABLE_SIGNER
235
+ });
236
+ accountIndex++;
237
+ }
238
+ for (let i = 0; i < header.numReadonlySignerAccounts; i++) {
239
+ accountMetas.push({
240
+ address: message.staticAccounts[accountIndex],
241
+ role: AccountRole.READONLY_SIGNER
242
+ });
243
+ accountIndex++;
244
+ }
245
+ for (let i = 0; i < numWritableNonSignerAccounts; i++) {
246
+ accountMetas.push({
247
+ address: message.staticAccounts[accountIndex],
248
+ role: AccountRole.WRITABLE
249
+ });
250
+ accountIndex++;
251
+ }
252
+ for (let i = 0; i < header.numReadonlyNonSignerAccounts; i++) {
253
+ accountMetas.push({
254
+ address: message.staticAccounts[accountIndex],
255
+ role: AccountRole.READONLY
256
+ });
257
+ accountIndex++;
258
+ }
259
+ return accountMetas;
260
+ }
261
+ function getAddressLookupMetas(compiledAddressTableLookups, addressesByLookupTableAddress) {
262
+ const compiledAddressTableLookupAddresses = compiledAddressTableLookups.map((l) => l.lookupTableAddress);
263
+ const missing = compiledAddressTableLookupAddresses.filter((a) => addressesByLookupTableAddress[a] === void 0);
264
+ if (missing.length > 0) {
265
+ throw new SolanaError(SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_ADDRESS_LOOKUP_TABLE_CONTENTS_MISSING, {
266
+ lookupTableAddresses: missing
267
+ });
268
+ }
269
+ const readOnlyMetas = [];
270
+ const writableMetas = [];
271
+ for (const lookup of compiledAddressTableLookups) {
272
+ const addresses = addressesByLookupTableAddress[lookup.lookupTableAddress];
273
+ const highestIndex = Math.max(...lookup.readableIndices, ...lookup.writableIndices);
274
+ if (highestIndex >= addresses.length) {
275
+ throw new SolanaError(
276
+ SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_ADDRESS_LOOKUP_TABLE_INDEX_OUT_OF_RANGE,
277
+ {
278
+ highestKnownIndex: addresses.length - 1,
279
+ highestRequestedIndex: highestIndex,
280
+ lookupTableAddress: lookup.lookupTableAddress
281
+ }
282
+ );
283
+ }
284
+ const readOnlyForLookup = lookup.readableIndices.map((r) => ({
285
+ address: addresses[r],
286
+ addressIndex: r,
287
+ lookupTableAddress: lookup.lookupTableAddress,
288
+ role: AccountRole.READONLY
289
+ }));
290
+ readOnlyMetas.push(...readOnlyForLookup);
291
+ const writableForLookup = lookup.writableIndices.map((w) => ({
292
+ address: addresses[w],
293
+ addressIndex: w,
294
+ lookupTableAddress: lookup.lookupTableAddress,
295
+ role: AccountRole.WRITABLE
296
+ }));
297
+ writableMetas.push(...writableForLookup);
298
+ }
299
+ return [...writableMetas, ...readOnlyMetas];
300
+ }
301
+ function convertInstruction(instruction, accountMetas) {
302
+ const programAddress = accountMetas[instruction.programAddressIndex]?.address;
303
+ if (!programAddress) {
304
+ throw new SolanaError(SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_INSTRUCTION_PROGRAM_ADDRESS_NOT_FOUND, {
305
+ index: instruction.programAddressIndex
306
+ });
307
+ }
308
+ const accounts = instruction.accountIndices?.map((accountIndex) => accountMetas[accountIndex]);
309
+ const { data } = instruction;
310
+ return {
311
+ programAddress,
312
+ ...accounts && accounts.length ? { accounts } : {},
313
+ ...data && data.length ? { data } : {}
314
+ };
315
+ }
316
+ function getLifetimeConstraint(messageLifetimeToken, firstInstruction, lastValidBlockHeight) {
317
+ if (!firstInstruction || !isAdvanceNonceAccountInstruction(firstInstruction)) {
318
+ return {
319
+ blockhash: messageLifetimeToken,
320
+ lastValidBlockHeight: lastValidBlockHeight ?? 2n ** 64n - 1n
321
+ // U64 MAX
322
+ };
323
+ } else {
324
+ const nonceAccountAddress = firstInstruction.accounts[0].address;
325
+ assertIsAddress(nonceAccountAddress);
326
+ const nonceAuthorityAddress = firstInstruction.accounts[2].address;
327
+ assertIsAddress(nonceAuthorityAddress);
328
+ return {
329
+ nonce: messageLifetimeToken,
330
+ nonceAccountAddress,
331
+ nonceAuthorityAddress
332
+ };
333
+ }
334
+ }
335
+ function convertSignatures(compiledTransaction) {
336
+ const {
337
+ compiledMessage: { staticAccounts },
338
+ signatures
339
+ } = compiledTransaction;
340
+ return signatures.reduce((acc, sig, index) => {
341
+ const allZeros = sig.every((byte) => byte === 0);
342
+ if (allZeros)
343
+ return acc;
344
+ const address = staticAccounts[index];
345
+ return { ...acc, [address]: sig };
346
+ }, {});
347
+ }
348
+ function decompileTransaction(compiledTransaction, config) {
349
+ const { compiledMessage } = compiledTransaction;
350
+ const feePayer = compiledMessage.staticAccounts[0];
351
+ if (!feePayer) {
352
+ throw new SolanaError(SOLANA_ERROR__TRANSACTION_FAILED_TO_DECOMPILE_FEE_PAYER_MISSING);
353
+ }
354
+ const accountMetas = getAccountMetas(compiledMessage);
355
+ const accountLookupMetas = "addressTableLookups" in compiledMessage && compiledMessage.addressTableLookups !== void 0 && compiledMessage.addressTableLookups.length > 0 ? getAddressLookupMetas(compiledMessage.addressTableLookups, config?.addressesByLookupTableAddress ?? {}) : [];
356
+ const transactionMetas = [...accountMetas, ...accountLookupMetas];
357
+ const instructions = compiledMessage.instructions.map(
358
+ (compiledInstruction) => convertInstruction(compiledInstruction, transactionMetas)
359
+ );
360
+ const firstInstruction = instructions[0];
361
+ const lifetimeConstraint = getLifetimeConstraint(
362
+ compiledMessage.lifetimeToken,
363
+ firstInstruction,
364
+ config?.lastValidBlockHeight
365
+ );
366
+ const signatures = convertSignatures(compiledTransaction);
367
+ return pipe(
368
+ createTransaction({ version: compiledMessage.version }),
369
+ (tx) => setTransactionFeePayer(feePayer, tx),
370
+ (tx) => instructions.reduce((acc, instruction) => {
371
+ return appendTransactionInstruction(instruction, acc);
372
+ }, tx),
373
+ (tx) => "blockhash" in lifetimeConstraint ? setTransactionLifetimeUsingBlockhash(lifetimeConstraint, tx) : setTransactionLifetimeUsingDurableNonce(lifetimeConstraint, tx),
374
+ (tx) => Object.keys(signatures).length > 0 ? { ...tx, signatures } : tx
375
+ );
376
+ }
101
377
  function upsert(addressMap, address, update) {
102
378
  addressMap[address] = update(addressMap[address] ?? { role: AccountRole.READONLY });
103
379
  }
@@ -114,13 +390,13 @@ function getAddressMapFromInstructions(feePayer, instructions) {
114
390
  if (isWritableRole(entry.role)) {
115
391
  switch (entry[TYPE]) {
116
392
  case 0 /* FEE_PAYER */:
117
- throw new Error(
118
- `This transaction includes an address (\`${instruction.programAddress}\`) which is both invoked and set as the fee payer. Program addresses may not pay fees.`
119
- );
393
+ throw new SolanaError(SOLANA_ERROR__TRANSACTION_INVOKED_PROGRAMS_CANNOT_PAY_FEES, {
394
+ programAddress: instruction.programAddress
395
+ });
120
396
  default:
121
- throw new Error(
122
- `This transaction includes an address (\`${instruction.programAddress}\`) which is both invoked and marked writable. Program addresses may not be writable.`
123
- );
397
+ throw new SolanaError(SOLANA_ERROR__TRANSACTION_INVOKED_PROGRAMS_MUST_NOT_BE_WRITABLE, {
398
+ programAddress: instruction.programAddress
399
+ });
124
400
  }
125
401
  }
126
402
  if (entry[TYPE] === 2 /* STATIC */) {
@@ -150,7 +426,7 @@ function getAddressMapFromInstructions(feePayer, instructions) {
150
426
  const shouldReplaceEntry = (
151
427
  // Consider using the new LOOKUP_TABLE if its address is different...
152
428
  entry.lookupTableAddress !== accountMeta.lookupTableAddress && // ...and sorts before the existing one.
153
- (addressComparator || (addressComparator = getBase58EncodedAddressComparator()))(
429
+ (addressComparator ||= getAddressComparator())(
154
430
  accountMeta.lookupTableAddress,
155
431
  entry.lookupTableAddress
156
432
  ) < 0
@@ -185,8 +461,11 @@ function getAddressMapFromInstructions(feePayer, instructions) {
185
461
  addressesOfInvokedPrograms.has(account.address)
186
462
  ) {
187
463
  if (isWritableRole(accountMeta.role)) {
188
- throw new Error(
189
- `This transaction includes an address (\`${account.address}\`) which is both invoked and marked writable. Program addresses may not be writable.`
464
+ throw new SolanaError(
465
+ SOLANA_ERROR__TRANSACTION_INVOKED_PROGRAMS_MUST_NOT_BE_WRITABLE,
466
+ {
467
+ programAddress: account.address
468
+ }
190
469
  );
191
470
  }
192
471
  if (entry.role !== nextRole) {
@@ -256,7 +535,7 @@ function getOrderedAccountsFromAddressMap(addressMap) {
256
535
  if (leftIsWritable !== isWritableRole(rightEntry.role)) {
257
536
  return leftIsWritable ? -1 : 1;
258
537
  }
259
- addressComparator || (addressComparator = getBase58EncodedAddressComparator());
538
+ addressComparator ||= getAddressComparator();
260
539
  if (leftEntry[TYPE] === 1 /* LOOKUP_TABLE */ && rightEntry[TYPE] === 1 /* LOOKUP_TABLE */ && leftEntry.lookupTableAddress !== rightEntry.lookupTableAddress) {
261
540
  return addressComparator(leftEntry.lookupTableAddress, rightEntry.lookupTableAddress);
262
541
  } else {
@@ -269,23 +548,22 @@ function getOrderedAccountsFromAddressMap(addressMap) {
269
548
  return orderedAccounts;
270
549
  }
271
550
  function getCompiledAddressTableLookups(orderedAccounts) {
272
- var _a;
273
551
  const index = {};
274
552
  for (const account of orderedAccounts) {
275
553
  if (!("lookupTableAddress" in account)) {
276
554
  continue;
277
555
  }
278
- const entry = index[_a = account.lookupTableAddress] || (index[_a] = {
556
+ const entry = index[account.lookupTableAddress] ||= {
279
557
  readableIndices: [],
280
558
  writableIndices: []
281
- });
559
+ };
282
560
  if (account.role === AccountRole.WRITABLE) {
283
561
  entry.writableIndices.push(account.addressIndex);
284
562
  } else {
285
563
  entry.readableIndices.push(account.addressIndex);
286
564
  }
287
565
  }
288
- return Object.keys(index).sort(getBase58EncodedAddressComparator()).map((lookupTableAddress) => ({
566
+ return Object.keys(index).sort(getAddressComparator()).map((lookupTableAddress) => ({
289
567
  lookupTableAddress,
290
568
  ...index[lookupTableAddress]
291
569
  }));
@@ -364,260 +642,293 @@ function compileMessage(transaction) {
364
642
  version: transaction.version
365
643
  };
366
644
  }
367
- function getAddressTableLookupCodec() {
368
- return struct(
369
- [
370
- [
371
- "lookupTableAddress",
372
- getBase58EncodedAddressCodec(
373
- __DEV__ ? {
374
- description: "The address of the address lookup table account from which instruction addresses should be looked up"
375
- } : void 0
376
- )
377
- ],
645
+ var memoizedAddressTableLookupEncoder;
646
+ function getAddressTableLookupEncoder() {
647
+ if (!memoizedAddressTableLookupEncoder) {
648
+ memoizedAddressTableLookupEncoder = getStructEncoder([
649
+ ["lookupTableAddress", getAddressEncoder()],
378
650
  [
379
651
  "writableIndices",
380
- array(u8(), {
381
- ...__DEV__ ? {
382
- description: "The indices of the accounts in the lookup table that should be loaded as writeable"
383
- } : null,
384
- size: shortU16()
385
- })
652
+ getArrayEncoder(getU8Encoder(), { size: getShortU16Encoder() })
386
653
  ],
387
654
  [
388
655
  "readableIndices",
389
- array(u8(), {
390
- ...__DEV__ ? {
391
- description: "The indices of the accounts in the lookup table that should be loaded as read-only"
392
- } : void 0,
393
- size: shortU16()
394
- })
656
+ getArrayEncoder(getU8Encoder(), { size: getShortU16Encoder() })
395
657
  ]
396
- ],
397
- __DEV__ ? {
398
- description: "A pointer to the address of an address lookup table, along with the readonly/writeable indices of the addresses that should be loaded from it"
399
- } : void 0
400
- );
658
+ ]);
659
+ }
660
+ return memoizedAddressTableLookupEncoder;
661
+ }
662
+ var memoizedAddressTableLookupDecoder;
663
+ function getAddressTableLookupDecoder() {
664
+ if (!memoizedAddressTableLookupDecoder) {
665
+ memoizedAddressTableLookupDecoder = getStructDecoder([
666
+ ["lookupTableAddress", getAddressDecoder()],
667
+ ["writableIndices", getArrayDecoder(getU8Decoder(), { size: getShortU16Decoder() })],
668
+ ["readableIndices", getArrayDecoder(getU8Decoder(), { size: getShortU16Decoder() })]
669
+ ]);
670
+ }
671
+ return memoizedAddressTableLookupDecoder;
672
+ }
673
+ var memoizedU8Encoder;
674
+ function getMemoizedU8Encoder() {
675
+ if (!memoizedU8Encoder)
676
+ memoizedU8Encoder = getU8Encoder();
677
+ return memoizedU8Encoder;
678
+ }
679
+ var memoizedU8Decoder;
680
+ function getMemoizedU8Decoder() {
681
+ if (!memoizedU8Decoder)
682
+ memoizedU8Decoder = getU8Decoder();
683
+ return memoizedU8Decoder;
684
+ }
685
+ function getMessageHeaderEncoder() {
686
+ return getStructEncoder([
687
+ ["numSignerAccounts", getMemoizedU8Encoder()],
688
+ ["numReadonlySignerAccounts", getMemoizedU8Encoder()],
689
+ ["numReadonlyNonSignerAccounts", getMemoizedU8Encoder()]
690
+ ]);
401
691
  }
402
- function getMessageHeaderCodec() {
403
- return struct(
404
- [
405
- [
406
- "numSignerAccounts",
407
- u8(
408
- __DEV__ ? {
409
- description: "The expected number of addresses in the static address list belonging to accounts that are required to sign this transaction"
410
- } : void 0
411
- )
412
- ],
413
- [
414
- "numReadonlySignerAccounts",
415
- u8(
416
- __DEV__ ? {
417
- description: "The expected number of addresses in the static address list belonging to accounts that are required to sign this transaction, but may not be writable"
418
- } : void 0
419
- )
420
- ],
421
- [
422
- "numReadonlyNonSignerAccounts",
423
- u8(
424
- __DEV__ ? {
425
- description: "The expected number of addresses in the static address list belonging to accounts that are neither signers, nor writable"
426
- } : void 0
427
- )
428
- ]
429
- ],
430
- __DEV__ ? {
431
- description: "The transaction message header containing counts of the signer, readonly-signer, and readonly-nonsigner account addresses"
432
- } : void 0
433
- );
692
+ function getMessageHeaderDecoder() {
693
+ return getStructDecoder([
694
+ ["numSignerAccounts", getMemoizedU8Decoder()],
695
+ ["numReadonlySignerAccounts", getMemoizedU8Decoder()],
696
+ ["numReadonlyNonSignerAccounts", getMemoizedU8Decoder()]
697
+ ]);
434
698
  }
435
- function getInstructionCodec() {
436
- return mapSerializer(
437
- struct([
438
- [
439
- "programAddressIndex",
440
- u8(
441
- __DEV__ ? {
442
- description: "The index of the program being called, according to the well-ordered accounts list for this transaction"
443
- } : void 0
444
- )
445
- ],
446
- [
447
- "addressIndices",
448
- array(
449
- u8({
450
- description: __DEV__ ? "The index of an account, according to the well-ordered accounts list for this transaction" : ""
451
- }),
452
- {
453
- description: __DEV__ ? "An optional list of account indices, according to the well-ordered accounts list for this transaction, in the order in which the program being called expects them" : "",
454
- size: shortU16()
455
- }
456
- )
457
- ],
458
- [
459
- "data",
460
- bytes({
461
- description: __DEV__ ? "An optional buffer of data passed to the instruction" : "",
462
- size: shortU16()
463
- })
464
- ]
699
+ var memoizedGetInstructionEncoder;
700
+ function getInstructionEncoder() {
701
+ if (!memoizedGetInstructionEncoder) {
702
+ memoizedGetInstructionEncoder = mapEncoder(
703
+ getStructEncoder([
704
+ ["programAddressIndex", getU8Encoder()],
705
+ ["accountIndices", getArrayEncoder(getU8Encoder(), { size: getShortU16Encoder() })],
706
+ ["data", getBytesEncoder({ size: getShortU16Encoder() })]
707
+ ]),
708
+ // Convert an instruction to have all fields defined
709
+ (instruction) => {
710
+ if (instruction.accountIndices !== void 0 && instruction.data !== void 0) {
711
+ return instruction;
712
+ }
713
+ return {
714
+ ...instruction,
715
+ accountIndices: instruction.accountIndices ?? [],
716
+ data: instruction.data ?? new Uint8Array(0)
717
+ };
718
+ }
719
+ );
720
+ }
721
+ return memoizedGetInstructionEncoder;
722
+ }
723
+ var memoizedGetInstructionDecoder;
724
+ function getInstructionDecoder() {
725
+ if (!memoizedGetInstructionDecoder) {
726
+ memoizedGetInstructionDecoder = mapDecoder(
727
+ getStructDecoder([
728
+ ["programAddressIndex", getU8Decoder()],
729
+ ["accountIndices", getArrayDecoder(getU8Decoder(), { size: getShortU16Decoder() })],
730
+ ["data", getBytesDecoder({ size: getShortU16Decoder() })]
731
+ ]),
732
+ // Convert an instruction to exclude optional fields if they are empty
733
+ (instruction) => {
734
+ if (instruction.accountIndices.length && instruction.data.byteLength) {
735
+ return instruction;
736
+ }
737
+ const { accountIndices, data, ...rest } = instruction;
738
+ return {
739
+ ...rest,
740
+ ...accountIndices.length ? { accountIndices } : null,
741
+ ...data.byteLength ? { data } : null
742
+ };
743
+ }
744
+ );
745
+ }
746
+ return memoizedGetInstructionDecoder;
747
+ }
748
+ var VERSION_FLAG_MASK = 128;
749
+ function getTransactionVersionEncoder() {
750
+ return createEncoder({
751
+ getSizeFromValue: (value) => value === "legacy" ? 0 : 1,
752
+ maxSize: 1,
753
+ write: (value, bytes, offset) => {
754
+ if (value === "legacy") {
755
+ return offset;
756
+ }
757
+ if (value < 0 || value > 127) {
758
+ throw new SolanaError(SOLANA_ERROR__TRANSACTION_VERSION_NUMBER_OUT_OF_RANGE, {
759
+ actualVersion: value
760
+ });
761
+ }
762
+ bytes.set([value | VERSION_FLAG_MASK], offset);
763
+ return offset + 1;
764
+ }
765
+ });
766
+ }
767
+ function getTransactionVersionDecoder() {
768
+ return createDecoder({
769
+ maxSize: 1,
770
+ read: (bytes, offset) => {
771
+ const firstByte = bytes[offset];
772
+ if ((firstByte & VERSION_FLAG_MASK) === 0) {
773
+ return ["legacy", offset];
774
+ } else {
775
+ const version = firstByte ^ VERSION_FLAG_MASK;
776
+ return [version, offset + 1];
777
+ }
778
+ }
779
+ });
780
+ }
781
+
782
+ // src/serializers/message.ts
783
+ function getCompiledMessageLegacyEncoder() {
784
+ return getStructEncoder(getPreludeStructEncoderTuple());
785
+ }
786
+ function getCompiledMessageVersionedEncoder() {
787
+ return mapEncoder(
788
+ getStructEncoder([
789
+ ...getPreludeStructEncoderTuple(),
790
+ ["addressTableLookups", getAddressTableLookupArrayEncoder()]
465
791
  ]),
466
792
  (value) => {
467
- if (value.addressIndices !== void 0 && value.data !== void 0) {
793
+ if (value.version === "legacy") {
468
794
  return value;
469
795
  }
470
796
  return {
471
797
  ...value,
472
- addressIndices: value.addressIndices ?? [],
473
- data: value.data ?? new Uint8Array(0)
798
+ addressTableLookups: value.addressTableLookups ?? []
474
799
  };
800
+ }
801
+ );
802
+ }
803
+ function getPreludeStructEncoderTuple() {
804
+ return [
805
+ ["version", getTransactionVersionEncoder()],
806
+ ["header", getMessageHeaderEncoder()],
807
+ ["staticAccounts", getArrayEncoder(getAddressEncoder(), { size: getShortU16Encoder() })],
808
+ ["lifetimeToken", getStringEncoder({ encoding: getBase58Encoder(), size: 32 })],
809
+ ["instructions", getArrayEncoder(getInstructionEncoder(), { size: getShortU16Encoder() })]
810
+ ];
811
+ }
812
+ function getPreludeStructDecoderTuple() {
813
+ return [
814
+ ["version", getTransactionVersionDecoder()],
815
+ ["header", getMessageHeaderDecoder()],
816
+ ["staticAccounts", getArrayDecoder(getAddressDecoder(), { size: getShortU16Decoder() })],
817
+ ["lifetimeToken", getStringDecoder({ encoding: getBase58Decoder(), size: 32 })],
818
+ ["instructions", getArrayDecoder(getInstructionDecoder(), { size: getShortU16Decoder() })],
819
+ ["addressTableLookups", getAddressTableLookupArrayDecoder()]
820
+ ];
821
+ }
822
+ function getAddressTableLookupArrayEncoder() {
823
+ return getArrayEncoder(getAddressTableLookupEncoder(), { size: getShortU16Encoder() });
824
+ }
825
+ function getAddressTableLookupArrayDecoder() {
826
+ return getArrayDecoder(getAddressTableLookupDecoder(), { size: getShortU16Decoder() });
827
+ }
828
+ function getCompiledMessageEncoder() {
829
+ return createEncoder({
830
+ getSizeFromValue: (compiledMessage) => {
831
+ if (compiledMessage.version === "legacy") {
832
+ return getCompiledMessageLegacyEncoder().getSizeFromValue(compiledMessage);
833
+ } else {
834
+ return getCompiledMessageVersionedEncoder().getSizeFromValue(compiledMessage);
835
+ }
475
836
  },
476
- (value) => {
477
- if (value.addressIndices.length && value.data.byteLength) {
478
- return value;
837
+ write: (compiledMessage, bytes, offset) => {
838
+ if (compiledMessage.version === "legacy") {
839
+ return getCompiledMessageLegacyEncoder().write(compiledMessage, bytes, offset);
840
+ } else {
841
+ return getCompiledMessageVersionedEncoder().write(compiledMessage, bytes, offset);
479
842
  }
480
- const { addressIndices, data, ...rest } = value;
481
- return {
482
- ...rest,
483
- ...addressIndices.length ? { addressIndices } : null,
484
- ...data.byteLength ? { data } : null
485
- };
486
843
  }
487
- );
844
+ });
488
845
  }
489
-
490
- // src/serializers/unimplemented.ts
491
- function getError(type, name) {
492
- const functionSuffix = name + type[0].toUpperCase() + type.slice(1);
493
- return new Error(
494
- `No ${type} exists for ${name}. Use \`get${functionSuffix}()\` if you need a ${type}, and \`get${name}Codec()\` if you need to both encode and decode ${name}`
846
+ function getCompiledMessageDecoder() {
847
+ return mapDecoder(
848
+ getStructDecoder(getPreludeStructDecoderTuple()),
849
+ ({ addressTableLookups, ...restOfMessage }) => {
850
+ if (restOfMessage.version === "legacy" || !addressTableLookups?.length) {
851
+ return restOfMessage;
852
+ }
853
+ return { ...restOfMessage, addressTableLookups };
854
+ }
495
855
  );
496
856
  }
497
- function getUnimplementedDecoder(name) {
498
- return () => {
499
- throw getError("decoder", name);
500
- };
857
+ function getCompiledMessageCodec() {
858
+ return combineCodec(getCompiledMessageEncoder(), getCompiledMessageDecoder());
501
859
  }
502
860
 
503
- // src/serializers/transaction-version.ts
504
- var VERSION_FLAG_MASK = 128;
505
- var BASE_CONFIG = {
506
- description: __DEV__ ? "A single byte that encodes the version of the transaction" : "",
507
- fixedSize: null,
508
- maxSize: 1
509
- };
510
- function deserialize(bytes2, offset = 0) {
511
- const firstByte = bytes2[offset];
512
- if ((firstByte & VERSION_FLAG_MASK) === 0) {
513
- return ["legacy", offset];
861
+ // src/compile-transaction.ts
862
+ function getCompiledTransaction(transaction) {
863
+ const compiledMessage = compileMessage(transaction);
864
+ let signatures;
865
+ if ("signatures" in transaction) {
866
+ signatures = [];
867
+ for (let ii = 0; ii < compiledMessage.header.numSignerAccounts; ii++) {
868
+ signatures[ii] = transaction.signatures[compiledMessage.staticAccounts[ii]] ?? new Uint8Array(Array(64).fill(0));
869
+ }
514
870
  } else {
515
- const version = firstByte ^ VERSION_FLAG_MASK;
516
- return [version, offset + 1];
871
+ signatures = Array(compiledMessage.header.numSignerAccounts).fill(new Uint8Array(Array(64).fill(0)));
517
872
  }
518
- }
519
- function serialize(value) {
520
- if (value === "legacy") {
521
- return new Uint8Array();
522
- }
523
- if (value < 0 || value > 127) {
524
- throw new Error(`Transaction version must be in the range [0, 127]. \`${value}\` given.`);
525
- }
526
- return new Uint8Array([value | VERSION_FLAG_MASK]);
527
- }
528
- function getTransactionVersionCodec() {
529
873
  return {
530
- ...BASE_CONFIG,
531
- deserialize,
532
- serialize
874
+ compiledMessage,
875
+ signatures
533
876
  };
534
877
  }
535
878
 
536
- // src/serializers/message.ts
537
- var BASE_CONFIG2 = {
538
- description: __DEV__ ? "The wire format of a Solana transaction message" : "",
539
- fixedSize: null,
540
- maxSize: null
541
- };
542
- function serialize2(compiledMessage) {
543
- if (compiledMessage.version === "legacy") {
544
- return struct(getPreludeStructSerializerTuple()).serialize(compiledMessage);
545
- } else {
546
- return mapSerializer(
547
- struct([
548
- ...getPreludeStructSerializerTuple(),
549
- ["addressTableLookups", getAddressTableLookupsSerializer()]
550
- ]),
551
- (value) => {
552
- if (value.version === "legacy") {
553
- return value;
554
- }
555
- return {
556
- ...value,
557
- addressTableLookups: value.addressTableLookups ?? []
558
- };
559
- }
560
- ).serialize(compiledMessage);
561
- }
879
+ // src/serializers/transaction.ts
880
+ function getCompiledTransactionEncoder() {
881
+ return getStructEncoder([
882
+ ["signatures", getArrayEncoder(getBytesEncoder({ size: 64 }), { size: getShortU16Encoder() })],
883
+ ["compiledMessage", getCompiledMessageEncoder()]
884
+ ]);
562
885
  }
563
- function getPreludeStructSerializerTuple() {
564
- return [
565
- ["version", getTransactionVersionCodec()],
566
- ["header", getMessageHeaderCodec()],
567
- [
568
- "staticAccounts",
569
- array(getBase58EncodedAddressCodec(), {
570
- description: __DEV__ ? "A compact-array of static account addresses belonging to this transaction" : "",
571
- size: shortU16()
572
- })
573
- ],
886
+ function getCompiledTransactionDecoder() {
887
+ return getStructDecoder([
574
888
  [
575
- "lifetimeToken",
576
- string({
577
- description: __DEV__ ? "A 32-byte token that specifies the lifetime of this transaction (eg. a recent blockhash, or a durable nonce)" : "",
578
- encoding: base58,
579
- size: 32
889
+ "signatures",
890
+ getArrayDecoder(getBytesDecoder({ size: 64 }), {
891
+ size: getShortU16Decoder()
580
892
  })
581
893
  ],
582
- [
583
- "instructions",
584
- array(getInstructionCodec(), {
585
- description: __DEV__ ? "A compact-array of instructions belonging to this transaction" : "",
586
- size: shortU16()
587
- })
588
- ]
589
- ];
894
+ ["compiledMessage", getCompiledMessageDecoder()]
895
+ ]);
590
896
  }
591
- function getAddressTableLookupsSerializer() {
592
- return array(getAddressTableLookupCodec(), {
593
- ...__DEV__ ? { description: "A compact array of address table lookups belonging to this transaction" } : null,
594
- size: shortU16()
595
- });
897
+ function getTransactionEncoder() {
898
+ return mapEncoder(getCompiledTransactionEncoder(), getCompiledTransaction);
596
899
  }
597
- function getCompiledMessageEncoder() {
598
- return {
599
- ...BASE_CONFIG2,
600
- deserialize: getUnimplementedDecoder("CompiledMessage"),
601
- serialize: serialize2
602
- };
900
+ function getTransactionDecoder(config) {
901
+ return mapDecoder(
902
+ getCompiledTransactionDecoder(),
903
+ (compiledTransaction) => decompileTransaction(compiledTransaction, config)
904
+ );
603
905
  }
604
-
605
- // src/signatures.ts
606
- async function getCompiledMessageSignature(message, secretKey) {
607
- const wireMessageBytes = getCompiledMessageEncoder().serialize(message);
608
- const signature = await signBytes(secretKey, wireMessageBytes);
609
- return signature;
906
+ function getTransactionCodec(config) {
907
+ return combineCodec(getTransactionEncoder(), getTransactionDecoder(config));
610
908
  }
611
- async function signTransaction(keyPair, transaction) {
909
+ var base58Decoder;
910
+ function getSignatureFromTransaction(transaction) {
911
+ if (!base58Decoder)
912
+ base58Decoder = getBase58Decoder();
913
+ const signatureBytes = transaction.signatures[transaction.feePayer];
914
+ if (!signatureBytes) {
915
+ throw new SolanaError(SOLANA_ERROR__TRANSACTION_SIGNATURE_NOT_COMPUTABLE);
916
+ }
917
+ const transactionSignature = base58Decoder.decode(signatureBytes);
918
+ return transactionSignature;
919
+ }
920
+ async function partiallySignTransaction(keyPairs, transaction) {
612
921
  const compiledMessage = compileMessage(transaction);
613
- const [signerPublicKey, signature] = await Promise.all([
614
- getBase58EncodedAddressFromPublicKey(keyPair.publicKey),
615
- getCompiledMessageSignature(compiledMessage, keyPair.privateKey)
616
- ]);
617
- const nextSignatures = {
618
- ..."signatures" in transaction ? transaction.signatures : null,
619
- ...{ [signerPublicKey]: signature }
620
- };
922
+ const nextSignatures = "signatures" in transaction ? { ...transaction.signatures } : {};
923
+ const wireMessageBytes = getCompiledMessageEncoder().encode(compiledMessage);
924
+ const publicKeySignaturePairs = await Promise.all(
925
+ keyPairs.map(
926
+ (keyPair) => Promise.all([getAddressFromPublicKey(keyPair.publicKey), signBytes(keyPair.privateKey, wireMessageBytes)])
927
+ )
928
+ );
929
+ for (const [signerPublicKey, signature] of publicKeySignaturePairs) {
930
+ nextSignatures[signerPublicKey] = signature;
931
+ }
621
932
  const out = {
622
933
  ...transaction,
623
934
  signatures: nextSignatures
@@ -625,7 +936,32 @@ async function signTransaction(keyPair, transaction) {
625
936
  Object.freeze(out);
626
937
  return out;
627
938
  }
939
+ async function signTransaction(keyPairs, transaction) {
940
+ const out = await partiallySignTransaction(keyPairs, transaction);
941
+ assertTransactionIsFullySigned(out);
942
+ Object.freeze(out);
943
+ return out;
944
+ }
945
+ function assertTransactionIsFullySigned(transaction) {
946
+ const signerAddressesFromInstructions = transaction.instructions.flatMap((i) => i.accounts?.filter((a) => isSignerRole(a.role)) ?? []).map((a) => a.address);
947
+ const requiredSigners = /* @__PURE__ */ new Set([transaction.feePayer, ...signerAddressesFromInstructions]);
948
+ const missingSigs = [];
949
+ requiredSigners.forEach((address) => {
950
+ if (!transaction.signatures[address]) {
951
+ missingSigs.push(address);
952
+ }
953
+ });
954
+ if (missingSigs.length > 0) {
955
+ throw new SolanaError(SOLANA_ERROR__TRANSACTION_MISSING_SIGNATURES, {
956
+ addresses: missingSigs
957
+ });
958
+ }
959
+ }
960
+ function getBase64EncodedWireTransaction(transaction) {
961
+ const wireTransactionBytes = getTransactionEncoder().encode(transaction);
962
+ return getBase64Decoder().decode(wireTransactionBytes);
963
+ }
628
964
 
629
- export { appendTransactionInstruction, createTransaction, prependTransactionInstruction, setTransactionFeePayer, signTransaction };
965
+ export { appendTransactionInstruction, appendTransactionInstructions, assertIsDurableNonceTransaction, assertIsTransactionWithBlockhashLifetime, assertTransactionIsFullySigned, compileMessage, createTransaction, decompileTransaction, getBase64EncodedWireTransaction, getCompiledMessageCodec, getCompiledMessageDecoder, getCompiledMessageEncoder, getCompiledTransactionDecoder, getSignatureFromTransaction, getTransactionCodec, getTransactionDecoder, getTransactionEncoder, getUnsignedTransaction, isAdvanceNonceAccountInstruction, partiallySignTransaction, prependTransactionInstruction, prependTransactionInstructions, setTransactionFeePayer, setTransactionLifetimeUsingBlockhash, setTransactionLifetimeUsingDurableNonce, signTransaction };
630
966
  //# sourceMappingURL=out.js.map
631
967
  //# sourceMappingURL=index.browser.js.map