@solana/transactions 2.0.0-experimental.68e85dc → 2.0.0-experimental.699bde0

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.
@@ -1,9 +1,9 @@
1
- import { base58 } from '@metaplex-foundation/umi-serializers';
2
- import { mapEncoder } from '@solana/codecs-core';
3
- import { getStructEncoder, getArrayEncoder, getBytesEncoder } from '@solana/codecs-data-structures';
4
- import { getShortU16Encoder, getU8Encoder } from '@solana/codecs-numbers';
5
- import { getAddressFromPublicKey, getAddressComparator, getAddressEncoder } from '@solana/addresses';
6
- import { getStringEncoder, getBase58Encoder } from '@solana/codecs-strings';
1
+ import { getBase58Encoder, getBase58Decoder, getBase64Decoder, getStringEncoder, getStringDecoder } from '@solana/codecs-strings';
2
+ import { mapEncoder, mapDecoder, combineCodec } from '@solana/codecs-core';
3
+ import { getStructEncoder, getArrayEncoder, getBytesEncoder, getStructDecoder, getArrayDecoder, getBytesDecoder } from '@solana/codecs-data-structures';
4
+ import { getShortU16Encoder, getShortU16Decoder, getU8Encoder, getU8Decoder } from '@solana/codecs-numbers';
5
+ import { getAddressFromPublicKey, getAddressComparator, assertIsAddress, getAddressEncoder, getAddressDecoder } from '@solana/addresses';
6
+ import { pipe } from '@solana/functional';
7
7
  import { signBytes } from '@solana/keys';
8
8
 
9
9
  // ../build-scripts/env-shim.ts
@@ -24,7 +24,10 @@ function getUnsignedTransaction(transaction) {
24
24
  }
25
25
 
26
26
  // src/blockhash.ts
