@solana/transactions 2.0.0-experimental.fb88a79 → 2.0.0-experimental.fbbf6ba

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 (46) hide show
  1. package/README.md +7 -3
  2. package/dist/index.browser.cjs +189 -139
  3. package/dist/index.browser.cjs.map +1 -1
  4. package/dist/index.browser.js +189 -143
  5. package/dist/index.browser.js.map +1 -1
  6. package/dist/index.native.js +189 -143
  7. package/dist/index.native.js.map +1 -1
  8. package/dist/index.node.cjs +189 -139
  9. package/dist/index.node.cjs.map +1 -1
  10. package/dist/index.node.js +189 -143
  11. package/dist/index.node.js.map +1 -1
  12. package/dist/types/blockhash.d.ts +4 -7
  13. package/dist/types/blockhash.d.ts.map +1 -1
  14. package/dist/types/compilable-transaction.d.ts +4 -4
  15. package/dist/types/compile-address-table-lookups.d.ts +1 -1
  16. package/dist/types/compile-header.d.ts +1 -1
  17. package/dist/types/compile-instructions.d.ts +1 -1
  18. package/dist/types/compile-lifetime-token.d.ts +1 -1
  19. package/dist/types/compile-static-accounts.d.ts +1 -1
  20. package/dist/types/compile-transaction.d.ts +3 -3
  21. package/dist/types/create-transaction.d.ts +1 -1
  22. package/dist/types/decompile-transaction.d.ts +12 -4
  23. package/dist/types/decompile-transaction.d.ts.map +1 -1
  24. package/dist/types/durable-nonce.d.ts +2 -2
  25. package/dist/types/fee-payer.d.ts +2 -2
  26. package/dist/types/index.d.ts +13 -11
  27. package/dist/types/index.d.ts.map +1 -1
  28. package/dist/types/instructions.d.ts +4 -2
  29. package/dist/types/instructions.d.ts.map +1 -1
  30. package/dist/types/message.d.ts +6 -6
  31. package/dist/types/serializers/address-table-lookup.d.ts +1 -1
  32. package/dist/types/serializers/header.d.ts +1 -1
  33. package/dist/types/serializers/index.d.ts +2 -2
  34. package/dist/types/serializers/instruction.d.ts +1 -1
  35. package/dist/types/serializers/message.d.ts +1 -1
  36. package/dist/types/serializers/transaction-version.d.ts +1 -1
  37. package/dist/types/serializers/transaction.d.ts +7 -4
  38. package/dist/types/serializers/transaction.d.ts.map +1 -1
  39. package/dist/types/signatures.d.ts +2 -2
  40. package/dist/types/signatures.d.ts.map +1 -1
  41. package/dist/types/unsigned-transaction.d.ts +1 -1
  42. package/dist/types/wire-transaction.d.ts +1 -1
  43. package/package.json +18 -39
  44. package/dist/index.development.js +0 -1628
  45. package/dist/index.development.js.map +0 -1
  46. package/dist/index.production.min.js +0 -32
@@ -1,28 +1,13 @@
1
- import { getBase58Encoder, getBase58Decoder, getBase64Decoder, getStringEncoder, getStringDecoder } from '@solana/codecs-strings';
2
- import { getAddressFromPublicKey, getAddressComparator, getAddressEncoder, getAddressDecoder, assertIsAddress } from '@solana/addresses';
3
- import { createEncoder, mapDecoder, combineCodec, mapEncoder, createDecoder } from '@solana/codecs-core';
4
- import { getStructDecoder, getStructEncoder, getArrayEncoder, getArrayDecoder, getBytesEncoder, getBytesDecoder } from '@solana/codecs-data-structures';
5
- import { getShortU16Encoder, getShortU16Decoder, getU8Encoder, getU8Decoder } from '@solana/codecs-numbers';
1
+ import { getBase58Decoder, getBase64Decoder, getStringEncoder, getBase58Encoder, getStringDecoder } from '@solana/codecs-strings';
2
+ import { getAddressFromPublicKey, assertIsAddress, getAddressComparator, getAddressEncoder, getAddressDecoder } from '@solana/addresses';
6
3
  import { pipe } from '@solana/functional';
