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