I've been having this problem for a few weeks now. First, I'm creating a PDA for managing campaigns:
pub struct CreateCampaign<'info> {
#[account(
init,
payer = seller,
space = 200,
seeds = [
seller.key().as_ref(),
b"_mff_",
timestamp.to_le_bytes().as_ref(),
],
bump
)]
pub campaign: Account<'info, Campaign>,
#[account(mut)]
pub seller: Signer<'info>,
...
Then I proceed to create a mint, initialize it and set the mint authority for the PDA address:
let create_account_accounts = CreateAccount {
from: ctx.accounts.seller.to_account_info(),
to: ctx.accounts.mint.to_account_info(),
};
let create_account_cpi_ctx = CpiContext::new(
ctx.accounts.token_program.to_account_info(),
create_account_accounts,
);
let rent_balance = Rent::get()?.minimum_balance(82);
system_program::create_account(
create_account_cpi_ctx,
rent_balance,
82,
&ctx.accounts.token_program.key(),
)?;
let initialize_mint_accounts = token::InitializeMint {
mint: ctx.accounts.mint.to_account_info(),
rent: ctx.accounts.rent.to_account_info(),
};
let initialize_mint_cpi_ctx = CpiContext::new(
ctx.accounts.token_program.to_account_info(),
initialize_mint_accounts,
);
token::initialize_mint(
initialize_mint_cpi_ctx,
0,
&ctx.accounts.campaign.key(), // transfer the mint authority to PDA
Some(&ctx.accounts.campaign.key()),
)?;
Until this point, everything works as expected. Checking the token mint account in solana explorer confirms that the mint authority is set to the PDA. The problem starts when I try to mint any token using the PDA as signer. This is my context.
#[derive(Accounts)]
pub struct BuyerEditBid<'info> {
#[account(mut, has_one = buyer)]
pub bid: Account<'info, Bid>,
#[account(mut)]
pub campaign: Account<'info, Campaign>,
#[account(mut)]
pub buyer: Signer<'info>,
#[account(mut)]
pub mint: Account<'info, token::Mint>,
/// CHECK: We'll create this with Metaplex if bid is closed
// #[account(mut)]
// pub metadata: UncheckedAccount<'info>,
/// CHECK: We'll create this with Anchor if bid is closed
#[account(mut)]
pub token_account: UncheckedAccount<'info>,
...
Then I run this function:
fn mint_closed_bid_token(accounts: &mut BuyerEditBid) -> Result<()> {
associated_token::create(CpiContext::new(
accounts.associated_token_program.to_account_info(),
associated_token::Create {
payer: accounts.buyer.to_account_info(),
associated_token: accounts.token_account.to_account_info(),
authority: accounts.buyer.to_account_info(),
mint: accounts.mint.to_account_info(),
system_program: accounts.system_program.to_account_info(),
token_program: accounts.token_program.to_account_info(),
rent: accounts.rent.to_account_info(),
},
))?;
let seller = accounts.campaign.seller.key();
let timestamp = accounts.campaign.timestamp.to_le_bytes();
let seeds = [seller.as_ref(), "_mff_".as_bytes(), timestamp.as_ref()];
let signer_seeds = &[&seeds[..]][..];
msg!("seeds signer {:?}", signer_seeds);
let result = token::mint_to(
CpiContext::new_with_signer(
accounts.token_program.to_account_info(),
token::MintTo {
mint: accounts.mint.to_account_info(),
to: accounts.token_account.to_account_info(),
authority: accounts.campaign.to_account_info(),
},
signer_seeds,
),
u64::from(accounts.bid.amount),
);
To my surprise, I get the not so unusual error:
Cross-program invocation with unauthorized signer or writable account
Any ideas why? I've checked the seeds, even used PublicKey::find_program_address
to confirm that the seeds are correct. In fact, they are.
Why do I get this (not so descriptive) error? I can't mark my campaign account as signer. Should this error run in PDA owned accounts, when their seeds are correct?
Thanks in advance