I'm building a transaction on the server using Solnet:

var newTransaction = new Transaction();
newTransaction.RecentBlockHash = blockHash.Result.Value.Blockhash;
newTransaction.FeePayer = vaultAccount;
newTransaction.Add(SystemProgram.Transfer(vaultAccount.PublicKey, new PublicKey(userWalletAddress), (ulong)transactionAmount));
newTransaction.Add(SystemProgram.Transfer(new PublicKey(userWalletAddress), vaultAccount.PublicKey, (ulong)transactionAmount));
newTransaction.Add(MemoProgram.NewMemo(vaultAccount.PublicKey, "Staking proceeds"));
serializedTransaction = newTransaction.Serialize();
var base64Transaction = Convert.ToBase64String(serializedTransaction);
return base64Transaction;

I'm transferring Sol in both directions as a test. I want to get a signature on both the client and server.

In the browser, deserialize it back in to a solanaWeb3.Transaction:

const characters = atob(response);

//create a byte array
const byteArray = new Uint8Array(characters.length);
for (let i = 0; i < characters.length; i++) {
    byteArray[i] = characters.charCodeAt(i);

//deserialize into a transaction
const transaction = solanaWeb3.Transaction.from(byteArray);

This appears to work so far. I get a transaction with my 3 instructions and 1 signature:

debug info about the transaction object

Next I sign it with the Phantom wallet like this:

const signedTransaction = await window.solana.signTransaction(transaction);

phantom wallet with approve button

Now at this point the original transaction object has two signatures and so does the signedTransaction object. There are some differences in the two objects though.

signedTransaction: signedTransaction object properties

transaction: transaction object properties

I'm not sure which object to use, but regardless they both throw an error if I try to serialize them:

signedTransaction = signedTransaction.serialize();


Signature verification failed
  at te.serialize (inpageSol.js:268:84506)
  at Object.success (site.js?v=m-LPXQI9321elyVH3u3T3dgZpTNz3YRC9eNs1QdG94w:48:104)
serialize @ inpageSol.js:268

As a test, I tried skipping the wallet signature and the transaction serialized without error. Any help is appreciated.

1 Answer 1


It looks like the wallet is replacing the existing blockhash and using its own, which invalidates the previous signature from vaultAccount. This may be a Phantom bug, since every example I'm looking at uses this exact model of adding the blockhash and then asking the wallet to sign.

If this is taking a long time, perhaps the blockhash is expiring before calling into Phantom, which is making it replace the blockhash?

  • I made a mistake when posting my question. I must have grabbed screenshots from two different transactions. Phantom isn't changing the blockhash. Commented May 23, 2023 at 3:19

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.