UNPKG

@solana/transactions

Version:

Helpers for creating and serializing transactions

1 lines 50 kB
{"version":3,"sources":["../src/codecs/signatures-encoder.ts","../src/codecs/transaction-codec.ts","../src/lifetime.ts","../src/compile-transaction.ts","../src/signatures.ts","../src/wire-transaction.ts","../src/transaction-size.ts","../src/sendable-transaction.ts","../src/transaction-message-size.ts"],"names":["getBytesEncoder","SolanaError","SOLANA_ERROR__TRANSACTION__EXCEEDS_SIZE_LIMIT"],"mappings":"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","file":"index.node.mjs","sourcesContent":["import { fixEncoderSize, transformEncoder, VariableSizeEncoder } from '@solana/codecs-core';\nimport { getArrayEncoder, getBytesEncoder } from '@solana/codecs-data-structures';\nimport { getShortU16Encoder } from '@solana/codecs-numbers';\nimport { SOLANA_ERROR__TRANSACTION__CANNOT_ENCODE_WITH_EMPTY_SIGNATURES, SolanaError } from '@solana/errors';\nimport { SignatureBytes } from '@solana/keys';\n\nimport { SignaturesMap } from '../transaction';\n\nfunction getSignaturesToEncode(signaturesMap: SignaturesMap): SignatureBytes[] {\n const signatures = Object.values(signaturesMap);\n if (signatures.length === 0) {\n throw new SolanaError(SOLANA_ERROR__TRANSACTION__CANNOT_ENCODE_WITH_EMPTY_SIGNATURES);\n }\n\n return signatures.map(signature => {\n if (!signature) {\n return new Uint8Array(64).fill(0) as SignatureBytes;\n }\n return signature;\n });\n}\n\nexport function getSignaturesEncoder(): VariableSizeEncoder<SignaturesMap> {\n return transformEncoder(\n getArrayEncoder(fixEncoderSize(getBytesEncoder(), 64), { size: getShortU16Encoder() }),\n getSignaturesToEncode,\n );\n}\n","import { getAddressDecoder } from '@solana/addresses';\nimport {\n combineCodec,\n fixDecoderSize,\n padRightDecoder,\n ReadonlyUint8Array,\n transformDecoder,\n VariableSizeCodec,\n VariableSizeDecoder,\n VariableSizeEncoder,\n} from '@solana/codecs-core';\nimport {\n getArrayDecoder,\n getBytesDecoder,\n getBytesEncoder,\n getStructDecoder,\n getStructEncoder,\n getTupleDecoder,\n} from '@solana/codecs-data-structures';\nimport { getShortU16Decoder, getU8Decoder } from '@solana/codecs-numbers';\nimport { SOLANA_ERROR__TRANSACTION__MESSAGE_SIGNATURES_MISMATCH, SolanaError } from '@solana/errors';\nimport { SignatureBytes } from '@solana/keys';\nimport { getTransactionVersionDecoder } from '@solana/transaction-messages';\n\nimport { SignaturesMap, Transaction, TransactionMessageBytes } from '../transaction';\nimport { getSignaturesEncoder } from './signatures-encoder';\n\n/**\n * Returns an encoder that you can use to encode a {@link Transaction} to a byte array in a wire\n * format appropriate for sending to the Solana network for execution.\n */\nexport function getTransactionEncoder(): VariableSizeEncoder<Transaction> {\n return getStructEncoder([\n ['signatures', getSignaturesEncoder()],\n ['messageBytes', getBytesEncoder()],\n ]);\n}\n\n/**\n * Returns a decoder that you can use to convert a byte array in the Solana transaction wire format\n * to a {@link Transaction} object.\n *\n * @example\n * ```ts\n * import { getTransactionDecoder } from '@solana/transactions';\n *\n * const transactionDecoder = getTransactionDecoder();\n * const transaction = transactionDecoder.decode(wireTransactionBytes);\n * for (const [address, signature] in Object.entries(transaction.signatures)) {\n * console.log(`Signature by ${address}`, signature);\n * }\n * ```\n */\n\nexport function getTransactionDecoder(): VariableSizeDecoder<Transaction> {\n return transformDecoder(\n getStructDecoder([\n ['signatures', getArrayDecoder(fixDecoderSize(getBytesDecoder(), 64), { size: getShortU16Decoder() })],\n ['messageBytes', getBytesDecoder()],\n ]),\n decodePartiallyDecodedTransaction,\n );\n}\n\n/**\n * Returns a codec that you can use to encode from or decode to a {@link Transaction}\n *\n * @see {@link getTransactionDecoder}\n * @see {@link getTransactionEncoder}\n */\nexport function getTransactionCodec(): VariableSizeCodec<Transaction> {\n return combineCodec(getTransactionEncoder(), getTransactionDecoder());\n}\n\ntype PartiallyDecodedTransaction = {\n messageBytes: ReadonlyUint8Array;\n signatures: ReadonlyUint8Array[];\n};\n\nfunction decodePartiallyDecodedTransaction(transaction: PartiallyDecodedTransaction): Transaction {\n const { messageBytes, signatures } = transaction;\n\n /*\n Relevant message structure is at the start:\n - transaction version (0 bytes for legacy transactions, 1 byte for versioned transactions)\n - `numRequiredSignatures` (1 byte, we verify this matches the length of signatures)\n - `numReadOnlySignedAccounts` (1 byte, not used here)\n - `numReadOnlyUnsignedAccounts` (1 byte, not used here)\n - static addresses, with signers first. This is an array of addresses, prefixed with a short-u16 length\n */\n\n const signerAddressesDecoder = getTupleDecoder([\n // read transaction version\n getTransactionVersionDecoder(),\n // read first byte of header, `numSignerAccounts`\n // padRight to skip the next 2 bytes, `numReadOnlySignedAccounts` and `numReadOnlyUnsignedAccounts` which we don't need\n padRightDecoder(getU8Decoder(), 2),\n // read static addresses\n getArrayDecoder(getAddressDecoder(), { size: getShortU16Decoder() }),\n ]);\n const [_txVersion, numRequiredSignatures, staticAddresses] = signerAddressesDecoder.decode(messageBytes);\n\n const signerAddresses = staticAddresses.slice(0, numRequiredSignatures);\n\n // signer addresses and signatures must be the same length\n // we encode an all-zero signature when the signature is missing\n if (signerAddresses.length !== signatures.length) {\n throw new SolanaError(SOLANA_ERROR__TRANSACTION__MESSAGE_SIGNATURES_MISMATCH, {\n numRequiredSignatures,\n signaturesLength: signatures.length,\n signerAddresses,\n });\n }\n\n // combine the signer addresses + signatures into the signatures map\n const signaturesMap: SignaturesMap = {};\n signerAddresses.forEach((address, index) => {\n const signatureForAddress = signatures[index];\n if (signatureForAddress.every(b => b === 0)) {\n signaturesMap[address] = null;\n } else {\n signaturesMap[address] = signatureForAddress as SignatureBytes;\n }\n });\n\n return {\n messageBytes: messageBytes as TransactionMessageBytes,\n signatures: Object.freeze(signaturesMap),\n };\n}\n","import { type Address, isAddress } from '@solana/addresses';\nimport { ReadonlyUint8Array } from '@solana/codecs-core';\nimport {\n SOLANA_ERROR__TRANSACTION__EXPECTED_BLOCKHASH_LIFETIME,\n SOLANA_ERROR__TRANSACTION__EXPECTED_NONCE_LIFETIME,\n SOLANA_ERROR__TRANSACTION__NONCE_ACCOUNT_CANNOT_BE_IN_LOOKUP_TABLE,\n SolanaError,\n} from '@solana/errors';\nimport { type Blockhash, isBlockhash, type Slot } from '@solana/rpc-types';\nimport type {\n CompiledTransactionMessage,\n CompiledTransactionMessageWithLifetime,\n Nonce,\n TransactionMessage,\n TransactionMessageWithBlockhashLifetime,\n TransactionMessageWithDurableNonceLifetime,\n} from '@solana/transaction-messages';\n\nimport type { Transaction } from './transaction';\n\n/**\n * A constraint which, when applied to a transaction, makes that transaction eligible to land on the\n * network. The transaction will continue to be eligible to land until the network considers the\n * `blockhash` to be expired.\n *\n * This can happen when the network proceeds past the `lastValidBlockHeight` for which the blockhash\n * is considered valid, or when the network switches to a fork where that blockhash is not present.\n */\nexport type TransactionBlockhashLifetime = {\n /**\n * A recent blockhash observed by the transaction proposer.\n *\n * The transaction will be considered eligible to land until the network determines this\n * blockhash to be too old, or has switched to a fork where it is not present.\n */\n blockhash: Blockhash;\n /**\n * This is the block height beyond which the network will consider the blockhash to be too old\n * to make a transaction eligible to land.\n */\n lastValidBlockHeight: Slot;\n};\n\n/**\n * A constraint which, when applied to a transaction, makes that transaction eligible to land on the\n * network.\n *\n * The transaction will continue to be eligible to land until the network considers the `nonce` to\n * have advanced. This can happen when the nonce account in which this nonce is found is destroyed,\n * or the nonce value within changes.\n */\nexport type TransactionDurableNonceLifetime = {\n /**\n * A value contained in the account with address `nonceAccountAddress` at the time the\n * transaction was prepared.\n *\n * The transaction will be considered eligible to land until the nonce account ceases to exist\n * or contain this value.\n */\n nonce: Nonce;\n /** The account that contains the `nonce` value */\n nonceAccountAddress: Address;\n};\n\n/**\n * A transaction whose ability to land on the network is determined by some evanescent criteria.\n *\n * This describes a window of time after which a transaction is constructed and before which it will\n * no longer be accepted by the network.\n *\n * No transaction can land on Solana without having a `lifetimeConstraint` set.\n */\nexport type TransactionWithLifetime = {\n readonly lifetimeConstraint: TransactionBlockhashLifetime | TransactionDurableNonceLifetime;\n};\n\n/**\n * A transaction whose lifetime is determined by the age of a blockhash observed on the network.\n *\n * The transaction will continue to be eligible to land until the network considers the `blockhash`\n * to be expired.\n */\nexport type TransactionWithBlockhashLifetime = {\n readonly lifetimeConstraint: TransactionBlockhashLifetime;\n};\n\n/**\n * A transaction whose lifetime is determined by a nonce.\n *\n * The transaction will continue to be eligible to land until the network considers the `nonce` to\n * have advanced. This can happen when the nonce account in which this nonce is found is destroyed,\n * or the nonce value within changes.\n */\nexport type TransactionWithDurableNonceLifetime = {\n readonly lifetimeConstraint: TransactionDurableNonceLifetime;\n};\n\n/**\n * Helper type that sets the lifetime constraint of a transaction to be the same as the\n * lifetime constraint of the provided transaction message.\n *\n * If the transaction message has no explicit lifetime constraint, neither will the transaction.\n */\nexport type SetTransactionLifetimeFromTransactionMessage<\n TTransaction extends Transaction,\n TTransactionMessage extends TransactionMessage,\n> = TTransactionMessage extends { lifetimeConstraint: unknown }\n ? TTransactionMessage['lifetimeConstraint'] extends TransactionMessageWithBlockhashLifetime['lifetimeConstraint']\n ? TransactionWithBlockhashLifetime & TTransaction\n : TTransactionMessage['lifetimeConstraint'] extends TransactionMessageWithDurableNonceLifetime['lifetimeConstraint']\n ? TransactionWithDurableNonceLifetime & TTransaction\n : TransactionWithLifetime & TTransaction\n : TTransaction;\n\nconst SYSTEM_PROGRAM_ADDRESS = '11111111111111111111111111111111' as Address;\n\nfunction compiledInstructionIsAdvanceNonceInstruction(\n instruction: CompiledTransactionMessage['instructions'][number],\n staticAddresses: Address[],\n): instruction is typeof instruction & { accountIndices: [number, number, number] } {\n return (\n staticAddresses[instruction.programAddressIndex] === SYSTEM_PROGRAM_ADDRESS &&\n // Test for `AdvanceNonceAccount` instruction data\n instruction.data != null &&\n isAdvanceNonceAccountInstructionData(instruction.data) &&\n // Test for exactly 3 accounts\n instruction.accountIndices?.length === 3\n );\n}\n\nfunction isAdvanceNonceAccountInstructionData(data: ReadonlyUint8Array): boolean {\n // AdvanceNonceAccount is the fifth instruction in the System Program (index 4)\n return data.byteLength === 4 && data[0] === 4 && data[1] === 0 && data[2] === 0 && data[3] === 0;\n}\n\n/**\n * Get the lifetime constraint for a transaction from a compiled transaction message that includes a lifetime token.\n * @param compiledTransactionMessage A compiled transaction message that includes a lifetime token\n * @returns A lifetime constraint for the transaction\n * Note that this is less precise than checking a decompiled instruction, as we can't inspect\n * the address or role of input accounts (which may be in lookup tables). However, this is\n * sufficient for all valid advance durable nonce instructions.\n * Note that the program address must not be in a lookup table, see [this answer on StackExchange](https://solana.stackexchange.com/a/16224/289)\n * @see {@link isAdvanceNonceAccountInstruction}\n * Note that this function is async to allow for future implementations that may fetch `lastValidBlockHeight` using an RPC\n */\n// eslint-disable-next-line @typescript-eslint/require-await\nexport async function getTransactionLifetimeConstraintFromCompiledTransactionMessage(\n compiledTransactionMessage: CompiledTransactionMessage & CompiledTransactionMessageWithLifetime,\n): Promise<TransactionBlockhashLifetime | TransactionDurableNonceLifetime> {\n const firstInstruction = compiledTransactionMessage.instructions[0];\n const { staticAccounts } = compiledTransactionMessage;\n\n // We need to check if the first instruction is an AdvanceNonceAccount instruction\n if (firstInstruction && compiledInstructionIsAdvanceNonceInstruction(firstInstruction, staticAccounts)) {\n const nonceAccountAddress = staticAccounts[firstInstruction.accountIndices[0]];\n if (!nonceAccountAddress) {\n throw new SolanaError(SOLANA_ERROR__TRANSACTION__NONCE_ACCOUNT_CANNOT_BE_IN_LOOKUP_TABLE, {\n nonce: compiledTransactionMessage.lifetimeToken,\n });\n }\n return {\n nonce: compiledTransactionMessage.lifetimeToken as Nonce,\n nonceAccountAddress,\n };\n } else {\n return {\n blockhash: compiledTransactionMessage.lifetimeToken as Blockhash,\n // This is not known from the compiled message, so we set it to the maximum possible value\n lastValidBlockHeight: 0xffffffffffffffffn,\n };\n }\n}\n\n/**\n * A type guard that returns `true` if the transaction conforms to the\n * {@link TransactionWithBlockhashLifetime} type, and refines its type for use in your\n * program.\n *\n * @example\n * ```ts\n * import { isTransactionWithBlockhashLifetime } from '@solana/transactions';\n *\n * if (isTransactionWithBlockhashLifetime(transaction)) {\n * // At this point, `transaction` has been refined to a `TransactionWithBlockhashLifetime`.\n * const { blockhash } = transaction.lifetimeConstraint;\n * const { value: blockhashIsValid } = await rpc.isBlockhashValid(blockhash).send();\n * setBlockhashIsValid(blockhashIsValid);\n * } else {\n * setError(\n * `${getSignatureFromTransaction(transaction)} does not have a blockhash-based lifetime`,\n * );\n * }\n * ```\n */\nexport function isTransactionWithBlockhashLifetime(\n transaction: Transaction | (Transaction & TransactionWithLifetime),\n): transaction is Transaction & TransactionWithBlockhashLifetime {\n return (\n 'lifetimeConstraint' in transaction &&\n 'blockhash' in transaction.lifetimeConstraint &&\n typeof transaction.lifetimeConstraint.blockhash === 'string' &&\n typeof transaction.lifetimeConstraint.lastValidBlockHeight === 'bigint' &&\n isBlockhash(transaction.lifetimeConstraint.blockhash)\n );\n}\n\n/**\n * From time to time you might acquire a transaction, that you expect to have a\n * blockhash-based lifetime, from for example a wallet. Use this function to\n * assert that such a transaction actually has a blockhash-based lifetime.\n *\n * @example\n * ```ts\n * import { assertIsTransactionWithBlockhashLifetime } from '@solana/transactions';\n *\n * try {\n * // If this type assertion function doesn't throw, then\n * // Typescript will upcast `transaction` to `TransactionWithBlockhashLifetime`.\n * assertIsTransactionWithBlockhashLifetime(transaction);\n * // At this point, `transaction` is a `TransactionWithBlockhashLifetime` that can be used\n * // with the RPC.\n * const { blockhash } = transaction.lifetimeConstraint;\n * const { value: blockhashIsValid } = await rpc.isBlockhashValid(blockhash).send();\n * } catch (e) {\n * // `transaction` turned out not to have a blockhash-based lifetime\n * }\n * ```\n */\nexport function assertIsTransactionWithBlockhashLifetime(\n transaction: Transaction | (Transaction & TransactionWithLifetime),\n): asserts transaction is Transaction & TransactionWithBlockhashLifetime {\n if (!isTransactionWithBlockhashLifetime(transaction)) {\n throw new SolanaError(SOLANA_ERROR__TRANSACTION__EXPECTED_BLOCKHASH_LIFETIME);\n }\n}\n\n/**\n * A type guard that returns `true` if the transaction conforms to the\n * {@link TransactionWithDurableNonceLifetime} type, and refines its type for use in your\n * program.\n *\n * @example\n * ```ts\n * import { isTransactionWithDurableNonceLifetime } from '@solana/transactions';\n * import { fetchNonce } from \"@solana-program/system\";\n *\n * if (isTransactionWithDurableNonceLifetime(transaction)) {\n * // At this point, `transaction` has been refined to a\n * // `TransactionWithDurableNonceLifetime`.\n * const { nonce, nonceAccountAddress } = transaction.lifetimeConstraint;\n * const { data: { blockhash: actualNonce } } = await fetchNonce(nonceAccountAddress);\n * setNonceIsValid(nonce === actualNonce);\n * } else {\n * setError(\n * `${getSignatureFromTransaction(transaction)} does not have a nonce-based lifetime`,\n * );\n * }\n * ```\n */\nexport function isTransactionWithDurableNonceLifetime(\n transaction: Transaction | (Transaction & TransactionWithLifetime),\n): transaction is Transaction & TransactionWithDurableNonceLifetime {\n return (\n 'lifetimeConstraint' in transaction &&\n 'nonce' in transaction.lifetimeConstraint &&\n typeof transaction.lifetimeConstraint.nonce === 'string' &&\n typeof transaction.lifetimeConstraint.nonceAccountAddress === 'string' &&\n isAddress(transaction.lifetimeConstraint.nonceAccountAddress)\n );\n}\n\n/**\n * From time to time you might acquire a transaction, that you expect to have a\n * nonce-based lifetime, from for example a wallet. Use this function to assert\n * that such a transaction actually has a nonce-based lifetime.\n *\n * @example\n * ```ts\n * import { assertIsTransactionWithDurableNonceLifetime } from '@solana/transactions';\n *\n * try {\n * // If this type assertion function doesn't throw, then\n * // Typescript will upcast `transaction` to `TransactionWithDurableNonceLifetime`.\n * assertIsTransactionWithDurableNonceLifetime(transaction);\n * // At this point, `transaction` is a `TransactionWithDurableNonceLifetime` that can be used\n * // with the RPC.\n * const { nonce, nonceAccountAddress } = transaction.lifetimeConstraint;\n * const { data: { blockhash: actualNonce } } = await fetchNonce(nonceAccountAddress);\n * } catch (e) {\n * // `transaction` turned out not to have a nonce-based lifetime\n * }\n * ```\n */\nexport function assertIsTransactionWithDurableNonceLifetime(\n transaction: Transaction | (Transaction & TransactionWithLifetime),\n): asserts transaction is Transaction & TransactionWithDurableNonceLifetime {\n if (!isTransactionWithDurableNonceLifetime(transaction)) {\n throw new SolanaError(SOLANA_ERROR__TRANSACTION__EXPECTED_NONCE_LIFETIME);\n }\n}\n","import {\n compileTransactionMessage,\n getCompiledTransactionMessageEncoder,\n isTransactionMessageWithBlockhashLifetime,\n isTransactionMessageWithDurableNonceLifetime,\n TransactionMessage,\n TransactionMessageWithFeePayer,\n} from '@solana/transaction-messages';\n\nimport type { TransactionWithLifetime } from './lifetime';\nimport type { SignaturesMap, TransactionFromTransactionMessage, TransactionMessageBytes } from './transaction';\n\n/**\n * Returns a {@link Transaction} object for a given {@link TransactionMessage}.\n *\n * This includes the compiled bytes of the transaction message, and a map of signatures. This map\n * will have a key for each address that is required to sign the transaction. The transaction will\n * not yet have signatures for any of these addresses.\n *\n * Whether a transaction message is ready to be compiled or not is enforced for you at the type\n * level. In order to be signable, a transaction message must:\n *\n * - have a version and a list of zero or more instructions (ie. conform to\n * {@link TransactionMessage})\n * - have a fee payer set (ie. conform to {@link TransactionMessageWithFeePayer})\n * - have a lifetime specified (ie. conform to {@link TransactionMessageWithBlockhashLifetime} or\n * {@link TransactionMessageWithDurableNonceLifetime})\n */\nexport function compileTransaction<TTransactionMessage extends TransactionMessage & TransactionMessageWithFeePayer>(\n transactionMessage: TTransactionMessage,\n): Readonly<TransactionFromTransactionMessage<TTransactionMessage>> {\n type ReturnType = Readonly<TransactionFromTransactionMessage<TTransactionMessage>>;\n\n const compiledMessage = compileTransactionMessage(transactionMessage);\n const messageBytes = getCompiledTransactionMessageEncoder().encode(compiledMessage) as TransactionMessageBytes;\n\n const transactionSigners = compiledMessage.staticAccounts.slice(0, compiledMessage.header.numSignerAccounts);\n const signatures: SignaturesMap = {};\n for (const signerAddress of transactionSigners) {\n signatures[signerAddress] = null;\n }\n\n let lifetimeConstraint: TransactionWithLifetime['lifetimeConstraint'] | undefined;\n if (isTransactionMessageWithBlockhashLifetime(transactionMessage)) {\n lifetimeConstraint = {\n blockhash: transactionMessage.lifetimeConstraint.blockhash,\n lastValidBlockHeight: transactionMessage.lifetimeConstraint.lastValidBlockHeight,\n };\n } else if (isTransactionMessageWithDurableNonceLifetime(transactionMessage)) {\n lifetimeConstraint = {\n nonce: transactionMessage.lifetimeConstraint.nonce,\n nonceAccountAddress: transactionMessage.instructions[0].accounts[0].address,\n };\n }\n\n return Object.freeze({\n ...(lifetimeConstraint ? { lifetimeConstraint } : undefined),\n messageBytes: messageBytes,\n signatures: Object.freeze(signatures),\n }) as ReturnType;\n}\n","import { Address, getAddressFromPublicKey } from '@solana/addresses';\nimport { bytesEqual, Decoder } from '@solana/codecs-core';\nimport { getBase58Decoder } from '@solana/codecs-strings';\nimport {\n SOLANA_ERROR__TRANSACTION__ADDRESSES_CANNOT_SIGN_TRANSACTION,\n SOLANA_ERROR__TRANSACTION__FEE_PAYER_SIGNATURE_MISSING,\n SOLANA_ERROR__TRANSACTION__SIGNATURES_MISSING,\n SolanaError,\n} from '@solana/errors';\nimport { Signature, SignatureBytes, signBytes } from '@solana/keys';\nimport { NominalType } from '@solana/nominal-types';\n\nimport { Transaction } from './transaction';\n\n/**\n * Represents a transaction that is signed by all of its required signers. Being fully signed is a\n * prerequisite of functions designed to land transactions on the network.\n */\nexport type FullySignedTransaction = NominalType<'transactionSignedness', 'fullySigned'>;\n\nlet base58Decoder: Decoder<string> | undefined;\n\n/**\n * Given a transaction signed by its fee payer, this method will return the {@link Signature} that\n * uniquely identifies it. This string can be used to look up transactions at a later date, for\n * example on a Solana block explorer.\n *\n * @example\n * ```ts\n * import { getSignatureFromTransaction } from '@solana/transactions';\n *\n * const signature = getSignatureFromTransaction(tx);\n * console.debug(`Inspect this transaction at https://explorer.solana.com/tx/${signature}`);\n * ```\n */\nexport function getSignatureFromTransaction(transaction: Transaction): Signature {\n if (!base58Decoder) base58Decoder = getBase58Decoder();\n\n // We have ordered signatures from the compiled message accounts\n // first signature is the fee payer\n const signatureBytes = Object.values(transaction.signatures)[0];\n if (!signatureBytes) {\n throw new SolanaError(SOLANA_ERROR__TRANSACTION__FEE_PAYER_SIGNATURE_MISSING);\n }\n const transactionSignature = base58Decoder.decode(signatureBytes);\n return transactionSignature as Signature;\n}\n\n/**\n * Given an array of `CryptoKey` objects which are private keys pertaining to addresses that are\n * required to sign a transaction, this method will return a new signed transaction of type\n * {@link Transaction}.\n *\n * Though the resulting transaction might have every signature it needs to land on the network, this\n * function will not assert that it does. A partially signed transaction cannot be landed on the\n * network, but can be serialized and deserialized.\n *\n * @example\n * ```ts\n * import { generateKeyPair } from '@solana/keys';\n * import { partiallySignTransaction } from '@solana/transactions';\n *\n * const partiallySignedTransaction = await partiallySignTransaction([myPrivateKey], tx);\n * ```\n *\n * @see {@link signTransaction} if you want to assert that the transaction has all of its required\n * signatures after signing.\n */\nexport async function partiallySignTransaction<TTransaction extends Transaction>(\n keyPairs: CryptoKeyPair[],\n transaction: TTransaction,\n): Promise<TTransaction> {\n let newSignatures: Record<Address, SignatureBytes> | undefined;\n let unexpectedSigners: Set<Address> | undefined;\n\n await Promise.all(\n keyPairs.map(async keyPair => {\n const address = await getAddressFromPublicKey(keyPair.publicKey);\n const existingSignature = transaction.signatures[address];\n\n // Check if the address is expected to sign the transaction\n if (existingSignature === undefined) {\n // address is not an expected signer for this transaction\n unexpectedSigners ||= new Set();\n unexpectedSigners.add(address);\n return;\n }\n\n // Return if there are any unexpected signers already since we won't be using signatures\n if (unexpectedSigners) {\n return;\n }\n\n const newSignature = await signBytes(keyPair.privateKey, transaction.messageBytes);\n\n if (existingSignature !== null && bytesEqual(newSignature, existingSignature)) {\n // already have the same signature set\n return;\n }\n\n newSignatures ||= {};\n newSignatures[address] = newSignature;\n }),\n );\n\n if (unexpectedSigners && unexpectedSigners.size > 0) {\n const expectedSigners = Object.keys(transaction.signatures);\n throw new SolanaError(SOLANA_ERROR__TRANSACTION__ADDRESSES_CANNOT_SIGN_TRANSACTION, {\n expectedAddresses: expectedSigners,\n unexpectedAddresses: [...unexpectedSigners],\n });\n }\n\n if (!newSignatures) {\n return transaction;\n }\n\n return Object.freeze({\n ...transaction,\n signatures: Object.freeze({\n ...transaction.signatures,\n ...newSignatures,\n }),\n });\n}\n\n/**\n * Given an array of `CryptoKey` objects which are private keys pertaining to addresses that are\n * required to sign a transaction, this method will return a new signed transaction of type\n * {@link FullySignedTransaction}.\n *\n * This function will throw unless the resulting transaction is fully signed.\n *\n * @example\n * ```ts\n * import { generateKeyPair } from '@solana/keys';\n * import { signTransaction } from '@solana/transactions';\n *\n * const signedTransaction = await signTransaction([myPrivateKey], tx);\n * ```\n *\n * @see {@link partiallySignTransaction} if you want to sign the transaction without asserting that\n * the resulting transaction is fully signed.\n */\nexport async function signTransaction<TTransaction extends Transaction>(\n keyPairs: CryptoKeyPair[],\n transaction: TTransaction,\n): Promise<FullySignedTransaction & TTransaction> {\n const out = await partiallySignTransaction(keyPairs, transaction);\n assertIsFullySignedTransaction(out);\n Object.freeze(out);\n return out;\n}\n\n/**\n * Checks whether a given {@link Transaction} is fully signed.\n *\n * @example\n * ```ts\n * import { isFullySignedTransaction } from '@solana/transactions';\n *\n * const transaction = getTransactionDecoder().decode(transactionBytes);\n * if (isFullySignedTransaction(transaction)) {\n * // At this point we know that the transaction is signed and can be sent to the network.\n * }\n * ```\n */\nexport function isFullySignedTransaction<TTransaction extends Transaction>(\n transaction: TTransaction,\n): transaction is FullySignedTransaction & TTransaction {\n return Object.entries(transaction.signatures).every(([_, signatureBytes]) => !!signatureBytes);\n}\n\n/**\n * From time to time you might acquire a {@link Transaction}, that you expect to be fully signed,\n * from an untrusted network API or user input. Use this function to assert that such a transaction\n * is fully signed.\n *\n * @example\n * ```ts\n * import { assertIsFullySignedTransaction } from '@solana/transactions';\n *\n * const transaction = getTransactionDecoder().decode(transactionBytes);\n * try {\n * // If this type assertion function doesn't throw, then Typescript will upcast `transaction`\n * // to `FullySignedTransaction`.\n * assertIsFullySignedTransaction(transaction);\n * // At this point we know that the transaction is signed and can be sent to the network.\n * await sendAndConfirmTransaction(transaction, { commitment: 'confirmed' });\n * } catch(e) {\n * if (isSolanaError(e, SOLANA_ERROR__TRANSACTION__SIGNATURES_MISSING)) {\n * setError(`Missing signatures for ${e.context.addresses.join(', ')}`);\n * }\n * throw;\n * }\n * ```\n */\nexport function assertIsFullySignedTransaction<TTransaction extends Transaction>(\n transaction: TTransaction,\n): asserts transaction is FullySignedTransaction & TTransaction {\n const missingSigs: Address[] = [];\n Object.entries(transaction.signatures).forEach(([address, signatureBytes]) => {\n if (!signatureBytes) {\n missingSigs.push(address as Address);\n }\n });\n\n if (missingSigs.length > 0) {\n throw new SolanaError(SOLANA_ERROR__TRANSACTION__SIGNATURES_MISSING, {\n addresses: missingSigs,\n });\n }\n}\n","import { getBase64Decoder } from '@solana/codecs-strings';\nimport { Brand, EncodedString } from '@solana/nominal-types';\n\nimport { getTransactionEncoder } from './codecs';\nimport { Transaction } from './transaction';\n\n/** Represents the wire format of a transaction as a base64-encoded string. */\nexport type Base64EncodedWireTransaction = Brand<EncodedString<string, 'base64'>, 'Base64EncodedWireTransaction'>;\n\n/**\n * Given a signed transaction, this method returns the transaction as a string that conforms to the\n * {@link Base64EncodedWireTransaction} type.\n *\n * @example\n * ```ts\n * import { getBase64EncodedWireTransaction, signTransaction } from '@solana/transactions';\n *\n * const serializedTransaction = getBase64EncodedWireTransaction(signedTransaction);\n * const signature = await rpc.sendTransaction(serializedTransaction, { encoding: 'base64' }).send();\n * ```\n */\nexport function getBase64EncodedWireTransaction(transaction: Transaction): Base64EncodedWireTransaction {\n const wireTransactionBytes = getTransactionEncoder().encode(transaction);\n return getBase64Decoder().decode(wireTransactionBytes) as Base64EncodedWireTransaction;\n}\n","import { SOLANA_ERROR__TRANSACTION__EXCEEDS_SIZE_LIMIT, SolanaError } from '@solana/errors';\nimport type { NominalType } from '@solana/nominal-types';\nimport type { BaseTransactionMessage, TransactionMessageWithinSizeLimit } from '@solana/transaction-messages';\n\nimport { getTransactionEncoder } from './codecs';\nimport { Transaction } from './transaction';\n\n/**\n * The maximum size of a transaction packet in bytes.\n */\nexport const TRANSACTION_PACKET_SIZE = 1280;\n\n/**\n * The size of the transaction packet header in bytes.\n * This includes the IPv6 header and the fragment header.\n */\nexport const TRANSACTION_PACKET_HEADER =\n 40 /* 40 bytes is the size of the IPv6 header. */ + 8; /* 8 bytes is the size of the fragment header. */\n\n/**\n * The maximum size of a transaction in bytes.\n *\n * Note that this excludes the transaction packet header.\n * In other words, this is how much content we can fit in a transaction packet.\n */\nexport const TRANSACTION_SIZE_LIMIT = TRANSACTION_PACKET_SIZE - TRANSACTION_PACKET_HEADER;\n\n/**\n * Gets the size of a given transaction in bytes.\n *\n * @example\n * ```ts\n * const transactionSize = getTransactionSize(transaction);\n * ```\n */\nexport function getTransactionSize(transaction: Transaction): number {\n return getTransactionEncoder().getSizeFromValue(transaction);\n}\n\n/**\n * A type guard that checks if a transaction is within the size limit.\n */\nexport type TransactionWithinSizeLimit = NominalType<'transactionSize', 'withinLimit'>;\n\n/**\n * Helper type that adds the `TransactionWithinSizeLimit` flag to\n * a transaction if and only if the provided transaction message\n * is also within the size limit.\n */\nexport type SetTransactionWithinSizeLimitFromTransactionMessage<\n TTransaction extends Transaction,\n TTransactionMessage extends BaseTransactionMessage,\n> = TTransactionMessage extends TransactionMessageWithinSizeLimit\n ? TransactionWithinSizeLimit & TTransaction\n : TTransaction;\n\n/**\n * Checks if a transaction is within the size limit.\n *\n * @typeParam TTransaction - The type of the given transaction.\n *\n * @example\n * ```ts\n * if (isTransactionWithinSizeLimit(transaction)) {\n * transaction satisfies TransactionWithinSizeLimit;\n * }\n * ```\n */\nexport function isTransactionWithinSizeLimit<TTransaction extends Transaction>(\n transaction: TTransaction,\n): transaction is TransactionWithinSizeLimit & TTransaction {\n return getTransactionSize(transaction) <= TRANSACTION_SIZE_LIMIT;\n}\n\n/**\n * Asserts that a given transaction is within the size limit.\n *\n * Throws a {@link SolanaError} of code {@link SOLANA_ERROR__TRANSACTION__EXCEEDS_SIZE_LIMIT}\n * if the transaction exceeds the size limit.\n *\n * @typeParam TTransaction - The type of the given transaction.\n *\n * @example\n * ```ts\n * assertIsTransactionWithinSizeLimit(transaction);\n * transaction satisfies TransactionWithinSizeLimit;\n * ```\n */\nexport function assertIsTransactionWithinSizeLimit<TTransaction extends Transaction>(\n transaction: TTransaction,\n): asserts transaction is TransactionWithinSizeLimit & TTransaction {\n const transactionSize = getTransactionSize(transaction);\n if (transactionSize > TRANSACTION_SIZE_LIMIT) {\n throw new SolanaError(SOLANA_ERROR__TRANSACTION__EXCEEDS_SIZE_LIMIT, {\n transactionSize,\n transactionSizeLimit: TRANSACTION_SIZE_LIMIT,\n });\n }\n}\n","import { assertIsFullySignedTransaction, FullySignedTransaction, isFullySignedTransaction } from './signatures';\nimport { Transaction } from './transaction';\nimport {\n assertIsTransactionWithinSizeLimit,\n isTransactionWithinSizeLimit,\n TransactionWithinSizeLimit,\n} from './transaction-size';\n\n/**\n * Helper type that includes all transaction types required\n * for the transaction to be sent to the network.\n *\n * @see {@link isSendableTransaction}\n * @see {@link assertIsSendableTransaction}\n */\nexport type SendableTransaction = FullySignedTransaction & TransactionWithinSizeLimit;\n\n/**\n * Checks if a transaction has all the required\n * conditions to be sent to the network.\n *\n * @example\n * ```ts\n * import { isSendableTransaction } from '@solana/transactions';\n *\n * const transaction = getTransactionDecoder().decode(transactionBytes);\n * if (isSendableTransaction(transaction)) {\n * // At this point we know that the transaction can be sent to the network.\n * }\n * ```\n *\n * @see {@link assertIsSendableTransaction}\n */\nexport function isSendableTransaction<TTransaction extends Transaction>(\n transaction: TTransaction,\n): transaction is SendableTransaction & TTransaction {\n return isFullySignedTransaction(transaction) && isTransactionWithinSizeLimit(transaction);\n}\n\n/**\n * Asserts that a given transaction has all the\n * required conditions to be sent to the network.\n *\n * From time to time you might acquire a {@link Transaction}\n * from an untrusted network API or user input and you are not sure\n * that it has all the required conditions to be sent to the network\n * — such as being fully signed and within the size limit.\n * This function can be used to assert that such a transaction\n * is in fact sendable.\n *\n * @example\n * ```ts\n * import { assertIsSendableTransaction } from '@solana/transactions';\n *\n * const transaction = getTransactionDecoder().decode(transactionBytes);\n * try {\n * // If this type assertion function doesn't throw, then Typescript will upcast `transaction`\n * // to `SendableTransaction`.\n * assertIsSendableTransaction(transaction);\n * // At this point we know that the transaction can be sent to the network.\n * await sendAndConfirmTransaction(transaction, { commitment: 'confirmed' });\n * } catch(e) {\n * if (isSolanaError(e, SOLANA_ERROR__TRANSACTION__SIGNATURES_MISSING)) {\n * setError(`Missing signatures for ${e.context.addresses.join(', ')}`);\n * } else if (isSolanaError(e, SOLANA_ERROR__TRANSACTION__EXCEEDS_SIZE_LIMIT)) {\n * setError(`Transaction exceeds size limit of ${e.context.transactionSizeLimit} bytes`);\n * }\n * throw;\n * }\n * ```\n */\nexport function assertIsSendableTransaction<TTransaction extends Transaction>(\n transaction: TTransaction,\n): asserts transaction is SendableTransaction & TTransaction {\n assertIsFullySignedTransaction(transaction);\n assertIsTransactionWithinSizeLimit(transaction);\n}\n","import { SOLANA_ERROR__TRANSACTION__EXCEEDS_SIZE_LIMIT, SolanaError } from '@solana/errors';\nimport type {\n BaseTransactionMessage,\n TransactionMessageWithFeePayer,\n TransactionMessageWithinSizeLimit,\n} from '@solana/transaction-messages';\n\nimport { compileTransaction } from './compile-transaction';\nimport { getTransactionSize, TRANSACTION_SIZE_LIMIT } from './transaction-size';\n\n/**\n * Gets the compiled transaction size of a given transaction message in bytes.\n *\n * @example\n * ```ts\n * const transactionSize = getTransactionMessageSize(transactionMessage);\n * ```\n */\nexport function getTransactionMessageSize(\n transactionMessage: BaseTransactionMessage & TransactionMessageWithFeePayer,\n): number {\n return getTransactionSize(compileTransaction(transactionMessage));\n}\n\n/**\n * Checks if a transaction message is within the size limit\n * when compiled into a transaction.\n *\n * @typeParam TTransactionMessage - The type of the given transaction message.\n *\n * @example\n * ```ts\n * if (isTransactionMessageWithinSizeLimit(transactionMessage)) {\n * transactionMessage satisfies TransactionMessageWithinSizeLimit;\n * }\n * ```\n */\nexport function isTransactionMessageWithinSizeLimit<\n TTransactionMessage extends BaseTransactionMessage & TransactionMessageWithFeePayer,\n>(\n transactionMessage: TTransactionMessage,\n): transactionMessage is TransactionMessageWithinSizeLimit & TTransactionMessage {\n return getTransactionMessageSize(transactionMessage) <= TRANSACTION_SIZE_LIMIT;\n}\n\n/**\n * Asserts that a given transaction message is within the size limit\n * when compiled into a transaction.\n *\n * Throws a {@link SolanaError} of code {@link SOLANA_ERROR__TRANSACTION__EXCEEDS_SIZE_LIMIT}\n * if the transaction message exceeds the size limit.\n *\n * @typeParam TTransactionMessage - The type of the given transaction message.\n *\n * @example\n * ```ts\n * assertIsTransactionMessageWithinSizeLimit(transactionMessage);\n * transactionMessage satisfies TransactionMessageWithinSizeLimit;\n * ```\n */\nexport function assertIsTransactionMessageWithinSizeLimit<\n TTransactionMessage extends BaseTransactionMessage & TransactionMessageWithFeePayer,\n>(\n transactionMessage: TTransactionMessage,\n): asserts transactionMessage is TransactionMessageWithinSizeLimit & TTransactionMessage {\n const transactionSize = getTransactionMessageSize(transactionMessage);\n if (transactionSize > TRANSACTION_SIZE_LIMIT) {\n throw new SolanaError(SOLANA_ERROR__TRANSACTION__EXCEEDS_SIZE_LIMIT, {\n transactionSize,\n transactionSizeLimit: TRANSACTION_SIZE_LIMIT,\n });\n }\n}\n"]}