module_ntoken/states/
distribute_token.rs1use crate::constants::account_size::{DISTRIBUTE_TOKEN_PREFIX_SIZE, NUMBER_USERS_DISTRIBUTE, LIST_DISTRIBUTE_USER_SIZE, USER_DISTRIBUTE_SIZE};
3use crate::constants::constant::PUBKEY_SIZE;
4use crate::{
5 constants::{account_size::DISTRIBUTE_TOKEN_SIZE, account_type::TYPE_ACCOUNT_AIRDROP_ACCOUNT},
6 error::PortfolioError,
7};
8use arrayref::{array_ref, array_refs};
9use serde::{Deserialize, Serialize};
10use solana_program::{
11 entrypoint_deprecated::ProgramResult,
12 program_error::ProgramError,
13 program_pack::{IsInitialized, Sealed},
14 pubkey::Pubkey,
15};
16use std::vec::Vec;
17
18const TYPE_SIZE: usize = 1;
19const STATE_DISTIBUTE_TOKENS_SIZE: usize = 1;
20const AMOUNT_SIZE: usize = 8;
21const NFT_FIND_SIZE: usize = 1;
22const STATE_USER_DISTRIBUTE_SIZE: usize = 1;
23
24#[repr(C)]
25#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
26
27pub struct UserDistributeStruct {
28 pub user_portfolio_account: Pubkey,
30 pub amount: u64,
32 pub nft_find: u8,
35 pub state_user_distribute: u8,
37}
38impl UserDistributeStruct {
39 pub fn add_user_distribute(
41 &mut self,
42 user_portfolio_account: Pubkey,
43 amount: u64,
44 nft_find: u8,
45 state_user_distribute: u8,
46 ) -> ProgramResult {
47 self.user_portfolio_account = user_portfolio_account;
48 self.amount = self
49 .amount
50 .checked_add(amount)
51 .ok_or(PortfolioError::InvalidAmount)?;
52
53 self.nft_find = nft_find;
54 self.state_user_distribute = state_user_distribute;
55 Ok(())
56 }
57 pub fn update_state_user_distribute(&mut self, state_user_distribute: u8) -> ProgramResult {
59 self.state_user_distribute = state_user_distribute;
60 Ok(())
61 }
62}
63
64#[repr(C)]
66#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
67pub struct DistributeTokens {
68 pub type_account: u8,
70 pub state_distribute_tokens: u8,
72 pub portfolio_address: Pubkey,
74 pub list_user_distribute: Vec<UserDistributeStruct>,
76}
77
78impl Sealed for DistributeTokens {}
79
80impl IsInitialized for DistributeTokens {
81 fn is_initialized(&self) -> bool {
82 return self.type_account == TYPE_ACCOUNT_AIRDROP_ACCOUNT;
83 }
84}
85pub trait PackDistributeTokens {
87 fn unpack_distribute_token(src: &[u8]) -> Result<DistributeTokens, ProgramError>;
89 fn pack_distribute_token(&self, dst: &mut [u8]);
91}
92
93impl PackDistributeTokens for DistributeTokens {
94 fn unpack_distribute_token(src: &[u8]) -> Result<Self, ProgramError> {
96 let src_fix = array_ref![&src, 0, DISTRIBUTE_TOKEN_PREFIX_SIZE];
97 let (type_account, state_distribute_tokens, portfolio_address) =
98 array_refs![src_fix, TYPE_SIZE, STATE_DISTIBUTE_TOKENS_SIZE, PUBKEY_SIZE];
99 let mut user_distribute_vec: Vec<UserDistributeStruct> =
100 Vec::with_capacity(NUMBER_USERS_DISTRIBUTE);
101
102 let list_user_distribute_data = &src[DISTRIBUTE_TOKEN_PREFIX_SIZE
104 ..DISTRIBUTE_TOKEN_PREFIX_SIZE + LIST_DISTRIBUTE_USER_SIZE as usize];
105 let mut offset = 0;
106 for _ in 0..NUMBER_USERS_DISTRIBUTE {
107 let user_data = array_ref![list_user_distribute_data, offset, USER_DISTRIBUTE_SIZE];
108 #[allow(clippy::ptr_offset_with_cast)]
109 let (user_portfolio_account, amount, nft_find, state_user_distribute) = array_refs![
110 user_data,
111 PUBKEY_SIZE,
112 AMOUNT_SIZE,
113 NFT_FIND_SIZE,
114 STATE_USER_DISTRIBUTE_SIZE
115 ];
116 user_distribute_vec.push(UserDistributeStruct {
117 user_portfolio_account: Pubkey::new_from_array(*user_portfolio_account),
118 amount: u64::from_le_bytes(*amount),
119 nft_find: u8::from_le_bytes(*nft_find),
120 state_user_distribute: u8::from_le_bytes(*state_user_distribute),
121 });
122 offset += USER_DISTRIBUTE_SIZE;
123 }
124
125 Ok(DistributeTokens {
126 type_account: u8::from_le_bytes(*type_account),
127 state_distribute_tokens: u8::from_le_bytes(*state_distribute_tokens),
128 portfolio_address: Pubkey::new_from_array(*portfolio_address),
129 list_user_distribute: user_distribute_vec.to_vec(),
130 })
131 }
132
133 fn pack_distribute_token(&self, dst: &mut [u8]) {
135 let DistributeTokens {
136 type_account,
137 state_distribute_tokens,
138 portfolio_address,
139 list_user_distribute,
140 } = self;
141
142 let mut buffer = [0; DISTRIBUTE_TOKEN_SIZE];
143 buffer[0] = *type_account;
144 let state_distribute_tokens_range = TYPE_SIZE;
145 buffer[state_distribute_tokens_range] = *state_distribute_tokens;
146 let portfolio_address_range = TYPE_SIZE + STATE_DISTIBUTE_TOKENS_SIZE
147 ..TYPE_SIZE + STATE_DISTIBUTE_TOKENS_SIZE + PUBKEY_SIZE;
148 buffer[portfolio_address_range].clone_from_slice(portfolio_address.as_ref());
149 let user_distribute_vec_tmp = bincode::serialize(&list_user_distribute).unwrap();
150 let mut user_distribute_data_tmp = [0; LIST_DISTRIBUTE_USER_SIZE]; let len_user_distribute = user_distribute_vec_tmp.len();
152 let nbre_user_distribute = len_user_distribute / USER_DISTRIBUTE_SIZE; let len_slu_reel = nbre_user_distribute * USER_DISTRIBUTE_SIZE;
154 user_distribute_data_tmp[0..len_slu_reel as usize]
155 .clone_from_slice(&user_distribute_vec_tmp[8..len_user_distribute]); buffer[DISTRIBUTE_TOKEN_PREFIX_SIZE..DISTRIBUTE_TOKEN_PREFIX_SIZE + len_slu_reel as usize]
158 .clone_from_slice(&user_distribute_data_tmp[0..len_slu_reel as usize]);
159
160 dst[0..DISTRIBUTE_TOKEN_PREFIX_SIZE + len_slu_reel as usize]
161 .copy_from_slice(&buffer[0..DISTRIBUTE_TOKEN_PREFIX_SIZE + len_slu_reel as usize]);
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168 use crate::constants::account_type::TYPE_ACCOUNT_AIRDROP_ACCOUNT;
169 #[test]
170 fn test_pack_distribute_token() {
171 let user_portfolio_account = Pubkey::new_unique();
172 let amount = 12;
173 let nft_find = 0;
174 let state_user_distribute = 0;
175
176 let _user_distribute = UserDistributeStruct {
177 user_portfolio_account,
178 amount,
179 nft_find,
180 state_user_distribute,
181 };
182 let mut list_user_distribute = Vec::new();
183 for _i in 0..NUMBER_USERS_DISTRIBUTE {
184 let user_distribute = UserDistributeStruct {
185 user_portfolio_account,
186 amount,
187 nft_find,
188 state_user_distribute,
189 };
190 list_user_distribute.push(user_distribute);
191 }
192
193 let distribute_token = DistributeTokens {
194 type_account: TYPE_ACCOUNT_AIRDROP_ACCOUNT,
195 state_distribute_tokens: 0,
196 portfolio_address: Pubkey::new_unique(),
197 list_user_distribute,
198 };
199
200 const LEN: usize = DISTRIBUTE_TOKEN_SIZE;
201 let mut packed = [0u8; LEN];
202 PackDistributeTokens::pack_distribute_token(&distribute_token, &mut packed[..]);
203 let unpacked = DistributeTokens::unpack_distribute_token(&packed).unwrap();
204 assert_eq!(distribute_token, unpacked);
205 assert_eq!(unpacked.type_account,TYPE_ACCOUNT_AIRDROP_ACCOUNT);
206 }
207}