1#![no_std]
2
3use core::mem::MaybeUninit;
6use pinocchio::{
7 account_info::AccountInfo,
8 instruction::{Seed, Signer},
9 program_error::ProgramError,
10 pubkey::Pubkey,
11 sysvars::{rent::Rent, Sysvar},
12 ProgramResult,
13};
14use pinocchio_pubkey::derive_address;
15use pinocchio_system::instructions::CreateAccount;
16
17pub fn create_pda_account<const N: usize>(
18 payer: &AccountInfo,
19 pda: &AccountInfo,
20 program_id: &Pubkey,
21 space: u64,
22 seeds: &[&[u8]],
23 bump: u8,
24) -> ProgramResult {
25 if !payer.is_signer() {
27 return Err(ProgramError::MissingRequiredSignature);
28 }
29 if pda.lamports() != 0 {
30 return Err(ProgramError::AccountAlreadyInitialized);
31 }
32
33 if seeds.len() + 1 > N {
34 return Err(ProgramError::InvalidArgument);
35 }
36
37 let bump_seed = [bump];
38 let mut seeds_with_bump: [&[u8]; N] = [&[]; N];
39
40 let seeds_count = seeds.len();
42 seeds_with_bump[..seeds_count].copy_from_slice(seeds);
43 seeds_with_bump[seeds_count] = &bump_seed;
44
45 let expected_pda = derive_address(&seeds_with_bump, None, program_id);
47 if &expected_pda != pda.key() {
48 return Err(ProgramError::InvalidSeeds);
49 }
50
51 let rent = Rent::get()?;
53 let lamports = rent.minimum_balance(space as usize);
54
55 let mut pinocchio_seeds: [MaybeUninit<Seed>; N] =
57 unsafe { MaybeUninit::uninit().assume_init() };
58 for i in 0..=seeds_count {
59 pinocchio_seeds[i] = MaybeUninit::new(Seed::from(seeds_with_bump[i]));
60 }
61
62 let signer_seeds: &[Seed] = unsafe {
63 core::slice::from_raw_parts(pinocchio_seeds.as_ptr() as *const Seed, seeds_count + 1)
64 };
65
66 CreateAccount {
68 from: payer,
69 to: pda,
70 lamports,
71 space,
72 owner: program_id,
73 }
74 .invoke_signed(&[Signer::from(signer_seeds)])?;
75
76 Ok(())
77}