1

I am getting some error while sending a transaction in Android (Kotlin)

Error processing Instruction 0: Cross-program invocation with unauthorized signer or writable account

This is the function which is creating the Instruction Object.

public fun createQuestion(author: PublicKey, question: String): TransactionInstruction {
        val keys = mutableListOf<AccountMeta>()
        keys.add(AccountMeta(getQuestionPda().address, false, true))
        keys.add(AccountMeta(getProgramInfoPda().address, false, true))
        keys.add(AccountMeta(author, true, true))
        keys.add(AccountMeta(SystemProgram.PROGRAM_ID, false, false))
        return TransactionInstruction(PublicKey(BuildConfig.PROGRAM_ID), keys,
            Borsh.encodeToByteArray(AnchorInstructionSerializer("create_question"), Args_createQuestion("Android Question")))
}

PS: Typescript Tests are working, I had one more Instruction in Android which is also working.

This is the structure for this instruction:

{
      "name": "createQuestion",
      "accounts": [
        {
          "name": "question",
          "isMut": true,
          "isSigner": false
        },
        {
          "name": "programInfo",
          "isMut": true,
          "isSigner": false
        },
        {
          "name": "author",
          "isMut": true,
          "isSigner": true
        },
        {
          "name": "systemProgram",
          "isMut": false,
          "isSigner": false
        }
      ],
      "args": [
        {
          "name": "content",
          "type": "string"
        }
      ]
    }

This is the Anchor Instruction:

#[derive(Accounts)]
#[instruction(content: String)]
pub struct CreateQuestion<'info> {
    #[account(
        init_if_needed, 
        payer = author, 
        space = Question::LEN + content.len(), 
        seeds = [b"question", program_info.question_count.to_be_bytes().as_ref()],
        bump
    )]
    pub question: Account<'info, Question>,

    #[account(mut)]
    program_info: Account<'info, ProgramInfo>,

    #[account(mut)]
    pub author: Signer<'info>,

    pub system_program: Program<'info, System>,
}

I have already tried:

  • Writing the anchor program again and redeploying.
  • Ran typescript tests to check if they were working (and they are)
  • Used a new keypair to sign transactions in typescript (still working)

Note: InitializeProgramInfo instruction is working in Android. Only CreateQuestion is not working.

This is the instruction for Create Question

pub fn create_question(ctx: Context<CreateQuestion>, content: String) -> Result<()> {

    require!(content.chars().count() < 30, QuestionError::QuestionTooLong);
    require!(content.chars().count() > 1, QuestionError::QuestionEmpty);

    let clock: Clock = Clock::get().unwrap();

    ctx.accounts.question.set_inner(
        Question::new(
            ctx.accounts.author.key(),
            clock.unix_timestamp,
            content,
            ctx.accounts.program_info.question_count,
            0,
            *ctx.bumps.get("question").unwrap()
        )
    );

    ctx.accounts.program_info.increment_question_count();

    Ok(())
}
4
  • To be able to answer this I would need the actual instruction code to be able to tell which CPI fails. I would log the accounts from the TransactionInstruction and see if the signers and mutable flags are are actually set correctly. Also check if the program_info exists and can be mutable.
    – Jonas H.
    Commented Jun 22, 2023 at 12:41
  • @JonasH. Hey I added the instruction code in the question description. Also logged and checked the Accounts, they are correct. program_info also exists and is mutable Commented Jun 22, 2023 at 18:41
  • Could you run the transaction with skip-preflight checks and send one of the transaction signatures. My guess is maybe the question PDA is derived differently in client and program.
    – Jonas H.
    Commented Jun 23, 2023 at 10:53
  • 1
    @JonasH. I compared the PDA's generated Android Side and Typescript Side, they are different, thatswhy it was failing. Commented Jun 25, 2023 at 5:18

1 Answer 1

0

As described in the comments this error can have many different causes.

  • An account that needs to be a signer didn't sign
  • An account that is being changed is not marked as mutable
  • The PDA address is derived differently in the program and in the client

So here the PDA derived in the kotlin sdk was not the same as in the anchor program.

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.