@solana/transactions 2.0.0-experimental.6b66b7d → 2.0.0-experimental.6bfb261

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