Skip to main content

oil_api/state/
whitelist.rs

1use serde::{Deserialize, Serialize};
2use solana_program::program_error::ProgramError;
3use solana_program::log::sol_log;
4use steel::*;
5
6use crate::consts::WHITELIST;
7use super::OilAccount;
8
9/// Whitelist tracks access codes for pre-mine phase.
10#[repr(C)]
11#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable, Serialize, Deserialize)]
12pub struct Whitelist {
13    /// The code hash (first 32 bytes of keccak256 hash of the code string)
14    pub code_hash: [u8; 32],
15    
16    /// Number of times this code has been used (optional tracking)
17    pub usage_count: u64,
18}
19
20impl Whitelist {
21    /// Derives the PDA for a Whitelist account.
22    pub fn pda(code_hash: [u8; 32]) -> (Pubkey, u8) {
23        use crate::ID;
24        Pubkey::find_program_address(&[WHITELIST, &code_hash], &ID)
25    }
26
27    /// Validates and processes a premine access code for a new transaction.
28    pub fn validate_premine_code<'a>(
29        is_premine: bool,
30        has_access_code: bool,
31        access_code_hash: [u8; 32],
32        whitelist_info_opt: Option<&AccountInfo<'a>>,
33    ) -> Result<(), ProgramError> {
34        if is_premine {
35            if !has_access_code {
36                return Err(ProgramError::InvalidArgument); // Access code required during pre-mine
37            }
38            
39            // Validate access code: check if Whitelist PDA exists
40            let whitelist_info = whitelist_info_opt.ok_or(ProgramError::NotEnoughAccountKeys)?;
41            
42            // Derive PDA using code_hash only (not tied to wallet)
43            let (whitelist_pda, _) = Self::pda(access_code_hash);
44            whitelist_info.has_address(&whitelist_pda)?;
45            
46            // Check if account exists (has data)
47            if whitelist_info.data_is_empty() {
48                return Err(ProgramError::InvalidArgument); // Access code not found
49            }
50            
51            // Validate the code hash matches
52            let whitelist = whitelist_info.as_account::<Whitelist>(&crate::ID)?;
53            if whitelist.code_hash != access_code_hash {
54                return Err(ProgramError::InvalidArgument); // Access code hash mismatch
55            }
56            
57            // Increment usage count (optional tracking)
58            let whitelist_mut = whitelist_info.as_account_mut::<Whitelist>(&crate::ID)?;
59            whitelist_mut.usage_count = whitelist_mut.usage_count.saturating_add(1);
60            
61            sol_log(&format!(
62                "Pre-mine: access code validated, usage_count={}",
63                whitelist_mut.usage_count
64            ));
65        } else if has_access_code {
66            // Access code provided but not in pre-mine - ignore it (not an error)
67            sol_log("Access code provided but pre-mine is not active - ignoring");
68        }
69        
70        Ok(())
71    }
72}
73
74account!(OilAccount, Whitelist);