spl_associated_token_account/tools/
account.rs1use {
4 solana_program::{
5 account_info::AccountInfo,
6 entrypoint::ProgramResult,
7 program::{get_return_data, invoke, invoke_signed},
8 program_error::ProgramError,
9 pubkey::Pubkey,
10 rent::Rent,
11 system_instruction,
12 },
13 spl_token_2022::extension::ExtensionType,
14 std::convert::TryInto,
15};
16
17pub fn create_pda_account<'a>(
20 payer: &AccountInfo<'a>,
21 rent: &Rent,
22 space: usize,
23 owner: &Pubkey,
24 system_program: &AccountInfo<'a>,
25 new_pda_account: &AccountInfo<'a>,
26 new_pda_signer_seeds: &[&[u8]],
27) -> ProgramResult {
28 if new_pda_account.lamports() > 0 {
29 let required_lamports = rent
30 .minimum_balance(space)
31 .max(1)
32 .saturating_sub(new_pda_account.lamports());
33
34 if required_lamports > 0 {
35 invoke(
36 &system_instruction::transfer(payer.key, new_pda_account.key, required_lamports),
37 &[
38 payer.clone(),
39 new_pda_account.clone(),
40 system_program.clone(),
41 ],
42 )?;
43 }
44
45 invoke_signed(
46 &system_instruction::allocate(new_pda_account.key, space as u64),
47 &[new_pda_account.clone(), system_program.clone()],
48 &[new_pda_signer_seeds],
49 )?;
50
51 invoke_signed(
52 &system_instruction::assign(new_pda_account.key, owner),
53 &[new_pda_account.clone(), system_program.clone()],
54 &[new_pda_signer_seeds],
55 )
56 } else {
57 invoke_signed(
58 &system_instruction::create_account(
59 payer.key,
60 new_pda_account.key,
61 rent.minimum_balance(space).max(1),
62 space as u64,
63 owner,
64 ),
65 &[
66 payer.clone(),
67 new_pda_account.clone(),
68 system_program.clone(),
69 ],
70 &[new_pda_signer_seeds],
71 )
72 }
73}
74
75pub fn get_account_len<'a>(
78 mint: &AccountInfo<'a>,
79 spl_token_program: &AccountInfo<'a>,
80 extension_types: &[ExtensionType],
81) -> Result<usize, ProgramError> {
82 invoke(
83 &spl_token_2022::instruction::get_account_data_size(
84 spl_token_program.key,
85 mint.key,
86 extension_types,
87 )?,
88 &[mint.clone(), spl_token_program.clone()],
89 )?;
90 get_return_data()
91 .ok_or(ProgramError::InvalidInstructionData)
92 .and_then(|(key, data)| {
93 if key != *spl_token_program.key {
94 return Err(ProgramError::IncorrectProgramId);
95 }
96 data.try_into()
97 .map(usize::from_le_bytes)
98 .map_err(|_| ProgramError::InvalidInstructionData)
99 })
100}