1use crate::{borsh_size::BorshSize, WrappedPod};
2use borsh::{BorshDeserialize, BorshSerialize};
3use bytemuck::{bytes_of, NoUninit};
4use solana_program::{
5 instruction::{AccountMeta, Instruction},
6 pubkey::Pubkey,
7};
8
9pub trait InstructionsAccount {
10 fn get_accounts_vec(&self) -> Vec<AccountMeta>;
11
12 fn get_instruction<P: BorshDeserialize + BorshSerialize + BorshSize>(
13 &self,
14 program_id: Pubkey,
15 instruction_id: u8,
16 params: P,
17 ) -> Instruction {
18 let cap = 1 + params.borsh_len();
19 let mut data = Vec::with_capacity(cap);
20 #[allow(clippy::uninit_vec)]
21 unsafe {
22 data.set_len(cap);
23 }
24 data[0] = instruction_id;
25 let mut data_pointer = &mut data[1..];
26 params.serialize(&mut data_pointer).unwrap();
27 if !data_pointer.is_empty() {
29 panic!()
30 }
31
32 let accounts_vec = self.get_accounts_vec();
33 Instruction {
34 program_id,
35 accounts: accounts_vec,
36 data,
37 }
38 }
39 fn get_instruction_cast<P: NoUninit>(
40 &self,
41 program_id: Pubkey,
42 instruction_id: u8,
43 params: P,
44 ) -> Instruction {
45 let cap = 8 + std::mem::size_of::<P>();
46 let mut data = Vec::with_capacity(cap);
47 data.push(instruction_id);
48 data.extend([0; 7].iter());
49 data.extend(bytes_of(¶ms));
50
51 Instruction {
52 program_id,
53 accounts: self.get_accounts_vec(),
54 data,
55 }
56 }
57 fn get_instruction_wrapped_pod<'a, P: WrappedPod<'a>>(
58 &self,
59 program_id: Pubkey,
60 instruction_id: u8,
61 params: P,
62 ) -> Instruction {
63 let cap = 8 + params.size();
64 let mut data = Vec::with_capacity(cap);
65 data.push(instruction_id);
66 data.extend([0; 7].iter());
67 params.export(&mut data);
68
69 Instruction {
70 program_id,
71 accounts: self.get_accounts_vec(),
72 data,
73 }
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::InstructionsAccount;
80 use crate::borsh_size::BorshSize;
81 use bonfida_macros::{BorshSize, InstructionsAccount};
82 use borsh::{BorshDeserialize, BorshSerialize};
83 use solana_program::pubkey::Pubkey;
84
85 mod accounts {
89 use super::*;
90 #[derive(InstructionsAccount, Clone)]
91 pub struct Accounts<'a, T> {
92 #[cons(writable)]
93 pub a: &'a T,
94 pub b: &'a T,
95 #[cons(writable)]
96 pub c: &'a [T],
97 pub d: &'a [T],
98 #[cons(writable, signer)]
99 pub e: &'a T,
100 #[cons(signer)]
101 pub f: &'a T,
102 #[cons(writable, signer)]
103 pub g: &'a [T],
104 #[cons(signer)]
105 pub h: &'a [T],
106 #[cons(signer)]
107 pub i: Option<&'a T>,
108 }
109 }
110 #[derive(BorshDeserialize, BorshSerialize, BorshSize, Clone, Copy)]
111 #[repr(C)]
113 pub struct Params {
114 pub match_limit: u64,
115 }
116
117 mod accounts_with_vec {
118 use super::*;
119 #[derive(InstructionsAccount, Clone)]
120 pub struct Accounts<'a, T> {
121 #[cons(writable)]
122 pub a: &'a T,
123 pub b: &'a T,
124 #[cons(writable)]
125 pub c: &'a [T],
126 pub d: &'a [T],
127 #[cons(writable, signer)]
128 pub e: &'a T,
129 #[cons(signer)]
130 pub f: &'a T,
131 #[cons(writable, signer)]
132 pub g: &'a [T],
133 #[cons(signer)]
134 pub h: &'a [T],
135 #[cons(signer)]
136 pub i: Vec<&'a T>,
137 }
138 }
139
140 #[test]
141 #[allow(clippy::bool_assert_comparison)]
142 fn functional_0() {
143 let i = Pubkey::new_unique();
144 let a = accounts::Accounts {
145 a: &Pubkey::new_unique(),
146 b: &Pubkey::new_unique(),
147 c: &[Pubkey::new_unique()],
148 d: &[Pubkey::new_unique()],
149 e: &Pubkey::new_unique(),
150 f: &Pubkey::new_unique(),
151 g: &[Pubkey::new_unique()],
152 h: &[Pubkey::new_unique()],
153 i: Some(&i),
154 };
155 let params = Params { match_limit: 46 };
156 let instruction = a.get_instruction(crate::ID, 0, params);
157 assert_eq!(instruction.accounts[0].is_writable, true);
158 assert_eq!(instruction.accounts[0].is_signer, false);
159 assert_eq!(instruction.accounts[0].pubkey, *a.a);
160 assert_eq!(instruction.accounts[1].is_writable, false);
161 assert_eq!(instruction.accounts[1].is_signer, false);
162 assert_eq!(instruction.accounts[1].pubkey, *a.b);
163 assert_eq!(instruction.accounts[2].is_writable, true);
164 assert_eq!(instruction.accounts[2].is_signer, false);
165 assert_eq!(instruction.accounts[2].pubkey, a.c[0]);
166 assert_eq!(instruction.accounts[3].is_writable, false);
167 assert_eq!(instruction.accounts[3].is_signer, false);
168 assert_eq!(instruction.accounts[3].pubkey, a.d[0]);
169
170 assert_eq!(instruction.accounts[4].is_writable, true);
171 assert_eq!(instruction.accounts[4].is_signer, true);
172 assert_eq!(instruction.accounts[4].pubkey, *a.e);
173 assert_eq!(instruction.accounts[5].is_writable, false);
174 assert_eq!(instruction.accounts[5].is_signer, true);
175 assert_eq!(instruction.accounts[5].pubkey, *a.f);
176 assert_eq!(instruction.accounts[6].is_writable, true);
177 assert_eq!(instruction.accounts[6].is_signer, true);
178 assert_eq!(instruction.accounts[6].pubkey, a.g[0]);
179 assert_eq!(instruction.accounts[7].is_writable, false);
180 assert_eq!(instruction.accounts[7].is_signer, true);
181 assert_eq!(instruction.accounts[7].pubkey, a.h[0]);
182 assert_eq!(instruction.accounts[8].is_writable, false);
183 assert_eq!(instruction.accounts[8].is_signer, true);
184 assert_eq!(instruction.accounts[8].pubkey, *a.i.unwrap());
185 let mut instruction_data = vec![0];
186 instruction_data.extend(¶ms.try_to_vec().unwrap());
187
188 assert_eq!(instruction_data, instruction.data);
189
190 }
199
200 #[test]
201 #[allow(clippy::bool_assert_comparison)]
202 fn functional_1() {
203 let i = (0..4).map(|_| Pubkey::new_unique()).collect::<Vec<_>>();
204 let a = accounts_with_vec::Accounts {
205 a: &Pubkey::new_unique(),
206 b: &Pubkey::new_unique(),
207 c: &[Pubkey::new_unique()],
208 d: &[Pubkey::new_unique()],
209 e: &Pubkey::new_unique(),
210 f: &Pubkey::new_unique(),
211 g: &[Pubkey::new_unique()],
212 h: &[Pubkey::new_unique()],
213 i: vec![&i[0], &i[1], &i[2], &i[3]],
214 };
215 let params = Params { match_limit: 46 };
216 let instruction = a.get_instruction(crate::ID, 0, params);
217 assert_eq!(instruction.accounts[0].is_writable, true);
218 assert_eq!(instruction.accounts[0].is_signer, false);
219 assert_eq!(instruction.accounts[0].pubkey, *a.a);
220 assert_eq!(instruction.accounts[1].is_writable, false);
221 assert_eq!(instruction.accounts[1].is_signer, false);
222 assert_eq!(instruction.accounts[1].pubkey, *a.b);
223 assert_eq!(instruction.accounts[2].is_writable, true);
224 assert_eq!(instruction.accounts[2].is_signer, false);
225 assert_eq!(instruction.accounts[2].pubkey, a.c[0]);
226 assert_eq!(instruction.accounts[3].is_writable, false);
227 assert_eq!(instruction.accounts[3].is_signer, false);
228 assert_eq!(instruction.accounts[3].pubkey, a.d[0]);
229
230 assert_eq!(instruction.accounts[4].is_writable, true);
231 assert_eq!(instruction.accounts[4].is_signer, true);
232 assert_eq!(instruction.accounts[4].pubkey, *a.e);
233 assert_eq!(instruction.accounts[5].is_writable, false);
234 assert_eq!(instruction.accounts[5].is_signer, true);
235 assert_eq!(instruction.accounts[5].pubkey, *a.f);
236 assert_eq!(instruction.accounts[6].is_writable, true);
237 assert_eq!(instruction.accounts[6].is_signer, true);
238 assert_eq!(instruction.accounts[6].pubkey, a.g[0]);
239 assert_eq!(instruction.accounts[7].is_writable, false);
240 assert_eq!(instruction.accounts[7].is_signer, true);
241 assert_eq!(instruction.accounts[7].pubkey, a.h[0]);
242 assert_eq!(instruction.accounts[8].is_writable, false);
243 assert_eq!(instruction.accounts[8].is_signer, true);
244 assert_eq!(instruction.accounts[8].pubkey, *a.i[0]);
245 assert_eq!(instruction.accounts[9].is_writable, false);
246 assert_eq!(instruction.accounts[9].is_signer, true);
247 assert_eq!(instruction.accounts[9].pubkey, *a.i[1]);
248 assert_eq!(instruction.accounts[10].is_writable, false);
249 assert_eq!(instruction.accounts[10].is_signer, true);
250 assert_eq!(instruction.accounts[10].pubkey, *a.i[2]);
251 let mut instruction_data = vec![0];
252 instruction_data.extend(¶ms.try_to_vec().unwrap());
253
254 assert_eq!(instruction_data, instruction.data);
255
256 }
265}