Skip to main content

spherenet_program_whitelist_interface/onchain/
create_whitelist.rs

1//! Onchain functionality for the `CreateWhitelist` instruction
2
3use {
4    crate::{
5        onchain::{write_bytes, UNINIT_BYTE},
6        program::ID,
7    },
8    core::{mem::MaybeUninit, slice::from_raw_parts},
9    pinocchio::{
10        account_info::AccountInfo,
11        instruction::{AccountMeta, Instruction, Signer},
12        program::invoke_signed,
13        ProgramResult,
14    },
15};
16
17/// Initializes the program whitelist account, setting its initial state with
18/// the initial authority.
19///
20/// ### Accounts:
21///   0. `[WRITE]` The whitelist account to initialize
22///   1. `[SIGNER]` The authority that will control the whitelist
23///   2. `[SIGNER]` Account that will pay for the account creation
24///   3. `[]` The system program
25pub struct CreateWhitelist<'a> {
26    /// The whitelist account to initialize
27    pub whitelist_account: &'a AccountInfo,
28    /// The authority that will control the whitelist
29    pub whitelist_authority: &'a AccountInfo,
30    /// Account that will pay for the account creation
31    pub funder: &'a AccountInfo,
32    /// System program
33    pub system_program: &'a AccountInfo,
34}
35
36impl<'a> CreateWhitelist<'a> {
37    #[inline(always)]
38    pub fn invoke(&self) -> ProgramResult {
39        self.invoke_signed(&[])
40    }
41
42    /// Creates the instruction data for the CreateWhitelist instruction
43    fn create_instruction_data() -> [MaybeUninit<u8>; 1] {
44        let mut instruction_data = [UNINIT_BYTE; 1];
45
46        // Set discriminator as u8 at offset [0]
47        write_bytes(&mut instruction_data, &[0]);
48
49        instruction_data
50    }
51
52    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
53        // account metadata
54        let account_metas: [AccountMeta; 4] = [
55            AccountMeta::writable(self.whitelist_account.key()),
56            AccountMeta::readonly_signer(self.whitelist_authority.key()),
57            AccountMeta::writable_signer(self.funder.key()),
58            AccountMeta::readonly(self.system_program.key()),
59        ];
60
61        // Create instruction data
62        let instruction_data = Self::create_instruction_data();
63
64        let instruction = Instruction {
65            program_id: &ID,
66            accounts: &account_metas,
67            data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 1) },
68        };
69
70        invoke_signed(
71            &instruction,
72            &[
73                self.whitelist_account,
74                self.whitelist_authority,
75                self.funder,
76                self.system_program,
77            ],
78            signers,
79        )
80    }
81}
82
83/// Convenience helper for the `CreateWhitelist` instruction
84pub fn create_whitelist(
85    whitelist_account: &AccountInfo,
86    whitelist_authority: &AccountInfo,
87    funder: &AccountInfo,
88    system_program: &AccountInfo,
89) -> ProgramResult {
90    let ix = CreateWhitelist {
91        whitelist_account,
92        whitelist_authority,
93        funder,
94        system_program,
95    };
96    ix.invoke()
97}
98
99/// Convenience helper for the `CreateWhitelist` instruction with the given
100/// signers.
101pub fn create_whitelist_with_seed(
102    whitelist_account: &AccountInfo,
103    whitelist_authority: &AccountInfo,
104    funder: &AccountInfo,
105    system_program: &AccountInfo,
106    signer_seeds: &[Signer],
107) -> ProgramResult {
108    let ix = CreateWhitelist {
109        whitelist_account,
110        whitelist_authority,
111        funder,
112        system_program,
113    };
114    ix.invoke_signed(signer_seeds)
115}
116
117#[cfg(test)]
118mod tests {
119    use {super::*, crate::instructions::ProgramWhitelistInstruction};
120
121    #[test]
122    fn test_instruction_data_creation() {
123        // Create instruction data using our function
124        let instruction_data = CreateWhitelist::create_instruction_data();
125
126        // Create an instruction with this data for parsing
127        let instruction = Instruction {
128            program_id: &ID,
129            accounts: &[], // Accounts not relevant for this test
130            data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 1) },
131        };
132
133        // Parse the instruction data
134        let parsed_ix = ProgramWhitelistInstruction::unpack(instruction.data).unwrap();
135
136        // Verify that the parsed instruction matches what we expect
137        match parsed_ix {
138            ProgramWhitelistInstruction::CreateWhitelist {} => (),
139            _ => panic!("Parsed incorrect instruction type"),
140        }
141    }
142}