1use num_enum::{IntoPrimitive, TryFromPrimitive};
2use solana_program::{
3 account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError,
4 pubkey::Pubkey, rent::Rent, sysvar::Sysvar,
5};
6
7#[inline(always)]
9pub(crate) fn create_pda<'a, 'info>(
10 target_account: &'a AccountInfo<'info>,
11 owner: &Pubkey,
12 space: usize,
13 pda_seeds: &[&[u8]],
14 system_program: &'a AccountInfo<'info>,
15 payer: &'a AccountInfo<'info>,
16) -> ProgramResult {
17 let rent = Rent::get()?;
18 if target_account.lamports().eq(&0) {
19 solana_program::program::invoke_signed(
21 &solana_program::system_instruction::create_account(
22 payer.key,
23 target_account.key,
24 rent.minimum_balance(space),
25 space as u64,
26 owner,
27 ),
28 &[
29 payer.clone(),
30 target_account.clone(),
31 system_program.clone(),
32 ],
33 &[pda_seeds],
34 )?;
35 } else {
36 let rent_exempt_balance = rent
40 .minimum_balance(space)
41 .saturating_sub(target_account.lamports());
42 if rent_exempt_balance.gt(&0) {
43 solana_program::program::invoke(
44 &solana_program::system_instruction::transfer(
45 payer.key,
46 target_account.key,
47 rent_exempt_balance,
48 ),
49 &[
50 payer.as_ref().clone(),
51 target_account.as_ref().clone(),
52 system_program.as_ref().clone(),
53 ],
54 )?;
55 }
56
57 solana_program::program::invoke_signed(
59 &solana_program::system_instruction::allocate(target_account.key, space as u64),
60 &[
61 target_account.as_ref().clone(),
62 system_program.as_ref().clone(),
63 ],
64 &[pda_seeds],
65 )?;
66
67 solana_program::program::invoke_signed(
69 &solana_program::system_instruction::assign(target_account.key, owner),
70 &[
71 target_account.as_ref().clone(),
72 system_program.as_ref().clone(),
73 ],
74 &[pda_seeds],
75 )?;
76 }
77
78 Ok(())
79}
80
81#[repr(u8)]
82#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)]
83pub enum AccountDiscriminator {
84 Bus = 100,
85 Proof = 101,
86 Treasury = 102,
87}
88
89pub trait Discriminator {
90 fn discriminator() -> AccountDiscriminator;
91}
92
93pub trait AccountDeserialize {
94 fn try_from_bytes(data: &[u8]) -> Result<&Self, ProgramError>;
95 fn try_from_bytes_mut(data: &mut [u8]) -> Result<&mut Self, ProgramError>;
96}
97
98#[macro_export]
99macro_rules! impl_to_bytes {
100 ($struct_name:ident) => {
101 impl $struct_name {
102 pub fn to_bytes(&self) -> &[u8] {
103 bytemuck::bytes_of(self)
104 }
105 }
106 };
107}
108
109#[macro_export]
110macro_rules! impl_account_from_bytes {
111 ($struct_name:ident) => {
112 impl crate::utils::AccountDeserialize for $struct_name {
113 fn try_from_bytes(
114 data: &[u8],
115 ) -> Result<&Self, solana_program::program_error::ProgramError> {
116 if (Self::discriminator() as u8).ne(&data[0]) {
117 return Err(solana_program::program_error::ProgramError::InvalidAccountData);
118 }
119 bytemuck::try_from_bytes::<Self>(&data[8..]).or(Err(
120 solana_program::program_error::ProgramError::InvalidAccountData,
121 ))
122 }
123 fn try_from_bytes_mut(
124 data: &mut [u8],
125 ) -> Result<&mut Self, solana_program::program_error::ProgramError> {
126 if (Self::discriminator() as u8).ne(&data[0]) {
127 return Err(solana_program::program_error::ProgramError::InvalidAccountData);
128 }
129 bytemuck::try_from_bytes_mut::<Self>(&mut data[8..]).or(Err(
130 solana_program::program_error::ProgramError::InvalidAccountData,
131 ))
132 }
133 }
134 };
135}
136
137#[macro_export]
138macro_rules! impl_instruction_from_bytes {
139 ($struct_name:ident) => {
140 impl $struct_name {
141 pub fn try_from_bytes(
142 data: &[u8],
143 ) -> Result<&Self, solana_program::program_error::ProgramError> {
144 bytemuck::try_from_bytes::<Self>(data).or(Err(
145 solana_program::program_error::ProgramError::InvalidInstructionData,
146 ))
147 }
148 }
149 };
150}