1use crate::{
2 StateProof,
3 tn_public_address::tn_pubkey_to_address_string,
4 txn_lib::{TnPubkey, Transaction},
5};
6use anyhow::Result;
7use hex;
8use std::collections::HashMap;
9
10pub const NOOP_PROGRAM: [u8; 32] = {
12 let mut arr = [0u8; 32];
13 arr[31] = 0x03;
14 arr
15};
16pub const SYSTEM_PROGRAM: [u8; 32] = {
17 let mut arr = [0u8; 32];
18 arr[31] = 0x01;
19 arr
20};
21pub const EOA_PROGRAM: [u8; 32] = {
22 let arr = [0u8; 32];
23 arr
24};
25
26pub const UPLOADER_PROGRAM: [u8; 32] = {
27 let mut arr = [0u8; 32];
28 arr[31] = 0x02;
29 arr
30};
31pub const FAUCET_PROGRAM: [u8; 32] = {
32 let mut arr = [0u8; 32];
33 arr[31] = 0xFA;
34 arr
35};
36
37pub const CONSENSUS_VALIDATOR_PROGRAM: [u8; 32] = {
39 let mut arr = [0u8; 32];
40 arr[30] = 0x0C;
41 arr[31] = 0x01;
42 arr
43};
44
45pub const TOKEN_PROGRAM: [u8; 32] = {
47 let mut arr = [0u8; 32];
48 arr[31] = 0xAA;
49 arr
50};
51
52pub const ATTESTOR_TABLE: [u8; 32] = {
54 let mut arr = [0u8; 32];
55 arr[30] = 0x0C;
56 arr[31] = 0x02;
57 arr
58};
59
60pub const CONVERTED_VAULT: [u8; 32] = {
62 let mut arr = [0u8; 32];
63 arr[30] = 0x0C;
64 arr[31] = 0x04;
65 arr
66};
67
68#[derive(Debug, Clone)]
69pub struct TransactionBuilder {
70 }
75
76impl TransactionBuilder {
77 pub fn build_create_with_fee_payer_proof(
79 fee_payer: TnPubkey,
80 start_slot: u64,
81 fee_payer_state_proof: &StateProof,
82 ) -> Result<Transaction> {
83 let tx = Transaction::new(fee_payer, NOOP_PROGRAM, 0, 0)
84 .with_fee_payer_state_proof(fee_payer_state_proof)
85 .with_start_slot(start_slot)
86 .with_expiry_after(100)
87 .with_compute_units(10_000)
88 .with_memory_units(10_000)
89 .with_state_units(10_000);
90 Ok(tx)
91 }
92
93 pub fn build_transfer(
107 fee_payer: TnPubkey,
108 program: TnPubkey,
109 to_account: TnPubkey,
110 amount: u64,
111 fee: u64,
112 nonce: u64,
113 start_slot: u64,
114 ) -> Result<Transaction> {
115 let from_account_idx = 0u16; let to_account_idx = 2u16; let instruction_data =
120 build_transfer_instruction(from_account_idx, to_account_idx, amount)?;
121
122 let tx = Transaction::new(fee_payer, program, fee, nonce)
123 .with_start_slot(start_slot)
124 .add_rw_account(to_account) .with_instructions(instruction_data)
126 .with_expiry_after(100)
127 .with_compute_units(10000)
128 .with_memory_units(10000)
129 .with_state_units(10000);
130
131 Ok(tx)
132 }
133
134 pub fn build_create_account(
136 fee_payer: TnPubkey,
137 program: TnPubkey,
138 target_account: TnPubkey,
139 seed: &str,
140 state_proof: Option<&[u8]>,
141 fee: u64,
142 nonce: u64,
143 start_slot: u64,
144 ) -> Result<Transaction> {
145 let target_account_idx = 2u16; let instruction_data =
148 build_create_account_instruction(target_account_idx, seed, state_proof)?;
149
150 let tx = Transaction::new(fee_payer, program, fee, nonce)
151 .with_start_slot(start_slot)
152 .add_rw_account(target_account)
153 .with_instructions(instruction_data)
154 .with_expiry_after(100)
155 .with_compute_units(10_000)
156 .with_memory_units(10_000)
157 .with_state_units(10_000);
158
159 Ok(tx)
160 }
161
162 pub fn build_create_ephemeral_account(
164 fee_payer: TnPubkey,
165 program: TnPubkey,
166 target_account: TnPubkey,
167 seed: &[u8; 32],
168 fee: u64,
169 nonce: u64,
170 start_slot: u64,
171 ) -> Result<Transaction> {
172 let target_account_idx = 2u16; let instruction_data = build_ephemeral_account_instruction(target_account_idx, seed)?;
175
176 let tx = Transaction::new(fee_payer, program, fee, nonce)
177 .with_start_slot(start_slot)
178 .add_rw_account(target_account)
179 .with_instructions(instruction_data)
180 .with_expiry_after(100)
181 .with_compute_units(50_000)
182 .with_memory_units(10_000)
183 .with_state_units(10_000);
184 Ok(tx)
185 }
186
187 pub fn build_resize_account(
189 fee_payer: TnPubkey,
190 program: TnPubkey,
191 target_account: TnPubkey,
192 new_size: u64,
193 fee: u64,
194 nonce: u64,
195 start_slot: u64,
196 ) -> Result<Transaction> {
197 let target_account_idx = 2u16; let instruction_data = build_resize_instruction(target_account_idx, new_size)?;
200
201 let tx = Transaction::new(fee_payer, program, fee, nonce)
202 .with_start_slot(start_slot)
203 .with_expiry_after(100)
204 .with_compute_units(100032)
205 .with_state_units(1 + new_size.checked_div(4096).unwrap() as u16)
206 .with_memory_units(10000)
207 .add_rw_account(target_account)
208 .with_instructions(instruction_data)
209 .with_expiry_after(100)
210 .with_compute_units(10_000 + 2 * new_size as u32)
211 .with_memory_units(10_000)
212 .with_state_units(10_000);
213
214 Ok(tx)
215 }
216
217 pub fn build_compress_account(
219 fee_payer: TnPubkey,
220 program: TnPubkey,
221 target_account: TnPubkey,
222 state_proof: &[u8],
223 fee: u64,
224 nonce: u64,
225 start_slot: u64,
226 account_size: u32,
227 ) -> Result<Transaction> {
228 let target_account_idx = 2u16; let instruction_data = build_compress_instruction(target_account_idx, state_proof)?;
231
232 let tx = Transaction::new(fee_payer, program, fee, nonce)
233 .with_start_slot(start_slot)
234 .with_may_compress_account()
235 .add_rw_account(target_account)
236 .with_instructions(instruction_data)
237 .with_expiry_after(100)
238 .with_compute_units(100_300 + account_size * 2)
239 .with_memory_units(10000)
240 .with_state_units(10000);
241
242 Ok(tx)
243 }
244
245 pub fn build_decompress_account(
247 fee_payer: TnPubkey,
248 program: TnPubkey,
249 target_account: TnPubkey,
250 account_data: &[u8],
251 state_proof: &[u8],
252 fee: u64,
253 nonce: u64,
254 start_slot: u64,
255 ) -> Result<Transaction> {
256 let target_account_idx = 2u16; let instruction_data =
259 build_decompress_instruction(target_account_idx, account_data, state_proof)?;
260
261 let tx = Transaction::new(fee_payer, program, fee, nonce)
262 .with_start_slot(start_slot)
263 .add_rw_account(target_account)
264 .with_instructions(instruction_data)
265 .with_compute_units(100_300 + account_data.len() as u32 * 2)
266 .with_state_units(10_000)
267 .with_memory_units(10_000)
268 .with_expiry_after(100);
269 Ok(tx)
270 }
271
272 pub fn build_write_data(
274 fee_payer: TnPubkey,
275 program: TnPubkey,
276 target_account: TnPubkey,
277 offset: u16,
278 data: &[u8],
279 fee: u64,
280 nonce: u64,
281 start_slot: u64,
282 ) -> Result<Transaction> {
283 let target_account_idx = 2u16; let instruction_data = build_write_instruction(target_account_idx, offset, data)?;
286
287 let tx = Transaction::new(fee_payer, program, fee, nonce)
288 .with_start_slot(start_slot)
289 .with_expiry_after(100)
290 .with_compute_units(100045)
291 .with_state_units(10000)
292 .with_memory_units(10000)
293 .add_rw_account(target_account)
294 .with_instructions(instruction_data);
295
296 Ok(tx)
297 }
298}
299
300fn build_transfer_instruction(
309 from_account_idx: u16,
310 to_account_idx: u16,
311 amount: u64,
312) -> Result<Vec<u8>> {
313 let mut instruction = Vec::new();
314
315 instruction.extend_from_slice(&1u32.to_le_bytes());
317
318 instruction.extend_from_slice(&amount.to_le_bytes());
321
322 instruction.extend_from_slice(&from_account_idx.to_le_bytes());
324
325 instruction.extend_from_slice(&to_account_idx.to_le_bytes());
327
328 Ok(instruction)
329}
330
331fn build_create_account_instruction(
333 target_account_idx: u16,
334 seed: &str,
335 state_proof: Option<&[u8]>,
336) -> Result<Vec<u8>> {
337 let mut instruction = Vec::new();
338
339 instruction.push(0x00);
341
342 instruction.extend_from_slice(&target_account_idx.to_le_bytes());
344
345 let seed_bytes =
347 hex::decode(seed).map_err(|e| anyhow::anyhow!("Failed to decode hex seed: {}", e))?;
348
349 instruction.extend_from_slice(&(seed_bytes.len() as u64).to_le_bytes());
351
352 let has_proof = state_proof.is_some();
354 instruction.push(if has_proof { 1u8 } else { 0u8 });
355
356 instruction.extend_from_slice(&seed_bytes);
358
359 if let Some(proof) = state_proof {
361 instruction.extend_from_slice(proof);
362 }
363
364 Ok(instruction)
365}
366
367fn build_ephemeral_account_instruction(
369 target_account_idx: u16,
370 seed: &[u8; 32],
371) -> Result<Vec<u8>> {
372 let mut instruction = Vec::new();
373
374 instruction.push(0x01);
376
377 instruction.extend_from_slice(&target_account_idx.to_le_bytes());
379
380 instruction.extend_from_slice(&(seed.len() as u64).to_le_bytes());
382
383 instruction.extend_from_slice(seed);
385
386 Ok(instruction)
387}
388
389fn build_resize_instruction(target_account_idx: u16, new_size: u64) -> Result<Vec<u8>> {
391 let mut instruction = Vec::new();
392
393 instruction.push(0x04);
395
396 instruction.extend_from_slice(&target_account_idx.to_le_bytes());
398
399 instruction.extend_from_slice(&new_size.to_le_bytes());
401
402 Ok(instruction)
403}
404
405fn build_write_instruction(target_account_idx: u16, offset: u16, data: &[u8]) -> Result<Vec<u8>> {
407 let mut instruction = Vec::new();
408
409 instruction.push(0xC8);
411
412 instruction.extend_from_slice(&target_account_idx.to_le_bytes());
414
415 instruction.extend_from_slice(&offset.to_le_bytes());
417
418 instruction.extend_from_slice(&(data.len() as u16).to_le_bytes());
420
421 instruction.extend_from_slice(data);
423
424 Ok(instruction)
425}
426
427fn build_compress_instruction(target_account_idx: u16, state_proof: &[u8]) -> Result<Vec<u8>> {
429 let mut instruction = Vec::new();
430
431 instruction.push(0x05);
434
435 instruction.extend_from_slice(&target_account_idx.to_le_bytes());
437
438 instruction.extend_from_slice(state_proof);
440
441 Ok(instruction)
442}
443
444fn build_decompress_instruction(
445 target_account_idx: u16,
446 account_data: &[u8],
447 state_proof: &[u8],
448) -> Result<Vec<u8>> {
449 let mut instruction = Vec::new();
450
451 instruction.push(0x06);
453
454 instruction.extend_from_slice(&target_account_idx.to_le_bytes());
456 instruction.extend_from_slice(&(account_data.len() as u64).to_le_bytes());
457
458 instruction.extend_from_slice(account_data);
460
461 instruction.extend_from_slice(state_proof);
463
464 Ok(instruction)
465}
466
467pub fn generate_ephemeral_address(seed: &str) -> Result<String> {
472 let owner_pubkey = [0u8; 32];
474
475 let seed_bytes =
477 hex::decode(seed).map_err(|e| anyhow::anyhow!("Failed to decode hex seed: {}", e))?;
478
479 let mut seed_32 = [0u8; 32];
481 let copy_len = std::cmp::min(seed_bytes.len(), 32);
482 seed_32[..copy_len].copy_from_slice(&seed_bytes[..copy_len]);
483
484 Ok(
486 crate::tn_public_address::create_program_defined_account_address_string(
487 &owner_pubkey,
488 true, &seed_32,
490 ),
491 )
492}
493
494pub fn generate_system_derived_address(seed: &str, is_ephemeral: bool) -> Result<String> {
495 let seed_bytes =
497 hex::decode(seed).map_err(|e| anyhow::anyhow!("Failed to decode hex seed: {}", e))?;
498
499 let pubkey = generate_derived_address(&seed_bytes, &[0u8; 32], is_ephemeral)?;
500
501 Ok(tn_pubkey_to_address_string(&pubkey))
502}
503
504pub fn generate_derived_address(
505 seed: &[u8],
506 owner_pubkey: &[u8; 32],
507 is_ephemeral: bool,
508) -> Result<[u8; 32]> {
509 use sha2::{Digest, Sha256};
510
511 let mut hasher = Sha256::new();
513
514 hasher.update(&owner_pubkey);
516
517 hasher.update(&[is_ephemeral as u8]);
519
520 hasher.update(&seed);
522
523 Ok(hasher.finalize().into())
525}
526
527#[cfg(test)]
528mod tests {
529 use super::*;
530
531 #[test]
532 fn test_ephemeral_address_generation() {
533 let hex_seed1 = hex::encode("test_seed_123");
535 let hex_seed2 = hex::encode("test_seed_123");
536 let hex_seed3 = hex::encode("different_seed");
537
538 let addr1 = generate_ephemeral_address(&hex_seed1).unwrap();
539 let addr2 = generate_ephemeral_address(&hex_seed2).unwrap();
540 let addr3 = generate_ephemeral_address(&hex_seed3).unwrap();
541
542 assert_eq!(addr1, addr2);
544
545 assert_ne!(addr1, addr3);
547
548 assert!(addr1.starts_with("ta"));
550 assert!(addr2.starts_with("ta"));
551 assert!(addr3.starts_with("ta"));
552
553 assert_eq!(addr1.len(), 46);
555 assert_eq!(addr2.len(), 46);
556 assert_eq!(addr3.len(), 46);
557 }
558
559 #[test]
560 fn test_eoa_transfer_instruction_format() {
561 let from_idx = 0u16;
563 let to_idx = 2u16;
564 let amount = 1000u64;
565
566 let instruction = build_transfer_instruction(from_idx, to_idx, amount).unwrap();
567
568 assert_eq!(instruction.len(), 16, "Instruction should be 16 bytes");
576
577 let discriminant = u32::from_le_bytes([
579 instruction[0],
580 instruction[1],
581 instruction[2],
582 instruction[3],
583 ]);
584 assert_eq!(discriminant, 1, "Discriminant should be 1 for TRANSFER");
585
586 let parsed_amount = u64::from_le_bytes([
588 instruction[4],
589 instruction[5],
590 instruction[6],
591 instruction[7],
592 instruction[8],
593 instruction[9],
594 instruction[10],
595 instruction[11],
596 ]);
597 assert_eq!(parsed_amount, amount, "Amount should match input");
598
599 let parsed_from = u16::from_le_bytes([instruction[12], instruction[13]]);
601 assert_eq!(parsed_from, from_idx, "From index should match input");
602
603 let parsed_to = u16::from_le_bytes([instruction[14], instruction[15]]);
605 assert_eq!(parsed_to, to_idx, "To index should match input");
606 }
607
608 #[test]
609 fn test_faucet_deposit_instruction_layout_with_fee_payer_depositor() {
610 let fee_payer = [1u8; 32];
611 let faucet_program = FAUCET_PROGRAM;
612 let faucet_account = [2u8; 32];
613 let depositor_account = fee_payer;
614 let amount = 500u64;
615
616 let tx = TransactionBuilder::build_faucet_deposit(
617 fee_payer,
618 faucet_program,
619 faucet_account,
620 depositor_account,
621 EOA_PROGRAM,
622 amount,
623 0,
624 42,
625 100,
626 )
627 .expect("build faucet deposit");
628
629 let rw_accs = tx.rw_accs.expect("rw accounts must exist");
630 assert_eq!(rw_accs.len(), 1);
631 assert_eq!(rw_accs[0], faucet_account);
632
633 let ro_accs = tx.r_accs.expect("ro accounts must exist");
634 assert_eq!(ro_accs.len(), 1);
635 assert_eq!(ro_accs[0], EOA_PROGRAM);
636
637 let instruction = tx.instructions.expect("instruction bytes must exist");
638 assert_eq!(instruction.len(), 18, "Deposit instruction must be 18 bytes");
639
640 let discriminant =
641 u32::from_le_bytes([instruction[0], instruction[1], instruction[2], instruction[3]]);
642 assert_eq!(discriminant, 0, "Deposit discriminant should be 0");
643
644 let faucet_idx = u16::from_le_bytes([instruction[4], instruction[5]]);
645 let depositor_idx = u16::from_le_bytes([instruction[6], instruction[7]]);
646 let eoa_idx = u16::from_le_bytes([instruction[8], instruction[9]]);
647 let parsed_amount = u64::from_le_bytes([
648 instruction[10],
649 instruction[11],
650 instruction[12],
651 instruction[13],
652 instruction[14],
653 instruction[15],
654 instruction[16],
655 instruction[17],
656 ]);
657
658 assert_eq!(faucet_idx, 2, "Faucet account should be first RW account");
659 assert_eq!(depositor_idx, 0, "Depositor shares the fee payer index");
660 assert_eq!(eoa_idx, 3, "EOA program should follow RW accounts");
661 assert_eq!(parsed_amount, amount, "Amount should match input");
662 }
663
664 #[test]
665 fn test_build_token_initialize_mint() {
666 let fee_payer = [1u8; 32];
668 let token_program = [2u8; 32];
669 let mint_account = [3u8; 32];
670 let creator = [4u8; 32];
671 let mint_authority = [5u8; 32];
672 let freeze_authority = [6u8; 32];
673
674 let decimals = 9u8;
675 let ticker = "TEST";
676 let seed = [7u8; 32];
677 let state_proof = vec![8u8; 64];
678
679 let result = TransactionBuilder::build_token_initialize_mint(
681 fee_payer,
682 token_program,
683 mint_account,
684 creator,
685 mint_authority,
686 Some(freeze_authority),
687 decimals,
688 ticker,
689 seed,
690 state_proof.clone(),
691 1000, 1, 100, );
695
696 assert!(result.is_ok(), "Should build valid transaction with freeze authority");
697 let tx = result.unwrap();
698 assert!(tx.instructions.is_some(), "Transaction should have instructions");
699
700 let result_no_freeze = TransactionBuilder::build_token_initialize_mint(
702 fee_payer,
703 token_program,
704 mint_account,
705 creator,
706 mint_authority,
707 None,
708 decimals,
709 ticker,
710 seed,
711 state_proof,
712 1000,
713 1,
714 100,
715 );
716
717 assert!(result_no_freeze.is_ok(), "Should build valid transaction without freeze authority");
718 }
719
720 #[test]
721 fn test_build_token_initialize_mint_instruction_format() {
722 let mint_account_idx = 2u16;
723 let decimals = 9u8;
724 let creator = [1u8; 32];
725 let mint_authority = [2u8; 32];
726 let freeze_authority = [3u8; 32];
727 let ticker = "TST";
728 let seed = [4u8; 32];
729 let state_proof = vec![5u8; 10];
730
731 let instruction = build_token_initialize_mint_instruction(
732 mint_account_idx,
733 decimals,
734 creator,
735 mint_authority,
736 Some(freeze_authority),
737 ticker,
738 seed,
739 state_proof.clone(),
740 )
741 .unwrap();
742
743 let expected_min_size = 1 + 2 + 1 + 32 + 32 + 32 + 1 + 1 + 8 + 32 + state_proof.len();
747 assert_eq!(instruction.len(), expected_min_size);
748
749 assert_eq!(instruction[0], 0, "First byte should be InitializeMint tag (0)");
751
752 let parsed_idx = u16::from_le_bytes([instruction[1], instruction[2]]);
754 assert_eq!(parsed_idx, mint_account_idx);
755
756 assert_eq!(instruction[3], decimals);
758
759 assert_eq!(&instruction[4..36], &creator);
761
762 assert_eq!(&instruction[36..68], &mint_authority);
764
765 assert_eq!(&instruction[68..100], &freeze_authority);
767
768 assert_eq!(instruction[100], 1);
770 }
771
772 #[test]
773 fn test_token_initialize_mint_creator_vs_mint_authority() {
774 let fee_payer = [1u8; 32];
776 let token_program = [2u8; 32];
777 let mint_account = [3u8; 32];
778 let creator = [4u8; 32];
779 let mint_authority = [5u8; 32]; let seed = [6u8; 32];
781 let state_proof = vec![7u8; 32];
782
783 let result = TransactionBuilder::build_token_initialize_mint(
784 fee_payer,
785 token_program,
786 mint_account,
787 creator,
788 mint_authority,
789 None,
790 9,
791 "TEST",
792 seed,
793 state_proof,
794 1000,
795 1,
796 100,
797 );
798
799 assert!(result.is_ok(), "Should allow different creator and mint_authority");
800
801 let result_same = TransactionBuilder::build_token_initialize_mint(
803 fee_payer,
804 token_program,
805 mint_account,
806 creator,
807 creator, None,
809 9,
810 "TEST",
811 seed,
812 vec![7u8; 32],
813 1000,
814 1,
815 100,
816 );
817
818 assert!(result_same.is_ok(), "Should allow same creator and mint_authority");
819 }
820}
821
822pub const TN_UPLOADER_PROGRAM_INSTRUCTION_CREATE: u32 = 0x00;
824pub const TN_UPLOADER_PROGRAM_INSTRUCTION_WRITE: u32 = 0x01;
825pub const TN_UPLOADER_PROGRAM_INSTRUCTION_DESTROY: u32 = 0x02;
826pub const TN_UPLOADER_PROGRAM_INSTRUCTION_FINALIZE: u32 = 0x03;
827
828#[repr(C, packed)]
830#[derive(Debug, Clone, Copy)]
831pub struct UploaderCreateArgs {
832 pub buffer_account_idx: u16,
833 pub meta_account_idx: u16,
834 pub authority_account_idx: u16,
835 pub buffer_account_sz: u32,
836 pub expected_account_hash: [u8; 32],
837 pub seed_len: u32,
838 }
840
841#[repr(C, packed)]
843#[derive(Debug, Clone, Copy)]
844pub struct UploaderWriteArgs {
845 pub buffer_account_idx: u16,
846 pub meta_account_idx: u16,
847 pub data_len: u32,
848 pub data_offset: u32,
849 }
851
852#[repr(C, packed)]
854#[derive(Debug, Clone, Copy)]
855pub struct UploaderFinalizeArgs {
856 pub buffer_account_idx: u16,
857 pub meta_account_idx: u16,
858 pub expected_account_hash: [u8; 32],
859}
860
861#[repr(C, packed)]
863#[derive(Debug, Clone, Copy)]
864pub struct UploaderDestroyArgs {
865 pub buffer_account_idx: u16,
866 pub meta_account_idx: u16,
867}
868
869pub const MANAGER_INSTRUCTION_CREATE_PERMANENT: u8 = 0x00;
871pub const MANAGER_INSTRUCTION_CREATE_EPHEMERAL: u8 = 0x01;
872pub const MANAGER_INSTRUCTION_UPGRADE: u8 = 0x02;
873pub const MANAGER_INSTRUCTION_SET_PAUSE: u8 = 0x03;
874pub const MANAGER_INSTRUCTION_DESTROY: u8 = 0x04;
875pub const MANAGER_INSTRUCTION_FINALIZE: u8 = 0x05;
876pub const MANAGER_INSTRUCTION_SET_AUTHORITY: u8 = 0x06;
877pub const MANAGER_INSTRUCTION_CLAIM_AUTHORITY: u8 = 0x07;
878
879pub const ABI_MANAGER_INSTRUCTION_CREATE_PERMANENT: u8 = 0x00;
880pub const ABI_MANAGER_INSTRUCTION_CREATE_EPHEMERAL: u8 = 0x01;
881pub const ABI_MANAGER_INSTRUCTION_UPGRADE: u8 = 0x02;
882pub const ABI_MANAGER_INSTRUCTION_CLOSE: u8 = 0x03;
883pub const ABI_MANAGER_INSTRUCTION_FINALIZE: u8 = 0x04;
884
885#[repr(C, packed)]
887#[derive(Debug, Clone, Copy)]
888pub struct ManagerHeaderArgs {
889 pub discriminant: u8,
890 pub meta_account_idx: u16,
891 pub program_account_idx: u16,
892}
893
894#[repr(C, packed)]
896#[derive(Debug, Clone, Copy)]
897pub struct ManagerCreateArgs {
898 pub discriminant: u8,
899 pub meta_account_idx: u16,
900 pub program_account_idx: u16,
901 pub srcbuf_account_idx: u16,
902 pub srcbuf_offset: u32,
903 pub srcbuf_size: u32,
904 pub authority_account_idx: u16,
905 pub seed_len: u32,
906 }
908
909#[repr(C, packed)]
911#[derive(Debug, Clone, Copy)]
912pub struct ManagerUpgradeArgs {
913 pub discriminant: u8,
914 pub meta_account_idx: u16,
915 pub program_account_idx: u16,
916 pub srcbuf_account_idx: u16,
917 pub srcbuf_offset: u32,
918 pub srcbuf_size: u32,
919}
920
921#[repr(C, packed)]
923#[derive(Debug, Clone, Copy)]
924pub struct AbiManagerCreateArgs {
925 pub program_meta_account_idx: u16,
926 pub abi_account_idx: u16,
927 pub srcbuf_account_idx: u16,
928 pub srcbuf_offset: u32,
929 pub srcbuf_size: u32,
930 pub authority_account_idx: u16,
931 pub seed: [u8; 32], }
933
934#[repr(C, packed)]
936#[derive(Debug, Clone, Copy)]
937pub struct AbiManagerUpgradeArgs {
938 pub program_meta_account_idx: u16,
939 pub abi_account_idx: u16,
940 pub srcbuf_account_idx: u16,
941 pub srcbuf_offset: u32,
942 pub srcbuf_size: u32,
943 pub authority_account_idx: u16,
944}
945
946#[repr(C, packed)]
948#[derive(Debug, Clone, Copy)]
949pub struct AbiManagerFinalizeArgs {
950 pub program_meta_account_idx: u16,
951 pub abi_account_idx: u16,
952 pub authority_account_idx: u16,
953}
954
955#[repr(C, packed)]
957#[derive(Debug, Clone, Copy)]
958pub struct AbiManagerCloseArgs {
959 pub program_meta_account_idx: u16,
960 pub abi_account_idx: u16,
961 pub authority_account_idx: u16,
962}
963
964#[repr(C, packed)]
966#[derive(Debug, Clone, Copy)]
967pub struct ManagerSetPauseArgs {
968 pub discriminant: u8,
969 pub meta_account_idx: u16,
970 pub program_account_idx: u16,
971 pub is_paused: u8,
972}
973
974#[repr(C, packed)]
976#[derive(Debug, Clone, Copy)]
977pub struct ManagerSetAuthorityArgs {
978 pub discriminant: u8,
979 pub meta_account_idx: u16,
980 pub program_account_idx: u16,
981 pub authority_candidate: [u8; 32],
982}
983
984pub const TN_TEST_UPLOADER_PROGRAM_DISCRIMINANT_CREATE: u8 = 0x00;
986pub const TN_TEST_UPLOADER_PROGRAM_DISCRIMINANT_WRITE: u8 = 0x01;
987
988#[repr(C, packed)]
990#[derive(Debug, Clone, Copy)]
991pub struct TestUploaderCreateArgs {
992 pub account_idx: u16,
993 pub is_ephemeral: u8,
994 pub account_sz: u32,
995 pub seed_len: u32,
996 }
998
999#[repr(C, packed)]
1001#[derive(Debug, Clone, Copy)]
1002pub struct TestUploaderWriteArgs {
1003 pub target_account_idx: u16,
1004 pub target_offset: u32,
1005 pub data_len: u32,
1006 }
1008
1009#[repr(C, packed)]
1011#[derive(Debug, Clone, Copy)]
1012pub struct SystemProgramDecompress2Args {
1013 pub target_account_idx: u16,
1014 pub meta_account_idx: u16,
1015 pub data_account_idx: u16,
1016 pub data_offset: u32,
1017}
1018
1019impl TransactionBuilder {
1020 pub fn build_uploader_create(
1022 fee_payer: TnPubkey,
1023 uploader_program: TnPubkey,
1024 meta_account: TnPubkey,
1025 buffer_account: TnPubkey,
1026 buffer_size: u32,
1027 expected_hash: [u8; 32],
1028 seed: &[u8],
1029 fee: u64,
1030 nonce: u64,
1031 start_slot: u64,
1032 ) -> Result<Transaction> {
1033 let authority_account_idx = 0u16;
1035
1036 let mut tx = Transaction::new(fee_payer, uploader_program, fee, nonce)
1037 .with_start_slot(start_slot)
1038 .with_expiry_after(10)
1039 .with_compute_units(50_000 + 2 * buffer_size as u32)
1040 .with_memory_units(10_000)
1041 .with_state_units(10_000);
1042
1043 let mut meta_account_idx = 2u16;
1044 let mut buffer_account_idx = 3u16;
1045 if meta_account > buffer_account {
1046 meta_account_idx = 3u16;
1047 buffer_account_idx = 2u16;
1048 tx = tx
1049 .add_rw_account(buffer_account)
1050 .add_rw_account(meta_account)
1051 } else {
1052 tx = tx
1053 .add_rw_account(meta_account)
1054 .add_rw_account(buffer_account)
1055 }
1056
1057 let instruction_data = build_uploader_create_instruction(
1058 buffer_account_idx,
1059 meta_account_idx,
1060 authority_account_idx,
1061 buffer_size,
1062 expected_hash,
1063 seed,
1064 )?;
1065
1066 tx = tx.with_instructions(instruction_data);
1067
1068 Ok(tx)
1069 }
1070
1071 pub fn build_uploader_write(
1073 fee_payer: TnPubkey,
1074 uploader_program: TnPubkey,
1075 meta_account: TnPubkey,
1076 buffer_account: TnPubkey,
1077 data: &[u8],
1078 offset: u32,
1079 fee: u64,
1080 nonce: u64,
1081 start_slot: u64,
1082 ) -> Result<Transaction> {
1083 let mut tx = Transaction::new(fee_payer, uploader_program, fee, nonce)
1085 .with_start_slot(start_slot)
1086 .with_expiry_after(10000)
1087 .with_compute_units(500_000_000)
1088 .with_memory_units(5000)
1089 .with_state_units(5000);
1090
1091 let mut meta_account_idx = 2u16;
1092 let mut buffer_account_idx = 3u16;
1093 if meta_account > buffer_account {
1094 meta_account_idx = 3u16;
1095 buffer_account_idx = 2u16;
1096 tx = tx
1097 .add_rw_account(buffer_account)
1098 .add_rw_account(meta_account)
1099 } else {
1100 tx = tx
1101 .add_rw_account(meta_account)
1102 .add_rw_account(buffer_account)
1103 }
1104
1105 let instruction_data =
1106 build_uploader_write_instruction(buffer_account_idx, meta_account_idx, data, offset)?;
1107
1108 tx = tx.with_instructions(instruction_data);
1109
1110 Ok(tx)
1111 }
1112
1113 pub fn build_uploader_finalize(
1115 fee_payer: TnPubkey,
1116 uploader_program: TnPubkey,
1117 meta_account: TnPubkey,
1118 buffer_account: TnPubkey,
1119 buffer_size: u32,
1120 expected_hash: [u8; 32],
1121 fee: u64,
1122 nonce: u64,
1123 start_slot: u64,
1124 ) -> Result<Transaction> {
1125 let mut tx = Transaction::new(fee_payer, uploader_program, fee, nonce)
1126 .with_start_slot(start_slot)
1127 .with_expiry_after(10000)
1128 .with_compute_units(50_000 + 200 * buffer_size as u32)
1129 .with_memory_units(5000)
1130 .with_state_units(5000);
1131
1132 let mut meta_account_idx = 2u16;
1134 let mut buffer_account_idx = 3u16;
1135 if meta_account > buffer_account {
1136 meta_account_idx = 3u16;
1137 buffer_account_idx = 2u16;
1138 tx = tx
1139 .add_rw_account(buffer_account)
1140 .add_rw_account(meta_account)
1141 } else {
1142 tx = tx
1143 .add_rw_account(meta_account)
1144 .add_rw_account(buffer_account)
1145 }
1146
1147 let instruction_data = build_uploader_finalize_instruction(
1148 buffer_account_idx,
1149 meta_account_idx,
1150 expected_hash,
1151 )?;
1152
1153 tx = tx.with_instructions(instruction_data);
1154
1155 Ok(tx)
1156 }
1157
1158 pub fn build_uploader_destroy(
1160 fee_payer: TnPubkey,
1161 uploader_program: TnPubkey,
1162 meta_account: TnPubkey,
1163 buffer_account: TnPubkey,
1164 fee: u64,
1165 nonce: u64,
1166 start_slot: u64,
1167 ) -> Result<Transaction> {
1168 let mut tx = Transaction::new(fee_payer, uploader_program, fee, nonce)
1169 .with_start_slot(start_slot)
1170 .with_expiry_after(10000)
1171 .with_compute_units(50000)
1172 .with_memory_units(5000)
1173 .with_state_units(5000);
1174
1175 let mut meta_account_idx = 2u16;
1177 let mut buffer_account_idx = 3u16;
1178 if meta_account > buffer_account {
1179 meta_account_idx = 3u16;
1180 buffer_account_idx = 2u16;
1181 tx = tx
1182 .add_rw_account(buffer_account)
1183 .add_rw_account(meta_account)
1184 } else {
1185 tx = tx
1186 .add_rw_account(meta_account)
1187 .add_rw_account(buffer_account)
1188 }
1189
1190 let instruction_data =
1191 build_uploader_destroy_instruction(buffer_account_idx, meta_account_idx)?;
1192
1193 tx = tx.with_instructions(instruction_data);
1194 Ok(tx)
1195 }
1196
1197 pub fn build_manager_create(
1199 fee_payer: TnPubkey,
1200 manager_program: TnPubkey,
1201 meta_account: TnPubkey,
1202 program_account: TnPubkey,
1203 srcbuf_account: TnPubkey,
1204 authority_account: TnPubkey,
1205 srcbuf_offset: u32,
1206 srcbuf_size: u32,
1207 seed: &[u8],
1208 is_ephemeral: bool,
1209 meta_proof: Option<&[u8]>,
1210 program_proof: Option<&[u8]>,
1211 fee: u64,
1212 nonce: u64,
1213 start_slot: u64,
1214 ) -> Result<Transaction> {
1215 let mut tx = Transaction::new(fee_payer, manager_program, fee, nonce)
1216 .with_start_slot(start_slot)
1217 .with_expiry_after(10000)
1218 .with_compute_units(500_000_000)
1219 .with_memory_units(5000)
1220 .with_state_units(5000);
1221
1222 let authority_is_fee_payer = authority_account == fee_payer;
1224
1225 let mut rw_accounts = vec![(meta_account, "meta"), (program_account, "program")];
1227
1228 let mut r_accounts = vec![(srcbuf_account, "srcbuf")];
1229
1230 if !authority_is_fee_payer {
1232 r_accounts.push((authority_account, "authority"));
1233 }
1234
1235 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1237
1238 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1240
1241 let mut accounts = rw_accounts;
1243 accounts.extend(r_accounts);
1244
1245 let mut meta_account_idx = 0u16;
1246 let mut program_account_idx = 0u16;
1247 let mut srcbuf_account_idx = 0u16;
1248 let mut authority_account_idx = if authority_is_fee_payer {
1249 0u16 } else {
1251 0u16 };
1253
1254 for (i, (account, account_type)) in accounts.iter().enumerate() {
1255 let idx = (i + 2) as u16; match *account_type {
1257 "meta" => {
1258 meta_account_idx = idx;
1259 tx = tx.add_rw_account(*account);
1260 }
1261 "program" => {
1262 program_account_idx = idx;
1263 tx = tx.add_rw_account(*account);
1264 }
1265 "srcbuf" => {
1266 srcbuf_account_idx = idx;
1267 tx = tx.add_r_account(*account);
1268 }
1269 "authority" => {
1270 authority_account_idx = idx;
1271 tx = tx.add_r_account(*account);
1272 }
1273 _ => unreachable!(),
1274 }
1275 }
1276
1277 let discriminant = if is_ephemeral {
1278 MANAGER_INSTRUCTION_CREATE_EPHEMERAL
1279 } else {
1280 MANAGER_INSTRUCTION_CREATE_PERMANENT
1281 };
1282
1283 let combined_proof = if let (Some(meta), Some(program)) = (meta_proof, program_proof) {
1285 let mut combined = Vec::with_capacity(meta.len() + program.len());
1286 combined.extend_from_slice(meta);
1287 combined.extend_from_slice(program);
1288 Some(combined)
1289 } else {
1290 None
1291 };
1292
1293 let instruction_data = build_manager_create_instruction(
1294 discriminant,
1295 meta_account_idx,
1296 program_account_idx,
1297 srcbuf_account_idx,
1298 authority_account_idx,
1299 srcbuf_offset,
1300 srcbuf_size,
1301 seed,
1302 combined_proof.as_deref(),
1303 )?;
1304
1305 tx = tx.with_instructions(instruction_data);
1306 Ok(tx)
1307 }
1308
1309 #[allow(clippy::too_many_arguments)]
1311 pub fn build_abi_manager_create(
1312 fee_payer: TnPubkey,
1313 abi_manager_program: TnPubkey,
1314 program_meta_account: TnPubkey,
1315 abi_account: TnPubkey,
1316 srcbuf_account: TnPubkey,
1317 authority_account: TnPubkey,
1318 srcbuf_offset: u32,
1319 srcbuf_size: u32,
1320 seed: &[u8],
1321 is_ephemeral: bool,
1322 abi_proof: Option<&[u8]>,
1323 fee: u64,
1324 nonce: u64,
1325 start_slot: u64,
1326 ) -> Result<Transaction> {
1327 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
1328 .with_start_slot(start_slot)
1329 .with_expiry_after(10000)
1330 .with_compute_units(500_000_000)
1331 .with_memory_units(5000)
1332 .with_state_units(5000);
1333
1334 let authority_is_fee_payer = authority_account == fee_payer;
1335
1336 let mut rw_accounts = vec![(program_meta_account, "meta"), (abi_account, "abi")];
1337
1338 let mut r_accounts = vec![(srcbuf_account, "srcbuf")];
1339
1340 if !authority_is_fee_payer {
1341 r_accounts.push((authority_account, "authority"));
1342 }
1343
1344 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1345 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1346
1347 let mut accounts = rw_accounts;
1348 accounts.extend(r_accounts);
1349
1350 let mut program_meta_account_idx = 0u16;
1351 let mut abi_account_idx = 0u16;
1352 let mut srcbuf_account_idx = 0u16;
1353 let mut authority_account_idx = 0u16;
1354
1355 for (i, (account, account_type)) in accounts.iter().enumerate() {
1356 let idx = (i + 2) as u16;
1357 match *account_type {
1358 "meta" => {
1359 program_meta_account_idx = idx;
1360 tx = tx.add_rw_account(*account);
1361 }
1362 "abi" => {
1363 abi_account_idx = idx;
1364 tx = tx.add_rw_account(*account);
1365 }
1366 "srcbuf" => {
1367 srcbuf_account_idx = idx;
1368 tx = tx.add_r_account(*account);
1369 }
1370 "authority" => {
1371 authority_account_idx = idx;
1372 tx = tx.add_r_account(*account);
1373 }
1374 _ => unreachable!(),
1375 }
1376 }
1377
1378 let discriminant = if is_ephemeral {
1379 ABI_MANAGER_INSTRUCTION_CREATE_EPHEMERAL
1380 } else {
1381 ABI_MANAGER_INSTRUCTION_CREATE_PERMANENT
1382 };
1383
1384 let instruction_data = build_abi_manager_create_instruction(
1385 discriminant,
1386 program_meta_account_idx,
1387 abi_account_idx,
1388 srcbuf_account_idx,
1389 srcbuf_offset,
1390 srcbuf_size,
1391 authority_account_idx,
1392 seed,
1393 abi_proof,
1394 )?;
1395
1396 tx = tx.with_instructions(instruction_data);
1397 Ok(tx)
1398 }
1399
1400 #[allow(clippy::too_many_arguments)]
1402 pub fn build_abi_manager_upgrade(
1403 fee_payer: TnPubkey,
1404 abi_manager_program: TnPubkey,
1405 program_meta_account: TnPubkey,
1406 abi_account: TnPubkey,
1407 srcbuf_account: TnPubkey,
1408 authority_account: TnPubkey,
1409 srcbuf_offset: u32,
1410 srcbuf_size: u32,
1411 fee: u64,
1412 nonce: u64,
1413 start_slot: u64,
1414 ) -> Result<Transaction> {
1415 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
1416 .with_start_slot(start_slot)
1417 .with_expiry_after(10000)
1418 .with_compute_units(500_000_000)
1419 .with_memory_units(5000)
1420 .with_state_units(5000);
1421
1422 let authority_is_fee_payer = authority_account == fee_payer;
1423
1424 let mut rw_accounts = vec![(program_meta_account, "meta"), (abi_account, "abi")];
1425 let mut r_accounts = vec![(srcbuf_account, "srcbuf")];
1426
1427 if !authority_is_fee_payer {
1428 r_accounts.push((authority_account, "authority"));
1429 }
1430
1431 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1432 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1433
1434 let mut accounts = rw_accounts;
1435 accounts.extend(r_accounts);
1436
1437 let mut program_meta_account_idx = 0u16;
1438 let mut abi_account_idx = 0u16;
1439 let mut srcbuf_account_idx = 0u16;
1440 let mut authority_account_idx = 0u16;
1441
1442 for (i, (account, account_type)) in accounts.iter().enumerate() {
1443 let idx = (i + 2) as u16;
1444 match *account_type {
1445 "meta" => {
1446 program_meta_account_idx = idx;
1447 tx = tx.add_rw_account(*account);
1448 }
1449 "abi" => {
1450 abi_account_idx = idx;
1451 tx = tx.add_rw_account(*account);
1452 }
1453 "srcbuf" => {
1454 srcbuf_account_idx = idx;
1455 tx = tx.add_r_account(*account);
1456 }
1457 "authority" => {
1458 authority_account_idx = idx;
1459 tx = tx.add_r_account(*account);
1460 }
1461 _ => unreachable!(),
1462 }
1463 }
1464
1465 let authority_idx = if authority_is_fee_payer {
1466 0u16
1467 } else {
1468 authority_account_idx
1469 };
1470
1471 let instruction_data = build_abi_manager_upgrade_instruction(
1472 program_meta_account_idx,
1473 abi_account_idx,
1474 srcbuf_account_idx,
1475 srcbuf_offset,
1476 srcbuf_size,
1477 authority_idx,
1478 )?;
1479
1480 tx = tx.with_instructions(instruction_data);
1481 Ok(tx)
1482 }
1483
1484 pub fn build_abi_manager_finalize(
1486 fee_payer: TnPubkey,
1487 abi_manager_program: TnPubkey,
1488 program_meta_account: TnPubkey,
1489 abi_account: TnPubkey,
1490 authority_account: TnPubkey,
1491 fee: u64,
1492 nonce: u64,
1493 start_slot: u64,
1494 ) -> Result<Transaction> {
1495 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
1496 .with_start_slot(start_slot)
1497 .with_expiry_after(10000)
1498 .with_compute_units(500_000_000)
1499 .with_memory_units(5000)
1500 .with_state_units(5000);
1501
1502 let authority_is_fee_payer = authority_account == fee_payer;
1503
1504 let mut rw_accounts = vec![(program_meta_account, "meta"), (abi_account, "abi")];
1505 let mut r_accounts = Vec::new();
1506
1507 if !authority_is_fee_payer {
1508 r_accounts.push((authority_account, "authority"));
1509 }
1510
1511 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1512 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1513
1514 let mut accounts = rw_accounts;
1515 accounts.extend(r_accounts);
1516
1517 let mut program_meta_account_idx = 0u16;
1518 let mut abi_account_idx = 0u16;
1519 let mut authority_account_idx = 0u16;
1520
1521 for (i, (account, account_type)) in accounts.iter().enumerate() {
1522 let idx = (i + 2) as u16;
1523 match *account_type {
1524 "meta" => {
1525 program_meta_account_idx = idx;
1526 tx = tx.add_rw_account(*account);
1527 }
1528 "abi" => {
1529 abi_account_idx = idx;
1530 tx = tx.add_rw_account(*account);
1531 }
1532 "authority" => {
1533 authority_account_idx = idx;
1534 tx = tx.add_r_account(*account);
1535 }
1536 _ => unreachable!(),
1537 }
1538 }
1539
1540 let authority_idx = if authority_is_fee_payer {
1541 0u16
1542 } else {
1543 authority_account_idx
1544 };
1545
1546 let instruction_data = build_abi_manager_finalize_instruction(
1547 program_meta_account_idx,
1548 abi_account_idx,
1549 authority_idx,
1550 )?;
1551
1552 tx = tx.with_instructions(instruction_data);
1553 Ok(tx)
1554 }
1555
1556 pub fn build_abi_manager_close(
1558 fee_payer: TnPubkey,
1559 abi_manager_program: TnPubkey,
1560 program_meta_account: TnPubkey,
1561 abi_account: TnPubkey,
1562 authority_account: TnPubkey,
1563 fee: u64,
1564 nonce: u64,
1565 start_slot: u64,
1566 ) -> Result<Transaction> {
1567 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
1568 .with_start_slot(start_slot)
1569 .with_expiry_after(10000)
1570 .with_compute_units(500_000_000)
1571 .with_memory_units(5000)
1572 .with_state_units(5000);
1573
1574 let authority_is_fee_payer = authority_account == fee_payer;
1575
1576 let mut rw_accounts = vec![(program_meta_account, "meta"), (abi_account, "abi")];
1577 let mut r_accounts = Vec::new();
1578
1579 if !authority_is_fee_payer {
1580 r_accounts.push((authority_account, "authority"));
1581 }
1582
1583 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1584 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1585
1586 let mut accounts = rw_accounts;
1587 accounts.extend(r_accounts);
1588
1589 let mut program_meta_account_idx = 0u16;
1590 let mut abi_account_idx = 0u16;
1591 let mut authority_account_idx = 0u16;
1592
1593 for (i, (account, account_type)) in accounts.iter().enumerate() {
1594 let idx = (i + 2) as u16;
1595 match *account_type {
1596 "meta" => {
1597 program_meta_account_idx = idx;
1598 tx = tx.add_rw_account(*account);
1599 }
1600 "abi" => {
1601 abi_account_idx = idx;
1602 tx = tx.add_rw_account(*account);
1603 }
1604 "authority" => {
1605 authority_account_idx = idx;
1606 tx = tx.add_r_account(*account);
1607 }
1608 _ => unreachable!(),
1609 }
1610 }
1611
1612 let authority_idx = if authority_is_fee_payer {
1613 0u16
1614 } else {
1615 authority_account_idx
1616 };
1617
1618 let instruction_data = build_abi_manager_close_instruction(
1619 program_meta_account_idx,
1620 abi_account_idx,
1621 authority_idx,
1622 )?;
1623
1624 tx = tx.with_instructions(instruction_data);
1625 Ok(tx)
1626 }
1627
1628 pub fn build_manager_upgrade(
1630 fee_payer: TnPubkey,
1631 manager_program: TnPubkey,
1632 meta_account: TnPubkey,
1633 program_account: TnPubkey,
1634 srcbuf_account: TnPubkey,
1635 srcbuf_offset: u32,
1636 srcbuf_size: u32,
1637 fee: u64,
1638 nonce: u64,
1639 start_slot: u64,
1640 ) -> Result<Transaction> {
1641 let mut tx = Transaction::new(fee_payer, manager_program, fee, nonce)
1642 .with_start_slot(start_slot)
1643 .with_expiry_after(10000)
1644 .with_compute_units(500_000_000)
1645 .with_memory_units(5000)
1646 .with_state_units(5000);
1647
1648 let mut rw_accounts = vec![(meta_account, "meta"), (program_account, "program")];
1650
1651 let mut r_accounts = vec![(srcbuf_account, "srcbuf")];
1652
1653 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1655
1656 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1658
1659 let mut accounts = rw_accounts;
1661 accounts.extend(r_accounts);
1662
1663 let mut meta_account_idx = 0u16;
1664 let mut program_account_idx = 0u16;
1665 let mut srcbuf_account_idx = 0u16;
1666
1667 for (i, (account, account_type)) in accounts.iter().enumerate() {
1668 let idx = (i + 2) as u16; match *account_type {
1670 "meta" => {
1671 meta_account_idx = idx;
1672 tx = tx.add_rw_account(*account);
1673 }
1674 "program" => {
1675 program_account_idx = idx;
1676 tx = tx.add_rw_account(*account);
1677 }
1678 "srcbuf" => {
1679 srcbuf_account_idx = idx;
1680 tx = tx.add_r_account(*account);
1681 }
1682 _ => unreachable!(),
1683 }
1684 }
1685
1686 let instruction_data = build_manager_upgrade_instruction(
1687 meta_account_idx,
1688 program_account_idx,
1689 srcbuf_account_idx,
1690 srcbuf_offset,
1691 srcbuf_size,
1692 )?;
1693
1694 tx = tx.with_instructions(instruction_data);
1695 Ok(tx)
1696 }
1697
1698 pub fn build_manager_set_pause(
1700 fee_payer: TnPubkey,
1701 manager_program: TnPubkey,
1702 meta_account: TnPubkey,
1703 program_account: TnPubkey,
1704 is_paused: bool,
1705 fee: u64,
1706 nonce: u64,
1707 start_slot: u64,
1708 ) -> Result<Transaction> {
1709 let mut tx = Transaction::new(fee_payer, manager_program, fee, nonce)
1710 .with_start_slot(start_slot)
1711 .with_expiry_after(10000)
1712 .with_compute_units(100_000_000)
1713 .with_memory_units(5000)
1714 .with_state_units(5000);
1715
1716 let mut accounts = vec![(meta_account, "meta"), (program_account, "program")];
1718 accounts.sort_by(|a, b| a.0.cmp(&b.0));
1719
1720 let mut meta_account_idx = 0u16;
1721 let mut program_account_idx = 0u16;
1722
1723 for (i, (account, account_type)) in accounts.iter().enumerate() {
1724 let idx = (i + 2) as u16;
1725 match *account_type {
1726 "meta" => {
1727 meta_account_idx = idx;
1728 tx = tx.add_rw_account(*account);
1729 }
1730 "program" => {
1731 program_account_idx = idx;
1732 tx = tx.add_rw_account(*account);
1733 }
1734 _ => unreachable!(),
1735 }
1736 }
1737
1738 let instruction_data =
1739 build_manager_set_pause_instruction(meta_account_idx, program_account_idx, is_paused)?;
1740
1741 tx = tx.with_instructions(instruction_data);
1742 Ok(tx)
1743 }
1744
1745 pub fn build_manager_simple(
1747 fee_payer: TnPubkey,
1748 manager_program: TnPubkey,
1749 meta_account: TnPubkey,
1750 program_account: TnPubkey,
1751 instruction_type: u8,
1752 fee: u64,
1753 nonce: u64,
1754 start_slot: u64,
1755 ) -> Result<Transaction> {
1756 let mut tx = Transaction::new(fee_payer, manager_program, fee, nonce)
1757 .with_start_slot(start_slot)
1758 .with_expiry_after(10000)
1759 .with_compute_units(100_000_000)
1760 .with_memory_units(5000)
1761 .with_state_units(5000);
1762
1763 let mut accounts = vec![(meta_account, "meta"), (program_account, "program")];
1765 accounts.sort_by(|a, b| a.0.cmp(&b.0));
1766
1767 let mut meta_account_idx = 0u16;
1768 let mut program_account_idx = 0u16;
1769
1770 for (i, (account, account_type)) in accounts.iter().enumerate() {
1771 let idx = (i + 2) as u16;
1772 match *account_type {
1773 "meta" => {
1774 meta_account_idx = idx;
1775 tx = tx.add_rw_account(*account);
1776 }
1777 "program" => {
1778 program_account_idx = idx;
1779 tx = tx.add_rw_account(*account);
1780 }
1781 _ => unreachable!(),
1782 }
1783 }
1784
1785 let instruction_data = build_manager_header_instruction(
1786 instruction_type,
1787 meta_account_idx,
1788 program_account_idx,
1789 )?;
1790
1791 tx = tx.with_instructions(instruction_data);
1792 Ok(tx)
1793 }
1794
1795 pub fn build_manager_set_authority(
1797 fee_payer: TnPubkey,
1798 manager_program: TnPubkey,
1799 meta_account: TnPubkey,
1800 program_account: TnPubkey,
1801 authority_candidate: [u8; 32],
1802 fee: u64,
1803 nonce: u64,
1804 start_slot: u64,
1805 ) -> Result<Transaction> {
1806 let mut tx = Transaction::new(fee_payer, manager_program, fee, nonce)
1807 .with_start_slot(start_slot)
1808 .with_expiry_after(10000)
1809 .with_compute_units(100_000_000)
1810 .with_memory_units(5000)
1811 .with_state_units(5000);
1812
1813 let mut accounts = vec![(meta_account, "meta"), (program_account, "program")];
1815 accounts.sort_by(|a, b| a.0.cmp(&b.0));
1816
1817 let mut meta_account_idx = 0u16;
1818 let mut program_account_idx = 0u16;
1819
1820 for (i, (account, account_type)) in accounts.iter().enumerate() {
1821 let idx = (i + 2) as u16;
1822 match *account_type {
1823 "meta" => {
1824 meta_account_idx = idx;
1825 tx = tx.add_rw_account(*account);
1826 }
1827 "program" => {
1828 program_account_idx = idx;
1829 tx = tx.add_rw_account(*account);
1830 }
1831 _ => unreachable!(),
1832 }
1833 }
1834
1835 let instruction_data = build_manager_set_authority_instruction(
1836 meta_account_idx,
1837 program_account_idx,
1838 authority_candidate,
1839 )?;
1840
1841 tx = tx.with_instructions(instruction_data);
1842 Ok(tx)
1843 }
1844
1845 pub fn build_test_uploader_create(
1847 fee_payer: TnPubkey,
1848 test_uploader_program: TnPubkey,
1849 target_account: TnPubkey,
1850 account_sz: u32,
1851 seed: &[u8],
1852 is_ephemeral: bool,
1853 state_proof: Option<&[u8]>,
1854 fee: u64,
1855 nonce: u64,
1856 start_slot: u64,
1857 ) -> Result<Transaction> {
1858 let target_account_idx = 2u16;
1860
1861 let tx = Transaction::new(fee_payer, test_uploader_program, fee, nonce)
1862 .with_start_slot(start_slot)
1863 .with_expiry_after(100)
1864 .with_compute_units(100_000 + account_sz)
1865 .with_memory_units(10_000)
1866 .with_state_units(10_000)
1867 .add_rw_account(target_account);
1868
1869 let instruction_data = build_test_uploader_create_instruction(
1870 target_account_idx,
1871 account_sz,
1872 seed,
1873 is_ephemeral,
1874 state_proof,
1875 )?;
1876
1877 let tx = tx.with_instructions(instruction_data);
1878 Ok(tx)
1879 }
1880
1881 pub fn build_test_uploader_write(
1883 fee_payer: TnPubkey,
1884 test_uploader_program: TnPubkey,
1885 target_account: TnPubkey,
1886 offset: u32,
1887 data: &[u8],
1888 fee: u64,
1889 nonce: u64,
1890 start_slot: u64,
1891 ) -> Result<Transaction> {
1892 let target_account_idx = 2u16;
1894
1895 let tx = Transaction::new(fee_payer, test_uploader_program, fee, nonce)
1896 .with_start_slot(start_slot)
1897 .with_expiry_after(10_000)
1898 .with_compute_units(100_000 + 18 * data.len() as u32)
1899 .with_memory_units(10_000)
1900 .with_state_units(10_000)
1901 .add_rw_account(target_account);
1902
1903 let instruction_data =
1904 build_test_uploader_write_instruction(target_account_idx, offset, data)?;
1905
1906 let tx = tx.with_instructions(instruction_data);
1907 Ok(tx)
1908 }
1909
1910 pub fn build_decompress2(
1912 fee_payer: TnPubkey,
1913 program: TnPubkey,
1914 target_account: TnPubkey,
1915 meta_account: TnPubkey,
1916 data_account: TnPubkey,
1917 data_offset: u32,
1918 state_proof: &[u8],
1919 fee: u64,
1920 nonce: u64,
1921 start_slot: u64,
1922 data_sz: u32,
1923 ) -> Result<Transaction> {
1924 let mut tx = Transaction::new(fee_payer, program, fee, nonce)
1926 .with_start_slot(start_slot)
1927 .with_expiry_after(100)
1928 .with_compute_units(10_000 + 2 * data_sz)
1929 .with_memory_units(10_000)
1930 .with_state_units(10);
1931
1932 let target_account_idx = 2u16;
1934 tx = tx.add_rw_account(target_account);
1935
1936 let mut meta_account_idx = 0u16;
1937 let mut data_account_idx = 0u16;
1938
1939 if meta_account == data_account {
1941 let account_idx = 3u16;
1943 meta_account_idx = account_idx;
1944 data_account_idx = account_idx;
1945 tx = tx.add_r_account(meta_account);
1946 } else {
1947 let mut read_accounts = vec![(meta_account, "meta"), (data_account, "data")];
1949 read_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1950
1951 for (i, (account, account_type)) in read_accounts.iter().enumerate() {
1952 let idx = (3 + i) as u16; match *account_type {
1954 "meta" => {
1955 meta_account_idx = idx;
1956 tx = tx.add_r_account(*account);
1957 }
1958 "data" => {
1959 data_account_idx = idx;
1960 tx = tx.add_r_account(*account);
1961 }
1962 _ => unreachable!(),
1963 }
1964 }
1965 }
1966
1967 let instruction_data = build_decompress2_instruction(
1968 target_account_idx,
1969 meta_account_idx,
1970 data_account_idx,
1971 data_offset,
1972 state_proof,
1973 )?;
1974
1975 tx = tx.with_instructions(instruction_data);
1976 Ok(tx)
1977 }
1978}
1979
1980fn build_uploader_create_instruction(
1982 buffer_account_idx: u16,
1983 meta_account_idx: u16,
1984 authority_account_idx: u16,
1985 buffer_size: u32,
1986 expected_hash: [u8; 32],
1987 seed: &[u8],
1988) -> Result<Vec<u8>> {
1989 let mut instruction = Vec::new();
1990
1991 instruction.extend_from_slice(&TN_UPLOADER_PROGRAM_INSTRUCTION_CREATE.to_le_bytes());
1993
1994 let args = UploaderCreateArgs {
1996 buffer_account_idx,
1997 meta_account_idx,
1998 authority_account_idx,
1999 buffer_account_sz: buffer_size,
2000 expected_account_hash: expected_hash,
2001 seed_len: seed.len() as u32,
2002 };
2003
2004 let args_bytes = unsafe {
2006 std::slice::from_raw_parts(
2007 &args as *const _ as *const u8,
2008 std::mem::size_of::<UploaderCreateArgs>(),
2009 )
2010 };
2011 instruction.extend_from_slice(args_bytes);
2012
2013 instruction.extend_from_slice(seed);
2015
2016 Ok(instruction)
2017}
2018
2019fn build_uploader_write_instruction(
2021 buffer_account_idx: u16,
2022 meta_account_idx: u16,
2023 data: &[u8],
2024 offset: u32,
2025) -> Result<Vec<u8>> {
2026 let mut instruction = Vec::new();
2027
2028 instruction.extend_from_slice(&TN_UPLOADER_PROGRAM_INSTRUCTION_WRITE.to_le_bytes());
2030
2031 let args = UploaderWriteArgs {
2033 buffer_account_idx,
2034 meta_account_idx,
2035 data_len: data.len() as u32,
2036 data_offset: offset,
2037 };
2038
2039 let args_bytes = unsafe {
2041 std::slice::from_raw_parts(
2042 &args as *const _ as *const u8,
2043 std::mem::size_of::<UploaderWriteArgs>(),
2044 )
2045 };
2046 instruction.extend_from_slice(args_bytes);
2047
2048 instruction.extend_from_slice(data);
2050
2051 Ok(instruction)
2052}
2053
2054fn build_uploader_finalize_instruction(
2056 buffer_account_idx: u16,
2057 meta_account_idx: u16,
2058 expected_hash: [u8; 32],
2059) -> Result<Vec<u8>> {
2060 let mut instruction = Vec::new();
2061
2062 instruction.extend_from_slice(&TN_UPLOADER_PROGRAM_INSTRUCTION_FINALIZE.to_le_bytes());
2064
2065 let args = UploaderFinalizeArgs {
2067 buffer_account_idx,
2068 meta_account_idx,
2069 expected_account_hash: expected_hash,
2070 };
2071
2072 let args_bytes = unsafe {
2074 std::slice::from_raw_parts(
2075 &args as *const _ as *const u8,
2076 std::mem::size_of::<UploaderFinalizeArgs>(),
2077 )
2078 };
2079 instruction.extend_from_slice(args_bytes);
2080
2081 Ok(instruction)
2082}
2083
2084fn build_uploader_destroy_instruction(
2086 buffer_account_idx: u16,
2087 meta_account_idx: u16,
2088) -> Result<Vec<u8>> {
2089 let mut instruction = Vec::new();
2090
2091 instruction.extend_from_slice(&TN_UPLOADER_PROGRAM_INSTRUCTION_DESTROY.to_le_bytes());
2093
2094 let args = UploaderDestroyArgs {
2096 buffer_account_idx,
2097 meta_account_idx,
2098 };
2099
2100 let args_bytes = unsafe {
2102 std::slice::from_raw_parts(
2103 &args as *const _ as *const u8,
2104 std::mem::size_of::<UploaderDestroyArgs>(),
2105 )
2106 };
2107 instruction.extend_from_slice(args_bytes);
2108
2109 Ok(instruction)
2110}
2111
2112fn build_manager_create_instruction(
2114 discriminant: u8,
2115 meta_account_idx: u16,
2116 program_account_idx: u16,
2117 srcbuf_account_idx: u16,
2118 authority_account_idx: u16,
2119 srcbuf_offset: u32,
2120 srcbuf_size: u32,
2121 seed: &[u8],
2122 proof: Option<&[u8]>,
2123) -> Result<Vec<u8>> {
2124 let mut instruction = Vec::new();
2125
2126 let args = ManagerCreateArgs {
2128 discriminant,
2129 meta_account_idx,
2130 program_account_idx,
2131 srcbuf_account_idx,
2132 srcbuf_offset,
2133 srcbuf_size,
2134 authority_account_idx,
2135 seed_len: seed.len() as u32,
2136 };
2137
2138 let args_bytes = unsafe {
2140 std::slice::from_raw_parts(
2141 &args as *const ManagerCreateArgs as *const u8,
2142 std::mem::size_of::<ManagerCreateArgs>(),
2143 )
2144 };
2145 instruction.extend_from_slice(args_bytes);
2146
2147 instruction.extend_from_slice(seed);
2149
2150 if let Some(proof_bytes) = proof {
2152 instruction.extend_from_slice(proof_bytes);
2153 }
2154
2155 Ok(instruction)
2156}
2157
2158fn build_abi_manager_create_instruction(
2160 discriminant: u8,
2161 program_meta_account_idx: u16,
2162 abi_account_idx: u16,
2163 srcbuf_account_idx: u16,
2164 srcbuf_offset: u32,
2165 srcbuf_size: u32,
2166 authority_account_idx: u16,
2167 seed: &[u8],
2168 proof: Option<&[u8]>,
2169) -> Result<Vec<u8>> {
2170 let mut instruction = Vec::new();
2171
2172 let mut seed_bytes = [0u8; 32];
2174 if seed.len() <= 32 {
2175 seed_bytes[..seed.len()].copy_from_slice(seed);
2176 } else {
2177 use sha2::{Digest, Sha256};
2179 let hash = Sha256::digest(seed);
2180 seed_bytes.copy_from_slice(&hash);
2181 }
2182
2183 instruction.push(discriminant);
2185
2186 let args = AbiManagerCreateArgs {
2187 program_meta_account_idx,
2188 abi_account_idx,
2189 srcbuf_account_idx,
2190 srcbuf_offset,
2191 srcbuf_size,
2192 authority_account_idx,
2193 seed: seed_bytes,
2194 };
2195
2196 let args_bytes = unsafe {
2197 std::slice::from_raw_parts(
2198 &args as *const AbiManagerCreateArgs as *const u8,
2199 std::mem::size_of::<AbiManagerCreateArgs>(),
2200 )
2201 };
2202
2203 instruction.extend_from_slice(args_bytes);
2204 if let Some(proof_bytes) = proof {
2207 instruction.extend_from_slice(proof_bytes);
2208 }
2209
2210 Ok(instruction)
2211}
2212
2213fn build_abi_manager_upgrade_instruction(
2214 program_meta_account_idx: u16,
2215 abi_account_idx: u16,
2216 srcbuf_account_idx: u16,
2217 srcbuf_offset: u32,
2218 srcbuf_size: u32,
2219 authority_account_idx: u16,
2220) -> Result<Vec<u8>> {
2221 let mut instruction = Vec::new();
2222
2223 instruction.push(ABI_MANAGER_INSTRUCTION_UPGRADE);
2225
2226 let args = AbiManagerUpgradeArgs {
2227 program_meta_account_idx,
2228 abi_account_idx,
2229 srcbuf_account_idx,
2230 srcbuf_offset,
2231 srcbuf_size,
2232 authority_account_idx,
2233 };
2234
2235 let args_bytes = unsafe {
2236 std::slice::from_raw_parts(
2237 &args as *const AbiManagerUpgradeArgs as *const u8,
2238 std::mem::size_of::<AbiManagerUpgradeArgs>(),
2239 )
2240 };
2241
2242 instruction.extend_from_slice(args_bytes);
2243 Ok(instruction)
2244}
2245
2246fn build_abi_manager_finalize_instruction(
2247 program_meta_account_idx: u16,
2248 abi_account_idx: u16,
2249 authority_account_idx: u16,
2250) -> Result<Vec<u8>> {
2251 let mut instruction = Vec::new();
2252
2253 instruction.push(ABI_MANAGER_INSTRUCTION_FINALIZE);
2255
2256 let args = AbiManagerFinalizeArgs {
2257 program_meta_account_idx,
2258 abi_account_idx,
2259 authority_account_idx,
2260 };
2261
2262 let args_bytes = unsafe {
2263 std::slice::from_raw_parts(
2264 &args as *const AbiManagerFinalizeArgs as *const u8,
2265 std::mem::size_of::<AbiManagerFinalizeArgs>(),
2266 )
2267 };
2268
2269 instruction.extend_from_slice(args_bytes);
2270 Ok(instruction)
2271}
2272
2273fn build_abi_manager_close_instruction(
2274 program_meta_account_idx: u16,
2275 abi_account_idx: u16,
2276 authority_account_idx: u16,
2277) -> Result<Vec<u8>> {
2278 let mut instruction = Vec::new();
2279
2280 instruction.push(ABI_MANAGER_INSTRUCTION_CLOSE);
2282
2283 let args = AbiManagerCloseArgs {
2284 program_meta_account_idx,
2285 abi_account_idx,
2286 authority_account_idx,
2287 };
2288
2289 let args_bytes = unsafe {
2290 std::slice::from_raw_parts(
2291 &args as *const AbiManagerCloseArgs as *const u8,
2292 std::mem::size_of::<AbiManagerCloseArgs>(),
2293 )
2294 };
2295
2296 instruction.extend_from_slice(args_bytes);
2297 Ok(instruction)
2298}
2299
2300fn build_manager_upgrade_instruction(
2302 meta_account_idx: u16,
2303 program_account_idx: u16,
2304 srcbuf_account_idx: u16,
2305 srcbuf_offset: u32,
2306 srcbuf_size: u32,
2307) -> Result<Vec<u8>> {
2308 let mut instruction = Vec::new();
2309
2310 let args = ManagerUpgradeArgs {
2311 discriminant: MANAGER_INSTRUCTION_UPGRADE,
2312 meta_account_idx,
2313 program_account_idx,
2314 srcbuf_account_idx,
2315 srcbuf_offset,
2316 srcbuf_size,
2317 };
2318
2319 let args_bytes = unsafe {
2320 std::slice::from_raw_parts(
2321 &args as *const ManagerUpgradeArgs as *const u8,
2322 std::mem::size_of::<ManagerUpgradeArgs>(),
2323 )
2324 };
2325 instruction.extend_from_slice(args_bytes);
2326
2327 Ok(instruction)
2328}
2329
2330fn build_manager_set_pause_instruction(
2332 meta_account_idx: u16,
2333 program_account_idx: u16,
2334 is_paused: bool,
2335) -> Result<Vec<u8>> {
2336 let mut instruction = Vec::new();
2337
2338 let args = ManagerSetPauseArgs {
2339 discriminant: MANAGER_INSTRUCTION_SET_PAUSE,
2340 meta_account_idx,
2341 program_account_idx,
2342 is_paused: if is_paused { 1 } else { 0 },
2343 };
2344
2345 let args_bytes = unsafe {
2346 std::slice::from_raw_parts(
2347 &args as *const ManagerSetPauseArgs as *const u8,
2348 std::mem::size_of::<ManagerSetPauseArgs>(),
2349 )
2350 };
2351 instruction.extend_from_slice(args_bytes);
2352
2353 Ok(instruction)
2354}
2355
2356fn build_manager_header_instruction(
2358 discriminant: u8,
2359 meta_account_idx: u16,
2360 program_account_idx: u16,
2361) -> Result<Vec<u8>> {
2362 let mut instruction = Vec::new();
2363
2364 let args = ManagerHeaderArgs {
2365 discriminant,
2366 meta_account_idx,
2367 program_account_idx,
2368 };
2369
2370 let args_bytes = unsafe {
2371 std::slice::from_raw_parts(
2372 &args as *const ManagerHeaderArgs as *const u8,
2373 std::mem::size_of::<ManagerHeaderArgs>(),
2374 )
2375 };
2376 instruction.extend_from_slice(args_bytes);
2377
2378 Ok(instruction)
2379}
2380
2381fn build_manager_set_authority_instruction(
2383 meta_account_idx: u16,
2384 program_account_idx: u16,
2385 authority_candidate: [u8; 32],
2386) -> Result<Vec<u8>> {
2387 let mut instruction = Vec::new();
2388
2389 let args = ManagerSetAuthorityArgs {
2390 discriminant: MANAGER_INSTRUCTION_SET_AUTHORITY,
2391 meta_account_idx,
2392 program_account_idx,
2393 authority_candidate,
2394 };
2395
2396 let args_bytes = unsafe {
2397 std::slice::from_raw_parts(
2398 &args as *const ManagerSetAuthorityArgs as *const u8,
2399 std::mem::size_of::<ManagerSetAuthorityArgs>(),
2400 )
2401 };
2402 instruction.extend_from_slice(args_bytes);
2403
2404 Ok(instruction)
2405}
2406
2407fn build_test_uploader_create_instruction(
2409 account_idx: u16,
2410 account_sz: u32,
2411 seed: &[u8],
2412 is_ephemeral: bool,
2413 state_proof: Option<&[u8]>,
2414) -> Result<Vec<u8>> {
2415 let mut instruction = Vec::new();
2416
2417 instruction.push(TN_TEST_UPLOADER_PROGRAM_DISCRIMINANT_CREATE);
2419
2420 let args = TestUploaderCreateArgs {
2422 account_idx,
2423 is_ephemeral: if is_ephemeral { 1u8 } else { 0u8 },
2424 account_sz,
2425 seed_len: seed.len() as u32,
2426 };
2427
2428 let args_bytes = unsafe {
2430 std::slice::from_raw_parts(
2431 &args as *const _ as *const u8,
2432 std::mem::size_of::<TestUploaderCreateArgs>(),
2433 )
2434 };
2435 instruction.extend_from_slice(args_bytes);
2436
2437 instruction.extend_from_slice(seed);
2439
2440 if let Some(proof) = state_proof {
2442 instruction.extend_from_slice(proof);
2443 }
2444
2445 Ok(instruction)
2446}
2447
2448fn build_test_uploader_write_instruction(
2450 target_account_idx: u16,
2451 target_offset: u32,
2452 data: &[u8],
2453) -> Result<Vec<u8>> {
2454 let mut instruction = Vec::new();
2455
2456 instruction.push(TN_TEST_UPLOADER_PROGRAM_DISCRIMINANT_WRITE);
2458
2459 let args = TestUploaderWriteArgs {
2461 target_account_idx,
2462 target_offset,
2463 data_len: data.len() as u32,
2464 };
2465
2466 let args_bytes = unsafe {
2468 std::slice::from_raw_parts(
2469 &args as *const _ as *const u8,
2470 std::mem::size_of::<TestUploaderWriteArgs>(),
2471 )
2472 };
2473 instruction.extend_from_slice(args_bytes);
2474
2475 instruction.extend_from_slice(data);
2477
2478 Ok(instruction)
2479}
2480
2481pub fn build_decompress2_instruction(
2483 target_account_idx: u16,
2484 meta_account_idx: u16,
2485 data_account_idx: u16,
2486 data_offset: u32,
2487 state_proof: &[u8],
2488) -> Result<Vec<u8>> {
2489 let mut instruction = Vec::new();
2490
2491 instruction.push(0x08);
2493
2494 let args = SystemProgramDecompress2Args {
2496 target_account_idx,
2497 meta_account_idx,
2498 data_account_idx,
2499 data_offset,
2500 };
2501
2502 let args_bytes = unsafe {
2504 std::slice::from_raw_parts(
2505 &args as *const _ as *const u8,
2506 std::mem::size_of::<SystemProgramDecompress2Args>(),
2507 )
2508 };
2509 instruction.extend_from_slice(args_bytes);
2510
2511 instruction.extend_from_slice(state_proof);
2513
2514 Ok(instruction)
2515}
2516
2517pub const TOKEN_INSTRUCTION_INITIALIZE_MINT: u8 = 0x00;
2519pub const TOKEN_INSTRUCTION_INITIALIZE_ACCOUNT: u8 = 0x01;
2520pub const TOKEN_INSTRUCTION_TRANSFER: u8 = 0x02;
2521pub const TOKEN_INSTRUCTION_MINT_TO: u8 = 0x03;
2522pub const TOKEN_INSTRUCTION_BURN: u8 = 0x04;
2523pub const TOKEN_INSTRUCTION_CLOSE_ACCOUNT: u8 = 0x05;
2524pub const TOKEN_INSTRUCTION_FREEZE_ACCOUNT: u8 = 0x06;
2525pub const TOKEN_INSTRUCTION_THAW_ACCOUNT: u8 = 0x07;
2526
2527pub const TN_WTHRU_INSTRUCTION_INITIALIZE_MINT: u32 = 0;
2529pub const TN_WTHRU_INSTRUCTION_DEPOSIT: u32 = 1;
2530pub const TN_WTHRU_INSTRUCTION_WITHDRAW: u32 = 2;
2531pub const TN_NAME_SERVICE_INSTRUCTION_INITIALIZE_ROOT: u32 = 0;
2537pub const TN_NAME_SERVICE_INSTRUCTION_REGISTER_SUBDOMAIN: u32 = 1;
2538pub const TN_NAME_SERVICE_INSTRUCTION_APPEND_RECORD: u32 = 2;
2539pub const TN_NAME_SERVICE_INSTRUCTION_DELETE_RECORD: u32 = 3;
2540pub const TN_NAME_SERVICE_INSTRUCTION_UNREGISTER: u32 = 4;
2541
2542pub const TN_NAME_SERVICE_PROOF_INLINE: u32 = 0;
2544
2545pub const TN_NAME_SERVICE_MAX_DOMAIN_LENGTH: usize = 64;
2547pub const TN_NAME_SERVICE_MAX_KEY_LENGTH: usize = 32;
2548pub const TN_NAME_SERVICE_MAX_VALUE_LENGTH: usize = 256;
2549
2550pub const TN_THRU_REGISTRAR_INSTRUCTION_INITIALIZE_REGISTRY: u32 = 0;
2552pub const TN_THRU_REGISTRAR_INSTRUCTION_PURCHASE_DOMAIN: u32 = 1;
2553pub const TN_THRU_REGISTRAR_INSTRUCTION_RENEW_LEASE: u32 = 2;
2554pub const TN_THRU_REGISTRAR_INSTRUCTION_CLAIM_EXPIRED_DOMAIN: u32 = 3;
2555
2556fn add_sorted_accounts(tx: Transaction, accounts: &[(TnPubkey, bool)]) -> (Transaction, Vec<u16>) {
2558 let mut rw_accounts: Vec<_> = accounts.iter().enumerate()
2560 .filter(|(_, (_, writable))| *writable)
2561 .collect();
2562 let mut ro_accounts: Vec<_> = accounts.iter().enumerate()
2563 .filter(|(_, (_, writable))| !*writable)
2564 .collect();
2565
2566 rw_accounts.sort_by(|a, b| a.1.0.cmp(&b.1.0));
2568 ro_accounts.sort_by(|a, b| a.1.0.cmp(&b.1.0));
2569
2570 let mut updated_tx = tx;
2571 let mut indices = vec![0u16; accounts.len()];
2572 let mut seen: HashMap<TnPubkey, u16> = HashMap::new();
2573 seen.insert(updated_tx.fee_payer, 0u16);
2574 seen.insert(updated_tx.program, 1u16);
2575
2576 let mut next_idx = 2u16;
2577
2578 for (i, (account, _)) in rw_accounts.iter() {
2580 if let Some(idx) = seen.get(account) {
2581 indices[*i] = *idx;
2582 continue;
2583 }
2584
2585 let account_idx = next_idx;
2586 next_idx = next_idx.saturating_add(1);
2587 seen.insert(*account, account_idx);
2588 indices[*i] = account_idx;
2589
2590 updated_tx = updated_tx.add_rw_account(*account);
2591 }
2592
2593 for (i, (account, _)) in ro_accounts.iter() {
2595 if let Some(idx) = seen.get(account) {
2596 indices[*i] = *idx;
2597 continue;
2598 }
2599
2600 let account_idx = next_idx;
2601 next_idx = next_idx.saturating_add(1);
2602 seen.insert(*account, account_idx);
2603 indices[*i] = account_idx;
2604
2605 updated_tx = updated_tx.add_r_account(*account);
2606 }
2607
2608 (updated_tx, indices)
2609}
2610
2611fn add_sorted_rw_accounts(mut tx: Transaction, accounts: &[TnPubkey]) -> (Transaction, Vec<u16>) {
2613 if accounts.is_empty() {
2614 return (tx, Vec::new());
2615 }
2616
2617 let mut sorted: Vec<(usize, TnPubkey)> = accounts.iter().cloned().enumerate().collect();
2618 sorted.sort_by(|a, b| a.1.cmp(&b.1));
2619
2620 let mut indices = vec![0u16; accounts.len()];
2621 for (pos, (orig_idx, account)) in sorted.into_iter().enumerate() {
2622 let idx = (2 + pos) as u16;
2623 indices[orig_idx] = idx;
2624 tx = tx.add_rw_account(account);
2625 }
2626
2627 (tx, indices)
2628}
2629
2630fn add_sorted_ro_accounts(
2631 mut tx: Transaction,
2632 base_idx: u16,
2633 accounts: &[TnPubkey],
2634) -> (Transaction, Vec<u16>) {
2635 if accounts.is_empty() {
2636 return (tx, Vec::new());
2637 }
2638
2639 let mut sorted: Vec<(usize, TnPubkey)> = accounts.iter().cloned().enumerate().collect();
2640 sorted.sort_by(|a, b| a.1.cmp(&b.1));
2641
2642 let mut indices = vec![0u16; accounts.len()];
2643 for (pos, (orig_idx, account)) in sorted.into_iter().enumerate() {
2644 let idx = base_idx + pos as u16;
2645 indices[orig_idx] = idx;
2646 tx = tx.add_r_account(account);
2647 }
2648
2649 (tx, indices)
2650}
2651
2652impl TransactionBuilder {
2653 pub fn build_token_initialize_mint(
2655 fee_payer: TnPubkey,
2656 token_program: TnPubkey,
2657 mint_account: TnPubkey,
2658 creator: TnPubkey,
2659 mint_authority: TnPubkey,
2660 freeze_authority: Option<TnPubkey>,
2661 decimals: u8,
2662 ticker: &str,
2663 seed: [u8; 32],
2664 state_proof: Vec<u8>,
2665 fee: u64,
2666 nonce: u64,
2667 start_slot: u64,
2668 ) -> Result<Transaction> {
2669 let base_tx =
2670 Transaction::new(fee_payer, token_program, fee, nonce).with_start_slot(start_slot);
2671 let (tx, indices) = add_sorted_rw_accounts(base_tx, &[mint_account]);
2672 let mint_account_idx = indices[0];
2673
2674 let instruction_data = build_token_initialize_mint_instruction(
2675 mint_account_idx,
2676 decimals,
2677 creator,
2678 mint_authority,
2679 freeze_authority,
2680 ticker,
2681 seed,
2682 state_proof,
2683 )?;
2684
2685 let tx = tx
2686 .with_instructions(instruction_data)
2687 .with_expiry_after(100)
2688 .with_compute_units(300_000)
2689 .with_state_units(10_000)
2690 .with_memory_units(10_000);
2691
2692 Ok(tx)
2693 }
2694
2695 pub fn build_token_initialize_account(
2697 fee_payer: TnPubkey,
2698 token_program: TnPubkey,
2699 token_account: TnPubkey,
2700 mint_account: TnPubkey,
2701 owner: TnPubkey,
2702 seed: [u8; 32],
2703 state_proof: Vec<u8>,
2704 fee: u64,
2705 nonce: u64,
2706 start_slot: u64,
2707 ) -> Result<Transaction> {
2708 let owner_is_fee_payer = owner == fee_payer;
2709
2710 let mut rw_accounts = vec![token_account];
2711 rw_accounts.sort();
2712
2713 let mut ro_accounts = vec![mint_account];
2714 if !owner_is_fee_payer {
2715 ro_accounts.push(owner);
2716 ro_accounts.sort();
2717 }
2718
2719 let mut tx =
2720 Transaction::new(fee_payer, token_program, fee, nonce).with_start_slot(start_slot);
2721
2722 let mut token_account_idx = 0u16;
2723 for (i, account) in rw_accounts.iter().enumerate() {
2724 let idx = (2 + i) as u16;
2725 if *account == token_account {
2726 token_account_idx = idx;
2727 }
2728 tx = tx.add_rw_account(*account);
2729 }
2730
2731 let base_ro_idx = 2 + rw_accounts.len() as u16;
2732 let mut mint_account_idx = 0u16;
2733 let mut owner_account_idx = if owner_is_fee_payer { 0u16 } else { 0u16 };
2734 for (i, account) in ro_accounts.iter().enumerate() {
2735 let idx = base_ro_idx + i as u16;
2736 if *account == mint_account {
2737 mint_account_idx = idx;
2738 } else if !owner_is_fee_payer && *account == owner {
2739 owner_account_idx = idx;
2740 }
2741 tx = tx.add_r_account(*account);
2742 }
2743
2744 let instruction_data = build_token_initialize_account_instruction(
2745 token_account_idx,
2746 mint_account_idx,
2747 owner_account_idx,
2748 seed,
2749 state_proof,
2750 )?;
2751
2752 let tx = tx
2753 .with_instructions(instruction_data)
2754 .with_expiry_after(100)
2755 .with_compute_units(300_000)
2756 .with_state_units(10_000)
2757 .with_memory_units(10_000);
2758
2759 Ok(tx)
2760 }
2761
2762 pub fn build_token_transfer(
2764 fee_payer: TnPubkey,
2765 token_program: TnPubkey,
2766 source_account: TnPubkey,
2767 dest_account: TnPubkey,
2768 _authority: TnPubkey,
2769 amount: u64,
2770 fee: u64,
2771 nonce: u64,
2772 start_slot: u64,
2773 ) -> Result<Transaction> {
2774 let mut tx = Transaction::new(fee_payer, token_program, fee, nonce)
2775 .with_start_slot(start_slot)
2776 .with_expiry_after(100)
2777 .with_compute_units(300_000)
2778 .with_state_units(10_000)
2779 .with_memory_units(10_000);
2780
2781 let is_self_transfer = source_account == dest_account;
2782 let (source_account_idx, dest_account_idx) = if is_self_transfer {
2783 tx = tx.add_rw_account(source_account);
2785 (2u16, 2u16)
2786 } else {
2787 let accounts = &[(source_account, true), (dest_account, true)];
2789 let (updated_tx, indices) = add_sorted_accounts(tx, accounts);
2790 tx = updated_tx;
2791 (indices[0], indices[1])
2792 };
2793
2794 let instruction_data =
2798 build_token_transfer_instruction(source_account_idx, dest_account_idx, amount)?;
2799
2800 Ok(tx.with_instructions(instruction_data))
2801 }
2802
2803 pub fn build_token_mint_to(
2805 fee_payer: TnPubkey,
2806 token_program: TnPubkey,
2807 mint_account: TnPubkey,
2808 dest_account: TnPubkey,
2809 authority: TnPubkey,
2810 amount: u64,
2811 fee: u64,
2812 nonce: u64,
2813 start_slot: u64,
2814 ) -> Result<Transaction> {
2815 let base_tx = Transaction::new(fee_payer, token_program, fee, nonce)
2816 .with_start_slot(start_slot)
2817 .with_expiry_after(100)
2818 .with_compute_units(300_000)
2819 .with_state_units(10_000)
2820 .with_memory_units(10_000);
2821
2822 let (tx_after_rw, rw_indices) =
2823 add_sorted_rw_accounts(base_tx, &[mint_account, dest_account]);
2824 let mint_account_idx = rw_indices[0];
2825 let dest_account_idx = rw_indices[1];
2826
2827 let mut tx = tx_after_rw;
2828 let authority_account_idx = if authority == fee_payer {
2829 0u16
2830 } else {
2831 let base_ro_idx = 2 + rw_indices.len() as u16;
2832 let (tx_after_ro, ro_indices) = add_sorted_ro_accounts(tx, base_ro_idx, &[authority]);
2833 tx = tx_after_ro;
2834 ro_indices[0]
2835 };
2836
2837 let instruction_data = build_token_mint_to_instruction(
2838 mint_account_idx,
2839 dest_account_idx,
2840 authority_account_idx,
2841 amount,
2842 )?;
2843
2844 Ok(tx.with_instructions(instruction_data))
2845 }
2846
2847 pub fn build_token_burn(
2849 fee_payer: TnPubkey,
2850 token_program: TnPubkey,
2851 token_account: TnPubkey,
2852 mint_account: TnPubkey,
2853 authority: TnPubkey,
2854 amount: u64,
2855 fee: u64,
2856 nonce: u64,
2857 start_slot: u64,
2858 ) -> Result<Transaction> {
2859 let base_tx = Transaction::new(fee_payer, token_program, fee, nonce)
2860 .with_start_slot(start_slot)
2861 .with_expiry_after(100)
2862 .with_compute_units(300_000)
2863 .with_state_units(10_000)
2864 .with_memory_units(10_000);
2865
2866 let (tx_after_rw, rw_indices) =
2867 add_sorted_rw_accounts(base_tx, &[token_account, mint_account]);
2868 let token_account_idx = rw_indices[0];
2869 let mint_account_idx = rw_indices[1];
2870
2871 let mut tx = tx_after_rw;
2872 let authority_account_idx = if authority == fee_payer {
2873 0u16
2874 } else {
2875 let base_ro_idx = 2 + rw_indices.len() as u16;
2876 let (tx_after_ro, ro_indices) = add_sorted_ro_accounts(tx, base_ro_idx, &[authority]);
2877 tx = tx_after_ro;
2878 ro_indices[0]
2879 };
2880
2881 let instruction_data = build_token_burn_instruction(
2882 token_account_idx,
2883 mint_account_idx,
2884 authority_account_idx,
2885 amount,
2886 )?;
2887
2888 Ok(tx.with_instructions(instruction_data))
2889 }
2890
2891 pub fn build_token_freeze_account(
2893 fee_payer: TnPubkey,
2894 token_program: TnPubkey,
2895 token_account: TnPubkey,
2896 mint_account: TnPubkey,
2897 authority: TnPubkey,
2898 fee: u64,
2899 nonce: u64,
2900 start_slot: u64,
2901 ) -> Result<Transaction> {
2902 let base_tx = Transaction::new(fee_payer, token_program, fee, nonce)
2903 .with_start_slot(start_slot)
2904 .with_expiry_after(100)
2905 .with_compute_units(300_000)
2906 .with_state_units(10_000)
2907 .with_memory_units(10_000);
2908
2909 let (tx_after_rw, rw_indices) =
2910 add_sorted_rw_accounts(base_tx, &[token_account, mint_account]);
2911 let token_account_idx = rw_indices[0];
2912 let mint_account_idx = rw_indices[1];
2913
2914 let mut tx = tx_after_rw;
2915 let authority_account_idx = if authority == fee_payer {
2916 0u16
2917 } else {
2918 let base_ro_idx = 2 + rw_indices.len() as u16;
2919 let (tx_after_ro, ro_indices) = add_sorted_ro_accounts(tx, base_ro_idx, &[authority]);
2920 tx = tx_after_ro;
2921 ro_indices[0]
2922 };
2923
2924 let instruction_data = build_token_freeze_account_instruction(
2925 token_account_idx,
2926 mint_account_idx,
2927 authority_account_idx,
2928 )?;
2929
2930 Ok(tx.with_instructions(instruction_data))
2931 }
2932
2933 pub fn build_token_thaw_account(
2935 fee_payer: TnPubkey,
2936 token_program: TnPubkey,
2937 token_account: TnPubkey,
2938 mint_account: TnPubkey,
2939 authority: TnPubkey,
2940 fee: u64,
2941 nonce: u64,
2942 start_slot: u64,
2943 ) -> Result<Transaction> {
2944 let base_tx = Transaction::new(fee_payer, token_program, fee, nonce)
2945 .with_start_slot(start_slot)
2946 .with_expiry_after(100)
2947 .with_compute_units(300_000)
2948 .with_state_units(10_000)
2949 .with_memory_units(10_000);
2950
2951 let (tx_after_rw, rw_indices) =
2952 add_sorted_rw_accounts(base_tx, &[token_account, mint_account]);
2953 let token_account_idx = rw_indices[0];
2954 let mint_account_idx = rw_indices[1];
2955
2956 let mut tx = tx_after_rw;
2957 let authority_account_idx = if authority == fee_payer {
2958 0u16
2959 } else {
2960 let base_ro_idx = 2 + rw_indices.len() as u16;
2961 let (tx_after_ro, ro_indices) = add_sorted_ro_accounts(tx, base_ro_idx, &[authority]);
2962 tx = tx_after_ro;
2963 ro_indices[0]
2964 };
2965
2966 let instruction_data = build_token_thaw_account_instruction(
2967 token_account_idx,
2968 mint_account_idx,
2969 authority_account_idx,
2970 )?;
2971
2972 Ok(tx.with_instructions(instruction_data))
2973 }
2974
2975 pub fn build_token_close_account(
2977 fee_payer: TnPubkey,
2978 token_program: TnPubkey,
2979 token_account: TnPubkey,
2980 destination: TnPubkey,
2981 authority: TnPubkey,
2982 fee: u64,
2983 nonce: u64,
2984 start_slot: u64,
2985 ) -> Result<Transaction> {
2986 let base_tx = Transaction::new(fee_payer, token_program, fee, nonce)
2987 .with_start_slot(start_slot)
2988 .with_expiry_after(100)
2989 .with_compute_units(300_000)
2990 .with_state_units(10_000)
2991 .with_memory_units(10_000);
2992
2993 let mut rw_accounts = vec![token_account];
2994 let destination_in_accounts = destination != fee_payer;
2995 if destination_in_accounts {
2996 rw_accounts.push(destination);
2997 }
2998
2999 let (tx_after_rw, rw_indices) = add_sorted_rw_accounts(base_tx, &rw_accounts);
3000 let token_account_idx = rw_indices[0];
3001 let destination_idx = if destination_in_accounts {
3002 rw_indices[1]
3003 } else {
3004 0u16
3005 };
3006
3007 let mut tx = tx_after_rw;
3008 let authority_account_idx = if authority == fee_payer {
3009 0u16
3010 } else {
3011 let base_ro_idx = 2 + rw_indices.len() as u16;
3012 let (tx_after_ro, ro_indices) = add_sorted_ro_accounts(tx, base_ro_idx, &[authority]);
3013 tx = tx_after_ro;
3014 ro_indices[0]
3015 };
3016
3017 let instruction_data = build_token_close_account_instruction(
3018 token_account_idx,
3019 destination_idx,
3020 authority_account_idx,
3021 )?;
3022
3023 Ok(tx.with_instructions(instruction_data))
3024 }
3025
3026 pub fn build_wthru_initialize_mint(
3028 fee_payer: TnPubkey,
3029 wthru_program: TnPubkey,
3030 token_program: TnPubkey,
3031 mint_account: TnPubkey,
3032 vault_account: TnPubkey,
3033 decimals: u8,
3034 mint_seed: [u8; 32],
3035 mint_proof: Vec<u8>,
3036 vault_proof: Vec<u8>,
3037 fee: u64,
3038 nonce: u64,
3039 start_slot: u64,
3040 ) -> Result<Transaction> {
3041 let mut tx = Transaction::new(fee_payer, wthru_program, fee, nonce)
3042 .with_start_slot(start_slot)
3043 .with_expiry_after(100)
3044 .with_compute_units(500_000)
3045 .with_state_units(10_000)
3046 .with_memory_units(10_000);
3047
3048 let accounts = [
3049 (mint_account, true),
3050 (vault_account, true),
3051 (token_program, false),
3052 ];
3053
3054 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
3055 tx = tx_with_accounts;
3056
3057 let mint_account_idx = indices[0];
3058 let vault_account_idx = indices[1];
3059 let token_program_idx = indices[2];
3060
3061 let instruction_data = build_wthru_initialize_mint_instruction(
3062 token_program_idx,
3063 mint_account_idx,
3064 vault_account_idx,
3065 decimals,
3066 mint_seed,
3067 mint_proof,
3068 vault_proof,
3069 )?;
3070
3071 Ok(tx.with_instructions(instruction_data))
3072 }
3073
3074 pub fn build_wthru_deposit(
3076 fee_payer: TnPubkey,
3077 wthru_program: TnPubkey,
3078 token_program: TnPubkey,
3079 mint_account: TnPubkey,
3080 vault_account: TnPubkey,
3081 dest_token_account: TnPubkey,
3082 fee: u64,
3083 nonce: u64,
3084 start_slot: u64,
3085 ) -> Result<Transaction> {
3086 let mut tx = Transaction::new(fee_payer, wthru_program, fee, nonce)
3087 .with_start_slot(start_slot)
3088 .with_expiry_after(100)
3089 .with_compute_units(400_000)
3090 .with_state_units(10_000)
3091 .with_memory_units(10_000);
3092
3093 let accounts = [
3094 (mint_account, true),
3095 (vault_account, true),
3096 (dest_token_account, true),
3097 (token_program, false),
3098 ];
3099
3100 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
3101 tx = tx_with_accounts;
3102
3103 let mint_account_idx = indices[0];
3104 let vault_account_idx = indices[1];
3105 let dest_account_idx = indices[2];
3106 let token_program_idx = indices[3];
3107
3108 let instruction_data = build_wthru_deposit_instruction(
3109 token_program_idx,
3110 vault_account_idx,
3111 mint_account_idx,
3112 dest_account_idx,
3113 )?;
3114
3115 Ok(tx.with_instructions(instruction_data))
3116 }
3117
3118 pub fn build_wthru_withdraw(
3120 fee_payer: TnPubkey,
3121 wthru_program: TnPubkey,
3122 token_program: TnPubkey,
3123 mint_account: TnPubkey,
3124 vault_account: TnPubkey,
3125 wthru_token_account: TnPubkey,
3126 recipient_account: TnPubkey,
3127 amount: u64,
3128 fee: u64,
3129 nonce: u64,
3130 start_slot: u64,
3131 ) -> Result<Transaction> {
3132 let mut tx = Transaction::new(fee_payer, wthru_program, fee, nonce)
3133 .with_start_slot(start_slot)
3134 .with_expiry_after(100)
3135 .with_compute_units(400_000)
3136 .with_state_units(10_000)
3137 .with_memory_units(10_000);
3138
3139 let accounts = [
3140 (mint_account, true),
3141 (vault_account, true),
3142 (wthru_token_account, true),
3143 (recipient_account, true),
3144 (token_program, false),
3145 ];
3146
3147 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
3148 tx = tx_with_accounts;
3149
3150 let mint_account_idx = indices[0];
3151 let vault_account_idx = indices[1];
3152 let token_account_idx = indices[2];
3153 let recipient_account_idx = indices[3];
3154 let token_program_idx = indices[4];
3155
3156 let owner_account_idx = 0u16; let instruction_data = build_wthru_withdraw_instruction(
3159 token_program_idx,
3160 vault_account_idx,
3161 mint_account_idx,
3162 token_account_idx,
3163 owner_account_idx,
3164 recipient_account_idx,
3165 amount,
3166 )?;
3167
3168 Ok(tx.with_instructions(instruction_data))
3169 }
3170
3171 pub fn build_faucet_deposit(
3174 fee_payer: TnPubkey,
3175 faucet_program: TnPubkey,
3176 faucet_account: TnPubkey,
3177 depositor_account: TnPubkey,
3178 eoa_program: TnPubkey,
3179 amount: u64,
3180 fee: u64,
3181 nonce: u64,
3182 start_slot: u64,
3183 ) -> Result<Transaction> {
3184 let tx = Transaction::new(fee_payer, faucet_program, fee, nonce)
3185 .with_start_slot(start_slot)
3186 .with_expiry_after(100)
3187 .with_compute_units(300_000)
3188 .with_state_units(10_000)
3189 .with_memory_units(10_000);
3190
3191 let (tx, depositor_account_idx) = Self::ensure_rw_account(tx, depositor_account);
3192 let (tx, faucet_account_idx) = Self::ensure_rw_account(tx, faucet_account);
3193 let (tx, eoa_program_idx) = Self::ensure_ro_account(tx, eoa_program);
3194
3195 let instruction_data = build_faucet_deposit_instruction(
3196 faucet_account_idx,
3197 depositor_account_idx,
3198 eoa_program_idx,
3199 amount,
3200 )?;
3201
3202 Ok(tx.with_instructions(instruction_data))
3203 }
3204
3205 fn resolve_account_index(tx: &Transaction, target: &TnPubkey) -> Option<u16> {
3206 if *target == tx.fee_payer {
3207 return Some(0u16);
3208 }
3209
3210 if *target == tx.program {
3211 return Some(1u16);
3212 }
3213
3214 if let Some(ref rw) = tx.rw_accs {
3215 if let Some(pos) = rw.iter().position(|acc| acc == target) {
3216 return Some(2u16 + pos as u16);
3217 }
3218 }
3219
3220 if let Some(ref ro) = tx.r_accs {
3221 let base = 2u16 + tx.rw_accs.as_ref().map_or(0u16, |v| v.len() as u16);
3222 if let Some(pos) = ro.iter().position(|acc| acc == target) {
3223 return Some(base + pos as u16);
3224 }
3225 }
3226
3227 None
3228 }
3229
3230 fn ensure_rw_account(mut tx: Transaction, account: TnPubkey) -> (Transaction, u16) {
3231 if let Some(idx) = Self::resolve_account_index(&tx, &account) {
3232 return (tx, idx);
3233 }
3234
3235 tx = tx.add_rw_account(account);
3236 let idx = Self::resolve_account_index(&tx, &account)
3237 .expect("read-write account index should exist after insertion");
3238
3239 (tx, idx)
3240 }
3241
3242 fn ensure_ro_account(mut tx: Transaction, account: TnPubkey) -> (Transaction, u16) {
3243 if let Some(idx) = Self::resolve_account_index(&tx, &account) {
3244 return (tx, idx);
3245 }
3246
3247 tx = tx.add_r_account(account);
3248 let idx = Self::resolve_account_index(&tx, &account)
3249 .expect("read-only account index should exist after insertion");
3250
3251 (tx, idx)
3252 }
3253
3254 pub fn build_faucet_withdraw(
3256 fee_payer: TnPubkey,
3257 faucet_program: TnPubkey,
3258 faucet_account: TnPubkey,
3259 recipient_account: TnPubkey,
3260 amount: u64,
3261 fee: u64,
3262 nonce: u64,
3263 start_slot: u64,
3264 ) -> Result<Transaction> {
3265 let mut tx = Transaction::new(fee_payer, faucet_program, fee, nonce)
3266 .with_start_slot(start_slot)
3267 .with_expiry_after(100)
3268 .with_compute_units(300_000)
3269 .with_state_units(10_000)
3270 .with_memory_units(10_000);
3271
3272 let faucet_is_fee_payer = faucet_account == fee_payer;
3275 let recipient_is_fee_payer = recipient_account == fee_payer;
3276 let recipient_is_faucet = recipient_account == faucet_account;
3277
3278 let (faucet_account_idx, recipient_account_idx) = if faucet_is_fee_payer && recipient_is_fee_payer {
3279 (0u16, 0u16)
3281 } else if faucet_is_fee_payer {
3282 tx = tx.add_rw_account(recipient_account);
3284 (0u16, 2u16)
3285 } else if recipient_is_fee_payer {
3286 tx = tx.add_rw_account(faucet_account);
3288 (2u16, 0u16)
3289 } else if recipient_is_faucet {
3290 tx = tx.add_rw_account(faucet_account);
3292 (2u16, 2u16)
3293 } else {
3294 if faucet_account < recipient_account {
3296 tx = tx.add_rw_account(faucet_account);
3297 tx = tx.add_rw_account(recipient_account);
3298 (2u16, 3u16)
3299 } else {
3300 tx = tx.add_rw_account(recipient_account);
3301 tx = tx.add_rw_account(faucet_account);
3302 (3u16, 2u16)
3303 }
3304 };
3305
3306 let instruction_data = build_faucet_withdraw_instruction(
3307 faucet_account_idx,
3308 recipient_account_idx,
3309 amount,
3310 )?;
3311
3312 Ok(tx.with_instructions(instruction_data))
3313 }
3314
3315 pub fn build_activate(
3331 fee_payer: TnPubkey,
3332 source_token_account: TnPubkey,
3333 bls_pk: [u8; 96],
3334 claim_authority: TnPubkey,
3335 token_amount: u64,
3336 fee: u64,
3337 nonce: u64,
3338 start_slot: u64,
3339 ) -> Result<Transaction> {
3340 let program: TnPubkey = CONSENSUS_VALIDATOR_PROGRAM;
3341 let attestor_table: TnPubkey = ATTESTOR_TABLE;
3342 let token_program: TnPubkey = TOKEN_PROGRAM;
3343 let converted_vault: TnPubkey = CONVERTED_VAULT;
3344
3345 let tx = Transaction::new(fee_payer, program, fee, nonce)
3346 .with_start_slot(start_slot)
3347 .with_expiry_after(100)
3348 .with_compute_units(500_000_000) .with_state_units(50_000)
3350 .with_memory_units(50_000);
3351
3352 let accounts = [
3357 (attestor_table, true), (source_token_account, true), (converted_vault, true), (token_program, false), ];
3362 let (tx, indices) = add_sorted_accounts(tx, &accounts);
3363 let attestor_table_idx = indices[0];
3364 let source_token_account_idx = indices[1];
3365 let converted_vault_idx = indices[2];
3366 let token_program_idx = indices[3];
3367
3368 let identity_idx = 0u16;
3370
3371 let instruction_data = build_activate_instruction(
3372 attestor_table_idx as u64,
3373 token_program_idx,
3374 source_token_account_idx,
3375 converted_vault_idx,
3376 identity_idx,
3377 bls_pk,
3378 claim_authority,
3379 token_amount,
3380 )?;
3381
3382 Ok(tx.with_instructions(instruction_data))
3383 }
3384
3385 pub fn build_name_service_initialize_root(
3387 fee_payer: TnPubkey,
3388 name_service_program: TnPubkey,
3389 registrar_account: TnPubkey,
3390 authority_account: TnPubkey,
3391 root_name: &str,
3392 state_proof: Vec<u8>,
3393 fee: u64,
3394 nonce: u64,
3395 start_slot: u64,
3396 ) -> Result<Transaction> {
3397 let mut tx = Transaction::new(fee_payer, name_service_program, fee, nonce)
3398 .with_start_slot(start_slot)
3399 .with_expiry_after(100)
3400 .with_compute_units(500_000)
3401 .with_state_units(10_000)
3402 .with_memory_units(10_000);
3403
3404 let accounts = [(registrar_account, true), (authority_account, false)];
3405 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
3406 tx = tx_with_accounts;
3407
3408 let registrar_account_idx = indices[0];
3409 let authority_account_idx = indices[1];
3410
3411 let instruction_data = build_name_service_initialize_root_instruction(
3412 registrar_account_idx,
3413 authority_account_idx,
3414 root_name,
3415 state_proof,
3416 )?;
3417
3418 Ok(tx.with_instructions(instruction_data))
3419 }
3420
3421 pub fn build_name_service_register_subdomain(
3423 fee_payer: TnPubkey,
3424 name_service_program: TnPubkey,
3425 domain_account: TnPubkey,
3426 parent_account: TnPubkey,
3427 owner_account: TnPubkey,
3428 authority_account: TnPubkey,
3429 domain_name: &str,
3430 state_proof: Vec<u8>,
3431 fee: u64,
3432 nonce: u64,
3433 start_slot: u64,
3434 ) -> Result<Transaction> {
3435 let mut tx = Transaction::new(fee_payer, name_service_program, fee, nonce)
3436 .with_start_slot(start_slot)
3437 .with_expiry_after(100)
3438 .with_compute_units(500_000)
3439 .with_state_units(10_000)
3440 .with_memory_units(10_000);
3441
3442 let accounts = [
3443 (domain_account, true),
3444 (parent_account, true),
3445 (owner_account, false),
3446 (authority_account, false),
3447 ];
3448 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
3449 tx = tx_with_accounts;
3450
3451 let domain_account_idx = indices[0];
3452 let parent_account_idx = indices[1];
3453 let owner_account_idx = indices[2];
3454 let authority_account_idx = indices[3];
3455
3456 let instruction_data = build_name_service_register_subdomain_instruction(
3457 domain_account_idx,
3458 parent_account_idx,
3459 owner_account_idx,
3460 authority_account_idx,
3461 domain_name,
3462 state_proof,
3463 )?;
3464
3465 Ok(tx.with_instructions(instruction_data))
3466 }
3467
3468 pub fn build_name_service_append_record(
3470 fee_payer: TnPubkey,
3471 name_service_program: TnPubkey,
3472 domain_account: TnPubkey,
3473 owner_account: TnPubkey,
3474 key: &[u8],
3475 value: &[u8],
3476 fee: u64,
3477 nonce: u64,
3478 start_slot: u64,
3479 ) -> Result<Transaction> {
3480 let mut tx = Transaction::new(fee_payer, name_service_program, fee, nonce)
3481 .with_start_slot(start_slot)
3482 .with_expiry_after(100)
3483 .with_compute_units(250_000)
3484 .with_state_units(10_000)
3485 .with_memory_units(10_000);
3486
3487 let accounts = [(domain_account, true), (owner_account, false)];
3488 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
3489 tx = tx_with_accounts;
3490
3491 let domain_account_idx = indices[0];
3492 let owner_account_idx = indices[1];
3493
3494 let instruction_data = build_name_service_append_record_instruction(
3495 domain_account_idx,
3496 owner_account_idx,
3497 key,
3498 value,
3499 )?;
3500
3501 Ok(tx.with_instructions(instruction_data))
3502 }
3503
3504 pub fn build_name_service_delete_record(
3506 fee_payer: TnPubkey,
3507 name_service_program: TnPubkey,
3508 domain_account: TnPubkey,
3509 owner_account: TnPubkey,
3510 key: &[u8],
3511 fee: u64,
3512 nonce: u64,
3513 start_slot: u64,
3514 ) -> Result<Transaction> {
3515 let mut tx = Transaction::new(fee_payer, name_service_program, fee, nonce)
3516 .with_start_slot(start_slot)
3517 .with_expiry_after(100)
3518 .with_compute_units(200_000)
3519 .with_state_units(10_000)
3520 .with_memory_units(10_000);
3521
3522 let accounts = [(domain_account, true), (owner_account, false)];
3523 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
3524 tx = tx_with_accounts;
3525
3526 let domain_account_idx = indices[0];
3527 let owner_account_idx = indices[1];
3528
3529 let instruction_data = build_name_service_delete_record_instruction(
3530 domain_account_idx,
3531 owner_account_idx,
3532 key,
3533 )?;
3534
3535 Ok(tx.with_instructions(instruction_data))
3536 }
3537
3538 pub fn build_name_service_unregister_subdomain(
3540 fee_payer: TnPubkey,
3541 name_service_program: TnPubkey,
3542 domain_account: TnPubkey,
3543 owner_account: TnPubkey,
3544 fee: u64,
3545 nonce: u64,
3546 start_slot: u64,
3547 ) -> Result<Transaction> {
3548 let mut tx = Transaction::new(fee_payer, name_service_program, fee, nonce)
3549 .with_start_slot(start_slot)
3550 .with_expiry_after(100)
3551 .with_compute_units(200_000)
3552 .with_state_units(10_000)
3553 .with_memory_units(10_000);
3554
3555 let accounts = [(domain_account, true), (owner_account, false)];
3556 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
3557 tx = tx_with_accounts;
3558
3559 let domain_account_idx = indices[0];
3560 let owner_account_idx = indices[1];
3561
3562 let instruction_data = build_name_service_unregister_subdomain_instruction(
3563 domain_account_idx,
3564 owner_account_idx,
3565 )?;
3566
3567 Ok(tx.with_instructions(instruction_data))
3568 }
3569
3570 pub fn build_thru_registrar_initialize_registry(
3572 fee_payer: TnPubkey,
3573 thru_registrar_program: TnPubkey,
3574 config_account: TnPubkey,
3575 name_service_program: TnPubkey,
3576 root_registrar_account: TnPubkey,
3577 treasurer_account: TnPubkey,
3578 token_mint_account: TnPubkey,
3579 token_program: TnPubkey,
3580 root_domain_name: &str,
3581 price_per_year: u64,
3582 config_proof: Vec<u8>,
3583 registrar_proof: Vec<u8>,
3584 fee: u64,
3585 nonce: u64,
3586 start_slot: u64,
3587 ) -> Result<Transaction> {
3588 let mut tx = Transaction::new(fee_payer, thru_registrar_program, fee, nonce)
3589 .with_start_slot(start_slot)
3590 .with_expiry_after(100)
3591 .with_compute_units(500_000)
3592 .with_state_units(10_000)
3593 .with_memory_units(10_000);
3594
3595 let mut rw_accounts = vec![config_account, root_registrar_account];
3598 rw_accounts.sort();
3599
3600 let mut ro_accounts = vec![
3601 name_service_program,
3602 treasurer_account,
3603 token_mint_account,
3604 token_program,
3605 ];
3606 ro_accounts.sort();
3607
3608 let mut config_account_idx = 0u16;
3610 let mut root_registrar_account_idx = 0u16;
3611 for (i, account) in rw_accounts.iter().enumerate() {
3612 let idx = (2 + i) as u16;
3613 if *account == config_account {
3614 config_account_idx = idx;
3615 } else if *account == root_registrar_account {
3616 root_registrar_account_idx = idx;
3617 }
3618 tx = tx.add_rw_account(*account);
3619 }
3620
3621 let base_ro_idx = 2 + rw_accounts.len() as u16;
3623 let mut name_service_program_idx = 0u16;
3624 let mut treasurer_account_idx = 0u16;
3625 let mut token_mint_account_idx = 0u16;
3626 let mut token_program_idx = 0u16;
3627
3628 for (i, account) in ro_accounts.iter().enumerate() {
3629 let idx = base_ro_idx + i as u16;
3630 if *account == name_service_program {
3631 name_service_program_idx = idx;
3632 } else if *account == root_registrar_account {
3633 root_registrar_account_idx = idx;
3634 } else if *account == treasurer_account {
3635 treasurer_account_idx = idx;
3636 } else if *account == token_mint_account {
3637 token_mint_account_idx = idx;
3638 } else if *account == token_program {
3639 token_program_idx = idx;
3640 }
3641 tx = tx.add_r_account(*account);
3642 }
3643
3644 let instruction_data = build_thru_registrar_initialize_registry_instruction(
3645 config_account_idx,
3646 name_service_program_idx,
3647 root_registrar_account_idx,
3648 treasurer_account_idx,
3649 token_mint_account_idx,
3650 token_program_idx,
3651 root_domain_name,
3652 price_per_year,
3653 config_proof,
3654 registrar_proof,
3655 )?;
3656
3657 Ok(tx.with_instructions(instruction_data))
3658 }
3659
3660 pub fn build_thru_registrar_purchase_domain(
3662 fee_payer: TnPubkey,
3663 thru_registrar_program: TnPubkey,
3664 config_account: TnPubkey,
3665 lease_account: TnPubkey,
3666 domain_account: TnPubkey,
3667 name_service_program: TnPubkey,
3668 root_registrar_account: TnPubkey,
3669 treasurer_account: TnPubkey,
3670 payer_token_account: TnPubkey,
3671 token_mint_account: TnPubkey,
3672 token_program: TnPubkey,
3673 domain_name: &str,
3674 years: u8,
3675 lease_proof: Vec<u8>,
3676 domain_proof: Vec<u8>,
3677 fee: u64,
3678 nonce: u64,
3679 start_slot: u64,
3680 ) -> Result<Transaction> {
3681 let mut tx = Transaction::new(fee_payer, thru_registrar_program, fee, nonce)
3682 .with_start_slot(start_slot)
3683 .with_expiry_after(100)
3684 .with_compute_units(500_000)
3685 .with_state_units(10_000)
3686 .with_memory_units(10_000);
3687
3688 let mut rw_accounts = vec![
3691 config_account,
3692 lease_account,
3693 domain_account,
3694 treasurer_account,
3695 payer_token_account,
3696 root_registrar_account,
3697 ];
3698 rw_accounts.sort();
3699
3700 let mut ro_accounts = vec![
3701 name_service_program,
3702 token_mint_account,
3703 token_program,
3704 ];
3705 ro_accounts.sort();
3706
3707 let mut config_account_idx = 0u16;
3709 let mut lease_account_idx = 0u16;
3710 let mut domain_account_idx = 0u16;
3711 let mut treasurer_account_idx = 0u16;
3712 let mut payer_token_account_idx = 0u16;
3713 let mut root_registrar_account_idx = 0u16;
3714 for (i, account) in rw_accounts.iter().enumerate() {
3715 let idx = (2 + i) as u16;
3716 if *account == config_account {
3717 config_account_idx = idx;
3718 } else if *account == lease_account {
3719 lease_account_idx = idx;
3720 } else if *account == domain_account {
3721 domain_account_idx = idx;
3722 } else if *account == treasurer_account {
3723 treasurer_account_idx = idx;
3724 } else if *account == payer_token_account {
3725 payer_token_account_idx = idx;
3726 } else if *account == root_registrar_account {
3727 root_registrar_account_idx = idx;
3728 }
3729 tx = tx.add_rw_account(*account);
3730 }
3731
3732 let base_ro_idx = 2 + rw_accounts.len() as u16;
3734 let mut name_service_program_idx = 0u16;
3735 let mut token_mint_account_idx = 0u16;
3736 let mut token_program_idx = 0u16;
3737
3738 for (i, account) in ro_accounts.iter().enumerate() {
3739 let idx = base_ro_idx + i as u16;
3740 if *account == config_account {
3741 config_account_idx = idx; } else if *account == name_service_program {
3743 name_service_program_idx = idx;
3744 } else if *account == root_registrar_account {
3745 root_registrar_account_idx = idx;
3746 } else if *account == treasurer_account {
3747 treasurer_account_idx = idx;
3748 } else if *account == payer_token_account {
3749 payer_token_account_idx = idx;
3750 } else if *account == token_mint_account {
3751 token_mint_account_idx = idx;
3752 } else if *account == token_program {
3753 token_program_idx = idx;
3754 }
3755 tx = tx.add_r_account(*account);
3756 }
3757
3758 let instruction_data = build_thru_registrar_purchase_domain_instruction(
3759 config_account_idx,
3760 lease_account_idx,
3761 domain_account_idx,
3762 name_service_program_idx,
3763 root_registrar_account_idx,
3764 treasurer_account_idx,
3765 payer_token_account_idx,
3766 token_mint_account_idx,
3767 token_program_idx,
3768 domain_name,
3769 years,
3770 lease_proof,
3771 domain_proof,
3772 )?;
3773
3774 Ok(tx.with_instructions(instruction_data))
3775 }
3776
3777 pub fn build_thru_registrar_renew_lease(
3779 fee_payer: TnPubkey,
3780 thru_registrar_program: TnPubkey,
3781 config_account: TnPubkey,
3782 lease_account: TnPubkey,
3783 treasurer_account: TnPubkey,
3784 payer_token_account: TnPubkey,
3785 token_mint_account: TnPubkey,
3786 token_program: TnPubkey,
3787 years: u8,
3788 fee: u64,
3789 nonce: u64,
3790 start_slot: u64,
3791 ) -> Result<Transaction> {
3792 let mut tx = Transaction::new(fee_payer, thru_registrar_program, fee, nonce)
3793 .with_start_slot(start_slot)
3794 .with_expiry_after(100)
3795 .with_compute_units(300_000)
3796 .with_state_units(10_000)
3797 .with_memory_units(10_000);
3798
3799 let mut rw_accounts = vec![lease_account, treasurer_account, payer_token_account];
3802 rw_accounts.sort();
3803
3804 let mut ro_accounts = vec![
3805 config_account,
3806 token_mint_account,
3807 token_program,
3808 ];
3809 ro_accounts.sort();
3810
3811 let mut lease_account_idx = 0u16;
3813 let mut treasurer_account_idx = 0u16;
3814 let mut payer_token_account_idx = 0u16;
3815 for (i, account) in rw_accounts.iter().enumerate() {
3816 let idx = (2 + i) as u16;
3817 if *account == lease_account {
3818 lease_account_idx = idx;
3819 } else if *account == treasurer_account {
3820 treasurer_account_idx = idx;
3821 } else if *account == payer_token_account {
3822 payer_token_account_idx = idx;
3823 }
3824 tx = tx.add_rw_account(*account);
3825 }
3826
3827 let base_ro_idx = 2 + rw_accounts.len() as u16;
3829 let mut config_account_idx = 0u16;
3830 let mut token_mint_account_idx = 0u16;
3831 let mut token_program_idx = 0u16;
3832
3833 for (i, account) in ro_accounts.iter().enumerate() {
3834 let idx = base_ro_idx + i as u16;
3835 if *account == config_account {
3836 config_account_idx = idx;
3837 } else if *account == token_mint_account {
3838 token_mint_account_idx = idx;
3839 } else if *account == token_program {
3840 token_program_idx = idx;
3841 }
3842 tx = tx.add_r_account(*account);
3843 }
3844
3845 let instruction_data = build_thru_registrar_renew_lease_instruction(
3846 config_account_idx,
3847 lease_account_idx,
3848 treasurer_account_idx,
3849 payer_token_account_idx,
3850 token_mint_account_idx,
3851 token_program_idx,
3852 years,
3853 )?;
3854
3855 Ok(tx.with_instructions(instruction_data))
3856 }
3857
3858 pub fn build_thru_registrar_claim_expired_domain(
3860 fee_payer: TnPubkey,
3861 thru_registrar_program: TnPubkey,
3862 config_account: TnPubkey,
3863 lease_account: TnPubkey,
3864 treasurer_account: TnPubkey,
3865 payer_token_account: TnPubkey,
3866 token_mint_account: TnPubkey,
3867 token_program: TnPubkey,
3868 years: u8,
3869 fee: u64,
3870 nonce: u64,
3871 start_slot: u64,
3872 ) -> Result<Transaction> {
3873 let mut tx = Transaction::new(fee_payer, thru_registrar_program, fee, nonce)
3874 .with_start_slot(start_slot)
3875 .with_expiry_after(100)
3876 .with_compute_units(300_000)
3877 .with_state_units(10_000)
3878 .with_memory_units(10_000);
3879
3880 let mut rw_accounts = vec![lease_account, treasurer_account, payer_token_account];
3883 rw_accounts.sort();
3884
3885 let mut ro_accounts = vec![
3886 config_account,
3887 token_mint_account,
3888 token_program,
3889 ];
3890 ro_accounts.sort();
3891
3892 let mut lease_account_idx = 0u16;
3894 let mut treasurer_account_idx = 0u16;
3895 let mut payer_token_account_idx = 0u16;
3896 for (i, account) in rw_accounts.iter().enumerate() {
3897 let idx = (2 + i) as u16;
3898 if *account == lease_account {
3899 lease_account_idx = idx;
3900 } else if *account == treasurer_account {
3901 treasurer_account_idx = idx;
3902 } else if *account == payer_token_account {
3903 payer_token_account_idx = idx;
3904 }
3905 tx = tx.add_rw_account(*account);
3906 }
3907
3908 let base_ro_idx = 2 + rw_accounts.len() as u16;
3910 let mut config_account_idx = 0u16;
3911 let mut token_mint_account_idx = 0u16;
3912 let mut token_program_idx = 0u16;
3913
3914 for (i, account) in ro_accounts.iter().enumerate() {
3915 let idx = base_ro_idx + i as u16;
3916 if *account == config_account {
3917 config_account_idx = idx;
3918 } else if *account == token_mint_account {
3919 token_mint_account_idx = idx;
3920 } else if *account == token_program {
3921 token_program_idx = idx;
3922 }
3923 tx = tx.add_r_account(*account);
3924 }
3925
3926 let instruction_data = build_thru_registrar_claim_expired_domain_instruction(
3927 config_account_idx,
3928 lease_account_idx,
3929 treasurer_account_idx,
3930 payer_token_account_idx,
3931 token_mint_account_idx,
3932 token_program_idx,
3933 years,
3934 )?;
3935
3936 Ok(tx.with_instructions(instruction_data))
3937 }
3938}
3939
3940fn build_token_initialize_mint_instruction(
3942 mint_account_idx: u16,
3943 decimals: u8,
3944 creator: TnPubkey,
3945 mint_authority: TnPubkey,
3946 freeze_authority: Option<TnPubkey>,
3947 ticker: &str,
3948 seed: [u8; 32],
3949 state_proof: Vec<u8>,
3950) -> Result<Vec<u8>> {
3951 let mut instruction_data = Vec::new();
3952
3953 instruction_data.push(TOKEN_INSTRUCTION_INITIALIZE_MINT);
3955
3956 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
3958
3959 instruction_data.push(decimals);
3961
3962 instruction_data.extend_from_slice(&creator);
3964
3965 instruction_data.extend_from_slice(&mint_authority);
3967
3968 let (freeze_auth, has_freeze_auth) = match freeze_authority {
3970 Some(auth) => (auth, 1u8),
3971 None => ([0u8; 32], 0u8),
3972 };
3973 instruction_data.extend_from_slice(&freeze_auth);
3974 instruction_data.push(has_freeze_auth);
3975
3976 let ticker_bytes = ticker.as_bytes();
3978 if ticker_bytes.len() > 8 {
3979 return Err(anyhow::anyhow!("Ticker must be 8 characters or less"));
3980 }
3981
3982 instruction_data.push(ticker_bytes.len() as u8);
3983 let mut ticker_padded = [0u8; 8];
3984 ticker_padded[..ticker_bytes.len()].copy_from_slice(ticker_bytes);
3985 instruction_data.extend_from_slice(&ticker_padded);
3986
3987 instruction_data.extend_from_slice(&seed);
3989
3990 instruction_data.extend_from_slice(&state_proof);
3992
3993 Ok(instruction_data)
3994}
3995
3996fn build_token_initialize_account_instruction(
3998 token_account_idx: u16,
3999 mint_account_idx: u16,
4000 owner_account_idx: u16,
4001 seed: [u8; 32],
4002 state_proof: Vec<u8>,
4003) -> Result<Vec<u8>> {
4004 let mut instruction_data = Vec::new();
4005
4006 instruction_data.push(TOKEN_INSTRUCTION_INITIALIZE_ACCOUNT);
4008
4009 instruction_data.extend_from_slice(&token_account_idx.to_le_bytes());
4011
4012 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
4014
4015 instruction_data.extend_from_slice(&owner_account_idx.to_le_bytes());
4017
4018 instruction_data.extend_from_slice(&seed);
4020
4021 instruction_data.extend_from_slice(&state_proof);
4023
4024 Ok(instruction_data)
4025}
4026
4027fn build_token_transfer_instruction(
4029 source_account_idx: u16,
4030 dest_account_idx: u16,
4031 amount: u64,
4032) -> Result<Vec<u8>> {
4033 let mut instruction_data = Vec::new();
4034
4035 instruction_data.push(TOKEN_INSTRUCTION_TRANSFER);
4037
4038 instruction_data.extend_from_slice(&source_account_idx.to_le_bytes());
4040
4041 instruction_data.extend_from_slice(&dest_account_idx.to_le_bytes());
4043
4044 instruction_data.extend_from_slice(&amount.to_le_bytes());
4046
4047 Ok(instruction_data)
4048}
4049
4050fn build_token_mint_to_instruction(
4052 mint_account_idx: u16,
4053 dest_account_idx: u16,
4054 authority_idx: u16,
4055 amount: u64,
4056) -> Result<Vec<u8>> {
4057 let mut instruction_data = Vec::new();
4058
4059 instruction_data.push(TOKEN_INSTRUCTION_MINT_TO);
4061
4062 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
4064
4065 instruction_data.extend_from_slice(&dest_account_idx.to_le_bytes());
4067
4068 instruction_data.extend_from_slice(&authority_idx.to_le_bytes());
4070
4071 instruction_data.extend_from_slice(&amount.to_le_bytes());
4073
4074 Ok(instruction_data)
4075}
4076
4077fn build_token_burn_instruction(
4079 token_account_idx: u16,
4080 mint_account_idx: u16,
4081 authority_idx: u16,
4082 amount: u64,
4083) -> Result<Vec<u8>> {
4084 let mut instruction_data = Vec::new();
4085
4086 instruction_data.push(TOKEN_INSTRUCTION_BURN);
4088
4089 instruction_data.extend_from_slice(&token_account_idx.to_le_bytes());
4091
4092 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
4094
4095 instruction_data.extend_from_slice(&authority_idx.to_le_bytes());
4097
4098 instruction_data.extend_from_slice(&amount.to_le_bytes());
4100
4101 Ok(instruction_data)
4102}
4103
4104fn build_token_freeze_account_instruction(
4106 token_account_idx: u16,
4107 mint_account_idx: u16,
4108 authority_idx: u16,
4109) -> Result<Vec<u8>> {
4110 let mut instruction_data = Vec::new();
4111
4112 instruction_data.push(TOKEN_INSTRUCTION_FREEZE_ACCOUNT);
4114
4115 instruction_data.extend_from_slice(&token_account_idx.to_le_bytes());
4117
4118 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
4120
4121 instruction_data.extend_from_slice(&authority_idx.to_le_bytes());
4123
4124 Ok(instruction_data)
4125}
4126
4127fn build_token_thaw_account_instruction(
4129 token_account_idx: u16,
4130 mint_account_idx: u16,
4131 authority_idx: u16,
4132) -> Result<Vec<u8>> {
4133 let mut instruction_data = Vec::new();
4134
4135 instruction_data.push(TOKEN_INSTRUCTION_THAW_ACCOUNT);
4137
4138 instruction_data.extend_from_slice(&token_account_idx.to_le_bytes());
4140
4141 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
4143
4144 instruction_data.extend_from_slice(&authority_idx.to_le_bytes());
4146
4147 Ok(instruction_data)
4148}
4149
4150fn build_token_close_account_instruction(
4152 token_account_idx: u16,
4153 destination_idx: u16,
4154 authority_idx: u16,
4155) -> Result<Vec<u8>> {
4156 let mut instruction_data = Vec::new();
4157
4158 instruction_data.push(TOKEN_INSTRUCTION_CLOSE_ACCOUNT);
4160
4161 instruction_data.extend_from_slice(&token_account_idx.to_le_bytes());
4163
4164 instruction_data.extend_from_slice(&destination_idx.to_le_bytes());
4166
4167 instruction_data.extend_from_slice(&authority_idx.to_le_bytes());
4169
4170 Ok(instruction_data)
4171}
4172
4173fn build_wthru_initialize_mint_instruction(
4174 token_program_idx: u16,
4175 mint_account_idx: u16,
4176 vault_account_idx: u16,
4177 decimals: u8,
4178 mint_seed: [u8; 32],
4179 mint_proof: Vec<u8>,
4180 vault_proof: Vec<u8>,
4181) -> Result<Vec<u8>> {
4182 let mint_proof_len =
4183 u64::try_from(mint_proof.len()).map_err(|_| anyhow::anyhow!("mint proof too large"))?;
4184 let vault_proof_len =
4185 u64::try_from(vault_proof.len()).map_err(|_| anyhow::anyhow!("vault proof too large"))?;
4186
4187 let mut instruction_data = Vec::new();
4188 instruction_data.extend_from_slice(&TN_WTHRU_INSTRUCTION_INITIALIZE_MINT.to_le_bytes());
4189 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
4190 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
4191 instruction_data.extend_from_slice(&vault_account_idx.to_le_bytes());
4192 instruction_data.push(decimals);
4193 instruction_data.extend_from_slice(&mint_seed);
4194 instruction_data.extend_from_slice(&mint_proof_len.to_le_bytes());
4195 instruction_data.extend_from_slice(&vault_proof_len.to_le_bytes());
4196 instruction_data.extend_from_slice(&mint_proof);
4197 instruction_data.extend_from_slice(&vault_proof);
4198
4199 Ok(instruction_data)
4200}
4201
4202fn build_wthru_deposit_instruction(
4203 token_program_idx: u16,
4204 vault_account_idx: u16,
4205 mint_account_idx: u16,
4206 dest_account_idx: u16,
4207) -> Result<Vec<u8>> {
4208 let mut instruction_data = Vec::new();
4209 instruction_data.extend_from_slice(&TN_WTHRU_INSTRUCTION_DEPOSIT.to_le_bytes());
4210 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
4211 instruction_data.extend_from_slice(&vault_account_idx.to_le_bytes());
4212 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
4213 instruction_data.extend_from_slice(&dest_account_idx.to_le_bytes());
4214
4215 Ok(instruction_data)
4216}
4217
4218fn build_wthru_withdraw_instruction(
4219 token_program_idx: u16,
4220 vault_account_idx: u16,
4221 mint_account_idx: u16,
4222 wthru_token_account_idx: u16,
4223 owner_account_idx: u16,
4224 recipient_account_idx: u16,
4225 amount: u64,
4226) -> Result<Vec<u8>> {
4227 let mut instruction_data = Vec::new();
4228 instruction_data.extend_from_slice(&TN_WTHRU_INSTRUCTION_WITHDRAW.to_le_bytes());
4229 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
4230 instruction_data.extend_from_slice(&vault_account_idx.to_le_bytes());
4231 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
4232 instruction_data.extend_from_slice(&wthru_token_account_idx.to_le_bytes());
4233 instruction_data.extend_from_slice(&owner_account_idx.to_le_bytes());
4234 instruction_data.extend_from_slice(&recipient_account_idx.to_le_bytes());
4235 instruction_data.extend_from_slice(&amount.to_le_bytes());
4236
4237 Ok(instruction_data)
4238}
4239
4240fn build_faucet_deposit_instruction(
4242 faucet_account_idx: u16,
4243 depositor_account_idx: u16,
4244 eoa_program_idx: u16,
4245 amount: u64,
4246) -> Result<Vec<u8>> {
4247 let mut instruction_data = Vec::new();
4248
4249 instruction_data.extend_from_slice(&0u32.to_le_bytes());
4251
4252 instruction_data.extend_from_slice(&faucet_account_idx.to_le_bytes());
4255
4256 instruction_data.extend_from_slice(&depositor_account_idx.to_le_bytes());
4258
4259 instruction_data.extend_from_slice(&eoa_program_idx.to_le_bytes());
4261
4262 instruction_data.extend_from_slice(&amount.to_le_bytes());
4264
4265 Ok(instruction_data)
4266}
4267
4268fn build_faucet_withdraw_instruction(
4270 faucet_account_idx: u16,
4271 recipient_account_idx: u16,
4272 amount: u64,
4273) -> Result<Vec<u8>> {
4274 let mut instruction_data = Vec::new();
4275
4276 instruction_data.extend_from_slice(&1u32.to_le_bytes());
4278
4279 instruction_data.extend_from_slice(&faucet_account_idx.to_le_bytes());
4282
4283 instruction_data.extend_from_slice(&recipient_account_idx.to_le_bytes());
4285
4286 instruction_data.extend_from_slice(&amount.to_le_bytes());
4288
4289 Ok(instruction_data)
4290}
4291
4292fn build_activate_instruction(
4295 attestor_table_idx: u64,
4296 token_program_idx: u16,
4297 source_token_account_idx: u16,
4298 converted_vault_idx: u16,
4299 identity_idx: u16,
4300 bls_pk: [u8; 96],
4301 claim_authority: [u8; 32],
4302 token_amount: u64,
4303) -> Result<Vec<u8>> {
4304 let mut instruction_data = Vec::new();
4305
4306 instruction_data.extend_from_slice(&1u32.to_le_bytes());
4308
4309 instruction_data.extend_from_slice(&attestor_table_idx.to_le_bytes());
4312
4313 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
4315
4316 instruction_data.extend_from_slice(&source_token_account_idx.to_le_bytes());
4318
4319 instruction_data.extend_from_slice(&converted_vault_idx.to_le_bytes());
4321
4322 instruction_data.extend_from_slice(&identity_idx.to_le_bytes());
4324
4325 instruction_data.extend_from_slice(&bls_pk);
4327
4328 instruction_data.extend_from_slice(&claim_authority);
4330
4331 instruction_data.extend_from_slice(&token_amount.to_le_bytes());
4333
4334 Ok(instruction_data)
4335}
4336
4337#[repr(C, packed)]
4338struct NameServiceInitializeRootArgs {
4339 registrar_account_idx: u16,
4340 authority_account_idx: u16,
4341 root_name: [u8; TN_NAME_SERVICE_MAX_DOMAIN_LENGTH],
4342 root_name_length: u32,
4343}
4344
4345#[repr(C, packed)]
4346struct NameServiceRegisterSubdomainArgs {
4347 domain_account_idx: u16,
4348 parent_account_idx: u16,
4349 owner_account_idx: u16,
4350 authority_account_idx: u16,
4351 name: [u8; TN_NAME_SERVICE_MAX_DOMAIN_LENGTH],
4352 name_length: u32,
4353}
4354
4355#[repr(C, packed)]
4356struct NameServiceAppendRecordArgs {
4357 domain_account_idx: u16,
4358 owner_account_idx: u16,
4359 key_length: u32,
4360 key: [u8; TN_NAME_SERVICE_MAX_KEY_LENGTH],
4361 value_length: u32,
4362 value: [u8; TN_NAME_SERVICE_MAX_VALUE_LENGTH],
4363}
4364
4365#[repr(C, packed)]
4366struct NameServiceDeleteRecordArgs {
4367 domain_account_idx: u16,
4368 owner_account_idx: u16,
4369 key_length: u32,
4370 key: [u8; TN_NAME_SERVICE_MAX_KEY_LENGTH],
4371}
4372
4373#[repr(C, packed)]
4374struct NameServiceUnregisterSubdomainArgs {
4375 domain_account_idx: u16,
4376 owner_account_idx: u16,
4377}
4378
4379fn build_name_service_initialize_root_instruction(
4381 registrar_account_idx: u16,
4382 authority_account_idx: u16,
4383 root_name: &str,
4384 state_proof: Vec<u8>,
4385) -> Result<Vec<u8>> {
4386 let root_name_bytes = root_name.as_bytes();
4387 if root_name_bytes.is_empty()
4388 || root_name_bytes.len() > TN_NAME_SERVICE_MAX_DOMAIN_LENGTH
4389 {
4390 return Err(anyhow::anyhow!(
4391 "Root name length must be between 1 and {}",
4392 TN_NAME_SERVICE_MAX_DOMAIN_LENGTH
4393 ));
4394 }
4395
4396 let mut args = NameServiceInitializeRootArgs {
4397 registrar_account_idx,
4398 authority_account_idx,
4399 root_name: [0u8; TN_NAME_SERVICE_MAX_DOMAIN_LENGTH],
4400 root_name_length: root_name_bytes.len() as u32,
4401 };
4402 args.root_name[..root_name_bytes.len()].copy_from_slice(root_name_bytes);
4403
4404 let mut instruction_data = Vec::new();
4405 instruction_data.extend_from_slice(&TN_NAME_SERVICE_INSTRUCTION_INITIALIZE_ROOT.to_le_bytes());
4406
4407 let args_bytes = unsafe {
4408 std::slice::from_raw_parts(
4409 &args as *const _ as *const u8,
4410 std::mem::size_of::<NameServiceInitializeRootArgs>(),
4411 )
4412 };
4413 instruction_data.extend_from_slice(args_bytes);
4414
4415 instruction_data.extend_from_slice(&TN_NAME_SERVICE_PROOF_INLINE.to_le_bytes());
4416 instruction_data.extend_from_slice(&state_proof);
4417
4418 Ok(instruction_data)
4419}
4420
4421fn build_name_service_register_subdomain_instruction(
4423 domain_account_idx: u16,
4424 parent_account_idx: u16,
4425 owner_account_idx: u16,
4426 authority_account_idx: u16,
4427 domain_name: &str,
4428 state_proof: Vec<u8>,
4429) -> Result<Vec<u8>> {
4430 let domain_bytes = domain_name.as_bytes();
4431 if domain_bytes.is_empty()
4432 || domain_bytes.len() > TN_NAME_SERVICE_MAX_DOMAIN_LENGTH
4433 {
4434 return Err(anyhow::anyhow!(
4435 "Domain name length must be between 1 and {}",
4436 TN_NAME_SERVICE_MAX_DOMAIN_LENGTH
4437 ));
4438 }
4439
4440 let mut args = NameServiceRegisterSubdomainArgs {
4441 domain_account_idx,
4442 parent_account_idx,
4443 owner_account_idx,
4444 authority_account_idx,
4445 name: [0u8; TN_NAME_SERVICE_MAX_DOMAIN_LENGTH],
4446 name_length: domain_bytes.len() as u32,
4447 };
4448 args.name[..domain_bytes.len()].copy_from_slice(domain_bytes);
4449
4450 let mut instruction_data = Vec::new();
4451 instruction_data.extend_from_slice(&TN_NAME_SERVICE_INSTRUCTION_REGISTER_SUBDOMAIN.to_le_bytes());
4452
4453 let args_bytes = unsafe {
4454 std::slice::from_raw_parts(
4455 &args as *const _ as *const u8,
4456 std::mem::size_of::<NameServiceRegisterSubdomainArgs>(),
4457 )
4458 };
4459 instruction_data.extend_from_slice(args_bytes);
4460
4461 instruction_data.extend_from_slice(&TN_NAME_SERVICE_PROOF_INLINE.to_le_bytes());
4462 instruction_data.extend_from_slice(&state_proof);
4463
4464 Ok(instruction_data)
4465}
4466
4467fn build_name_service_append_record_instruction(
4469 domain_account_idx: u16,
4470 owner_account_idx: u16,
4471 key: &[u8],
4472 value: &[u8],
4473) -> Result<Vec<u8>> {
4474 if key.is_empty() || key.len() > TN_NAME_SERVICE_MAX_KEY_LENGTH {
4475 return Err(anyhow::anyhow!(
4476 "Key length must be between 1 and {} bytes",
4477 TN_NAME_SERVICE_MAX_KEY_LENGTH
4478 ));
4479 }
4480 if value.len() > TN_NAME_SERVICE_MAX_VALUE_LENGTH {
4481 return Err(anyhow::anyhow!(
4482 "Value length must be <= {} bytes",
4483 TN_NAME_SERVICE_MAX_VALUE_LENGTH
4484 ));
4485 }
4486
4487 let mut args = NameServiceAppendRecordArgs {
4488 domain_account_idx,
4489 owner_account_idx,
4490 key_length: key.len() as u32,
4491 key: [0u8; TN_NAME_SERVICE_MAX_KEY_LENGTH],
4492 value_length: value.len() as u32,
4493 value: [0u8; TN_NAME_SERVICE_MAX_VALUE_LENGTH],
4494 };
4495 args.key[..key.len()].copy_from_slice(key);
4496 args.value[..value.len()].copy_from_slice(value);
4497
4498 let mut instruction_data = Vec::new();
4499 instruction_data.extend_from_slice(&TN_NAME_SERVICE_INSTRUCTION_APPEND_RECORD.to_le_bytes());
4500
4501 let args_bytes = unsafe {
4502 std::slice::from_raw_parts(
4503 &args as *const _ as *const u8,
4504 std::mem::size_of::<NameServiceAppendRecordArgs>(),
4505 )
4506 };
4507 instruction_data.extend_from_slice(args_bytes);
4508
4509 Ok(instruction_data)
4510}
4511
4512fn build_name_service_delete_record_instruction(
4514 domain_account_idx: u16,
4515 owner_account_idx: u16,
4516 key: &[u8],
4517) -> Result<Vec<u8>> {
4518 if key.is_empty() || key.len() > TN_NAME_SERVICE_MAX_KEY_LENGTH {
4519 return Err(anyhow::anyhow!(
4520 "Key length must be between 1 and {} bytes",
4521 TN_NAME_SERVICE_MAX_KEY_LENGTH
4522 ));
4523 }
4524
4525 let mut args = NameServiceDeleteRecordArgs {
4526 domain_account_idx,
4527 owner_account_idx,
4528 key_length: key.len() as u32,
4529 key: [0u8; TN_NAME_SERVICE_MAX_KEY_LENGTH],
4530 };
4531 args.key[..key.len()].copy_from_slice(key);
4532
4533 let mut instruction_data = Vec::new();
4534 instruction_data.extend_from_slice(&TN_NAME_SERVICE_INSTRUCTION_DELETE_RECORD.to_le_bytes());
4535
4536 let args_bytes = unsafe {
4537 std::slice::from_raw_parts(
4538 &args as *const _ as *const u8,
4539 std::mem::size_of::<NameServiceDeleteRecordArgs>(),
4540 )
4541 };
4542 instruction_data.extend_from_slice(args_bytes);
4543
4544 Ok(instruction_data)
4545}
4546
4547fn build_name_service_unregister_subdomain_instruction(
4549 domain_account_idx: u16,
4550 owner_account_idx: u16,
4551) -> Result<Vec<u8>> {
4552 let args = NameServiceUnregisterSubdomainArgs {
4553 domain_account_idx,
4554 owner_account_idx,
4555 };
4556
4557 let mut instruction_data = Vec::new();
4558 instruction_data.extend_from_slice(&TN_NAME_SERVICE_INSTRUCTION_UNREGISTER.to_le_bytes());
4559
4560 let args_bytes = unsafe {
4561 std::slice::from_raw_parts(
4562 &args as *const _ as *const u8,
4563 std::mem::size_of::<NameServiceUnregisterSubdomainArgs>(),
4564 )
4565 };
4566 instruction_data.extend_from_slice(args_bytes);
4567
4568 Ok(instruction_data)
4569}
4570
4571fn build_thru_registrar_initialize_registry_instruction(
4573 config_account_idx: u16,
4574 name_service_program_idx: u16,
4575 root_registrar_account_idx: u16,
4576 treasurer_account_idx: u16,
4577 token_mint_account_idx: u16,
4578 token_program_idx: u16,
4579 root_domain_name: &str,
4580 price_per_year: u64,
4581 config_proof: Vec<u8>,
4582 registrar_proof: Vec<u8>,
4583) -> Result<Vec<u8>> {
4584 let mut instruction_data = Vec::new();
4585
4586 instruction_data.extend_from_slice(&TN_THRU_REGISTRAR_INSTRUCTION_INITIALIZE_REGISTRY.to_le_bytes());
4588
4589 instruction_data.extend_from_slice(&config_account_idx.to_le_bytes());
4592 instruction_data.extend_from_slice(&name_service_program_idx.to_le_bytes());
4594 instruction_data.extend_from_slice(&root_registrar_account_idx.to_le_bytes());
4596 instruction_data.extend_from_slice(&treasurer_account_idx.to_le_bytes());
4598 instruction_data.extend_from_slice(&token_mint_account_idx.to_le_bytes());
4600 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
4602 let domain_bytes = root_domain_name.as_bytes();
4604 if domain_bytes.len() > 64 {
4605 return Err(anyhow::anyhow!("Root domain name must be 64 characters or less"));
4606 }
4607 let mut domain_padded = [0u8; 64];
4608 domain_padded[..domain_bytes.len()].copy_from_slice(domain_bytes);
4609 instruction_data.extend_from_slice(&domain_padded);
4610 instruction_data.extend_from_slice(&(domain_bytes.len() as u32).to_le_bytes());
4612 instruction_data.extend_from_slice(&price_per_year.to_le_bytes());
4614
4615 instruction_data.extend_from_slice(&config_proof);
4618 instruction_data.extend_from_slice(®istrar_proof);
4620
4621 Ok(instruction_data)
4622}
4623
4624fn build_thru_registrar_purchase_domain_instruction(
4626 config_account_idx: u16,
4627 lease_account_idx: u16,
4628 domain_account_idx: u16,
4629 name_service_program_idx: u16,
4630 root_registrar_account_idx: u16,
4631 treasurer_account_idx: u16,
4632 payer_token_account_idx: u16,
4633 token_mint_account_idx: u16,
4634 token_program_idx: u16,
4635 domain_name: &str,
4636 years: u8,
4637 lease_proof: Vec<u8>,
4638 domain_proof: Vec<u8>,
4639) -> Result<Vec<u8>> {
4640 let mut instruction_data = Vec::new();
4641
4642 instruction_data.extend_from_slice(&TN_THRU_REGISTRAR_INSTRUCTION_PURCHASE_DOMAIN.to_le_bytes());
4644
4645 instruction_data.extend_from_slice(&config_account_idx.to_le_bytes());
4648 instruction_data.extend_from_slice(&lease_account_idx.to_le_bytes());
4650 instruction_data.extend_from_slice(&domain_account_idx.to_le_bytes());
4652 instruction_data.extend_from_slice(&name_service_program_idx.to_le_bytes());
4654 instruction_data.extend_from_slice(&root_registrar_account_idx.to_le_bytes());
4656 instruction_data.extend_from_slice(&treasurer_account_idx.to_le_bytes());
4658 instruction_data.extend_from_slice(&payer_token_account_idx.to_le_bytes());
4660 instruction_data.extend_from_slice(&token_mint_account_idx.to_le_bytes());
4662 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
4664 let domain_bytes = domain_name.as_bytes();
4666 if domain_bytes.len() > 64 {
4667 return Err(anyhow::anyhow!("Domain name must be 64 characters or less"));
4668 }
4669 let mut domain_padded = [0u8; 64];
4670 domain_padded[..domain_bytes.len()].copy_from_slice(domain_bytes);
4671 instruction_data.extend_from_slice(&domain_padded);
4672 instruction_data.extend_from_slice(&(domain_bytes.len() as u32).to_le_bytes());
4674 instruction_data.push(years);
4676
4677 instruction_data.extend_from_slice(&lease_proof);
4680 instruction_data.extend_from_slice(&domain_proof);
4682
4683 Ok(instruction_data)
4684}
4685
4686fn build_thru_registrar_renew_lease_instruction(
4688 config_account_idx: u16,
4689 lease_account_idx: u16,
4690 treasurer_account_idx: u16,
4691 payer_token_account_idx: u16,
4692 token_mint_account_idx: u16,
4693 token_program_idx: u16,
4694 years: u8,
4695) -> Result<Vec<u8>> {
4696 let mut instruction_data = Vec::new();
4697
4698 instruction_data.extend_from_slice(&TN_THRU_REGISTRAR_INSTRUCTION_RENEW_LEASE.to_le_bytes());
4700
4701 instruction_data.extend_from_slice(&config_account_idx.to_le_bytes());
4704 instruction_data.extend_from_slice(&lease_account_idx.to_le_bytes());
4706 instruction_data.extend_from_slice(&treasurer_account_idx.to_le_bytes());
4708 instruction_data.extend_from_slice(&payer_token_account_idx.to_le_bytes());
4710 instruction_data.extend_from_slice(&token_mint_account_idx.to_le_bytes());
4712 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
4714 instruction_data.push(years);
4716
4717 Ok(instruction_data)
4718}
4719
4720fn build_thru_registrar_claim_expired_domain_instruction(
4722 config_account_idx: u16,
4723 lease_account_idx: u16,
4724 treasurer_account_idx: u16,
4725 payer_token_account_idx: u16,
4726 token_mint_account_idx: u16,
4727 token_program_idx: u16,
4728 years: u8,
4729) -> Result<Vec<u8>> {
4730 let mut instruction_data = Vec::new();
4731
4732 instruction_data.extend_from_slice(&TN_THRU_REGISTRAR_INSTRUCTION_CLAIM_EXPIRED_DOMAIN.to_le_bytes());
4734
4735 instruction_data.extend_from_slice(&config_account_idx.to_le_bytes());
4738 instruction_data.extend_from_slice(&lease_account_idx.to_le_bytes());
4740 instruction_data.extend_from_slice(&treasurer_account_idx.to_le_bytes());
4742 instruction_data.extend_from_slice(&payer_token_account_idx.to_le_bytes());
4744 instruction_data.extend_from_slice(&token_mint_account_idx.to_le_bytes());
4746 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
4748 instruction_data.push(years);
4750
4751 Ok(instruction_data)
4752}