spherenet-program-whitelist-interface 0.3.0

Interface of SphereNet's Program Whitelist Program
Documentation
use {
    super::{EntryState, Initializable},
    bytemuck::{Pod, Zeroable},
    pinocchio::pubkey::Pubkey,
    shank::ShankAccount,
};

/// Offset of the entry_address field in the account data
pub const ENTRY_ADDRESS_OFFSET: usize = 0;
/// Offset of the state field in the account data
pub const STATE_OFFSET: usize = 32;

#[repr(C)]
#[derive(Copy, Clone, Pod, Zeroable, ShankAccount)]
pub struct ProgramWhitelistEntry {
    pub entry_address: Pubkey,
    pub state: u8,
}

impl ProgramWhitelistEntry {
    /// Mark the entry as approved (active on the whitelist)
    #[inline(always)]
    pub fn set_approved(&mut self) {
        self.state = EntryState::Approved as u8;
    }

    /// Mark the entry as a pending request (awaiting authority approval)
    #[inline(always)]
    pub fn set_pending(&mut self) {
        self.state = EntryState::Pending as u8;
    }

    /// Check if the deployer has been approved (state == Approved).
    /// A `Pending` entry is initialized but NOT approved — the deploy gate
    /// must check this, not just `is_initialized()`.
    #[inline(always)]
    pub fn is_approved(&self) -> bool {
        self.state == EntryState::Approved as u8
    }
}

impl Initializable for ProgramWhitelistEntry {
    #[inline(always)]
    fn is_initialized(&self) -> bool {
        self.state != EntryState::Uninitialized as u8
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    /// The deploy gate checks `is_approved()`, NOT `is_initialized()`: a pending
    /// request is initialized but must not pass the gate. Only an approved entry
    /// deploys.
    #[test]
    fn pending_entry_does_not_pass_deploy_gate() {
        let mut entry = ProgramWhitelistEntry {
            entry_address: Pubkey::default(),
            state: EntryState::Uninitialized as u8,
        };

        entry.set_pending();
        assert!(entry.is_initialized());
        assert!(!entry.is_approved(), "pending entry must not be deployable");

        entry.set_approved();
        assert!(entry.is_approved(), "approved entry must be deployable");
    }
}