I probably am doing something really stupid but this basic thing doesn't seem to work for me for this scenario. I checked the other questions similar to this one but they are either different scenarios or their answers didn't help me.
I have these instruction accounts:
#[derive(Accounts)]
pub struct CreateProfile<'info> {
pub state: Account<'info, State>,
#[account(
init,
payer = user,
space = 60,
seeds = [state.to_account_info().key.as_ref(), user.key.as_ref()],
bump,
)]
pub user_profile: Account<'info, UserProfile>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}
The actual create_profile()
function is empty, i.e. Ok(())
. When running a test against it, it fails with:
Program Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS invoke [1]
Program log: Instruction: CreateProfile
HCrVyydLF9CgiqeQNxq9dyxUswJF7KkYGurFcj2E7gfh's signer privilege escalated
Program Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS consumed 7512 of 200000 compute units
Program Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS failed: Cross-program invocation with unauthorized signer or writable account
The only CPI call is the one Anchor does to create the account, due to init
constraint. I know that to create an account, you'll need two signers: the payer and the new account itself. I am not quite sure what happens when the latter is a PDA.
This is the code that is testing it:
// omitted: state initialised in an earlier transaction
const userA = Keypair.generate();
// omitted: airdop for userA
const [pdaA] = await PublicKey.findProgramAddress(
[state.publicKey.toBytes(), userA.publicKey.toBytes()],
program.programId
);
await program.methods
.create_profile()
.accounts({
state: state.publicKey,
user_profile: pdaA,
user: userA.publicKey,
})
.signers([userA])
.rpc({ skipPreflight: true });
From the code above, it doesn't look like I am sending in the wrong seeds neither.