4
+ import { createEncoder, mapDecoder, combineCodec, mapEncoder, createDecoder } from '@solana/codecs-core';
5
+ import { getStructDecoder, getArrayDecoder, getBytesDecoder, getStructEncoder, getArrayEncoder, getBytesEncoder } from '@solana/codecs-data-structures';
6
+ import { getShortU16Decoder, getShortU16Encoder, getU8Encoder, getU8Decoder } from '@solana/codecs-numbers';
7
+ import { SolanaError, SOLANA_ERROR__TRANSACTION_SIGNATURE_NOT_COMPUTABLE, SOLANA_ERROR__TRANSACTION_MISSING_SIGNATURES } from '@solana/errors';
7
8
  import { signBytes } from '@solana/keys';
8
9
 
9
- // src/blockhash.ts
10
-
11
- // src/unsigned-transaction.ts
12
- function getUnsignedTransaction(transaction) {
13
- if ("signatures" in transaction) {
14
- const {
15
- signatures: _,
16
- // eslint-disable-line @typescript-eslint/no-unused-vars
17
- ...unsignedTransaction
18
- } = transaction;
19
- return unsignedTransaction;
20
- } else {
21
- return transaction;
22
- }
23
- }
24
-
25
- // src/blockhash.ts
10
+ // ../rpc-types/dist/index.browser.js
26
11
  var base58Encoder;
27
12
  function assertIsBlockhash(putativeBlockhash) {
28
13
  if (!base58Encoder)
@@ -46,6 +31,22 @@ function assertIsBlockhash(putativeBlockhash) {
46
31
  });
47
32
  }
48
33
  }
