ephemeral_rollups_sdk/
utils.rs

1use crate::solana_compat::solana::{
2    invoke, invoke_signed, resize, system_instruction, AccountInfo, ProgramResult, Pubkey, Rent,
3    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    rent_exempt: bool,
16) -> ProgramResult {
17    let rent = Rent::get()?;
18    if target_account.lamports().eq(&0) {
19        let lamports = if rent_exempt {
20            rent.minimum_balance(space)
21        } else {
22            0
23        };
24        // If balance is zero, create account
25        invoke_signed(
26            &system_instruction::create_account(
27                payer.key,
28                target_account.key,
29                lamports,
30                space as u64,
31                owner,
32            ),
33            &[
34                payer.clone(),
35                target_account.clone(),
36                system_program.clone(),
37            ],
38            pda_seeds,
39        )?;
40    } else {
41        // Otherwise, if balance is nonzero:
42        // 1) transfer sufficient lamports for rent exemption
43        if rent_exempt {
44            let rent_exempt_balance = rent
45                .minimum_balance(space)
46                .saturating_sub(target_account.lamports());
47            if rent_exempt_balance.gt(&0) {
48                invoke(
49                    &system_instruction::transfer(
50                        payer.key,
51                        target_account.key,
52                        rent_exempt_balance,
53                    ),
54                    &[
55                        payer.as_ref().clone(),
56                        target_account.as_ref().clone(),
57                        system_program.as_ref().clone(),
58                    ],
59                )?;
60            }
61        }
62
63        // 2) allocate space for the account
64        invoke_signed(
65            &system_instruction::allocate(target_account.key, space as u64),
66            &[
67                target_account.as_ref().clone(),
68                system_program.as_ref().clone(),
69            ],
70            pda_seeds,
71        )?;
72
73        // 3) assign our program as the owner
74        invoke_signed(
75            &system_instruction::assign(target_account.key, owner),
76            &[
77                target_account.as_ref().clone(),
78                system_program.as_ref().clone(),
79            ],
80            pda_seeds,
81        )?;
82    }
83
84    Ok(())
85}
86
87/// Close PDA
88#[inline(always)]
89pub fn close_pda<'a, 'info>(
90    target_account: &'a AccountInfo<'info>,
91    destination: &'a AccountInfo<'info>,
92) -> ProgramResult {
93    // Transfer tokens from the account to the destination.
94    let dest_starting_lamports = destination.lamports();
95    **destination.lamports.borrow_mut() = dest_starting_lamports
96        .checked_add(target_account.lamports())
97        .unwrap();
98    **target_account.lamports.borrow_mut() = 0;
99
100    target_account.assign(&crate::solana_compat::solana::system_program::id());
101
102    resize(target_account, 0)
103}
104
105/// Close PDA with transfer
106#[inline(always)]
107pub fn close_pda_with_system_transfer<'a, 'info>(
108    target_account: &'a AccountInfo<'info>,
109    seeds: &[&[&[u8]]],
110    destination: &'a AccountInfo<'info>,
111    system_program: &'a AccountInfo<'info>,
112) -> ProgramResult {
113    resize(target_account, 0)?;
114    target_account.assign(&crate::solana_compat::solana::system_program::id());
115    if target_account.lamports() > 0 {
116        let transfer_instruction = system_instruction::transfer(
117            target_account.key,
118            destination.key,
119            target_account.lamports(),
120        );
121        invoke_signed(
122            &transfer_instruction,
123            &[
124                target_account.clone(),
125                destination.clone(),
126                system_program.clone(),
127            ],
128            seeds,
129        )?;
130    }
131
132    Ok(())
133}
134
135/// Seeds with bump
136#[inline(always)]
137pub fn seeds_with_bump<'a>(seeds: &'a [&'a [u8]], bump: &'a [u8]) -> Vec<&'a [u8]> {
138    let mut v = Vec::from(seeds);
139    v.push(bump);
140    v
141}