27
+ var base58Encoder;
27
28
  function assertIsBlockhash(putativeBlockhash) {
29
+ if (!base58Encoder)
30
+ base58Encoder = getBase58Encoder();
28
31
  try {
29
32
  if (
30
33
  // Lowest value (32 bytes of zeroes)
@@ -33,7 +36,7 @@ function assertIsBlockhash(putativeBlockhash) {
33
36
  ) {
34
37
  throw new Error("Expected input string to decode to a byte array of length 32.");
35
38
  }
36
- const bytes = base58.serialize(putativeBlockhash);
39
+ const bytes = base58Encoder.encode(putativeBlockhash);
37
40
  const numBytes = bytes.byteLength;
38
41
  if (numBytes !== 32) {
39
42
  throw new Error(`Expected input string to decode to a byte array of length 32. Actual length: ${numBytes}`);
@@ -119,7 +122,7 @@ function isAdvanceNonceAccountInstruction(instruction) {
119
122
  instruction.accounts?.length === 3 && // First account is nonce account address
120
123
  instruction.accounts[0].address != null && instruction.accounts[0].role === AccountRole.WRITABLE && // Second account is recent blockhashes sysvar
121
124
  instruction.accounts[1].address === RECENT_BLOCKHASHES_SYSVAR_ADDRESS && instruction.accounts[1].role === AccountRole.READONLY && // Third account is nonce authority account
122
- instruction.accounts[2].address != null && instruction.accounts[2].role === AccountRole.READONLY_SIGNER;
125
+ instruction.accounts[2].address != null && isSignerRole(instruction.accounts[2].role);
123
126
  }
124
127
  function isAdvanceNonceAccountInstructionData(data) {
125
128
  return data.byteLength === 4 && data[0] === 4 && data[1] === 0 && data[2] === 0 && data[3] === 0;
@@ -127,21 +130,38 @@ function isAdvanceNonceAccountInstructionData(data) {
127
130
  function isDurableNonceTransaction(transaction) {
128
131
  return "lifetimeConstraint" in transaction && typeof transaction.lifetimeConstraint.nonce === "string" && transaction.instructions[0] != null && isAdvanceNonceAccountInstruction(transaction.instructions[0]);
129
132
  }
133
+ function isAdvanceNonceAccountInstructionForNonce(instruction, nonceAccountAddress, nonceAuthorityAddress) {
134
+ return instruction.accounts[0].address === nonceAccountAddress && instruction.accounts[2].address === nonceAuthorityAddress;
135
+ }
130
136
  function setTransactionLifetimeUsingDurableNonce({
131
137
  nonce,
132
138
  nonceAccountAddress,
133
139
  nonceAuthorityAddress
134
140
  }, transaction) {
135
- const isAlreadyDurableNonceTransaction = isDurableNonceTransaction(transaction);
136
- if (isAlreadyDurableNonceTransaction && transaction.lifetimeConstraint.nonce === nonce && transaction.instructions[0].accounts[0].address === nonceAccountAddress && transaction.instructions[0].accounts[2].address === nonceAuthorityAddress) {
137
- return transaction;
141
+ let newInstructions;
142
+ const firstInstruction = transaction.instructions[0];
143
+ if (firstInstruction && isAdvanceNonceAccountInstruction(firstInstruction)) {
144
+ if (isAdvanceNonceAccountInstructionForNonce(firstInstruction, nonceAccountAddress, nonceAuthorityAddress)) {
145
+ if (isDurableNonceTransaction(transaction) && transaction.lifetimeConstraint.nonce === nonce) {
146
+ return transaction;
147
+ } else {
148
+ newInstructions = [firstInstruction, ...transaction.instructions.slice(1)];
149
+ }
150
+ } else {
151
+ newInstructions = [
152
+ createAdvanceNonceAccountInstruction(nonceAccountAddress, nonceAuthorityAddress),
153
+ ...transaction.instructions.slice(1)
154
+ ];
155
+ }
156
+ } else {
157
+ newInstructions = [
158
+ createAdvanceNonceAccountInstruction(nonceAccountAddress, nonceAuthorityAddress),
159
+ ...transaction.instructions
160
+ ];
138
161
  }
139
162
  const out = {
140
163
  ...getUnsignedTransaction(transaction),
141
- instructions: [
142
- createAdvanceNonceAccountInstruction(nonceAccountAddress, nonceAuthorityAddress),
143
- ...isAlreadyDurableNonceTransaction ? transaction.instructions.slice(1) : transaction.instructions
144
- ],
164
+ instructions: newInstructions,
145
165
  lifetimeConstraint: {
146
166
  nonce
147
167
  }
@@ -232,7 +252,7 @@ function getAddressMapFromInstructions(feePayer, instructions) {
232
252
  const shouldReplaceEntry = (
233
253
  // Consider using the new LOOKUP_TABLE if its address is different...
234
254
  entry.lookupTableAddress !== accountMeta.lookupTableAddress && // ...and sorts before the existing one.
235
- (addressComparator || (addressComparator = getAddressComparator()))(
255
+ (addressComparator ||= getAddressComparator())(
236
256
  accountMeta.lookupTableAddress,
237
257
  entry.lookupTableAddress
238
258
  ) < 0
@@ -338,7 +358,7 @@ function getOrderedAccountsFromAddressMap(addressMap) {
338
358
  if (leftIsWritable !== isWritableRole(rightEntry.role)) {
339
359
  return leftIsWritable ? -1 : 1;
340
360
  }
341
- addressComparator || (addressComparator = getAddressComparator());
361
+ addressComparator ||= getAddressComparator();
342
362
  if (leftEntry[TYPE] === 1 /* LOOKUP_TABLE */ && rightEntry[TYPE] === 1 /* LOOKUP_TABLE */ && leftEntry.lookupTableAddress !== rightEntry.lookupTableAddress) {
343
363
  return addressComparator(leftEntry.lookupTableAddress, rightEntry.lookupTableAddress);
344
364
  } else {
@@ -351,16 +371,15 @@ function getOrderedAccountsFromAddressMap(addressMap) {
351
371
  return orderedAccounts;
352
372
  }
353
373
  function getCompiledAddressTableLookups(orderedAccounts) {
354
- var _a;
355
374
  const index = {};
356
375
  for (const account of orderedAccounts) {
357
376
  if (!("lookupTableAddress" in account)) {
358
377
  continue;
359
378
  }
360
- const entry = index[_a = account.lookupTableAddress] || (index[_a] = {
379
+ const entry = index[account.lookupTableAddress] ||= {
361
380
  readableIndices: [],
362
381
  writableIndices: []
363
- });
382
+ };
364
383
  if (account.role === AccountRole.WRITABLE) {
365
384
  entry.writableIndices.push(account.addressIndex);
366
385
  } else {
@@ -464,6 +483,116 @@ function getCompiledTransaction(transaction) {
464
483
  signatures
465
484
  };
466
485
  }
486
+ function getAccountMetas(message) {
487
+ const { header } = message;
488
+ const numWritableSignerAccounts = header.numSignerAccounts - header.numReadonlySignerAccounts;
489
+ const numWritableNonSignerAccounts = message.staticAccounts.length - header.numSignerAccounts - header.numReadonlyNonSignerAccounts;
490
+ const accountMetas = [];
491
+ let accountIndex = 0;
492
+ for (let i = 0; i < numWritableSignerAccounts; i++) {
493
+ accountMetas.push({
494
+ address: message.staticAccounts[accountIndex],
495
+ role: AccountRole.WRITABLE_SIGNER
496
+ });
497
+ accountIndex++;
498
+ }
499
+ for (let i = 0; i < header.numReadonlySignerAccounts; i++) {
500
+ accountMetas.push({
501
+ address: message.staticAccounts[accountIndex],
502
+ role: AccountRole.READONLY_SIGNER
503
+ });
504
+ accountIndex++;
505
+ }
506
+ for (let i = 0; i < numWritableNonSignerAccounts; i++) {
507
+ accountMetas.push({
508
+ address: message.staticAccounts[accountIndex],
509
+ role: AccountRole.WRITABLE
510
+ });
511
+ accountIndex++;
512
+ }
513
+ for (let i = 0; i < header.numReadonlyNonSignerAccounts; i++) {
514
+ accountMetas.push({
515
+ address: message.staticAccounts[accountIndex],
516
+ role: AccountRole.READONLY
517
+ });
518
+ accountIndex++;
519
+ }
520
+ return accountMetas;
521
+ }
522
+ function convertInstruction(instruction, accountMetas) {
523
+ const programAddress = accountMetas[instruction.programAddressIndex]?.address;
524
+ if (!programAddress) {
525
+ throw new Error(`Could not find program address at index ${instruction.programAddressIndex}`);
526
+ }
527
+ const accounts = instruction.accountIndices?.map((accountIndex) => accountMetas[accountIndex]);
528
+ const { data } = instruction;
529
+ return {
530
+ programAddress,
531
+ ...accounts && accounts.length ? { accounts } : {},
532
+ ...data && data.length ? { data } : {}
533
+ };
534
+ }
535
+ function getLifetimeConstraint(messageLifetimeToken, firstInstruction, lastValidBlockHeight) {
536
+ if (!firstInstruction || !isAdvanceNonceAccountInstruction(firstInstruction)) {
537
+ return {
538
+ blockhash: messageLifetimeToken,
539
+ lastValidBlockHeight: lastValidBlockHeight ?? 2n ** 64n - 1n
540
+ // U64 MAX
541
+ };
542
+ } else {
543
+ const nonceAccountAddress = firstInstruction.accounts[0].address;
544
+ assertIsAddress(nonceAccountAddress);
545
+ const nonceAuthorityAddress = firstInstruction.accounts[2].address;
546
+ assertIsAddress(nonceAuthorityAddress);
547
+ return {
548
+ nonce: messageLifetimeToken,
549
+ nonceAccountAddress,
550
+ nonceAuthorityAddress
551
+ };
552
+ }
553
+ }
554
+ function convertSignatures(compiledTransaction) {
555
+ const {
556
+ compiledMessage: { staticAccounts },
557
+ signatures
558
+ } = compiledTransaction;
559
+ return signatures.reduce((acc, sig, index) => {
560
+ const allZeros = sig.every((byte) => byte === 0);
561
+ if (allZeros)
562
+ return acc;
563
+ const address = staticAccounts[index];
564
+ return { ...acc, [address]: sig };
565
+ }, {});
566
+ }
567
+ function decompileTransaction(compiledTransaction, lastValidBlockHeight) {
568
+ const { compiledMessage } = compiledTransaction;
569
+ if ("addressTableLookups" in compiledMessage && compiledMessage.addressTableLookups.length > 0) {
570
+ throw new Error("Cannot convert transaction with addressTableLookups");
571
+ }
572
+ const feePayer = compiledMessage.staticAccounts[0];
573
+ if (!feePayer)
574
+ throw new Error("No fee payer set in CompiledTransaction");
575
+ const accountMetas = getAccountMetas(compiledMessage);
576
+ const instructions = compiledMessage.instructions.map(
577
+ (compiledInstruction) => convertInstruction(compiledInstruction, accountMetas)
578
+ );
579
+ const firstInstruction = instructions[0];
580
+ const lifetimeConstraint = getLifetimeConstraint(
581
+ compiledMessage.lifetimeToken,
582
+ firstInstruction,
583
+ lastValidBlockHeight
584
+ );
585
+ const signatures = convertSignatures(compiledTransaction);
586
+ return pipe(
587
+ createTransaction({ version: compiledMessage.version }),
588
+ (tx) => setTransactionFeePayer(feePayer, tx),
589
+ (tx) => instructions.reduce((acc, instruction) => {
590
+ return appendTransactionInstruction(instruction, acc);
591
+ }, tx),
592
+ (tx) => "blockhash" in lifetimeConstraint ? setTransactionLifetimeUsingBlockhash(lifetimeConstraint, tx) : setTransactionLifetimeUsingDurableNonce(lifetimeConstraint, tx),
593
+ (tx) => compiledTransaction.signatures.length ? { ...tx, signatures } : tx
594
+ );
595
+ }
467
596
  var lookupTableAddressDescription = __DEV__ ? "The address of the address lookup table account from which instruction addresses should be looked up" : "lookupTableAddress";
468
597
  var writableIndicesDescription = __DEV__ ? "The indices of the accounts in the lookup table that should be loaded as writeable" : "writableIndices";
469
598
  var readableIndicesDescription = __DEV__ ? "The indices of the accounts in the lookup table that should be loaded as read-only" : "readableIndices";
@@ -494,6 +623,32 @@ function getAddressTableLookupEncoder() {
494
623
  }
495
624
  return memoizedAddressTableLookupEncoder;
496
625
  }
626
+ var memoizedAddressTableLookupDecoder;
627
+ function getAddressTableLookupDecoder() {
628
+ if (!memoizedAddressTableLookupDecoder) {
629
+ memoizedAddressTableLookupDecoder = getStructDecoder(
630
+ [
631
+ ["lookupTableAddress", getAddressDecoder({ description: lookupTableAddressDescription })],
632
+ [
633
+ "writableIndices",
634
+ getArrayDecoder(getU8Decoder(), {
635
+ description: writableIndicesDescription,
636
+ size: getShortU16Decoder()
637
+ })
638
+ ],
639
+ [
640
+ "readableIndices",
641
+ getArrayDecoder(getU8Decoder(), {
642
+ description: readableIndicesDescription,
643
+ size: getShortU16Decoder()
644
+ })
645
+ ]
646
+ ],
647
+ { description: addressTableLookupDescription }
648
+ );
649
+ }
650
+ return memoizedAddressTableLookupDecoder;
651
+ }
497
652
  var memoizedU8Encoder;
498
653
  function getMemoizedU8Encoder() {
499
654
  if (!memoizedU8Encoder)
@@ -507,6 +662,19 @@ function getMemoizedU8EncoderDescription(description) {
507
662
  description: description ?? encoder.description
508
663
  };
509
664
  }
665
+ var memoizedU8Decoder;
666
+ function getMemoizedU8Decoder() {
667
+ if (!memoizedU8Decoder)
668
+ memoizedU8Decoder = getU8Decoder();
669
+ return memoizedU8Decoder;
670
+ }
671
+ function getMemoizedU8DecoderDescription(description) {
672
+ const decoder = getMemoizedU8Decoder();
673
+ return {
674
+ ...decoder,
675
+ description: description ?? decoder.description
676
+ };
677
+ }
510
678
  var numSignerAccountsDescription = __DEV__ ? "The expected number of addresses in the static address list belonging to accounts that are required to sign this transaction" : void 0;
511
679
  var numReadonlySignerAccountsDescription = __DEV__ ? "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" : void 0;
512
680
  var numReadonlyNonSignerAccountsDescription = __DEV__ ? "The expected number of addresses in the static address list belonging to accounts that are neither signers, nor writable" : void 0;
@@ -523,6 +691,18 @@ function getMessageHeaderEncoder() {
523
691
  }
524
692
  );
525
693
  }
694
+ function getMessageHeaderDecoder() {
695
+ return getStructDecoder(
696
+ [
697
+ ["numSignerAccounts", getMemoizedU8DecoderDescription(numSignerAccountsDescription)],
698
+ ["numReadonlySignerAccounts", getMemoizedU8DecoderDescription(numReadonlySignerAccountsDescription)],
699
+ ["numReadonlyNonSignerAccounts", getMemoizedU8DecoderDescription(numReadonlyNonSignerAccountsDescription)]
700
+ ],
701
+ {
702
+ description: messageHeaderDescription
703
+ }
704
+ );
705
+ }
526
706
  var programAddressIndexDescription = __DEV__ ? "The index of the program being called, according to the well-ordered accounts list for this transaction" : "programAddressIndex";
527
707
  var accountIndexDescription = __DEV__ ? "The index of an account, according to the well-ordered accounts list for this transaction" : void 0;
528
708
  var accountIndicesDescription = __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" : "accountIndices";
@@ -557,12 +737,52 @@ function getInstructionEncoder() {
557
737
  }
558
738
  return memoizedGetInstructionEncoder;
559
739
  }
740
+ var memoizedGetInstructionDecoder;
741
+ function getInstructionDecoder() {
742
+ if (!memoizedGetInstructionDecoder) {
743
+ memoizedGetInstructionDecoder = mapDecoder(
744
+ getStructDecoder([
745
+ ["programAddressIndex", getU8Decoder({ description: programAddressIndexDescription })],
746
+ [
747
+ "accountIndices",
748
+ getArrayDecoder(getU8Decoder({ description: accountIndexDescription }), {
749
+ description: accountIndicesDescription,
750
+ size: getShortU16Decoder()
751
+ })
752
+ ],
753
+ ["data", getBytesDecoder({ description: dataDescription, size: getShortU16Decoder() })]
754
+ ]),
755
+ // Convert an instruction to exclude optional fields if they are empty
756
+ (instruction) => {
757
+ if (instruction.accountIndices.length && instruction.data.byteLength) {
758
+ return instruction;
759
+ }
760
+ const { accountIndices, data, ...rest } = instruction;
761
+ return {
762
+ ...rest,
763
+ ...accountIndices.length ? { accountIndices } : null,
764
+ ...data.byteLength ? { data } : null
765
+ };
766
+ }
767
+ );
768
+ }
769
+ return memoizedGetInstructionDecoder;
770
+ }
560
771
  var VERSION_FLAG_MASK = 128;
561
772
  var BASE_CONFIG = {
562
773
  description: __DEV__ ? "A single byte that encodes the version of the transaction" : "",
563
774
  fixedSize: null,
564
775
  maxSize: 1
565
776
  };
777
+ function decode(bytes, offset = 0) {
778
+ const firstByte = bytes[offset];
779
+ if ((firstByte & VERSION_FLAG_MASK) === 0) {
780
+ return ["legacy", offset];
781
+ } else {
782
+ const version = firstByte ^ VERSION_FLAG_MASK;
783
+ return [version, offset + 1];
784
+ }
785
+ }
566
786
  function encode(value) {
567
787
  if (value === "legacy") {
568
788
  return new Uint8Array();
@@ -572,6 +792,12 @@ function encode(value) {
572
792
  }
573
793
  return new Uint8Array([value | VERSION_FLAG_MASK]);
574
794
  }
795
+ function getTransactionVersionDecoder() {
796
+ return {
797
+ ...BASE_CONFIG,
798
+ decode
799
+ };
800
+ }
575
801
  function getTransactionVersionEncoder() {
576
802
  return {
577
803
  ...BASE_CONFIG,
@@ -632,12 +858,47 @@ function getPreludeStructEncoderTuple() {
632
858
  ]
633
859
  ];
634
860
  }
861
+ function getPreludeStructDecoderTuple() {
862
+ return [
863
+ ["version", getTransactionVersionDecoder()],
864
+ ["header", getMessageHeaderDecoder()],
865
+ [
866
+ "staticAccounts",
867
+ getArrayDecoder(getAddressDecoder(), {
868
+ description: staticAccountsDescription,
869
+ size: getShortU16Decoder()
870
+ })
871
+ ],
872
+ [
873
+ "lifetimeToken",
874
+ getStringDecoder({
875
+ description: lifetimeTokenDescription,
876
+ encoding: getBase58Decoder(),
877
+ size: 32
878
+ })
879
+ ],
880
+ [
881
+ "instructions",
882
+ getArrayDecoder(getInstructionDecoder(), {
883
+ description: instructionsDescription,
884
+ size: getShortU16Decoder()
885
+ })
886
+ ],
887
+ ["addressTableLookups", getAddressTableLookupArrayDecoder()]
888
+ ];
889
+ }
635
890
  function getAddressTableLookupArrayEncoder() {
636
891
  return getArrayEncoder(getAddressTableLookupEncoder(), {
637
892
  description: addressTableLookupsDescription,
638
893
  size: getShortU16Encoder()
639
894
  });
640
895
  }
896
+ function getAddressTableLookupArrayDecoder() {
897
+ return getArrayDecoder(getAddressTableLookupDecoder(), {
898
+ description: addressTableLookupsDescription,
899
+ size: getShortU16Decoder()
900
+ });
901
+ }
641
902
  var messageDescription = __DEV__ ? "The wire format of a Solana transaction message" : "message";
642
903
  function getCompiledMessageEncoder() {
643
904
  return {
@@ -653,10 +914,23 @@ function getCompiledMessageEncoder() {
653
914
  maxSize: null
654
915
  };
655
916
  }
917
+ function getCompiledMessageDecoder() {
918
+ return mapDecoder(
919
+ getStructDecoder(getPreludeStructDecoderTuple(), {
920
+ description: messageDescription
921
+ }),
922
+ ({ addressTableLookups, ...restOfMessage }) => {
923
+ if (restOfMessage.version === "legacy" || !addressTableLookups?.length) {
924
+ return restOfMessage;
925
+ }
926
+ return { ...restOfMessage, addressTableLookups };
927
+ }
928
+ );
929
+ }
656
930
 
657
931
  // src/serializers/transaction.ts
658
- var transactionDescription = __DEV__ ? "The wire format of a Solana transaction" : "transaction";
659
932
  var signaturesDescription = __DEV__ ? "A compact array of 64-byte, base-64 encoded Ed25519 signatures" : "signatures";
933
+ var transactionDescription = __DEV__ ? "The wire format of a Solana transaction" : "transaction";
660
934
  function getCompiledTransactionEncoder() {
661
935
  return getStructEncoder(
662
936
  [
@@ -674,68 +948,58 @@ function getCompiledTransactionEncoder() {
674
948
  }
675
949
  );
676
950
  }
677
- function getTransactionEncoder() {
678
- return mapEncoder(getCompiledTransactionEncoder(), getCompiledTransaction);
951
+ function getSignatureDecoder() {
952
+ return mapDecoder(getBytesDecoder({ size: 64 }), (bytes) => bytes);
679
953
  }
680
- function assertIsTransactionSignature(putativeTransactionSignature) {
681
- try {
682
- if (
683
- // Lowest value (64 bytes of zeroes)
684
- putativeTransactionSignature.length < 64 || // Highest value (64 bytes of 255)
685
- putativeTransactionSignature.length > 88
686
- ) {
687
- throw new Error("Expected input string to decode to a byte array of length 64.");
688
- }
689
- const bytes = base58.serialize(putativeTransactionSignature);
690
- const numBytes = bytes.byteLength;
691
- if (numBytes !== 64) {
692
- throw new Error(`Expected input string to decode to a byte array of length 64. Actual length: ${numBytes}`);
954
+ function getCompiledTransactionDecoder() {
955
+ return getStructDecoder(
956
+ [
957
+ [
958
+ "signatures",
959
+ getArrayDecoder(getSignatureDecoder(), {
960
+ description: signaturesDescription,
961
+ size: getShortU16Decoder()
962
+ })
963
+ ],
964
+ ["compiledMessage", getCompiledMessageDecoder()]
965
+ ],
966
+ {
967
+ description: transactionDescription
693
968
  }
694
- } catch (e) {
695
- throw new Error(`\`${putativeTransactionSignature}\` is not a transaction signature`, {
696
- cause: e
697
- });
698
- }
969
+ );
699
970
  }
700
- function isTransactionSignature(putativeTransactionSignature) {
701
- if (
702
- // Lowest value (64 bytes of zeroes)
703
- putativeTransactionSignature.length < 64 || // Highest value (64 bytes of 255)
704
- putativeTransactionSignature.length > 88
705
- ) {
706
- return false;
707
- }
708
- const bytes = base58.serialize(putativeTransactionSignature);
709
- const numBytes = bytes.byteLength;
710
- if (numBytes !== 64) {
711
- return false;
712
- }
713
- return true;
971
+ function getTransactionEncoder() {
972
+ return mapEncoder(getCompiledTransactionEncoder(), getCompiledTransaction);
973
+ }
974
+ function getTransactionDecoder(lastValidBlockHeight) {
975
+ return mapDecoder(
976
+ getCompiledTransactionDecoder(),
977
+ (compiledTransaction) => decompileTransaction(compiledTransaction, lastValidBlockHeight)
978
+ );
714
979
  }
715
- async function getCompiledMessageSignature(message, secretKey) {
716
- const wireMessageBytes = getCompiledMessageEncoder().encode(message);
717
- const signature = await signBytes(secretKey, wireMessageBytes);
718
- return signature;
980
+ function getTransactionCodec(lastValidBlockHeight) {
981
+ return combineCodec(getTransactionEncoder(), getTransactionDecoder(lastValidBlockHeight));
719
982
  }
983
+ var base58Decoder;
720
984
  function getSignatureFromTransaction(transaction) {
985
+ if (!base58Decoder)
986
+ base58Decoder = getBase58Decoder();
721
987
  const signatureBytes = transaction.signatures[transaction.feePayer];
722
988
  if (!signatureBytes) {
723
989
  throw new Error(
724
990
  "Could not determine this transaction's signature. Make sure that the transaction has been signed by its fee payer."
725
991
  );
726
992
  }
727
- const transactionSignature2 = base58.deserialize(signatureBytes)[0];
728
- return transactionSignature2;
993
+ const transactionSignature = base58Decoder.decode(signatureBytes)[0];
994
+ return transactionSignature;
729
995
  }
730
- async function signTransaction(keyPairs, transaction) {
996
+ async function partiallySignTransaction(keyPairs, transaction) {
731
997
  const compiledMessage = compileMessage(transaction);
732
998
  const nextSignatures = "signatures" in transaction ? { ...transaction.signatures } : {};
999
+ const wireMessageBytes = getCompiledMessageEncoder().encode(compiledMessage);
733
1000
  const publicKeySignaturePairs = await Promise.all(
734
1001
  keyPairs.map(
735
- (keyPair) => Promise.all([
736
- getAddressFromPublicKey(keyPair.publicKey),
737
- getCompiledMessageSignature(compiledMessage, keyPair.privateKey)
738
- ])
1002
+ (keyPair) => Promise.all([getAddressFromPublicKey(keyPair.publicKey), signBytes(keyPair.privateKey, wireMessageBytes)])
739
1003
  )
740
1004
  );
741
1005
  for (const [signerPublicKey, signature] of publicKeySignaturePairs) {
@@ -748,19 +1012,26 @@ async function signTransaction(keyPairs, transaction) {
748
1012
  Object.freeze(out);
749
1013
  return out;
750
1014
  }
751
- function transactionSignature(putativeTransactionSignature) {
752
- assertIsTransactionSignature(putativeTransactionSignature);
753
- return putativeTransactionSignature;
1015
+ async function signTransaction(keyPairs, transaction) {
1016
+ const out = await partiallySignTransaction(keyPairs, transaction);
1017
+ assertTransactionIsFullySigned(out);
1018
+ Object.freeze(out);
1019
+ return out;
1020
+ }
1021
+ function assertTransactionIsFullySigned(transaction) {
1022
+ const signerAddressesFromInstructions = transaction.instructions.flatMap((i) => i.accounts?.filter((a) => isSignerRole(a.role)) ?? []).map((a) => a.address);
1023
+ const requiredSigners = /* @__PURE__ */ new Set([transaction.feePayer, ...signerAddressesFromInstructions]);
1024
+ requiredSigners.forEach((address) => {
1025
+ if (!transaction.signatures[address]) {
1026
+ throw new Error(`Transaction is missing signature for address \`${address}\``);
1027
+ }
1028
+ });
754
1029
  }
755
-
756
- // src/wire-transaction.ts
757
1030
  function getBase64EncodedWireTransaction(transaction) {
758
1031
  const wireTransactionBytes = getTransactionEncoder().encode(transaction);
759
- {
760
- return btoa(String.fromCharCode(...wireTransactionBytes));
761
- }
1032
+ return getBase64Decoder().decode(wireTransactionBytes)[0];
762
1033
  }
763
1034
 
764
- export { appendTransactionInstruction, assertIsBlockhash, assertIsDurableNonceTransaction, assertIsTransactionSignature, createTransaction, getBase64EncodedWireTransaction, getSignatureFromTransaction, getTransactionEncoder, isAdvanceNonceAccountInstruction, isTransactionSignature, prependTransactionInstruction, setTransactionFeePayer, setTransactionLifetimeUsingBlockhash, setTransactionLifetimeUsingDurableNonce, signTransaction, transactionSignature };
1035
+ export { appendTransactionInstruction, assertIsBlockhash, assertIsDurableNonceTransaction, assertTransactionIsFullySigned, createTransaction, getBase64EncodedWireTransaction, getSignatureFromTransaction, getTransactionCodec, getTransactionDecoder, getTransactionEncoder, isAdvanceNonceAccountInstruction, partiallySignTransaction, prependTransactionInstruction, setTransactionFeePayer, setTransactionLifetimeUsingBlockhash, setTransactionLifetimeUsingDurableNonce, signTransaction };
765
1036
  //# sourceMappingURL=out.js.map
766
1037
  //# sourceMappingURL=index.native.js.map