34
+
35
+ // src/unsigned-transaction.ts
36
+ function getUnsignedTransaction(transaction) {
37
+ if ("signatures" in transaction) {
38
+ const {
39
+ signatures: _,
40
+ // eslint-disable-line @typescript-eslint/no-unused-vars
41
+ ...unsignedTransaction
42
+ } = transaction;
43
+ return unsignedTransaction;
44
+ } else {
45
+ return transaction;
46
+ }
47
+ }
48
+
49
+ // src/blockhash.ts
49
50
  function isTransactionWithBlockhashLifetime(transaction) {
50
51
  const lifetimeConstraintShapeMatches = "lifetimeConstraint" in transaction && typeof transaction.lifetimeConstraint.blockhash === "string" && typeof transaction.lifetimeConstraint.lastValidBlockHeight === "bigint";
51
52
  if (!lifetimeConstraintShapeMatches)
@@ -200,21 +201,172 @@ function setTransactionFeePayer(feePayer, transaction) {
200
201
 
201
202
  // src/instructions.ts
202
203
  function appendTransactionInstruction(instruction, transaction) {
204
+ return appendTransactionInstructions([instruction], transaction);
205
+ }
206
+ function appendTransactionInstructions(instructions, transaction) {
203
207
  const out = {
204
208
  ...getUnsignedTransaction(transaction),
205
- instructions: [...transaction.instructions, instruction]
209
+ instructions: [...transaction.instructions, ...instructions]
206
210
  };
207
211
  Object.freeze(out);
208
212
  return out;
209
213
  }
210
214
  function prependTransactionInstruction(instruction, transaction) {
215
+ return prependTransactionInstructions([instruction], transaction);
216
+ }
217
+ function prependTransactionInstructions(instructions, transaction) {
211
218
  const out = {
212
219
  ...getUnsignedTransaction(transaction),
213
- instructions: [instruction, ...transaction.instructions]
220
+ instructions: [...instructions, ...transaction.instructions]
214
221
  };
215
222
  Object.freeze(out);
216
223
  return out;
217
224
  }
225
+
226
+ // src/decompile-transaction.ts
227
+ function getAccountMetas(message) {
228
+ const { header } = message;
229
+ const numWritableSignerAccounts = header.numSignerAccounts - header.numReadonlySignerAccounts;
230
+ const numWritableNonSignerAccounts = message.staticAccounts.length - header.numSignerAccounts - header.numReadonlyNonSignerAccounts;
231
+ const accountMetas = [];
232
+ let accountIndex = 0;
233
+ for (let i = 0; i < numWritableSignerAccounts; i++) {
234
+ accountMetas.push({
235
+ address: message.staticAccounts[accountIndex],
236
+ role: AccountRole.WRITABLE_SIGNER
237
+ });
238
+ accountIndex++;
239
+ }
240
+ for (let i = 0; i < header.numReadonlySignerAccounts; i++) {
241
+ accountMetas.push({
242
+ address: message.staticAccounts[accountIndex],
243
+ role: AccountRole.READONLY_SIGNER
244
+ });
245
+ accountIndex++;
246
+ }
247
+ for (let i = 0; i < numWritableNonSignerAccounts; i++) {
248
+ accountMetas.push({
249
+ address: message.staticAccounts[accountIndex],
250
+ role: AccountRole.WRITABLE
251
+ });
252
+ accountIndex++;
253
+ }
254
+ for (let i = 0; i < header.numReadonlyNonSignerAccounts; i++) {
255
+ accountMetas.push({
256
+ address: message.staticAccounts[accountIndex],
257
+ role: AccountRole.READONLY
258
+ });
259
+ accountIndex++;
260
+ }
261
+ return accountMetas;
262
+ }
263
+ function getAddressLookupMetas(compiledAddressTableLookups, addressesByLookupTableAddress) {
264
+ const compiledAddressTableLookupAddresses = compiledAddressTableLookups.map((l) => l.lookupTableAddress);
265
+ const missing = compiledAddressTableLookupAddresses.filter((a) => addressesByLookupTableAddress[a] === void 0);
266
+ if (missing.length > 0) {
267
+ const missingAddresses = missing.join(", ");
268
+ throw new Error(`Addresses not provided for lookup tables: [${missingAddresses}]`);
269
+ }
270
+ const readOnlyMetas = [];
271
+ const writableMetas = [];
272
+ for (const lookup of compiledAddressTableLookups) {
273
+ const addresses = addressesByLookupTableAddress[lookup.lookupTableAddress];
274
+ const highestIndex = Math.max(...lookup.readableIndices, ...lookup.writableIndices);
275
+ if (highestIndex >= addresses.length) {
276
+ throw new Error(
277
+ `Cannot look up index ${highestIndex} in lookup table [${lookup.lookupTableAddress}]. The lookup table may have been extended since the addresses provided were retrieved.`
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 Error(`Could not find program address at index ${instruction.programAddressIndex}`);
301
+ }
302
+ const accounts = instruction.accountIndices?.map((accountIndex) => accountMetas[accountIndex]);
303
+ const { data } = instruction;
304
+ return {
305
+ programAddress,
306
+ ...accounts && accounts.length ? { accounts } : {},
307
+ ...data && data.length ? { data } : {}
308
+ };
309
+ }
310
+ function getLifetimeConstraint(messageLifetimeToken, firstInstruction, lastValidBlockHeight) {
311
+ if (!firstInstruction || !isAdvanceNonceAccountInstruction(firstInstruction)) {
312
+ return {
313
+ blockhash: messageLifetimeToken,
314
+ lastValidBlockHeight: lastValidBlockHeight ?? 2n ** 64n - 1n
315
+ // U64 MAX
316
+ };
317
+ } else {
318
+ const nonceAccountAddress = firstInstruction.accounts[0].address;
319
+ assertIsAddress(nonceAccountAddress);
320
+ const nonceAuthorityAddress = firstInstruction.accounts[2].address;
321
+ assertIsAddress(nonceAuthorityAddress);
322
+ return {
323
+ nonce: messageLifetimeToken,
324
+ nonceAccountAddress,
325
+ nonceAuthorityAddress
326
+ };
327
+ }
328
+ }
329
+ function convertSignatures(compiledTransaction) {
330
+ const {
331
+ compiledMessage: { staticAccounts },
332
+ signatures
333
+ } = compiledTransaction;
334
+ return signatures.reduce((acc, sig, index) => {
335
+ const allZeros = sig.every((byte) => byte === 0);
336
+ if (allZeros)
337
+ return acc;
338
+ const address = staticAccounts[index];
339
+ return { ...acc, [address]: sig };
340
+ }, {});
341
+ }
342
+ function decompileTransaction(compiledTransaction, config) {
343
+ const { compiledMessage } = compiledTransaction;
344
+ const feePayer = compiledMessage.staticAccounts[0];
345
+ if (!feePayer)
346
+ throw new Error("No fee payer set in CompiledTransaction");
347
+ const accountMetas = getAccountMetas(compiledMessage);
348
+ const accountLookupMetas = "addressTableLookups" in compiledMessage && compiledMessage.addressTableLookups !== void 0 && compiledMessage.addressTableLookups.length > 0 ? getAddressLookupMetas(compiledMessage.addressTableLookups, config?.addressesByLookupTableAddress ?? {}) : [];
349
+ const transactionMetas = [...accountMetas, ...accountLookupMetas];
350
+ const instructions = compiledMessage.instructions.map(
351
+ (compiledInstruction) => convertInstruction(compiledInstruction, transactionMetas)
352
+ );
353
+ const firstInstruction = instructions[0];
354
+ const lifetimeConstraint = getLifetimeConstraint(
355
+ compiledMessage.lifetimeToken,
356
+ firstInstruction,
357
+ config?.lastValidBlockHeight
358
+ );
359
+ const signatures = convertSignatures(compiledTransaction);
360
+ return pipe(
361
+ createTransaction({ version: compiledMessage.version }),
362
+ (tx) => setTransactionFeePayer(feePayer, tx),
363
+ (tx) => instructions.reduce((acc, instruction) => {
364
+ return appendTransactionInstruction(instruction, acc);
365
+ }, tx),
366
+ (tx) => "blockhash" in lifetimeConstraint ? setTransactionLifetimeUsingBlockhash(lifetimeConstraint, tx) : setTransactionLifetimeUsingDurableNonce(lifetimeConstraint, tx),
367
+ (tx) => Object.keys(signatures).length > 0 ? { ...tx, signatures } : tx
368
+ );
369
+ }
218
370
  function upsert(addressMap, address, update) {
219
371
  addressMap[address] = update(addressMap[address] ?? { role: AccountRole.READONLY });
220
372
  }
@@ -708,116 +860,6 @@ function getCompiledTransaction(transaction) {
708
860
  signatures
709
861
  };
710
862
  }
711
- function getAccountMetas(message) {
712
- const { header } = message;
713
- const numWritableSignerAccounts = header.numSignerAccounts - header.numReadonlySignerAccounts;
714
- const numWritableNonSignerAccounts = message.staticAccounts.length - header.numSignerAccounts - header.numReadonlyNonSignerAccounts;
715
- const accountMetas = [];
716
- let accountIndex = 0;
717
- for (let i = 0; i < numWritableSignerAccounts; i++) {
718
- accountMetas.push({
719
- address: message.staticAccounts[accountIndex],
720
- role: AccountRole.WRITABLE_SIGNER
721
- });
722
- accountIndex++;
723
- }
724
- for (let i = 0; i < header.numReadonlySignerAccounts; i++) {
725
- accountMetas.push({
726
- address: message.staticAccounts[accountIndex],
727
- role: AccountRole.READONLY_SIGNER
728
- });
729
- accountIndex++;
730
- }
731
- for (let i = 0; i < numWritableNonSignerAccounts; i++) {
732
- accountMetas.push({
733
- address: message.staticAccounts[accountIndex],
734
- role: AccountRole.WRITABLE
735
- });
736
- accountIndex++;
737
- }
738
- for (let i = 0; i < header.numReadonlyNonSignerAccounts; i++) {
739
- accountMetas.push({
740
- address: message.staticAccounts[accountIndex],
741
- role: AccountRole.READONLY
742
- });
743
- accountIndex++;
744
- }
745
- return accountMetas;
746
- }
747
- function convertInstruction(instruction, accountMetas) {
748
- const programAddress = accountMetas[instruction.programAddressIndex]?.address;
749
- if (!programAddress) {
750
- throw new Error(`Could not find program address at index ${instruction.programAddressIndex}`);
751
- }
752
- const accounts = instruction.accountIndices?.map((accountIndex) => accountMetas[accountIndex]);
753
- const { data } = instruction;
754
- return {
755
- programAddress,
756
- ...accounts && accounts.length ? { accounts } : {},
757
- ...data && data.length ? { data } : {}
758
- };
759
- }
760
- function getLifetimeConstraint(messageLifetimeToken, firstInstruction, lastValidBlockHeight) {
761
- if (!firstInstruction || !isAdvanceNonceAccountInstruction(firstInstruction)) {
762
- return {
763
- blockhash: messageLifetimeToken,
764
- lastValidBlockHeight: lastValidBlockHeight ?? 2n ** 64n - 1n
765
- // U64 MAX
766
- };
767
- } else {
768
- const nonceAccountAddress = firstInstruction.accounts[0].address;
769
- assertIsAddress(nonceAccountAddress);
770
- const nonceAuthorityAddress = firstInstruction.accounts[2].address;
771
- assertIsAddress(nonceAuthorityAddress);
772
- return {
773
- nonce: messageLifetimeToken,
774
- nonceAccountAddress,
775
- nonceAuthorityAddress
776
- };
777
- }
778
- }
779
- function convertSignatures(compiledTransaction) {
780
- const {
781
- compiledMessage: { staticAccounts },
782
- signatures
783
- } = compiledTransaction;
784
- return signatures.reduce((acc, sig, index) => {
785
- const allZeros = sig.every((byte) => byte === 0);
786
- if (allZeros)
787
- return acc;
788
- const address = staticAccounts[index];
789
- return { ...acc, [address]: sig };
790
- }, {});
791
- }
792
- function decompileTransaction(compiledTransaction, lastValidBlockHeight) {
793
- const { compiledMessage } = compiledTransaction;
794
- if ("addressTableLookups" in compiledMessage && compiledMessage.addressTableLookups.length > 0) {
795
- throw new Error("Cannot convert transaction with addressTableLookups");
796
- }
797
- const feePayer = compiledMessage.staticAccounts[0];
798
- if (!feePayer)
799
- throw new Error("No fee payer set in CompiledTransaction");
800
- const accountMetas = getAccountMetas(compiledMessage);
801
- const instructions = compiledMessage.instructions.map(
802
- (compiledInstruction) => convertInstruction(compiledInstruction, accountMetas)
803
- );
804
- const firstInstruction = instructions[0];
805
- const lifetimeConstraint = getLifetimeConstraint(
806
- compiledMessage.lifetimeToken,
807
- firstInstruction,
808
- lastValidBlockHeight
809
- );
810
- const signatures = convertSignatures(compiledTransaction);
811
- return pipe(
812
- createTransaction({ version: compiledMessage.version }),
813
- (tx) => setTransactionFeePayer(feePayer, tx),
814
- (tx) => instructions.reduce((acc, instruction) => {
815
- return appendTransactionInstruction(instruction, acc);
816
- }, tx),
817
- (tx) => "blockhash" in lifetimeConstraint ? setTransactionLifetimeUsingBlockhash(lifetimeConstraint, tx) : setTransactionLifetimeUsingDurableNonce(lifetimeConstraint, tx),
818
- (tx) => compiledTransaction.signatures.length ? { ...tx, signatures } : tx
819
- );
820
- }
821
863
 
822
864
  // src/serializers/transaction.ts
823
865
  function getCompiledTransactionEncoder() {
@@ -840,14 +882,14 @@ function getCompiledTransactionDecoder() {
840
882
  function getTransactionEncoder() {
841
883
  return mapEncoder(getCompiledTransactionEncoder(), getCompiledTransaction);
842
884
  }
843
- function getTransactionDecoder(lastValidBlockHeight) {
885
+ function getTransactionDecoder(config) {
844
886
  return mapDecoder(
845
887
  getCompiledTransactionDecoder(),
846
- (compiledTransaction) => decompileTransaction(compiledTransaction, lastValidBlockHeight)
888
+ (compiledTransaction) => decompileTransaction(compiledTransaction, config)
847
889
  );
848
890
  }
849
- function getTransactionCodec(lastValidBlockHeight) {
850
- return combineCodec(getTransactionEncoder(), getTransactionDecoder(lastValidBlockHeight));
891
+ function getTransactionCodec(config) {
892
+ return combineCodec(getTransactionEncoder(), getTransactionDecoder(config));
851
893
  }
852
894
  var base58Decoder;
853
895
  function getSignatureFromTransaction(transaction) {
@@ -855,9 +897,7 @@ function getSignatureFromTransaction(transaction) {
855
897
  base58Decoder = getBase58Decoder();
856
898
  const signatureBytes = transaction.signatures[transaction.feePayer];
857
899
  if (!signatureBytes) {
858
- throw new Error(
859
- "Could not determine this transaction's signature. Make sure that the transaction has been signed by its fee payer."
860
- );
900
+ throw new SolanaError(SOLANA_ERROR__TRANSACTION_SIGNATURE_NOT_COMPUTABLE);
861
901
  }
862
902
  const transactionSignature = base58Decoder.decode(signatureBytes);
863
903
  return transactionSignature;
@@ -890,17 +930,23 @@ async function signTransaction(keyPairs, transaction) {
890
930
  function assertTransactionIsFullySigned(transaction) {
891
931
  const signerAddressesFromInstructions = transaction.instructions.flatMap((i) => i.accounts?.filter((a) => isSignerRole(a.role)) ?? []).map((a) => a.address);
892
932
  const requiredSigners = /* @__PURE__ */ new Set([transaction.feePayer, ...signerAddressesFromInstructions]);
933
+ const missingSigs = [];
893
934
  requiredSigners.forEach((address) => {
894
935
  if (!transaction.signatures[address]) {
895
- throw new Error(`Transaction is missing signature for address \`${address}\``);
936
+ missingSigs.push(address);
896
937
  }
897
938
  });
939
+ if (missingSigs.length > 0) {
940
+ throw new SolanaError(SOLANA_ERROR__TRANSACTION_MISSING_SIGNATURES, {
941
+ addresses: missingSigs
942
+ });
943
+ }
898
944
  }
899
945
  function getBase64EncodedWireTransaction(transaction) {
900
946
  const wireTransactionBytes = getTransactionEncoder().encode(transaction);
901
947
  return getBase64Decoder().decode(wireTransactionBytes);
902
948
  }
903
949
 
904
- export { appendTransactionInstruction, assertIsBlockhash, assertIsDurableNonceTransaction, assertIsTransactionWithBlockhashLifetime, assertTransactionIsFullySigned, compileMessage, createTransaction, getBase64EncodedWireTransaction, getCompiledMessageCodec, getCompiledMessageDecoder, getCompiledMessageEncoder, getSignatureFromTransaction, getTransactionCodec, getTransactionDecoder, getTransactionEncoder, isAdvanceNonceAccountInstruction, partiallySignTransaction, prependTransactionInstruction, setTransactionFeePayer, setTransactionLifetimeUsingBlockhash, setTransactionLifetimeUsingDurableNonce, signTransaction };
950
+ 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 };
905
951
  //# sourceMappingURL=out.js.map
906
952
  //# sourceMappingURL=index.native.js.map