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