@solana/transactions 2.0.0-experimental.fd64233 → 2.0.0-experimental.feaeef2

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.
package/README.md CHANGED
@@ -30,7 +30,7 @@ const transferTransaction = pipe(
30
30
  createTransaction({ version: 0 }),
31
31
  tx => setTransactionFeePayer(myAddress, tx),
32
32
  tx => setTransactionLifetimeUsingBlockhash(latestBlockhash, tx),
33
- tx => appendTransactionInstruction(createTransferInstruction(myAddress, toAddress, amountInLamports), tx)
33
+ tx => appendTransactionInstruction(createTransferInstruction(myAddress, toAddress, amountInLamports), tx),
34
34
  );
35
35
  ```
36
36
 
@@ -144,7 +144,7 @@ const nonce =
144
144
 
145
145
  const durableNonceTransaction = setTransactionLifetimeUsingDurableNonce(
146
146
  { nonce, nonceAccountAddress, nonceAuthorityAddress },
147
- tx
147
+ tx,
148
148
  );
149
149
  ```
150
150
 
@@ -210,14 +210,18 @@ const memoTransaction = appendTransactionInstruction(
210
210
  data: new TextEncoder().encode('Hello world!'),
211
211
  programAddress: address('MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr'),
212
212
  },
213
- tx
213
+ tx,
214
214
  );
215
215
  ```
216
216
 
217
+ If you'd like to add multiple instructions to a transaction at once, you may use the `appendTransactionInstructions` function instead which accepts an array of instructions.
218
+
217
219
  #### `prependTransactionInstruction()`
218
220
 
219
221
  Given an instruction, this method will return a new transaction with that instruction having been added to the beginning of the list of existing instructions.
220
222
 
223
+ If you'd like to prepend multiple instructions to a transaction at once, you may use the `prependTransactionInstructions` function instead which accepts an array of instructions.
224
+
221
225
  See [`appendTransactionInstruction()`](#appendtransactioninstruction) for an example of how to use this function.
222
226
 
223
227
  ## Signing transactions
@@ -1,35 +1,33 @@
1
1
  'use strict';
2
2
 
3
+ var errors = require('@solana/errors');
3
4
  var codecsStrings = require('@solana/codecs-strings');
4
5
  var addresses = require('@solana/addresses');
5
6
  var functional = require('@solana/functional');
6
7
  var codecsCore = require('@solana/codecs-core');
7
8
  var codecsDataStructures = require('@solana/codecs-data-structures');
8
9
  var codecsNumbers = require('@solana/codecs-numbers');
9
- var errors = require('@solana/errors');
10
10
  var keys = require('@solana/keys');
11
11
 
12
- // ../rpc-types/dist/index.browser.js
12
+ // src/blockhash.ts
13
13
  var base58Encoder;
14
14
  function assertIsBlockhash(putativeBlockhash) {
15
15
  if (!base58Encoder)
16
16
  base58Encoder = codecsStrings.getBase58Encoder();
17
- try {
18
- if (
19
- // Lowest value (32 bytes of zeroes)
20
- putativeBlockhash.length < 32 || // Highest value (32 bytes of 255)
21
- putativeBlockhash.length > 44
22
- ) {
23
- throw new Error("Expected input string to decode to a byte array of length 32.");
24
- }
25
- const bytes = base58Encoder.encode(putativeBlockhash);
26
- const numBytes = bytes.byteLength;
27
- if (numBytes !== 32) {
28
- throw new Error(`Expected input string to decode to a byte array of length 32. Actual length: ${numBytes}`);
29
- }
30
- } catch (e) {
31
- throw new Error(`\`${putativeBlockhash}\` is not a blockhash`, {
32
- cause: e
17
+ if (
18
+ // Lowest value (32 bytes of zeroes)
19
+ putativeBlockhash.length < 32 || // Highest value (32 bytes of 255)
20
+ putativeBlockhash.length > 44
21
+ ) {
22
+ throw new errors.SolanaError(errors.SOLANA_ERROR__BLOCKHASH_STRING_LENGTH_OUT_OF_RANGE, {
23
+ actualLength: putativeBlockhash.length
24
+ });
25
+ }
26
+ const bytes = base58Encoder.encode(putativeBlockhash);
27
+ const numBytes = bytes.byteLength;
28
+ if (numBytes !== 32) {
29
+ throw new errors.SolanaError(errors.SOLANA_ERROR__INVALID_BLOCKHASH_BYTE_LENGTH, {
30
+ actualLength: numBytes
33
31
  });
34
32
  }
35
33
  }
