delegation_program_sdk/
utils.rs

1use solana_program::{
2    account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey, rent::Rent,
3    sysvar::Sysvar,
4};
5
6/// Creates a new pda
7#[inline(always)]
8pub fn create_pda<'a, 'info>(
9    target_account: &'a AccountInfo<'info>,
10    owner: &Pubkey,
11    space: usize,
12    pda_seeds: &[&[&[u8]]],
13    system_program: &'a AccountInfo<'info>,
14    payer: &'a AccountInfo<'info>,
15) -> ProgramResult {
16    let rent = Rent::get()?;
17    if target_account.lamports().eq(&0) {
18        // If balance is zero, create account
19        solana_program::program::invoke_signed(
20            &solana_program::system_instruction::create_account(
21                payer.key,
22                target_account.key,
23                rent.minimum_balance(space),
24                space as u64,
25                owner,
26            ),
27            &[
28                payer.clone(),
29                target_account.clone(),
30                system_program.clone(),
31            ],
32            pda_seeds,
33        )?;
34    } else {
35        // Otherwise, if balance is nonzero:
36        // 1) transfer sufficient lamports for rent exemption
37        let rent_exempt_balance = rent
38            .minimum_balance(space)
39            .saturating_sub(target_account.lamports());
40        if rent_exempt_balance.gt(&0) {
41            solana_program::program::invoke(
42                &solana_program::system_instruction::transfer(
43                    payer.key,
44                    target_account.key,
45                    rent_exempt_balance,
46                ),
47                &[
48                    payer.as_ref().clone(),
49                    target_account.as_ref().clone(),
50                    system_program.as_ref().clone(),
51                ],
52            )?;
53        }
54
55        // 2) allocate space for the account
56        solana_program::program::invoke_signed(
57            &solana_program::system_instruction::allocate(target_account.key, space as u64),
58            &[
59                target_account.as_ref().clone(),
60                system_program.as_ref().clone(),
61            ],
62            pda_seeds,
63        )?;
64
65        // 3) assign our program as the owner
66        solana_program::program::invoke_signed(
67            &solana_program::system_instruction::assign(target_account.key, owner),
68            &[
69                target_account.as_ref().clone(),
70                system_program.as_ref().clone(),
71            ],
72            pda_seeds,
73        )?;
74    }
75
76    Ok(())
77}
78
79/// Close PDA
80#[inline(always)]
81pub fn close_pda<'a, 'info>(
82    target_account: &'a AccountInfo<'info>,
83    destination: &'a AccountInfo<'info>,
84) -> ProgramResult {
85    // Transfer tokens from the account to the destination.
86    let dest_starting_lamports = destination.lamports();
87    **destination.lamports.borrow_mut() = dest_starting_lamports
88        .checked_add(target_account.lamports())
89        .unwrap();
90    **target_account.lamports.borrow_mut() = 0;
91
92    target_account.assign(&solana_program::system_program::ID);
93    target_account.realloc(0, false).map_err(Into::into)
94}
95
96/// Seeds with bump
97#[inline(always)]
98pub fn seeds_with_bump<'a>(seeds: &'a [&'a [u8]], bump: &'a [u8]) -> Vec<&'a [u8]> {
99    let mut combined: Vec<&'a [u8]> = Vec::with_capacity(seeds.len() + 1);
100    combined.extend_from_slice(seeds);
101    combined.push(bump);
102    combined
103}