bitoku_sdk_agent_native/
processor.rs

1use solana_program::{
2    account_info::{next_account_info, AccountInfo},
3    entrypoint::ProgramResult,
4    msg,
5    program::invoke_signed,
6    program_memory::sol_memset,
7    program_pack::Pack,
8    pubkey::Pubkey,
9    system_instruction::create_account,
10    sysvar::{rent::Rent, Sysvar},
11};
12
13use crate::{
14    error::BitokuError::{InvalidName, NoAvailableClients, Overflow, UnregisteredClient},
15    instruction::{BitokuInstructions, Request},
16    state::{addel, delel, isel, validate_name, BookKeeper, RequestData},
17};
18
19pub struct Processor;
20
21impl Processor {
22    pub fn process(
23        program_id: &Pubkey,
24        accounts: &[AccountInfo],
25        instruction_data: &[u8],
26    ) -> ProgramResult {
27        let instruction = BitokuInstructions::unpack(instruction_data)?;
28        msg!("{:?}", instruction);
29
30        match instruction {
31            BitokuInstructions::InitBitoku => {
32                msg!("Instruction : InitBitoku");
33                Self::process_init_bitoku(accounts, program_id)
34            }
35            BitokuInstructions::RegisterClient => {
36                msg!("Instruction : RegisterClient");
37                self::Processor::process_register_client(accounts, program_id)
38            }
39
40            BitokuInstructions::RemoveClient { client_id } => {
41                msg!("Instruction : RemoveClient");
42                self::Processor::process_remove_client(accounts, program_id, client_id)
43            }
44
45            BitokuInstructions::SendRequest { request } => {
46                msg!("Instruction : SendRequest");
47                self::Processor::process_send_request(accounts, program_id, request)
48            }
49        }
50    }
51
52    fn process_init_bitoku(accounts: &[AccountInfo], program_id: &Pubkey) -> ProgramResult {
53        let account_iter = &mut accounts.iter();
54
55        let fee_payer = next_account_info(account_iter)?;
56        let bookkeeper = next_account_info(account_iter)?;
57        let system_program = next_account_info(account_iter)?;
58        let rent_sysvar_account = next_account_info(account_iter)?;
59
60        let rent = Rent::from_account_info(rent_sysvar_account)?;
61
62        let (bookkeeper_key, _bump) =
63            Pubkey::find_program_address(&["bookkeeper".as_ref()], program_id);
64
65        let init_bookkeeper = create_account(
66            &fee_payer.key,
67            &bookkeeper_key,
68            rent.minimum_balance(33),
69            33,
70            &program_id,
71        );
72
73        invoke_signed(
74            &init_bookkeeper,
75            &[
76                system_program.clone(),
77                fee_payer.clone(),
78                bookkeeper.clone(),
79            ],
80            &[&["bookkeeper".as_ref(), &[_bump]]],
81        )?;
82
83        Ok(())
84    }
85
86    fn process_register_client(accounts: &[AccountInfo], program_id: &Pubkey) -> ProgramResult {
87        let accounts_iter = &mut accounts.iter();
88
89        let fee_payer = next_account_info(accounts_iter)?;
90        let bookkeeper = next_account_info(accounts_iter)?;
91        let request = next_account_info(accounts_iter)?;
92        let system_program = next_account_info(accounts_iter)?;
93        let rent_sys_var = next_account_info(accounts_iter)?;
94
95        let rent = Rent::from_account_info(rent_sys_var)?;
96
97        let (request_key, bump) =
98            Pubkey::find_program_address(&["request".as_ref(), fee_payer.key.as_ref()], program_id);
99
100        let init_request = create_account(
101            &fee_payer.key,
102            &request_key,
103            rent.minimum_balance(163),
104            163,
105            &program_id,
106        );
107
108        invoke_signed(
109            &init_request,
110            &[system_program.clone(), fee_payer.clone(), request.clone()],
111            &[&["request".as_ref(), fee_payer.key.as_ref(), &[bump]]],
112        )?;
113
114        let mut bookkeeper_data = BookKeeper::unpack_unchecked(&bookkeeper.try_borrow_data()?)?;
115        let my_id = bookkeeper_data.next_id;
116
117        addel(&mut bookkeeper_data.status, my_id);
118
119        let mut request_data = RequestData::unpack_unchecked(&request.try_borrow_data()?)?;
120
121        request_data.client_id = my_id;
122        if bookkeeper_data.next_id == 255 {
123            return Err(NoAvailableClients.into());
124        }
125
126        bookkeeper_data.next_id += 1;
127        BookKeeper::pack(bookkeeper_data, &mut bookkeeper.try_borrow_mut_data()?)?;
128        RequestData::pack(request_data, &mut request.try_borrow_mut_data()?)?;
129
130        Ok(())
131    }
132
133    fn process_remove_client(
134        accounts: &[AccountInfo],
135        _program_id: &Pubkey,
136        client_id: u8,
137    ) -> ProgramResult {
138        let accounts_iter = &mut accounts.iter();
139        let fee_payer = next_account_info(accounts_iter)?;
140        let bookkeeper = next_account_info(accounts_iter)?;
141        let request = next_account_info(accounts_iter)?;
142
143        let mut bookkeeper_data = BookKeeper::unpack_unchecked(&bookkeeper.try_borrow_data()?)?;
144
145        let bool = isel(bookkeeper_data.status, client_id);
146        if !bool {
147            return Err(UnregisteredClient.into());
148        }
149
150        delel(&mut bookkeeper_data.status, client_id);
151
152        BookKeeper::pack(bookkeeper_data, &mut bookkeeper.try_borrow_mut_data()?)?;
153
154        //closing the request PDA account
155        let current_lamps = request.lamports();
156        let account_data_size = request.data_len();
157
158        //Transferring lamports to the fee_payer account
159        **request.lamports.borrow_mut() = 0;
160        **fee_payer.lamports.borrow_mut() = fee_payer
161            .lamports()
162            .checked_add(current_lamps)
163            .ok_or(Overflow)?;
164
165        //zeroing the stored data in the account
166        sol_memset(&mut *request.try_borrow_mut_data()?, 0, account_data_size);
167
168        Ok(())
169    }
170
171    fn process_send_request(
172        accounts: &[AccountInfo],
173        _program_id: &Pubkey,
174        request: Request,
175    ) -> ProgramResult {
176        let accounts_iter = &mut accounts.iter();
177
178        let fee_payer = next_account_info(accounts_iter)?;
179        let req = next_account_info(accounts_iter)?;
180
181        let mut request_data = RequestData::unpack_unchecked(&req.try_borrow_data()?)?;
182
183        //Validating the name of the request
184
185        let s = request.name();
186        let name = String::from_utf8(s.to_vec()).unwrap();
187        if validate_name(&name.as_bytes()) == false {
188            return Err(InvalidName.into());
189        }
190
191        request_data.requester = *fee_payer.key;
192        request_data.request = request;
193
194        RequestData::pack(request_data, &mut req.try_borrow_mut_data()?)?;
195
196        Ok(())
197    }
198}