magic-js
magic-js copied to clipboard
Solana `signTransaction` drops signatures from transactions which are partially signed
✅ Prerequisites
- [x] Did you perform a cursory search of open issues? Is this bug already reported elsewhere?
- [x] Are you running the latest SDK version?
- [x] Are you reporting to the correct repository (
magic-sdk)?
🐛 Description
If Solana transactions need multiple signers then calling transaction.partialSign(Keypair) is necessary.
If a Solana transaction is partially signed before calling magic.solana.signTransaction the returned rawTransaction will return with the signatures array having the signature for that previously partially signed key as undefined, and the rawTransaction will not include the partially signed method.
A really good example of a use case would be in order for a transaction to have another wallet be the fee payer of the transaction. So it would need to be partiallySigned by a wallet on a server, sent back to the magic client, who would then sign and send the transaction. Since magic signing strips the previous signatures from the transaction, the transaction would not be valid.
🧩 Steps to Reproduce
Create a Solana transaction that requires partial signing and sign with magic.
🤔 Expected behavior
The rawTransaction should include the partially signed method.
😮 Actual behavior
Transaction will fail to due signature verification error.
💻 Code Sample
const metadata = await magic.user.getMetadata();
const recipientPubKey = new web3.PublicKey(destinationAddress);
const payer = new web3.PublicKey(metadata.publicAddress);
const connection = new web3.Connection(rpcUrl);
const hash = await connection.getRecentBlockhash();
let transactionMagic = new web3.Transaction({
feePayer: payer,
recentBlockhash: hash.blockhash
});
const transaction = web3.SystemProgram.transfer({
fromPubkey: payer,
toPubkey: recipientPubKey,
lamports: sendAmount,
});
transactionMagic.add(...([transaction]));
transactionMagic.partialSign(Keypair.generate());
const serializeConfig = {
requireAllSignatures: false,
verifySignatures: true
};
const signedTransaction = await magic.solana.signTransaction(transactionMagic, serializeConfig);
🌎 Environment
| Software | Version(s) |
|---|---|
magic-sdk |
8.0.1 |
| Browser | Chrome |
yarn |
any |
| Operating System | any |
This issue can be fixed on the magic server by instead of calling transaction.sign(keypair) you instead call transaction.partialSign(keypair) which will preserve all of the signatures during serialization.
@harryEth Could you take a look?
@bmeeder22 or @harryEth have you found a solution or workaround to this? Wallets like Phantom solved this recently but if users use the magic wallet we are forced to do it through magic Solana.
@Ethella @harryEth it would be as simple as adding the extra method to the sdk right? So we can have a magic.solana.signTransaction() and a magic.solana.partialSignTransaction(). It is a functionality that's being used more and it's quite blocking since looks like there is no workaround.
@edmbn Forwarded your request to the stakeholder
@Ethella thank you... communication is really appreciated. Through Discord has been very difficult getting some answers or information about this topic. If you need anything ask us about the problem and will try to help as much as possible.
In case it helps to understand a clear use case for this: With Solana Pay specification users receive a partially signed transaction that must then sign and send. If we can't handle partially signed transactions users are blocked from using Solana Pay with existing Magic wallets.
@edmbn Thx for the clarification. It seems it's a must-have use case. Based on the current bandwidth we have, I can only say we'll support it by start of the next month
@Ethella can we expect to have this fix anytime soon? Wouldn't be worried if it was anything else but this is super blocking for any e-commerce trying to use Solana Pay. Thank you for your time.
@harryEth Any updates?
@Ethella I know the team may have been busy with the Magic Connect launch but is there any way we can get more info on this issue? It is something that most popular wallets have already solved yet and it is becoming increasingly necessary for Magic too. Thank you!
@Ethella I want to make a pull request to add the client part of the partialSignTransaction, which is very easy but if this helps speed the whole development I want to do it. Do I need extra permission to upload a branch, don't I?
@edmbn I just struck with this and find a workaround to it. The Transaction class allows you add the signature you had from the original partially signed transaction. Here's a snippet that allows you to re-add it to the transaction that Magic signs.
async signTransaction(tx: Transaction): Promise<Transaction> {
const serializeConfig = {
requireAllSignatures: false,
verifySignatures: true,
};
const signedTransaction = await magic.solana.signTransaction(
tx,
serializeConfig
);
const transaction = Transaction.from(signedTransaction.rawTransaction);
// add missing signers from original transaction to the newly created one
const missingSigners = transaction.signatures
.filter((s) => !s.signature)
.map((s) => s.publicKey);
missingSigners.forEach((publicKey) => {
const signature = tx.signatures.find((s) =>
publicKey.equals(s.publicKey)
);
transaction.addSignature(publicKey, signature!.signature!);
});
return transaction;
}
@cryptorrivem Sorry for getting to you late. Yes, this is a valid workaround. Also, you can make your second transaction signature on the backend and the transaction will have both signatures. Still, this latest workaround won't work with Solana Pay since the transaction already comes with the signature. Hopefully, this gets addressed soon. Thank you for posting your solution.
Hello folks, do you have any deadline for implementing partialSign transactions? Thanks for your support! <3