8

Is it anyhow possible to apartial sign a transaction from client side and send it back to server side for final sign and sending to blockchain?

3 Answers 3

7

I think Elliot's answer can be accepted, but I want to add some clarifying comments, and it's easier to read these as a separate answer.

partialSign is an API of the web3.js Transaction object, but not the new VersionedTransaction object, which has only a sign method. This means it won't be used at all if you're using VersionedTransaction (or the wallet uses it internally). If you look at the implementation of partialSign, you will see that all it's doing is signing the transaction, without verifying the signatures (which Transaction::sign does). Some wallets call partialSign internally, others just create the cryptographic signature and call Transaction::addSignature.

signTransaction is an API of Wallet Adapter. This is what you want to use to sign a transaction without sending it. How wallets implement this is out of scope for Wallet Adapter, and more importantly, cannot be determined by Wallet Adapter (e.g. whether they use partialSign, addSignature, directly manipulate the signatures array, or something else). Wallet Adapter sends a Transaction in (maybe with some signatures on it), and gets a Transaction out (hopefully with more signatures on it).

Transaction should never have had two methods for this, because signing and verification of signatures should never have been bundled together. This is why the newer VersionedTransaction implementation does not have two methods for signing. Wallet Adapter (and the solana: features of the Wallet Standard) will not implement a partialSign API, because from its perspective, all signing should be regarded as "partial". All wallets should correctly implement multiple signatures because Solana's transaction format allows and expects them.

The "workaround" is to get wallets to fix their implementations. If you're encountering wallets that incorrectly handle multiple expected signatures, please take it up with them, and let me know who they are, so I can pester them about it. :)

6

At the time of writing this, there isn't a one-size fits all solution to do this. In testing, you can do as Swaroop suggested, but in the real world you'll likely only have access to the user's private key abstracted away by a walletadapter interface.

If you look inside the walletadapter interface, at the time of this writing, it only specifies a signTransaction and signAllTransactions interface that wallets have to implement, but it does not specify a method by which to partial sign at the moment. Since it is an interface however, it is not unlikely that some wallets actually do support partial signing in the actual implementation.

So what can you concretely do?

  1. Jordan, the maintainer of the wallet adapter repo, is very active and helpful. If you think partial signing is an important feature, I suggest you open an issue/PR suggesting/implementing it.
  2. In the meantime, you can parse through the different wallet adapter implementations of the wallet adapter by different wallets which you can find in packages/wallets/<walletName> for each wallet (here is the link for Solflare to get you started) and then do a check for the wallet type in your app that throws an error if the wallet does not support partial signing (I trust in your ability to serialize & parse the transaction once it's partially signed ;)).
3
  • I'm aware the temporary workaround 2. is a major pain in the bum, but I wanted to suggest something as I hate stackexchange answers that just say "You can't"
    – Ahri
    Dec 27, 2022 at 21:02
  • Thank you for the explanations! Appreciate it. I've opened an issue in the wallet-adapter repo to see if anyone can possibly see it as a need of implementation and implements it in near future. Dec 29, 2022 at 8:03
  • See solana.stackexchange.com/a/5030/364 but Elliot's answer is good :)
    – Jordan
    Dec 29, 2022 at 18:00
-2

You can partially sign your transaction and send it to the server as a base64 encoded string.

Steps:

  1. Sign the transaction partially.
  2. Then encode it as a string and send it to the server.
  3. Deserialize the transaction on the server and sign it with the remaining keys.
  4. Execute the transaction.

Client Side

transaction.partialSign(mint);
const encoded = base64.encode(transaction.serialize());

Server Side

const transactionBuf = Buffer.from(serializedTransaction, 'base64')
var transaction = VersionedTransaction.deserialize(transactionBuf);
2
  • 1
    How do I go with asking the user for approval of the transaction in that case? Dec 27, 2022 at 18:37
  • You have to decode the transaction in frontend and do wallet.signTransaction(transaction) from the wallet-adapter-package to sign the tx by the user and then you can use the sendTransaction method to send it to the blockchain
    – Pratik.js
    Dec 30, 2022 at 7:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.