I'm attempting to process a transaction in my solana contract. The way it seems I should do this is by using createAccountWithSeed to generate a transfer account owned by both the program (8DqELvN5TFeMtNJciUYvGqso2CyG5M6XNWxh3HRr3Vjv) and payer. So I create the new transfer account to send through to the solana program processor to execute the transaction. But when I pass the transfer account through to my Rust program the check_account_owner states that the account is owned by the System Program (11111111111111111111111111111111) rather than my program.
So my problem is two-fold:
- Is that the correct pattern to use in this instance?
- If yes, how do I create an account that both the program and payer can execute?
Here's the JS for the createAccountWithSeed in the client.
const transferAcc = await PublicKey.createWithSeed(
payer.publicKey,
"payer",
PROGRAM_ID,
);
await connection.requestAirdrop(transferAcc, 100000);
SystemProgram.createAccountWithSeed({
basePubkey: payer.publicKey,
fromPubkey: payer.publicKey,
lamports: 100000,
newAccountPubkey: transferAcc,
programId: PROGRAM_ID,
seed: "payer",
space: 1024,
});
const accInfo = await connection.getAccountInfo(transferAcc);
console.log(
`Paying from acc: ${transferAcc.toBase58()}, Owned by: ${accInfo?.owner.toBase58()}`
);
And here's the Rust code which is attempting to make the transfer.
pub fn process_payment(
program_id: &Pubkey,
accounts: &[AccountInfo],
payment_fee: u64,
) -> ProgramResult {
let account_info_iter = &mut accounts.iter();
let token_program = next_account_info(account_info_iter)?;
let payer_acc = next_account_info(account_info_iter)?;
let transfer_acc = next_account_info(account_info_iter)?;
let receiver_acc = next_account_info(account_info_iter)?;
if !payer_acc.is_signer {
return Err(ProgramError::MissingRequiredSignature);
}
if *token_program.key != id() {
return Err(SosolError::IncorrectTokenProgramId.into());
}
check_account_owner(payer_payment_acc, &program_id)?;
msg!("Calling the token program to transfer tokens to the receiver...");
token_transfer(
token_program.clone(),
transfer_acc.clone(),
receiver_account_key.clone(),
payer_acc.clone(),
payment_fee,
)?;
Ok(())
}
/// Issue a spl_token `Transfer` instruction.
#[allow(clippy::too_many_arguments)]
fn token_transfer<'a>(
token_program: AccountInfo<'a>,
source: AccountInfo<'a>,
destination: AccountInfo<'a>,
authority: AccountInfo<'a>,
amount: u64,
) -> Result<(), ProgramError> {
let ix = transfer(
token_program.key,
source.key,
destination.key,
authority.key,
&[],
amount,
)?;
invoke(&ix, &[source, destination, authority, token_program])
}
The error logs state:
Program log: Expected account to be owned by program 8DqELvN5TFeMtNJciUYvGqso2CyG5M6XNWxh3HRr3Vjv, received 11111111111111111111111111111111
Program log: CUSTOM-ERROR: The account did not have the expected program id