1use crate::instruction::MAX_SIGNERS;
4use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs};
5use num_enum::TryFromPrimitive;
6use gemachain_program::{
7 program_error::ProgramError,
8 program_option::COption,
9 program_pack::{IsInitialized, Pack, Sealed},
10 pubkey::Pubkey,
11};
12
13#[repr(C)]
15#[derive(Clone, Copy, Debug, Default, PartialEq)]
16pub struct Mint {
17 pub mint_authority: COption<Pubkey>,
21 pub supply: u64,
23 pub decimals: u8,
25 pub is_initialized: bool,
27 pub freeze_authority: COption<Pubkey>,
29}
30impl Sealed for Mint {}
31impl IsInitialized for Mint {
32 fn is_initialized(&self) -> bool {
33 self.is_initialized
34 }
35}
36impl Pack for Mint {
37 const LEN: usize = 82;
38 fn unpack_from_slice(src: &[u8]) -> Result<Self, ProgramError> {
39 let src = array_ref![src, 0, 82];
40 let (mint_authority, supply, decimals, is_initialized, freeze_authority) =
41 array_refs![src, 36, 8, 1, 1, 36];
42 let mint_authority = unpack_coption_key(mint_authority)?;
43 let supply = u64::from_le_bytes(*supply);
44 let decimals = decimals[0];
45 let is_initialized = match is_initialized {
46 [0] => false,
47 [1] => true,
48 _ => return Err(ProgramError::InvalidAccountData),
49 };
50 let freeze_authority = unpack_coption_key(freeze_authority)?;
51 Ok(Mint {
52 mint_authority,
53 supply,
54 decimals,
55 is_initialized,
56 freeze_authority,
57 })
58 }
59 fn pack_into_slice(&self, dst: &mut [u8]) {
60 let dst = array_mut_ref![dst, 0, 82];
61 let (
62 mint_authority_dst,
63 supply_dst,
64 decimals_dst,
65 is_initialized_dst,
66 freeze_authority_dst,
67 ) = mut_array_refs![dst, 36, 8, 1, 1, 36];
68 let &Mint {
69 ref mint_authority,
70 supply,
71 decimals,
72 is_initialized,
73 ref freeze_authority,
74 } = self;
75 pack_coption_key(mint_authority, mint_authority_dst);
76 *supply_dst = supply.to_le_bytes();
77 decimals_dst[0] = decimals;
78 is_initialized_dst[0] = is_initialized as u8;
79 pack_coption_key(freeze_authority, freeze_authority_dst);
80 }
81}
82
83#[repr(C)]
85#[derive(Clone, Copy, Debug, Default, PartialEq)]
86pub struct Account {
87 pub mint: Pubkey,
89 pub owner: Pubkey,
91 pub amount: u64,
93 pub delegate: COption<Pubkey>,
96 pub state: AccountState,
98 pub is_native: COption<u64>,
102 pub delegated_amount: u64,
104 pub close_authority: COption<Pubkey>,
106}
107impl Account {
108 pub fn is_frozen(&self) -> bool {
110 self.state == AccountState::Frozen
111 }
112 pub fn is_native(&self) -> bool {
114 self.is_native.is_some()
115 }
116}
117impl Sealed for Account {}
118impl IsInitialized for Account {
119 fn is_initialized(&self) -> bool {
120 self.state != AccountState::Uninitialized
121 }
122}
123impl Pack for Account {
124 const LEN: usize = 165;
125 fn unpack_from_slice(src: &[u8]) -> Result<Self, ProgramError> {
126 let src = array_ref![src, 0, 165];
127 let (mint, owner, amount, delegate, state, is_native, delegated_amount, close_authority) =
128 array_refs![src, 32, 32, 8, 36, 1, 12, 8, 36];
129 Ok(Account {
130 mint: Pubkey::new_from_array(*mint),
131 owner: Pubkey::new_from_array(*owner),
132 amount: u64::from_le_bytes(*amount),
133 delegate: unpack_coption_key(delegate)?,
134 state: AccountState::try_from_primitive(state[0])
135 .or(Err(ProgramError::InvalidAccountData))?,
136 is_native: unpack_coption_u64(is_native)?,
137 delegated_amount: u64::from_le_bytes(*delegated_amount),
138 close_authority: unpack_coption_key(close_authority)?,
139 })
140 }
141 fn pack_into_slice(&self, dst: &mut [u8]) {
142 let dst = array_mut_ref![dst, 0, 165];
143 let (
144 mint_dst,
145 owner_dst,
146 amount_dst,
147 delegate_dst,
148 state_dst,
149 is_native_dst,
150 delegated_amount_dst,
151 close_authority_dst,
152 ) = mut_array_refs![dst, 32, 32, 8, 36, 1, 12, 8, 36];
153 let &Account {
154 ref mint,
155 ref owner,
156 amount,
157 ref delegate,
158 state,
159 ref is_native,
160 delegated_amount,
161 ref close_authority,
162 } = self;
163 mint_dst.copy_from_slice(mint.as_ref());
164 owner_dst.copy_from_slice(owner.as_ref());
165 *amount_dst = amount.to_le_bytes();
166 pack_coption_key(delegate, delegate_dst);
167 state_dst[0] = state as u8;
168 pack_coption_u64(is_native, is_native_dst);
169 *delegated_amount_dst = delegated_amount.to_le_bytes();
170 pack_coption_key(close_authority, close_authority_dst);
171 }
172}
173
174#[repr(u8)]
176#[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive)]
177pub enum AccountState {
178 Uninitialized,
180 Initialized,
183 Frozen,
186}
187
188impl Default for AccountState {
189 fn default() -> Self {
190 AccountState::Uninitialized
191 }
192}
193
194#[repr(C)]
196#[derive(Clone, Copy, Debug, Default, PartialEq)]
197pub struct Multisig {
198 pub m: u8,
200 pub n: u8,
202 pub is_initialized: bool,
204 pub signers: [Pubkey; MAX_SIGNERS],
206}
207impl Sealed for Multisig {}
208impl IsInitialized for Multisig {
209 fn is_initialized(&self) -> bool {
210 self.is_initialized
211 }
212}
213impl Pack for Multisig {
214 const LEN: usize = 355;
215 fn unpack_from_slice(src: &[u8]) -> Result<Self, ProgramError> {
216 let src = array_ref![src, 0, 355];
217 #[allow(clippy::ptr_offset_with_cast)]
218 let (m, n, is_initialized, signers_flat) = array_refs![src, 1, 1, 1, 32 * MAX_SIGNERS];
219 let mut result = Multisig {
220 m: m[0],
221 n: n[0],
222 is_initialized: match is_initialized {
223 [0] => false,
224 [1] => true,
225 _ => return Err(ProgramError::InvalidAccountData),
226 },
227 signers: [Pubkey::new_from_array([0u8; 32]); MAX_SIGNERS],
228 };
229 for (src, dst) in signers_flat.chunks(32).zip(result.signers.iter_mut()) {
230 *dst = Pubkey::new(src);
231 }
232 Ok(result)
233 }
234 fn pack_into_slice(&self, dst: &mut [u8]) {
235 let dst = array_mut_ref![dst, 0, 355];
236 #[allow(clippy::ptr_offset_with_cast)]
237 let (m, n, is_initialized, signers_flat) = mut_array_refs![dst, 1, 1, 1, 32 * MAX_SIGNERS];
238 *m = [self.m];
239 *n = [self.n];
240 *is_initialized = [self.is_initialized as u8];
241 for (i, src) in self.signers.iter().enumerate() {
242 let dst_array = array_mut_ref![signers_flat, 32 * i, 32];
243 dst_array.copy_from_slice(src.as_ref());
244 }
245 }
246}
247
248fn pack_coption_key(src: &COption<Pubkey>, dst: &mut [u8; 36]) {
250 let (tag, body) = mut_array_refs![dst, 4, 32];
251 match src {
252 COption::Some(key) => {
253 *tag = [1, 0, 0, 0];
254 body.copy_from_slice(key.as_ref());
255 }
256 COption::None => {
257 *tag = [0; 4];
258 }
259 }
260}
261fn unpack_coption_key(src: &[u8; 36]) -> Result<COption<Pubkey>, ProgramError> {
262 let (tag, body) = array_refs![src, 4, 32];
263 match *tag {
264 [0, 0, 0, 0] => Ok(COption::None),
265 [1, 0, 0, 0] => Ok(COption::Some(Pubkey::new_from_array(*body))),
266 _ => Err(ProgramError::InvalidAccountData),
267 }
268}
269fn pack_coption_u64(src: &COption<u64>, dst: &mut [u8; 12]) {
270 let (tag, body) = mut_array_refs![dst, 4, 8];
271 match src {
272 COption::Some(amount) => {
273 *tag = [1, 0, 0, 0];
274 *body = amount.to_le_bytes();
275 }
276 COption::None => {
277 *tag = [0; 4];
278 }
279 }
280}
281fn unpack_coption_u64(src: &[u8; 12]) -> Result<COption<u64>, ProgramError> {
282 let (tag, body) = array_refs![src, 4, 8];
283 match *tag {
284 [0, 0, 0, 0] => Ok(COption::None),
285 [1, 0, 0, 0] => Ok(COption::Some(u64::from_le_bytes(*body))),
286 _ => Err(ProgramError::InvalidAccountData),
287 }
288}