4

I'm trying to sign a transaction manually with the anchor framework.

The following is the normal and currently working method to call the program:

await program.value.rpc.sendTweet(topic, content, {
    accounts: {
        author: wallet.value.publicKey,
        tweet: tweet.publicKey,
        systemProgram: web3.SystemProgram.programId,
    },
    signers: [tweet],
});

Instead I want to be able to manually compile, sign and send the transaction, so I've wrote the following:

const transactionInstruction = program.value.instruction.sendTweet(topic, content, {
    accounts: {
        author: wallet.value.publicKey,
        tweet: tweet.publicKey,
        systemProgram: web3.SystemProgram.programId,
    },
    signers: [tweet, wallet.value],
});

const recentBlockhash = await connection.getLatestBlockhash();

const manualTransaction = new Transaction({
    recentBlockhash: recentBlockhash.blockhash,
    feePayer: wallet.value.publicKey,
});
manualTransaction.add(transactionInstruction);

const transactionBuffer = manualTransaction.serializeMessage();

const signature = await program.value.provider.wallet.signTransaction(manualTransaction);

const config_serializer = {
    requireAllSignatures: true,
    verifySignatures: true,
};
const rawTransaction2 = manualTransaction.serialize(config_serializer);

await web3.sendAndConfirmRawTransaction(connection, rawTransaction2);

When i trigger the button, the wallet pop up, I confirm the transaction, but the I get the error: Error: Signature verification failed at Transaction.serialize

If I inspect the transaction after signing it, I cannot see any changes, so I'm definitely signing it wrong.

What am I doing wrong?


In the contract, Tweet is defined as follow:

#[account]
pub struct Tweet {
    pub author: Pubkey,
    pub timestamp: i64,
    pub topic: String,
    pub content: String,
}

The full code base is this one https://github.com/lorisleiva/solana-twitter

1 Answer 1

3

Anchor's Wallet interface looks like this:

export interface Wallet {
  signTransaction<T extends Transaction | VersionedTransaction>(
    tx: T
  ): Promise<T>;
  /* ... */
}

That means that the signTransaction() method takes in a transaction and returns a promise for a signed transaction.

Your code assigns the return value, mistakenly, to const signature and then does not use it.

Instead, do this.

const signedManualTransaction =
  await program.value.provider.wallet.signTransaction(manualTransaction);
const rawTransaction2 = signedManualTransaction.serialize({
  requireAllSignatures: true,
  verifySignatures: true,
});
await web3.sendAndConfirmRawTransaction(connection, rawTransaction2);

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.