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