Skip to main content

solr_token_whitelist/
processor.rs

1use num_traits::FromPrimitive;
2use solana_program::{
3    account_info::{next_account_info, AccountInfo},
4    entrypoint::ProgramResult,
5    msg,
6    decode_error::DecodeError,
7    program_error::{PrintProgramError, ProgramError},
8    program_pack::{IsInitialized},
9    pubkey::Pubkey,
10    sysvar::{rent::Rent, Sysvar},
11};
12
13use crate::{error::TokenWhitelistError, instruction::TokenWhitelistInstruction, state::TokenWhitelist};
14
15pub struct Processor;
16impl Processor {
17    pub fn process(
18        program_id: &Pubkey,
19        accounts: &[AccountInfo],
20        instruction_data: &[u8],
21    ) -> ProgramResult {
22        let instruction = TokenWhitelistInstruction::unpack(instruction_data)?;
23
24        match instruction {
25            TokenWhitelistInstruction::InitTokenWhitelist { max_whitelist_size } => {
26                msg!("Instruction: InitTokenWhitelist");
27                Self::process_init_whitelist(
28                    accounts,
29                    max_whitelist_size,
30                    program_id
31                )
32            }
33            TokenWhitelistInstruction::AddToWhitelist {} => {
34                msg!("Instruction: AddToWhitelist");
35                Self::process_add_whitelist(
36                    accounts,
37                    program_id
38                )
39            }
40            TokenWhitelistInstruction::RemoveFromWhitelist {} => {
41                msg!("Instruction: RemoveFromWhitelist");
42                Self::process_remove_whitelist(
43                    accounts,
44                    program_id
45                )
46            }
47            TokenWhitelistInstruction::SetAllocationToZero {} => {
48                msg!("Instruction: SetAllocationToZero");
49                Self::process_set_allocation_to_zero(
50                    accounts,
51                    program_id
52                )
53            }
54        }
55    }
56
57    fn process_init_whitelist(
58        accounts: &[AccountInfo],
59        max_whitelist_size: u64,
60        _program_id: &Pubkey,
61    ) -> ProgramResult {
62        let account_info_iter = &mut accounts.iter();
63
64        let whitelist_owner = next_account_info(account_info_iter)?;
65        if !whitelist_owner.is_signer {
66            return Err(ProgramError::MissingRequiredSignature);
67        }
68
69        let token_whitelist_account = next_account_info(account_info_iter)?;
70
71        let sysvar_rent_pubkey = &Rent::from_account_info(next_account_info(account_info_iter)?)?;
72        if !sysvar_rent_pubkey.is_exempt(token_whitelist_account.lamports(), token_whitelist_account.data_len()) {
73            msg!("token whitelist account must be rent exempt");
74            return Err(TokenWhitelistError::NotRentExempt.into());
75        }
76
77        let mut token_whitelist_state = TokenWhitelist::unpack_from_slice(&token_whitelist_account.data.borrow())?;
78        if token_whitelist_state.is_initialized() {
79            msg!("token whitelist already initialized");
80            return Err(ProgramError::AccountAlreadyInitialized);
81        }
82
83        token_whitelist_state.is_initialized = true;
84        token_whitelist_state.init_pubkey = *whitelist_owner.key;
85        token_whitelist_state.max_whitelist_size = max_whitelist_size;
86
87        token_whitelist_state.pack_into_slice(&mut token_whitelist_account.data.borrow_mut());
88
89        Ok(())
90    }
91
92    fn process_add_whitelist(
93        accounts: &[AccountInfo],
94        _program_id: &Pubkey,
95    ) -> ProgramResult {
96        let account_info_iter = &mut accounts.iter();
97
98        let whitelist_owner = next_account_info(account_info_iter)?;
99        if !whitelist_owner.is_signer {
100            return Err(ProgramError::MissingRequiredSignature);
101        }
102
103        let token_whitelist_account = next_account_info(account_info_iter)?;
104        let account_to_add = next_account_info(account_info_iter)?;
105
106        let mut token_whitelist_state = TokenWhitelist::unpack_from_slice(&token_whitelist_account.data.borrow())?;
107        if !token_whitelist_state.is_initialized() {
108            msg!("token whitelist needs to be initialized before attempting to add");
109            return Err(TokenWhitelistError::TokenWhitelistNotInit.into());
110        }
111        if whitelist_owner.key != &token_whitelist_state.init_pubkey {
112            msg!("signer must be whitelist owner");
113            msg!("{}", whitelist_owner.key);
114            msg!("{}", token_whitelist_state.init_pubkey);
115            return Err(TokenWhitelistError::TokenWhitelistNotOwner.into());
116        }
117
118        let whitelist_amount: u64 = 250;
119        token_whitelist_state.add_keypair(&account_to_add.key.to_string(), &whitelist_amount);
120        token_whitelist_state.pack_into_slice(&mut token_whitelist_account.data.borrow_mut());
121
122        Ok(())
123    }
124
125    fn process_remove_whitelist(
126        accounts: &[AccountInfo],
127        _program_id: &Pubkey,
128    ) -> ProgramResult {
129        let account_info_iter = &mut accounts.iter();
130
131        let whitelist_owner = next_account_info(account_info_iter)?;
132        if !whitelist_owner.is_signer {
133            return Err(ProgramError::MissingRequiredSignature);
134        }
135
136        let token_whitelist_account = next_account_info(account_info_iter)?;
137        let account_to_remove = next_account_info(account_info_iter)?;
138
139        let mut token_whitelist_state = TokenWhitelist::unpack_from_slice(&token_whitelist_account.data.borrow())?;
140        if !token_whitelist_state.is_initialized() {
141            msg!("token whitelist needs to be initialized before attempting to remove");
142            return Err(TokenWhitelistError::TokenWhitelistNotInit.into());
143        }
144        if whitelist_owner.key != &token_whitelist_state.init_pubkey {
145            msg!("signer must be whitelist owner");
146            msg!("{}", whitelist_owner.key);
147            msg!("{}", token_whitelist_state.init_pubkey);
148            return Err(TokenWhitelistError::TokenWhitelistNotOwner.into());
149        }
150
151        token_whitelist_state.drop_key(&account_to_remove.key.to_string());
152        token_whitelist_state.pack_into_slice(&mut token_whitelist_account.data.borrow_mut());
153
154        Ok(())
155    }
156
157    fn process_set_allocation_to_zero(
158        accounts: &[AccountInfo],
159        _program_id: &Pubkey,
160    ) -> ProgramResult {
161        let account_info_iter = &mut accounts.iter();
162
163        let account_owner = next_account_info(account_info_iter)?;
164        if !account_owner.is_signer {
165            return Err(ProgramError::MissingRequiredSignature);
166        }
167
168        let token_whitelist_account = next_account_info(account_info_iter)?;
169        let account_to_reset = next_account_info(account_info_iter)?;
170
171        let mut token_whitelist_state = TokenWhitelist::unpack_from_slice(&token_whitelist_account.data.borrow())?;
172        if !token_whitelist_state.is_initialized() {
173            msg!("token whitelist needs to be initialized before attempting to update");
174            return Err(TokenWhitelistError::TokenWhitelistNotInit.into());
175        }
176        if account_owner.key != account_to_reset.key {
177            msg!("signer must be the owner of the account");
178            msg!("{}", account_owner.key);
179            msg!("{}", account_to_reset.key);
180            return Err(TokenWhitelistError::NotOwner.into());
181        }
182
183        let whitelist_amount: u64 = 0;
184        token_whitelist_state.add_keypair(&account_to_reset.key.to_string(), &whitelist_amount);
185        token_whitelist_state.pack_into_slice(&mut token_whitelist_account.data.borrow_mut());
186
187        Ok(())
188    }
189}
190
191impl PrintProgramError for TokenWhitelistError {
192    fn print<E>(&self)
193    where
194        E: 'static + std::error::Error + DecodeError<E> + PrintProgramError + FromPrimitive,
195    {
196        match self {
197            TokenWhitelistError::InvalidInstruction => msg!("Error: Invalid Instruction"),
198            TokenWhitelistError::NotRentExempt => msg!("Error: Not Rent Exempt"),
199            TokenWhitelistError::TokenWhitelistNotInit => msg!("Error: Token Whitelist Not Initialized"),
200            TokenWhitelistError::TokenWhitelistNotOwner => msg!("Error: Signer Not Token Whitelist Owner"),
201            TokenWhitelistError::TokenWhitelistSizeExceeds => msg!("Error: Token Whitelist Size Exceeds"),
202            TokenWhitelistError::NotOwner => msg!("Error: Signer Not Account Owner"),
203        }
204    }
205}