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!