@@ -62,7 +60,7 @@ function isTransactionWithBlockhashLifetime(transaction) {
62
60
  }
63
61
  function assertIsTransactionWithBlockhashLifetime(transaction) {
64
62
  if (!isTransactionWithBlockhashLifetime(transaction)) {
65
- throw new Error("Transaction does not have a blockhash lifetime");
63
+ throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION__EXPECTED_BLOCKHASH_LIFETIME);
66
64
  }
67
65
  }
68
66
  function setTransactionLifetimeUsingBlockhash(blockhashLifetimeConstraint, transaction) {
@@ -88,8 +86,6 @@ function createTransaction({
88
86
  Object.freeze(out);
89
87
  return out;
90
88
  }
91
-
92
- // ../instructions/dist/index.browser.js
93
89
  var AccountRole = /* @__PURE__ */ ((AccountRole2) => {
94
90
  AccountRole2[AccountRole2["WRITABLE_SIGNER"] = /* 3 */
95
91
  3] = "WRITABLE_SIGNER";
@@ -111,13 +107,11 @@ function isWritableRole(role) {
111
107
  function mergeRoles(roleA, roleB) {
112
108
  return roleA | roleB;
113
109
  }
114
-
115
- // src/durable-nonce.ts
116
110
  var RECENT_BLOCKHASHES_SYSVAR_ADDRESS = "SysvarRecentB1ockHashes11111111111111111111";
117
111
  var SYSTEM_PROGRAM_ADDRESS = "11111111111111111111111111111111";
118
112
  function assertIsDurableNonceTransaction(transaction) {
119
113
  if (!isDurableNonceTransaction(transaction)) {
120
- throw new Error("Transaction is not a durable nonce transaction");
114
+ throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION__EXPECTED_NONCE_LIFETIME);
121
115
  }
122
116
  }
123
117
  function createAdvanceNonceAccountInstruction(nonceAccountAddress, nonceAuthorityAddress) {
@@ -203,17 +197,23 @@ function setTransactionFeePayer(feePayer, transaction) {
203
197
 
204
198
  // src/instructions.ts
205
199
  function appendTransactionInstruction(instruction, transaction) {
200
+ return appendTransactionInstructions([instruction], transaction);
201
+ }
202
+ function appendTransactionInstructions(instructions, transaction) {
206
203
  const out = {
207
204
  ...getUnsignedTransaction(transaction),
208
- instructions: [...transaction.instructions, instruction]
205
+ instructions: [...transaction.instructions, ...instructions]
209
206
  };
210
207
  Object.freeze(out);
211
208
  return out;
212
209
  }
213
210
  function prependTransactionInstruction(instruction, transaction) {
211
+ return prependTransactionInstructions([instruction], transaction);
212
+ }
213
+ function prependTransactionInstructions(instructions, transaction) {
214
214
  const out = {
215
215
  ...getUnsignedTransaction(transaction),
216
- instructions: [instruction, ...transaction.instructions]
216
+ instructions: [...instructions, ...transaction.instructions]
217
217
  };
218
218
  Object.freeze(out);
219
219
  return out;
@@ -260,8 +260,9 @@ function getAddressLookupMetas(compiledAddressTableLookups, addressesByLookupTab
260
260
  const compiledAddressTableLookupAddresses = compiledAddressTableLookups.map((l) => l.lookupTableAddress);
261
261
  const missing = compiledAddressTableLookupAddresses.filter((a) => addressesByLookupTableAddress[a] === void 0);
262
262
  if (missing.length > 0) {
263
- const missingAddresses = missing.join(", ");
264
- throw new Error(`Addresses not provided for lookup tables: [${missingAddresses}]`);
263
+ throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION__FAILED_TO_DECOMPILE_ADDRESS_LOOKUP_TABLE_CONTENTS_MISSING, {
264
+ lookupTableAddresses: missing
265
+ });
265
266
  }
266
267
  const readOnlyMetas = [];
267
268
  const writableMetas = [];
@@ -269,8 +270,13 @@ function getAddressLookupMetas(compiledAddressTableLookups, addressesByLookupTab
269
270
  const addresses = addressesByLookupTableAddress[lookup.lookupTableAddress];
270
271
  const highestIndex = Math.max(...lookup.readableIndices, ...lookup.writableIndices);
271
272
  if (highestIndex >= addresses.length) {
272
- throw new Error(
273
- `Cannot look up index ${highestIndex} in lookup table [${lookup.lookupTableAddress}]. The lookup table may have been extended since the addresses provided were retrieved.`
273
+ throw new errors.SolanaError(
274
+ errors.SOLANA_ERROR__TRANSACTION__FAILED_TO_DECOMPILE_ADDRESS_LOOKUP_TABLE_INDEX_OUT_OF_RANGE,
275
+ {
276
+ highestKnownIndex: addresses.length - 1,
277
+ highestRequestedIndex: highestIndex,
278
+ lookupTableAddress: lookup.lookupTableAddress
279
+ }
274
280
  );
275
281
  }
276
282
  const readOnlyForLookup = lookup.readableIndices.map((r) => ({
@@ -293,7 +299,9 @@ function getAddressLookupMetas(compiledAddressTableLookups, addressesByLookupTab
293
299
  function convertInstruction(instruction, accountMetas) {
294
300
  const programAddress = accountMetas[instruction.programAddressIndex]?.address;
295
301
  if (!programAddress) {
296
- throw new Error(`Could not find program address at index ${instruction.programAddressIndex}`);
302
+ throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION__FAILED_TO_DECOMPILE_INSTRUCTION_PROGRAM_ADDRESS_NOT_FOUND, {
303
+ index: instruction.programAddressIndex
304
+ });
297
305
  }
298
306
  const accounts = instruction.accountIndices?.map((accountIndex) => accountMetas[accountIndex]);
299
307
  const { data } = instruction;
@@ -338,8 +346,9 @@ function convertSignatures(compiledTransaction) {
338
346
  function decompileTransaction(compiledTransaction, config) {
339
347
  const { compiledMessage } = compiledTransaction;
340
348
  const feePayer = compiledMessage.staticAccounts[0];
341
- if (!feePayer)
342
- throw new Error("No fee payer set in CompiledTransaction");
349
+ if (!feePayer) {
350
+ throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION__FAILED_TO_DECOMPILE_FEE_PAYER_MISSING);
351
+ }
343
352
  const accountMetas = getAccountMetas(compiledMessage);
344
353
  const accountLookupMetas = "addressTableLookups" in compiledMessage && compiledMessage.addressTableLookups !== void 0 && compiledMessage.addressTableLookups.length > 0 ? getAddressLookupMetas(compiledMessage.addressTableLookups, config?.addressesByLookupTableAddress ?? {}) : [];
345
354
  const transactionMetas = [...accountMetas, ...accountLookupMetas];
@@ -379,13 +388,13 @@ function getAddressMapFromInstructions(feePayer, instructions) {
379
388
  if (isWritableRole(entry.role)) {
380
389
  switch (entry[TYPE]) {
381
390
  case 0 /* FEE_PAYER */:
382
- throw new Error(
383
- `This transaction includes an address (\`${instruction.programAddress}\`) which is both invoked and set as the fee payer. Program addresses may not pay fees.`
384
- );
391
+ throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION__INVOKED_PROGRAMS_CANNOT_PAY_FEES, {
392
+ programAddress: instruction.programAddress
393
+ });
385
394
  default:
386
- throw new Error(
387
- `This transaction includes an address (\`${instruction.programAddress}\`) which is both invoked and marked writable. Program addresses may not be writable.`
388
- );
395
+ throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION__INVOKED_PROGRAMS_MUST_NOT_BE_WRITABLE, {
396
+ programAddress: instruction.programAddress
397
+ });
389
398
  }
390
399
  }
391
400
  if (entry[TYPE] === 2 /* STATIC */) {
@@ -450,8 +459,11 @@ function getAddressMapFromInstructions(feePayer, instructions) {
450
459
  addressesOfInvokedPrograms.has(account.address)
451
460
  ) {
452
461
  if (isWritableRole(accountMeta.role)) {
453
- throw new Error(
454
- `This transaction includes an address (\`${account.address}\`) which is both invoked and marked writable. Program addresses may not be writable.`
462
+ throw new errors.SolanaError(
463
+ errors.SOLANA_ERROR__TRANSACTION__INVOKED_PROGRAMS_MUST_NOT_BE_WRITABLE,
464
+ {
465
+ programAddress: account.address
466
+ }
455
467
  );
456
468
  }
457
469
  if (entry.role !== nextRole) {
@@ -741,7 +753,9 @@ function getTransactionVersionEncoder() {
741
753
  return offset;
742
754
  }
743
755
  if (value < 0 || value > 127) {
744
- throw new Error(`Transaction version must be in the range [0, 127]. \`${value}\` given.`);
756
+ throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION__VERSION_NUMBER_OUT_OF_RANGE, {
757
+ actualVersion: value
758
+ });
745
759
  }
746
760
  bytes.set([value | VERSION_FLAG_MASK], offset);
747
761
  return offset + 1;
@@ -828,12 +842,15 @@ function getCompiledMessageEncoder() {
828
842
  });
829
843
  }
830
844
  function getCompiledMessageDecoder() {
831
- return codecsCore.mapDecoder(codecsDataStructures.getStructDecoder(getPreludeStructDecoderTuple()), ({ addressTableLookups, ...restOfMessage }) => {
832
- if (restOfMessage.version === "legacy" || !addressTableLookups?.length) {
833
- return restOfMessage;
845
+ return codecsCore.mapDecoder(
846
+ codecsDataStructures.getStructDecoder(getPreludeStructDecoderTuple()),
847
+ ({ addressTableLookups, ...restOfMessage }) => {
848
+ if (restOfMessage.version === "legacy" || !addressTableLookups?.length) {
849
+ return restOfMessage;
850
+ }
851
+ return { ...restOfMessage, addressTableLookups };
834
852
  }
835
- return { ...restOfMessage, addressTableLookups };
836
- });
853
+ );
837
854
  }
838
855
  function getCompiledMessageCodec() {
839
856
  return codecsCore.combineCodec(getCompiledMessageEncoder(), getCompiledMessageDecoder());
@@ -893,7 +910,7 @@ function getSignatureFromTransaction(transaction) {
893
910
  base58Decoder = codecsStrings.getBase58Decoder();
894
911
  const signatureBytes = transaction.signatures[transaction.feePayer];
895
912
  if (!signatureBytes) {
896
- throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION_SIGNATURE_NOT_COMPUTABLE);
913
+ throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION__FEE_PAYER_SIGNATURE_MISSING);
897
914
  }
898
915
  const transactionSignature = base58Decoder.decode(signatureBytes);
899
916
  return transactionSignature;
@@ -933,7 +950,7 @@ function assertTransactionIsFullySigned(transaction) {
933
950
  }
934
951
  });
935
952
  if (missingSigs.length > 0) {
936
- throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION_MISSING_SIGNATURES, {
953
+ throw new errors.SolanaError(errors.SOLANA_ERROR__TRANSACTION__SIGNATURES_MISSING, {
937
954
  addresses: missingSigs
938
955
  });
939
956
  }
@@ -944,6 +961,7 @@ function getBase64EncodedWireTransaction(transaction) {
944
961
  }
945
962
 
946
963
  exports.appendTransactionInstruction = appendTransactionInstruction;
964
+ exports.appendTransactionInstructions = appendTransactionInstructions;
947
965
  exports.assertIsDurableNonceTransaction = assertIsDurableNonceTransaction;
948
966
  exports.assertIsTransactionWithBlockhashLifetime = assertIsTransactionWithBlockhashLifetime;
949
967
  exports.assertTransactionIsFullySigned = assertTransactionIsFullySigned;
@@ -959,9 +977,11 @@ exports.getSignatureFromTransaction = getSignatureFromTransaction;
959
977
  exports.getTransactionCodec = getTransactionCodec;
960
978
  exports.getTransactionDecoder = getTransactionDecoder;
961
979
  exports.getTransactionEncoder = getTransactionEncoder;
980
+ exports.getUnsignedTransaction = getUnsignedTransaction;
962
981
  exports.isAdvanceNonceAccountInstruction = isAdvanceNonceAccountInstruction;
963
982
  exports.partiallySignTransaction = partiallySignTransaction;
964
983
  exports.prependTransactionInstruction = prependTransactionInstruction;
984
+ exports.prependTransactionInstructions = prependTransactionInstructions;
965
985
  exports.setTransactionFeePayer = setTransactionFeePayer;
966
986
  exports.setTransactionLifetimeUsingBlockhash = setTransactionLifetimeUsingBlockhash;
967
987
  exports.setTransactionLifetimeUsingDurableNonce = setTransactionLifetimeUsingDurableNonce;