1use crate::{
6 instruction::{AccountMeta, Instruction},
7 loader_v4_instruction::LoaderV4Instruction,
8 pubkey::Pubkey,
9 system_instruction,
10};
11
12crate::declare_id!("LoaderV411111111111111111111111111111111111");
13
14pub const DEPLOYMENT_COOLDOWN_IN_SLOTS: u64 = 750;
16
17#[repr(u64)]
18#[derive(Debug, PartialEq, Eq, Clone, Copy, AbiExample)]
19pub enum LoaderV4Status {
20 Retracted,
22 Deployed,
24 Finalized,
26}
27
28#[repr(C)]
30#[derive(Debug, PartialEq, Eq, Clone, Copy, AbiExample)]
31pub struct LoaderV4State {
32 pub slot: u64,
34 pub authority_address: Pubkey,
36 pub status: LoaderV4Status,
38 }
41
42impl LoaderV4State {
43 pub const fn program_data_offset() -> usize {
45 std::mem::size_of::<Self>()
46 }
47}
48
49pub fn is_write_instruction(instruction_data: &[u8]) -> bool {
50 !instruction_data.is_empty() && 0 == instruction_data[0]
51}
52
53pub fn is_truncate_instruction(instruction_data: &[u8]) -> bool {
54 !instruction_data.is_empty() && 1 == instruction_data[0]
55}
56
57pub fn is_deploy_instruction(instruction_data: &[u8]) -> bool {
58 !instruction_data.is_empty() && 2 == instruction_data[0]
59}
60
61pub fn is_retract_instruction(instruction_data: &[u8]) -> bool {
62 !instruction_data.is_empty() && 3 == instruction_data[0]
63}
64
65pub fn is_transfer_authority_instruction(instruction_data: &[u8]) -> bool {
66 !instruction_data.is_empty() && 4 == instruction_data[0]
67}
68
69pub fn create_buffer(
71 payer_address: &Pubkey,
72 buffer_address: &Pubkey,
73 lamports: u64,
74 authority: &Pubkey,
75 new_size: u32,
76 recipient_address: &Pubkey,
77) -> Vec<Instruction> {
78 vec![
79 system_instruction::create_account(payer_address, buffer_address, lamports, 0, &id()),
80 truncate_uninitialized(buffer_address, authority, new_size, recipient_address),
81 ]
82}
83
84pub fn truncate_uninitialized(
87 program_address: &Pubkey,
88 authority: &Pubkey,
89 new_size: u32,
90 recipient_address: &Pubkey,
91) -> Instruction {
92 Instruction::new_with_bincode(
93 id(),
94 &LoaderV4Instruction::Truncate { new_size },
95 vec![
96 AccountMeta::new(*program_address, true),
97 AccountMeta::new_readonly(*authority, true),
98 AccountMeta::new(*recipient_address, false),
99 ],
100 )
101}
102
103pub fn truncate(
105 program_address: &Pubkey,
106 authority: &Pubkey,
107 new_size: u32,
108 recipient_address: &Pubkey,
109) -> Instruction {
110 Instruction::new_with_bincode(
111 id(),
112 &LoaderV4Instruction::Truncate { new_size },
113 vec![
114 AccountMeta::new(*program_address, false),
115 AccountMeta::new_readonly(*authority, true),
116 AccountMeta::new(*recipient_address, false),
117 ],
118 )
119}
120
121pub fn write(
124 program_address: &Pubkey,
125 authority: &Pubkey,
126 offset: u32,
127 bytes: Vec<u8>,
128) -> Instruction {
129 Instruction::new_with_bincode(
130 id(),
131 &LoaderV4Instruction::Write { offset, bytes },
132 vec![
133 AccountMeta::new(*program_address, false),
134 AccountMeta::new_readonly(*authority, true),
135 ],
136 )
137}
138
139pub fn deploy(program_address: &Pubkey, authority: &Pubkey) -> Instruction {
141 Instruction::new_with_bincode(
142 id(),
143 &LoaderV4Instruction::Deploy,
144 vec![
145 AccountMeta::new(*program_address, false),
146 AccountMeta::new_readonly(*authority, true),
147 ],
148 )
149}
150
151pub fn deploy_from_source(
153 program_address: &Pubkey,
154 authority: &Pubkey,
155 source_address: &Pubkey,
156) -> Instruction {
157 Instruction::new_with_bincode(
158 id(),
159 &LoaderV4Instruction::Deploy,
160 vec![
161 AccountMeta::new(*program_address, false),
162 AccountMeta::new_readonly(*authority, true),
163 AccountMeta::new(*source_address, false),
164 ],
165 )
166}
167
168pub fn retract(program_address: &Pubkey, authority: &Pubkey) -> Instruction {
170 Instruction::new_with_bincode(
171 id(),
172 &LoaderV4Instruction::Retract,
173 vec![
174 AccountMeta::new(*program_address, false),
175 AccountMeta::new_readonly(*authority, true),
176 ],
177 )
178}
179
180pub fn transfer_authority(
182 program_address: &Pubkey,
183 authority: &Pubkey,
184 new_authority: Option<&Pubkey>,
185) -> Instruction {
186 let mut accounts = vec![
187 AccountMeta::new(*program_address, false),
188 AccountMeta::new_readonly(*authority, true),
189 ];
190
191 if let Some(new_auth) = new_authority {
192 accounts.push(AccountMeta::new_readonly(*new_auth, true));
193 }
194
195 Instruction::new_with_bincode(id(), &LoaderV4Instruction::TransferAuthority, accounts)
196}
197
198#[cfg(test)]
199mod tests {
200 use {super::*, crate::system_program, memoffset::offset_of};
201
202 #[test]
203 fn test_layout() {
204 assert_eq!(offset_of!(LoaderV4State, slot), 0x00);
205 assert_eq!(offset_of!(LoaderV4State, authority_address), 0x08);
206 assert_eq!(offset_of!(LoaderV4State, status), 0x28);
207 assert_eq!(LoaderV4State::program_data_offset(), 0x30);
208 }
209
210 #[test]
211 fn test_create_buffer_instruction() {
212 let payer = Pubkey::new_unique();
213 let program = Pubkey::new_unique();
214 let authority = Pubkey::new_unique();
215 let recipient = Pubkey::new_unique();
216 let instructions = create_buffer(&payer, &program, 123, &authority, 10, &recipient);
217 assert_eq!(instructions.len(), 2);
218 let instruction0 = &instructions[0];
219 assert_eq!(instruction0.program_id, system_program::id());
220 assert_eq!(instruction0.accounts.len(), 2);
221 assert_eq!(instruction0.accounts[0].pubkey, payer);
222 assert!(instruction0.accounts[0].is_writable);
223 assert!(instruction0.accounts[0].is_signer);
224 assert_eq!(instruction0.accounts[1].pubkey, program);
225 assert!(instruction0.accounts[1].is_writable);
226 assert!(instruction0.accounts[1].is_signer);
227
228 let instruction1 = &instructions[1];
229 assert!(is_truncate_instruction(&instruction1.data));
230 assert_eq!(instruction1.program_id, id());
231 assert_eq!(instruction1.accounts.len(), 3);
232 assert_eq!(instruction1.accounts[0].pubkey, program);
233 assert!(instruction1.accounts[0].is_writable);
234 assert!(instruction1.accounts[0].is_signer);
235 assert_eq!(instruction1.accounts[1].pubkey, authority);
236 assert!(!instruction1.accounts[1].is_writable);
237 assert!(instruction1.accounts[1].is_signer);
238 assert_eq!(instruction1.accounts[2].pubkey, recipient);
239 assert!(instruction1.accounts[2].is_writable);
240 assert!(!instruction1.accounts[2].is_signer);
241 }
242
243 #[test]
244 fn test_write_instruction() {
245 let program = Pubkey::new_unique();
246 let authority = Pubkey::new_unique();
247 let instruction = write(&program, &authority, 123, vec![1, 2, 3, 4]);
248 assert!(is_write_instruction(&instruction.data));
249 assert_eq!(instruction.program_id, id());
250 assert_eq!(instruction.accounts.len(), 2);
251 assert_eq!(instruction.accounts[0].pubkey, program);
252 assert!(instruction.accounts[0].is_writable);
253 assert!(!instruction.accounts[0].is_signer);
254 assert_eq!(instruction.accounts[1].pubkey, authority);
255 assert!(!instruction.accounts[1].is_writable);
256 assert!(instruction.accounts[1].is_signer);
257 }
258
259 #[test]
260 fn test_truncate_instruction() {
261 let program = Pubkey::new_unique();
262 let authority = Pubkey::new_unique();
263 let recipient = Pubkey::new_unique();
264 let instruction = truncate(&program, &authority, 10, &recipient);
265 assert!(is_truncate_instruction(&instruction.data));
266 assert_eq!(instruction.program_id, id());
267 assert_eq!(instruction.accounts.len(), 3);
268 assert_eq!(instruction.accounts[0].pubkey, program);
269 assert!(instruction.accounts[0].is_writable);
270 assert!(!instruction.accounts[0].is_signer);
271 assert_eq!(instruction.accounts[1].pubkey, authority);
272 assert!(!instruction.accounts[1].is_writable);
273 assert!(instruction.accounts[1].is_signer);
274 assert_eq!(instruction.accounts[2].pubkey, recipient);
275 assert!(instruction.accounts[2].is_writable);
276 assert!(!instruction.accounts[2].is_signer);
277 }
278
279 #[test]
280 fn test_deploy_instruction() {
281 let program = Pubkey::new_unique();
282 let authority = Pubkey::new_unique();
283 let instruction = deploy(&program, &authority);
284 assert!(is_deploy_instruction(&instruction.data));
285 assert_eq!(instruction.program_id, id());
286 assert_eq!(instruction.accounts.len(), 2);
287 assert_eq!(instruction.accounts[0].pubkey, program);
288 assert!(instruction.accounts[0].is_writable);
289 assert!(!instruction.accounts[0].is_signer);
290 assert_eq!(instruction.accounts[1].pubkey, authority);
291 assert!(!instruction.accounts[1].is_writable);
292 assert!(instruction.accounts[1].is_signer);
293 }
294
295 #[test]
296 fn test_deploy_from_source_instruction() {
297 let program = Pubkey::new_unique();
298 let authority = Pubkey::new_unique();
299 let source = Pubkey::new_unique();
300 let instruction = deploy_from_source(&program, &authority, &source);
301 assert!(is_deploy_instruction(&instruction.data));
302 assert_eq!(instruction.program_id, id());
303 assert_eq!(instruction.accounts.len(), 3);
304 assert_eq!(instruction.accounts[0].pubkey, program);
305 assert!(instruction.accounts[0].is_writable);
306 assert!(!instruction.accounts[0].is_signer);
307 assert_eq!(instruction.accounts[1].pubkey, authority);
308 assert!(!instruction.accounts[1].is_writable);
309 assert!(instruction.accounts[1].is_signer);
310 assert_eq!(instruction.accounts[2].pubkey, source);
311 assert!(instruction.accounts[2].is_writable);
312 assert!(!instruction.accounts[2].is_signer);
313 }
314
315 #[test]
316 fn test_retract_instruction() {
317 let program = Pubkey::new_unique();
318 let authority = Pubkey::new_unique();
319 let instruction = retract(&program, &authority);
320 assert!(is_retract_instruction(&instruction.data));
321 assert_eq!(instruction.program_id, id());
322 assert_eq!(instruction.accounts.len(), 2);
323 assert_eq!(instruction.accounts[0].pubkey, program);
324 assert!(instruction.accounts[0].is_writable);
325 assert!(!instruction.accounts[0].is_signer);
326 assert_eq!(instruction.accounts[1].pubkey, authority);
327 assert!(!instruction.accounts[1].is_writable);
328 assert!(instruction.accounts[1].is_signer);
329 }
330
331 #[test]
332 fn test_transfer_authority_instruction() {
333 let program = Pubkey::new_unique();
334 let authority = Pubkey::new_unique();
335 let new_authority = Pubkey::new_unique();
336 let instruction = transfer_authority(&program, &authority, Some(&new_authority));
337 assert!(is_transfer_authority_instruction(&instruction.data));
338 assert_eq!(instruction.program_id, id());
339 assert_eq!(instruction.accounts.len(), 3);
340 assert_eq!(instruction.accounts[0].pubkey, program);
341 assert!(instruction.accounts[0].is_writable);
342 assert!(!instruction.accounts[0].is_signer);
343 assert_eq!(instruction.accounts[1].pubkey, authority);
344 assert!(!instruction.accounts[1].is_writable);
345 assert!(instruction.accounts[1].is_signer);
346 assert_eq!(instruction.accounts[2].pubkey, new_authority);
347 assert!(!instruction.accounts[2].is_writable);
348 assert!(instruction.accounts[2].is_signer);
349 }
350
351 #[test]
352 fn test_transfer_authority_finalize_instruction() {
353 let program = Pubkey::new_unique();
354 let authority = Pubkey::new_unique();
355 let instruction = transfer_authority(&program, &authority, None);
356 assert!(is_transfer_authority_instruction(&instruction.data));
357 assert_eq!(instruction.program_id, id());
358 assert_eq!(instruction.accounts.len(), 2);
359 assert_eq!(instruction.accounts[0].pubkey, program);
360 assert!(instruction.accounts[0].is_writable);
361 assert!(!instruction.accounts[0].is_signer);
362 assert_eq!(instruction.accounts[1].pubkey, authority);
363 assert!(!instruction.accounts[1].is_writable);
364 assert!(instruction.accounts[1].is_signer);
365 }
366}