From cec9048b2f83535df7e499db5488c336981dfb5a Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Wed, 26 Jun 2024 10:07:27 +0100 Subject: [PATCH] refactor(experimental): assert single sending signer inside signAndSend function (#2852) Fixes https://github.com/solana-labs/solana-web3.js/issues/2818 This PR calls the `assertIsTransactionMessageWithSingleSendingSigner` inside the `signAndSendTransactionMessageWithSigners` so the end-user doesn't need to do it explicitly. This is partly to improve the developer experience and partly because TS doesn't fail properly when the transaction message hasn't been asserted on prior to calling the sign and send function. Note that I did not remove the `assertIsTransactionMessageWithSingleSendingSigner` and the `isTransactionMessageWithSingleSendingSigner` from the package's exports since they may still be useful for custom use-cases such as the one described in the documentation: ```ts let transactionSignature: SignatureBytes; if (isTransactionMessageWithSingleSendingSigner(transaction)) { transactionSignature = await signAndSendTransactionMessageWithSigners(transaction); } else { const signedTransaction = await signTransactionMessageWithSigners(transaction); const encodedTransaction = getBase64EncodedWireTransaction(signedTransaction); transactionSignature = await rpc.sendTransaction(encodedTransaction).send(); } ``` --- .changeset/short-jokes-begin.md | 5 +++++ packages/signers/README.md | 4 ++-- packages/signers/src/sign-transaction.ts | 8 ++++---- 3 files changed, 11 insertions(+), 6 deletions(-) create mode 100644 .changeset/short-jokes-begin.md diff --git a/.changeset/short-jokes-begin.md b/.changeset/short-jokes-begin.md new file mode 100644 index 000000000000..d4d688f6c90f --- /dev/null +++ b/.changeset/short-jokes-begin.md @@ -0,0 +1,5 @@ +--- +'@solana/signers': patch +--- + +The `signAndSendTransactionMessageWithSigners` function now automatically asserts that the provided transaction message contains a single sending signer and fails otherwise. diff --git a/packages/signers/README.md b/packages/signers/README.md index f53f286f3b09..092221c5eb09 100644 --- a/packages/signers/README.md +++ b/packages/signers/README.md @@ -549,9 +549,9 @@ Here as well, composite transaction signers are treated such that at least one s - `TransactionModifyingSigner`, if no other `TransactionModifyingSigner` exists. - `TransactionPartialSigner`, otherwise. -The provided transaction must be of type `ITransactionWithSingleSendingSigner` meaning that it must contain exactly one `TransactionSendingSigner` inside its account metas. If more than one composite signers implement the `TransactionSendingSigner` interface, one of them will be selected as the sending signer. +The provided transaction must contain exactly one `TransactionSendingSigner` inside its account metas. If more than one composite signers implement the `TransactionSendingSigner` interface, one of them will be selected as the sending signer. Otherwise, if multiple `TransactionSendingSigners` must be selected, the function will throw an error. -Therefore, you may use the `assertIsTransactionWithSingleSendingSigner()` function to ensure the transaction is of the expected type. +If you'd like to assert that a transaction makes use of exactly one `TransactionSendingSigner` _before_ calling this function, you may use the `assertIsTransactionWithSingleSendingSigner` function. ```ts assertIsTransactionWithSingleSendingSigner(myTransaction); diff --git a/packages/signers/src/sign-transaction.ts b/packages/signers/src/sign-transaction.ts index ca2ff4894fd6..f64410a430b8 100644 --- a/packages/signers/src/sign-transaction.ts +++ b/packages/signers/src/sign-transaction.ts @@ -21,7 +21,7 @@ import { isTransactionModifyingSigner, TransactionModifyingSigner } from './tran import { isTransactionPartialSigner, TransactionPartialSigner } from './transaction-partial-signer'; import { isTransactionSendingSigner, TransactionSendingSigner } from './transaction-sending-signer'; import { isTransactionSigner, TransactionSigner } from './transaction-signer'; -import { ITransactionMessageWithSingleSendingSigner } from './transaction-with-single-sending-signer'; +import { assertIsTransactionMessageWithSingleSendingSigner } from './transaction-with-single-sending-signer'; type CompilableTransactionMessageWithSigners = CompilableTransactionMessage & ITransactionMessageWithSigners; @@ -123,10 +123,10 @@ export async function signTransactionMessageWithSigners< * Otherwise, it will send the transaction using the provided fallbackSender. */ export async function signAndSendTransactionMessageWithSigners< - TTransactionMessage extends CompilableTransactionMessageWithSigners & - ITransactionMessageWithSingleSendingSigner = CompilableTransactionMessageWithSigners & - ITransactionMessageWithSingleSendingSigner, + TTransactionMessage extends CompilableTransactionMessageWithSigners = CompilableTransactionMessageWithSigners, >(transaction: TTransactionMessage, config: { abortSignal?: AbortSignal } = {}): Promise { + assertIsTransactionMessageWithSingleSendingSigner(transaction); + const abortSignal = config.abortSignal; const { partialSigners, modifyingSigners, sendingSigner } = categorizeTransactionSigners( deduplicateSigners(getSignersFromTransactionMessage(transaction).filter(isTransactionSigner)),