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
68pub const UNCLAIMED_VAULT: [u8; 32] = {
70 let mut arr = [0u8; 32];
71 arr[30] = 0x0C;
72 arr[31] = 0x05;
73 arr
74};
75
76const CONSENSUS_VALIDATOR_DEFAULT_EXPIRY_AFTER: u32 = 100;
77const CONSENSUS_VALIDATOR_DEFAULT_COMPUTE_UNITS: u32 = 500_000_000;
78const CONSENSUS_VALIDATOR_DEFAULT_STATE_UNITS: u16 = 50_000;
79const CONSENSUS_VALIDATOR_DEFAULT_MEMORY_UNITS: u16 = 50_000;
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82pub struct ConsensusValidatorAccounts {
83 pub program: TnPubkey,
84 pub attestor_table: TnPubkey,
85 pub token_program: TnPubkey,
86 pub converted_vault: TnPubkey,
87 pub unclaimed_vault: TnPubkey,
88}
89
90impl Default for ConsensusValidatorAccounts {
91 fn default() -> Self {
92 Self {
93 program: CONSENSUS_VALIDATOR_PROGRAM,
94 attestor_table: ATTESTOR_TABLE,
95 token_program: TOKEN_PROGRAM,
96 converted_vault: CONVERTED_VAULT,
97 unclaimed_vault: UNCLAIMED_VAULT,
98 }
99 }
100}
101
102fn build_consensus_validator_tx(
103 fee_payer: TnPubkey,
104 program: TnPubkey,
105 fee: u64,
106 nonce: u64,
107 start_slot: u64,
108) -> Transaction {
109 Transaction::new(fee_payer, program, fee, nonce)
110 .with_start_slot(start_slot)
111 .with_expiry_after(CONSENSUS_VALIDATOR_DEFAULT_EXPIRY_AFTER)
112 .with_compute_units(CONSENSUS_VALIDATOR_DEFAULT_COMPUTE_UNITS)
113 .with_state_units(CONSENSUS_VALIDATOR_DEFAULT_STATE_UNITS)
114 .with_memory_units(CONSENSUS_VALIDATOR_DEFAULT_MEMORY_UNITS)
115}
116
117#[derive(Debug, Clone)]
118pub struct TransactionBuilder {
119 }
124
125impl TransactionBuilder {
126 pub fn build_create_with_fee_payer_proof(
128 fee_payer: TnPubkey,
129 start_slot: u64,
130 fee_payer_state_proof: &StateProof,
131 ) -> Result<Transaction> {
132 let tx = Transaction::new(fee_payer, NOOP_PROGRAM, 0, 0)
133 .with_fee_payer_state_proof(fee_payer_state_proof)
134 .with_start_slot(start_slot)
135 .with_expiry_after(100)
136 .with_compute_units(10_000)
137 .with_memory_units(10_000)
138 .with_state_units(10_000);
139 Ok(tx)
140 }
141
142 pub fn build_transfer(
156 fee_payer: TnPubkey,
157 program: TnPubkey,
158 to_account: TnPubkey,
159 amount: u64,
160 fee: u64,
161 nonce: u64,
162 start_slot: u64,
163 ) -> Result<Transaction> {
164 let from_account_idx = 0u16; let to_account_idx = 2u16; let instruction_data =
169 build_transfer_instruction(from_account_idx, to_account_idx, amount)?;
170
171 let tx = Transaction::new(fee_payer, program, fee, nonce)
172 .with_start_slot(start_slot)
173 .add_rw_account(to_account) .with_instructions(instruction_data)
175 .with_expiry_after(100)
176 .with_compute_units(10000)
177 .with_memory_units(10000)
178 .with_state_units(10000);
179
180 Ok(tx)
181 }
182
183 pub fn build_create_account(
185 fee_payer: TnPubkey,
186 program: TnPubkey,
187 target_account: TnPubkey,
188 seed: &str,
189 state_proof: Option<&[u8]>,
190 fee: u64,
191 nonce: u64,
192 start_slot: u64,
193 ) -> Result<Transaction> {
194 let target_account_idx = 2u16; let instruction_data =
197 build_create_account_instruction(target_account_idx, seed, state_proof)?;
198
199 let tx = Transaction::new(fee_payer, program, fee, nonce)
200 .with_start_slot(start_slot)
201 .add_rw_account(target_account)
202 .with_instructions(instruction_data)
203 .with_expiry_after(100)
204 .with_compute_units(10_000)
205 .with_memory_units(10_000)
206 .with_state_units(10_000);
207
208 Ok(tx)
209 }
210
211 pub fn build_create_ephemeral_account(
213 fee_payer: TnPubkey,
214 program: TnPubkey,
215 target_account: TnPubkey,
216 seed: &[u8; 32],
217 fee: u64,
218 nonce: u64,
219 start_slot: u64,
220 ) -> Result<Transaction> {
221 let target_account_idx = 2u16; let instruction_data = build_ephemeral_account_instruction(target_account_idx, seed)?;
224
225 let tx = Transaction::new(fee_payer, program, fee, nonce)
226 .with_start_slot(start_slot)
227 .add_rw_account(target_account)
228 .with_instructions(instruction_data)
229 .with_expiry_after(100)
230 .with_compute_units(50_000)
231 .with_memory_units(10_000)
232 .with_state_units(10_000);
233 Ok(tx)
234 }
235
236 pub fn build_resize_account(
238 fee_payer: TnPubkey,
239 program: TnPubkey,
240 target_account: TnPubkey,
241 new_size: u64,
242 fee: u64,
243 nonce: u64,
244 start_slot: u64,
245 ) -> Result<Transaction> {
246 let target_account_idx = 2u16; let instruction_data = build_resize_instruction(target_account_idx, new_size)?;
249
250 let tx = Transaction::new(fee_payer, program, fee, nonce)
251 .with_start_slot(start_slot)
252 .with_expiry_after(100)
253 .with_compute_units(100032)
254 .with_state_units(1 + new_size.checked_div(4096).unwrap() as u16)
255 .with_memory_units(10000)
256 .add_rw_account(target_account)
257 .with_instructions(instruction_data)
258 .with_expiry_after(100)
259 .with_compute_units(10_000 + 2 * new_size as u32)
260 .with_memory_units(10_000)
261 .with_state_units(10_000);
262
263 Ok(tx)
264 }
265
266 pub fn build_compress_account(
268 fee_payer: TnPubkey,
269 program: TnPubkey,
270 target_account: TnPubkey,
271 state_proof: &[u8],
272 fee: u64,
273 nonce: u64,
274 start_slot: u64,
275 account_size: u32,
276 ) -> Result<Transaction> {
277 let target_account_idx = 2u16; let instruction_data = build_compress_instruction(target_account_idx, state_proof)?;
280
281 let tx = Transaction::new(fee_payer, program, fee, nonce)
282 .with_start_slot(start_slot)
283 .with_may_compress_account()
284 .add_rw_account(target_account)
285 .with_instructions(instruction_data)
286 .with_expiry_after(100)
287 .with_compute_units(100_300 + account_size * 2)
288 .with_memory_units(10000)
289 .with_state_units(10000);
290
291 Ok(tx)
292 }
293
294 pub fn build_decompress_account(
296 fee_payer: TnPubkey,
297 program: TnPubkey,
298 target_account: TnPubkey,
299 account_data: &[u8],
300 state_proof: &[u8],
301 fee: u64,
302 nonce: u64,
303 start_slot: u64,
304 ) -> Result<Transaction> {
305 let target_account_idx = 2u16; let instruction_data =
308 build_decompress_instruction(target_account_idx, account_data, state_proof)?;
309
310 let tx = Transaction::new(fee_payer, program, fee, nonce)
311 .with_start_slot(start_slot)
312 .add_rw_account(target_account)
313 .with_instructions(instruction_data)
314 .with_compute_units(100_300 + account_data.len() as u32 * 2)
315 .with_state_units(10_000)
316 .with_memory_units(10_000)
317 .with_expiry_after(100);
318 Ok(tx)
319 }
320
321 pub fn build_write_data(
323 fee_payer: TnPubkey,
324 program: TnPubkey,
325 target_account: TnPubkey,
326 offset: u16,
327 data: &[u8],
328 fee: u64,
329 nonce: u64,
330 start_slot: u64,
331 ) -> Result<Transaction> {
332 let target_account_idx = 2u16; let instruction_data = build_write_instruction(target_account_idx, offset, data)?;
335
336 let tx = Transaction::new(fee_payer, program, fee, nonce)
337 .with_start_slot(start_slot)
338 .with_expiry_after(100)
339 .with_compute_units(100045)
340 .with_state_units(10000)
341 .with_memory_units(10000)
342 .add_rw_account(target_account)
343 .with_instructions(instruction_data);
344
345 Ok(tx)
346 }
347}
348
349fn build_transfer_instruction(
358 from_account_idx: u16,
359 to_account_idx: u16,
360 amount: u64,
361) -> Result<Vec<u8>> {
362 let mut instruction = Vec::new();
363
364 instruction.extend_from_slice(&1u32.to_le_bytes());
366
367 instruction.extend_from_slice(&amount.to_le_bytes());
370
371 instruction.extend_from_slice(&from_account_idx.to_le_bytes());
373
374 instruction.extend_from_slice(&to_account_idx.to_le_bytes());
376
377 Ok(instruction)
378}
379
380fn build_create_account_instruction(
382 target_account_idx: u16,
383 seed: &str,
384 state_proof: Option<&[u8]>,
385) -> Result<Vec<u8>> {
386 let mut instruction = Vec::new();
387
388 instruction.push(0x00);
390
391 instruction.extend_from_slice(&target_account_idx.to_le_bytes());
393
394 let seed_bytes =
396 hex::decode(seed).map_err(|e| anyhow::anyhow!("Failed to decode hex seed: {}", e))?;
397
398 instruction.extend_from_slice(&(seed_bytes.len() as u64).to_le_bytes());
400
401 let has_proof = state_proof.is_some();
403 instruction.push(if has_proof { 1u8 } else { 0u8 });
404
405 instruction.extend_from_slice(&seed_bytes);
407
408 if let Some(proof) = state_proof {
410 instruction.extend_from_slice(proof);
411 }
412
413 Ok(instruction)
414}
415
416fn build_ephemeral_account_instruction(
418 target_account_idx: u16,
419 seed: &[u8; 32],
420) -> Result<Vec<u8>> {
421 let mut instruction = Vec::new();
422
423 instruction.push(0x01);
425
426 instruction.extend_from_slice(&target_account_idx.to_le_bytes());
428
429 instruction.extend_from_slice(&(seed.len() as u64).to_le_bytes());
431
432 instruction.extend_from_slice(seed);
434
435 Ok(instruction)
436}
437
438fn build_resize_instruction(target_account_idx: u16, new_size: u64) -> Result<Vec<u8>> {
440 let mut instruction = Vec::new();
441
442 instruction.push(0x04);
444
445 instruction.extend_from_slice(&target_account_idx.to_le_bytes());
447
448 instruction.extend_from_slice(&new_size.to_le_bytes());
450
451 Ok(instruction)
452}
453
454fn build_write_instruction(target_account_idx: u16, offset: u16, data: &[u8]) -> Result<Vec<u8>> {
456 let mut instruction = Vec::new();
457
458 instruction.push(0xC8);
460
461 instruction.extend_from_slice(&target_account_idx.to_le_bytes());
463
464 instruction.extend_from_slice(&offset.to_le_bytes());
466
467 instruction.extend_from_slice(&(data.len() as u16).to_le_bytes());
469
470 instruction.extend_from_slice(data);
472
473 Ok(instruction)
474}
475
476fn build_compress_instruction(target_account_idx: u16, state_proof: &[u8]) -> Result<Vec<u8>> {
478 let mut instruction = Vec::new();
479
480 instruction.push(0x05);
483
484 instruction.extend_from_slice(&target_account_idx.to_le_bytes());
486
487 instruction.extend_from_slice(state_proof);
489
490 Ok(instruction)
491}
492
493fn build_decompress_instruction(
494 target_account_idx: u16,
495 account_data: &[u8],
496 state_proof: &[u8],
497) -> Result<Vec<u8>> {
498 let mut instruction = Vec::new();
499
500 instruction.push(0x06);
502
503 instruction.extend_from_slice(&target_account_idx.to_le_bytes());
505 instruction.extend_from_slice(&(account_data.len() as u64).to_le_bytes());
506
507 instruction.extend_from_slice(account_data);
509
510 instruction.extend_from_slice(state_proof);
512
513 Ok(instruction)
514}
515
516pub fn generate_ephemeral_address(seed: &str) -> Result<String> {
521 let owner_pubkey = [0u8; 32];
523
524 let seed_bytes =
526 hex::decode(seed).map_err(|e| anyhow::anyhow!("Failed to decode hex seed: {}", e))?;
527
528 let mut seed_32 = [0u8; 32];
530 let copy_len = std::cmp::min(seed_bytes.len(), 32);
531 seed_32[..copy_len].copy_from_slice(&seed_bytes[..copy_len]);
532
533 Ok(
535 crate::tn_public_address::create_program_defined_account_address_string(
536 &owner_pubkey,
537 true, &seed_32,
539 ),
540 )
541}
542
543pub fn generate_system_derived_address(seed: &str, is_ephemeral: bool) -> Result<String> {
544 let seed_bytes =
546 hex::decode(seed).map_err(|e| anyhow::anyhow!("Failed to decode hex seed: {}", e))?;
547
548 let pubkey = generate_derived_address(&seed_bytes, &[0u8; 32], is_ephemeral)?;
549
550 Ok(tn_pubkey_to_address_string(&pubkey))
551}
552
553pub fn generate_derived_address(
554 seed: &[u8],
555 owner_pubkey: &[u8; 32],
556 is_ephemeral: bool,
557) -> Result<[u8; 32]> {
558 use sha2::{Digest, Sha256};
559
560 let mut hasher = Sha256::new();
562
563 hasher.update(&owner_pubkey);
565
566 hasher.update(&[is_ephemeral as u8]);
568
569 hasher.update(&seed);
571
572 Ok(hasher.finalize().into())
574}
575
576#[cfg(test)]
577mod tests {
578 use super::*;
579
580 #[test]
581 fn test_ephemeral_address_generation() {
582 let hex_seed1 = hex::encode("test_seed_123");
584 let hex_seed2 = hex::encode("test_seed_123");
585 let hex_seed3 = hex::encode("different_seed");
586
587 let addr1 = generate_ephemeral_address(&hex_seed1).unwrap();
588 let addr2 = generate_ephemeral_address(&hex_seed2).unwrap();
589 let addr3 = generate_ephemeral_address(&hex_seed3).unwrap();
590
591 assert_eq!(addr1, addr2);
593
594 assert_ne!(addr1, addr3);
596
597 assert!(addr1.starts_with("ta"));
599 assert!(addr2.starts_with("ta"));
600 assert!(addr3.starts_with("ta"));
601
602 assert_eq!(addr1.len(), 46);
604 assert_eq!(addr2.len(), 46);
605 assert_eq!(addr3.len(), 46);
606 }
607
608 #[test]
609 fn test_eoa_transfer_instruction_format() {
610 let from_idx = 0u16;
612 let to_idx = 2u16;
613 let amount = 1000u64;
614
615 let instruction = build_transfer_instruction(from_idx, to_idx, amount).unwrap();
616
617 assert_eq!(instruction.len(), 16, "Instruction should be 16 bytes");
625
626 let discriminant = u32::from_le_bytes([
628 instruction[0],
629 instruction[1],
630 instruction[2],
631 instruction[3],
632 ]);
633 assert_eq!(discriminant, 1, "Discriminant should be 1 for TRANSFER");
634
635 let parsed_amount = u64::from_le_bytes([
637 instruction[4],
638 instruction[5],
639 instruction[6],
640 instruction[7],
641 instruction[8],
642 instruction[9],
643 instruction[10],
644 instruction[11],
645 ]);
646 assert_eq!(parsed_amount, amount, "Amount should match input");
647
648 let parsed_from = u16::from_le_bytes([instruction[12], instruction[13]]);
650 assert_eq!(parsed_from, from_idx, "From index should match input");
651
652 let parsed_to = u16::from_le_bytes([instruction[14], instruction[15]]);
654 assert_eq!(parsed_to, to_idx, "To index should match input");
655 }
656
657 #[test]
658 fn test_faucet_deposit_instruction_layout_with_fee_payer_depositor() {
659 let fee_payer = [1u8; 32];
660 let faucet_program = FAUCET_PROGRAM;
661 let faucet_account = [2u8; 32];
662 let depositor_account = fee_payer;
663 let amount = 500u64;
664
665 let tx = TransactionBuilder::build_faucet_deposit(
666 fee_payer,
667 faucet_program,
668 faucet_account,
669 depositor_account,
670 EOA_PROGRAM,
671 amount,
672 0,
673 42,
674 100,
675 )
676 .expect("build faucet deposit");
677
678 let rw_accs = tx.rw_accs.expect("rw accounts must exist");
679 assert_eq!(rw_accs.len(), 1);
680 assert_eq!(rw_accs[0], faucet_account);
681
682 let ro_accs = tx.r_accs.expect("ro accounts must exist");
683 assert_eq!(ro_accs.len(), 1);
684 assert_eq!(ro_accs[0], EOA_PROGRAM);
685
686 let instruction = tx.instructions.expect("instruction bytes must exist");
687 assert_eq!(
688 instruction.len(),
689 18,
690 "Deposit instruction must be 18 bytes"
691 );
692
693 let discriminant = u32::from_le_bytes([
694 instruction[0],
695 instruction[1],
696 instruction[2],
697 instruction[3],
698 ]);
699 assert_eq!(discriminant, 0, "Deposit discriminant should be 0");
700
701 let faucet_idx = u16::from_le_bytes([instruction[4], instruction[5]]);
702 let depositor_idx = u16::from_le_bytes([instruction[6], instruction[7]]);
703 let eoa_idx = u16::from_le_bytes([instruction[8], instruction[9]]);
704 let parsed_amount = u64::from_le_bytes([
705 instruction[10],
706 instruction[11],
707 instruction[12],
708 instruction[13],
709 instruction[14],
710 instruction[15],
711 instruction[16],
712 instruction[17],
713 ]);
714
715 assert_eq!(faucet_idx, 2, "Faucet account should be first RW account");
716 assert_eq!(depositor_idx, 0, "Depositor shares the fee payer index");
717 assert_eq!(eoa_idx, 3, "EOA program should follow RW accounts");
718 assert_eq!(parsed_amount, amount, "Amount should match input");
719 }
720
721 #[test]
722 fn test_build_token_initialize_mint() {
723 let fee_payer = [1u8; 32];
725 let token_program = [2u8; 32];
726 let mint_account = [3u8; 32];
727 let creator = [4u8; 32];
728 let mint_authority = [5u8; 32];
729 let freeze_authority = [6u8; 32];
730
731 let decimals = 9u8;
732 let ticker = "TEST";
733 let seed = [7u8; 32];
734 let state_proof = vec![8u8; 64];
735
736 let result = TransactionBuilder::build_token_initialize_mint(
738 fee_payer,
739 token_program,
740 mint_account,
741 creator,
742 mint_authority,
743 Some(freeze_authority),
744 decimals,
745 ticker,
746 seed,
747 state_proof.clone(),
748 1000, 1, 100, );
752
753 assert!(
754 result.is_ok(),
755 "Should build valid transaction with freeze authority"
756 );
757 let tx = result.unwrap();
758 assert!(
759 tx.instructions.is_some(),
760 "Transaction should have instructions"
761 );
762
763 let result_no_freeze = TransactionBuilder::build_token_initialize_mint(
765 fee_payer,
766 token_program,
767 mint_account,
768 creator,
769 mint_authority,
770 None,
771 decimals,
772 ticker,
773 seed,
774 state_proof,
775 1000,
776 1,
777 100,
778 );
779
780 assert!(
781 result_no_freeze.is_ok(),
782 "Should build valid transaction without freeze authority"
783 );
784 }
785
786 #[test]
787 fn test_build_token_initialize_mint_instruction_format() {
788 let mint_account_idx = 2u16;
789 let decimals = 9u8;
790 let creator = [1u8; 32];
791 let mint_authority = [2u8; 32];
792 let freeze_authority = [3u8; 32];
793 let ticker = "TST";
794 let seed = [4u8; 32];
795 let state_proof = vec![5u8; 10];
796
797 let instruction = build_token_initialize_mint_instruction(
798 mint_account_idx,
799 decimals,
800 creator,
801 mint_authority,
802 Some(freeze_authority),
803 ticker,
804 seed,
805 state_proof.clone(),
806 )
807 .unwrap();
808
809 let expected_min_size = 1 + 2 + 1 + 32 + 32 + 32 + 1 + 1 + 8 + 32 + state_proof.len();
813 assert_eq!(instruction.len(), expected_min_size);
814
815 assert_eq!(
817 instruction[0], 0,
818 "First byte should be InitializeMint tag (0)"
819 );
820
821 let parsed_idx = u16::from_le_bytes([instruction[1], instruction[2]]);
823 assert_eq!(parsed_idx, mint_account_idx);
824
825 assert_eq!(instruction[3], decimals);
827
828 assert_eq!(&instruction[4..36], &creator);
830
831 assert_eq!(&instruction[36..68], &mint_authority);
833
834 assert_eq!(&instruction[68..100], &freeze_authority);
836
837 assert_eq!(instruction[100], 1);
839 }
840
841 #[test]
842 fn test_token_initialize_mint_creator_vs_mint_authority() {
843 let fee_payer = [1u8; 32];
845 let token_program = [2u8; 32];
846 let mint_account = [3u8; 32];
847 let creator = [4u8; 32];
848 let mint_authority = [5u8; 32]; let seed = [6u8; 32];
850 let state_proof = vec![7u8; 32];
851
852 let result = TransactionBuilder::build_token_initialize_mint(
853 fee_payer,
854 token_program,
855 mint_account,
856 creator,
857 mint_authority,
858 None,
859 9,
860 "TEST",
861 seed,
862 state_proof,
863 1000,
864 1,
865 100,
866 );
867
868 assert!(
869 result.is_ok(),
870 "Should allow different creator and mint_authority"
871 );
872
873 let result_same = TransactionBuilder::build_token_initialize_mint(
875 fee_payer,
876 token_program,
877 mint_account,
878 creator,
879 creator, None,
881 9,
882 "TEST",
883 seed,
884 vec![7u8; 32],
885 1000,
886 1,
887 100,
888 );
889
890 assert!(
891 result_same.is_ok(),
892 "Should allow same creator and mint_authority"
893 );
894 }
895
896 #[test]
897 fn test_build_activate_with_custom_accounts_sorts_accounts_and_indices() {
898 let fee_payer = [0x10u8; 32];
899 let accounts = ConsensusValidatorAccounts {
900 program: [0xf0u8; 32],
901 attestor_table: [0x30u8; 32],
902 token_program: [0x90u8; 32],
903 converted_vault: [0x40u8; 32],
904 unclaimed_vault: [0x50u8; 32],
905 };
906 let source_token_account = [0x20u8; 32];
907 let claim_authority = [0x60u8; 32];
908 let bls_pk = [0x77u8; 96];
909
910 let tx = TransactionBuilder::build_activate_with_accounts(
911 fee_payer,
912 accounts,
913 source_token_account,
914 bls_pk,
915 claim_authority,
916 123,
917 0,
918 9,
919 44,
920 )
921 .expect("activate transaction should build");
922
923 assert_eq!(tx.program, accounts.program);
924 assert_eq!(
925 tx.rw_accs,
926 Some(vec![
927 source_token_account,
928 accounts.attestor_table,
929 accounts.converted_vault
930 ])
931 );
932 assert_eq!(tx.r_accs, Some(vec![accounts.token_program]));
933
934 let instruction = tx.instructions.expect("instruction bytes must exist");
935 assert_eq!(
936 u32::from_le_bytes(instruction[0..4].try_into().unwrap()),
937 1,
938 "activate discriminant should be 1"
939 );
940 assert_eq!(
941 u64::from_le_bytes(instruction[4..12].try_into().unwrap()),
942 3,
943 "attestor table should resolve to rw index 3"
944 );
945 assert_eq!(
946 u16::from_le_bytes(instruction[12..14].try_into().unwrap()),
947 5,
948 "token program should resolve to ro index 5"
949 );
950 assert_eq!(
951 u16::from_le_bytes(instruction[14..16].try_into().unwrap()),
952 2,
953 "source token account should resolve to rw index 2"
954 );
955 assert_eq!(
956 u16::from_le_bytes(instruction[16..18].try_into().unwrap()),
957 4,
958 "converted vault should resolve to rw index 4"
959 );
960 assert_eq!(
961 u16::from_le_bytes(instruction[18..20].try_into().unwrap()),
962 0,
963 "identity should remain fee payer index 0"
964 );
965 }
966
967 #[test]
968 fn test_build_deactivate_instruction_format() {
969 let instruction = build_deactivate_instruction(7, 8, 9, 10, 0).unwrap();
970
971 assert_eq!(instruction.len(), 20);
972 assert_eq!(
973 u32::from_le_bytes(instruction[0..4].try_into().unwrap()),
974 2,
975 "deactivate discriminant should be 2"
976 );
977 assert_eq!(
978 u64::from_le_bytes(instruction[4..12].try_into().unwrap()),
979 7
980 );
981 assert_eq!(
982 u16::from_le_bytes(instruction[12..14].try_into().unwrap()),
983 8
984 );
985 assert_eq!(
986 u16::from_le_bytes(instruction[14..16].try_into().unwrap()),
987 9
988 );
989 assert_eq!(
990 u16::from_le_bytes(instruction[16..18].try_into().unwrap()),
991 10
992 );
993 assert_eq!(
994 u16::from_le_bytes(instruction[18..20].try_into().unwrap()),
995 0
996 );
997 }
998
999 #[test]
1000 fn test_build_convert_tokens_instruction_format() {
1001 let instruction = build_convert_tokens_instruction(11, 12, 13, 14, 0, 500).unwrap();
1002
1003 assert_eq!(instruction.len(), 28);
1004 assert_eq!(
1005 u32::from_le_bytes(instruction[0..4].try_into().unwrap()),
1006 3,
1007 "convert-tokens discriminant should be 3"
1008 );
1009 assert_eq!(
1010 u64::from_le_bytes(instruction[4..12].try_into().unwrap()),
1011 11
1012 );
1013 assert_eq!(
1014 u16::from_le_bytes(instruction[12..14].try_into().unwrap()),
1015 12
1016 );
1017 assert_eq!(
1018 u16::from_le_bytes(instruction[14..16].try_into().unwrap()),
1019 13
1020 );
1021 assert_eq!(
1022 u16::from_le_bytes(instruction[16..18].try_into().unwrap()),
1023 14
1024 );
1025 assert_eq!(
1026 u16::from_le_bytes(instruction[18..20].try_into().unwrap()),
1027 0
1028 );
1029 assert_eq!(
1030 u64::from_le_bytes(instruction[20..28].try_into().unwrap()),
1031 500
1032 );
1033 }
1034
1035 #[test]
1036 fn test_build_claim_instruction_format() {
1037 let subject_attestor = [0xabu8; 32];
1038 let instruction = build_claim_instruction(15, 16, 17, 18, 0, subject_attestor).unwrap();
1039
1040 assert_eq!(instruction.len(), 52);
1041 assert_eq!(
1042 u32::from_le_bytes(instruction[0..4].try_into().unwrap()),
1043 4,
1044 "claim discriminant should be 4"
1045 );
1046 assert_eq!(
1047 u64::from_le_bytes(instruction[4..12].try_into().unwrap()),
1048 15
1049 );
1050 assert_eq!(
1051 u16::from_le_bytes(instruction[12..14].try_into().unwrap()),
1052 16
1053 );
1054 assert_eq!(
1055 u16::from_le_bytes(instruction[14..16].try_into().unwrap()),
1056 17
1057 );
1058 assert_eq!(
1059 u16::from_le_bytes(instruction[16..18].try_into().unwrap()),
1060 18
1061 );
1062 assert_eq!(
1063 u16::from_le_bytes(instruction[18..20].try_into().unwrap()),
1064 0
1065 );
1066 assert_eq!(&instruction[20..52], &subject_attestor);
1067 }
1068
1069 #[test]
1070 fn test_build_set_claim_authority_instruction_format() {
1071 let subject_attestor = [0x55u8; 32];
1072 let new_claim_authority = [0x66u8; 32];
1073 let instruction =
1074 build_set_claim_authority_instruction(19, 0, subject_attestor, new_claim_authority)
1075 .unwrap();
1076
1077 assert_eq!(instruction.len(), 78);
1078 assert_eq!(
1079 u32::from_le_bytes(instruction[0..4].try_into().unwrap()),
1080 5,
1081 "set-claim-authority discriminant should be 5"
1082 );
1083 assert_eq!(
1084 u64::from_le_bytes(instruction[4..12].try_into().unwrap()),
1085 19
1086 );
1087 assert_eq!(
1088 u16::from_le_bytes(instruction[12..14].try_into().unwrap()),
1089 0
1090 );
1091 assert_eq!(&instruction[14..46], &subject_attestor);
1092 assert_eq!(&instruction[46..78], &new_claim_authority);
1093 }
1094}
1095
1096pub const TN_UPLOADER_PROGRAM_INSTRUCTION_CREATE: u32 = 0x00;
1098pub const TN_UPLOADER_PROGRAM_INSTRUCTION_WRITE: u32 = 0x01;
1099pub const TN_UPLOADER_PROGRAM_INSTRUCTION_DESTROY: u32 = 0x02;
1100pub const TN_UPLOADER_PROGRAM_INSTRUCTION_FINALIZE: u32 = 0x03;
1101
1102#[repr(C, packed)]
1104#[derive(Debug, Clone, Copy)]
1105pub struct UploaderCreateArgs {
1106 pub buffer_account_idx: u16,
1107 pub meta_account_idx: u16,
1108 pub authority_account_idx: u16,
1109 pub buffer_account_sz: u32,
1110 pub expected_account_hash: [u8; 32],
1111 pub seed_len: u32,
1112 }
1114
1115#[repr(C, packed)]
1117#[derive(Debug, Clone, Copy)]
1118pub struct UploaderWriteArgs {
1119 pub buffer_account_idx: u16,
1120 pub meta_account_idx: u16,
1121 pub data_len: u32,
1122 pub data_offset: u32,
1123 }
1125
1126#[repr(C, packed)]
1128#[derive(Debug, Clone, Copy)]
1129pub struct UploaderFinalizeArgs {
1130 pub buffer_account_idx: u16,
1131 pub meta_account_idx: u16,
1132 pub expected_account_hash: [u8; 32],
1133}
1134
1135#[repr(C, packed)]
1137#[derive(Debug, Clone, Copy)]
1138pub struct UploaderDestroyArgs {
1139 pub buffer_account_idx: u16,
1140 pub meta_account_idx: u16,
1141}
1142
1143pub const MANAGER_INSTRUCTION_CREATE_PERMANENT: u8 = 0x00;
1145pub const MANAGER_INSTRUCTION_CREATE_EPHEMERAL: u8 = 0x01;
1146pub const MANAGER_INSTRUCTION_UPGRADE: u8 = 0x02;
1147pub const MANAGER_INSTRUCTION_SET_PAUSE: u8 = 0x03;
1148pub const MANAGER_INSTRUCTION_DESTROY: u8 = 0x04;
1149pub const MANAGER_INSTRUCTION_FINALIZE: u8 = 0x05;
1150pub const MANAGER_INSTRUCTION_SET_AUTHORITY: u8 = 0x06;
1151pub const MANAGER_INSTRUCTION_CLAIM_AUTHORITY: u8 = 0x07;
1152
1153pub const ABI_MANAGER_INSTRUCTION_CREATE_META_OFFICIAL_PERMANENT: u8 = 0x00;
1154pub const ABI_MANAGER_INSTRUCTION_CREATE_META_OFFICIAL_EPHEMERAL: u8 = 0x01;
1155pub const ABI_MANAGER_INSTRUCTION_CREATE_META_EXTERNAL_PERMANENT: u8 = 0x02;
1156pub const ABI_MANAGER_INSTRUCTION_CREATE_META_EXTERNAL_EPHEMERAL: u8 = 0x03;
1157pub const ABI_MANAGER_INSTRUCTION_CREATE_ABI_OFFICIAL_PERMANENT: u8 = 0x04;
1158pub const ABI_MANAGER_INSTRUCTION_CREATE_ABI_OFFICIAL_EPHEMERAL: u8 = 0x05;
1159pub const ABI_MANAGER_INSTRUCTION_CREATE_ABI_EXTERNAL_PERMANENT: u8 = 0x06;
1160pub const ABI_MANAGER_INSTRUCTION_CREATE_ABI_EXTERNAL_EPHEMERAL: u8 = 0x07;
1161pub const ABI_MANAGER_INSTRUCTION_UPGRADE_ABI_OFFICIAL: u8 = 0x08;
1162pub const ABI_MANAGER_INSTRUCTION_UPGRADE_ABI_EXTERNAL: u8 = 0x09;
1163pub const ABI_MANAGER_INSTRUCTION_CLOSE_ABI_OFFICIAL: u8 = 0x0a;
1164pub const ABI_MANAGER_INSTRUCTION_CLOSE_ABI_EXTERNAL: u8 = 0x0b;
1165pub const ABI_MANAGER_INSTRUCTION_FINALIZE_ABI_OFFICIAL: u8 = 0x0c;
1166pub const ABI_MANAGER_INSTRUCTION_FINALIZE_ABI_EXTERNAL: u8 = 0x0d;
1167
1168#[repr(C, packed)]
1170#[derive(Debug, Clone, Copy)]
1171pub struct ManagerHeaderArgs {
1172 pub discriminant: u8,
1173 pub meta_account_idx: u16,
1174 pub program_account_idx: u16,
1175}
1176
1177#[repr(C, packed)]
1179#[derive(Debug, Clone, Copy)]
1180pub struct ManagerCreateArgs {
1181 pub discriminant: u8,
1182 pub meta_account_idx: u16,
1183 pub program_account_idx: u16,
1184 pub srcbuf_account_idx: u16,
1185 pub srcbuf_offset: u32,
1186 pub srcbuf_size: u32,
1187 pub authority_account_idx: u16,
1188 pub seed_len: u32,
1189 }
1191
1192#[repr(C, packed)]
1194#[derive(Debug, Clone, Copy)]
1195pub struct ManagerUpgradeArgs {
1196 pub discriminant: u8,
1197 pub meta_account_idx: u16,
1198 pub program_account_idx: u16,
1199 pub srcbuf_account_idx: u16,
1200 pub srcbuf_offset: u32,
1201 pub srcbuf_size: u32,
1202}
1203
1204#[repr(C, packed)]
1206#[derive(Debug, Clone, Copy)]
1207pub struct AbiManagerCreateMetaOfficialArgs {
1208 pub abi_meta_account_idx: u16,
1209 pub program_meta_account_idx: u16,
1210 pub authority_account_idx: u16,
1211}
1212
1213#[repr(C, packed)]
1215#[derive(Debug, Clone, Copy)]
1216pub struct AbiManagerCreateMetaExternalArgs {
1217 pub abi_meta_account_idx: u16,
1218 pub authority_account_idx: u16,
1219 pub target_program: TnPubkey,
1220 pub seed: [u8; 32],
1221}
1222
1223#[repr(C, packed)]
1225#[derive(Debug, Clone, Copy)]
1226pub struct AbiManagerCreateAbiOfficialArgs {
1227 pub abi_meta_account_idx: u16,
1228 pub program_meta_account_idx: u16,
1229 pub abi_account_idx: u16,
1230 pub srcbuf_account_idx: u16,
1231 pub srcbuf_offset: u32,
1232 pub srcbuf_size: u32,
1233 pub authority_account_idx: u16,
1234}
1235
1236#[repr(C, packed)]
1238#[derive(Debug, Clone, Copy)]
1239pub struct AbiManagerCreateAbiExternalArgs {
1240 pub abi_meta_account_idx: u16,
1241 pub abi_account_idx: u16,
1242 pub srcbuf_account_idx: u16,
1243 pub srcbuf_offset: u32,
1244 pub srcbuf_size: u32,
1245 pub authority_account_idx: u16,
1246}
1247
1248#[repr(C, packed)]
1250#[derive(Debug, Clone, Copy)]
1251pub struct AbiManagerUpgradeAbiOfficialArgs {
1252 pub abi_meta_account_idx: u16,
1253 pub program_meta_account_idx: u16,
1254 pub abi_account_idx: u16,
1255 pub srcbuf_account_idx: u16,
1256 pub srcbuf_offset: u32,
1257 pub srcbuf_size: u32,
1258 pub authority_account_idx: u16,
1259}
1260
1261#[repr(C, packed)]
1263#[derive(Debug, Clone, Copy)]
1264pub struct AbiManagerUpgradeAbiExternalArgs {
1265 pub abi_meta_account_idx: u16,
1266 pub abi_account_idx: u16,
1267 pub srcbuf_account_idx: u16,
1268 pub srcbuf_offset: u32,
1269 pub srcbuf_size: u32,
1270 pub authority_account_idx: u16,
1271}
1272
1273#[repr(C, packed)]
1275#[derive(Debug, Clone, Copy)]
1276pub struct AbiManagerFinalizeAbiOfficialArgs {
1277 pub abi_meta_account_idx: u16,
1278 pub program_meta_account_idx: u16,
1279 pub abi_account_idx: u16,
1280 pub authority_account_idx: u16,
1281}
1282
1283#[repr(C, packed)]
1285#[derive(Debug, Clone, Copy)]
1286pub struct AbiManagerFinalizeAbiExternalArgs {
1287 pub abi_meta_account_idx: u16,
1288 pub abi_account_idx: u16,
1289 pub authority_account_idx: u16,
1290}
1291
1292#[repr(C, packed)]
1294#[derive(Debug, Clone, Copy)]
1295pub struct AbiManagerCloseAbiOfficialArgs {
1296 pub abi_meta_account_idx: u16,
1297 pub program_meta_account_idx: u16,
1298 pub abi_account_idx: u16,
1299 pub authority_account_idx: u16,
1300}
1301
1302#[repr(C, packed)]
1304#[derive(Debug, Clone, Copy)]
1305pub struct AbiManagerCloseAbiExternalArgs {
1306 pub abi_meta_account_idx: u16,
1307 pub abi_account_idx: u16,
1308 pub authority_account_idx: u16,
1309}
1310
1311#[repr(C, packed)]
1313#[derive(Debug, Clone, Copy)]
1314pub struct ManagerSetPauseArgs {
1315 pub discriminant: u8,
1316 pub meta_account_idx: u16,
1317 pub program_account_idx: u16,
1318 pub is_paused: u8,
1319}
1320
1321#[repr(C, packed)]
1323#[derive(Debug, Clone, Copy)]
1324pub struct ManagerSetAuthorityArgs {
1325 pub discriminant: u8,
1326 pub meta_account_idx: u16,
1327 pub program_account_idx: u16,
1328 pub authority_candidate: [u8; 32],
1329}
1330
1331pub const TN_TEST_UPLOADER_PROGRAM_DISCRIMINANT_CREATE: u8 = 0x00;
1333pub const TN_TEST_UPLOADER_PROGRAM_DISCRIMINANT_WRITE: u8 = 0x01;
1334
1335#[repr(C, packed)]
1337#[derive(Debug, Clone, Copy)]
1338pub struct TestUploaderCreateArgs {
1339 pub account_idx: u16,
1340 pub is_ephemeral: u8,
1341 pub account_sz: u32,
1342 pub seed_len: u32,
1343 }
1345
1346#[repr(C, packed)]
1348#[derive(Debug, Clone, Copy)]
1349pub struct TestUploaderWriteArgs {
1350 pub target_account_idx: u16,
1351 pub target_offset: u32,
1352 pub data_len: u32,
1353 }
1355
1356#[repr(C, packed)]
1358#[derive(Debug, Clone, Copy)]
1359pub struct SystemProgramDecompress2Args {
1360 pub target_account_idx: u16,
1361 pub meta_account_idx: u16,
1362 pub data_account_idx: u16,
1363 pub data_offset: u32,
1364}
1365
1366impl TransactionBuilder {
1367 pub fn build_uploader_create(
1369 fee_payer: TnPubkey,
1370 uploader_program: TnPubkey,
1371 meta_account: TnPubkey,
1372 buffer_account: TnPubkey,
1373 buffer_size: u32,
1374 expected_hash: [u8; 32],
1375 seed: &[u8],
1376 fee: u64,
1377 nonce: u64,
1378 start_slot: u64,
1379 ) -> Result<Transaction> {
1380 let authority_account_idx = 0u16;
1382
1383 let mut tx = Transaction::new(fee_payer, uploader_program, fee, nonce)
1384 .with_start_slot(start_slot)
1385 .with_expiry_after(10)
1386 .with_compute_units(50_000 + 2 * buffer_size as u32)
1387 .with_memory_units(10_000)
1388 .with_state_units(10_000);
1389
1390 let mut meta_account_idx = 2u16;
1391 let mut buffer_account_idx = 3u16;
1392 if meta_account > buffer_account {
1393 meta_account_idx = 3u16;
1394 buffer_account_idx = 2u16;
1395 tx = tx
1396 .add_rw_account(buffer_account)
1397 .add_rw_account(meta_account)
1398 } else {
1399 tx = tx
1400 .add_rw_account(meta_account)
1401 .add_rw_account(buffer_account)
1402 }
1403
1404 let instruction_data = build_uploader_create_instruction(
1405 buffer_account_idx,
1406 meta_account_idx,
1407 authority_account_idx,
1408 buffer_size,
1409 expected_hash,
1410 seed,
1411 )?;
1412
1413 tx = tx.with_instructions(instruction_data);
1414
1415 Ok(tx)
1416 }
1417
1418 pub fn build_uploader_write(
1420 fee_payer: TnPubkey,
1421 uploader_program: TnPubkey,
1422 meta_account: TnPubkey,
1423 buffer_account: TnPubkey,
1424 data: &[u8],
1425 offset: u32,
1426 fee: u64,
1427 nonce: u64,
1428 start_slot: u64,
1429 ) -> Result<Transaction> {
1430 let mut tx = Transaction::new(fee_payer, uploader_program, fee, nonce)
1432 .with_start_slot(start_slot)
1433 .with_expiry_after(10000)
1434 .with_compute_units(500_000_000)
1435 .with_memory_units(5000)
1436 .with_state_units(5000);
1437
1438 let mut meta_account_idx = 2u16;
1439 let mut buffer_account_idx = 3u16;
1440 if meta_account > buffer_account {
1441 meta_account_idx = 3u16;
1442 buffer_account_idx = 2u16;
1443 tx = tx
1444 .add_rw_account(buffer_account)
1445 .add_rw_account(meta_account)
1446 } else {
1447 tx = tx
1448 .add_rw_account(meta_account)
1449 .add_rw_account(buffer_account)
1450 }
1451
1452 let instruction_data =
1453 build_uploader_write_instruction(buffer_account_idx, meta_account_idx, data, offset)?;
1454
1455 tx = tx.with_instructions(instruction_data);
1456
1457 Ok(tx)
1458 }
1459
1460 pub fn build_uploader_finalize(
1462 fee_payer: TnPubkey,
1463 uploader_program: TnPubkey,
1464 meta_account: TnPubkey,
1465 buffer_account: TnPubkey,
1466 buffer_size: u32,
1467 expected_hash: [u8; 32],
1468 fee: u64,
1469 nonce: u64,
1470 start_slot: u64,
1471 ) -> Result<Transaction> {
1472 let mut tx = Transaction::new(fee_payer, uploader_program, fee, nonce)
1473 .with_start_slot(start_slot)
1474 .with_expiry_after(10000)
1475 .with_compute_units(50_000 + 200 * buffer_size as u32)
1476 .with_memory_units(5000)
1477 .with_state_units(5000);
1478
1479 let mut meta_account_idx = 2u16;
1481 let mut buffer_account_idx = 3u16;
1482 if meta_account > buffer_account {
1483 meta_account_idx = 3u16;
1484 buffer_account_idx = 2u16;
1485 tx = tx
1486 .add_rw_account(buffer_account)
1487 .add_rw_account(meta_account)
1488 } else {
1489 tx = tx
1490 .add_rw_account(meta_account)
1491 .add_rw_account(buffer_account)
1492 }
1493
1494 let instruction_data = build_uploader_finalize_instruction(
1495 buffer_account_idx,
1496 meta_account_idx,
1497 expected_hash,
1498 )?;
1499
1500 tx = tx.with_instructions(instruction_data);
1501
1502 Ok(tx)
1503 }
1504
1505 pub fn build_uploader_destroy(
1507 fee_payer: TnPubkey,
1508 uploader_program: TnPubkey,
1509 meta_account: TnPubkey,
1510 buffer_account: TnPubkey,
1511 fee: u64,
1512 nonce: u64,
1513 start_slot: u64,
1514 ) -> Result<Transaction> {
1515 let mut tx = Transaction::new(fee_payer, uploader_program, fee, nonce)
1516 .with_start_slot(start_slot)
1517 .with_expiry_after(10000)
1518 .with_compute_units(50000)
1519 .with_memory_units(5000)
1520 .with_state_units(5000);
1521
1522 let mut meta_account_idx = 2u16;
1524 let mut buffer_account_idx = 3u16;
1525 if meta_account > buffer_account {
1526 meta_account_idx = 3u16;
1527 buffer_account_idx = 2u16;
1528 tx = tx
1529 .add_rw_account(buffer_account)
1530 .add_rw_account(meta_account)
1531 } else {
1532 tx = tx
1533 .add_rw_account(meta_account)
1534 .add_rw_account(buffer_account)
1535 }
1536
1537 let instruction_data =
1538 build_uploader_destroy_instruction(buffer_account_idx, meta_account_idx)?;
1539
1540 tx = tx.with_instructions(instruction_data);
1541 Ok(tx)
1542 }
1543
1544 pub fn build_manager_create(
1546 fee_payer: TnPubkey,
1547 manager_program: TnPubkey,
1548 meta_account: TnPubkey,
1549 program_account: TnPubkey,
1550 srcbuf_account: TnPubkey,
1551 authority_account: TnPubkey,
1552 srcbuf_offset: u32,
1553 srcbuf_size: u32,
1554 seed: &[u8],
1555 is_ephemeral: bool,
1556 meta_proof: Option<&[u8]>,
1557 program_proof: Option<&[u8]>,
1558 fee: u64,
1559 nonce: u64,
1560 start_slot: u64,
1561 ) -> Result<Transaction> {
1562 let mut tx = Transaction::new(fee_payer, manager_program, fee, nonce)
1563 .with_start_slot(start_slot)
1564 .with_expiry_after(10000)
1565 .with_compute_units(500_000_000)
1566 .with_memory_units(5000)
1567 .with_state_units(5000);
1568
1569 let authority_is_fee_payer = authority_account == fee_payer;
1571
1572 let mut rw_accounts = vec![(meta_account, "meta"), (program_account, "program")];
1574
1575 let mut r_accounts = vec![(srcbuf_account, "srcbuf")];
1576
1577 if !authority_is_fee_payer {
1579 r_accounts.push((authority_account, "authority"));
1580 }
1581
1582 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1584
1585 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1587
1588 let mut accounts = rw_accounts;
1590 accounts.extend(r_accounts);
1591
1592 let mut meta_account_idx = 0u16;
1593 let mut program_account_idx = 0u16;
1594 let mut srcbuf_account_idx = 0u16;
1595 let mut authority_account_idx = if authority_is_fee_payer {
1596 0u16 } else {
1598 0u16 };
1600
1601 for (i, (account, account_type)) in accounts.iter().enumerate() {
1602 let idx = (i + 2) as u16; match *account_type {
1604 "meta" => {
1605 meta_account_idx = idx;
1606 tx = tx.add_rw_account(*account);
1607 }
1608 "program" => {
1609 program_account_idx = idx;
1610 tx = tx.add_rw_account(*account);
1611 }
1612 "srcbuf" => {
1613 srcbuf_account_idx = idx;
1614 tx = tx.add_r_account(*account);
1615 }
1616 "authority" => {
1617 authority_account_idx = idx;
1618 tx = tx.add_r_account(*account);
1619 }
1620 _ => unreachable!(),
1621 }
1622 }
1623
1624 let discriminant = if is_ephemeral {
1625 MANAGER_INSTRUCTION_CREATE_EPHEMERAL
1626 } else {
1627 MANAGER_INSTRUCTION_CREATE_PERMANENT
1628 };
1629
1630 let combined_proof = if let (Some(meta), Some(program)) = (meta_proof, program_proof) {
1632 let mut combined = Vec::with_capacity(meta.len() + program.len());
1633 combined.extend_from_slice(meta);
1634 combined.extend_from_slice(program);
1635 Some(combined)
1636 } else {
1637 None
1638 };
1639
1640 let instruction_data = build_manager_create_instruction(
1641 discriminant,
1642 meta_account_idx,
1643 program_account_idx,
1644 srcbuf_account_idx,
1645 authority_account_idx,
1646 srcbuf_offset,
1647 srcbuf_size,
1648 seed,
1649 combined_proof.as_deref(),
1650 )?;
1651
1652 tx = tx.with_instructions(instruction_data);
1653 Ok(tx)
1654 }
1655
1656 pub fn build_abi_manager_create_meta_official(
1658 fee_payer: TnPubkey,
1659 abi_manager_program: TnPubkey,
1660 program_meta_account: TnPubkey,
1661 abi_meta_account: TnPubkey,
1662 authority_account: TnPubkey,
1663 is_ephemeral: bool,
1664 abi_meta_proof: Option<&[u8]>,
1665 fee: u64,
1666 nonce: u64,
1667 start_slot: u64,
1668 ) -> Result<Transaction> {
1669 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
1670 .with_start_slot(start_slot)
1671 .with_expiry_after(10000)
1672 .with_compute_units(500_000_000)
1673 .with_memory_units(5000)
1674 .with_state_units(5000);
1675
1676 let authority_is_fee_payer = authority_account == fee_payer;
1677
1678 let mut rw_accounts = vec![(abi_meta_account, "abi_meta")];
1679 let mut r_accounts = vec![(program_meta_account, "program_meta")];
1680
1681 if !authority_is_fee_payer {
1682 r_accounts.push((authority_account, "authority"));
1683 }
1684
1685 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1686 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1687
1688 let mut accounts = rw_accounts;
1689 accounts.extend(r_accounts);
1690
1691 let mut abi_meta_account_idx = 0u16;
1692 let mut program_meta_account_idx = 0u16;
1693 let mut authority_account_idx = 0u16;
1694
1695 for (i, (account, account_type)) in accounts.iter().enumerate() {
1696 let idx = (i + 2) as u16;
1697 match *account_type {
1698 "abi_meta" => {
1699 abi_meta_account_idx = idx;
1700 tx = tx.add_rw_account(*account);
1701 }
1702 "program_meta" => {
1703 program_meta_account_idx = idx;
1704 tx = tx.add_r_account(*account);
1705 }
1706 "authority" => {
1707 authority_account_idx = idx;
1708 tx = tx.add_r_account(*account);
1709 }
1710 _ => unreachable!(),
1711 }
1712 }
1713
1714 let authority_idx = if authority_is_fee_payer {
1715 0u16
1716 } else {
1717 authority_account_idx
1718 };
1719
1720 let discriminant = if is_ephemeral {
1721 ABI_MANAGER_INSTRUCTION_CREATE_META_OFFICIAL_EPHEMERAL
1722 } else {
1723 ABI_MANAGER_INSTRUCTION_CREATE_META_OFFICIAL_PERMANENT
1724 };
1725
1726 let instruction_data = build_abi_manager_create_meta_official_instruction(
1727 discriminant,
1728 abi_meta_account_idx,
1729 program_meta_account_idx,
1730 authority_idx,
1731 abi_meta_proof,
1732 )?;
1733
1734 tx = tx.with_instructions(instruction_data);
1735 Ok(tx)
1736 }
1737
1738 pub fn build_abi_manager_create_meta_external(
1740 fee_payer: TnPubkey,
1741 abi_manager_program: TnPubkey,
1742 abi_meta_account: TnPubkey,
1743 authority_account: TnPubkey,
1744 target_program: TnPubkey,
1745 seed: [u8; 32],
1746 is_ephemeral: bool,
1747 abi_meta_proof: Option<&[u8]>,
1748 fee: u64,
1749 nonce: u64,
1750 start_slot: u64,
1751 ) -> Result<Transaction> {
1752 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
1753 .with_start_slot(start_slot)
1754 .with_expiry_after(10000)
1755 .with_compute_units(500_000_000)
1756 .with_memory_units(5000)
1757 .with_state_units(5000);
1758
1759 let authority_is_fee_payer = authority_account == fee_payer;
1760
1761 let mut rw_accounts = vec![(abi_meta_account, "abi_meta")];
1762 let mut r_accounts = Vec::new();
1763
1764 if !authority_is_fee_payer {
1765 r_accounts.push((authority_account, "authority"));
1766 }
1767
1768 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1769 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1770
1771 let mut accounts = rw_accounts;
1772 accounts.extend(r_accounts);
1773
1774 let mut abi_meta_account_idx = 0u16;
1775 let mut authority_account_idx = 0u16;
1776
1777 for (i, (account, account_type)) in accounts.iter().enumerate() {
1778 let idx = (i + 2) as u16;
1779 match *account_type {
1780 "abi_meta" => {
1781 abi_meta_account_idx = idx;
1782 tx = tx.add_rw_account(*account);
1783 }
1784 "authority" => {
1785 authority_account_idx = idx;
1786 tx = tx.add_r_account(*account);
1787 }
1788 _ => unreachable!(),
1789 }
1790 }
1791
1792 let authority_idx = if authority_is_fee_payer {
1793 0u16
1794 } else {
1795 authority_account_idx
1796 };
1797
1798 let discriminant = if is_ephemeral {
1799 ABI_MANAGER_INSTRUCTION_CREATE_META_EXTERNAL_EPHEMERAL
1800 } else {
1801 ABI_MANAGER_INSTRUCTION_CREATE_META_EXTERNAL_PERMANENT
1802 };
1803
1804 let instruction_data = build_abi_manager_create_meta_external_instruction(
1805 discriminant,
1806 abi_meta_account_idx,
1807 authority_idx,
1808 target_program,
1809 seed,
1810 abi_meta_proof,
1811 )?;
1812
1813 tx = tx.with_instructions(instruction_data);
1814 Ok(tx)
1815 }
1816
1817 #[allow(clippy::too_many_arguments)]
1819 pub fn build_abi_manager_create_abi_official(
1820 fee_payer: TnPubkey,
1821 abi_manager_program: TnPubkey,
1822 abi_meta_account: TnPubkey,
1823 program_meta_account: TnPubkey,
1824 abi_account: TnPubkey,
1825 srcbuf_account: TnPubkey,
1826 authority_account: TnPubkey,
1827 srcbuf_offset: u32,
1828 srcbuf_size: u32,
1829 is_ephemeral: bool,
1830 abi_proof: Option<&[u8]>,
1831 fee: u64,
1832 nonce: u64,
1833 start_slot: u64,
1834 ) -> Result<Transaction> {
1835 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
1836 .with_start_slot(start_slot)
1837 .with_expiry_after(10000)
1838 .with_compute_units(500_000_000)
1839 .with_memory_units(5000)
1840 .with_state_units(5000);
1841
1842 let authority_is_fee_payer = authority_account == fee_payer;
1843
1844 let mut rw_accounts = vec![(abi_account, "abi")];
1845 let mut r_accounts = vec![
1846 (abi_meta_account, "abi_meta"),
1847 (program_meta_account, "program_meta"),
1848 (srcbuf_account, "srcbuf"),
1849 ];
1850
1851 if !authority_is_fee_payer {
1852 r_accounts.push((authority_account, "authority"));
1853 }
1854
1855 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1856 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1857
1858 let mut accounts = rw_accounts;
1859 accounts.extend(r_accounts);
1860
1861 let mut abi_meta_account_idx = 0u16;
1862 let mut program_meta_account_idx = 0u16;
1863 let mut abi_account_idx = 0u16;
1864 let mut srcbuf_account_idx = 0u16;
1865 let mut authority_account_idx = 0u16;
1866
1867 for (i, (account, account_type)) in accounts.iter().enumerate() {
1868 let idx = (i + 2) as u16;
1869 match *account_type {
1870 "abi_meta" => {
1871 abi_meta_account_idx = idx;
1872 tx = tx.add_r_account(*account);
1873 }
1874 "program_meta" => {
1875 program_meta_account_idx = idx;
1876 tx = tx.add_r_account(*account);
1877 }
1878 "abi" => {
1879 abi_account_idx = idx;
1880 tx = tx.add_rw_account(*account);
1881 }
1882 "srcbuf" => {
1883 srcbuf_account_idx = idx;
1884 tx = tx.add_r_account(*account);
1885 }
1886 "authority" => {
1887 authority_account_idx = idx;
1888 tx = tx.add_r_account(*account);
1889 }
1890 _ => unreachable!(),
1891 }
1892 }
1893
1894 let authority_idx = if authority_is_fee_payer {
1895 0u16
1896 } else {
1897 authority_account_idx
1898 };
1899
1900 let discriminant = if is_ephemeral {
1901 ABI_MANAGER_INSTRUCTION_CREATE_ABI_OFFICIAL_EPHEMERAL
1902 } else {
1903 ABI_MANAGER_INSTRUCTION_CREATE_ABI_OFFICIAL_PERMANENT
1904 };
1905
1906 let instruction_data = build_abi_manager_create_abi_official_instruction(
1907 discriminant,
1908 abi_meta_account_idx,
1909 program_meta_account_idx,
1910 abi_account_idx,
1911 srcbuf_account_idx,
1912 srcbuf_offset,
1913 srcbuf_size,
1914 authority_idx,
1915 abi_proof,
1916 )?;
1917
1918 tx = tx.with_instructions(instruction_data);
1919 Ok(tx)
1920 }
1921
1922 #[allow(clippy::too_many_arguments)]
1924 pub fn build_abi_manager_create_abi_external(
1925 fee_payer: TnPubkey,
1926 abi_manager_program: TnPubkey,
1927 abi_meta_account: TnPubkey,
1928 abi_account: TnPubkey,
1929 srcbuf_account: TnPubkey,
1930 authority_account: TnPubkey,
1931 srcbuf_offset: u32,
1932 srcbuf_size: u32,
1933 is_ephemeral: bool,
1934 abi_proof: Option<&[u8]>,
1935 fee: u64,
1936 nonce: u64,
1937 start_slot: u64,
1938 ) -> Result<Transaction> {
1939 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
1940 .with_start_slot(start_slot)
1941 .with_expiry_after(10000)
1942 .with_compute_units(500_000_000)
1943 .with_memory_units(5000)
1944 .with_state_units(5000);
1945
1946 let authority_is_fee_payer = authority_account == fee_payer;
1947
1948 let mut rw_accounts = vec![(abi_account, "abi")];
1949 let mut r_accounts = vec![(abi_meta_account, "abi_meta"), (srcbuf_account, "srcbuf")];
1950
1951 if !authority_is_fee_payer {
1952 r_accounts.push((authority_account, "authority"));
1953 }
1954
1955 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1956 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1957
1958 let mut accounts = rw_accounts;
1959 accounts.extend(r_accounts);
1960
1961 let mut abi_meta_account_idx = 0u16;
1962 let mut abi_account_idx = 0u16;
1963 let mut srcbuf_account_idx = 0u16;
1964 let mut authority_account_idx = 0u16;
1965
1966 for (i, (account, account_type)) in accounts.iter().enumerate() {
1967 let idx = (i + 2) as u16;
1968 match *account_type {
1969 "abi_meta" => {
1970 abi_meta_account_idx = idx;
1971 tx = tx.add_r_account(*account);
1972 }
1973 "abi" => {
1974 abi_account_idx = idx;
1975 tx = tx.add_rw_account(*account);
1976 }
1977 "srcbuf" => {
1978 srcbuf_account_idx = idx;
1979 tx = tx.add_r_account(*account);
1980 }
1981 "authority" => {
1982 authority_account_idx = idx;
1983 tx = tx.add_r_account(*account);
1984 }
1985 _ => unreachable!(),
1986 }
1987 }
1988
1989 let authority_idx = if authority_is_fee_payer {
1990 0u16
1991 } else {
1992 authority_account_idx
1993 };
1994
1995 let discriminant = if is_ephemeral {
1996 ABI_MANAGER_INSTRUCTION_CREATE_ABI_EXTERNAL_EPHEMERAL
1997 } else {
1998 ABI_MANAGER_INSTRUCTION_CREATE_ABI_EXTERNAL_PERMANENT
1999 };
2000
2001 let instruction_data = build_abi_manager_create_abi_external_instruction(
2002 discriminant,
2003 abi_meta_account_idx,
2004 abi_account_idx,
2005 srcbuf_account_idx,
2006 srcbuf_offset,
2007 srcbuf_size,
2008 authority_idx,
2009 abi_proof,
2010 )?;
2011
2012 tx = tx.with_instructions(instruction_data);
2013 Ok(tx)
2014 }
2015
2016 #[allow(clippy::too_many_arguments)]
2018 pub fn build_abi_manager_upgrade_abi_official(
2019 fee_payer: TnPubkey,
2020 abi_manager_program: TnPubkey,
2021 abi_meta_account: TnPubkey,
2022 program_meta_account: TnPubkey,
2023 abi_account: TnPubkey,
2024 srcbuf_account: TnPubkey,
2025 authority_account: TnPubkey,
2026 srcbuf_offset: u32,
2027 srcbuf_size: u32,
2028 fee: u64,
2029 nonce: u64,
2030 start_slot: u64,
2031 ) -> Result<Transaction> {
2032 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
2033 .with_start_slot(start_slot)
2034 .with_expiry_after(10000)
2035 .with_compute_units(500_000_000)
2036 .with_memory_units(5000)
2037 .with_state_units(5000);
2038
2039 let authority_is_fee_payer = authority_account == fee_payer;
2040
2041 let mut rw_accounts = vec![(abi_account, "abi")];
2042 let mut r_accounts = vec![
2043 (abi_meta_account, "abi_meta"),
2044 (program_meta_account, "program_meta"),
2045 (srcbuf_account, "srcbuf"),
2046 ];
2047
2048 if !authority_is_fee_payer {
2049 r_accounts.push((authority_account, "authority"));
2050 }
2051
2052 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2053 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2054
2055 let mut accounts = rw_accounts;
2056 accounts.extend(r_accounts);
2057
2058 let mut abi_meta_account_idx = 0u16;
2059 let mut program_meta_account_idx = 0u16;
2060 let mut abi_account_idx = 0u16;
2061 let mut srcbuf_account_idx = 0u16;
2062 let mut authority_account_idx = 0u16;
2063
2064 for (i, (account, account_type)) in accounts.iter().enumerate() {
2065 let idx = (i + 2) as u16;
2066 match *account_type {
2067 "abi_meta" => {
2068 abi_meta_account_idx = idx;
2069 tx = tx.add_r_account(*account);
2070 }
2071 "program_meta" => {
2072 program_meta_account_idx = idx;
2073 tx = tx.add_r_account(*account);
2074 }
2075 "abi" => {
2076 abi_account_idx = idx;
2077 tx = tx.add_rw_account(*account);
2078 }
2079 "srcbuf" => {
2080 srcbuf_account_idx = idx;
2081 tx = tx.add_r_account(*account);
2082 }
2083 "authority" => {
2084 authority_account_idx = idx;
2085 tx = tx.add_r_account(*account);
2086 }
2087 _ => unreachable!(),
2088 }
2089 }
2090
2091 let authority_idx = if authority_is_fee_payer {
2092 0u16
2093 } else {
2094 authority_account_idx
2095 };
2096
2097 let instruction_data = build_abi_manager_upgrade_abi_official_instruction(
2098 abi_meta_account_idx,
2099 program_meta_account_idx,
2100 abi_account_idx,
2101 srcbuf_account_idx,
2102 srcbuf_offset,
2103 srcbuf_size,
2104 authority_idx,
2105 )?;
2106
2107 tx = tx.with_instructions(instruction_data);
2108 Ok(tx)
2109 }
2110
2111 #[allow(clippy::too_many_arguments)]
2113 pub fn build_abi_manager_upgrade_abi_external(
2114 fee_payer: TnPubkey,
2115 abi_manager_program: TnPubkey,
2116 abi_meta_account: TnPubkey,
2117 abi_account: TnPubkey,
2118 srcbuf_account: TnPubkey,
2119 authority_account: TnPubkey,
2120 srcbuf_offset: u32,
2121 srcbuf_size: u32,
2122 fee: u64,
2123 nonce: u64,
2124 start_slot: u64,
2125 ) -> Result<Transaction> {
2126 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
2127 .with_start_slot(start_slot)
2128 .with_expiry_after(10000)
2129 .with_compute_units(500_000_000)
2130 .with_memory_units(5000)
2131 .with_state_units(5000);
2132
2133 let authority_is_fee_payer = authority_account == fee_payer;
2134
2135 let mut rw_accounts = vec![(abi_account, "abi")];
2136 let mut r_accounts = vec![(abi_meta_account, "abi_meta"), (srcbuf_account, "srcbuf")];
2137
2138 if !authority_is_fee_payer {
2139 r_accounts.push((authority_account, "authority"));
2140 }
2141
2142 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2143 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2144
2145 let mut accounts = rw_accounts;
2146 accounts.extend(r_accounts);
2147
2148 let mut abi_meta_account_idx = 0u16;
2149 let mut abi_account_idx = 0u16;
2150 let mut srcbuf_account_idx = 0u16;
2151 let mut authority_account_idx = 0u16;
2152
2153 for (i, (account, account_type)) in accounts.iter().enumerate() {
2154 let idx = (i + 2) as u16;
2155 match *account_type {
2156 "abi_meta" => {
2157 abi_meta_account_idx = idx;
2158 tx = tx.add_r_account(*account);
2159 }
2160 "abi" => {
2161 abi_account_idx = idx;
2162 tx = tx.add_rw_account(*account);
2163 }
2164 "srcbuf" => {
2165 srcbuf_account_idx = idx;
2166 tx = tx.add_r_account(*account);
2167 }
2168 "authority" => {
2169 authority_account_idx = idx;
2170 tx = tx.add_r_account(*account);
2171 }
2172 _ => unreachable!(),
2173 }
2174 }
2175
2176 let authority_idx = if authority_is_fee_payer {
2177 0u16
2178 } else {
2179 authority_account_idx
2180 };
2181
2182 let instruction_data = build_abi_manager_upgrade_abi_external_instruction(
2183 abi_meta_account_idx,
2184 abi_account_idx,
2185 srcbuf_account_idx,
2186 srcbuf_offset,
2187 srcbuf_size,
2188 authority_idx,
2189 )?;
2190
2191 tx = tx.with_instructions(instruction_data);
2192 Ok(tx)
2193 }
2194
2195 pub fn build_abi_manager_finalize_abi_official(
2197 fee_payer: TnPubkey,
2198 abi_manager_program: TnPubkey,
2199 abi_meta_account: TnPubkey,
2200 program_meta_account: TnPubkey,
2201 abi_account: TnPubkey,
2202 authority_account: TnPubkey,
2203 fee: u64,
2204 nonce: u64,
2205 start_slot: u64,
2206 ) -> Result<Transaction> {
2207 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
2208 .with_start_slot(start_slot)
2209 .with_expiry_after(10000)
2210 .with_compute_units(500_000_000)
2211 .with_memory_units(5000)
2212 .with_state_units(5000);
2213
2214 let authority_is_fee_payer = authority_account == fee_payer;
2215
2216 let mut rw_accounts = vec![(abi_account, "abi")];
2217 let mut r_accounts = vec![
2218 (abi_meta_account, "abi_meta"),
2219 (program_meta_account, "program_meta"),
2220 ];
2221
2222 if !authority_is_fee_payer {
2223 r_accounts.push((authority_account, "authority"));
2224 }
2225
2226 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2227 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2228
2229 let mut accounts = rw_accounts;
2230 accounts.extend(r_accounts);
2231
2232 let mut abi_meta_account_idx = 0u16;
2233 let mut program_meta_account_idx = 0u16;
2234 let mut abi_account_idx = 0u16;
2235 let mut authority_account_idx = 0u16;
2236
2237 for (i, (account, account_type)) in accounts.iter().enumerate() {
2238 let idx = (i + 2) as u16;
2239 match *account_type {
2240 "abi_meta" => {
2241 abi_meta_account_idx = idx;
2242 tx = tx.add_r_account(*account);
2243 }
2244 "program_meta" => {
2245 program_meta_account_idx = idx;
2246 tx = tx.add_r_account(*account);
2247 }
2248 "abi" => {
2249 abi_account_idx = idx;
2250 tx = tx.add_rw_account(*account);
2251 }
2252 "authority" => {
2253 authority_account_idx = idx;
2254 tx = tx.add_r_account(*account);
2255 }
2256 _ => unreachable!(),
2257 }
2258 }
2259
2260 let authority_idx = if authority_is_fee_payer {
2261 0u16
2262 } else {
2263 authority_account_idx
2264 };
2265
2266 let instruction_data = build_abi_manager_finalize_abi_official_instruction(
2267 abi_meta_account_idx,
2268 program_meta_account_idx,
2269 abi_account_idx,
2270 authority_idx,
2271 )?;
2272
2273 tx = tx.with_instructions(instruction_data);
2274 Ok(tx)
2275 }
2276
2277 pub fn build_abi_manager_finalize_abi_external(
2279 fee_payer: TnPubkey,
2280 abi_manager_program: TnPubkey,
2281 abi_meta_account: TnPubkey,
2282 abi_account: TnPubkey,
2283 authority_account: TnPubkey,
2284 fee: u64,
2285 nonce: u64,
2286 start_slot: u64,
2287 ) -> Result<Transaction> {
2288 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
2289 .with_start_slot(start_slot)
2290 .with_expiry_after(10000)
2291 .with_compute_units(500_000_000)
2292 .with_memory_units(5000)
2293 .with_state_units(5000);
2294
2295 let authority_is_fee_payer = authority_account == fee_payer;
2296
2297 let mut rw_accounts = vec![(abi_account, "abi")];
2298 let mut r_accounts = vec![(abi_meta_account, "abi_meta")];
2299
2300 if !authority_is_fee_payer {
2301 r_accounts.push((authority_account, "authority"));
2302 }
2303
2304 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2305 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2306
2307 let mut accounts = rw_accounts;
2308 accounts.extend(r_accounts);
2309
2310 let mut abi_meta_account_idx = 0u16;
2311 let mut abi_account_idx = 0u16;
2312 let mut authority_account_idx = 0u16;
2313
2314 for (i, (account, account_type)) in accounts.iter().enumerate() {
2315 let idx = (i + 2) as u16;
2316 match *account_type {
2317 "abi_meta" => {
2318 abi_meta_account_idx = idx;
2319 tx = tx.add_r_account(*account);
2320 }
2321 "abi" => {
2322 abi_account_idx = idx;
2323 tx = tx.add_rw_account(*account);
2324 }
2325 "authority" => {
2326 authority_account_idx = idx;
2327 tx = tx.add_r_account(*account);
2328 }
2329 _ => unreachable!(),
2330 }
2331 }
2332
2333 let authority_idx = if authority_is_fee_payer {
2334 0u16
2335 } else {
2336 authority_account_idx
2337 };
2338
2339 let instruction_data = build_abi_manager_finalize_abi_external_instruction(
2340 abi_meta_account_idx,
2341 abi_account_idx,
2342 authority_idx,
2343 )?;
2344
2345 tx = tx.with_instructions(instruction_data);
2346 Ok(tx)
2347 }
2348
2349 pub fn build_abi_manager_close_abi_official(
2351 fee_payer: TnPubkey,
2352 abi_manager_program: TnPubkey,
2353 abi_meta_account: TnPubkey,
2354 program_meta_account: TnPubkey,
2355 abi_account: TnPubkey,
2356 authority_account: TnPubkey,
2357 fee: u64,
2358 nonce: u64,
2359 start_slot: u64,
2360 ) -> Result<Transaction> {
2361 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
2362 .with_start_slot(start_slot)
2363 .with_expiry_after(10000)
2364 .with_compute_units(500_000_000)
2365 .with_memory_units(5000)
2366 .with_state_units(5000);
2367
2368 let authority_is_fee_payer = authority_account == fee_payer;
2369
2370 let mut rw_accounts = vec![(abi_account, "abi")];
2371 let mut r_accounts = vec![
2372 (abi_meta_account, "abi_meta"),
2373 (program_meta_account, "program_meta"),
2374 ];
2375
2376 if !authority_is_fee_payer {
2377 r_accounts.push((authority_account, "authority"));
2378 }
2379
2380 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2381 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2382
2383 let mut accounts = rw_accounts;
2384 accounts.extend(r_accounts);
2385
2386 let mut abi_meta_account_idx = 0u16;
2387 let mut program_meta_account_idx = 0u16;
2388 let mut abi_account_idx = 0u16;
2389 let mut authority_account_idx = 0u16;
2390
2391 for (i, (account, account_type)) in accounts.iter().enumerate() {
2392 let idx = (i + 2) as u16;
2393 match *account_type {
2394 "abi_meta" => {
2395 abi_meta_account_idx = idx;
2396 tx = tx.add_r_account(*account);
2397 }
2398 "program_meta" => {
2399 program_meta_account_idx = idx;
2400 tx = tx.add_r_account(*account);
2401 }
2402 "abi" => {
2403 abi_account_idx = idx;
2404 tx = tx.add_rw_account(*account);
2405 }
2406 "authority" => {
2407 authority_account_idx = idx;
2408 tx = tx.add_r_account(*account);
2409 }
2410 _ => unreachable!(),
2411 }
2412 }
2413
2414 let authority_idx = if authority_is_fee_payer {
2415 0u16
2416 } else {
2417 authority_account_idx
2418 };
2419
2420 let instruction_data = build_abi_manager_close_abi_official_instruction(
2421 abi_meta_account_idx,
2422 program_meta_account_idx,
2423 abi_account_idx,
2424 authority_idx,
2425 )?;
2426
2427 tx = tx.with_instructions(instruction_data);
2428 Ok(tx)
2429 }
2430
2431 pub fn build_abi_manager_close_abi_external(
2433 fee_payer: TnPubkey,
2434 abi_manager_program: TnPubkey,
2435 abi_meta_account: TnPubkey,
2436 abi_account: TnPubkey,
2437 authority_account: TnPubkey,
2438 fee: u64,
2439 nonce: u64,
2440 start_slot: u64,
2441 ) -> Result<Transaction> {
2442 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
2443 .with_start_slot(start_slot)
2444 .with_expiry_after(10000)
2445 .with_compute_units(500_000_000)
2446 .with_memory_units(5000)
2447 .with_state_units(5000);
2448
2449 let authority_is_fee_payer = authority_account == fee_payer;
2450
2451 let mut rw_accounts = vec![(abi_account, "abi")];
2452 let mut r_accounts = vec![(abi_meta_account, "abi_meta")];
2453
2454 if !authority_is_fee_payer {
2455 r_accounts.push((authority_account, "authority"));
2456 }
2457
2458 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2459 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2460
2461 let mut accounts = rw_accounts;
2462 accounts.extend(r_accounts);
2463
2464 let mut abi_meta_account_idx = 0u16;
2465 let mut abi_account_idx = 0u16;
2466 let mut authority_account_idx = 0u16;
2467
2468 for (i, (account, account_type)) in accounts.iter().enumerate() {
2469 let idx = (i + 2) as u16;
2470 match *account_type {
2471 "abi_meta" => {
2472 abi_meta_account_idx = idx;
2473 tx = tx.add_r_account(*account);
2474 }
2475 "abi" => {
2476 abi_account_idx = idx;
2477 tx = tx.add_rw_account(*account);
2478 }
2479 "authority" => {
2480 authority_account_idx = idx;
2481 tx = tx.add_r_account(*account);
2482 }
2483 _ => unreachable!(),
2484 }
2485 }
2486
2487 let authority_idx = if authority_is_fee_payer {
2488 0u16
2489 } else {
2490 authority_account_idx
2491 };
2492
2493 let instruction_data = build_abi_manager_close_abi_external_instruction(
2494 abi_meta_account_idx,
2495 abi_account_idx,
2496 authority_idx,
2497 )?;
2498
2499 tx = tx.with_instructions(instruction_data);
2500 Ok(tx)
2501 }
2502
2503 pub fn build_manager_upgrade(
2505 fee_payer: TnPubkey,
2506 manager_program: TnPubkey,
2507 meta_account: TnPubkey,
2508 program_account: TnPubkey,
2509 srcbuf_account: TnPubkey,
2510 srcbuf_offset: u32,
2511 srcbuf_size: u32,
2512 fee: u64,
2513 nonce: u64,
2514 start_slot: u64,
2515 ) -> Result<Transaction> {
2516 let mut tx = Transaction::new(fee_payer, manager_program, fee, nonce)
2517 .with_start_slot(start_slot)
2518 .with_expiry_after(10000)
2519 .with_compute_units(500_000_000)
2520 .with_memory_units(5000)
2521 .with_state_units(5000);
2522
2523 let mut rw_accounts = vec![(meta_account, "meta"), (program_account, "program")];
2525
2526 let mut r_accounts = vec![(srcbuf_account, "srcbuf")];
2527
2528 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2530
2531 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2533
2534 let mut accounts = rw_accounts;
2536 accounts.extend(r_accounts);
2537
2538 let mut meta_account_idx = 0u16;
2539 let mut program_account_idx = 0u16;
2540 let mut srcbuf_account_idx = 0u16;
2541
2542 for (i, (account, account_type)) in accounts.iter().enumerate() {
2543 let idx = (i + 2) as u16; match *account_type {
2545 "meta" => {
2546 meta_account_idx = idx;
2547 tx = tx.add_rw_account(*account);
2548 }
2549 "program" => {
2550 program_account_idx = idx;
2551 tx = tx.add_rw_account(*account);
2552 }
2553 "srcbuf" => {
2554 srcbuf_account_idx = idx;
2555 tx = tx.add_r_account(*account);
2556 }
2557 _ => unreachable!(),
2558 }
2559 }
2560
2561 let instruction_data = build_manager_upgrade_instruction(
2562 meta_account_idx,
2563 program_account_idx,
2564 srcbuf_account_idx,
2565 srcbuf_offset,
2566 srcbuf_size,
2567 )?;
2568
2569 tx = tx.with_instructions(instruction_data);
2570 Ok(tx)
2571 }
2572
2573 pub fn build_manager_set_pause(
2575 fee_payer: TnPubkey,
2576 manager_program: TnPubkey,
2577 meta_account: TnPubkey,
2578 program_account: TnPubkey,
2579 is_paused: bool,
2580 fee: u64,
2581 nonce: u64,
2582 start_slot: u64,
2583 ) -> Result<Transaction> {
2584 let mut tx = Transaction::new(fee_payer, manager_program, fee, nonce)
2585 .with_start_slot(start_slot)
2586 .with_expiry_after(10000)
2587 .with_compute_units(100_000_000)
2588 .with_memory_units(5000)
2589 .with_state_units(5000);
2590
2591 let mut accounts = vec![(meta_account, "meta"), (program_account, "program")];
2593 accounts.sort_by(|a, b| a.0.cmp(&b.0));
2594
2595 let mut meta_account_idx = 0u16;
2596 let mut program_account_idx = 0u16;
2597
2598 for (i, (account, account_type)) in accounts.iter().enumerate() {
2599 let idx = (i + 2) as u16;
2600 match *account_type {
2601 "meta" => {
2602 meta_account_idx = idx;
2603 tx = tx.add_rw_account(*account);
2604 }
2605 "program" => {
2606 program_account_idx = idx;
2607 tx = tx.add_rw_account(*account);
2608 }
2609 _ => unreachable!(),
2610 }
2611 }
2612
2613 let instruction_data =
2614 build_manager_set_pause_instruction(meta_account_idx, program_account_idx, is_paused)?;
2615
2616 tx = tx.with_instructions(instruction_data);
2617 Ok(tx)
2618 }
2619
2620 pub fn build_manager_simple(
2622 fee_payer: TnPubkey,
2623 manager_program: TnPubkey,
2624 meta_account: TnPubkey,
2625 program_account: TnPubkey,
2626 instruction_type: u8,
2627 fee: u64,
2628 nonce: u64,
2629 start_slot: u64,
2630 ) -> Result<Transaction> {
2631 let mut tx = Transaction::new(fee_payer, manager_program, fee, nonce)
2632 .with_start_slot(start_slot)
2633 .with_expiry_after(10000)
2634 .with_compute_units(100_000_000)
2635 .with_memory_units(5000)
2636 .with_state_units(5000);
2637
2638 let mut accounts = vec![(meta_account, "meta"), (program_account, "program")];
2640 accounts.sort_by(|a, b| a.0.cmp(&b.0));
2641
2642 let mut meta_account_idx = 0u16;
2643 let mut program_account_idx = 0u16;
2644
2645 for (i, (account, account_type)) in accounts.iter().enumerate() {
2646 let idx = (i + 2) as u16;
2647 match *account_type {
2648 "meta" => {
2649 meta_account_idx = idx;
2650 tx = tx.add_rw_account(*account);
2651 }
2652 "program" => {
2653 program_account_idx = idx;
2654 tx = tx.add_rw_account(*account);
2655 }
2656 _ => unreachable!(),
2657 }
2658 }
2659
2660 let instruction_data = build_manager_header_instruction(
2661 instruction_type,
2662 meta_account_idx,
2663 program_account_idx,
2664 )?;
2665
2666 tx = tx.with_instructions(instruction_data);
2667 Ok(tx)
2668 }
2669
2670 pub fn build_manager_set_authority(
2672 fee_payer: TnPubkey,
2673 manager_program: TnPubkey,
2674 meta_account: TnPubkey,
2675 program_account: TnPubkey,
2676 authority_candidate: [u8; 32],
2677 fee: u64,
2678 nonce: u64,
2679 start_slot: u64,
2680 ) -> Result<Transaction> {
2681 let mut tx = Transaction::new(fee_payer, manager_program, fee, nonce)
2682 .with_start_slot(start_slot)
2683 .with_expiry_after(10000)
2684 .with_compute_units(100_000_000)
2685 .with_memory_units(5000)
2686 .with_state_units(5000);
2687
2688 let mut accounts = vec![(meta_account, "meta"), (program_account, "program")];
2690 accounts.sort_by(|a, b| a.0.cmp(&b.0));
2691
2692 let mut meta_account_idx = 0u16;
2693 let mut program_account_idx = 0u16;
2694
2695 for (i, (account, account_type)) in accounts.iter().enumerate() {
2696 let idx = (i + 2) as u16;
2697 match *account_type {
2698 "meta" => {
2699 meta_account_idx = idx;
2700 tx = tx.add_rw_account(*account);
2701 }
2702 "program" => {
2703 program_account_idx = idx;
2704 tx = tx.add_rw_account(*account);
2705 }
2706 _ => unreachable!(),
2707 }
2708 }
2709
2710 let instruction_data = build_manager_set_authority_instruction(
2711 meta_account_idx,
2712 program_account_idx,
2713 authority_candidate,
2714 )?;
2715
2716 tx = tx.with_instructions(instruction_data);
2717 Ok(tx)
2718 }
2719
2720 pub fn build_test_uploader_create(
2722 fee_payer: TnPubkey,
2723 test_uploader_program: TnPubkey,
2724 target_account: TnPubkey,
2725 account_sz: u32,
2726 seed: &[u8],
2727 is_ephemeral: bool,
2728 state_proof: Option<&[u8]>,
2729 fee: u64,
2730 nonce: u64,
2731 start_slot: u64,
2732 ) -> Result<Transaction> {
2733 let target_account_idx = 2u16;
2735
2736 let tx = Transaction::new(fee_payer, test_uploader_program, fee, nonce)
2737 .with_start_slot(start_slot)
2738 .with_expiry_after(100)
2739 .with_compute_units(100_000 + account_sz)
2740 .with_memory_units(10_000)
2741 .with_state_units(10_000)
2742 .add_rw_account(target_account);
2743
2744 let instruction_data = build_test_uploader_create_instruction(
2745 target_account_idx,
2746 account_sz,
2747 seed,
2748 is_ephemeral,
2749 state_proof,
2750 )?;
2751
2752 let tx = tx.with_instructions(instruction_data);
2753 Ok(tx)
2754 }
2755
2756 pub fn build_test_uploader_write(
2758 fee_payer: TnPubkey,
2759 test_uploader_program: TnPubkey,
2760 target_account: TnPubkey,
2761 offset: u32,
2762 data: &[u8],
2763 fee: u64,
2764 nonce: u64,
2765 start_slot: u64,
2766 ) -> Result<Transaction> {
2767 let target_account_idx = 2u16;
2769
2770 let tx = Transaction::new(fee_payer, test_uploader_program, fee, nonce)
2771 .with_start_slot(start_slot)
2772 .with_expiry_after(10_000)
2773 .with_compute_units(100_000 + 18 * data.len() as u32)
2774 .with_memory_units(10_000)
2775 .with_state_units(10_000)
2776 .add_rw_account(target_account);
2777
2778 let instruction_data =
2779 build_test_uploader_write_instruction(target_account_idx, offset, data)?;
2780
2781 let tx = tx.with_instructions(instruction_data);
2782 Ok(tx)
2783 }
2784
2785 pub fn build_decompress2(
2787 fee_payer: TnPubkey,
2788 program: TnPubkey,
2789 target_account: TnPubkey,
2790 meta_account: TnPubkey,
2791 data_account: TnPubkey,
2792 data_offset: u32,
2793 state_proof: &[u8],
2794 fee: u64,
2795 nonce: u64,
2796 start_slot: u64,
2797 data_sz: u32,
2798 ) -> Result<Transaction> {
2799 let mut tx = Transaction::new(fee_payer, program, fee, nonce)
2801 .with_start_slot(start_slot)
2802 .with_expiry_after(100)
2803 .with_compute_units(10_000 + 2 * data_sz)
2804 .with_memory_units(10_000)
2805 .with_state_units(10);
2806
2807 let target_account_idx = 2u16;
2809 tx = tx.add_rw_account(target_account);
2810
2811 let mut meta_account_idx = 0u16;
2812 let mut data_account_idx = 0u16;
2813
2814 if meta_account == data_account {
2816 let account_idx = 3u16;
2818 meta_account_idx = account_idx;
2819 data_account_idx = account_idx;
2820 tx = tx.add_r_account(meta_account);
2821 } else {
2822 let mut read_accounts = vec![(meta_account, "meta"), (data_account, "data")];
2824 read_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2825
2826 for (i, (account, account_type)) in read_accounts.iter().enumerate() {
2827 let idx = (3 + i) as u16; match *account_type {
2829 "meta" => {
2830 meta_account_idx = idx;
2831 tx = tx.add_r_account(*account);
2832 }
2833 "data" => {
2834 data_account_idx = idx;
2835 tx = tx.add_r_account(*account);
2836 }
2837 _ => unreachable!(),
2838 }
2839 }
2840 }
2841
2842 let instruction_data = build_decompress2_instruction(
2843 target_account_idx,
2844 meta_account_idx,
2845 data_account_idx,
2846 data_offset,
2847 state_proof,
2848 )?;
2849
2850 tx = tx.with_instructions(instruction_data);
2851 Ok(tx)
2852 }
2853}
2854
2855fn build_uploader_create_instruction(
2857 buffer_account_idx: u16,
2858 meta_account_idx: u16,
2859 authority_account_idx: u16,
2860 buffer_size: u32,
2861 expected_hash: [u8; 32],
2862 seed: &[u8],
2863) -> Result<Vec<u8>> {
2864 let mut instruction = Vec::new();
2865
2866 instruction.extend_from_slice(&TN_UPLOADER_PROGRAM_INSTRUCTION_CREATE.to_le_bytes());
2868
2869 let args = UploaderCreateArgs {
2871 buffer_account_idx,
2872 meta_account_idx,
2873 authority_account_idx,
2874 buffer_account_sz: buffer_size,
2875 expected_account_hash: expected_hash,
2876 seed_len: seed.len() as u32,
2877 };
2878
2879 let args_bytes = unsafe {
2881 std::slice::from_raw_parts(
2882 &args as *const _ as *const u8,
2883 std::mem::size_of::<UploaderCreateArgs>(),
2884 )
2885 };
2886 instruction.extend_from_slice(args_bytes);
2887
2888 instruction.extend_from_slice(seed);
2890
2891 Ok(instruction)
2892}
2893
2894fn build_uploader_write_instruction(
2896 buffer_account_idx: u16,
2897 meta_account_idx: u16,
2898 data: &[u8],
2899 offset: u32,
2900) -> Result<Vec<u8>> {
2901 let mut instruction = Vec::new();
2902
2903 instruction.extend_from_slice(&TN_UPLOADER_PROGRAM_INSTRUCTION_WRITE.to_le_bytes());
2905
2906 let args = UploaderWriteArgs {
2908 buffer_account_idx,
2909 meta_account_idx,
2910 data_len: data.len() as u32,
2911 data_offset: offset,
2912 };
2913
2914 let args_bytes = unsafe {
2916 std::slice::from_raw_parts(
2917 &args as *const _ as *const u8,
2918 std::mem::size_of::<UploaderWriteArgs>(),
2919 )
2920 };
2921 instruction.extend_from_slice(args_bytes);
2922
2923 instruction.extend_from_slice(data);
2925
2926 Ok(instruction)
2927}
2928
2929fn build_uploader_finalize_instruction(
2931 buffer_account_idx: u16,
2932 meta_account_idx: u16,
2933 expected_hash: [u8; 32],
2934) -> Result<Vec<u8>> {
2935 let mut instruction = Vec::new();
2936
2937 instruction.extend_from_slice(&TN_UPLOADER_PROGRAM_INSTRUCTION_FINALIZE.to_le_bytes());
2939
2940 let args = UploaderFinalizeArgs {
2942 buffer_account_idx,
2943 meta_account_idx,
2944 expected_account_hash: expected_hash,
2945 };
2946
2947 let args_bytes = unsafe {
2949 std::slice::from_raw_parts(
2950 &args as *const _ as *const u8,
2951 std::mem::size_of::<UploaderFinalizeArgs>(),
2952 )
2953 };
2954 instruction.extend_from_slice(args_bytes);
2955
2956 Ok(instruction)
2957}
2958
2959fn build_uploader_destroy_instruction(
2961 buffer_account_idx: u16,
2962 meta_account_idx: u16,
2963) -> Result<Vec<u8>> {
2964 let mut instruction = Vec::new();
2965
2966 instruction.extend_from_slice(&TN_UPLOADER_PROGRAM_INSTRUCTION_DESTROY.to_le_bytes());
2968
2969 let args = UploaderDestroyArgs {
2971 buffer_account_idx,
2972 meta_account_idx,
2973 };
2974
2975 let args_bytes = unsafe {
2977 std::slice::from_raw_parts(
2978 &args as *const _ as *const u8,
2979 std::mem::size_of::<UploaderDestroyArgs>(),
2980 )
2981 };
2982 instruction.extend_from_slice(args_bytes);
2983
2984 Ok(instruction)
2985}
2986
2987fn build_manager_create_instruction(
2989 discriminant: u8,
2990 meta_account_idx: u16,
2991 program_account_idx: u16,
2992 srcbuf_account_idx: u16,
2993 authority_account_idx: u16,
2994 srcbuf_offset: u32,
2995 srcbuf_size: u32,
2996 seed: &[u8],
2997 proof: Option<&[u8]>,
2998) -> Result<Vec<u8>> {
2999 let mut instruction = Vec::new();
3000
3001 let args = ManagerCreateArgs {
3003 discriminant,
3004 meta_account_idx,
3005 program_account_idx,
3006 srcbuf_account_idx,
3007 srcbuf_offset,
3008 srcbuf_size,
3009 authority_account_idx,
3010 seed_len: seed.len() as u32,
3011 };
3012
3013 let args_bytes = unsafe {
3015 std::slice::from_raw_parts(
3016 &args as *const ManagerCreateArgs as *const u8,
3017 std::mem::size_of::<ManagerCreateArgs>(),
3018 )
3019 };
3020 instruction.extend_from_slice(args_bytes);
3021
3022 instruction.extend_from_slice(seed);
3024
3025 if let Some(proof_bytes) = proof {
3027 instruction.extend_from_slice(proof_bytes);
3028 }
3029
3030 Ok(instruction)
3031}
3032
3033fn build_abi_manager_create_meta_official_instruction(
3035 discriminant: u8,
3036 abi_meta_account_idx: u16,
3037 program_meta_account_idx: u16,
3038 authority_account_idx: u16,
3039 proof: Option<&[u8]>,
3040) -> Result<Vec<u8>> {
3041 let mut instruction = Vec::new();
3042 instruction.push(discriminant);
3043
3044 let args = AbiManagerCreateMetaOfficialArgs {
3045 abi_meta_account_idx,
3046 program_meta_account_idx,
3047 authority_account_idx,
3048 };
3049
3050 let args_bytes = unsafe {
3051 std::slice::from_raw_parts(
3052 &args as *const AbiManagerCreateMetaOfficialArgs as *const u8,
3053 std::mem::size_of::<AbiManagerCreateMetaOfficialArgs>(),
3054 )
3055 };
3056
3057 instruction.extend_from_slice(args_bytes);
3058 if let Some(proof_bytes) = proof {
3059 instruction.extend_from_slice(proof_bytes);
3060 }
3061
3062 Ok(instruction)
3063}
3064
3065fn build_abi_manager_create_meta_external_instruction(
3067 discriminant: u8,
3068 abi_meta_account_idx: u16,
3069 authority_account_idx: u16,
3070 target_program: TnPubkey,
3071 seed: [u8; 32],
3072 proof: Option<&[u8]>,
3073) -> Result<Vec<u8>> {
3074 let mut instruction = Vec::new();
3075 instruction.push(discriminant);
3076
3077 let args = AbiManagerCreateMetaExternalArgs {
3078 abi_meta_account_idx,
3079 authority_account_idx,
3080 target_program,
3081 seed,
3082 };
3083
3084 let args_bytes = unsafe {
3085 std::slice::from_raw_parts(
3086 &args as *const AbiManagerCreateMetaExternalArgs as *const u8,
3087 std::mem::size_of::<AbiManagerCreateMetaExternalArgs>(),
3088 )
3089 };
3090
3091 instruction.extend_from_slice(args_bytes);
3092 if let Some(proof_bytes) = proof {
3093 instruction.extend_from_slice(proof_bytes);
3094 }
3095
3096 Ok(instruction)
3097}
3098
3099fn build_abi_manager_create_abi_official_instruction(
3101 discriminant: u8,
3102 abi_meta_account_idx: u16,
3103 program_meta_account_idx: u16,
3104 abi_account_idx: u16,
3105 srcbuf_account_idx: u16,
3106 srcbuf_offset: u32,
3107 srcbuf_size: u32,
3108 authority_account_idx: u16,
3109 proof: Option<&[u8]>,
3110) -> Result<Vec<u8>> {
3111 let mut instruction = Vec::new();
3112 instruction.push(discriminant);
3113
3114 let args = AbiManagerCreateAbiOfficialArgs {
3115 abi_meta_account_idx,
3116 program_meta_account_idx,
3117 abi_account_idx,
3118 srcbuf_account_idx,
3119 srcbuf_offset,
3120 srcbuf_size,
3121 authority_account_idx,
3122 };
3123
3124 let args_bytes = unsafe {
3125 std::slice::from_raw_parts(
3126 &args as *const AbiManagerCreateAbiOfficialArgs as *const u8,
3127 std::mem::size_of::<AbiManagerCreateAbiOfficialArgs>(),
3128 )
3129 };
3130
3131 instruction.extend_from_slice(args_bytes);
3132 if let Some(proof_bytes) = proof {
3133 instruction.extend_from_slice(proof_bytes);
3134 }
3135
3136 Ok(instruction)
3137}
3138
3139fn build_abi_manager_create_abi_external_instruction(
3141 discriminant: u8,
3142 abi_meta_account_idx: u16,
3143 abi_account_idx: u16,
3144 srcbuf_account_idx: u16,
3145 srcbuf_offset: u32,
3146 srcbuf_size: u32,
3147 authority_account_idx: u16,
3148 proof: Option<&[u8]>,
3149) -> Result<Vec<u8>> {
3150 let mut instruction = Vec::new();
3151 instruction.push(discriminant);
3152
3153 let args = AbiManagerCreateAbiExternalArgs {
3154 abi_meta_account_idx,
3155 abi_account_idx,
3156 srcbuf_account_idx,
3157 srcbuf_offset,
3158 srcbuf_size,
3159 authority_account_idx,
3160 };
3161
3162 let args_bytes = unsafe {
3163 std::slice::from_raw_parts(
3164 &args as *const AbiManagerCreateAbiExternalArgs as *const u8,
3165 std::mem::size_of::<AbiManagerCreateAbiExternalArgs>(),
3166 )
3167 };
3168
3169 instruction.extend_from_slice(args_bytes);
3170 if let Some(proof_bytes) = proof {
3171 instruction.extend_from_slice(proof_bytes);
3172 }
3173
3174 Ok(instruction)
3175}
3176
3177fn build_abi_manager_upgrade_abi_official_instruction(
3178 abi_meta_account_idx: u16,
3179 program_meta_account_idx: u16,
3180 abi_account_idx: u16,
3181 srcbuf_account_idx: u16,
3182 srcbuf_offset: u32,
3183 srcbuf_size: u32,
3184 authority_account_idx: u16,
3185) -> Result<Vec<u8>> {
3186 let mut instruction = Vec::new();
3187 instruction.push(ABI_MANAGER_INSTRUCTION_UPGRADE_ABI_OFFICIAL);
3188
3189 let args = AbiManagerUpgradeAbiOfficialArgs {
3190 abi_meta_account_idx,
3191 program_meta_account_idx,
3192 abi_account_idx,
3193 srcbuf_account_idx,
3194 srcbuf_offset,
3195 srcbuf_size,
3196 authority_account_idx,
3197 };
3198
3199 let args_bytes = unsafe {
3200 std::slice::from_raw_parts(
3201 &args as *const AbiManagerUpgradeAbiOfficialArgs as *const u8,
3202 std::mem::size_of::<AbiManagerUpgradeAbiOfficialArgs>(),
3203 )
3204 };
3205
3206 instruction.extend_from_slice(args_bytes);
3207 Ok(instruction)
3208}
3209
3210fn build_abi_manager_upgrade_abi_external_instruction(
3211 abi_meta_account_idx: u16,
3212 abi_account_idx: u16,
3213 srcbuf_account_idx: u16,
3214 srcbuf_offset: u32,
3215 srcbuf_size: u32,
3216 authority_account_idx: u16,
3217) -> Result<Vec<u8>> {
3218 let mut instruction = Vec::new();
3219 instruction.push(ABI_MANAGER_INSTRUCTION_UPGRADE_ABI_EXTERNAL);
3220
3221 let args = AbiManagerUpgradeAbiExternalArgs {
3222 abi_meta_account_idx,
3223 abi_account_idx,
3224 srcbuf_account_idx,
3225 srcbuf_offset,
3226 srcbuf_size,
3227 authority_account_idx,
3228 };
3229
3230 let args_bytes = unsafe {
3231 std::slice::from_raw_parts(
3232 &args as *const AbiManagerUpgradeAbiExternalArgs as *const u8,
3233 std::mem::size_of::<AbiManagerUpgradeAbiExternalArgs>(),
3234 )
3235 };
3236
3237 instruction.extend_from_slice(args_bytes);
3238 Ok(instruction)
3239}
3240
3241fn build_abi_manager_finalize_abi_official_instruction(
3242 abi_meta_account_idx: u16,
3243 program_meta_account_idx: u16,
3244 abi_account_idx: u16,
3245 authority_account_idx: u16,
3246) -> Result<Vec<u8>> {
3247 let mut instruction = Vec::new();
3248 instruction.push(ABI_MANAGER_INSTRUCTION_FINALIZE_ABI_OFFICIAL);
3249
3250 let args = AbiManagerFinalizeAbiOfficialArgs {
3251 abi_meta_account_idx,
3252 program_meta_account_idx,
3253 abi_account_idx,
3254 authority_account_idx,
3255 };
3256
3257 let args_bytes = unsafe {
3258 std::slice::from_raw_parts(
3259 &args as *const AbiManagerFinalizeAbiOfficialArgs as *const u8,
3260 std::mem::size_of::<AbiManagerFinalizeAbiOfficialArgs>(),
3261 )
3262 };
3263
3264 instruction.extend_from_slice(args_bytes);
3265 Ok(instruction)
3266}
3267
3268fn build_abi_manager_finalize_abi_external_instruction(
3269 abi_meta_account_idx: u16,
3270 abi_account_idx: u16,
3271 authority_account_idx: u16,
3272) -> Result<Vec<u8>> {
3273 let mut instruction = Vec::new();
3274 instruction.push(ABI_MANAGER_INSTRUCTION_FINALIZE_ABI_EXTERNAL);
3275
3276 let args = AbiManagerFinalizeAbiExternalArgs {
3277 abi_meta_account_idx,
3278 abi_account_idx,
3279 authority_account_idx,
3280 };
3281
3282 let args_bytes = unsafe {
3283 std::slice::from_raw_parts(
3284 &args as *const AbiManagerFinalizeAbiExternalArgs as *const u8,
3285 std::mem::size_of::<AbiManagerFinalizeAbiExternalArgs>(),
3286 )
3287 };
3288
3289 instruction.extend_from_slice(args_bytes);
3290 Ok(instruction)
3291}
3292
3293fn build_abi_manager_close_abi_official_instruction(
3294 abi_meta_account_idx: u16,
3295 program_meta_account_idx: u16,
3296 abi_account_idx: u16,
3297 authority_account_idx: u16,
3298) -> Result<Vec<u8>> {
3299 let mut instruction = Vec::new();
3300 instruction.push(ABI_MANAGER_INSTRUCTION_CLOSE_ABI_OFFICIAL);
3301
3302 let args = AbiManagerCloseAbiOfficialArgs {
3303 abi_meta_account_idx,
3304 program_meta_account_idx,
3305 abi_account_idx,
3306 authority_account_idx,
3307 };
3308
3309 let args_bytes = unsafe {
3310 std::slice::from_raw_parts(
3311 &args as *const AbiManagerCloseAbiOfficialArgs as *const u8,
3312 std::mem::size_of::<AbiManagerCloseAbiOfficialArgs>(),
3313 )
3314 };
3315
3316 instruction.extend_from_slice(args_bytes);
3317 Ok(instruction)
3318}
3319
3320fn build_abi_manager_close_abi_external_instruction(
3321 abi_meta_account_idx: u16,
3322 abi_account_idx: u16,
3323 authority_account_idx: u16,
3324) -> Result<Vec<u8>> {
3325 let mut instruction = Vec::new();
3326 instruction.push(ABI_MANAGER_INSTRUCTION_CLOSE_ABI_EXTERNAL);
3327
3328 let args = AbiManagerCloseAbiExternalArgs {
3329 abi_meta_account_idx,
3330 abi_account_idx,
3331 authority_account_idx,
3332 };
3333
3334 let args_bytes = unsafe {
3335 std::slice::from_raw_parts(
3336 &args as *const AbiManagerCloseAbiExternalArgs as *const u8,
3337 std::mem::size_of::<AbiManagerCloseAbiExternalArgs>(),
3338 )
3339 };
3340
3341 instruction.extend_from_slice(args_bytes);
3342 Ok(instruction)
3343}
3344
3345fn build_manager_upgrade_instruction(
3347 meta_account_idx: u16,
3348 program_account_idx: u16,
3349 srcbuf_account_idx: u16,
3350 srcbuf_offset: u32,
3351 srcbuf_size: u32,
3352) -> Result<Vec<u8>> {
3353 let mut instruction = Vec::new();
3354
3355 let args = ManagerUpgradeArgs {
3356 discriminant: MANAGER_INSTRUCTION_UPGRADE,
3357 meta_account_idx,
3358 program_account_idx,
3359 srcbuf_account_idx,
3360 srcbuf_offset,
3361 srcbuf_size,
3362 };
3363
3364 let args_bytes = unsafe {
3365 std::slice::from_raw_parts(
3366 &args as *const ManagerUpgradeArgs as *const u8,
3367 std::mem::size_of::<ManagerUpgradeArgs>(),
3368 )
3369 };
3370 instruction.extend_from_slice(args_bytes);
3371
3372 Ok(instruction)
3373}
3374
3375fn build_manager_set_pause_instruction(
3377 meta_account_idx: u16,
3378 program_account_idx: u16,
3379 is_paused: bool,
3380) -> Result<Vec<u8>> {
3381 let mut instruction = Vec::new();
3382
3383 let args = ManagerSetPauseArgs {
3384 discriminant: MANAGER_INSTRUCTION_SET_PAUSE,
3385 meta_account_idx,
3386 program_account_idx,
3387 is_paused: if is_paused { 1 } else { 0 },
3388 };
3389
3390 let args_bytes = unsafe {
3391 std::slice::from_raw_parts(
3392 &args as *const ManagerSetPauseArgs as *const u8,
3393 std::mem::size_of::<ManagerSetPauseArgs>(),
3394 )
3395 };
3396 instruction.extend_from_slice(args_bytes);
3397
3398 Ok(instruction)
3399}
3400
3401fn build_manager_header_instruction(
3403 discriminant: u8,
3404 meta_account_idx: u16,
3405 program_account_idx: u16,
3406) -> Result<Vec<u8>> {
3407 let mut instruction = Vec::new();
3408
3409 let args = ManagerHeaderArgs {
3410 discriminant,
3411 meta_account_idx,
3412 program_account_idx,
3413 };
3414
3415 let args_bytes = unsafe {
3416 std::slice::from_raw_parts(
3417 &args as *const ManagerHeaderArgs as *const u8,
3418 std::mem::size_of::<ManagerHeaderArgs>(),
3419 )
3420 };
3421 instruction.extend_from_slice(args_bytes);
3422
3423 Ok(instruction)
3424}
3425
3426fn build_manager_set_authority_instruction(
3428 meta_account_idx: u16,
3429 program_account_idx: u16,
3430 authority_candidate: [u8; 32],
3431) -> Result<Vec<u8>> {
3432 let mut instruction = Vec::new();
3433
3434 let args = ManagerSetAuthorityArgs {
3435 discriminant: MANAGER_INSTRUCTION_SET_AUTHORITY,
3436 meta_account_idx,
3437 program_account_idx,
3438 authority_candidate,
3439 };
3440
3441 let args_bytes = unsafe {
3442 std::slice::from_raw_parts(
3443 &args as *const ManagerSetAuthorityArgs as *const u8,
3444 std::mem::size_of::<ManagerSetAuthorityArgs>(),
3445 )
3446 };
3447 instruction.extend_from_slice(args_bytes);
3448
3449 Ok(instruction)
3450}
3451
3452fn build_test_uploader_create_instruction(
3454 account_idx: u16,
3455 account_sz: u32,
3456 seed: &[u8],
3457 is_ephemeral: bool,
3458 state_proof: Option<&[u8]>,
3459) -> Result<Vec<u8>> {
3460 let mut instruction = Vec::new();
3461
3462 instruction.push(TN_TEST_UPLOADER_PROGRAM_DISCRIMINANT_CREATE);
3464
3465 let args = TestUploaderCreateArgs {
3467 account_idx,
3468 is_ephemeral: if is_ephemeral { 1u8 } else { 0u8 },
3469 account_sz,
3470 seed_len: seed.len() as u32,
3471 };
3472
3473 let args_bytes = unsafe {
3475 std::slice::from_raw_parts(
3476 &args as *const _ as *const u8,
3477 std::mem::size_of::<TestUploaderCreateArgs>(),
3478 )
3479 };
3480 instruction.extend_from_slice(args_bytes);
3481
3482 instruction.extend_from_slice(seed);
3484
3485 if let Some(proof) = state_proof {
3487 instruction.extend_from_slice(proof);
3488 }
3489
3490 Ok(instruction)
3491}
3492
3493fn build_test_uploader_write_instruction(
3495 target_account_idx: u16,
3496 target_offset: u32,
3497 data: &[u8],
3498) -> Result<Vec<u8>> {
3499 let mut instruction = Vec::new();
3500
3501 instruction.push(TN_TEST_UPLOADER_PROGRAM_DISCRIMINANT_WRITE);
3503
3504 let args = TestUploaderWriteArgs {
3506 target_account_idx,
3507 target_offset,
3508 data_len: data.len() as u32,
3509 };
3510
3511 let args_bytes = unsafe {
3513 std::slice::from_raw_parts(
3514 &args as *const _ as *const u8,
3515 std::mem::size_of::<TestUploaderWriteArgs>(),
3516 )
3517 };
3518 instruction.extend_from_slice(args_bytes);
3519
3520 instruction.extend_from_slice(data);
3522
3523 Ok(instruction)
3524}
3525
3526pub fn build_decompress2_instruction(
3528 target_account_idx: u16,
3529 meta_account_idx: u16,
3530 data_account_idx: u16,
3531 data_offset: u32,
3532 state_proof: &[u8],
3533) -> Result<Vec<u8>> {
3534 let mut instruction = Vec::new();
3535
3536 instruction.push(0x08);
3538
3539 let args = SystemProgramDecompress2Args {
3541 target_account_idx,
3542 meta_account_idx,
3543 data_account_idx,
3544 data_offset,
3545 };
3546
3547 let args_bytes = unsafe {
3549 std::slice::from_raw_parts(
3550 &args as *const _ as *const u8,
3551 std::mem::size_of::<SystemProgramDecompress2Args>(),
3552 )
3553 };
3554 instruction.extend_from_slice(args_bytes);
3555
3556 instruction.extend_from_slice(state_proof);
3558
3559 Ok(instruction)
3560}
3561
3562pub const TOKEN_INSTRUCTION_INITIALIZE_MINT: u8 = 0x00;
3564pub const TOKEN_INSTRUCTION_INITIALIZE_ACCOUNT: u8 = 0x01;
3565pub const TOKEN_INSTRUCTION_TRANSFER: u8 = 0x02;
3566pub const TOKEN_INSTRUCTION_MINT_TO: u8 = 0x03;
3567pub const TOKEN_INSTRUCTION_BURN: u8 = 0x04;
3568pub const TOKEN_INSTRUCTION_CLOSE_ACCOUNT: u8 = 0x05;
3569pub const TOKEN_INSTRUCTION_FREEZE_ACCOUNT: u8 = 0x06;
3570pub const TOKEN_INSTRUCTION_THAW_ACCOUNT: u8 = 0x07;
3571
3572pub const TN_WTHRU_INSTRUCTION_INITIALIZE_MINT: u32 = 0;
3574pub const TN_WTHRU_INSTRUCTION_DEPOSIT: u32 = 1;
3575pub const TN_WTHRU_INSTRUCTION_WITHDRAW: u32 = 2;
3576pub const TN_NAME_SERVICE_INSTRUCTION_INITIALIZE_ROOT: u32 = 0;
3582pub const TN_NAME_SERVICE_INSTRUCTION_REGISTER_SUBDOMAIN: u32 = 1;
3583pub const TN_NAME_SERVICE_INSTRUCTION_APPEND_RECORD: u32 = 2;
3584pub const TN_NAME_SERVICE_INSTRUCTION_DELETE_RECORD: u32 = 3;
3585pub const TN_NAME_SERVICE_INSTRUCTION_UNREGISTER: u32 = 4;
3586
3587pub const TN_NAME_SERVICE_PROOF_INLINE: u32 = 0;
3589
3590pub const TN_NAME_SERVICE_MAX_DOMAIN_LENGTH: usize = 64;
3592pub const TN_NAME_SERVICE_MAX_KEY_LENGTH: usize = 32;
3593pub const TN_NAME_SERVICE_MAX_VALUE_LENGTH: usize = 256;
3594
3595pub const TN_THRU_REGISTRAR_INSTRUCTION_INITIALIZE_REGISTRY: u32 = 0;
3597pub const TN_THRU_REGISTRAR_INSTRUCTION_PURCHASE_DOMAIN: u32 = 1;
3598pub const TN_THRU_REGISTRAR_INSTRUCTION_RENEW_LEASE: u32 = 2;
3599pub const TN_THRU_REGISTRAR_INSTRUCTION_CLAIM_EXPIRED_DOMAIN: u32 = 3;
3600
3601fn add_sorted_accounts(tx: Transaction, accounts: &[(TnPubkey, bool)]) -> (Transaction, Vec<u16>) {
3603 let mut rw_accounts: Vec<_> = accounts
3605 .iter()
3606 .enumerate()
3607 .filter(|(_, (_, writable))| *writable)
3608 .collect();
3609 let mut ro_accounts: Vec<_> = accounts
3610 .iter()
3611 .enumerate()
3612 .filter(|(_, (_, writable))| !*writable)
3613 .collect();
3614
3615 rw_accounts.sort_by(|a, b| a.1.0.cmp(&b.1.0));
3617 ro_accounts.sort_by(|a, b| a.1.0.cmp(&b.1.0));
3618
3619 let mut updated_tx = tx;
3620 let mut indices = vec![0u16; accounts.len()];
3621 let mut seen: HashMap<TnPubkey, u16> = HashMap::new();
3622 seen.insert(updated_tx.fee_payer, 0u16);
3623 seen.insert(updated_tx.program, 1u16);
3624
3625 let mut next_idx = 2u16;
3626
3627 for (i, (account, _)) in rw_accounts.iter() {
3629 if let Some(idx) = seen.get(account) {
3630 indices[*i] = *idx;
3631 continue;
3632 }
3633
3634 let account_idx = next_idx;
3635 next_idx = next_idx.saturating_add(1);
3636 seen.insert(*account, account_idx);
3637 indices[*i] = account_idx;
3638
3639 updated_tx = updated_tx.add_rw_account(*account);
3640 }
3641
3642 for (i, (account, _)) in ro_accounts.iter() {
3644 if let Some(idx) = seen.get(account) {
3645 indices[*i] = *idx;
3646 continue;
3647 }
3648
3649 let account_idx = next_idx;
3650 next_idx = next_idx.saturating_add(1);
3651 seen.insert(*account, account_idx);
3652 indices[*i] = account_idx;
3653
3654 updated_tx = updated_tx.add_r_account(*account);
3655 }
3656
3657 (updated_tx, indices)
3658}
3659
3660fn add_sorted_rw_accounts(mut tx: Transaction, accounts: &[TnPubkey]) -> (Transaction, Vec<u16>) {
3662 if accounts.is_empty() {
3663 return (tx, Vec::new());
3664 }
3665
3666 let mut sorted: Vec<(usize, TnPubkey)> = accounts.iter().cloned().enumerate().collect();
3667 sorted.sort_by(|a, b| a.1.cmp(&b.1));
3668
3669 let mut indices = vec![0u16; accounts.len()];
3670 for (pos, (orig_idx, account)) in sorted.into_iter().enumerate() {
3671 let idx = (2 + pos) as u16;
3672 indices[orig_idx] = idx;
3673 tx = tx.add_rw_account(account);
3674 }
3675
3676 (tx, indices)
3677}
3678
3679fn add_sorted_ro_accounts(
3680 mut tx: Transaction,
3681 base_idx: u16,
3682 accounts: &[TnPubkey],
3683) -> (Transaction, Vec<u16>) {
3684 if accounts.is_empty() {
3685 return (tx, Vec::new());
3686 }
3687
3688 let mut sorted: Vec<(usize, TnPubkey)> = accounts.iter().cloned().enumerate().collect();
3689 sorted.sort_by(|a, b| a.1.cmp(&b.1));
3690
3691 let mut indices = vec![0u16; accounts.len()];
3692 for (pos, (orig_idx, account)) in sorted.into_iter().enumerate() {
3693 let idx = base_idx + pos as u16;
3694 indices[orig_idx] = idx;
3695 tx = tx.add_r_account(account);
3696 }
3697
3698 (tx, indices)
3699}
3700
3701impl TransactionBuilder {
3702 pub fn build_token_initialize_mint(
3704 fee_payer: TnPubkey,
3705 token_program: TnPubkey,
3706 mint_account: TnPubkey,
3707 creator: TnPubkey,
3708 mint_authority: TnPubkey,
3709 freeze_authority: Option<TnPubkey>,
3710 decimals: u8,
3711 ticker: &str,
3712 seed: [u8; 32],
3713 state_proof: Vec<u8>,
3714 fee: u64,
3715 nonce: u64,
3716 start_slot: u64,
3717 ) -> Result<Transaction> {
3718 let base_tx =
3719 Transaction::new(fee_payer, token_program, fee, nonce).with_start_slot(start_slot);
3720 let (tx, indices) = add_sorted_rw_accounts(base_tx, &[mint_account]);
3721 let mint_account_idx = indices[0];
3722
3723 let instruction_data = build_token_initialize_mint_instruction(
3724 mint_account_idx,
3725 decimals,
3726 creator,
3727 mint_authority,
3728 freeze_authority,
3729 ticker,
3730 seed,
3731 state_proof,
3732 )?;
3733
3734 let tx = tx
3735 .with_instructions(instruction_data)
3736 .with_expiry_after(100)
3737 .with_compute_units(300_000)
3738 .with_state_units(10_000)
3739 .with_memory_units(10_000);
3740
3741 Ok(tx)
3742 }
3743
3744 pub fn build_token_initialize_account(
3746 fee_payer: TnPubkey,
3747 token_program: TnPubkey,
3748 token_account: TnPubkey,
3749 mint_account: TnPubkey,
3750 owner: TnPubkey,
3751 seed: [u8; 32],
3752 state_proof: Vec<u8>,
3753 fee: u64,
3754 nonce: u64,
3755 start_slot: u64,
3756 ) -> Result<Transaction> {
3757 let owner_is_fee_payer = owner == fee_payer;
3758
3759 let mut rw_accounts = vec![token_account];
3760 rw_accounts.sort();
3761
3762 let mut ro_accounts = vec![mint_account];
3763 if !owner_is_fee_payer {
3764 ro_accounts.push(owner);
3765 ro_accounts.sort();
3766 }
3767
3768 let mut tx =
3769 Transaction::new(fee_payer, token_program, fee, nonce).with_start_slot(start_slot);
3770
3771 let mut token_account_idx = 0u16;
3772 for (i, account) in rw_accounts.iter().enumerate() {
3773 let idx = (2 + i) as u16;
3774 if *account == token_account {
3775 token_account_idx = idx;
3776 }
3777 tx = tx.add_rw_account(*account);
3778 }
3779
3780 let base_ro_idx = 2 + rw_accounts.len() as u16;
3781 let mut mint_account_idx = 0u16;
3782 let mut owner_account_idx = if owner_is_fee_payer { 0u16 } else { 0u16 };
3783 for (i, account) in ro_accounts.iter().enumerate() {
3784 let idx = base_ro_idx + i as u16;
3785 if *account == mint_account {
3786 mint_account_idx = idx;
3787 } else if !owner_is_fee_payer && *account == owner {
3788 owner_account_idx = idx;
3789 }
3790 tx = tx.add_r_account(*account);
3791 }
3792
3793 let instruction_data = build_token_initialize_account_instruction(
3794 token_account_idx,
3795 mint_account_idx,
3796 owner_account_idx,
3797 seed,
3798 state_proof,
3799 )?;
3800
3801 let tx = tx
3802 .with_instructions(instruction_data)
3803 .with_expiry_after(100)
3804 .with_compute_units(300_000)
3805 .with_state_units(10_000)
3806 .with_memory_units(10_000);
3807
3808 Ok(tx)
3809 }
3810
3811 pub fn build_token_transfer(
3813 fee_payer: TnPubkey,
3814 token_program: TnPubkey,
3815 source_account: TnPubkey,
3816 dest_account: TnPubkey,
3817 _authority: TnPubkey,
3818 amount: u64,
3819 fee: u64,
3820 nonce: u64,
3821 start_slot: u64,
3822 ) -> Result<Transaction> {
3823 let mut tx = Transaction::new(fee_payer, token_program, fee, nonce)
3824 .with_start_slot(start_slot)
3825 .with_expiry_after(100)
3826 .with_compute_units(300_000)
3827 .with_state_units(10_000)
3828 .with_memory_units(10_000);
3829
3830 let is_self_transfer = source_account == dest_account;
3831 let (source_account_idx, dest_account_idx) = if is_self_transfer {
3832 tx = tx.add_rw_account(source_account);
3834 (2u16, 2u16)
3835 } else {
3836 let accounts = &[(source_account, true), (dest_account, true)];
3838 let (updated_tx, indices) = add_sorted_accounts(tx, accounts);
3839 tx = updated_tx;
3840 (indices[0], indices[1])
3841 };
3842
3843 let instruction_data =
3847 build_token_transfer_instruction(source_account_idx, dest_account_idx, amount)?;
3848
3849 Ok(tx.with_instructions(instruction_data))
3850 }
3851
3852 pub fn build_token_mint_to(
3854 fee_payer: TnPubkey,
3855 token_program: TnPubkey,
3856 mint_account: TnPubkey,
3857 dest_account: TnPubkey,
3858 authority: TnPubkey,
3859 amount: u64,
3860 fee: u64,
3861 nonce: u64,
3862 start_slot: u64,
3863 ) -> Result<Transaction> {
3864 let base_tx = Transaction::new(fee_payer, token_program, fee, nonce)
3865 .with_start_slot(start_slot)
3866 .with_expiry_after(100)
3867 .with_compute_units(300_000)
3868 .with_state_units(10_000)
3869 .with_memory_units(10_000);
3870
3871 let (tx_after_rw, rw_indices) =
3872 add_sorted_rw_accounts(base_tx, &[mint_account, dest_account]);
3873 let mint_account_idx = rw_indices[0];
3874 let dest_account_idx = rw_indices[1];
3875
3876 let mut tx = tx_after_rw;
3877 let authority_account_idx = if authority == fee_payer {
3878 0u16
3879 } else {
3880 let base_ro_idx = 2 + rw_indices.len() as u16;
3881 let (tx_after_ro, ro_indices) = add_sorted_ro_accounts(tx, base_ro_idx, &[authority]);
3882 tx = tx_after_ro;
3883 ro_indices[0]
3884 };
3885
3886 let instruction_data = build_token_mint_to_instruction(
3887 mint_account_idx,
3888 dest_account_idx,
3889 authority_account_idx,
3890 amount,
3891 )?;
3892
3893 Ok(tx.with_instructions(instruction_data))
3894 }
3895
3896 pub fn build_token_burn(
3898 fee_payer: TnPubkey,
3899 token_program: TnPubkey,
3900 token_account: TnPubkey,
3901 mint_account: TnPubkey,
3902 authority: TnPubkey,
3903 amount: u64,
3904 fee: u64,
3905 nonce: u64,
3906 start_slot: u64,
3907 ) -> Result<Transaction> {
3908 let base_tx = Transaction::new(fee_payer, token_program, fee, nonce)
3909 .with_start_slot(start_slot)
3910 .with_expiry_after(100)
3911 .with_compute_units(300_000)
3912 .with_state_units(10_000)
3913 .with_memory_units(10_000);
3914
3915 let (tx_after_rw, rw_indices) =
3916 add_sorted_rw_accounts(base_tx, &[token_account, mint_account]);
3917 let token_account_idx = rw_indices[0];
3918 let mint_account_idx = rw_indices[1];
3919
3920 let mut tx = tx_after_rw;
3921 let authority_account_idx = if authority == fee_payer {
3922 0u16
3923 } else {
3924 let base_ro_idx = 2 + rw_indices.len() as u16;
3925 let (tx_after_ro, ro_indices) = add_sorted_ro_accounts(tx, base_ro_idx, &[authority]);
3926 tx = tx_after_ro;
3927 ro_indices[0]
3928 };
3929
3930 let instruction_data = build_token_burn_instruction(
3931 token_account_idx,
3932 mint_account_idx,
3933 authority_account_idx,
3934 amount,
3935 )?;
3936
3937 Ok(tx.with_instructions(instruction_data))
3938 }
3939
3940 pub fn build_token_freeze_account(
3942 fee_payer: TnPubkey,
3943 token_program: TnPubkey,
3944 token_account: TnPubkey,
3945 mint_account: TnPubkey,
3946 authority: TnPubkey,
3947 fee: u64,
3948 nonce: u64,
3949 start_slot: u64,
3950 ) -> Result<Transaction> {
3951 let base_tx = Transaction::new(fee_payer, token_program, fee, nonce)
3952 .with_start_slot(start_slot)
3953 .with_expiry_after(100)
3954 .with_compute_units(300_000)
3955 .with_state_units(10_000)
3956 .with_memory_units(10_000);
3957
3958 let (tx_after_rw, rw_indices) =
3959 add_sorted_rw_accounts(base_tx, &[token_account, mint_account]);
3960 let token_account_idx = rw_indices[0];
3961 let mint_account_idx = rw_indices[1];
3962
3963 let mut tx = tx_after_rw;
3964 let authority_account_idx = if authority == fee_payer {
3965 0u16
3966 } else {
3967 let base_ro_idx = 2 + rw_indices.len() as u16;
3968 let (tx_after_ro, ro_indices) = add_sorted_ro_accounts(tx, base_ro_idx, &[authority]);
3969 tx = tx_after_ro;
3970 ro_indices[0]
3971 };
3972
3973 let instruction_data = build_token_freeze_account_instruction(
3974 token_account_idx,
3975 mint_account_idx,
3976 authority_account_idx,
3977 )?;
3978
3979 Ok(tx.with_instructions(instruction_data))
3980 }
3981
3982 pub fn build_token_thaw_account(
3984 fee_payer: TnPubkey,
3985 token_program: TnPubkey,
3986 token_account: TnPubkey,
3987 mint_account: TnPubkey,
3988 authority: TnPubkey,
3989 fee: u64,
3990 nonce: u64,
3991 start_slot: u64,
3992 ) -> Result<Transaction> {
3993 let base_tx = Transaction::new(fee_payer, token_program, fee, nonce)
3994 .with_start_slot(start_slot)
3995 .with_expiry_after(100)
3996 .with_compute_units(300_000)
3997 .with_state_units(10_000)
3998 .with_memory_units(10_000);
3999
4000 let (tx_after_rw, rw_indices) =
4001 add_sorted_rw_accounts(base_tx, &[token_account, mint_account]);
4002 let token_account_idx = rw_indices[0];
4003 let mint_account_idx = rw_indices[1];
4004
4005 let mut tx = tx_after_rw;
4006 let authority_account_idx = if authority == fee_payer {
4007 0u16
4008 } else {
4009 let base_ro_idx = 2 + rw_indices.len() as u16;
4010 let (tx_after_ro, ro_indices) = add_sorted_ro_accounts(tx, base_ro_idx, &[authority]);
4011 tx = tx_after_ro;
4012 ro_indices[0]
4013 };
4014
4015 let instruction_data = build_token_thaw_account_instruction(
4016 token_account_idx,
4017 mint_account_idx,
4018 authority_account_idx,
4019 )?;
4020
4021 Ok(tx.with_instructions(instruction_data))
4022 }
4023
4024 pub fn build_token_close_account(
4026 fee_payer: TnPubkey,
4027 token_program: TnPubkey,
4028 token_account: TnPubkey,
4029 destination: TnPubkey,
4030 authority: TnPubkey,
4031 fee: u64,
4032 nonce: u64,
4033 start_slot: u64,
4034 ) -> Result<Transaction> {
4035 let base_tx = Transaction::new(fee_payer, token_program, fee, nonce)
4036 .with_start_slot(start_slot)
4037 .with_expiry_after(100)
4038 .with_compute_units(300_000)
4039 .with_state_units(10_000)
4040 .with_memory_units(10_000);
4041
4042 let mut rw_accounts = vec![token_account];
4043 let destination_in_accounts = destination != fee_payer;
4044 if destination_in_accounts {
4045 rw_accounts.push(destination);
4046 }
4047
4048 let (tx_after_rw, rw_indices) = add_sorted_rw_accounts(base_tx, &rw_accounts);
4049 let token_account_idx = rw_indices[0];
4050 let destination_idx = if destination_in_accounts {
4051 rw_indices[1]
4052 } else {
4053 0u16
4054 };
4055
4056 let mut tx = tx_after_rw;
4057 let authority_account_idx = if authority == fee_payer {
4058 0u16
4059 } else {
4060 let base_ro_idx = 2 + rw_indices.len() as u16;
4061 let (tx_after_ro, ro_indices) = add_sorted_ro_accounts(tx, base_ro_idx, &[authority]);
4062 tx = tx_after_ro;
4063 ro_indices[0]
4064 };
4065
4066 let instruction_data = build_token_close_account_instruction(
4067 token_account_idx,
4068 destination_idx,
4069 authority_account_idx,
4070 )?;
4071
4072 Ok(tx.with_instructions(instruction_data))
4073 }
4074
4075 pub fn build_wthru_initialize_mint(
4077 fee_payer: TnPubkey,
4078 wthru_program: TnPubkey,
4079 token_program: TnPubkey,
4080 mint_account: TnPubkey,
4081 vault_account: TnPubkey,
4082 decimals: u8,
4083 mint_seed: [u8; 32],
4084 mint_proof: Vec<u8>,
4085 vault_proof: Vec<u8>,
4086 fee: u64,
4087 nonce: u64,
4088 start_slot: u64,
4089 ) -> Result<Transaction> {
4090 let mut tx = Transaction::new(fee_payer, wthru_program, fee, nonce)
4091 .with_start_slot(start_slot)
4092 .with_expiry_after(100)
4093 .with_compute_units(500_000)
4094 .with_state_units(10_000)
4095 .with_memory_units(10_000);
4096
4097 let accounts = [
4098 (mint_account, true),
4099 (vault_account, true),
4100 (token_program, false),
4101 ];
4102
4103 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
4104 tx = tx_with_accounts;
4105
4106 let mint_account_idx = indices[0];
4107 let vault_account_idx = indices[1];
4108 let token_program_idx = indices[2];
4109
4110 let instruction_data = build_wthru_initialize_mint_instruction(
4111 token_program_idx,
4112 mint_account_idx,
4113 vault_account_idx,
4114 decimals,
4115 mint_seed,
4116 mint_proof,
4117 vault_proof,
4118 )?;
4119
4120 Ok(tx.with_instructions(instruction_data))
4121 }
4122
4123 pub fn build_wthru_deposit(
4125 fee_payer: TnPubkey,
4126 wthru_program: TnPubkey,
4127 token_program: TnPubkey,
4128 mint_account: TnPubkey,
4129 vault_account: TnPubkey,
4130 dest_token_account: TnPubkey,
4131 fee: u64,
4132 nonce: u64,
4133 start_slot: u64,
4134 ) -> Result<Transaction> {
4135 let mut tx = Transaction::new(fee_payer, wthru_program, fee, nonce)
4136 .with_start_slot(start_slot)
4137 .with_expiry_after(100)
4138 .with_compute_units(400_000)
4139 .with_state_units(10_000)
4140 .with_memory_units(10_000);
4141
4142 let accounts = [
4143 (mint_account, true),
4144 (vault_account, true),
4145 (dest_token_account, true),
4146 (token_program, false),
4147 ];
4148
4149 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
4150 tx = tx_with_accounts;
4151
4152 let mint_account_idx = indices[0];
4153 let vault_account_idx = indices[1];
4154 let dest_account_idx = indices[2];
4155 let token_program_idx = indices[3];
4156
4157 let instruction_data = build_wthru_deposit_instruction(
4158 token_program_idx,
4159 vault_account_idx,
4160 mint_account_idx,
4161 dest_account_idx,
4162 )?;
4163
4164 Ok(tx.with_instructions(instruction_data))
4165 }
4166
4167 pub fn build_wthru_withdraw(
4169 fee_payer: TnPubkey,
4170 wthru_program: TnPubkey,
4171 token_program: TnPubkey,
4172 mint_account: TnPubkey,
4173 vault_account: TnPubkey,
4174 wthru_token_account: TnPubkey,
4175 recipient_account: TnPubkey,
4176 amount: u64,
4177 fee: u64,
4178 nonce: u64,
4179 start_slot: u64,
4180 ) -> Result<Transaction> {
4181 let mut tx = Transaction::new(fee_payer, wthru_program, fee, nonce)
4182 .with_start_slot(start_slot)
4183 .with_expiry_after(100)
4184 .with_compute_units(400_000)
4185 .with_state_units(10_000)
4186 .with_memory_units(10_000);
4187
4188 let accounts = [
4189 (mint_account, true),
4190 (vault_account, true),
4191 (wthru_token_account, true),
4192 (recipient_account, true),
4193 (token_program, false),
4194 ];
4195
4196 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
4197 tx = tx_with_accounts;
4198
4199 let mint_account_idx = indices[0];
4200 let vault_account_idx = indices[1];
4201 let token_account_idx = indices[2];
4202 let recipient_account_idx = indices[3];
4203 let token_program_idx = indices[4];
4204
4205 let owner_account_idx = 0u16; let instruction_data = build_wthru_withdraw_instruction(
4208 token_program_idx,
4209 vault_account_idx,
4210 mint_account_idx,
4211 token_account_idx,
4212 owner_account_idx,
4213 recipient_account_idx,
4214 amount,
4215 )?;
4216
4217 Ok(tx.with_instructions(instruction_data))
4218 }
4219
4220 pub fn build_faucet_deposit(
4223 fee_payer: TnPubkey,
4224 faucet_program: TnPubkey,
4225 faucet_account: TnPubkey,
4226 depositor_account: TnPubkey,
4227 eoa_program: TnPubkey,
4228 amount: u64,
4229 fee: u64,
4230 nonce: u64,
4231 start_slot: u64,
4232 ) -> Result<Transaction> {
4233 let tx = Transaction::new(fee_payer, faucet_program, fee, nonce)
4234 .with_start_slot(start_slot)
4235 .with_expiry_after(100)
4236 .with_compute_units(300_000)
4237 .with_state_units(10_000)
4238 .with_memory_units(10_000);
4239
4240 let (tx, depositor_account_idx) = Self::ensure_rw_account(tx, depositor_account);
4241 let (tx, faucet_account_idx) = Self::ensure_rw_account(tx, faucet_account);
4242 let (tx, eoa_program_idx) = Self::ensure_ro_account(tx, eoa_program);
4243
4244 let instruction_data = build_faucet_deposit_instruction(
4245 faucet_account_idx,
4246 depositor_account_idx,
4247 eoa_program_idx,
4248 amount,
4249 )?;
4250
4251 Ok(tx.with_instructions(instruction_data))
4252 }
4253
4254 fn resolve_account_index(tx: &Transaction, target: &TnPubkey) -> Option<u16> {
4255 if *target == tx.fee_payer {
4256 return Some(0u16);
4257 }
4258
4259 if *target == tx.program {
4260 return Some(1u16);
4261 }
4262
4263 if let Some(ref rw) = tx.rw_accs {
4264 if let Some(pos) = rw.iter().position(|acc| acc == target) {
4265 return Some(2u16 + pos as u16);
4266 }
4267 }
4268
4269 if let Some(ref ro) = tx.r_accs {
4270 let base = 2u16 + tx.rw_accs.as_ref().map_or(0u16, |v| v.len() as u16);
4271 if let Some(pos) = ro.iter().position(|acc| acc == target) {
4272 return Some(base + pos as u16);
4273 }
4274 }
4275
4276 None
4277 }
4278
4279 fn ensure_rw_account(mut tx: Transaction, account: TnPubkey) -> (Transaction, u16) {
4280 if let Some(idx) = Self::resolve_account_index(&tx, &account) {
4281 return (tx, idx);
4282 }
4283
4284 tx = tx.add_rw_account(account);
4285 let idx = Self::resolve_account_index(&tx, &account)
4286 .expect("read-write account index should exist after insertion");
4287
4288 (tx, idx)
4289 }
4290
4291 fn ensure_ro_account(mut tx: Transaction, account: TnPubkey) -> (Transaction, u16) {
4292 if let Some(idx) = Self::resolve_account_index(&tx, &account) {
4293 return (tx, idx);
4294 }
4295
4296 tx = tx.add_r_account(account);
4297 let idx = Self::resolve_account_index(&tx, &account)
4298 .expect("read-only account index should exist after insertion");
4299
4300 (tx, idx)
4301 }
4302
4303 pub fn build_faucet_withdraw(
4305 fee_payer: TnPubkey,
4306 faucet_program: TnPubkey,
4307 faucet_account: TnPubkey,
4308 recipient_account: TnPubkey,
4309 amount: u64,
4310 fee: u64,
4311 nonce: u64,
4312 start_slot: u64,
4313 ) -> Result<Transaction> {
4314 let mut tx = Transaction::new(fee_payer, faucet_program, fee, nonce)
4315 .with_start_slot(start_slot)
4316 .with_expiry_after(100)
4317 .with_compute_units(300_000)
4318 .with_state_units(10_000)
4319 .with_memory_units(10_000);
4320
4321 let faucet_is_fee_payer = faucet_account == fee_payer;
4324 let recipient_is_fee_payer = recipient_account == fee_payer;
4325 let recipient_is_faucet = recipient_account == faucet_account;
4326
4327 let (faucet_account_idx, recipient_account_idx) =
4328 if faucet_is_fee_payer && recipient_is_fee_payer {
4329 (0u16, 0u16)
4331 } else if faucet_is_fee_payer {
4332 tx = tx.add_rw_account(recipient_account);
4334 (0u16, 2u16)
4335 } else if recipient_is_fee_payer {
4336 tx = tx.add_rw_account(faucet_account);
4338 (2u16, 0u16)
4339 } else if recipient_is_faucet {
4340 tx = tx.add_rw_account(faucet_account);
4342 (2u16, 2u16)
4343 } else {
4344 if faucet_account < recipient_account {
4346 tx = tx.add_rw_account(faucet_account);
4347 tx = tx.add_rw_account(recipient_account);
4348 (2u16, 3u16)
4349 } else {
4350 tx = tx.add_rw_account(recipient_account);
4351 tx = tx.add_rw_account(faucet_account);
4352 (3u16, 2u16)
4353 }
4354 };
4355
4356 let instruction_data =
4357 build_faucet_withdraw_instruction(faucet_account_idx, recipient_account_idx, amount)?;
4358
4359 Ok(tx.with_instructions(instruction_data))
4360 }
4361
4362 pub fn build_activate(
4378 fee_payer: TnPubkey,
4379 source_token_account: TnPubkey,
4380 bls_pk: [u8; 96],
4381 claim_authority: TnPubkey,
4382 token_amount: u64,
4383 fee: u64,
4384 nonce: u64,
4385 start_slot: u64,
4386 ) -> Result<Transaction> {
4387 Self::build_activate_with_accounts(
4388 fee_payer,
4389 ConsensusValidatorAccounts::default(),
4390 source_token_account,
4391 bls_pk,
4392 claim_authority,
4393 token_amount,
4394 fee,
4395 nonce,
4396 start_slot,
4397 )
4398 }
4399
4400 pub fn build_activate_with_accounts(
4403 fee_payer: TnPubkey,
4404 accounts: ConsensusValidatorAccounts,
4405 source_token_account: TnPubkey,
4406 bls_pk: [u8; 96],
4407 claim_authority: TnPubkey,
4408 token_amount: u64,
4409 fee: u64,
4410 nonce: u64,
4411 start_slot: u64,
4412 ) -> Result<Transaction> {
4413 let tx = build_consensus_validator_tx(fee_payer, accounts.program, fee, nonce, start_slot);
4414
4415 let accounts = [
4420 (accounts.attestor_table, true), (source_token_account, true), (accounts.converted_vault, true), (accounts.token_program, false), ];
4425 let (tx, indices) = add_sorted_accounts(tx, &accounts);
4426 let attestor_table_idx = indices[0];
4427 let source_token_account_idx = indices[1];
4428 let converted_vault_idx = indices[2];
4429 let token_program_idx = indices[3];
4430
4431 let identity_idx = 0u16;
4433
4434 let instruction_data = build_activate_instruction(
4435 attestor_table_idx as u64,
4436 token_program_idx,
4437 source_token_account_idx,
4438 converted_vault_idx,
4439 identity_idx,
4440 bls_pk,
4441 claim_authority,
4442 token_amount,
4443 )?;
4444
4445 Ok(tx.with_instructions(instruction_data))
4446 }
4447
4448 pub fn build_deactivate(
4450 fee_payer: TnPubkey,
4451 dest_token_account: TnPubkey,
4452 fee: u64,
4453 nonce: u64,
4454 start_slot: u64,
4455 ) -> Result<Transaction> {
4456 Self::build_deactivate_with_accounts(
4457 fee_payer,
4458 ConsensusValidatorAccounts::default(),
4459 dest_token_account,
4460 fee,
4461 nonce,
4462 start_slot,
4463 )
4464 }
4465
4466 pub fn build_deactivate_with_accounts(
4469 fee_payer: TnPubkey,
4470 accounts: ConsensusValidatorAccounts,
4471 dest_token_account: TnPubkey,
4472 fee: u64,
4473 nonce: u64,
4474 start_slot: u64,
4475 ) -> Result<Transaction> {
4476 let tx = build_consensus_validator_tx(fee_payer, accounts.program, fee, nonce, start_slot);
4477
4478 let tx_accounts = [
4479 (accounts.attestor_table, true),
4480 (accounts.unclaimed_vault, true),
4481 (dest_token_account, true),
4482 (accounts.token_program, false),
4483 ];
4484 let (tx, indices) = add_sorted_accounts(tx, &tx_accounts);
4485 let attestor_table_idx = indices[0];
4486 let unclaimed_vault_idx = indices[1];
4487 let dest_token_account_idx = indices[2];
4488 let token_program_idx = indices[3];
4489
4490 let instruction_data = build_deactivate_instruction(
4491 attestor_table_idx as u64,
4492 token_program_idx,
4493 unclaimed_vault_idx,
4494 dest_token_account_idx,
4495 0u16,
4496 )?;
4497
4498 Ok(tx.with_instructions(instruction_data))
4499 }
4500
4501 pub fn build_convert_tokens(
4503 fee_payer: TnPubkey,
4504 source_token_account: TnPubkey,
4505 token_amount: u64,
4506 fee: u64,
4507 nonce: u64,
4508 start_slot: u64,
4509 ) -> Result<Transaction> {
4510 Self::build_convert_tokens_with_accounts(
4511 fee_payer,
4512 ConsensusValidatorAccounts::default(),
4513 source_token_account,
4514 token_amount,
4515 fee,
4516 nonce,
4517 start_slot,
4518 )
4519 }
4520
4521 pub fn build_convert_tokens_with_accounts(
4524 fee_payer: TnPubkey,
4525 accounts: ConsensusValidatorAccounts,
4526 source_token_account: TnPubkey,
4527 token_amount: u64,
4528 fee: u64,
4529 nonce: u64,
4530 start_slot: u64,
4531 ) -> Result<Transaction> {
4532 let tx = build_consensus_validator_tx(fee_payer, accounts.program, fee, nonce, start_slot);
4533
4534 let tx_accounts = [
4535 (accounts.attestor_table, true),
4536 (source_token_account, true),
4537 (accounts.converted_vault, true),
4538 (accounts.token_program, false),
4539 ];
4540 let (tx, indices) = add_sorted_accounts(tx, &tx_accounts);
4541 let attestor_table_idx = indices[0];
4542 let source_token_account_idx = indices[1];
4543 let converted_vault_idx = indices[2];
4544 let token_program_idx = indices[3];
4545
4546 let instruction_data = build_convert_tokens_instruction(
4547 attestor_table_idx as u64,
4548 token_program_idx,
4549 source_token_account_idx,
4550 converted_vault_idx,
4551 0u16,
4552 token_amount,
4553 )?;
4554
4555 Ok(tx.with_instructions(instruction_data))
4556 }
4557
4558 pub fn build_claim(
4560 fee_payer: TnPubkey,
4561 subject_attestor: TnPubkey,
4562 dest_token_account: TnPubkey,
4563 fee: u64,
4564 nonce: u64,
4565 start_slot: u64,
4566 ) -> Result<Transaction> {
4567 Self::build_claim_with_accounts(
4568 fee_payer,
4569 ConsensusValidatorAccounts::default(),
4570 subject_attestor,
4571 dest_token_account,
4572 fee,
4573 nonce,
4574 start_slot,
4575 )
4576 }
4577
4578 pub fn build_claim_with_accounts(
4581 fee_payer: TnPubkey,
4582 accounts: ConsensusValidatorAccounts,
4583 subject_attestor: TnPubkey,
4584 dest_token_account: TnPubkey,
4585 fee: u64,
4586 nonce: u64,
4587 start_slot: u64,
4588 ) -> Result<Transaction> {
4589 let tx = build_consensus_validator_tx(fee_payer, accounts.program, fee, nonce, start_slot);
4590
4591 let tx_accounts = [
4592 (accounts.attestor_table, true),
4593 (accounts.unclaimed_vault, true),
4594 (dest_token_account, true),
4595 (accounts.token_program, false),
4596 ];
4597 let (tx, indices) = add_sorted_accounts(tx, &tx_accounts);
4598 let attestor_table_idx = indices[0];
4599 let unclaimed_vault_idx = indices[1];
4600 let dest_token_account_idx = indices[2];
4601 let token_program_idx = indices[3];
4602
4603 let instruction_data = build_claim_instruction(
4604 attestor_table_idx as u64,
4605 token_program_idx,
4606 unclaimed_vault_idx,
4607 dest_token_account_idx,
4608 0u16,
4609 subject_attestor,
4610 )?;
4611
4612 Ok(tx.with_instructions(instruction_data))
4613 }
4614
4615 pub fn build_set_claim_authority(
4617 fee_payer: TnPubkey,
4618 subject_attestor: TnPubkey,
4619 new_claim_authority: TnPubkey,
4620 fee: u64,
4621 nonce: u64,
4622 start_slot: u64,
4623 ) -> Result<Transaction> {
4624 Self::build_set_claim_authority_with_accounts(
4625 fee_payer,
4626 ConsensusValidatorAccounts::default(),
4627 subject_attestor,
4628 new_claim_authority,
4629 fee,
4630 nonce,
4631 start_slot,
4632 )
4633 }
4634
4635 pub fn build_set_claim_authority_with_accounts(
4638 fee_payer: TnPubkey,
4639 accounts: ConsensusValidatorAccounts,
4640 subject_attestor: TnPubkey,
4641 new_claim_authority: TnPubkey,
4642 fee: u64,
4643 nonce: u64,
4644 start_slot: u64,
4645 ) -> Result<Transaction> {
4646 let tx = build_consensus_validator_tx(fee_payer, accounts.program, fee, nonce, start_slot);
4647
4648 let tx_accounts = [(accounts.attestor_table, true)];
4649 let (tx, indices) = add_sorted_accounts(tx, &tx_accounts);
4650 let attestor_table_idx = indices[0];
4651
4652 let instruction_data = build_set_claim_authority_instruction(
4653 attestor_table_idx as u64,
4654 0u16,
4655 subject_attestor,
4656 new_claim_authority,
4657 )?;
4658
4659 Ok(tx.with_instructions(instruction_data))
4660 }
4661
4662 pub fn build_name_service_initialize_root(
4664 fee_payer: TnPubkey,
4665 name_service_program: TnPubkey,
4666 registrar_account: TnPubkey,
4667 authority_account: TnPubkey,
4668 root_name: &str,
4669 state_proof: Vec<u8>,
4670 fee: u64,
4671 nonce: u64,
4672 start_slot: u64,
4673 ) -> Result<Transaction> {
4674 let mut tx = Transaction::new(fee_payer, name_service_program, fee, nonce)
4675 .with_start_slot(start_slot)
4676 .with_expiry_after(100)
4677 .with_compute_units(500_000)
4678 .with_state_units(10_000)
4679 .with_memory_units(10_000);
4680
4681 let accounts = [(registrar_account, true), (authority_account, false)];
4682 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
4683 tx = tx_with_accounts;
4684
4685 let registrar_account_idx = indices[0];
4686 let authority_account_idx = indices[1];
4687
4688 let instruction_data = build_name_service_initialize_root_instruction(
4689 registrar_account_idx,
4690 authority_account_idx,
4691 root_name,
4692 state_proof,
4693 )?;
4694
4695 Ok(tx.with_instructions(instruction_data))
4696 }
4697
4698 pub fn build_name_service_register_subdomain(
4700 fee_payer: TnPubkey,
4701 name_service_program: TnPubkey,
4702 domain_account: TnPubkey,
4703 parent_account: TnPubkey,
4704 owner_account: TnPubkey,
4705 authority_account: TnPubkey,
4706 domain_name: &str,
4707 state_proof: Vec<u8>,
4708 fee: u64,
4709 nonce: u64,
4710 start_slot: u64,
4711 ) -> Result<Transaction> {
4712 let mut tx = Transaction::new(fee_payer, name_service_program, fee, nonce)
4713 .with_start_slot(start_slot)
4714 .with_expiry_after(100)
4715 .with_compute_units(500_000)
4716 .with_state_units(10_000)
4717 .with_memory_units(10_000);
4718
4719 let accounts = [
4720 (domain_account, true),
4721 (parent_account, true),
4722 (owner_account, false),
4723 (authority_account, false),
4724 ];
4725 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
4726 tx = tx_with_accounts;
4727
4728 let domain_account_idx = indices[0];
4729 let parent_account_idx = indices[1];
4730 let owner_account_idx = indices[2];
4731 let authority_account_idx = indices[3];
4732
4733 let instruction_data = build_name_service_register_subdomain_instruction(
4734 domain_account_idx,
4735 parent_account_idx,
4736 owner_account_idx,
4737 authority_account_idx,
4738 domain_name,
4739 state_proof,
4740 )?;
4741
4742 Ok(tx.with_instructions(instruction_data))
4743 }
4744
4745 pub fn build_name_service_append_record(
4747 fee_payer: TnPubkey,
4748 name_service_program: TnPubkey,
4749 domain_account: TnPubkey,
4750 owner_account: TnPubkey,
4751 key: &[u8],
4752 value: &[u8],
4753 fee: u64,
4754 nonce: u64,
4755 start_slot: u64,
4756 ) -> Result<Transaction> {
4757 let mut tx = Transaction::new(fee_payer, name_service_program, fee, nonce)
4758 .with_start_slot(start_slot)
4759 .with_expiry_after(100)
4760 .with_compute_units(250_000)
4761 .with_state_units(10_000)
4762 .with_memory_units(10_000);
4763
4764 let accounts = [(domain_account, true), (owner_account, false)];
4765 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
4766 tx = tx_with_accounts;
4767
4768 let domain_account_idx = indices[0];
4769 let owner_account_idx = indices[1];
4770
4771 let instruction_data = build_name_service_append_record_instruction(
4772 domain_account_idx,
4773 owner_account_idx,
4774 key,
4775 value,
4776 )?;
4777
4778 Ok(tx.with_instructions(instruction_data))
4779 }
4780
4781 pub fn build_name_service_delete_record(
4783 fee_payer: TnPubkey,
4784 name_service_program: TnPubkey,
4785 domain_account: TnPubkey,
4786 owner_account: TnPubkey,
4787 key: &[u8],
4788 fee: u64,
4789 nonce: u64,
4790 start_slot: u64,
4791 ) -> Result<Transaction> {
4792 let mut tx = Transaction::new(fee_payer, name_service_program, fee, nonce)
4793 .with_start_slot(start_slot)
4794 .with_expiry_after(100)
4795 .with_compute_units(200_000)
4796 .with_state_units(10_000)
4797 .with_memory_units(10_000);
4798
4799 let accounts = [(domain_account, true), (owner_account, false)];
4800 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
4801 tx = tx_with_accounts;
4802
4803 let domain_account_idx = indices[0];
4804 let owner_account_idx = indices[1];
4805
4806 let instruction_data = build_name_service_delete_record_instruction(
4807 domain_account_idx,
4808 owner_account_idx,
4809 key,
4810 )?;
4811
4812 Ok(tx.with_instructions(instruction_data))
4813 }
4814
4815 pub fn build_name_service_unregister_subdomain(
4817 fee_payer: TnPubkey,
4818 name_service_program: TnPubkey,
4819 domain_account: TnPubkey,
4820 owner_account: TnPubkey,
4821 fee: u64,
4822 nonce: u64,
4823 start_slot: u64,
4824 ) -> Result<Transaction> {
4825 let mut tx = Transaction::new(fee_payer, name_service_program, fee, nonce)
4826 .with_start_slot(start_slot)
4827 .with_expiry_after(100)
4828 .with_compute_units(200_000)
4829 .with_state_units(10_000)
4830 .with_memory_units(10_000);
4831
4832 let accounts = [(domain_account, true), (owner_account, false)];
4833 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
4834 tx = tx_with_accounts;
4835
4836 let domain_account_idx = indices[0];
4837 let owner_account_idx = indices[1];
4838
4839 let instruction_data = build_name_service_unregister_subdomain_instruction(
4840 domain_account_idx,
4841 owner_account_idx,
4842 )?;
4843
4844 Ok(tx.with_instructions(instruction_data))
4845 }
4846
4847 pub fn build_thru_registrar_initialize_registry(
4849 fee_payer: TnPubkey,
4850 thru_registrar_program: TnPubkey,
4851 config_account: TnPubkey,
4852 name_service_program: TnPubkey,
4853 root_registrar_account: TnPubkey,
4854 treasurer_account: TnPubkey,
4855 token_mint_account: TnPubkey,
4856 token_program: TnPubkey,
4857 root_domain_name: &str,
4858 price_per_year: u64,
4859 config_proof: Vec<u8>,
4860 registrar_proof: Vec<u8>,
4861 fee: u64,
4862 nonce: u64,
4863 start_slot: u64,
4864 ) -> Result<Transaction> {
4865 let mut tx = Transaction::new(fee_payer, thru_registrar_program, fee, nonce)
4866 .with_start_slot(start_slot)
4867 .with_expiry_after(100)
4868 .with_compute_units(500_000)
4869 .with_state_units(10_000)
4870 .with_memory_units(10_000);
4871
4872 let mut rw_accounts = vec![config_account, root_registrar_account];
4875 rw_accounts.sort();
4876
4877 let mut ro_accounts = vec![
4878 name_service_program,
4879 treasurer_account,
4880 token_mint_account,
4881 token_program,
4882 ];
4883 ro_accounts.sort();
4884
4885 let mut config_account_idx = 0u16;
4887 let mut root_registrar_account_idx = 0u16;
4888 for (i, account) in rw_accounts.iter().enumerate() {
4889 let idx = (2 + i) as u16;
4890 if *account == config_account {
4891 config_account_idx = idx;
4892 } else if *account == root_registrar_account {
4893 root_registrar_account_idx = idx;
4894 }
4895 tx = tx.add_rw_account(*account);
4896 }
4897
4898 let base_ro_idx = 2 + rw_accounts.len() as u16;
4900 let mut name_service_program_idx = 0u16;
4901 let mut treasurer_account_idx = 0u16;
4902 let mut token_mint_account_idx = 0u16;
4903 let mut token_program_idx = 0u16;
4904
4905 for (i, account) in ro_accounts.iter().enumerate() {
4906 let idx = base_ro_idx + i as u16;
4907 if *account == name_service_program {
4908 name_service_program_idx = idx;
4909 } else if *account == root_registrar_account {
4910 root_registrar_account_idx = idx;
4911 } else if *account == treasurer_account {
4912 treasurer_account_idx = idx;
4913 } else if *account == token_mint_account {
4914 token_mint_account_idx = idx;
4915 } else if *account == token_program {
4916 token_program_idx = idx;
4917 }
4918 tx = tx.add_r_account(*account);
4919 }
4920
4921 let instruction_data = build_thru_registrar_initialize_registry_instruction(
4922 config_account_idx,
4923 name_service_program_idx,
4924 root_registrar_account_idx,
4925 treasurer_account_idx,
4926 token_mint_account_idx,
4927 token_program_idx,
4928 root_domain_name,
4929 price_per_year,
4930 config_proof,
4931 registrar_proof,
4932 )?;
4933
4934 Ok(tx.with_instructions(instruction_data))
4935 }
4936
4937 pub fn build_thru_registrar_purchase_domain(
4939 fee_payer: TnPubkey,
4940 thru_registrar_program: TnPubkey,
4941 config_account: TnPubkey,
4942 lease_account: TnPubkey,
4943 domain_account: TnPubkey,
4944 name_service_program: TnPubkey,
4945 root_registrar_account: TnPubkey,
4946 treasurer_account: TnPubkey,
4947 payer_token_account: TnPubkey,
4948 token_mint_account: TnPubkey,
4949 token_program: TnPubkey,
4950 domain_name: &str,
4951 years: u8,
4952 lease_proof: Vec<u8>,
4953 domain_proof: Vec<u8>,
4954 fee: u64,
4955 nonce: u64,
4956 start_slot: u64,
4957 ) -> Result<Transaction> {
4958 let mut tx = Transaction::new(fee_payer, thru_registrar_program, fee, nonce)
4959 .with_start_slot(start_slot)
4960 .with_expiry_after(100)
4961 .with_compute_units(500_000)
4962 .with_state_units(10_000)
4963 .with_memory_units(10_000);
4964
4965 let mut rw_accounts = vec![
4968 config_account,
4969 lease_account,
4970 domain_account,
4971 treasurer_account,
4972 payer_token_account,
4973 root_registrar_account,
4974 ];
4975 rw_accounts.sort();
4976
4977 let mut ro_accounts = vec![name_service_program, token_mint_account, token_program];
4978 ro_accounts.sort();
4979
4980 let mut config_account_idx = 0u16;
4982 let mut lease_account_idx = 0u16;
4983 let mut domain_account_idx = 0u16;
4984 let mut treasurer_account_idx = 0u16;
4985 let mut payer_token_account_idx = 0u16;
4986 let mut root_registrar_account_idx = 0u16;
4987 for (i, account) in rw_accounts.iter().enumerate() {
4988 let idx = (2 + i) as u16;
4989 if *account == config_account {
4990 config_account_idx = idx;
4991 } else if *account == lease_account {
4992 lease_account_idx = idx;
4993 } else if *account == domain_account {
4994 domain_account_idx = idx;
4995 } else if *account == treasurer_account {
4996 treasurer_account_idx = idx;
4997 } else if *account == payer_token_account {
4998 payer_token_account_idx = idx;
4999 } else if *account == root_registrar_account {
5000 root_registrar_account_idx = idx;
5001 }
5002 tx = tx.add_rw_account(*account);
5003 }
5004
5005 let base_ro_idx = 2 + rw_accounts.len() as u16;
5007 let mut name_service_program_idx = 0u16;
5008 let mut token_mint_account_idx = 0u16;
5009 let mut token_program_idx = 0u16;
5010
5011 for (i, account) in ro_accounts.iter().enumerate() {
5012 let idx = base_ro_idx + i as u16;
5013 if *account == config_account {
5014 config_account_idx = idx; } else if *account == name_service_program {
5016 name_service_program_idx = idx;
5017 } else if *account == root_registrar_account {
5018 root_registrar_account_idx = idx;
5019 } else if *account == treasurer_account {
5020 treasurer_account_idx = idx;
5021 } else if *account == payer_token_account {
5022 payer_token_account_idx = idx;
5023 } else if *account == token_mint_account {
5024 token_mint_account_idx = idx;
5025 } else if *account == token_program {
5026 token_program_idx = idx;
5027 }
5028 tx = tx.add_r_account(*account);
5029 }
5030
5031 let instruction_data = build_thru_registrar_purchase_domain_instruction(
5032 config_account_idx,
5033 lease_account_idx,
5034 domain_account_idx,
5035 name_service_program_idx,
5036 root_registrar_account_idx,
5037 treasurer_account_idx,
5038 payer_token_account_idx,
5039 token_mint_account_idx,
5040 token_program_idx,
5041 domain_name,
5042 years,
5043 lease_proof,
5044 domain_proof,
5045 )?;
5046
5047 Ok(tx.with_instructions(instruction_data))
5048 }
5049
5050 pub fn build_thru_registrar_renew_lease(
5052 fee_payer: TnPubkey,
5053 thru_registrar_program: TnPubkey,
5054 config_account: TnPubkey,
5055 lease_account: TnPubkey,
5056 treasurer_account: TnPubkey,
5057 payer_token_account: TnPubkey,
5058 token_mint_account: TnPubkey,
5059 token_program: TnPubkey,
5060 years: u8,
5061 fee: u64,
5062 nonce: u64,
5063 start_slot: u64,
5064 ) -> Result<Transaction> {
5065 let mut tx = Transaction::new(fee_payer, thru_registrar_program, fee, nonce)
5066 .with_start_slot(start_slot)
5067 .with_expiry_after(100)
5068 .with_compute_units(300_000)
5069 .with_state_units(10_000)
5070 .with_memory_units(10_000);
5071
5072 let mut rw_accounts = vec![lease_account, treasurer_account, payer_token_account];
5075 rw_accounts.sort();
5076
5077 let mut ro_accounts = vec![config_account, token_mint_account, token_program];
5078 ro_accounts.sort();
5079
5080 let mut lease_account_idx = 0u16;
5082 let mut treasurer_account_idx = 0u16;
5083 let mut payer_token_account_idx = 0u16;
5084 for (i, account) in rw_accounts.iter().enumerate() {
5085 let idx = (2 + i) as u16;
5086 if *account == lease_account {
5087 lease_account_idx = idx;
5088 } else if *account == treasurer_account {
5089 treasurer_account_idx = idx;
5090 } else if *account == payer_token_account {
5091 payer_token_account_idx = idx;
5092 }
5093 tx = tx.add_rw_account(*account);
5094 }
5095
5096 let base_ro_idx = 2 + rw_accounts.len() as u16;
5098 let mut config_account_idx = 0u16;
5099 let mut token_mint_account_idx = 0u16;
5100 let mut token_program_idx = 0u16;
5101
5102 for (i, account) in ro_accounts.iter().enumerate() {
5103 let idx = base_ro_idx + i as u16;
5104 if *account == config_account {
5105 config_account_idx = idx;
5106 } else if *account == token_mint_account {
5107 token_mint_account_idx = idx;
5108 } else if *account == token_program {
5109 token_program_idx = idx;
5110 }
5111 tx = tx.add_r_account(*account);
5112 }
5113
5114 let instruction_data = build_thru_registrar_renew_lease_instruction(
5115 config_account_idx,
5116 lease_account_idx,
5117 treasurer_account_idx,
5118 payer_token_account_idx,
5119 token_mint_account_idx,
5120 token_program_idx,
5121 years,
5122 )?;
5123
5124 Ok(tx.with_instructions(instruction_data))
5125 }
5126
5127 pub fn build_thru_registrar_claim_expired_domain(
5129 fee_payer: TnPubkey,
5130 thru_registrar_program: TnPubkey,
5131 config_account: TnPubkey,
5132 lease_account: TnPubkey,
5133 treasurer_account: TnPubkey,
5134 payer_token_account: TnPubkey,
5135 token_mint_account: TnPubkey,
5136 token_program: TnPubkey,
5137 years: u8,
5138 fee: u64,
5139 nonce: u64,
5140 start_slot: u64,
5141 ) -> Result<Transaction> {
5142 let mut tx = Transaction::new(fee_payer, thru_registrar_program, fee, nonce)
5143 .with_start_slot(start_slot)
5144 .with_expiry_after(100)
5145 .with_compute_units(300_000)
5146 .with_state_units(10_000)
5147 .with_memory_units(10_000);
5148
5149 let mut rw_accounts = vec![lease_account, treasurer_account, payer_token_account];
5152 rw_accounts.sort();
5153
5154 let mut ro_accounts = vec![config_account, token_mint_account, token_program];
5155 ro_accounts.sort();
5156
5157 let mut lease_account_idx = 0u16;
5159 let mut treasurer_account_idx = 0u16;
5160 let mut payer_token_account_idx = 0u16;
5161 for (i, account) in rw_accounts.iter().enumerate() {
5162 let idx = (2 + i) as u16;
5163 if *account == lease_account {
5164 lease_account_idx = idx;
5165 } else if *account == treasurer_account {
5166 treasurer_account_idx = idx;
5167 } else if *account == payer_token_account {
5168 payer_token_account_idx = idx;
5169 }
5170 tx = tx.add_rw_account(*account);
5171 }
5172
5173 let base_ro_idx = 2 + rw_accounts.len() as u16;
5175 let mut config_account_idx = 0u16;
5176 let mut token_mint_account_idx = 0u16;
5177 let mut token_program_idx = 0u16;
5178
5179 for (i, account) in ro_accounts.iter().enumerate() {
5180 let idx = base_ro_idx + i as u16;
5181 if *account == config_account {
5182 config_account_idx = idx;
5183 } else if *account == token_mint_account {
5184 token_mint_account_idx = idx;
5185 } else if *account == token_program {
5186 token_program_idx = idx;
5187 }
5188 tx = tx.add_r_account(*account);
5189 }
5190
5191 let instruction_data = build_thru_registrar_claim_expired_domain_instruction(
5192 config_account_idx,
5193 lease_account_idx,
5194 treasurer_account_idx,
5195 payer_token_account_idx,
5196 token_mint_account_idx,
5197 token_program_idx,
5198 years,
5199 )?;
5200
5201 Ok(tx.with_instructions(instruction_data))
5202 }
5203}
5204
5205fn build_token_initialize_mint_instruction(
5207 mint_account_idx: u16,
5208 decimals: u8,
5209 creator: TnPubkey,
5210 mint_authority: TnPubkey,
5211 freeze_authority: Option<TnPubkey>,
5212 ticker: &str,
5213 seed: [u8; 32],
5214 state_proof: Vec<u8>,
5215) -> Result<Vec<u8>> {
5216 let mut instruction_data = Vec::new();
5217
5218 instruction_data.push(TOKEN_INSTRUCTION_INITIALIZE_MINT);
5220
5221 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
5223
5224 instruction_data.push(decimals);
5226
5227 instruction_data.extend_from_slice(&creator);
5229
5230 instruction_data.extend_from_slice(&mint_authority);
5232
5233 let (freeze_auth, has_freeze_auth) = match freeze_authority {
5235 Some(auth) => (auth, 1u8),
5236 None => ([0u8; 32], 0u8),
5237 };
5238 instruction_data.extend_from_slice(&freeze_auth);
5239 instruction_data.push(has_freeze_auth);
5240
5241 let ticker_bytes = ticker.as_bytes();
5243 if ticker_bytes.len() > 8 {
5244 return Err(anyhow::anyhow!("Ticker must be 8 characters or less"));
5245 }
5246
5247 instruction_data.push(ticker_bytes.len() as u8);
5248 let mut ticker_padded = [0u8; 8];
5249 ticker_padded[..ticker_bytes.len()].copy_from_slice(ticker_bytes);
5250 instruction_data.extend_from_slice(&ticker_padded);
5251
5252 instruction_data.extend_from_slice(&seed);
5254
5255 instruction_data.extend_from_slice(&state_proof);
5257
5258 Ok(instruction_data)
5259}
5260
5261fn build_token_initialize_account_instruction(
5263 token_account_idx: u16,
5264 mint_account_idx: u16,
5265 owner_account_idx: u16,
5266 seed: [u8; 32],
5267 state_proof: Vec<u8>,
5268) -> Result<Vec<u8>> {
5269 let mut instruction_data = Vec::new();
5270
5271 instruction_data.push(TOKEN_INSTRUCTION_INITIALIZE_ACCOUNT);
5273
5274 instruction_data.extend_from_slice(&token_account_idx.to_le_bytes());
5276
5277 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
5279
5280 instruction_data.extend_from_slice(&owner_account_idx.to_le_bytes());
5282
5283 instruction_data.extend_from_slice(&seed);
5285
5286 instruction_data.extend_from_slice(&state_proof);
5288
5289 Ok(instruction_data)
5290}
5291
5292fn build_token_transfer_instruction(
5294 source_account_idx: u16,
5295 dest_account_idx: u16,
5296 amount: u64,
5297) -> Result<Vec<u8>> {
5298 let mut instruction_data = Vec::new();
5299
5300 instruction_data.push(TOKEN_INSTRUCTION_TRANSFER);
5302
5303 instruction_data.extend_from_slice(&source_account_idx.to_le_bytes());
5305
5306 instruction_data.extend_from_slice(&dest_account_idx.to_le_bytes());
5308
5309 instruction_data.extend_from_slice(&amount.to_le_bytes());
5311
5312 Ok(instruction_data)
5313}
5314
5315fn build_token_mint_to_instruction(
5317 mint_account_idx: u16,
5318 dest_account_idx: u16,
5319 authority_idx: u16,
5320 amount: u64,
5321) -> Result<Vec<u8>> {
5322 let mut instruction_data = Vec::new();
5323
5324 instruction_data.push(TOKEN_INSTRUCTION_MINT_TO);
5326
5327 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
5329
5330 instruction_data.extend_from_slice(&dest_account_idx.to_le_bytes());
5332
5333 instruction_data.extend_from_slice(&authority_idx.to_le_bytes());
5335
5336 instruction_data.extend_from_slice(&amount.to_le_bytes());
5338
5339 Ok(instruction_data)
5340}
5341
5342fn build_token_burn_instruction(
5344 token_account_idx: u16,
5345 mint_account_idx: u16,
5346 authority_idx: u16,
5347 amount: u64,
5348) -> Result<Vec<u8>> {
5349 let mut instruction_data = Vec::new();
5350
5351 instruction_data.push(TOKEN_INSTRUCTION_BURN);
5353
5354 instruction_data.extend_from_slice(&token_account_idx.to_le_bytes());
5356
5357 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
5359
5360 instruction_data.extend_from_slice(&authority_idx.to_le_bytes());
5362
5363 instruction_data.extend_from_slice(&amount.to_le_bytes());
5365
5366 Ok(instruction_data)
5367}
5368
5369fn build_token_freeze_account_instruction(
5371 token_account_idx: u16,
5372 mint_account_idx: u16,
5373 authority_idx: u16,
5374) -> Result<Vec<u8>> {
5375 let mut instruction_data = Vec::new();
5376
5377 instruction_data.push(TOKEN_INSTRUCTION_FREEZE_ACCOUNT);
5379
5380 instruction_data.extend_from_slice(&token_account_idx.to_le_bytes());
5382
5383 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
5385
5386 instruction_data.extend_from_slice(&authority_idx.to_le_bytes());
5388
5389 Ok(instruction_data)
5390}
5391
5392fn build_token_thaw_account_instruction(
5394 token_account_idx: u16,
5395 mint_account_idx: u16,
5396 authority_idx: u16,
5397) -> Result<Vec<u8>> {
5398 let mut instruction_data = Vec::new();
5399
5400 instruction_data.push(TOKEN_INSTRUCTION_THAW_ACCOUNT);
5402
5403 instruction_data.extend_from_slice(&token_account_idx.to_le_bytes());
5405
5406 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
5408
5409 instruction_data.extend_from_slice(&authority_idx.to_le_bytes());
5411
5412 Ok(instruction_data)
5413}
5414
5415fn build_token_close_account_instruction(
5417 token_account_idx: u16,
5418 destination_idx: u16,
5419 authority_idx: u16,
5420) -> Result<Vec<u8>> {
5421 let mut instruction_data = Vec::new();
5422
5423 instruction_data.push(TOKEN_INSTRUCTION_CLOSE_ACCOUNT);
5425
5426 instruction_data.extend_from_slice(&token_account_idx.to_le_bytes());
5428
5429 instruction_data.extend_from_slice(&destination_idx.to_le_bytes());
5431
5432 instruction_data.extend_from_slice(&authority_idx.to_le_bytes());
5434
5435 Ok(instruction_data)
5436}
5437
5438fn build_wthru_initialize_mint_instruction(
5439 token_program_idx: u16,
5440 mint_account_idx: u16,
5441 vault_account_idx: u16,
5442 decimals: u8,
5443 mint_seed: [u8; 32],
5444 mint_proof: Vec<u8>,
5445 vault_proof: Vec<u8>,
5446) -> Result<Vec<u8>> {
5447 let mint_proof_len =
5448 u64::try_from(mint_proof.len()).map_err(|_| anyhow::anyhow!("mint proof too large"))?;
5449 let vault_proof_len =
5450 u64::try_from(vault_proof.len()).map_err(|_| anyhow::anyhow!("vault proof too large"))?;
5451
5452 let mut instruction_data = Vec::new();
5453 instruction_data.extend_from_slice(&TN_WTHRU_INSTRUCTION_INITIALIZE_MINT.to_le_bytes());
5454 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
5455 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
5456 instruction_data.extend_from_slice(&vault_account_idx.to_le_bytes());
5457 instruction_data.push(decimals);
5458 instruction_data.extend_from_slice(&mint_seed);
5459 instruction_data.extend_from_slice(&mint_proof_len.to_le_bytes());
5460 instruction_data.extend_from_slice(&vault_proof_len.to_le_bytes());
5461 instruction_data.extend_from_slice(&mint_proof);
5462 instruction_data.extend_from_slice(&vault_proof);
5463
5464 Ok(instruction_data)
5465}
5466
5467fn build_wthru_deposit_instruction(
5468 token_program_idx: u16,
5469 vault_account_idx: u16,
5470 mint_account_idx: u16,
5471 dest_account_idx: u16,
5472) -> Result<Vec<u8>> {
5473 let mut instruction_data = Vec::new();
5474 instruction_data.extend_from_slice(&TN_WTHRU_INSTRUCTION_DEPOSIT.to_le_bytes());
5475 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
5476 instruction_data.extend_from_slice(&vault_account_idx.to_le_bytes());
5477 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
5478 instruction_data.extend_from_slice(&dest_account_idx.to_le_bytes());
5479
5480 Ok(instruction_data)
5481}
5482
5483fn build_wthru_withdraw_instruction(
5484 token_program_idx: u16,
5485 vault_account_idx: u16,
5486 mint_account_idx: u16,
5487 wthru_token_account_idx: u16,
5488 owner_account_idx: u16,
5489 recipient_account_idx: u16,
5490 amount: u64,
5491) -> Result<Vec<u8>> {
5492 let mut instruction_data = Vec::new();
5493 instruction_data.extend_from_slice(&TN_WTHRU_INSTRUCTION_WITHDRAW.to_le_bytes());
5494 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
5495 instruction_data.extend_from_slice(&vault_account_idx.to_le_bytes());
5496 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
5497 instruction_data.extend_from_slice(&wthru_token_account_idx.to_le_bytes());
5498 instruction_data.extend_from_slice(&owner_account_idx.to_le_bytes());
5499 instruction_data.extend_from_slice(&recipient_account_idx.to_le_bytes());
5500 instruction_data.extend_from_slice(&amount.to_le_bytes());
5501
5502 Ok(instruction_data)
5503}
5504
5505fn build_faucet_deposit_instruction(
5507 faucet_account_idx: u16,
5508 depositor_account_idx: u16,
5509 eoa_program_idx: u16,
5510 amount: u64,
5511) -> Result<Vec<u8>> {
5512 let mut instruction_data = Vec::new();
5513
5514 instruction_data.extend_from_slice(&0u32.to_le_bytes());
5516
5517 instruction_data.extend_from_slice(&faucet_account_idx.to_le_bytes());
5520
5521 instruction_data.extend_from_slice(&depositor_account_idx.to_le_bytes());
5523
5524 instruction_data.extend_from_slice(&eoa_program_idx.to_le_bytes());
5526
5527 instruction_data.extend_from_slice(&amount.to_le_bytes());
5529
5530 Ok(instruction_data)
5531}
5532
5533fn build_faucet_withdraw_instruction(
5535 faucet_account_idx: u16,
5536 recipient_account_idx: u16,
5537 amount: u64,
5538) -> Result<Vec<u8>> {
5539 let mut instruction_data = Vec::new();
5540
5541 instruction_data.extend_from_slice(&1u32.to_le_bytes());
5543
5544 instruction_data.extend_from_slice(&faucet_account_idx.to_le_bytes());
5547
5548 instruction_data.extend_from_slice(&recipient_account_idx.to_le_bytes());
5550
5551 instruction_data.extend_from_slice(&amount.to_le_bytes());
5553
5554 Ok(instruction_data)
5555}
5556
5557fn build_activate_instruction(
5560 attestor_table_idx: u64,
5561 token_program_idx: u16,
5562 source_token_account_idx: u16,
5563 converted_vault_idx: u16,
5564 identity_idx: u16,
5565 bls_pk: [u8; 96],
5566 claim_authority: [u8; 32],
5567 token_amount: u64,
5568) -> Result<Vec<u8>> {
5569 let mut instruction_data = Vec::new();
5570
5571 instruction_data.extend_from_slice(&1u32.to_le_bytes());
5573
5574 instruction_data.extend_from_slice(&attestor_table_idx.to_le_bytes());
5577
5578 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
5580
5581 instruction_data.extend_from_slice(&source_token_account_idx.to_le_bytes());
5583
5584 instruction_data.extend_from_slice(&converted_vault_idx.to_le_bytes());
5586
5587 instruction_data.extend_from_slice(&identity_idx.to_le_bytes());
5589
5590 instruction_data.extend_from_slice(&bls_pk);
5592
5593 instruction_data.extend_from_slice(&claim_authority);
5595
5596 instruction_data.extend_from_slice(&token_amount.to_le_bytes());
5598
5599 Ok(instruction_data)
5600}
5601
5602fn build_deactivate_instruction(
5605 attestor_table_idx: u64,
5606 token_program_idx: u16,
5607 unclaimed_vault_idx: u16,
5608 dest_token_account_idx: u16,
5609 identity_idx: u16,
5610) -> Result<Vec<u8>> {
5611 let mut instruction_data = Vec::new();
5612
5613 instruction_data.extend_from_slice(&2u32.to_le_bytes());
5614 instruction_data.extend_from_slice(&attestor_table_idx.to_le_bytes());
5615 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
5616 instruction_data.extend_from_slice(&unclaimed_vault_idx.to_le_bytes());
5617 instruction_data.extend_from_slice(&dest_token_account_idx.to_le_bytes());
5618 instruction_data.extend_from_slice(&identity_idx.to_le_bytes());
5619
5620 Ok(instruction_data)
5621}
5622
5623fn build_convert_tokens_instruction(
5626 attestor_table_idx: u64,
5627 token_program_idx: u16,
5628 source_token_account_idx: u16,
5629 converted_vault_idx: u16,
5630 identity_idx: u16,
5631 token_amount: u64,
5632) -> Result<Vec<u8>> {
5633 let mut instruction_data = Vec::new();
5634
5635 instruction_data.extend_from_slice(&3u32.to_le_bytes());
5636 instruction_data.extend_from_slice(&attestor_table_idx.to_le_bytes());
5637 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
5638 instruction_data.extend_from_slice(&source_token_account_idx.to_le_bytes());
5639 instruction_data.extend_from_slice(&converted_vault_idx.to_le_bytes());
5640 instruction_data.extend_from_slice(&identity_idx.to_le_bytes());
5641 instruction_data.extend_from_slice(&token_amount.to_le_bytes());
5642
5643 Ok(instruction_data)
5644}
5645
5646fn build_claim_instruction(
5649 attestor_table_idx: u64,
5650 token_program_idx: u16,
5651 unclaimed_vault_idx: u16,
5652 dest_token_account_idx: u16,
5653 claim_authority_idx: u16,
5654 subject_attestor: TnPubkey,
5655) -> Result<Vec<u8>> {
5656 let mut instruction_data = Vec::new();
5657
5658 instruction_data.extend_from_slice(&4u32.to_le_bytes());
5659 instruction_data.extend_from_slice(&attestor_table_idx.to_le_bytes());
5660 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
5661 instruction_data.extend_from_slice(&unclaimed_vault_idx.to_le_bytes());
5662 instruction_data.extend_from_slice(&dest_token_account_idx.to_le_bytes());
5663 instruction_data.extend_from_slice(&claim_authority_idx.to_le_bytes());
5664 instruction_data.extend_from_slice(&subject_attestor);
5665
5666 Ok(instruction_data)
5667}
5668
5669fn build_set_claim_authority_instruction(
5672 attestor_table_idx: u64,
5673 current_claim_auth_idx: u16,
5674 subject_attestor: TnPubkey,
5675 new_claim_authority: TnPubkey,
5676) -> Result<Vec<u8>> {
5677 let mut instruction_data = Vec::new();
5678
5679 instruction_data.extend_from_slice(&5u32.to_le_bytes());
5680 instruction_data.extend_from_slice(&attestor_table_idx.to_le_bytes());
5681 instruction_data.extend_from_slice(¤t_claim_auth_idx.to_le_bytes());
5682 instruction_data.extend_from_slice(&subject_attestor);
5683 instruction_data.extend_from_slice(&new_claim_authority);
5684
5685 Ok(instruction_data)
5686}
5687
5688#[repr(C, packed)]
5689struct NameServiceInitializeRootArgs {
5690 registrar_account_idx: u16,
5691 authority_account_idx: u16,
5692 root_name: [u8; TN_NAME_SERVICE_MAX_DOMAIN_LENGTH],
5693 root_name_length: u32,
5694}
5695
5696#[repr(C, packed)]
5697struct NameServiceRegisterSubdomainArgs {
5698 domain_account_idx: u16,
5699 parent_account_idx: u16,
5700 owner_account_idx: u16,
5701 authority_account_idx: u16,
5702 name: [u8; TN_NAME_SERVICE_MAX_DOMAIN_LENGTH],
5703 name_length: u32,
5704}
5705
5706#[repr(C, packed)]
5707struct NameServiceAppendRecordArgs {
5708 domain_account_idx: u16,
5709 owner_account_idx: u16,
5710 key_length: u32,
5711 key: [u8; TN_NAME_SERVICE_MAX_KEY_LENGTH],
5712 value_length: u32,
5713 value: [u8; TN_NAME_SERVICE_MAX_VALUE_LENGTH],
5714}
5715
5716#[repr(C, packed)]
5717struct NameServiceDeleteRecordArgs {
5718 domain_account_idx: u16,
5719 owner_account_idx: u16,
5720 key_length: u32,
5721 key: [u8; TN_NAME_SERVICE_MAX_KEY_LENGTH],
5722}
5723
5724#[repr(C, packed)]
5725struct NameServiceUnregisterSubdomainArgs {
5726 domain_account_idx: u16,
5727 owner_account_idx: u16,
5728}
5729
5730fn build_name_service_initialize_root_instruction(
5732 registrar_account_idx: u16,
5733 authority_account_idx: u16,
5734 root_name: &str,
5735 state_proof: Vec<u8>,
5736) -> Result<Vec<u8>> {
5737 let root_name_bytes = root_name.as_bytes();
5738 if root_name_bytes.is_empty() || root_name_bytes.len() > TN_NAME_SERVICE_MAX_DOMAIN_LENGTH {
5739 return Err(anyhow::anyhow!(
5740 "Root name length must be between 1 and {}",
5741 TN_NAME_SERVICE_MAX_DOMAIN_LENGTH
5742 ));
5743 }
5744
5745 let mut args = NameServiceInitializeRootArgs {
5746 registrar_account_idx,
5747 authority_account_idx,
5748 root_name: [0u8; TN_NAME_SERVICE_MAX_DOMAIN_LENGTH],
5749 root_name_length: root_name_bytes.len() as u32,
5750 };
5751 args.root_name[..root_name_bytes.len()].copy_from_slice(root_name_bytes);
5752
5753 let mut instruction_data = Vec::new();
5754 instruction_data.extend_from_slice(&TN_NAME_SERVICE_INSTRUCTION_INITIALIZE_ROOT.to_le_bytes());
5755
5756 let args_bytes = unsafe {
5757 std::slice::from_raw_parts(
5758 &args as *const _ as *const u8,
5759 std::mem::size_of::<NameServiceInitializeRootArgs>(),
5760 )
5761 };
5762 instruction_data.extend_from_slice(args_bytes);
5763
5764 instruction_data.extend_from_slice(&TN_NAME_SERVICE_PROOF_INLINE.to_le_bytes());
5765 instruction_data.extend_from_slice(&state_proof);
5766
5767 Ok(instruction_data)
5768}
5769
5770fn build_name_service_register_subdomain_instruction(
5772 domain_account_idx: u16,
5773 parent_account_idx: u16,
5774 owner_account_idx: u16,
5775 authority_account_idx: u16,
5776 domain_name: &str,
5777 state_proof: Vec<u8>,
5778) -> Result<Vec<u8>> {
5779 let domain_bytes = domain_name.as_bytes();
5780 if domain_bytes.is_empty() || domain_bytes.len() > TN_NAME_SERVICE_MAX_DOMAIN_LENGTH {
5781 return Err(anyhow::anyhow!(
5782 "Domain name length must be between 1 and {}",
5783 TN_NAME_SERVICE_MAX_DOMAIN_LENGTH
5784 ));
5785 }
5786
5787 let mut args = NameServiceRegisterSubdomainArgs {
5788 domain_account_idx,
5789 parent_account_idx,
5790 owner_account_idx,
5791 authority_account_idx,
5792 name: [0u8; TN_NAME_SERVICE_MAX_DOMAIN_LENGTH],
5793 name_length: domain_bytes.len() as u32,
5794 };
5795 args.name[..domain_bytes.len()].copy_from_slice(domain_bytes);
5796
5797 let mut instruction_data = Vec::new();
5798 instruction_data
5799 .extend_from_slice(&TN_NAME_SERVICE_INSTRUCTION_REGISTER_SUBDOMAIN.to_le_bytes());
5800
5801 let args_bytes = unsafe {
5802 std::slice::from_raw_parts(
5803 &args as *const _ as *const u8,
5804 std::mem::size_of::<NameServiceRegisterSubdomainArgs>(),
5805 )
5806 };
5807 instruction_data.extend_from_slice(args_bytes);
5808
5809 instruction_data.extend_from_slice(&TN_NAME_SERVICE_PROOF_INLINE.to_le_bytes());
5810 instruction_data.extend_from_slice(&state_proof);
5811
5812 Ok(instruction_data)
5813}
5814
5815fn build_name_service_append_record_instruction(
5817 domain_account_idx: u16,
5818 owner_account_idx: u16,
5819 key: &[u8],
5820 value: &[u8],
5821) -> Result<Vec<u8>> {
5822 if key.is_empty() || key.len() > TN_NAME_SERVICE_MAX_KEY_LENGTH {
5823 return Err(anyhow::anyhow!(
5824 "Key length must be between 1 and {} bytes",
5825 TN_NAME_SERVICE_MAX_KEY_LENGTH
5826 ));
5827 }
5828 if value.len() > TN_NAME_SERVICE_MAX_VALUE_LENGTH {
5829 return Err(anyhow::anyhow!(
5830 "Value length must be <= {} bytes",
5831 TN_NAME_SERVICE_MAX_VALUE_LENGTH
5832 ));
5833 }
5834
5835 let mut args = NameServiceAppendRecordArgs {
5836 domain_account_idx,
5837 owner_account_idx,
5838 key_length: key.len() as u32,
5839 key: [0u8; TN_NAME_SERVICE_MAX_KEY_LENGTH],
5840 value_length: value.len() as u32,
5841 value: [0u8; TN_NAME_SERVICE_MAX_VALUE_LENGTH],
5842 };
5843 args.key[..key.len()].copy_from_slice(key);
5844 args.value[..value.len()].copy_from_slice(value);
5845
5846 let mut instruction_data = Vec::new();
5847 instruction_data.extend_from_slice(&TN_NAME_SERVICE_INSTRUCTION_APPEND_RECORD.to_le_bytes());
5848
5849 let args_bytes = unsafe {
5850 std::slice::from_raw_parts(
5851 &args as *const _ as *const u8,
5852 std::mem::size_of::<NameServiceAppendRecordArgs>(),
5853 )
5854 };
5855 instruction_data.extend_from_slice(args_bytes);
5856
5857 Ok(instruction_data)
5858}
5859
5860fn build_name_service_delete_record_instruction(
5862 domain_account_idx: u16,
5863 owner_account_idx: u16,
5864 key: &[u8],
5865) -> Result<Vec<u8>> {
5866 if key.is_empty() || key.len() > TN_NAME_SERVICE_MAX_KEY_LENGTH {
5867 return Err(anyhow::anyhow!(
5868 "Key length must be between 1 and {} bytes",
5869 TN_NAME_SERVICE_MAX_KEY_LENGTH
5870 ));
5871 }
5872
5873 let mut args = NameServiceDeleteRecordArgs {
5874 domain_account_idx,
5875 owner_account_idx,
5876 key_length: key.len() as u32,
5877 key: [0u8; TN_NAME_SERVICE_MAX_KEY_LENGTH],
5878 };
5879 args.key[..key.len()].copy_from_slice(key);
5880
5881 let mut instruction_data = Vec::new();
5882 instruction_data.extend_from_slice(&TN_NAME_SERVICE_INSTRUCTION_DELETE_RECORD.to_le_bytes());
5883
5884 let args_bytes = unsafe {
5885 std::slice::from_raw_parts(
5886 &args as *const _ as *const u8,
5887 std::mem::size_of::<NameServiceDeleteRecordArgs>(),
5888 )
5889 };
5890 instruction_data.extend_from_slice(args_bytes);
5891
5892 Ok(instruction_data)
5893}
5894
5895fn build_name_service_unregister_subdomain_instruction(
5897 domain_account_idx: u16,
5898 owner_account_idx: u16,
5899) -> Result<Vec<u8>> {
5900 let args = NameServiceUnregisterSubdomainArgs {
5901 domain_account_idx,
5902 owner_account_idx,
5903 };
5904
5905 let mut instruction_data = Vec::new();
5906 instruction_data.extend_from_slice(&TN_NAME_SERVICE_INSTRUCTION_UNREGISTER.to_le_bytes());
5907
5908 let args_bytes = unsafe {
5909 std::slice::from_raw_parts(
5910 &args as *const _ as *const u8,
5911 std::mem::size_of::<NameServiceUnregisterSubdomainArgs>(),
5912 )
5913 };
5914 instruction_data.extend_from_slice(args_bytes);
5915
5916 Ok(instruction_data)
5917}
5918
5919fn build_thru_registrar_initialize_registry_instruction(
5921 config_account_idx: u16,
5922 name_service_program_idx: u16,
5923 root_registrar_account_idx: u16,
5924 treasurer_account_idx: u16,
5925 token_mint_account_idx: u16,
5926 token_program_idx: u16,
5927 root_domain_name: &str,
5928 price_per_year: u64,
5929 config_proof: Vec<u8>,
5930 registrar_proof: Vec<u8>,
5931) -> Result<Vec<u8>> {
5932 let mut instruction_data = Vec::new();
5933
5934 instruction_data
5936 .extend_from_slice(&TN_THRU_REGISTRAR_INSTRUCTION_INITIALIZE_REGISTRY.to_le_bytes());
5937
5938 instruction_data.extend_from_slice(&config_account_idx.to_le_bytes());
5941 instruction_data.extend_from_slice(&name_service_program_idx.to_le_bytes());
5943 instruction_data.extend_from_slice(&root_registrar_account_idx.to_le_bytes());
5945 instruction_data.extend_from_slice(&treasurer_account_idx.to_le_bytes());
5947 instruction_data.extend_from_slice(&token_mint_account_idx.to_le_bytes());
5949 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
5951 let domain_bytes = root_domain_name.as_bytes();
5953 if domain_bytes.len() > 64 {
5954 return Err(anyhow::anyhow!(
5955 "Root domain name must be 64 characters or less"
5956 ));
5957 }
5958 let mut domain_padded = [0u8; 64];
5959 domain_padded[..domain_bytes.len()].copy_from_slice(domain_bytes);
5960 instruction_data.extend_from_slice(&domain_padded);
5961 instruction_data.extend_from_slice(&(domain_bytes.len() as u32).to_le_bytes());
5963 instruction_data.extend_from_slice(&price_per_year.to_le_bytes());
5965
5966 instruction_data.extend_from_slice(&config_proof);
5969 instruction_data.extend_from_slice(®istrar_proof);
5971
5972 Ok(instruction_data)
5973}
5974
5975fn build_thru_registrar_purchase_domain_instruction(
5977 config_account_idx: u16,
5978 lease_account_idx: u16,
5979 domain_account_idx: u16,
5980 name_service_program_idx: u16,
5981 root_registrar_account_idx: u16,
5982 treasurer_account_idx: u16,
5983 payer_token_account_idx: u16,
5984 token_mint_account_idx: u16,
5985 token_program_idx: u16,
5986 domain_name: &str,
5987 years: u8,
5988 lease_proof: Vec<u8>,
5989 domain_proof: Vec<u8>,
5990) -> Result<Vec<u8>> {
5991 let mut instruction_data = Vec::new();
5992
5993 instruction_data
5995 .extend_from_slice(&TN_THRU_REGISTRAR_INSTRUCTION_PURCHASE_DOMAIN.to_le_bytes());
5996
5997 instruction_data.extend_from_slice(&config_account_idx.to_le_bytes());
6000 instruction_data.extend_from_slice(&lease_account_idx.to_le_bytes());
6002 instruction_data.extend_from_slice(&domain_account_idx.to_le_bytes());
6004 instruction_data.extend_from_slice(&name_service_program_idx.to_le_bytes());
6006 instruction_data.extend_from_slice(&root_registrar_account_idx.to_le_bytes());
6008 instruction_data.extend_from_slice(&treasurer_account_idx.to_le_bytes());
6010 instruction_data.extend_from_slice(&payer_token_account_idx.to_le_bytes());
6012 instruction_data.extend_from_slice(&token_mint_account_idx.to_le_bytes());
6014 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
6016 let domain_bytes = domain_name.as_bytes();
6018 if domain_bytes.len() > 64 {
6019 return Err(anyhow::anyhow!("Domain name must be 64 characters or less"));
6020 }
6021 let mut domain_padded = [0u8; 64];
6022 domain_padded[..domain_bytes.len()].copy_from_slice(domain_bytes);
6023 instruction_data.extend_from_slice(&domain_padded);
6024 instruction_data.extend_from_slice(&(domain_bytes.len() as u32).to_le_bytes());
6026 instruction_data.push(years);
6028
6029 instruction_data.extend_from_slice(&lease_proof);
6032 instruction_data.extend_from_slice(&domain_proof);
6034
6035 Ok(instruction_data)
6036}
6037
6038fn build_thru_registrar_renew_lease_instruction(
6040 config_account_idx: u16,
6041 lease_account_idx: u16,
6042 treasurer_account_idx: u16,
6043 payer_token_account_idx: u16,
6044 token_mint_account_idx: u16,
6045 token_program_idx: u16,
6046 years: u8,
6047) -> Result<Vec<u8>> {
6048 let mut instruction_data = Vec::new();
6049
6050 instruction_data.extend_from_slice(&TN_THRU_REGISTRAR_INSTRUCTION_RENEW_LEASE.to_le_bytes());
6052
6053 instruction_data.extend_from_slice(&config_account_idx.to_le_bytes());
6056 instruction_data.extend_from_slice(&lease_account_idx.to_le_bytes());
6058 instruction_data.extend_from_slice(&treasurer_account_idx.to_le_bytes());
6060 instruction_data.extend_from_slice(&payer_token_account_idx.to_le_bytes());
6062 instruction_data.extend_from_slice(&token_mint_account_idx.to_le_bytes());
6064 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
6066 instruction_data.push(years);
6068
6069 Ok(instruction_data)
6070}
6071
6072fn build_thru_registrar_claim_expired_domain_instruction(
6074 config_account_idx: u16,
6075 lease_account_idx: u16,
6076 treasurer_account_idx: u16,
6077 payer_token_account_idx: u16,
6078 token_mint_account_idx: u16,
6079 token_program_idx: u16,
6080 years: u8,
6081) -> Result<Vec<u8>> {
6082 let mut instruction_data = Vec::new();
6083
6084 instruction_data
6086 .extend_from_slice(&TN_THRU_REGISTRAR_INSTRUCTION_CLAIM_EXPIRED_DOMAIN.to_le_bytes());
6087
6088 instruction_data.extend_from_slice(&config_account_idx.to_le_bytes());
6091 instruction_data.extend_from_slice(&lease_account_idx.to_le_bytes());
6093 instruction_data.extend_from_slice(&treasurer_account_idx.to_le_bytes());
6095 instruction_data.extend_from_slice(&payer_token_account_idx.to_le_bytes());
6097 instruction_data.extend_from_slice(&token_mint_account_idx.to_le_bytes());
6099 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
6101 instruction_data.push(years);
6103
6104 Ok(instruction_data)
6105}