5

I was playing around with PDA's in anchor, but I'm having problems writing tests for it.

When I try to use anchor's worspace to create a transaction I get the error:

Error: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: Cross-program invocation with unauthorized signer or writable account

What's interesting is that if I deploy the app and write a frontend to talk with it with very similar code, everything works, it's only when I try to test it that I have problems.

Here's the simple SC I wrote:

use anchor_lang::prelude::*;
use std::mem::size_of;

declare_id!("3Z3dWerEbF5RGtcu7S3avuKRMSnHr8tUoJ69AhEWSDHM");

#[program]
pub mod demo_pda {
    use super::*;

    pub fn create_escrow(ctx: Context<CreateEscrow>, amount: u64) -> Result<()> {
        // Get Escrow Account
        let escrow = &mut ctx.accounts.escrow;

        // Set from
        escrow.from = ctx.accounts.from.key();
        // Set to
        escrow.to = ctx.accounts.to.key();
        // set amount
        escrow.amount = amount;

        Ok(())
    }
}

/// CreateEscrow context
#[derive(Accounts)]
pub struct CreateEscrow<'info> {
    // Escrow Account PDA
    #[account(
        init,
        // State account seed uses the string "state" and the users' key. 
        // Note that we can only have 1 active transaction
        seeds = [b"escrow".as_ref(), from.key().as_ref(), to.key().as_ref()],
        bump,
        payer = from,
        space = size_of::<EscrowAccount>() + 16
    )]
    pub escrow: Account<'info, EscrowAccount>,

    #[account(mut)]
    pub from: Signer<'info>,
    /// CHECK: safe
    #[account(mut)]
    pub to: AccountInfo<'info>,

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

// Escrow Account Structure
#[account]
pub struct EscrowAccount {
    // From address
    pub from: Pubkey,

    // To address
    pub to: Pubkey,

    // Amount that is owed
    pub amount: u64,
}

And here's the test I wrote for it:

import * as anchor from "@project-serum/anchor";
import { Program } from "@project-serum/anchor";
import { utf8 } from "@project-serum/anchor/dist/cjs/utils/bytes";
import { BN } from "bn.js";
import { assert } from "chai";
import { DemoPda } from "../target/types/demo_pda";

describe("demo-pda", () => {
  // Configure the client to use the local cluster.
  anchor.setProvider(anchor.AnchorProvider.env());

  const program = anchor.workspace.DemoPda as Program<DemoPda>;

  it("Is initialized!", async () => {
    const toWallet: anchor.web3.Keypair = anchor.web3.Keypair.generate();
    const [escrowPDA] = await anchor.web3.PublicKey.findProgramAddress(
      [utf8.encode('escrow')],
      program.programId
    );
    const provider = anchor.AnchorProvider.local();
    const tx = await program.methods.createEscrow(new BN(32)).accounts({
      from: provider.wallet.publicKey,
      to: toWallet.publicKey,
      systemProgram:  anchor.web3.SystemProgram.programId,
      escrow: escrowPDA
    }).rpc();
  });
});

Does anyone know why I'm only getting errors when trying to send a transaction with PDA's?

Thanks!

2 Answers 2

2

In the JS test code, replace this

    const [escrowPDA] = await anchor.web3.PublicKey.findProgramAddress(
      [utf8.encode('escrow')],
      program.programId
    );

with this

    const [escrowPDA] = await anchor.web3.PublicKey.findProgramAddress([
        utf8.encode('escrow'),
        provider.wallet.publicKey.toBuffer(),
        toWallet.publicKey.toBuffer()
      ],
      program.programId
    );

The parameters you pass into findProgramAddress must match the seeds you specified in the Rust/Anchor code, in this case eeds = [b"escrow".as_ref(), from.key().as_ref(), to.key().as_ref()].

1
  • 1
    Omg.... I swore I did that, but I guess not! That explains why my sample front end code works, but not my tests... Thanks so much for your help!
    – JoshChang
    Commented Aug 1, 2022 at 5:13
1

The client side findProgranAddress line uses different seeds than the anchor program:

seeds = [b"escrow".as_ref(), from.key().as_ref(), to.key().as_ref()],
1
  • Thanks! You're absolutely right, I forgot to include the correct seed.
    – JoshChang
    Commented Aug 1, 2022 at 5:13

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.