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