#![no_std]
use core::mem::MaybeUninit;
use pinocchio::{
account_info::AccountInfo,
instruction::{Seed, Signer},
program_error::ProgramError,
pubkey::Pubkey,
sysvars::{rent::Rent, Sysvar},
ProgramResult,
};
use pinocchio_pubkey::derive_address;
use pinocchio_system::instructions::CreateAccount;
pub fn create_pda_account<const N: usize>(
payer: &AccountInfo,
pda: &AccountInfo,
program_id: &Pubkey,
space: u64,
seeds: &[&[u8]],
bump: u8,
) -> ProgramResult {
if !payer.is_signer() {
return Err(ProgramError::MissingRequiredSignature);
}
if pda.lamports() != 0 {
return Err(ProgramError::AccountAlreadyInitialized);
}
if seeds.len() + 1 > N {
return Err(ProgramError::InvalidArgument);
}
let bump_seed = [bump];
let mut seeds_with_bump: [&[u8]; N] = [&[]; N];
let seeds_count = seeds.len();
seeds_with_bump[..seeds_count].copy_from_slice(seeds);
seeds_with_bump[seeds_count] = &bump_seed;
let expected_pda = derive_address(&seeds_with_bump, None, program_id);
if &expected_pda != pda.key() {
return Err(ProgramError::InvalidSeeds);
}
let rent = Rent::get()?;
let lamports = rent.minimum_balance(space as usize);
let mut pinocchio_seeds: [MaybeUninit<Seed>; N] =
unsafe { MaybeUninit::uninit().assume_init() };
for i in 0..=seeds_count {
pinocchio_seeds[i] = MaybeUninit::new(Seed::from(seeds_with_bump[i]));
}
let signer_seeds: &[Seed] = unsafe {
core::slice::from_raw_parts(pinocchio_seeds.as_ptr() as *const Seed, seeds_count + 1)
};
CreateAccount {
from: payer,
to: pda,
lamports,
space,
owner: program_id,
}
.invoke_signed(&[Signer::from(signer_seeds)])?;
Ok(())
}