spherenet_program_whitelist_interface/onchain/
add_entry.rs

1//! Onchain functionality for the `AddEntry` 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        pubkey::Pubkey,
14        ProgramResult,
15    },
16};
17
18/// Adds an address to the program whitelist or unrevokes a previously revoked
19/// address. If the `whitelist_entry_account` does not exist, this
20/// instruction creates and initializes it. If the account already exists
21/// and is marked as revoked, this instruction marks it as active again.
22///
23/// ### Accounts:
24///   0. `[]` The whitelist account (Used for validation/derivation)
25///   1. `[SIGNER]` The whitelist authority
26///   2. `[WRITE]` The whitelist entry account to be created/initialized or
27///      updated
28///   3. `[WRITE, SIGNER]` Payer account (must be a system account)
29///   4. `[]` System program
30pub struct AddEntry<'a> {
31    /// The whitelist account (Used for validation/derivation)
32    pub whitelist_account: &'a AccountInfo,
33    /// The whitelist authority
34    pub whitelist_authority: &'a AccountInfo,
35    /// The whitelist entry account to be created/initialized or updated
36    pub whitelist_entry_account: &'a AccountInfo,
37    /// Payer account (must be a system account)
38    pub payer: &'a AccountInfo,
39    /// System program
40    pub system_program: &'a AccountInfo,
41    /// program authority public key
42    pub program_authority: Pubkey,
43}
44
45impl<'a> AddEntry<'a> {
46    #[inline(always)]
47    pub fn invoke(&self) -> ProgramResult {
48        self.invoke_signed(&[])
49    }
50
51    /// Creates the instruction data for the AddEntry instruction
52    fn create_instruction_data(program_authority: &Pubkey) -> [MaybeUninit<u8>; 33] {
53        let mut instruction_data = [UNINIT_BYTE; 33];
54
55        // Set discriminator as u8 at offset [0]
56        write_bytes(&mut instruction_data, &[4]);
57        // Set program_authority as Pubkey at offset [1..33]
58        write_bytes(&mut instruction_data[1..33], program_authority.as_ref());
59
60        instruction_data
61    }
62
63    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
64        // account metadata
65        let account_metas: [AccountMeta; 5] = [
66            AccountMeta::readonly(self.whitelist_account.key()),
67            AccountMeta::readonly_signer(self.whitelist_authority.key()),
68            AccountMeta::writable(self.whitelist_entry_account.key()),
69            AccountMeta::writable_signer(self.payer.key()),
70            AccountMeta::readonly(self.system_program.key()),
71        ];
72
73        // Create instruction data
74        let instruction_data = Self::create_instruction_data(&self.program_authority);
75
76        let instruction = Instruction {
77            program_id: &ID,
78            accounts: &account_metas,
79            data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 33) },
80        };
81
82        invoke_signed(
83            &instruction,
84            &[
85                self.whitelist_account,
86                self.whitelist_authority,
87                self.whitelist_entry_account,
88                self.payer,
89                self.system_program,
90            ],
91            signers,
92        )
93    }
94}
95
96/// Convenience helper for the `AddEntry` instruction
97pub fn add_entry(
98    whitelist_account: &AccountInfo,
99    whitelist_authority: &AccountInfo,
100    whitelist_entry_account: &AccountInfo,
101    payer: &AccountInfo,
102    system_program: &AccountInfo,
103    program_authority: Pubkey,
104) -> ProgramResult {
105    let ix = AddEntry {
106        whitelist_account,
107        whitelist_authority,
108        whitelist_entry_account,
109        payer,
110        system_program,
111        program_authority,
112    };
113    ix.invoke()
114}
115
116/// Convenience helper for the `AddEntry` instruction with the given
117/// signers.
118pub fn add_entry_with_seed(
119    whitelist_account: &AccountInfo,
120    whitelist_authority: &AccountInfo,
121    whitelist_entry_account: &AccountInfo,
122    payer: &AccountInfo,
123    system_program: &AccountInfo,
124    program_authority: Pubkey,
125    signer_seeds: &[Signer],
126) -> ProgramResult {
127    let ix = AddEntry {
128        whitelist_account,
129        whitelist_authority,
130        whitelist_entry_account,
131        payer,
132        system_program,
133        program_authority,
134    };
135    ix.invoke_signed(signer_seeds)
136}
137
138#[cfg(test)]
139mod tests {
140    use {super::*, crate::instructions::ProgramWhitelistInstruction};
141
142    #[test]
143    fn test_instruction_data_creation() {
144        // Create a dummy pubkey for program authority
145        let program_authority_bytes = [42u8; 32]; // Use a fixed value for testing
146        let program_authority = Pubkey::from(program_authority_bytes);
147
148        // Create instruction data using our function
149        let instruction_data = AddEntry::create_instruction_data(&program_authority);
150
151        // Create an instruction with this data for parsing
152        let instruction = Instruction {
153            program_id: &ID,
154            accounts: &[], // Accounts not relevant for this test
155            data: unsafe { from_raw_parts(instruction_data.as_ptr() as _, 33) },
156        };
157
158        // Parse the instruction data
159        let parsed_ix = ProgramWhitelistInstruction::unpack(instruction.data).unwrap();
160
161        // Verify that the parsed instruction matches what we expect
162        match parsed_ix {
163            ProgramWhitelistInstruction::AddEntry {
164                program_authority: parsed_program_authority,
165            } => {
166                assert_eq!(parsed_program_authority, program_authority);
167            }
168            _ => panic!("Parsed incorrect instruction type"),
169        }
170    }
171}