0

I'm currently working with Solana Pay and need to add priority fees to a transaction that requires two signatures, one from the merchant to initiate a loyalty token transfer and another from the user to transfer funds.

A snippet of pseudocode is here:

// Given a mnemonic phrase and a url (solana pay compliant) ...

phrase = "a mnemonic phrase";
const posUrl = "a solana pay url";

// get the user's keypair from the provided phrase
const keyPair = keyPairFromPhrase(phrase);

const requestOptions = {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Accept-Encoding": "gzip, deflate, br",
  },
  body: JSON.stringify({
    account: keyPair.publicKey.toBase58(),
  }),
};

// we assume that the PoS server send a base 64 encoded legacy transaction, according to the solana pay spec
const fetchResponse = await fetch(posUrl, requestOptions);
const response = (await fetchResponse.json()) as SolanaPayPostResponse;

// get the transaction object from the response body
const encodedTransaction = response.transaction;

// base64-decode the transaction and deserialize it.
const decodedTx = Buffer.from(encodedTransaction, "base64");

// create a transaction object from the decoded transaction
const transaction = Transaction.from(decodedTx);

// add priority fee to the transaction
const priorityFee = await addPriorityFees(
  connection,
  transaction,
  PriorityLevel.HIGH
);

// THE PROBLEM IS HERE
transaction.add(priorityFee);

// sign the transaction with the user's keypair
transaction.partialSign(keyPair);

// versionate the transaction
const message = transaction.compileMessage();
const txSignatures = transaction.signatures;
// map signatures to Uint8Array
const signatures = txSignatures.map((signature) => {
  return new Uint8Array(signature.signature as Buffer);
});

const tx = new VersionedTransaction(message, signatures);

// I CAN'T SEND THE TRANSACTION TO THE RPC
return await connection.sendTransaction(tx);

The transaction (encoded) retrieved from the Point of Sale (POS, via the url) contains various instructions, all of which I can send without encountering any issues. However, when I include the priority fee instruction, I get the following error:

failed to send transaction: Transaction signature verification failure

Here's what I've discovered so far:

  • I've successfully simulated the transaction, including the addition of the priority fee, without encountering any errors.
  • I'm aware that signing should be the final step before sending the transaction to avoid invalidating the signatures.
  • I've successfully implemented a similar (example) with a simpler transaction and was able to send it without any problems.
  • I suspect that a valid solution could be to add the priority fee instruction in the POS

Thank you in advance and happy to document the solution :)

1 Answer 1

0

When a keypair signs a transaction, it's signing the bytes of the message. If the message is later changed, those message bytes will also change, which invalidates the previous signature.

When you deserialize the transaction from the merchant, and then change it, their signature is no longer valid.

This means that the change needs to be done at the API level -- the transaction generated and signed by the merchant must include the priority fee instructions.

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.