@solana/transactions
Version:
Helpers for creating and serializing transactions
1 lines • 24.8 kB
Source Map (JSON)
{"version":3,"sources":["../src/codecs/signatures-encoder.ts","../src/codecs/transaction-codec.ts","../src/compile-transaction.ts","../src/signatures.ts","../src/wire-transaction.ts"],"names":["SolanaError","SOLANA_ERROR__TRANSACTION__CANNOT_ENCODE_WITH_EMPTY_SIGNATURES","transformEncoder","getArrayEncoder","fixEncoderSize","getBytesEncoder","getShortU16Encoder","getStructEncoder","transformDecoder","getStructDecoder","getArrayDecoder","fixDecoderSize","getBytesDecoder","getShortU16Decoder","combineCodec","getTupleDecoder","getTransactionVersionDecoder","padRightDecoder","getU8Decoder","getAddressDecoder","SOLANA_ERROR__TRANSACTION__MESSAGE_SIGNATURES_MISMATCH","compileTransactionMessage","getCompiledTransactionMessageEncoder","isTransactionMessageWithBlockhashLifetime","getBase58Decoder","SOLANA_ERROR__TRANSACTION__FEE_PAYER_SIGNATURE_MISSING","getAddressFromPublicKey","signBytes","SOLANA_ERROR__TRANSACTION__ADDRESSES_CANNOT_SIGN_TRANSACTION","SOLANA_ERROR__TRANSACTION__SIGNATURES_MISSING","getBase64Decoder"],"mappings":"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","file":"index.node.cjs","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 {\n CompilableTransactionMessage,\n compileTransactionMessage,\n getCompiledTransactionMessageEncoder,\n isTransactionMessageWithBlockhashLifetime,\n TransactionMessageWithBlockhashLifetime,\n TransactionMessageWithDurableNonceLifetime,\n} from '@solana/transaction-messages';\n\nimport {\n TransactionWithBlockhashLifetime,\n TransactionWithDurableNonceLifetime,\n TransactionWithLifetime,\n} from './lifetime';\nimport { SignaturesMap, Transaction, 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 BaseTransactionMessage})\n * - have a fee payer set (ie. conform to {@link ITransactionMessageWithFeePayer})\n * - have a lifetime specified (ie. conform to {@link TransactionMessageWithBlockhashLifetime} or\n * {@link TransactionMessageWithDurableNonceLifetime})\n */\nexport function compileTransaction(\n transactionMessage: CompilableTransactionMessage & TransactionMessageWithBlockhashLifetime,\n): Readonly<Transaction & TransactionWithBlockhashLifetime>;\n\nexport function compileTransaction(\n transactionMessage: CompilableTransactionMessage & TransactionMessageWithDurableNonceLifetime,\n): Readonly<Transaction & TransactionWithDurableNonceLifetime>;\n\nexport function compileTransaction(\n transactionMessage: CompilableTransactionMessage,\n): Readonly<Transaction & TransactionWithLifetime>;\n\nexport function compileTransaction(\n transactionMessage: CompilableTransactionMessage,\n): Readonly<Transaction & TransactionWithLifetime> {\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'];\n if (isTransactionMessageWithBlockhashLifetime(transactionMessage)) {\n lifetimeConstraint = {\n blockhash: transactionMessage.lifetimeConstraint.blockhash,\n lastValidBlockHeight: transactionMessage.lifetimeConstraint.lastValidBlockHeight,\n };\n } else {\n lifetimeConstraint = {\n nonce: transactionMessage.lifetimeConstraint.nonce,\n nonceAccountAddress: transactionMessage.instructions[0].accounts[0].address,\n };\n }\n\n const transaction: Transaction & TransactionWithLifetime = {\n lifetimeConstraint,\n messageBytes: messageBytes,\n signatures: Object.freeze(signatures),\n };\n\n return Object.freeze(transaction);\n}\n","import { Address, getAddressFromPublicKey } from '@solana/addresses';\nimport { 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'> & Transaction;\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\nfunction uint8ArraysEqual(arr1: Uint8Array, arr2: Uint8Array) {\n return arr1.length === arr2.length && arr1.every((value, index) => value === arr2[index]);\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<T extends Transaction>(\n keyPairs: CryptoKeyPair[],\n transaction: T,\n): Promise<T> {\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 && uint8ArraysEqual(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<T extends Transaction>(\n keyPairs: CryptoKeyPair[],\n transaction: T,\n): Promise<FullySignedTransaction & T> {\n const out = await partiallySignTransaction(keyPairs, transaction);\n assertTransactionIsFullySigned(out);\n Object.freeze(out);\n return out;\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 { assertTransactionIsFullySigned } 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 * assertTransactionIsFullySigned(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 */\nexport function assertTransactionIsFullySigned(\n transaction: Transaction,\n): asserts transaction is FullySignedTransaction {\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"]}