phoenix/program/
system_utils.rs

1use solana_program::{
2    account_info::AccountInfo,
3    entrypoint::ProgramResult,
4    program::{invoke, invoke_signed},
5    pubkey::Pubkey,
6    rent::Rent,
7    system_instruction,
8};
9
10pub fn create_account<'a, 'info>(
11    payer: &'a AccountInfo<'info>,
12    new_account: &'a AccountInfo<'info>,
13    system_program: &'a AccountInfo<'info>,
14    program_owner: &Pubkey,
15    rent: &Rent,
16    space: u64,
17    seeds: Vec<Vec<u8>>,
18) -> ProgramResult {
19    let current_lamports = **new_account.try_borrow_lamports()?;
20    if current_lamports == 0 {
21        // If there are no lamports in the new account, we create it with the create_account instruction
22        invoke_signed(
23            &system_instruction::create_account(
24                payer.key,
25                new_account.key,
26                rent.minimum_balance(space as usize),
27                space,
28                program_owner,
29            ),
30            &[payer.clone(), new_account.clone(), system_program.clone()],
31            &[seeds
32                .iter()
33                .map(|seed| seed.as_slice())
34                .collect::<Vec<&[u8]>>()
35                .as_slice()],
36        )
37    } else {
38        // Fund the account for rent exemption.
39        let required_lamports = rent
40            .minimum_balance(space as usize)
41            .max(1)
42            .saturating_sub(current_lamports);
43        if required_lamports > 0 {
44            invoke(
45                &system_instruction::transfer(payer.key, new_account.key, required_lamports),
46                &[payer.clone(), new_account.clone(), system_program.clone()],
47            )?;
48        }
49        // Allocate space.
50        invoke_signed(
51            &system_instruction::allocate(new_account.key, space),
52            &[new_account.clone(), system_program.clone()],
53            &[seeds
54                .iter()
55                .map(|seed| seed.as_slice())
56                .collect::<Vec<&[u8]>>()
57                .as_slice()],
58        )?;
59        // Assign to the specified program
60        invoke_signed(
61            &system_instruction::assign(new_account.key, program_owner),
62            &[new_account.clone(), system_program.clone()],
63            &[seeds
64                .iter()
65                .map(|seed| seed.as_slice())
66                .collect::<Vec<&[u8]>>()
67                .as_slice()],
68        )
69    }
70}