1use crate::{
2 StateProof,
3 tn_public_address::tn_pubkey_to_address_string,
4 txn_lib::{TnPubkey, Transaction},
5};
6use anyhow::Result;
7use hex;
8use std::collections::HashMap;
9
10pub const NOOP_PROGRAM: [u8; 32] = {
12 let mut arr = [0u8; 32];
13 arr[31] = 0x03;
14 arr
15};
16pub const SYSTEM_PROGRAM: [u8; 32] = {
17 let mut arr = [0u8; 32];
18 arr[31] = 0x01;
19 arr
20};
21pub const EOA_PROGRAM: [u8; 32] = {
22 let arr = [0u8; 32];
23 arr
24};
25
26pub const UPLOADER_PROGRAM: [u8; 32] = {
27 let mut arr = [0u8; 32];
28 arr[31] = 0x02;
29 arr
30};
31pub const FAUCET_PROGRAM: [u8; 32] = {
32 let mut arr = [0u8; 32];
33 arr[31] = 0xFA;
34 arr
35};
36
37pub const CONSENSUS_VALIDATOR_PROGRAM: [u8; 32] = {
39 let mut arr = [0u8; 32];
40 arr[30] = 0x0C;
41 arr[31] = 0x01;
42 arr
43};
44
45pub const TOKEN_PROGRAM: [u8; 32] = {
47 let mut arr = [0u8; 32];
48 arr[31] = 0xAA;
49 arr
50};
51
52pub const ATTESTOR_TABLE: [u8; 32] = {
54 let mut arr = [0u8; 32];
55 arr[30] = 0x0C;
56 arr[31] = 0x02;
57 arr
58};
59
60pub const CONVERTED_VAULT: [u8; 32] = {
62 let mut arr = [0u8; 32];
63 arr[30] = 0x0C;
64 arr[31] = 0x04;
65 arr
66};
67
68#[derive(Debug, Clone)]
69pub struct TransactionBuilder {
70 }
75
76impl TransactionBuilder {
77 pub fn build_create_with_fee_payer_proof(
79 fee_payer: TnPubkey,
80 start_slot: u64,
81 fee_payer_state_proof: &StateProof,
82 ) -> Result<Transaction> {
83 let tx = Transaction::new(fee_payer, NOOP_PROGRAM, 0, 0)
84 .with_fee_payer_state_proof(fee_payer_state_proof)
85 .with_start_slot(start_slot)
86 .with_expiry_after(100)
87 .with_compute_units(10_000)
88 .with_memory_units(10_000)
89 .with_state_units(10_000);
90 Ok(tx)
91 }
92
93 pub fn build_transfer(
107 fee_payer: TnPubkey,
108 program: TnPubkey,
109 to_account: TnPubkey,
110 amount: u64,
111 fee: u64,
112 nonce: u64,
113 start_slot: u64,
114 ) -> Result<Transaction> {
115 let from_account_idx = 0u16; let to_account_idx = 2u16; let instruction_data =
120 build_transfer_instruction(from_account_idx, to_account_idx, amount)?;
121
122 let tx = Transaction::new(fee_payer, program, fee, nonce)
123 .with_start_slot(start_slot)
124 .add_rw_account(to_account) .with_instructions(instruction_data)
126 .with_expiry_after(100)
127 .with_compute_units(10000)
128 .with_memory_units(10000)
129 .with_state_units(10000);
130
131 Ok(tx)
132 }
133
134 pub fn build_create_account(
136 fee_payer: TnPubkey,
137 program: TnPubkey,
138 target_account: TnPubkey,
139 seed: &str,
140 state_proof: Option<&[u8]>,
141 fee: u64,
142 nonce: u64,
143 start_slot: u64,
144 ) -> Result<Transaction> {
145 let target_account_idx = 2u16; let instruction_data =
148 build_create_account_instruction(target_account_idx, seed, state_proof)?;
149
150 let tx = Transaction::new(fee_payer, program, fee, nonce)
151 .with_start_slot(start_slot)
152 .add_rw_account(target_account)
153 .with_instructions(instruction_data)
154 .with_expiry_after(100)
155 .with_compute_units(10_000)
156 .with_memory_units(10_000)
157 .with_state_units(10_000);
158
159 Ok(tx)
160 }
161
162 pub fn build_create_ephemeral_account(
164 fee_payer: TnPubkey,
165 program: TnPubkey,
166 target_account: TnPubkey,
167 seed: &[u8; 32],
168 fee: u64,
169 nonce: u64,
170 start_slot: u64,
171 ) -> Result<Transaction> {
172 let target_account_idx = 2u16; let instruction_data = build_ephemeral_account_instruction(target_account_idx, seed)?;
175
176 let tx = Transaction::new(fee_payer, program, fee, nonce)
177 .with_start_slot(start_slot)
178 .add_rw_account(target_account)
179 .with_instructions(instruction_data)
180 .with_expiry_after(100)
181 .with_compute_units(50_000)
182 .with_memory_units(10_000)
183 .with_state_units(10_000);
184 Ok(tx)
185 }
186
187 pub fn build_resize_account(
189 fee_payer: TnPubkey,
190 program: TnPubkey,
191 target_account: TnPubkey,
192 new_size: u64,
193 fee: u64,
194 nonce: u64,
195 start_slot: u64,
196 ) -> Result<Transaction> {
197 let target_account_idx = 2u16; let instruction_data = build_resize_instruction(target_account_idx, new_size)?;
200
201 let tx = Transaction::new(fee_payer, program, fee, nonce)
202 .with_start_slot(start_slot)
203 .with_expiry_after(100)
204 .with_compute_units(100032)
205 .with_state_units(1 + new_size.checked_div(4096).unwrap() as u16)
206 .with_memory_units(10000)
207 .add_rw_account(target_account)
208 .with_instructions(instruction_data)
209 .with_expiry_after(100)
210 .with_compute_units(10_000 + 2 * new_size as u32)
211 .with_memory_units(10_000)
212 .with_state_units(10_000);
213
214 Ok(tx)
215 }
216
217 pub fn build_compress_account(
219 fee_payer: TnPubkey,
220 program: TnPubkey,
221 target_account: TnPubkey,
222 state_proof: &[u8],
223 fee: u64,
224 nonce: u64,
225 start_slot: u64,
226 account_size: u32,
227 ) -> Result<Transaction> {
228 let target_account_idx = 2u16; let instruction_data = build_compress_instruction(target_account_idx, state_proof)?;
231
232 let tx = Transaction::new(fee_payer, program, fee, nonce)
233 .with_start_slot(start_slot)
234 .with_may_compress_account()
235 .add_rw_account(target_account)
236 .with_instructions(instruction_data)
237 .with_expiry_after(100)
238 .with_compute_units(100_300 + account_size * 2)
239 .with_memory_units(10000)
240 .with_state_units(10000);
241
242 Ok(tx)
243 }
244
245 pub fn build_decompress_account(
247 fee_payer: TnPubkey,
248 program: TnPubkey,
249 target_account: TnPubkey,
250 account_data: &[u8],
251 state_proof: &[u8],
252 fee: u64,
253 nonce: u64,
254 start_slot: u64,
255 ) -> Result<Transaction> {
256 let target_account_idx = 2u16; let instruction_data =
259 build_decompress_instruction(target_account_idx, account_data, state_proof)?;
260
261 let tx = Transaction::new(fee_payer, program, fee, nonce)
262 .with_start_slot(start_slot)
263 .add_rw_account(target_account)
264 .with_instructions(instruction_data)
265 .with_compute_units(100_300 + account_data.len() as u32 * 2)
266 .with_state_units(10_000)
267 .with_memory_units(10_000)
268 .with_expiry_after(100);
269 Ok(tx)
270 }
271
272 pub fn build_write_data(
274 fee_payer: TnPubkey,
275 program: TnPubkey,
276 target_account: TnPubkey,
277 offset: u16,
278 data: &[u8],
279 fee: u64,
280 nonce: u64,
281 start_slot: u64,
282 ) -> Result<Transaction> {
283 let target_account_idx = 2u16; let instruction_data = build_write_instruction(target_account_idx, offset, data)?;
286
287 let tx = Transaction::new(fee_payer, program, fee, nonce)
288 .with_start_slot(start_slot)
289 .with_expiry_after(100)
290 .with_compute_units(100045)
291 .with_state_units(10000)
292 .with_memory_units(10000)
293 .add_rw_account(target_account)
294 .with_instructions(instruction_data);
295
296 Ok(tx)
297 }
298}
299
300fn build_transfer_instruction(
309 from_account_idx: u16,
310 to_account_idx: u16,
311 amount: u64,
312) -> Result<Vec<u8>> {
313 let mut instruction = Vec::new();
314
315 instruction.extend_from_slice(&1u32.to_le_bytes());
317
318 instruction.extend_from_slice(&amount.to_le_bytes());
321
322 instruction.extend_from_slice(&from_account_idx.to_le_bytes());
324
325 instruction.extend_from_slice(&to_account_idx.to_le_bytes());
327
328 Ok(instruction)
329}
330
331fn build_create_account_instruction(
333 target_account_idx: u16,
334 seed: &str,
335 state_proof: Option<&[u8]>,
336) -> Result<Vec<u8>> {
337 let mut instruction = Vec::new();
338
339 instruction.push(0x00);
341
342 instruction.extend_from_slice(&target_account_idx.to_le_bytes());
344
345 let seed_bytes =
347 hex::decode(seed).map_err(|e| anyhow::anyhow!("Failed to decode hex seed: {}", e))?;
348
349 instruction.extend_from_slice(&(seed_bytes.len() as u64).to_le_bytes());
351
352 let has_proof = state_proof.is_some();
354 instruction.push(if has_proof { 1u8 } else { 0u8 });
355
356 instruction.extend_from_slice(&seed_bytes);
358
359 if let Some(proof) = state_proof {
361 instruction.extend_from_slice(proof);
362 }
363
364 Ok(instruction)
365}
366
367fn build_ephemeral_account_instruction(
369 target_account_idx: u16,
370 seed: &[u8; 32],
371) -> Result<Vec<u8>> {
372 let mut instruction = Vec::new();
373
374 instruction.push(0x01);
376
377 instruction.extend_from_slice(&target_account_idx.to_le_bytes());
379
380 instruction.extend_from_slice(&(seed.len() as u64).to_le_bytes());
382
383 instruction.extend_from_slice(seed);
385
386 Ok(instruction)
387}
388
389fn build_resize_instruction(target_account_idx: u16, new_size: u64) -> Result<Vec<u8>> {
391 let mut instruction = Vec::new();
392
393 instruction.push(0x04);
395
396 instruction.extend_from_slice(&target_account_idx.to_le_bytes());
398
399 instruction.extend_from_slice(&new_size.to_le_bytes());
401
402 Ok(instruction)
403}
404
405fn build_write_instruction(target_account_idx: u16, offset: u16, data: &[u8]) -> Result<Vec<u8>> {
407 let mut instruction = Vec::new();
408
409 instruction.push(0xC8);
411
412 instruction.extend_from_slice(&target_account_idx.to_le_bytes());
414
415 instruction.extend_from_slice(&offset.to_le_bytes());
417
418 instruction.extend_from_slice(&(data.len() as u16).to_le_bytes());
420
421 instruction.extend_from_slice(data);
423
424 Ok(instruction)
425}
426
427fn build_compress_instruction(target_account_idx: u16, state_proof: &[u8]) -> Result<Vec<u8>> {
429 let mut instruction = Vec::new();
430
431 instruction.push(0x05);
434
435 instruction.extend_from_slice(&target_account_idx.to_le_bytes());
437
438 instruction.extend_from_slice(state_proof);
440
441 Ok(instruction)
442}
443
444fn build_decompress_instruction(
445 target_account_idx: u16,
446 account_data: &[u8],
447 state_proof: &[u8],
448) -> Result<Vec<u8>> {
449 let mut instruction = Vec::new();
450
451 instruction.push(0x06);
453
454 instruction.extend_from_slice(&target_account_idx.to_le_bytes());
456 instruction.extend_from_slice(&(account_data.len() as u64).to_le_bytes());
457
458 instruction.extend_from_slice(account_data);
460
461 instruction.extend_from_slice(state_proof);
463
464 Ok(instruction)
465}
466
467pub fn generate_ephemeral_address(seed: &str) -> Result<String> {
472 let owner_pubkey = [0u8; 32];
474
475 let seed_bytes =
477 hex::decode(seed).map_err(|e| anyhow::anyhow!("Failed to decode hex seed: {}", e))?;
478
479 let mut seed_32 = [0u8; 32];
481 let copy_len = std::cmp::min(seed_bytes.len(), 32);
482 seed_32[..copy_len].copy_from_slice(&seed_bytes[..copy_len]);
483
484 Ok(
486 crate::tn_public_address::create_program_defined_account_address_string(
487 &owner_pubkey,
488 true, &seed_32,
490 ),
491 )
492}
493
494pub fn generate_system_derived_address(seed: &str, is_ephemeral: bool) -> Result<String> {
495 let seed_bytes =
497 hex::decode(seed).map_err(|e| anyhow::anyhow!("Failed to decode hex seed: {}", e))?;
498
499 let pubkey = generate_derived_address(&seed_bytes, &[0u8; 32], is_ephemeral)?;
500
501 Ok(tn_pubkey_to_address_string(&pubkey))
502}
503
504pub fn generate_derived_address(
505 seed: &[u8],
506 owner_pubkey: &[u8; 32],
507 is_ephemeral: bool,
508) -> Result<[u8; 32]> {
509 use sha2::{Digest, Sha256};
510
511 let mut hasher = Sha256::new();
513
514 hasher.update(&owner_pubkey);
516
517 hasher.update(&[is_ephemeral as u8]);
519
520 hasher.update(&seed);
522
523 Ok(hasher.finalize().into())
525}
526
527#[cfg(test)]
528mod tests {
529 use super::*;
530
531 #[test]
532 fn test_ephemeral_address_generation() {
533 let hex_seed1 = hex::encode("test_seed_123");
535 let hex_seed2 = hex::encode("test_seed_123");
536 let hex_seed3 = hex::encode("different_seed");
537
538 let addr1 = generate_ephemeral_address(&hex_seed1).unwrap();
539 let addr2 = generate_ephemeral_address(&hex_seed2).unwrap();
540 let addr3 = generate_ephemeral_address(&hex_seed3).unwrap();
541
542 assert_eq!(addr1, addr2);
544
545 assert_ne!(addr1, addr3);
547
548 assert!(addr1.starts_with("ta"));
550 assert!(addr2.starts_with("ta"));
551 assert!(addr3.starts_with("ta"));
552
553 assert_eq!(addr1.len(), 46);
555 assert_eq!(addr2.len(), 46);
556 assert_eq!(addr3.len(), 46);
557 }
558
559 #[test]
560 fn test_eoa_transfer_instruction_format() {
561 let from_idx = 0u16;
563 let to_idx = 2u16;
564 let amount = 1000u64;
565
566 let instruction = build_transfer_instruction(from_idx, to_idx, amount).unwrap();
567
568 assert_eq!(instruction.len(), 16, "Instruction should be 16 bytes");
576
577 let discriminant = u32::from_le_bytes([
579 instruction[0],
580 instruction[1],
581 instruction[2],
582 instruction[3],
583 ]);
584 assert_eq!(discriminant, 1, "Discriminant should be 1 for TRANSFER");
585
586 let parsed_amount = u64::from_le_bytes([
588 instruction[4],
589 instruction[5],
590 instruction[6],
591 instruction[7],
592 instruction[8],
593 instruction[9],
594 instruction[10],
595 instruction[11],
596 ]);
597 assert_eq!(parsed_amount, amount, "Amount should match input");
598
599 let parsed_from = u16::from_le_bytes([instruction[12], instruction[13]]);
601 assert_eq!(parsed_from, from_idx, "From index should match input");
602
603 let parsed_to = u16::from_le_bytes([instruction[14], instruction[15]]);
605 assert_eq!(parsed_to, to_idx, "To index should match input");
606 }
607
608 #[test]
609 fn test_faucet_deposit_instruction_layout_with_fee_payer_depositor() {
610 let fee_payer = [1u8; 32];
611 let faucet_program = FAUCET_PROGRAM;
612 let faucet_account = [2u8; 32];
613 let depositor_account = fee_payer;
614 let amount = 500u64;
615
616 let tx = TransactionBuilder::build_faucet_deposit(
617 fee_payer,
618 faucet_program,
619 faucet_account,
620 depositor_account,
621 EOA_PROGRAM,
622 amount,
623 0,
624 42,
625 100,
626 )
627 .expect("build faucet deposit");
628
629 let rw_accs = tx.rw_accs.expect("rw accounts must exist");
630 assert_eq!(rw_accs.len(), 1);
631 assert_eq!(rw_accs[0], faucet_account);
632
633 let ro_accs = tx.r_accs.expect("ro accounts must exist");
634 assert_eq!(ro_accs.len(), 1);
635 assert_eq!(ro_accs[0], EOA_PROGRAM);
636
637 let instruction = tx.instructions.expect("instruction bytes must exist");
638 assert_eq!(instruction.len(), 18, "Deposit instruction must be 18 bytes");
639
640 let discriminant =
641 u32::from_le_bytes([instruction[0], instruction[1], instruction[2], instruction[3]]);
642 assert_eq!(discriminant, 0, "Deposit discriminant should be 0");
643
644 let faucet_idx = u16::from_le_bytes([instruction[4], instruction[5]]);
645 let depositor_idx = u16::from_le_bytes([instruction[6], instruction[7]]);
646 let eoa_idx = u16::from_le_bytes([instruction[8], instruction[9]]);
647 let parsed_amount = u64::from_le_bytes([
648 instruction[10],
649 instruction[11],
650 instruction[12],
651 instruction[13],
652 instruction[14],
653 instruction[15],
654 instruction[16],
655 instruction[17],
656 ]);
657
658 assert_eq!(faucet_idx, 2, "Faucet account should be first RW account");
659 assert_eq!(depositor_idx, 0, "Depositor shares the fee payer index");
660 assert_eq!(eoa_idx, 3, "EOA program should follow RW accounts");
661 assert_eq!(parsed_amount, amount, "Amount should match input");
662 }
663
664 #[test]
665 fn test_build_token_initialize_mint() {
666 let fee_payer = [1u8; 32];
668 let token_program = [2u8; 32];
669 let mint_account = [3u8; 32];
670 let creator = [4u8; 32];
671 let mint_authority = [5u8; 32];
672 let freeze_authority = [6u8; 32];
673
674 let decimals = 9u8;
675 let ticker = "TEST";
676 let seed = [7u8; 32];
677 let state_proof = vec![8u8; 64];
678
679 let result = TransactionBuilder::build_token_initialize_mint(
681 fee_payer,
682 token_program,
683 mint_account,
684 creator,
685 mint_authority,
686 Some(freeze_authority),
687 decimals,
688 ticker,
689 seed,
690 state_proof.clone(),
691 1000, 1, 100, );
695
696 assert!(result.is_ok(), "Should build valid transaction with freeze authority");
697 let tx = result.unwrap();
698 assert!(tx.instructions.is_some(), "Transaction should have instructions");
699
700 let result_no_freeze = TransactionBuilder::build_token_initialize_mint(
702 fee_payer,
703 token_program,
704 mint_account,
705 creator,
706 mint_authority,
707 None,
708 decimals,
709 ticker,
710 seed,
711 state_proof,
712 1000,
713 1,
714 100,
715 );
716
717 assert!(result_no_freeze.is_ok(), "Should build valid transaction without freeze authority");
718 }
719
720 #[test]
721 fn test_build_token_initialize_mint_instruction_format() {
722 let mint_account_idx = 2u16;
723 let decimals = 9u8;
724 let creator = [1u8; 32];
725 let mint_authority = [2u8; 32];
726 let freeze_authority = [3u8; 32];
727 let ticker = "TST";
728 let seed = [4u8; 32];
729 let state_proof = vec![5u8; 10];
730
731 let instruction = build_token_initialize_mint_instruction(
732 mint_account_idx,
733 decimals,
734 creator,
735 mint_authority,
736 Some(freeze_authority),
737 ticker,
738 seed,
739 state_proof.clone(),
740 )
741 .unwrap();
742
743 let expected_min_size = 1 + 2 + 1 + 32 + 32 + 32 + 1 + 1 + 8 + 32 + state_proof.len();
747 assert_eq!(instruction.len(), expected_min_size);
748
749 assert_eq!(instruction[0], 0, "First byte should be InitializeMint tag (0)");
751
752 let parsed_idx = u16::from_le_bytes([instruction[1], instruction[2]]);
754 assert_eq!(parsed_idx, mint_account_idx);
755
756 assert_eq!(instruction[3], decimals);
758
759 assert_eq!(&instruction[4..36], &creator);
761
762 assert_eq!(&instruction[36..68], &mint_authority);
764
765 assert_eq!(&instruction[68..100], &freeze_authority);
767
768 assert_eq!(instruction[100], 1);
770 }
771
772 #[test]
773 fn test_token_initialize_mint_creator_vs_mint_authority() {
774 let fee_payer = [1u8; 32];
776 let token_program = [2u8; 32];
777 let mint_account = [3u8; 32];
778 let creator = [4u8; 32];
779 let mint_authority = [5u8; 32]; let seed = [6u8; 32];
781 let state_proof = vec![7u8; 32];
782
783 let result = TransactionBuilder::build_token_initialize_mint(
784 fee_payer,
785 token_program,
786 mint_account,
787 creator,
788 mint_authority,
789 None,
790 9,
791 "TEST",
792 seed,
793 state_proof,
794 1000,
795 1,
796 100,
797 );
798
799 assert!(result.is_ok(), "Should allow different creator and mint_authority");
800
801 let result_same = TransactionBuilder::build_token_initialize_mint(
803 fee_payer,
804 token_program,
805 mint_account,
806 creator,
807 creator, None,
809 9,
810 "TEST",
811 seed,
812 vec![7u8; 32],
813 1000,
814 1,
815 100,
816 );
817
818 assert!(result_same.is_ok(), "Should allow same creator and mint_authority");
819 }
820}
821
822pub const TN_UPLOADER_PROGRAM_INSTRUCTION_CREATE: u32 = 0x00;
824pub const TN_UPLOADER_PROGRAM_INSTRUCTION_WRITE: u32 = 0x01;
825pub const TN_UPLOADER_PROGRAM_INSTRUCTION_DESTROY: u32 = 0x02;
826pub const TN_UPLOADER_PROGRAM_INSTRUCTION_FINALIZE: u32 = 0x03;
827
828#[repr(C, packed)]
830#[derive(Debug, Clone, Copy)]
831pub struct UploaderCreateArgs {
832 pub buffer_account_idx: u16,
833 pub meta_account_idx: u16,
834 pub authority_account_idx: u16,
835 pub buffer_account_sz: u32,
836 pub expected_account_hash: [u8; 32],
837 pub seed_len: u32,
838 }
840
841#[repr(C, packed)]
843#[derive(Debug, Clone, Copy)]
844pub struct UploaderWriteArgs {
845 pub buffer_account_idx: u16,
846 pub meta_account_idx: u16,
847 pub data_len: u32,
848 pub data_offset: u32,
849 }
851
852#[repr(C, packed)]
854#[derive(Debug, Clone, Copy)]
855pub struct UploaderFinalizeArgs {
856 pub buffer_account_idx: u16,
857 pub meta_account_idx: u16,
858 pub expected_account_hash: [u8; 32],
859}
860
861#[repr(C, packed)]
863#[derive(Debug, Clone, Copy)]
864pub struct UploaderDestroyArgs {
865 pub buffer_account_idx: u16,
866 pub meta_account_idx: u16,
867}
868
869pub const MANAGER_INSTRUCTION_CREATE_PERMANENT: u8 = 0x00;
871pub const MANAGER_INSTRUCTION_CREATE_EPHEMERAL: u8 = 0x01;
872pub const MANAGER_INSTRUCTION_UPGRADE: u8 = 0x02;
873pub const MANAGER_INSTRUCTION_SET_PAUSE: u8 = 0x03;
874pub const MANAGER_INSTRUCTION_DESTROY: u8 = 0x04;
875pub const MANAGER_INSTRUCTION_FINALIZE: u8 = 0x05;
876pub const MANAGER_INSTRUCTION_SET_AUTHORITY: u8 = 0x06;
877pub const MANAGER_INSTRUCTION_CLAIM_AUTHORITY: u8 = 0x07;
878
879pub const ABI_MANAGER_INSTRUCTION_CREATE_META_OFFICIAL_PERMANENT: u8 = 0x00;
880pub const ABI_MANAGER_INSTRUCTION_CREATE_META_OFFICIAL_EPHEMERAL: u8 = 0x01;
881pub const ABI_MANAGER_INSTRUCTION_CREATE_META_EXTERNAL_PERMANENT: u8 = 0x02;
882pub const ABI_MANAGER_INSTRUCTION_CREATE_META_EXTERNAL_EPHEMERAL: u8 = 0x03;
883pub const ABI_MANAGER_INSTRUCTION_CREATE_ABI_OFFICIAL_PERMANENT: u8 = 0x04;
884pub const ABI_MANAGER_INSTRUCTION_CREATE_ABI_OFFICIAL_EPHEMERAL: u8 = 0x05;
885pub const ABI_MANAGER_INSTRUCTION_CREATE_ABI_EXTERNAL_PERMANENT: u8 = 0x06;
886pub const ABI_MANAGER_INSTRUCTION_CREATE_ABI_EXTERNAL_EPHEMERAL: u8 = 0x07;
887pub const ABI_MANAGER_INSTRUCTION_UPGRADE_ABI_OFFICIAL: u8 = 0x08;
888pub const ABI_MANAGER_INSTRUCTION_UPGRADE_ABI_EXTERNAL: u8 = 0x09;
889pub const ABI_MANAGER_INSTRUCTION_CLOSE_ABI_OFFICIAL: u8 = 0x0a;
890pub const ABI_MANAGER_INSTRUCTION_CLOSE_ABI_EXTERNAL: u8 = 0x0b;
891pub const ABI_MANAGER_INSTRUCTION_FINALIZE_ABI_OFFICIAL: u8 = 0x0c;
892pub const ABI_MANAGER_INSTRUCTION_FINALIZE_ABI_EXTERNAL: u8 = 0x0d;
893
894#[repr(C, packed)]
896#[derive(Debug, Clone, Copy)]
897pub struct ManagerHeaderArgs {
898 pub discriminant: u8,
899 pub meta_account_idx: u16,
900 pub program_account_idx: u16,
901}
902
903#[repr(C, packed)]
905#[derive(Debug, Clone, Copy)]
906pub struct ManagerCreateArgs {
907 pub discriminant: u8,
908 pub meta_account_idx: u16,
909 pub program_account_idx: u16,
910 pub srcbuf_account_idx: u16,
911 pub srcbuf_offset: u32,
912 pub srcbuf_size: u32,
913 pub authority_account_idx: u16,
914 pub seed_len: u32,
915 }
917
918#[repr(C, packed)]
920#[derive(Debug, Clone, Copy)]
921pub struct ManagerUpgradeArgs {
922 pub discriminant: u8,
923 pub meta_account_idx: u16,
924 pub program_account_idx: u16,
925 pub srcbuf_account_idx: u16,
926 pub srcbuf_offset: u32,
927 pub srcbuf_size: u32,
928}
929
930#[repr(C, packed)]
932#[derive(Debug, Clone, Copy)]
933pub struct AbiManagerCreateMetaOfficialArgs {
934 pub abi_meta_account_idx: u16,
935 pub program_meta_account_idx: u16,
936 pub authority_account_idx: u16,
937}
938
939#[repr(C, packed)]
941#[derive(Debug, Clone, Copy)]
942pub struct AbiManagerCreateMetaExternalArgs {
943 pub abi_meta_account_idx: u16,
944 pub authority_account_idx: u16,
945 pub target_program: TnPubkey,
946 pub seed: [u8; 32],
947}
948
949#[repr(C, packed)]
951#[derive(Debug, Clone, Copy)]
952pub struct AbiManagerCreateAbiOfficialArgs {
953 pub abi_meta_account_idx: u16,
954 pub program_meta_account_idx: u16,
955 pub abi_account_idx: u16,
956 pub srcbuf_account_idx: u16,
957 pub srcbuf_offset: u32,
958 pub srcbuf_size: u32,
959 pub authority_account_idx: u16,
960}
961
962#[repr(C, packed)]
964#[derive(Debug, Clone, Copy)]
965pub struct AbiManagerCreateAbiExternalArgs {
966 pub abi_meta_account_idx: u16,
967 pub abi_account_idx: u16,
968 pub srcbuf_account_idx: u16,
969 pub srcbuf_offset: u32,
970 pub srcbuf_size: u32,
971 pub authority_account_idx: u16,
972}
973
974#[repr(C, packed)]
976#[derive(Debug, Clone, Copy)]
977pub struct AbiManagerUpgradeAbiOfficialArgs {
978 pub abi_meta_account_idx: u16,
979 pub program_meta_account_idx: u16,
980 pub abi_account_idx: u16,
981 pub srcbuf_account_idx: u16,
982 pub srcbuf_offset: u32,
983 pub srcbuf_size: u32,
984 pub authority_account_idx: u16,
985}
986
987#[repr(C, packed)]
989#[derive(Debug, Clone, Copy)]
990pub struct AbiManagerUpgradeAbiExternalArgs {
991 pub abi_meta_account_idx: u16,
992 pub abi_account_idx: u16,
993 pub srcbuf_account_idx: u16,
994 pub srcbuf_offset: u32,
995 pub srcbuf_size: u32,
996 pub authority_account_idx: u16,
997}
998
999#[repr(C, packed)]
1001#[derive(Debug, Clone, Copy)]
1002pub struct AbiManagerFinalizeAbiOfficialArgs {
1003 pub abi_meta_account_idx: u16,
1004 pub program_meta_account_idx: u16,
1005 pub abi_account_idx: u16,
1006 pub authority_account_idx: u16,
1007}
1008
1009#[repr(C, packed)]
1011#[derive(Debug, Clone, Copy)]
1012pub struct AbiManagerFinalizeAbiExternalArgs {
1013 pub abi_meta_account_idx: u16,
1014 pub abi_account_idx: u16,
1015 pub authority_account_idx: u16,
1016}
1017
1018#[repr(C, packed)]
1020#[derive(Debug, Clone, Copy)]
1021pub struct AbiManagerCloseAbiOfficialArgs {
1022 pub abi_meta_account_idx: u16,
1023 pub program_meta_account_idx: u16,
1024 pub abi_account_idx: u16,
1025 pub authority_account_idx: u16,
1026}
1027
1028#[repr(C, packed)]
1030#[derive(Debug, Clone, Copy)]
1031pub struct AbiManagerCloseAbiExternalArgs {
1032 pub abi_meta_account_idx: u16,
1033 pub abi_account_idx: u16,
1034 pub authority_account_idx: u16,
1035}
1036
1037#[repr(C, packed)]
1039#[derive(Debug, Clone, Copy)]
1040pub struct ManagerSetPauseArgs {
1041 pub discriminant: u8,
1042 pub meta_account_idx: u16,
1043 pub program_account_idx: u16,
1044 pub is_paused: u8,
1045}
1046
1047#[repr(C, packed)]
1049#[derive(Debug, Clone, Copy)]
1050pub struct ManagerSetAuthorityArgs {
1051 pub discriminant: u8,
1052 pub meta_account_idx: u16,
1053 pub program_account_idx: u16,
1054 pub authority_candidate: [u8; 32],
1055}
1056
1057pub const TN_TEST_UPLOADER_PROGRAM_DISCRIMINANT_CREATE: u8 = 0x00;
1059pub const TN_TEST_UPLOADER_PROGRAM_DISCRIMINANT_WRITE: u8 = 0x01;
1060
1061#[repr(C, packed)]
1063#[derive(Debug, Clone, Copy)]
1064pub struct TestUploaderCreateArgs {
1065 pub account_idx: u16,
1066 pub is_ephemeral: u8,
1067 pub account_sz: u32,
1068 pub seed_len: u32,
1069 }
1071
1072#[repr(C, packed)]
1074#[derive(Debug, Clone, Copy)]
1075pub struct TestUploaderWriteArgs {
1076 pub target_account_idx: u16,
1077 pub target_offset: u32,
1078 pub data_len: u32,
1079 }
1081
1082#[repr(C, packed)]
1084#[derive(Debug, Clone, Copy)]
1085pub struct SystemProgramDecompress2Args {
1086 pub target_account_idx: u16,
1087 pub meta_account_idx: u16,
1088 pub data_account_idx: u16,
1089 pub data_offset: u32,
1090}
1091
1092impl TransactionBuilder {
1093 pub fn build_uploader_create(
1095 fee_payer: TnPubkey,
1096 uploader_program: TnPubkey,
1097 meta_account: TnPubkey,
1098 buffer_account: TnPubkey,
1099 buffer_size: u32,
1100 expected_hash: [u8; 32],
1101 seed: &[u8],
1102 fee: u64,
1103 nonce: u64,
1104 start_slot: u64,
1105 ) -> Result<Transaction> {
1106 let authority_account_idx = 0u16;
1108
1109 let mut tx = Transaction::new(fee_payer, uploader_program, fee, nonce)
1110 .with_start_slot(start_slot)
1111 .with_expiry_after(10)
1112 .with_compute_units(50_000 + 2 * buffer_size as u32)
1113 .with_memory_units(10_000)
1114 .with_state_units(10_000);
1115
1116 let mut meta_account_idx = 2u16;
1117 let mut buffer_account_idx = 3u16;
1118 if meta_account > buffer_account {
1119 meta_account_idx = 3u16;
1120 buffer_account_idx = 2u16;
1121 tx = tx
1122 .add_rw_account(buffer_account)
1123 .add_rw_account(meta_account)
1124 } else {
1125 tx = tx
1126 .add_rw_account(meta_account)
1127 .add_rw_account(buffer_account)
1128 }
1129
1130 let instruction_data = build_uploader_create_instruction(
1131 buffer_account_idx,
1132 meta_account_idx,
1133 authority_account_idx,
1134 buffer_size,
1135 expected_hash,
1136 seed,
1137 )?;
1138
1139 tx = tx.with_instructions(instruction_data);
1140
1141 Ok(tx)
1142 }
1143
1144 pub fn build_uploader_write(
1146 fee_payer: TnPubkey,
1147 uploader_program: TnPubkey,
1148 meta_account: TnPubkey,
1149 buffer_account: TnPubkey,
1150 data: &[u8],
1151 offset: u32,
1152 fee: u64,
1153 nonce: u64,
1154 start_slot: u64,
1155 ) -> Result<Transaction> {
1156 let mut tx = Transaction::new(fee_payer, uploader_program, fee, nonce)
1158 .with_start_slot(start_slot)
1159 .with_expiry_after(10000)
1160 .with_compute_units(500_000_000)
1161 .with_memory_units(5000)
1162 .with_state_units(5000);
1163
1164 let mut meta_account_idx = 2u16;
1165 let mut buffer_account_idx = 3u16;
1166 if meta_account > buffer_account {
1167 meta_account_idx = 3u16;
1168 buffer_account_idx = 2u16;
1169 tx = tx
1170 .add_rw_account(buffer_account)
1171 .add_rw_account(meta_account)
1172 } else {
1173 tx = tx
1174 .add_rw_account(meta_account)
1175 .add_rw_account(buffer_account)
1176 }
1177
1178 let instruction_data =
1179 build_uploader_write_instruction(buffer_account_idx, meta_account_idx, data, offset)?;
1180
1181 tx = tx.with_instructions(instruction_data);
1182
1183 Ok(tx)
1184 }
1185
1186 pub fn build_uploader_finalize(
1188 fee_payer: TnPubkey,
1189 uploader_program: TnPubkey,
1190 meta_account: TnPubkey,
1191 buffer_account: TnPubkey,
1192 buffer_size: u32,
1193 expected_hash: [u8; 32],
1194 fee: u64,
1195 nonce: u64,
1196 start_slot: u64,
1197 ) -> Result<Transaction> {
1198 let mut tx = Transaction::new(fee_payer, uploader_program, fee, nonce)
1199 .with_start_slot(start_slot)
1200 .with_expiry_after(10000)
1201 .with_compute_units(50_000 + 200 * buffer_size as u32)
1202 .with_memory_units(5000)
1203 .with_state_units(5000);
1204
1205 let mut meta_account_idx = 2u16;
1207 let mut buffer_account_idx = 3u16;
1208 if meta_account > buffer_account {
1209 meta_account_idx = 3u16;
1210 buffer_account_idx = 2u16;
1211 tx = tx
1212 .add_rw_account(buffer_account)
1213 .add_rw_account(meta_account)
1214 } else {
1215 tx = tx
1216 .add_rw_account(meta_account)
1217 .add_rw_account(buffer_account)
1218 }
1219
1220 let instruction_data = build_uploader_finalize_instruction(
1221 buffer_account_idx,
1222 meta_account_idx,
1223 expected_hash,
1224 )?;
1225
1226 tx = tx.with_instructions(instruction_data);
1227
1228 Ok(tx)
1229 }
1230
1231 pub fn build_uploader_destroy(
1233 fee_payer: TnPubkey,
1234 uploader_program: TnPubkey,
1235 meta_account: TnPubkey,
1236 buffer_account: TnPubkey,
1237 fee: u64,
1238 nonce: u64,
1239 start_slot: u64,
1240 ) -> Result<Transaction> {
1241 let mut tx = Transaction::new(fee_payer, uploader_program, fee, nonce)
1242 .with_start_slot(start_slot)
1243 .with_expiry_after(10000)
1244 .with_compute_units(50000)
1245 .with_memory_units(5000)
1246 .with_state_units(5000);
1247
1248 let mut meta_account_idx = 2u16;
1250 let mut buffer_account_idx = 3u16;
1251 if meta_account > buffer_account {
1252 meta_account_idx = 3u16;
1253 buffer_account_idx = 2u16;
1254 tx = tx
1255 .add_rw_account(buffer_account)
1256 .add_rw_account(meta_account)
1257 } else {
1258 tx = tx
1259 .add_rw_account(meta_account)
1260 .add_rw_account(buffer_account)
1261 }
1262
1263 let instruction_data =
1264 build_uploader_destroy_instruction(buffer_account_idx, meta_account_idx)?;
1265
1266 tx = tx.with_instructions(instruction_data);
1267 Ok(tx)
1268 }
1269
1270 pub fn build_manager_create(
1272 fee_payer: TnPubkey,
1273 manager_program: TnPubkey,
1274 meta_account: TnPubkey,
1275 program_account: TnPubkey,
1276 srcbuf_account: TnPubkey,
1277 authority_account: TnPubkey,
1278 srcbuf_offset: u32,
1279 srcbuf_size: u32,
1280 seed: &[u8],
1281 is_ephemeral: bool,
1282 meta_proof: Option<&[u8]>,
1283 program_proof: Option<&[u8]>,
1284 fee: u64,
1285 nonce: u64,
1286 start_slot: u64,
1287 ) -> Result<Transaction> {
1288 let mut tx = Transaction::new(fee_payer, manager_program, fee, nonce)
1289 .with_start_slot(start_slot)
1290 .with_expiry_after(10000)
1291 .with_compute_units(500_000_000)
1292 .with_memory_units(5000)
1293 .with_state_units(5000);
1294
1295 let authority_is_fee_payer = authority_account == fee_payer;
1297
1298 let mut rw_accounts = vec![(meta_account, "meta"), (program_account, "program")];
1300
1301 let mut r_accounts = vec![(srcbuf_account, "srcbuf")];
1302
1303 if !authority_is_fee_payer {
1305 r_accounts.push((authority_account, "authority"));
1306 }
1307
1308 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1310
1311 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1313
1314 let mut accounts = rw_accounts;
1316 accounts.extend(r_accounts);
1317
1318 let mut meta_account_idx = 0u16;
1319 let mut program_account_idx = 0u16;
1320 let mut srcbuf_account_idx = 0u16;
1321 let mut authority_account_idx = if authority_is_fee_payer {
1322 0u16 } else {
1324 0u16 };
1326
1327 for (i, (account, account_type)) in accounts.iter().enumerate() {
1328 let idx = (i + 2) as u16; match *account_type {
1330 "meta" => {
1331 meta_account_idx = idx;
1332 tx = tx.add_rw_account(*account);
1333 }
1334 "program" => {
1335 program_account_idx = idx;
1336 tx = tx.add_rw_account(*account);
1337 }
1338 "srcbuf" => {
1339 srcbuf_account_idx = idx;
1340 tx = tx.add_r_account(*account);
1341 }
1342 "authority" => {
1343 authority_account_idx = idx;
1344 tx = tx.add_r_account(*account);
1345 }
1346 _ => unreachable!(),
1347 }
1348 }
1349
1350 let discriminant = if is_ephemeral {
1351 MANAGER_INSTRUCTION_CREATE_EPHEMERAL
1352 } else {
1353 MANAGER_INSTRUCTION_CREATE_PERMANENT
1354 };
1355
1356 let combined_proof = if let (Some(meta), Some(program)) = (meta_proof, program_proof) {
1358 let mut combined = Vec::with_capacity(meta.len() + program.len());
1359 combined.extend_from_slice(meta);
1360 combined.extend_from_slice(program);
1361 Some(combined)
1362 } else {
1363 None
1364 };
1365
1366 let instruction_data = build_manager_create_instruction(
1367 discriminant,
1368 meta_account_idx,
1369 program_account_idx,
1370 srcbuf_account_idx,
1371 authority_account_idx,
1372 srcbuf_offset,
1373 srcbuf_size,
1374 seed,
1375 combined_proof.as_deref(),
1376 )?;
1377
1378 tx = tx.with_instructions(instruction_data);
1379 Ok(tx)
1380 }
1381
1382 pub fn build_abi_manager_create_meta_official(
1384 fee_payer: TnPubkey,
1385 abi_manager_program: TnPubkey,
1386 program_meta_account: TnPubkey,
1387 abi_meta_account: TnPubkey,
1388 authority_account: TnPubkey,
1389 is_ephemeral: bool,
1390 abi_meta_proof: Option<&[u8]>,
1391 fee: u64,
1392 nonce: u64,
1393 start_slot: u64,
1394 ) -> Result<Transaction> {
1395 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
1396 .with_start_slot(start_slot)
1397 .with_expiry_after(10000)
1398 .with_compute_units(500_000_000)
1399 .with_memory_units(5000)
1400 .with_state_units(5000);
1401
1402 let authority_is_fee_payer = authority_account == fee_payer;
1403
1404 let mut rw_accounts = vec![(abi_meta_account, "abi_meta")];
1405 let mut r_accounts = vec![(program_meta_account, "program_meta")];
1406
1407 if !authority_is_fee_payer {
1408 r_accounts.push((authority_account, "authority"));
1409 }
1410
1411 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1412 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1413
1414 let mut accounts = rw_accounts;
1415 accounts.extend(r_accounts);
1416
1417 let mut abi_meta_account_idx = 0u16;
1418 let mut program_meta_account_idx = 0u16;
1419 let mut authority_account_idx = 0u16;
1420
1421 for (i, (account, account_type)) in accounts.iter().enumerate() {
1422 let idx = (i + 2) as u16;
1423 match *account_type {
1424 "abi_meta" => {
1425 abi_meta_account_idx = idx;
1426 tx = tx.add_rw_account(*account);
1427 }
1428 "program_meta" => {
1429 program_meta_account_idx = idx;
1430 tx = tx.add_r_account(*account);
1431 }
1432 "authority" => {
1433 authority_account_idx = idx;
1434 tx = tx.add_r_account(*account);
1435 }
1436 _ => unreachable!(),
1437 }
1438 }
1439
1440 let authority_idx = if authority_is_fee_payer {
1441 0u16
1442 } else {
1443 authority_account_idx
1444 };
1445
1446 let discriminant = if is_ephemeral {
1447 ABI_MANAGER_INSTRUCTION_CREATE_META_OFFICIAL_EPHEMERAL
1448 } else {
1449 ABI_MANAGER_INSTRUCTION_CREATE_META_OFFICIAL_PERMANENT
1450 };
1451
1452 let instruction_data = build_abi_manager_create_meta_official_instruction(
1453 discriminant,
1454 abi_meta_account_idx,
1455 program_meta_account_idx,
1456 authority_idx,
1457 abi_meta_proof,
1458 )?;
1459
1460 tx = tx.with_instructions(instruction_data);
1461 Ok(tx)
1462 }
1463
1464 pub fn build_abi_manager_create_meta_external(
1466 fee_payer: TnPubkey,
1467 abi_manager_program: TnPubkey,
1468 abi_meta_account: TnPubkey,
1469 authority_account: TnPubkey,
1470 target_program: TnPubkey,
1471 seed: [u8; 32],
1472 is_ephemeral: bool,
1473 abi_meta_proof: Option<&[u8]>,
1474 fee: u64,
1475 nonce: u64,
1476 start_slot: u64,
1477 ) -> Result<Transaction> {
1478 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
1479 .with_start_slot(start_slot)
1480 .with_expiry_after(10000)
1481 .with_compute_units(500_000_000)
1482 .with_memory_units(5000)
1483 .with_state_units(5000);
1484
1485 let authority_is_fee_payer = authority_account == fee_payer;
1486
1487 let mut rw_accounts = vec![(abi_meta_account, "abi_meta")];
1488 let mut r_accounts = Vec::new();
1489
1490 if !authority_is_fee_payer {
1491 r_accounts.push((authority_account, "authority"));
1492 }
1493
1494 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1495 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1496
1497 let mut accounts = rw_accounts;
1498 accounts.extend(r_accounts);
1499
1500 let mut abi_meta_account_idx = 0u16;
1501 let mut authority_account_idx = 0u16;
1502
1503 for (i, (account, account_type)) in accounts.iter().enumerate() {
1504 let idx = (i + 2) as u16;
1505 match *account_type {
1506 "abi_meta" => {
1507 abi_meta_account_idx = idx;
1508 tx = tx.add_rw_account(*account);
1509 }
1510 "authority" => {
1511 authority_account_idx = idx;
1512 tx = tx.add_r_account(*account);
1513 }
1514 _ => unreachable!(),
1515 }
1516 }
1517
1518 let authority_idx = if authority_is_fee_payer {
1519 0u16
1520 } else {
1521 authority_account_idx
1522 };
1523
1524 let discriminant = if is_ephemeral {
1525 ABI_MANAGER_INSTRUCTION_CREATE_META_EXTERNAL_EPHEMERAL
1526 } else {
1527 ABI_MANAGER_INSTRUCTION_CREATE_META_EXTERNAL_PERMANENT
1528 };
1529
1530 let instruction_data = build_abi_manager_create_meta_external_instruction(
1531 discriminant,
1532 abi_meta_account_idx,
1533 authority_idx,
1534 target_program,
1535 seed,
1536 abi_meta_proof,
1537 )?;
1538
1539 tx = tx.with_instructions(instruction_data);
1540 Ok(tx)
1541 }
1542
1543 #[allow(clippy::too_many_arguments)]
1545 pub fn build_abi_manager_create_abi_official(
1546 fee_payer: TnPubkey,
1547 abi_manager_program: TnPubkey,
1548 abi_meta_account: TnPubkey,
1549 program_meta_account: TnPubkey,
1550 abi_account: TnPubkey,
1551 srcbuf_account: TnPubkey,
1552 authority_account: TnPubkey,
1553 srcbuf_offset: u32,
1554 srcbuf_size: u32,
1555 is_ephemeral: bool,
1556 abi_proof: Option<&[u8]>,
1557 fee: u64,
1558 nonce: u64,
1559 start_slot: u64,
1560 ) -> Result<Transaction> {
1561 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
1562 .with_start_slot(start_slot)
1563 .with_expiry_after(10000)
1564 .with_compute_units(500_000_000)
1565 .with_memory_units(5000)
1566 .with_state_units(5000);
1567
1568 let authority_is_fee_payer = authority_account == fee_payer;
1569
1570 let mut rw_accounts = vec![(abi_account, "abi")];
1571 let mut r_accounts = vec![
1572 (abi_meta_account, "abi_meta"),
1573 (program_meta_account, "program_meta"),
1574 (srcbuf_account, "srcbuf"),
1575 ];
1576
1577 if !authority_is_fee_payer {
1578 r_accounts.push((authority_account, "authority"));
1579 }
1580
1581 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1582 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1583
1584 let mut accounts = rw_accounts;
1585 accounts.extend(r_accounts);
1586
1587 let mut abi_meta_account_idx = 0u16;
1588 let mut program_meta_account_idx = 0u16;
1589 let mut abi_account_idx = 0u16;
1590 let mut srcbuf_account_idx = 0u16;
1591 let mut authority_account_idx = 0u16;
1592
1593 for (i, (account, account_type)) in accounts.iter().enumerate() {
1594 let idx = (i + 2) as u16;
1595 match *account_type {
1596 "abi_meta" => {
1597 abi_meta_account_idx = idx;
1598 tx = tx.add_r_account(*account);
1599 }
1600 "program_meta" => {
1601 program_meta_account_idx = idx;
1602 tx = tx.add_r_account(*account);
1603 }
1604 "abi" => {
1605 abi_account_idx = idx;
1606 tx = tx.add_rw_account(*account);
1607 }
1608 "srcbuf" => {
1609 srcbuf_account_idx = idx;
1610 tx = tx.add_r_account(*account);
1611 }
1612 "authority" => {
1613 authority_account_idx = idx;
1614 tx = tx.add_r_account(*account);
1615 }
1616 _ => unreachable!(),
1617 }
1618 }
1619
1620 let authority_idx = if authority_is_fee_payer {
1621 0u16
1622 } else {
1623 authority_account_idx
1624 };
1625
1626 let discriminant = if is_ephemeral {
1627 ABI_MANAGER_INSTRUCTION_CREATE_ABI_OFFICIAL_EPHEMERAL
1628 } else {
1629 ABI_MANAGER_INSTRUCTION_CREATE_ABI_OFFICIAL_PERMANENT
1630 };
1631
1632 let instruction_data = build_abi_manager_create_abi_official_instruction(
1633 discriminant,
1634 abi_meta_account_idx,
1635 program_meta_account_idx,
1636 abi_account_idx,
1637 srcbuf_account_idx,
1638 srcbuf_offset,
1639 srcbuf_size,
1640 authority_idx,
1641 abi_proof,
1642 )?;
1643
1644 tx = tx.with_instructions(instruction_data);
1645 Ok(tx)
1646 }
1647
1648 #[allow(clippy::too_many_arguments)]
1650 pub fn build_abi_manager_create_abi_external(
1651 fee_payer: TnPubkey,
1652 abi_manager_program: TnPubkey,
1653 abi_meta_account: TnPubkey,
1654 abi_account: TnPubkey,
1655 srcbuf_account: TnPubkey,
1656 authority_account: TnPubkey,
1657 srcbuf_offset: u32,
1658 srcbuf_size: u32,
1659 is_ephemeral: bool,
1660 abi_proof: Option<&[u8]>,
1661 fee: u64,
1662 nonce: u64,
1663 start_slot: u64,
1664 ) -> Result<Transaction> {
1665 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
1666 .with_start_slot(start_slot)
1667 .with_expiry_after(10000)
1668 .with_compute_units(500_000_000)
1669 .with_memory_units(5000)
1670 .with_state_units(5000);
1671
1672 let authority_is_fee_payer = authority_account == fee_payer;
1673
1674 let mut rw_accounts = vec![(abi_account, "abi")];
1675 let mut r_accounts = vec![(abi_meta_account, "abi_meta"), (srcbuf_account, "srcbuf")];
1676
1677 if !authority_is_fee_payer {
1678 r_accounts.push((authority_account, "authority"));
1679 }
1680
1681 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1682 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1683
1684 let mut accounts = rw_accounts;
1685 accounts.extend(r_accounts);
1686
1687 let mut abi_meta_account_idx = 0u16;
1688 let mut abi_account_idx = 0u16;
1689 let mut srcbuf_account_idx = 0u16;
1690 let mut authority_account_idx = 0u16;
1691
1692 for (i, (account, account_type)) in accounts.iter().enumerate() {
1693 let idx = (i + 2) as u16;
1694 match *account_type {
1695 "abi_meta" => {
1696 abi_meta_account_idx = idx;
1697 tx = tx.add_r_account(*account);
1698 }
1699 "abi" => {
1700 abi_account_idx = idx;
1701 tx = tx.add_rw_account(*account);
1702 }
1703 "srcbuf" => {
1704 srcbuf_account_idx = idx;
1705 tx = tx.add_r_account(*account);
1706 }
1707 "authority" => {
1708 authority_account_idx = idx;
1709 tx = tx.add_r_account(*account);
1710 }
1711 _ => unreachable!(),
1712 }
1713 }
1714
1715 let authority_idx = if authority_is_fee_payer {
1716 0u16
1717 } else {
1718 authority_account_idx
1719 };
1720
1721 let discriminant = if is_ephemeral {
1722 ABI_MANAGER_INSTRUCTION_CREATE_ABI_EXTERNAL_EPHEMERAL
1723 } else {
1724 ABI_MANAGER_INSTRUCTION_CREATE_ABI_EXTERNAL_PERMANENT
1725 };
1726
1727 let instruction_data = build_abi_manager_create_abi_external_instruction(
1728 discriminant,
1729 abi_meta_account_idx,
1730 abi_account_idx,
1731 srcbuf_account_idx,
1732 srcbuf_offset,
1733 srcbuf_size,
1734 authority_idx,
1735 abi_proof,
1736 )?;
1737
1738 tx = tx.with_instructions(instruction_data);
1739 Ok(tx)
1740 }
1741
1742 #[allow(clippy::too_many_arguments)]
1744 pub fn build_abi_manager_upgrade_abi_official(
1745 fee_payer: TnPubkey,
1746 abi_manager_program: TnPubkey,
1747 abi_meta_account: TnPubkey,
1748 program_meta_account: TnPubkey,
1749 abi_account: TnPubkey,
1750 srcbuf_account: TnPubkey,
1751 authority_account: TnPubkey,
1752 srcbuf_offset: u32,
1753 srcbuf_size: u32,
1754 fee: u64,
1755 nonce: u64,
1756 start_slot: u64,
1757 ) -> Result<Transaction> {
1758 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
1759 .with_start_slot(start_slot)
1760 .with_expiry_after(10000)
1761 .with_compute_units(500_000_000)
1762 .with_memory_units(5000)
1763 .with_state_units(5000);
1764
1765 let authority_is_fee_payer = authority_account == fee_payer;
1766
1767 let mut rw_accounts = vec![(abi_account, "abi")];
1768 let mut r_accounts = vec![
1769 (abi_meta_account, "abi_meta"),
1770 (program_meta_account, "program_meta"),
1771 (srcbuf_account, "srcbuf"),
1772 ];
1773
1774 if !authority_is_fee_payer {
1775 r_accounts.push((authority_account, "authority"));
1776 }
1777
1778 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1779 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1780
1781 let mut accounts = rw_accounts;
1782 accounts.extend(r_accounts);
1783
1784 let mut abi_meta_account_idx = 0u16;
1785 let mut program_meta_account_idx = 0u16;
1786 let mut abi_account_idx = 0u16;
1787 let mut srcbuf_account_idx = 0u16;
1788 let mut authority_account_idx = 0u16;
1789
1790 for (i, (account, account_type)) in accounts.iter().enumerate() {
1791 let idx = (i + 2) as u16;
1792 match *account_type {
1793 "abi_meta" => {
1794 abi_meta_account_idx = idx;
1795 tx = tx.add_r_account(*account);
1796 }
1797 "program_meta" => {
1798 program_meta_account_idx = idx;
1799 tx = tx.add_r_account(*account);
1800 }
1801 "abi" => {
1802 abi_account_idx = idx;
1803 tx = tx.add_rw_account(*account);
1804 }
1805 "srcbuf" => {
1806 srcbuf_account_idx = idx;
1807 tx = tx.add_r_account(*account);
1808 }
1809 "authority" => {
1810 authority_account_idx = idx;
1811 tx = tx.add_r_account(*account);
1812 }
1813 _ => unreachable!(),
1814 }
1815 }
1816
1817 let authority_idx = if authority_is_fee_payer {
1818 0u16
1819 } else {
1820 authority_account_idx
1821 };
1822
1823 let instruction_data = build_abi_manager_upgrade_abi_official_instruction(
1824 abi_meta_account_idx,
1825 program_meta_account_idx,
1826 abi_account_idx,
1827 srcbuf_account_idx,
1828 srcbuf_offset,
1829 srcbuf_size,
1830 authority_idx,
1831 )?;
1832
1833 tx = tx.with_instructions(instruction_data);
1834 Ok(tx)
1835 }
1836
1837 #[allow(clippy::too_many_arguments)]
1839 pub fn build_abi_manager_upgrade_abi_external(
1840 fee_payer: TnPubkey,
1841 abi_manager_program: TnPubkey,
1842 abi_meta_account: TnPubkey,
1843 abi_account: TnPubkey,
1844 srcbuf_account: TnPubkey,
1845 authority_account: TnPubkey,
1846 srcbuf_offset: u32,
1847 srcbuf_size: u32,
1848 fee: u64,
1849 nonce: u64,
1850 start_slot: u64,
1851 ) -> Result<Transaction> {
1852 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
1853 .with_start_slot(start_slot)
1854 .with_expiry_after(10000)
1855 .with_compute_units(500_000_000)
1856 .with_memory_units(5000)
1857 .with_state_units(5000);
1858
1859 let authority_is_fee_payer = authority_account == fee_payer;
1860
1861 let mut rw_accounts = vec![(abi_account, "abi")];
1862 let mut r_accounts = vec![(abi_meta_account, "abi_meta"), (srcbuf_account, "srcbuf")];
1863
1864 if !authority_is_fee_payer {
1865 r_accounts.push((authority_account, "authority"));
1866 }
1867
1868 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1869 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1870
1871 let mut accounts = rw_accounts;
1872 accounts.extend(r_accounts);
1873
1874 let mut abi_meta_account_idx = 0u16;
1875 let mut abi_account_idx = 0u16;
1876 let mut srcbuf_account_idx = 0u16;
1877 let mut authority_account_idx = 0u16;
1878
1879 for (i, (account, account_type)) in accounts.iter().enumerate() {
1880 let idx = (i + 2) as u16;
1881 match *account_type {
1882 "abi_meta" => {
1883 abi_meta_account_idx = idx;
1884 tx = tx.add_r_account(*account);
1885 }
1886 "abi" => {
1887 abi_account_idx = idx;
1888 tx = tx.add_rw_account(*account);
1889 }
1890 "srcbuf" => {
1891 srcbuf_account_idx = idx;
1892 tx = tx.add_r_account(*account);
1893 }
1894 "authority" => {
1895 authority_account_idx = idx;
1896 tx = tx.add_r_account(*account);
1897 }
1898 _ => unreachable!(),
1899 }
1900 }
1901
1902 let authority_idx = if authority_is_fee_payer {
1903 0u16
1904 } else {
1905 authority_account_idx
1906 };
1907
1908 let instruction_data = build_abi_manager_upgrade_abi_external_instruction(
1909 abi_meta_account_idx,
1910 abi_account_idx,
1911 srcbuf_account_idx,
1912 srcbuf_offset,
1913 srcbuf_size,
1914 authority_idx,
1915 )?;
1916
1917 tx = tx.with_instructions(instruction_data);
1918 Ok(tx)
1919 }
1920
1921 pub fn build_abi_manager_finalize_abi_official(
1923 fee_payer: TnPubkey,
1924 abi_manager_program: TnPubkey,
1925 abi_meta_account: TnPubkey,
1926 program_meta_account: TnPubkey,
1927 abi_account: TnPubkey,
1928 authority_account: TnPubkey,
1929 fee: u64,
1930 nonce: u64,
1931 start_slot: u64,
1932 ) -> Result<Transaction> {
1933 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
1934 .with_start_slot(start_slot)
1935 .with_expiry_after(10000)
1936 .with_compute_units(500_000_000)
1937 .with_memory_units(5000)
1938 .with_state_units(5000);
1939
1940 let authority_is_fee_payer = authority_account == fee_payer;
1941
1942 let mut rw_accounts = vec![(abi_account, "abi")];
1943 let mut r_accounts = vec![(abi_meta_account, "abi_meta"), (program_meta_account, "program_meta")];
1944
1945 if !authority_is_fee_payer {
1946 r_accounts.push((authority_account, "authority"));
1947 }
1948
1949 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1950 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
1951
1952 let mut accounts = rw_accounts;
1953 accounts.extend(r_accounts);
1954
1955 let mut abi_meta_account_idx = 0u16;
1956 let mut program_meta_account_idx = 0u16;
1957 let mut abi_account_idx = 0u16;
1958 let mut authority_account_idx = 0u16;
1959
1960 for (i, (account, account_type)) in accounts.iter().enumerate() {
1961 let idx = (i + 2) as u16;
1962 match *account_type {
1963 "abi_meta" => {
1964 abi_meta_account_idx = idx;
1965 tx = tx.add_r_account(*account);
1966 }
1967 "program_meta" => {
1968 program_meta_account_idx = idx;
1969 tx = tx.add_r_account(*account);
1970 }
1971 "abi" => {
1972 abi_account_idx = idx;
1973 tx = tx.add_rw_account(*account);
1974 }
1975 "authority" => {
1976 authority_account_idx = idx;
1977 tx = tx.add_r_account(*account);
1978 }
1979 _ => unreachable!(),
1980 }
1981 }
1982
1983 let authority_idx = if authority_is_fee_payer {
1984 0u16
1985 } else {
1986 authority_account_idx
1987 };
1988
1989 let instruction_data = build_abi_manager_finalize_abi_official_instruction(
1990 abi_meta_account_idx,
1991 program_meta_account_idx,
1992 abi_account_idx,
1993 authority_idx,
1994 )?;
1995
1996 tx = tx.with_instructions(instruction_data);
1997 Ok(tx)
1998 }
1999
2000 pub fn build_abi_manager_finalize_abi_external(
2002 fee_payer: TnPubkey,
2003 abi_manager_program: TnPubkey,
2004 abi_meta_account: TnPubkey,
2005 abi_account: TnPubkey,
2006 authority_account: TnPubkey,
2007 fee: u64,
2008 nonce: u64,
2009 start_slot: u64,
2010 ) -> Result<Transaction> {
2011 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
2012 .with_start_slot(start_slot)
2013 .with_expiry_after(10000)
2014 .with_compute_units(500_000_000)
2015 .with_memory_units(5000)
2016 .with_state_units(5000);
2017
2018 let authority_is_fee_payer = authority_account == fee_payer;
2019
2020 let mut rw_accounts = vec![(abi_account, "abi")];
2021 let mut r_accounts = vec![(abi_meta_account, "abi_meta")];
2022
2023 if !authority_is_fee_payer {
2024 r_accounts.push((authority_account, "authority"));
2025 }
2026
2027 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2028 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2029
2030 let mut accounts = rw_accounts;
2031 accounts.extend(r_accounts);
2032
2033 let mut abi_meta_account_idx = 0u16;
2034 let mut abi_account_idx = 0u16;
2035 let mut authority_account_idx = 0u16;
2036
2037 for (i, (account, account_type)) in accounts.iter().enumerate() {
2038 let idx = (i + 2) as u16;
2039 match *account_type {
2040 "abi_meta" => {
2041 abi_meta_account_idx = idx;
2042 tx = tx.add_r_account(*account);
2043 }
2044 "abi" => {
2045 abi_account_idx = idx;
2046 tx = tx.add_rw_account(*account);
2047 }
2048 "authority" => {
2049 authority_account_idx = idx;
2050 tx = tx.add_r_account(*account);
2051 }
2052 _ => unreachable!(),
2053 }
2054 }
2055
2056 let authority_idx = if authority_is_fee_payer {
2057 0u16
2058 } else {
2059 authority_account_idx
2060 };
2061
2062 let instruction_data = build_abi_manager_finalize_abi_external_instruction(
2063 abi_meta_account_idx,
2064 abi_account_idx,
2065 authority_idx,
2066 )?;
2067
2068 tx = tx.with_instructions(instruction_data);
2069 Ok(tx)
2070 }
2071
2072 pub fn build_abi_manager_close_abi_official(
2074 fee_payer: TnPubkey,
2075 abi_manager_program: TnPubkey,
2076 abi_meta_account: TnPubkey,
2077 program_meta_account: TnPubkey,
2078 abi_account: TnPubkey,
2079 authority_account: TnPubkey,
2080 fee: u64,
2081 nonce: u64,
2082 start_slot: u64,
2083 ) -> Result<Transaction> {
2084 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
2085 .with_start_slot(start_slot)
2086 .with_expiry_after(10000)
2087 .with_compute_units(500_000_000)
2088 .with_memory_units(5000)
2089 .with_state_units(5000);
2090
2091 let authority_is_fee_payer = authority_account == fee_payer;
2092
2093 let mut rw_accounts = vec![(abi_account, "abi")];
2094 let mut r_accounts = vec![(abi_meta_account, "abi_meta"), (program_meta_account, "program_meta")];
2095
2096 if !authority_is_fee_payer {
2097 r_accounts.push((authority_account, "authority"));
2098 }
2099
2100 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2101 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2102
2103 let mut accounts = rw_accounts;
2104 accounts.extend(r_accounts);
2105
2106 let mut abi_meta_account_idx = 0u16;
2107 let mut program_meta_account_idx = 0u16;
2108 let mut abi_account_idx = 0u16;
2109 let mut authority_account_idx = 0u16;
2110
2111 for (i, (account, account_type)) in accounts.iter().enumerate() {
2112 let idx = (i + 2) as u16;
2113 match *account_type {
2114 "abi_meta" => {
2115 abi_meta_account_idx = idx;
2116 tx = tx.add_r_account(*account);
2117 }
2118 "program_meta" => {
2119 program_meta_account_idx = idx;
2120 tx = tx.add_r_account(*account);
2121 }
2122 "abi" => {
2123 abi_account_idx = idx;
2124 tx = tx.add_rw_account(*account);
2125 }
2126 "authority" => {
2127 authority_account_idx = idx;
2128 tx = tx.add_r_account(*account);
2129 }
2130 _ => unreachable!(),
2131 }
2132 }
2133
2134 let authority_idx = if authority_is_fee_payer {
2135 0u16
2136 } else {
2137 authority_account_idx
2138 };
2139
2140 let instruction_data = build_abi_manager_close_abi_official_instruction(
2141 abi_meta_account_idx,
2142 program_meta_account_idx,
2143 abi_account_idx,
2144 authority_idx,
2145 )?;
2146
2147 tx = tx.with_instructions(instruction_data);
2148 Ok(tx)
2149 }
2150
2151 pub fn build_abi_manager_close_abi_external(
2153 fee_payer: TnPubkey,
2154 abi_manager_program: TnPubkey,
2155 abi_meta_account: TnPubkey,
2156 abi_account: TnPubkey,
2157 authority_account: TnPubkey,
2158 fee: u64,
2159 nonce: u64,
2160 start_slot: u64,
2161 ) -> Result<Transaction> {
2162 let mut tx = Transaction::new(fee_payer, abi_manager_program, fee, nonce)
2163 .with_start_slot(start_slot)
2164 .with_expiry_after(10000)
2165 .with_compute_units(500_000_000)
2166 .with_memory_units(5000)
2167 .with_state_units(5000);
2168
2169 let authority_is_fee_payer = authority_account == fee_payer;
2170
2171 let mut rw_accounts = vec![(abi_account, "abi")];
2172 let mut r_accounts = vec![(abi_meta_account, "abi_meta")];
2173
2174 if !authority_is_fee_payer {
2175 r_accounts.push((authority_account, "authority"));
2176 }
2177
2178 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2179 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2180
2181 let mut accounts = rw_accounts;
2182 accounts.extend(r_accounts);
2183
2184 let mut abi_meta_account_idx = 0u16;
2185 let mut abi_account_idx = 0u16;
2186 let mut authority_account_idx = 0u16;
2187
2188 for (i, (account, account_type)) in accounts.iter().enumerate() {
2189 let idx = (i + 2) as u16;
2190 match *account_type {
2191 "abi_meta" => {
2192 abi_meta_account_idx = idx;
2193 tx = tx.add_r_account(*account);
2194 }
2195 "abi" => {
2196 abi_account_idx = idx;
2197 tx = tx.add_rw_account(*account);
2198 }
2199 "authority" => {
2200 authority_account_idx = idx;
2201 tx = tx.add_r_account(*account);
2202 }
2203 _ => unreachable!(),
2204 }
2205 }
2206
2207 let authority_idx = if authority_is_fee_payer {
2208 0u16
2209 } else {
2210 authority_account_idx
2211 };
2212
2213 let instruction_data = build_abi_manager_close_abi_external_instruction(
2214 abi_meta_account_idx,
2215 abi_account_idx,
2216 authority_idx,
2217 )?;
2218
2219 tx = tx.with_instructions(instruction_data);
2220 Ok(tx)
2221 }
2222
2223 pub fn build_manager_upgrade(
2225 fee_payer: TnPubkey,
2226 manager_program: TnPubkey,
2227 meta_account: TnPubkey,
2228 program_account: TnPubkey,
2229 srcbuf_account: TnPubkey,
2230 srcbuf_offset: u32,
2231 srcbuf_size: u32,
2232 fee: u64,
2233 nonce: u64,
2234 start_slot: u64,
2235 ) -> Result<Transaction> {
2236 let mut tx = Transaction::new(fee_payer, manager_program, fee, nonce)
2237 .with_start_slot(start_slot)
2238 .with_expiry_after(10000)
2239 .with_compute_units(500_000_000)
2240 .with_memory_units(5000)
2241 .with_state_units(5000);
2242
2243 let mut rw_accounts = vec![(meta_account, "meta"), (program_account, "program")];
2245
2246 let mut r_accounts = vec![(srcbuf_account, "srcbuf")];
2247
2248 rw_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2250
2251 r_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2253
2254 let mut accounts = rw_accounts;
2256 accounts.extend(r_accounts);
2257
2258 let mut meta_account_idx = 0u16;
2259 let mut program_account_idx = 0u16;
2260 let mut srcbuf_account_idx = 0u16;
2261
2262 for (i, (account, account_type)) in accounts.iter().enumerate() {
2263 let idx = (i + 2) as u16; match *account_type {
2265 "meta" => {
2266 meta_account_idx = idx;
2267 tx = tx.add_rw_account(*account);
2268 }
2269 "program" => {
2270 program_account_idx = idx;
2271 tx = tx.add_rw_account(*account);
2272 }
2273 "srcbuf" => {
2274 srcbuf_account_idx = idx;
2275 tx = tx.add_r_account(*account);
2276 }
2277 _ => unreachable!(),
2278 }
2279 }
2280
2281 let instruction_data = build_manager_upgrade_instruction(
2282 meta_account_idx,
2283 program_account_idx,
2284 srcbuf_account_idx,
2285 srcbuf_offset,
2286 srcbuf_size,
2287 )?;
2288
2289 tx = tx.with_instructions(instruction_data);
2290 Ok(tx)
2291 }
2292
2293 pub fn build_manager_set_pause(
2295 fee_payer: TnPubkey,
2296 manager_program: TnPubkey,
2297 meta_account: TnPubkey,
2298 program_account: TnPubkey,
2299 is_paused: bool,
2300 fee: u64,
2301 nonce: u64,
2302 start_slot: u64,
2303 ) -> Result<Transaction> {
2304 let mut tx = Transaction::new(fee_payer, manager_program, fee, nonce)
2305 .with_start_slot(start_slot)
2306 .with_expiry_after(10000)
2307 .with_compute_units(100_000_000)
2308 .with_memory_units(5000)
2309 .with_state_units(5000);
2310
2311 let mut accounts = vec![(meta_account, "meta"), (program_account, "program")];
2313 accounts.sort_by(|a, b| a.0.cmp(&b.0));
2314
2315 let mut meta_account_idx = 0u16;
2316 let mut program_account_idx = 0u16;
2317
2318 for (i, (account, account_type)) in accounts.iter().enumerate() {
2319 let idx = (i + 2) as u16;
2320 match *account_type {
2321 "meta" => {
2322 meta_account_idx = idx;
2323 tx = tx.add_rw_account(*account);
2324 }
2325 "program" => {
2326 program_account_idx = idx;
2327 tx = tx.add_rw_account(*account);
2328 }
2329 _ => unreachable!(),
2330 }
2331 }
2332
2333 let instruction_data =
2334 build_manager_set_pause_instruction(meta_account_idx, program_account_idx, is_paused)?;
2335
2336 tx = tx.with_instructions(instruction_data);
2337 Ok(tx)
2338 }
2339
2340 pub fn build_manager_simple(
2342 fee_payer: TnPubkey,
2343 manager_program: TnPubkey,
2344 meta_account: TnPubkey,
2345 program_account: TnPubkey,
2346 instruction_type: u8,
2347 fee: u64,
2348 nonce: u64,
2349 start_slot: u64,
2350 ) -> Result<Transaction> {
2351 let mut tx = Transaction::new(fee_payer, manager_program, fee, nonce)
2352 .with_start_slot(start_slot)
2353 .with_expiry_after(10000)
2354 .with_compute_units(100_000_000)
2355 .with_memory_units(5000)
2356 .with_state_units(5000);
2357
2358 let mut accounts = vec![(meta_account, "meta"), (program_account, "program")];
2360 accounts.sort_by(|a, b| a.0.cmp(&b.0));
2361
2362 let mut meta_account_idx = 0u16;
2363 let mut program_account_idx = 0u16;
2364
2365 for (i, (account, account_type)) in accounts.iter().enumerate() {
2366 let idx = (i + 2) as u16;
2367 match *account_type {
2368 "meta" => {
2369 meta_account_idx = idx;
2370 tx = tx.add_rw_account(*account);
2371 }
2372 "program" => {
2373 program_account_idx = idx;
2374 tx = tx.add_rw_account(*account);
2375 }
2376 _ => unreachable!(),
2377 }
2378 }
2379
2380 let instruction_data = build_manager_header_instruction(
2381 instruction_type,
2382 meta_account_idx,
2383 program_account_idx,
2384 )?;
2385
2386 tx = tx.with_instructions(instruction_data);
2387 Ok(tx)
2388 }
2389
2390 pub fn build_manager_set_authority(
2392 fee_payer: TnPubkey,
2393 manager_program: TnPubkey,
2394 meta_account: TnPubkey,
2395 program_account: TnPubkey,
2396 authority_candidate: [u8; 32],
2397 fee: u64,
2398 nonce: u64,
2399 start_slot: u64,
2400 ) -> Result<Transaction> {
2401 let mut tx = Transaction::new(fee_payer, manager_program, fee, nonce)
2402 .with_start_slot(start_slot)
2403 .with_expiry_after(10000)
2404 .with_compute_units(100_000_000)
2405 .with_memory_units(5000)
2406 .with_state_units(5000);
2407
2408 let mut accounts = vec![(meta_account, "meta"), (program_account, "program")];
2410 accounts.sort_by(|a, b| a.0.cmp(&b.0));
2411
2412 let mut meta_account_idx = 0u16;
2413 let mut program_account_idx = 0u16;
2414
2415 for (i, (account, account_type)) in accounts.iter().enumerate() {
2416 let idx = (i + 2) as u16;
2417 match *account_type {
2418 "meta" => {
2419 meta_account_idx = idx;
2420 tx = tx.add_rw_account(*account);
2421 }
2422 "program" => {
2423 program_account_idx = idx;
2424 tx = tx.add_rw_account(*account);
2425 }
2426 _ => unreachable!(),
2427 }
2428 }
2429
2430 let instruction_data = build_manager_set_authority_instruction(
2431 meta_account_idx,
2432 program_account_idx,
2433 authority_candidate,
2434 )?;
2435
2436 tx = tx.with_instructions(instruction_data);
2437 Ok(tx)
2438 }
2439
2440 pub fn build_test_uploader_create(
2442 fee_payer: TnPubkey,
2443 test_uploader_program: TnPubkey,
2444 target_account: TnPubkey,
2445 account_sz: u32,
2446 seed: &[u8],
2447 is_ephemeral: bool,
2448 state_proof: Option<&[u8]>,
2449 fee: u64,
2450 nonce: u64,
2451 start_slot: u64,
2452 ) -> Result<Transaction> {
2453 let target_account_idx = 2u16;
2455
2456 let tx = Transaction::new(fee_payer, test_uploader_program, fee, nonce)
2457 .with_start_slot(start_slot)
2458 .with_expiry_after(100)
2459 .with_compute_units(100_000 + account_sz)
2460 .with_memory_units(10_000)
2461 .with_state_units(10_000)
2462 .add_rw_account(target_account);
2463
2464 let instruction_data = build_test_uploader_create_instruction(
2465 target_account_idx,
2466 account_sz,
2467 seed,
2468 is_ephemeral,
2469 state_proof,
2470 )?;
2471
2472 let tx = tx.with_instructions(instruction_data);
2473 Ok(tx)
2474 }
2475
2476 pub fn build_test_uploader_write(
2478 fee_payer: TnPubkey,
2479 test_uploader_program: TnPubkey,
2480 target_account: TnPubkey,
2481 offset: u32,
2482 data: &[u8],
2483 fee: u64,
2484 nonce: u64,
2485 start_slot: u64,
2486 ) -> Result<Transaction> {
2487 let target_account_idx = 2u16;
2489
2490 let tx = Transaction::new(fee_payer, test_uploader_program, fee, nonce)
2491 .with_start_slot(start_slot)
2492 .with_expiry_after(10_000)
2493 .with_compute_units(100_000 + 18 * data.len() as u32)
2494 .with_memory_units(10_000)
2495 .with_state_units(10_000)
2496 .add_rw_account(target_account);
2497
2498 let instruction_data =
2499 build_test_uploader_write_instruction(target_account_idx, offset, data)?;
2500
2501 let tx = tx.with_instructions(instruction_data);
2502 Ok(tx)
2503 }
2504
2505 pub fn build_decompress2(
2507 fee_payer: TnPubkey,
2508 program: TnPubkey,
2509 target_account: TnPubkey,
2510 meta_account: TnPubkey,
2511 data_account: TnPubkey,
2512 data_offset: u32,
2513 state_proof: &[u8],
2514 fee: u64,
2515 nonce: u64,
2516 start_slot: u64,
2517 data_sz: u32,
2518 ) -> Result<Transaction> {
2519 let mut tx = Transaction::new(fee_payer, program, fee, nonce)
2521 .with_start_slot(start_slot)
2522 .with_expiry_after(100)
2523 .with_compute_units(10_000 + 2 * data_sz)
2524 .with_memory_units(10_000)
2525 .with_state_units(10);
2526
2527 let target_account_idx = 2u16;
2529 tx = tx.add_rw_account(target_account);
2530
2531 let mut meta_account_idx = 0u16;
2532 let mut data_account_idx = 0u16;
2533
2534 if meta_account == data_account {
2536 let account_idx = 3u16;
2538 meta_account_idx = account_idx;
2539 data_account_idx = account_idx;
2540 tx = tx.add_r_account(meta_account);
2541 } else {
2542 let mut read_accounts = vec![(meta_account, "meta"), (data_account, "data")];
2544 read_accounts.sort_by(|a, b| a.0.cmp(&b.0));
2545
2546 for (i, (account, account_type)) in read_accounts.iter().enumerate() {
2547 let idx = (3 + i) as u16; match *account_type {
2549 "meta" => {
2550 meta_account_idx = idx;
2551 tx = tx.add_r_account(*account);
2552 }
2553 "data" => {
2554 data_account_idx = idx;
2555 tx = tx.add_r_account(*account);
2556 }
2557 _ => unreachable!(),
2558 }
2559 }
2560 }
2561
2562 let instruction_data = build_decompress2_instruction(
2563 target_account_idx,
2564 meta_account_idx,
2565 data_account_idx,
2566 data_offset,
2567 state_proof,
2568 )?;
2569
2570 tx = tx.with_instructions(instruction_data);
2571 Ok(tx)
2572 }
2573}
2574
2575fn build_uploader_create_instruction(
2577 buffer_account_idx: u16,
2578 meta_account_idx: u16,
2579 authority_account_idx: u16,
2580 buffer_size: u32,
2581 expected_hash: [u8; 32],
2582 seed: &[u8],
2583) -> Result<Vec<u8>> {
2584 let mut instruction = Vec::new();
2585
2586 instruction.extend_from_slice(&TN_UPLOADER_PROGRAM_INSTRUCTION_CREATE.to_le_bytes());
2588
2589 let args = UploaderCreateArgs {
2591 buffer_account_idx,
2592 meta_account_idx,
2593 authority_account_idx,
2594 buffer_account_sz: buffer_size,
2595 expected_account_hash: expected_hash,
2596 seed_len: seed.len() as u32,
2597 };
2598
2599 let args_bytes = unsafe {
2601 std::slice::from_raw_parts(
2602 &args as *const _ as *const u8,
2603 std::mem::size_of::<UploaderCreateArgs>(),
2604 )
2605 };
2606 instruction.extend_from_slice(args_bytes);
2607
2608 instruction.extend_from_slice(seed);
2610
2611 Ok(instruction)
2612}
2613
2614fn build_uploader_write_instruction(
2616 buffer_account_idx: u16,
2617 meta_account_idx: u16,
2618 data: &[u8],
2619 offset: u32,
2620) -> Result<Vec<u8>> {
2621 let mut instruction = Vec::new();
2622
2623 instruction.extend_from_slice(&TN_UPLOADER_PROGRAM_INSTRUCTION_WRITE.to_le_bytes());
2625
2626 let args = UploaderWriteArgs {
2628 buffer_account_idx,
2629 meta_account_idx,
2630 data_len: data.len() as u32,
2631 data_offset: offset,
2632 };
2633
2634 let args_bytes = unsafe {
2636 std::slice::from_raw_parts(
2637 &args as *const _ as *const u8,
2638 std::mem::size_of::<UploaderWriteArgs>(),
2639 )
2640 };
2641 instruction.extend_from_slice(args_bytes);
2642
2643 instruction.extend_from_slice(data);
2645
2646 Ok(instruction)
2647}
2648
2649fn build_uploader_finalize_instruction(
2651 buffer_account_idx: u16,
2652 meta_account_idx: u16,
2653 expected_hash: [u8; 32],
2654) -> Result<Vec<u8>> {
2655 let mut instruction = Vec::new();
2656
2657 instruction.extend_from_slice(&TN_UPLOADER_PROGRAM_INSTRUCTION_FINALIZE.to_le_bytes());
2659
2660 let args = UploaderFinalizeArgs {
2662 buffer_account_idx,
2663 meta_account_idx,
2664 expected_account_hash: expected_hash,
2665 };
2666
2667 let args_bytes = unsafe {
2669 std::slice::from_raw_parts(
2670 &args as *const _ as *const u8,
2671 std::mem::size_of::<UploaderFinalizeArgs>(),
2672 )
2673 };
2674 instruction.extend_from_slice(args_bytes);
2675
2676 Ok(instruction)
2677}
2678
2679fn build_uploader_destroy_instruction(
2681 buffer_account_idx: u16,
2682 meta_account_idx: u16,
2683) -> Result<Vec<u8>> {
2684 let mut instruction = Vec::new();
2685
2686 instruction.extend_from_slice(&TN_UPLOADER_PROGRAM_INSTRUCTION_DESTROY.to_le_bytes());
2688
2689 let args = UploaderDestroyArgs {
2691 buffer_account_idx,
2692 meta_account_idx,
2693 };
2694
2695 let args_bytes = unsafe {
2697 std::slice::from_raw_parts(
2698 &args as *const _ as *const u8,
2699 std::mem::size_of::<UploaderDestroyArgs>(),
2700 )
2701 };
2702 instruction.extend_from_slice(args_bytes);
2703
2704 Ok(instruction)
2705}
2706
2707fn build_manager_create_instruction(
2709 discriminant: u8,
2710 meta_account_idx: u16,
2711 program_account_idx: u16,
2712 srcbuf_account_idx: u16,
2713 authority_account_idx: u16,
2714 srcbuf_offset: u32,
2715 srcbuf_size: u32,
2716 seed: &[u8],
2717 proof: Option<&[u8]>,
2718) -> Result<Vec<u8>> {
2719 let mut instruction = Vec::new();
2720
2721 let args = ManagerCreateArgs {
2723 discriminant,
2724 meta_account_idx,
2725 program_account_idx,
2726 srcbuf_account_idx,
2727 srcbuf_offset,
2728 srcbuf_size,
2729 authority_account_idx,
2730 seed_len: seed.len() as u32,
2731 };
2732
2733 let args_bytes = unsafe {
2735 std::slice::from_raw_parts(
2736 &args as *const ManagerCreateArgs as *const u8,
2737 std::mem::size_of::<ManagerCreateArgs>(),
2738 )
2739 };
2740 instruction.extend_from_slice(args_bytes);
2741
2742 instruction.extend_from_slice(seed);
2744
2745 if let Some(proof_bytes) = proof {
2747 instruction.extend_from_slice(proof_bytes);
2748 }
2749
2750 Ok(instruction)
2751}
2752
2753fn build_abi_manager_create_meta_official_instruction(
2755 discriminant: u8,
2756 abi_meta_account_idx: u16,
2757 program_meta_account_idx: u16,
2758 authority_account_idx: u16,
2759 proof: Option<&[u8]>,
2760) -> Result<Vec<u8>> {
2761 let mut instruction = Vec::new();
2762 instruction.push(discriminant);
2763
2764 let args = AbiManagerCreateMetaOfficialArgs {
2765 abi_meta_account_idx,
2766 program_meta_account_idx,
2767 authority_account_idx,
2768 };
2769
2770 let args_bytes = unsafe {
2771 std::slice::from_raw_parts(
2772 &args as *const AbiManagerCreateMetaOfficialArgs as *const u8,
2773 std::mem::size_of::<AbiManagerCreateMetaOfficialArgs>(),
2774 )
2775 };
2776
2777 instruction.extend_from_slice(args_bytes);
2778 if let Some(proof_bytes) = proof {
2779 instruction.extend_from_slice(proof_bytes);
2780 }
2781
2782 Ok(instruction)
2783}
2784
2785fn build_abi_manager_create_meta_external_instruction(
2787 discriminant: u8,
2788 abi_meta_account_idx: u16,
2789 authority_account_idx: u16,
2790 target_program: TnPubkey,
2791 seed: [u8; 32],
2792 proof: Option<&[u8]>,
2793) -> Result<Vec<u8>> {
2794 let mut instruction = Vec::new();
2795 instruction.push(discriminant);
2796
2797 let args = AbiManagerCreateMetaExternalArgs {
2798 abi_meta_account_idx,
2799 authority_account_idx,
2800 target_program,
2801 seed,
2802 };
2803
2804 let args_bytes = unsafe {
2805 std::slice::from_raw_parts(
2806 &args as *const AbiManagerCreateMetaExternalArgs as *const u8,
2807 std::mem::size_of::<AbiManagerCreateMetaExternalArgs>(),
2808 )
2809 };
2810
2811 instruction.extend_from_slice(args_bytes);
2812 if let Some(proof_bytes) = proof {
2813 instruction.extend_from_slice(proof_bytes);
2814 }
2815
2816 Ok(instruction)
2817}
2818
2819fn build_abi_manager_create_abi_official_instruction(
2821 discriminant: u8,
2822 abi_meta_account_idx: u16,
2823 program_meta_account_idx: u16,
2824 abi_account_idx: u16,
2825 srcbuf_account_idx: u16,
2826 srcbuf_offset: u32,
2827 srcbuf_size: u32,
2828 authority_account_idx: u16,
2829 proof: Option<&[u8]>,
2830) -> Result<Vec<u8>> {
2831 let mut instruction = Vec::new();
2832 instruction.push(discriminant);
2833
2834 let args = AbiManagerCreateAbiOfficialArgs {
2835 abi_meta_account_idx,
2836 program_meta_account_idx,
2837 abi_account_idx,
2838 srcbuf_account_idx,
2839 srcbuf_offset,
2840 srcbuf_size,
2841 authority_account_idx,
2842 };
2843
2844 let args_bytes = unsafe {
2845 std::slice::from_raw_parts(
2846 &args as *const AbiManagerCreateAbiOfficialArgs as *const u8,
2847 std::mem::size_of::<AbiManagerCreateAbiOfficialArgs>(),
2848 )
2849 };
2850
2851 instruction.extend_from_slice(args_bytes);
2852 if let Some(proof_bytes) = proof {
2853 instruction.extend_from_slice(proof_bytes);
2854 }
2855
2856 Ok(instruction)
2857}
2858
2859fn build_abi_manager_create_abi_external_instruction(
2861 discriminant: u8,
2862 abi_meta_account_idx: u16,
2863 abi_account_idx: u16,
2864 srcbuf_account_idx: u16,
2865 srcbuf_offset: u32,
2866 srcbuf_size: u32,
2867 authority_account_idx: u16,
2868 proof: Option<&[u8]>,
2869) -> Result<Vec<u8>> {
2870 let mut instruction = Vec::new();
2871 instruction.push(discriminant);
2872
2873 let args = AbiManagerCreateAbiExternalArgs {
2874 abi_meta_account_idx,
2875 abi_account_idx,
2876 srcbuf_account_idx,
2877 srcbuf_offset,
2878 srcbuf_size,
2879 authority_account_idx,
2880 };
2881
2882 let args_bytes = unsafe {
2883 std::slice::from_raw_parts(
2884 &args as *const AbiManagerCreateAbiExternalArgs as *const u8,
2885 std::mem::size_of::<AbiManagerCreateAbiExternalArgs>(),
2886 )
2887 };
2888
2889 instruction.extend_from_slice(args_bytes);
2890 if let Some(proof_bytes) = proof {
2891 instruction.extend_from_slice(proof_bytes);
2892 }
2893
2894 Ok(instruction)
2895}
2896
2897fn build_abi_manager_upgrade_abi_official_instruction(
2898 abi_meta_account_idx: u16,
2899 program_meta_account_idx: u16,
2900 abi_account_idx: u16,
2901 srcbuf_account_idx: u16,
2902 srcbuf_offset: u32,
2903 srcbuf_size: u32,
2904 authority_account_idx: u16,
2905) -> Result<Vec<u8>> {
2906 let mut instruction = Vec::new();
2907 instruction.push(ABI_MANAGER_INSTRUCTION_UPGRADE_ABI_OFFICIAL);
2908
2909 let args = AbiManagerUpgradeAbiOfficialArgs {
2910 abi_meta_account_idx,
2911 program_meta_account_idx,
2912 abi_account_idx,
2913 srcbuf_account_idx,
2914 srcbuf_offset,
2915 srcbuf_size,
2916 authority_account_idx,
2917 };
2918
2919 let args_bytes = unsafe {
2920 std::slice::from_raw_parts(
2921 &args as *const AbiManagerUpgradeAbiOfficialArgs as *const u8,
2922 std::mem::size_of::<AbiManagerUpgradeAbiOfficialArgs>(),
2923 )
2924 };
2925
2926 instruction.extend_from_slice(args_bytes);
2927 Ok(instruction)
2928}
2929
2930fn build_abi_manager_upgrade_abi_external_instruction(
2931 abi_meta_account_idx: u16,
2932 abi_account_idx: u16,
2933 srcbuf_account_idx: u16,
2934 srcbuf_offset: u32,
2935 srcbuf_size: u32,
2936 authority_account_idx: u16,
2937) -> Result<Vec<u8>> {
2938 let mut instruction = Vec::new();
2939 instruction.push(ABI_MANAGER_INSTRUCTION_UPGRADE_ABI_EXTERNAL);
2940
2941 let args = AbiManagerUpgradeAbiExternalArgs {
2942 abi_meta_account_idx,
2943 abi_account_idx,
2944 srcbuf_account_idx,
2945 srcbuf_offset,
2946 srcbuf_size,
2947 authority_account_idx,
2948 };
2949
2950 let args_bytes = unsafe {
2951 std::slice::from_raw_parts(
2952 &args as *const AbiManagerUpgradeAbiExternalArgs as *const u8,
2953 std::mem::size_of::<AbiManagerUpgradeAbiExternalArgs>(),
2954 )
2955 };
2956
2957 instruction.extend_from_slice(args_bytes);
2958 Ok(instruction)
2959}
2960
2961fn build_abi_manager_finalize_abi_official_instruction(
2962 abi_meta_account_idx: u16,
2963 program_meta_account_idx: u16,
2964 abi_account_idx: u16,
2965 authority_account_idx: u16,
2966) -> Result<Vec<u8>> {
2967 let mut instruction = Vec::new();
2968 instruction.push(ABI_MANAGER_INSTRUCTION_FINALIZE_ABI_OFFICIAL);
2969
2970 let args = AbiManagerFinalizeAbiOfficialArgs {
2971 abi_meta_account_idx,
2972 program_meta_account_idx,
2973 abi_account_idx,
2974 authority_account_idx,
2975 };
2976
2977 let args_bytes = unsafe {
2978 std::slice::from_raw_parts(
2979 &args as *const AbiManagerFinalizeAbiOfficialArgs as *const u8,
2980 std::mem::size_of::<AbiManagerFinalizeAbiOfficialArgs>(),
2981 )
2982 };
2983
2984 instruction.extend_from_slice(args_bytes);
2985 Ok(instruction)
2986}
2987
2988fn build_abi_manager_finalize_abi_external_instruction(
2989 abi_meta_account_idx: u16,
2990 abi_account_idx: u16,
2991 authority_account_idx: u16,
2992) -> Result<Vec<u8>> {
2993 let mut instruction = Vec::new();
2994 instruction.push(ABI_MANAGER_INSTRUCTION_FINALIZE_ABI_EXTERNAL);
2995
2996 let args = AbiManagerFinalizeAbiExternalArgs {
2997 abi_meta_account_idx,
2998 abi_account_idx,
2999 authority_account_idx,
3000 };
3001
3002 let args_bytes = unsafe {
3003 std::slice::from_raw_parts(
3004 &args as *const AbiManagerFinalizeAbiExternalArgs as *const u8,
3005 std::mem::size_of::<AbiManagerFinalizeAbiExternalArgs>(),
3006 )
3007 };
3008
3009 instruction.extend_from_slice(args_bytes);
3010 Ok(instruction)
3011}
3012
3013fn build_abi_manager_close_abi_official_instruction(
3014 abi_meta_account_idx: u16,
3015 program_meta_account_idx: u16,
3016 abi_account_idx: u16,
3017 authority_account_idx: u16,
3018) -> Result<Vec<u8>> {
3019 let mut instruction = Vec::new();
3020 instruction.push(ABI_MANAGER_INSTRUCTION_CLOSE_ABI_OFFICIAL);
3021
3022 let args = AbiManagerCloseAbiOfficialArgs {
3023 abi_meta_account_idx,
3024 program_meta_account_idx,
3025 abi_account_idx,
3026 authority_account_idx,
3027 };
3028
3029 let args_bytes = unsafe {
3030 std::slice::from_raw_parts(
3031 &args as *const AbiManagerCloseAbiOfficialArgs as *const u8,
3032 std::mem::size_of::<AbiManagerCloseAbiOfficialArgs>(),
3033 )
3034 };
3035
3036 instruction.extend_from_slice(args_bytes);
3037 Ok(instruction)
3038}
3039
3040fn build_abi_manager_close_abi_external_instruction(
3041 abi_meta_account_idx: u16,
3042 abi_account_idx: u16,
3043 authority_account_idx: u16,
3044) -> Result<Vec<u8>> {
3045 let mut instruction = Vec::new();
3046 instruction.push(ABI_MANAGER_INSTRUCTION_CLOSE_ABI_EXTERNAL);
3047
3048 let args = AbiManagerCloseAbiExternalArgs {
3049 abi_meta_account_idx,
3050 abi_account_idx,
3051 authority_account_idx,
3052 };
3053
3054 let args_bytes = unsafe {
3055 std::slice::from_raw_parts(
3056 &args as *const AbiManagerCloseAbiExternalArgs as *const u8,
3057 std::mem::size_of::<AbiManagerCloseAbiExternalArgs>(),
3058 )
3059 };
3060
3061 instruction.extend_from_slice(args_bytes);
3062 Ok(instruction)
3063}
3064
3065fn build_manager_upgrade_instruction(
3067 meta_account_idx: u16,
3068 program_account_idx: u16,
3069 srcbuf_account_idx: u16,
3070 srcbuf_offset: u32,
3071 srcbuf_size: u32,
3072) -> Result<Vec<u8>> {
3073 let mut instruction = Vec::new();
3074
3075 let args = ManagerUpgradeArgs {
3076 discriminant: MANAGER_INSTRUCTION_UPGRADE,
3077 meta_account_idx,
3078 program_account_idx,
3079 srcbuf_account_idx,
3080 srcbuf_offset,
3081 srcbuf_size,
3082 };
3083
3084 let args_bytes = unsafe {
3085 std::slice::from_raw_parts(
3086 &args as *const ManagerUpgradeArgs as *const u8,
3087 std::mem::size_of::<ManagerUpgradeArgs>(),
3088 )
3089 };
3090 instruction.extend_from_slice(args_bytes);
3091
3092 Ok(instruction)
3093}
3094
3095fn build_manager_set_pause_instruction(
3097 meta_account_idx: u16,
3098 program_account_idx: u16,
3099 is_paused: bool,
3100) -> Result<Vec<u8>> {
3101 let mut instruction = Vec::new();
3102
3103 let args = ManagerSetPauseArgs {
3104 discriminant: MANAGER_INSTRUCTION_SET_PAUSE,
3105 meta_account_idx,
3106 program_account_idx,
3107 is_paused: if is_paused { 1 } else { 0 },
3108 };
3109
3110 let args_bytes = unsafe {
3111 std::slice::from_raw_parts(
3112 &args as *const ManagerSetPauseArgs as *const u8,
3113 std::mem::size_of::<ManagerSetPauseArgs>(),
3114 )
3115 };
3116 instruction.extend_from_slice(args_bytes);
3117
3118 Ok(instruction)
3119}
3120
3121fn build_manager_header_instruction(
3123 discriminant: u8,
3124 meta_account_idx: u16,
3125 program_account_idx: u16,
3126) -> Result<Vec<u8>> {
3127 let mut instruction = Vec::new();
3128
3129 let args = ManagerHeaderArgs {
3130 discriminant,
3131 meta_account_idx,
3132 program_account_idx,
3133 };
3134
3135 let args_bytes = unsafe {
3136 std::slice::from_raw_parts(
3137 &args as *const ManagerHeaderArgs as *const u8,
3138 std::mem::size_of::<ManagerHeaderArgs>(),
3139 )
3140 };
3141 instruction.extend_from_slice(args_bytes);
3142
3143 Ok(instruction)
3144}
3145
3146fn build_manager_set_authority_instruction(
3148 meta_account_idx: u16,
3149 program_account_idx: u16,
3150 authority_candidate: [u8; 32],
3151) -> Result<Vec<u8>> {
3152 let mut instruction = Vec::new();
3153
3154 let args = ManagerSetAuthorityArgs {
3155 discriminant: MANAGER_INSTRUCTION_SET_AUTHORITY,
3156 meta_account_idx,
3157 program_account_idx,
3158 authority_candidate,
3159 };
3160
3161 let args_bytes = unsafe {
3162 std::slice::from_raw_parts(
3163 &args as *const ManagerSetAuthorityArgs as *const u8,
3164 std::mem::size_of::<ManagerSetAuthorityArgs>(),
3165 )
3166 };
3167 instruction.extend_from_slice(args_bytes);
3168
3169 Ok(instruction)
3170}
3171
3172fn build_test_uploader_create_instruction(
3174 account_idx: u16,
3175 account_sz: u32,
3176 seed: &[u8],
3177 is_ephemeral: bool,
3178 state_proof: Option<&[u8]>,
3179) -> Result<Vec<u8>> {
3180 let mut instruction = Vec::new();
3181
3182 instruction.push(TN_TEST_UPLOADER_PROGRAM_DISCRIMINANT_CREATE);
3184
3185 let args = TestUploaderCreateArgs {
3187 account_idx,
3188 is_ephemeral: if is_ephemeral { 1u8 } else { 0u8 },
3189 account_sz,
3190 seed_len: seed.len() as u32,
3191 };
3192
3193 let args_bytes = unsafe {
3195 std::slice::from_raw_parts(
3196 &args as *const _ as *const u8,
3197 std::mem::size_of::<TestUploaderCreateArgs>(),
3198 )
3199 };
3200 instruction.extend_from_slice(args_bytes);
3201
3202 instruction.extend_from_slice(seed);
3204
3205 if let Some(proof) = state_proof {
3207 instruction.extend_from_slice(proof);
3208 }
3209
3210 Ok(instruction)
3211}
3212
3213fn build_test_uploader_write_instruction(
3215 target_account_idx: u16,
3216 target_offset: u32,
3217 data: &[u8],
3218) -> Result<Vec<u8>> {
3219 let mut instruction = Vec::new();
3220
3221 instruction.push(TN_TEST_UPLOADER_PROGRAM_DISCRIMINANT_WRITE);
3223
3224 let args = TestUploaderWriteArgs {
3226 target_account_idx,
3227 target_offset,
3228 data_len: data.len() as u32,
3229 };
3230
3231 let args_bytes = unsafe {
3233 std::slice::from_raw_parts(
3234 &args as *const _ as *const u8,
3235 std::mem::size_of::<TestUploaderWriteArgs>(),
3236 )
3237 };
3238 instruction.extend_from_slice(args_bytes);
3239
3240 instruction.extend_from_slice(data);
3242
3243 Ok(instruction)
3244}
3245
3246pub fn build_decompress2_instruction(
3248 target_account_idx: u16,
3249 meta_account_idx: u16,
3250 data_account_idx: u16,
3251 data_offset: u32,
3252 state_proof: &[u8],
3253) -> Result<Vec<u8>> {
3254 let mut instruction = Vec::new();
3255
3256 instruction.push(0x08);
3258
3259 let args = SystemProgramDecompress2Args {
3261 target_account_idx,
3262 meta_account_idx,
3263 data_account_idx,
3264 data_offset,
3265 };
3266
3267 let args_bytes = unsafe {
3269 std::slice::from_raw_parts(
3270 &args as *const _ as *const u8,
3271 std::mem::size_of::<SystemProgramDecompress2Args>(),
3272 )
3273 };
3274 instruction.extend_from_slice(args_bytes);
3275
3276 instruction.extend_from_slice(state_proof);
3278
3279 Ok(instruction)
3280}
3281
3282pub const TOKEN_INSTRUCTION_INITIALIZE_MINT: u8 = 0x00;
3284pub const TOKEN_INSTRUCTION_INITIALIZE_ACCOUNT: u8 = 0x01;
3285pub const TOKEN_INSTRUCTION_TRANSFER: u8 = 0x02;
3286pub const TOKEN_INSTRUCTION_MINT_TO: u8 = 0x03;
3287pub const TOKEN_INSTRUCTION_BURN: u8 = 0x04;
3288pub const TOKEN_INSTRUCTION_CLOSE_ACCOUNT: u8 = 0x05;
3289pub const TOKEN_INSTRUCTION_FREEZE_ACCOUNT: u8 = 0x06;
3290pub const TOKEN_INSTRUCTION_THAW_ACCOUNT: u8 = 0x07;
3291
3292pub const TN_WTHRU_INSTRUCTION_INITIALIZE_MINT: u32 = 0;
3294pub const TN_WTHRU_INSTRUCTION_DEPOSIT: u32 = 1;
3295pub const TN_WTHRU_INSTRUCTION_WITHDRAW: u32 = 2;
3296pub const TN_NAME_SERVICE_INSTRUCTION_INITIALIZE_ROOT: u32 = 0;
3302pub const TN_NAME_SERVICE_INSTRUCTION_REGISTER_SUBDOMAIN: u32 = 1;
3303pub const TN_NAME_SERVICE_INSTRUCTION_APPEND_RECORD: u32 = 2;
3304pub const TN_NAME_SERVICE_INSTRUCTION_DELETE_RECORD: u32 = 3;
3305pub const TN_NAME_SERVICE_INSTRUCTION_UNREGISTER: u32 = 4;
3306
3307pub const TN_NAME_SERVICE_PROOF_INLINE: u32 = 0;
3309
3310pub const TN_NAME_SERVICE_MAX_DOMAIN_LENGTH: usize = 64;
3312pub const TN_NAME_SERVICE_MAX_KEY_LENGTH: usize = 32;
3313pub const TN_NAME_SERVICE_MAX_VALUE_LENGTH: usize = 256;
3314
3315pub const TN_THRU_REGISTRAR_INSTRUCTION_INITIALIZE_REGISTRY: u32 = 0;
3317pub const TN_THRU_REGISTRAR_INSTRUCTION_PURCHASE_DOMAIN: u32 = 1;
3318pub const TN_THRU_REGISTRAR_INSTRUCTION_RENEW_LEASE: u32 = 2;
3319pub const TN_THRU_REGISTRAR_INSTRUCTION_CLAIM_EXPIRED_DOMAIN: u32 = 3;
3320
3321fn add_sorted_accounts(tx: Transaction, accounts: &[(TnPubkey, bool)]) -> (Transaction, Vec<u16>) {
3323 let mut rw_accounts: Vec<_> = accounts.iter().enumerate()
3325 .filter(|(_, (_, writable))| *writable)
3326 .collect();
3327 let mut ro_accounts: Vec<_> = accounts.iter().enumerate()
3328 .filter(|(_, (_, writable))| !*writable)
3329 .collect();
3330
3331 rw_accounts.sort_by(|a, b| a.1.0.cmp(&b.1.0));
3333 ro_accounts.sort_by(|a, b| a.1.0.cmp(&b.1.0));
3334
3335 let mut updated_tx = tx;
3336 let mut indices = vec![0u16; accounts.len()];
3337 let mut seen: HashMap<TnPubkey, u16> = HashMap::new();
3338 seen.insert(updated_tx.fee_payer, 0u16);
3339 seen.insert(updated_tx.program, 1u16);
3340
3341 let mut next_idx = 2u16;
3342
3343 for (i, (account, _)) in rw_accounts.iter() {
3345 if let Some(idx) = seen.get(account) {
3346 indices[*i] = *idx;
3347 continue;
3348 }
3349
3350 let account_idx = next_idx;
3351 next_idx = next_idx.saturating_add(1);
3352 seen.insert(*account, account_idx);
3353 indices[*i] = account_idx;
3354
3355 updated_tx = updated_tx.add_rw_account(*account);
3356 }
3357
3358 for (i, (account, _)) in ro_accounts.iter() {
3360 if let Some(idx) = seen.get(account) {
3361 indices[*i] = *idx;
3362 continue;
3363 }
3364
3365 let account_idx = next_idx;
3366 next_idx = next_idx.saturating_add(1);
3367 seen.insert(*account, account_idx);
3368 indices[*i] = account_idx;
3369
3370 updated_tx = updated_tx.add_r_account(*account);
3371 }
3372
3373 (updated_tx, indices)
3374}
3375
3376fn add_sorted_rw_accounts(mut tx: Transaction, accounts: &[TnPubkey]) -> (Transaction, Vec<u16>) {
3378 if accounts.is_empty() {
3379 return (tx, Vec::new());
3380 }
3381
3382 let mut sorted: Vec<(usize, TnPubkey)> = accounts.iter().cloned().enumerate().collect();
3383 sorted.sort_by(|a, b| a.1.cmp(&b.1));
3384
3385 let mut indices = vec![0u16; accounts.len()];
3386 for (pos, (orig_idx, account)) in sorted.into_iter().enumerate() {
3387 let idx = (2 + pos) as u16;
3388 indices[orig_idx] = idx;
3389 tx = tx.add_rw_account(account);
3390 }
3391
3392 (tx, indices)
3393}
3394
3395fn add_sorted_ro_accounts(
3396 mut tx: Transaction,
3397 base_idx: u16,
3398 accounts: &[TnPubkey],
3399) -> (Transaction, Vec<u16>) {
3400 if accounts.is_empty() {
3401 return (tx, Vec::new());
3402 }
3403
3404 let mut sorted: Vec<(usize, TnPubkey)> = accounts.iter().cloned().enumerate().collect();
3405 sorted.sort_by(|a, b| a.1.cmp(&b.1));
3406
3407 let mut indices = vec![0u16; accounts.len()];
3408 for (pos, (orig_idx, account)) in sorted.into_iter().enumerate() {
3409 let idx = base_idx + pos as u16;
3410 indices[orig_idx] = idx;
3411 tx = tx.add_r_account(account);
3412 }
3413
3414 (tx, indices)
3415}
3416
3417impl TransactionBuilder {
3418 pub fn build_token_initialize_mint(
3420 fee_payer: TnPubkey,
3421 token_program: TnPubkey,
3422 mint_account: TnPubkey,
3423 creator: TnPubkey,
3424 mint_authority: TnPubkey,
3425 freeze_authority: Option<TnPubkey>,
3426 decimals: u8,
3427 ticker: &str,
3428 seed: [u8; 32],
3429 state_proof: Vec<u8>,
3430 fee: u64,
3431 nonce: u64,
3432 start_slot: u64,
3433 ) -> Result<Transaction> {
3434 let base_tx =
3435 Transaction::new(fee_payer, token_program, fee, nonce).with_start_slot(start_slot);
3436 let (tx, indices) = add_sorted_rw_accounts(base_tx, &[mint_account]);
3437 let mint_account_idx = indices[0];
3438
3439 let instruction_data = build_token_initialize_mint_instruction(
3440 mint_account_idx,
3441 decimals,
3442 creator,
3443 mint_authority,
3444 freeze_authority,
3445 ticker,
3446 seed,
3447 state_proof,
3448 )?;
3449
3450 let tx = tx
3451 .with_instructions(instruction_data)
3452 .with_expiry_after(100)
3453 .with_compute_units(300_000)
3454 .with_state_units(10_000)
3455 .with_memory_units(10_000);
3456
3457 Ok(tx)
3458 }
3459
3460 pub fn build_token_initialize_account(
3462 fee_payer: TnPubkey,
3463 token_program: TnPubkey,
3464 token_account: TnPubkey,
3465 mint_account: TnPubkey,
3466 owner: TnPubkey,
3467 seed: [u8; 32],
3468 state_proof: Vec<u8>,
3469 fee: u64,
3470 nonce: u64,
3471 start_slot: u64,
3472 ) -> Result<Transaction> {
3473 let owner_is_fee_payer = owner == fee_payer;
3474
3475 let mut rw_accounts = vec![token_account];
3476 rw_accounts.sort();
3477
3478 let mut ro_accounts = vec![mint_account];
3479 if !owner_is_fee_payer {
3480 ro_accounts.push(owner);
3481 ro_accounts.sort();
3482 }
3483
3484 let mut tx =
3485 Transaction::new(fee_payer, token_program, fee, nonce).with_start_slot(start_slot);
3486
3487 let mut token_account_idx = 0u16;
3488 for (i, account) in rw_accounts.iter().enumerate() {
3489 let idx = (2 + i) as u16;
3490 if *account == token_account {
3491 token_account_idx = idx;
3492 }
3493 tx = tx.add_rw_account(*account);
3494 }
3495
3496 let base_ro_idx = 2 + rw_accounts.len() as u16;
3497 let mut mint_account_idx = 0u16;
3498 let mut owner_account_idx = if owner_is_fee_payer { 0u16 } else { 0u16 };
3499 for (i, account) in ro_accounts.iter().enumerate() {
3500 let idx = base_ro_idx + i as u16;
3501 if *account == mint_account {
3502 mint_account_idx = idx;
3503 } else if !owner_is_fee_payer && *account == owner {
3504 owner_account_idx = idx;
3505 }
3506 tx = tx.add_r_account(*account);
3507 }
3508
3509 let instruction_data = build_token_initialize_account_instruction(
3510 token_account_idx,
3511 mint_account_idx,
3512 owner_account_idx,
3513 seed,
3514 state_proof,
3515 )?;
3516
3517 let tx = tx
3518 .with_instructions(instruction_data)
3519 .with_expiry_after(100)
3520 .with_compute_units(300_000)
3521 .with_state_units(10_000)
3522 .with_memory_units(10_000);
3523
3524 Ok(tx)
3525 }
3526
3527 pub fn build_token_transfer(
3529 fee_payer: TnPubkey,
3530 token_program: TnPubkey,
3531 source_account: TnPubkey,
3532 dest_account: TnPubkey,
3533 _authority: TnPubkey,
3534 amount: u64,
3535 fee: u64,
3536 nonce: u64,
3537 start_slot: u64,
3538 ) -> Result<Transaction> {
3539 let mut tx = Transaction::new(fee_payer, token_program, fee, nonce)
3540 .with_start_slot(start_slot)
3541 .with_expiry_after(100)
3542 .with_compute_units(300_000)
3543 .with_state_units(10_000)
3544 .with_memory_units(10_000);
3545
3546 let is_self_transfer = source_account == dest_account;
3547 let (source_account_idx, dest_account_idx) = if is_self_transfer {
3548 tx = tx.add_rw_account(source_account);
3550 (2u16, 2u16)
3551 } else {
3552 let accounts = &[(source_account, true), (dest_account, true)];
3554 let (updated_tx, indices) = add_sorted_accounts(tx, accounts);
3555 tx = updated_tx;
3556 (indices[0], indices[1])
3557 };
3558
3559 let instruction_data =
3563 build_token_transfer_instruction(source_account_idx, dest_account_idx, amount)?;
3564
3565 Ok(tx.with_instructions(instruction_data))
3566 }
3567
3568 pub fn build_token_mint_to(
3570 fee_payer: TnPubkey,
3571 token_program: TnPubkey,
3572 mint_account: TnPubkey,
3573 dest_account: TnPubkey,
3574 authority: TnPubkey,
3575 amount: u64,
3576 fee: u64,
3577 nonce: u64,
3578 start_slot: u64,
3579 ) -> Result<Transaction> {
3580 let base_tx = Transaction::new(fee_payer, token_program, fee, nonce)
3581 .with_start_slot(start_slot)
3582 .with_expiry_after(100)
3583 .with_compute_units(300_000)
3584 .with_state_units(10_000)
3585 .with_memory_units(10_000);
3586
3587 let (tx_after_rw, rw_indices) =
3588 add_sorted_rw_accounts(base_tx, &[mint_account, dest_account]);
3589 let mint_account_idx = rw_indices[0];
3590 let dest_account_idx = rw_indices[1];
3591
3592 let mut tx = tx_after_rw;
3593 let authority_account_idx = if authority == fee_payer {
3594 0u16
3595 } else {
3596 let base_ro_idx = 2 + rw_indices.len() as u16;
3597 let (tx_after_ro, ro_indices) = add_sorted_ro_accounts(tx, base_ro_idx, &[authority]);
3598 tx = tx_after_ro;
3599 ro_indices[0]
3600 };
3601
3602 let instruction_data = build_token_mint_to_instruction(
3603 mint_account_idx,
3604 dest_account_idx,
3605 authority_account_idx,
3606 amount,
3607 )?;
3608
3609 Ok(tx.with_instructions(instruction_data))
3610 }
3611
3612 pub fn build_token_burn(
3614 fee_payer: TnPubkey,
3615 token_program: TnPubkey,
3616 token_account: TnPubkey,
3617 mint_account: TnPubkey,
3618 authority: TnPubkey,
3619 amount: u64,
3620 fee: u64,
3621 nonce: u64,
3622 start_slot: u64,
3623 ) -> Result<Transaction> {
3624 let base_tx = Transaction::new(fee_payer, token_program, fee, nonce)
3625 .with_start_slot(start_slot)
3626 .with_expiry_after(100)
3627 .with_compute_units(300_000)
3628 .with_state_units(10_000)
3629 .with_memory_units(10_000);
3630
3631 let (tx_after_rw, rw_indices) =
3632 add_sorted_rw_accounts(base_tx, &[token_account, mint_account]);
3633 let token_account_idx = rw_indices[0];
3634 let mint_account_idx = rw_indices[1];
3635
3636 let mut tx = tx_after_rw;
3637 let authority_account_idx = if authority == fee_payer {
3638 0u16
3639 } else {
3640 let base_ro_idx = 2 + rw_indices.len() as u16;
3641 let (tx_after_ro, ro_indices) = add_sorted_ro_accounts(tx, base_ro_idx, &[authority]);
3642 tx = tx_after_ro;
3643 ro_indices[0]
3644 };
3645
3646 let instruction_data = build_token_burn_instruction(
3647 token_account_idx,
3648 mint_account_idx,
3649 authority_account_idx,
3650 amount,
3651 )?;
3652
3653 Ok(tx.with_instructions(instruction_data))
3654 }
3655
3656 pub fn build_token_freeze_account(
3658 fee_payer: TnPubkey,
3659 token_program: TnPubkey,
3660 token_account: TnPubkey,
3661 mint_account: TnPubkey,
3662 authority: TnPubkey,
3663 fee: u64,
3664 nonce: u64,
3665 start_slot: u64,
3666 ) -> Result<Transaction> {
3667 let base_tx = Transaction::new(fee_payer, token_program, fee, nonce)
3668 .with_start_slot(start_slot)
3669 .with_expiry_after(100)
3670 .with_compute_units(300_000)
3671 .with_state_units(10_000)
3672 .with_memory_units(10_000);
3673
3674 let (tx_after_rw, rw_indices) =
3675 add_sorted_rw_accounts(base_tx, &[token_account, mint_account]);
3676 let token_account_idx = rw_indices[0];
3677 let mint_account_idx = rw_indices[1];
3678
3679 let mut tx = tx_after_rw;
3680 let authority_account_idx = if authority == fee_payer {
3681 0u16
3682 } else {
3683 let base_ro_idx = 2 + rw_indices.len() as u16;
3684 let (tx_after_ro, ro_indices) = add_sorted_ro_accounts(tx, base_ro_idx, &[authority]);
3685 tx = tx_after_ro;
3686 ro_indices[0]
3687 };
3688
3689 let instruction_data = build_token_freeze_account_instruction(
3690 token_account_idx,
3691 mint_account_idx,
3692 authority_account_idx,
3693 )?;
3694
3695 Ok(tx.with_instructions(instruction_data))
3696 }
3697
3698 pub fn build_token_thaw_account(
3700 fee_payer: TnPubkey,
3701 token_program: TnPubkey,
3702 token_account: TnPubkey,
3703 mint_account: TnPubkey,
3704 authority: TnPubkey,
3705 fee: u64,
3706 nonce: u64,
3707 start_slot: u64,
3708 ) -> Result<Transaction> {
3709 let base_tx = Transaction::new(fee_payer, token_program, fee, nonce)
3710 .with_start_slot(start_slot)
3711 .with_expiry_after(100)
3712 .with_compute_units(300_000)
3713 .with_state_units(10_000)
3714 .with_memory_units(10_000);
3715
3716 let (tx_after_rw, rw_indices) =
3717 add_sorted_rw_accounts(base_tx, &[token_account, mint_account]);
3718 let token_account_idx = rw_indices[0];
3719 let mint_account_idx = rw_indices[1];
3720
3721 let mut tx = tx_after_rw;
3722 let authority_account_idx = if authority == fee_payer {
3723 0u16
3724 } else {
3725 let base_ro_idx = 2 + rw_indices.len() as u16;
3726 let (tx_after_ro, ro_indices) = add_sorted_ro_accounts(tx, base_ro_idx, &[authority]);
3727 tx = tx_after_ro;
3728 ro_indices[0]
3729 };
3730
3731 let instruction_data = build_token_thaw_account_instruction(
3732 token_account_idx,
3733 mint_account_idx,
3734 authority_account_idx,
3735 )?;
3736
3737 Ok(tx.with_instructions(instruction_data))
3738 }
3739
3740 pub fn build_token_close_account(
3742 fee_payer: TnPubkey,
3743 token_program: TnPubkey,
3744 token_account: TnPubkey,
3745 destination: TnPubkey,
3746 authority: TnPubkey,
3747 fee: u64,
3748 nonce: u64,
3749 start_slot: u64,
3750 ) -> Result<Transaction> {
3751 let base_tx = Transaction::new(fee_payer, token_program, fee, nonce)
3752 .with_start_slot(start_slot)
3753 .with_expiry_after(100)
3754 .with_compute_units(300_000)
3755 .with_state_units(10_000)
3756 .with_memory_units(10_000);
3757
3758 let mut rw_accounts = vec![token_account];
3759 let destination_in_accounts = destination != fee_payer;
3760 if destination_in_accounts {
3761 rw_accounts.push(destination);
3762 }
3763
3764 let (tx_after_rw, rw_indices) = add_sorted_rw_accounts(base_tx, &rw_accounts);
3765 let token_account_idx = rw_indices[0];
3766 let destination_idx = if destination_in_accounts {
3767 rw_indices[1]
3768 } else {
3769 0u16
3770 };
3771
3772 let mut tx = tx_after_rw;
3773 let authority_account_idx = if authority == fee_payer {
3774 0u16
3775 } else {
3776 let base_ro_idx = 2 + rw_indices.len() as u16;
3777 let (tx_after_ro, ro_indices) = add_sorted_ro_accounts(tx, base_ro_idx, &[authority]);
3778 tx = tx_after_ro;
3779 ro_indices[0]
3780 };
3781
3782 let instruction_data = build_token_close_account_instruction(
3783 token_account_idx,
3784 destination_idx,
3785 authority_account_idx,
3786 )?;
3787
3788 Ok(tx.with_instructions(instruction_data))
3789 }
3790
3791 pub fn build_wthru_initialize_mint(
3793 fee_payer: TnPubkey,
3794 wthru_program: TnPubkey,
3795 token_program: TnPubkey,
3796 mint_account: TnPubkey,
3797 vault_account: TnPubkey,
3798 decimals: u8,
3799 mint_seed: [u8; 32],
3800 mint_proof: Vec<u8>,
3801 vault_proof: Vec<u8>,
3802 fee: u64,
3803 nonce: u64,
3804 start_slot: u64,
3805 ) -> Result<Transaction> {
3806 let mut tx = Transaction::new(fee_payer, wthru_program, fee, nonce)
3807 .with_start_slot(start_slot)
3808 .with_expiry_after(100)
3809 .with_compute_units(500_000)
3810 .with_state_units(10_000)
3811 .with_memory_units(10_000);
3812
3813 let accounts = [
3814 (mint_account, true),
3815 (vault_account, true),
3816 (token_program, false),
3817 ];
3818
3819 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
3820 tx = tx_with_accounts;
3821
3822 let mint_account_idx = indices[0];
3823 let vault_account_idx = indices[1];
3824 let token_program_idx = indices[2];
3825
3826 let instruction_data = build_wthru_initialize_mint_instruction(
3827 token_program_idx,
3828 mint_account_idx,
3829 vault_account_idx,
3830 decimals,
3831 mint_seed,
3832 mint_proof,
3833 vault_proof,
3834 )?;
3835
3836 Ok(tx.with_instructions(instruction_data))
3837 }
3838
3839 pub fn build_wthru_deposit(
3841 fee_payer: TnPubkey,
3842 wthru_program: TnPubkey,
3843 token_program: TnPubkey,
3844 mint_account: TnPubkey,
3845 vault_account: TnPubkey,
3846 dest_token_account: TnPubkey,
3847 fee: u64,
3848 nonce: u64,
3849 start_slot: u64,
3850 ) -> Result<Transaction> {
3851 let mut tx = Transaction::new(fee_payer, wthru_program, fee, nonce)
3852 .with_start_slot(start_slot)
3853 .with_expiry_after(100)
3854 .with_compute_units(400_000)
3855 .with_state_units(10_000)
3856 .with_memory_units(10_000);
3857
3858 let accounts = [
3859 (mint_account, true),
3860 (vault_account, true),
3861 (dest_token_account, true),
3862 (token_program, false),
3863 ];
3864
3865 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
3866 tx = tx_with_accounts;
3867
3868 let mint_account_idx = indices[0];
3869 let vault_account_idx = indices[1];
3870 let dest_account_idx = indices[2];
3871 let token_program_idx = indices[3];
3872
3873 let instruction_data = build_wthru_deposit_instruction(
3874 token_program_idx,
3875 vault_account_idx,
3876 mint_account_idx,
3877 dest_account_idx,
3878 )?;
3879
3880 Ok(tx.with_instructions(instruction_data))
3881 }
3882
3883 pub fn build_wthru_withdraw(
3885 fee_payer: TnPubkey,
3886 wthru_program: TnPubkey,
3887 token_program: TnPubkey,
3888 mint_account: TnPubkey,
3889 vault_account: TnPubkey,
3890 wthru_token_account: TnPubkey,
3891 recipient_account: TnPubkey,
3892 amount: u64,
3893 fee: u64,
3894 nonce: u64,
3895 start_slot: u64,
3896 ) -> Result<Transaction> {
3897 let mut tx = Transaction::new(fee_payer, wthru_program, fee, nonce)
3898 .with_start_slot(start_slot)
3899 .with_expiry_after(100)
3900 .with_compute_units(400_000)
3901 .with_state_units(10_000)
3902 .with_memory_units(10_000);
3903
3904 let accounts = [
3905 (mint_account, true),
3906 (vault_account, true),
3907 (wthru_token_account, true),
3908 (recipient_account, true),
3909 (token_program, false),
3910 ];
3911
3912 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
3913 tx = tx_with_accounts;
3914
3915 let mint_account_idx = indices[0];
3916 let vault_account_idx = indices[1];
3917 let token_account_idx = indices[2];
3918 let recipient_account_idx = indices[3];
3919 let token_program_idx = indices[4];
3920
3921 let owner_account_idx = 0u16; let instruction_data = build_wthru_withdraw_instruction(
3924 token_program_idx,
3925 vault_account_idx,
3926 mint_account_idx,
3927 token_account_idx,
3928 owner_account_idx,
3929 recipient_account_idx,
3930 amount,
3931 )?;
3932
3933 Ok(tx.with_instructions(instruction_data))
3934 }
3935
3936 pub fn build_faucet_deposit(
3939 fee_payer: TnPubkey,
3940 faucet_program: TnPubkey,
3941 faucet_account: TnPubkey,
3942 depositor_account: TnPubkey,
3943 eoa_program: TnPubkey,
3944 amount: u64,
3945 fee: u64,
3946 nonce: u64,
3947 start_slot: u64,
3948 ) -> Result<Transaction> {
3949 let tx = Transaction::new(fee_payer, faucet_program, fee, nonce)
3950 .with_start_slot(start_slot)
3951 .with_expiry_after(100)
3952 .with_compute_units(300_000)
3953 .with_state_units(10_000)
3954 .with_memory_units(10_000);
3955
3956 let (tx, depositor_account_idx) = Self::ensure_rw_account(tx, depositor_account);
3957 let (tx, faucet_account_idx) = Self::ensure_rw_account(tx, faucet_account);
3958 let (tx, eoa_program_idx) = Self::ensure_ro_account(tx, eoa_program);
3959
3960 let instruction_data = build_faucet_deposit_instruction(
3961 faucet_account_idx,
3962 depositor_account_idx,
3963 eoa_program_idx,
3964 amount,
3965 )?;
3966
3967 Ok(tx.with_instructions(instruction_data))
3968 }
3969
3970 fn resolve_account_index(tx: &Transaction, target: &TnPubkey) -> Option<u16> {
3971 if *target == tx.fee_payer {
3972 return Some(0u16);
3973 }
3974
3975 if *target == tx.program {
3976 return Some(1u16);
3977 }
3978
3979 if let Some(ref rw) = tx.rw_accs {
3980 if let Some(pos) = rw.iter().position(|acc| acc == target) {
3981 return Some(2u16 + pos as u16);
3982 }
3983 }
3984
3985 if let Some(ref ro) = tx.r_accs {
3986 let base = 2u16 + tx.rw_accs.as_ref().map_or(0u16, |v| v.len() as u16);
3987 if let Some(pos) = ro.iter().position(|acc| acc == target) {
3988 return Some(base + pos as u16);
3989 }
3990 }
3991
3992 None
3993 }
3994
3995 fn ensure_rw_account(mut tx: Transaction, account: TnPubkey) -> (Transaction, u16) {
3996 if let Some(idx) = Self::resolve_account_index(&tx, &account) {
3997 return (tx, idx);
3998 }
3999
4000 tx = tx.add_rw_account(account);
4001 let idx = Self::resolve_account_index(&tx, &account)
4002 .expect("read-write account index should exist after insertion");
4003
4004 (tx, idx)
4005 }
4006
4007 fn ensure_ro_account(mut tx: Transaction, account: TnPubkey) -> (Transaction, u16) {
4008 if let Some(idx) = Self::resolve_account_index(&tx, &account) {
4009 return (tx, idx);
4010 }
4011
4012 tx = tx.add_r_account(account);
4013 let idx = Self::resolve_account_index(&tx, &account)
4014 .expect("read-only account index should exist after insertion");
4015
4016 (tx, idx)
4017 }
4018
4019 pub fn build_faucet_withdraw(
4021 fee_payer: TnPubkey,
4022 faucet_program: TnPubkey,
4023 faucet_account: TnPubkey,
4024 recipient_account: TnPubkey,
4025 amount: u64,
4026 fee: u64,
4027 nonce: u64,
4028 start_slot: u64,
4029 ) -> Result<Transaction> {
4030 let mut tx = Transaction::new(fee_payer, faucet_program, fee, nonce)
4031 .with_start_slot(start_slot)
4032 .with_expiry_after(100)
4033 .with_compute_units(300_000)
4034 .with_state_units(10_000)
4035 .with_memory_units(10_000);
4036
4037 let faucet_is_fee_payer = faucet_account == fee_payer;
4040 let recipient_is_fee_payer = recipient_account == fee_payer;
4041 let recipient_is_faucet = recipient_account == faucet_account;
4042
4043 let (faucet_account_idx, recipient_account_idx) = if faucet_is_fee_payer && recipient_is_fee_payer {
4044 (0u16, 0u16)
4046 } else if faucet_is_fee_payer {
4047 tx = tx.add_rw_account(recipient_account);
4049 (0u16, 2u16)
4050 } else if recipient_is_fee_payer {
4051 tx = tx.add_rw_account(faucet_account);
4053 (2u16, 0u16)
4054 } else if recipient_is_faucet {
4055 tx = tx.add_rw_account(faucet_account);
4057 (2u16, 2u16)
4058 } else {
4059 if faucet_account < recipient_account {
4061 tx = tx.add_rw_account(faucet_account);
4062 tx = tx.add_rw_account(recipient_account);
4063 (2u16, 3u16)
4064 } else {
4065 tx = tx.add_rw_account(recipient_account);
4066 tx = tx.add_rw_account(faucet_account);
4067 (3u16, 2u16)
4068 }
4069 };
4070
4071 let instruction_data = build_faucet_withdraw_instruction(
4072 faucet_account_idx,
4073 recipient_account_idx,
4074 amount,
4075 )?;
4076
4077 Ok(tx.with_instructions(instruction_data))
4078 }
4079
4080 pub fn build_activate(
4096 fee_payer: TnPubkey,
4097 source_token_account: TnPubkey,
4098 bls_pk: [u8; 96],
4099 claim_authority: TnPubkey,
4100 token_amount: u64,
4101 fee: u64,
4102 nonce: u64,
4103 start_slot: u64,
4104 ) -> Result<Transaction> {
4105 let program: TnPubkey = CONSENSUS_VALIDATOR_PROGRAM;
4106 let attestor_table: TnPubkey = ATTESTOR_TABLE;
4107 let token_program: TnPubkey = TOKEN_PROGRAM;
4108 let converted_vault: TnPubkey = CONVERTED_VAULT;
4109
4110 let tx = Transaction::new(fee_payer, program, fee, nonce)
4111 .with_start_slot(start_slot)
4112 .with_expiry_after(100)
4113 .with_compute_units(500_000_000) .with_state_units(50_000)
4115 .with_memory_units(50_000);
4116
4117 let accounts = [
4122 (attestor_table, true), (source_token_account, true), (converted_vault, true), (token_program, false), ];
4127 let (tx, indices) = add_sorted_accounts(tx, &accounts);
4128 let attestor_table_idx = indices[0];
4129 let source_token_account_idx = indices[1];
4130 let converted_vault_idx = indices[2];
4131 let token_program_idx = indices[3];
4132
4133 let identity_idx = 0u16;
4135
4136 let instruction_data = build_activate_instruction(
4137 attestor_table_idx as u64,
4138 token_program_idx,
4139 source_token_account_idx,
4140 converted_vault_idx,
4141 identity_idx,
4142 bls_pk,
4143 claim_authority,
4144 token_amount,
4145 )?;
4146
4147 Ok(tx.with_instructions(instruction_data))
4148 }
4149
4150 pub fn build_name_service_initialize_root(
4152 fee_payer: TnPubkey,
4153 name_service_program: TnPubkey,
4154 registrar_account: TnPubkey,
4155 authority_account: TnPubkey,
4156 root_name: &str,
4157 state_proof: Vec<u8>,
4158 fee: u64,
4159 nonce: u64,
4160 start_slot: u64,
4161 ) -> Result<Transaction> {
4162 let mut tx = Transaction::new(fee_payer, name_service_program, fee, nonce)
4163 .with_start_slot(start_slot)
4164 .with_expiry_after(100)
4165 .with_compute_units(500_000)
4166 .with_state_units(10_000)
4167 .with_memory_units(10_000);
4168
4169 let accounts = [(registrar_account, true), (authority_account, false)];
4170 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
4171 tx = tx_with_accounts;
4172
4173 let registrar_account_idx = indices[0];
4174 let authority_account_idx = indices[1];
4175
4176 let instruction_data = build_name_service_initialize_root_instruction(
4177 registrar_account_idx,
4178 authority_account_idx,
4179 root_name,
4180 state_proof,
4181 )?;
4182
4183 Ok(tx.with_instructions(instruction_data))
4184 }
4185
4186 pub fn build_name_service_register_subdomain(
4188 fee_payer: TnPubkey,
4189 name_service_program: TnPubkey,
4190 domain_account: TnPubkey,
4191 parent_account: TnPubkey,
4192 owner_account: TnPubkey,
4193 authority_account: TnPubkey,
4194 domain_name: &str,
4195 state_proof: Vec<u8>,
4196 fee: u64,
4197 nonce: u64,
4198 start_slot: u64,
4199 ) -> Result<Transaction> {
4200 let mut tx = Transaction::new(fee_payer, name_service_program, fee, nonce)
4201 .with_start_slot(start_slot)
4202 .with_expiry_after(100)
4203 .with_compute_units(500_000)
4204 .with_state_units(10_000)
4205 .with_memory_units(10_000);
4206
4207 let accounts = [
4208 (domain_account, true),
4209 (parent_account, true),
4210 (owner_account, false),
4211 (authority_account, false),
4212 ];
4213 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
4214 tx = tx_with_accounts;
4215
4216 let domain_account_idx = indices[0];
4217 let parent_account_idx = indices[1];
4218 let owner_account_idx = indices[2];
4219 let authority_account_idx = indices[3];
4220
4221 let instruction_data = build_name_service_register_subdomain_instruction(
4222 domain_account_idx,
4223 parent_account_idx,
4224 owner_account_idx,
4225 authority_account_idx,
4226 domain_name,
4227 state_proof,
4228 )?;
4229
4230 Ok(tx.with_instructions(instruction_data))
4231 }
4232
4233 pub fn build_name_service_append_record(
4235 fee_payer: TnPubkey,
4236 name_service_program: TnPubkey,
4237 domain_account: TnPubkey,
4238 owner_account: TnPubkey,
4239 key: &[u8],
4240 value: &[u8],
4241 fee: u64,
4242 nonce: u64,
4243 start_slot: u64,
4244 ) -> Result<Transaction> {
4245 let mut tx = Transaction::new(fee_payer, name_service_program, fee, nonce)
4246 .with_start_slot(start_slot)
4247 .with_expiry_after(100)
4248 .with_compute_units(250_000)
4249 .with_state_units(10_000)
4250 .with_memory_units(10_000);
4251
4252 let accounts = [(domain_account, true), (owner_account, false)];
4253 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
4254 tx = tx_with_accounts;
4255
4256 let domain_account_idx = indices[0];
4257 let owner_account_idx = indices[1];
4258
4259 let instruction_data = build_name_service_append_record_instruction(
4260 domain_account_idx,
4261 owner_account_idx,
4262 key,
4263 value,
4264 )?;
4265
4266 Ok(tx.with_instructions(instruction_data))
4267 }
4268
4269 pub fn build_name_service_delete_record(
4271 fee_payer: TnPubkey,
4272 name_service_program: TnPubkey,
4273 domain_account: TnPubkey,
4274 owner_account: TnPubkey,
4275 key: &[u8],
4276 fee: u64,
4277 nonce: u64,
4278 start_slot: u64,
4279 ) -> Result<Transaction> {
4280 let mut tx = Transaction::new(fee_payer, name_service_program, fee, nonce)
4281 .with_start_slot(start_slot)
4282 .with_expiry_after(100)
4283 .with_compute_units(200_000)
4284 .with_state_units(10_000)
4285 .with_memory_units(10_000);
4286
4287 let accounts = [(domain_account, true), (owner_account, false)];
4288 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
4289 tx = tx_with_accounts;
4290
4291 let domain_account_idx = indices[0];
4292 let owner_account_idx = indices[1];
4293
4294 let instruction_data = build_name_service_delete_record_instruction(
4295 domain_account_idx,
4296 owner_account_idx,
4297 key,
4298 )?;
4299
4300 Ok(tx.with_instructions(instruction_data))
4301 }
4302
4303 pub fn build_name_service_unregister_subdomain(
4305 fee_payer: TnPubkey,
4306 name_service_program: TnPubkey,
4307 domain_account: TnPubkey,
4308 owner_account: TnPubkey,
4309 fee: u64,
4310 nonce: u64,
4311 start_slot: u64,
4312 ) -> Result<Transaction> {
4313 let mut tx = Transaction::new(fee_payer, name_service_program, fee, nonce)
4314 .with_start_slot(start_slot)
4315 .with_expiry_after(100)
4316 .with_compute_units(200_000)
4317 .with_state_units(10_000)
4318 .with_memory_units(10_000);
4319
4320 let accounts = [(domain_account, true), (owner_account, false)];
4321 let (tx_with_accounts, indices) = add_sorted_accounts(tx, &accounts);
4322 tx = tx_with_accounts;
4323
4324 let domain_account_idx = indices[0];
4325 let owner_account_idx = indices[1];
4326
4327 let instruction_data = build_name_service_unregister_subdomain_instruction(
4328 domain_account_idx,
4329 owner_account_idx,
4330 )?;
4331
4332 Ok(tx.with_instructions(instruction_data))
4333 }
4334
4335 pub fn build_thru_registrar_initialize_registry(
4337 fee_payer: TnPubkey,
4338 thru_registrar_program: TnPubkey,
4339 config_account: TnPubkey,
4340 name_service_program: TnPubkey,
4341 root_registrar_account: TnPubkey,
4342 treasurer_account: TnPubkey,
4343 token_mint_account: TnPubkey,
4344 token_program: TnPubkey,
4345 root_domain_name: &str,
4346 price_per_year: u64,
4347 config_proof: Vec<u8>,
4348 registrar_proof: Vec<u8>,
4349 fee: u64,
4350 nonce: u64,
4351 start_slot: u64,
4352 ) -> Result<Transaction> {
4353 let mut tx = Transaction::new(fee_payer, thru_registrar_program, fee, nonce)
4354 .with_start_slot(start_slot)
4355 .with_expiry_after(100)
4356 .with_compute_units(500_000)
4357 .with_state_units(10_000)
4358 .with_memory_units(10_000);
4359
4360 let mut rw_accounts = vec![config_account, root_registrar_account];
4363 rw_accounts.sort();
4364
4365 let mut ro_accounts = vec![
4366 name_service_program,
4367 treasurer_account,
4368 token_mint_account,
4369 token_program,
4370 ];
4371 ro_accounts.sort();
4372
4373 let mut config_account_idx = 0u16;
4375 let mut root_registrar_account_idx = 0u16;
4376 for (i, account) in rw_accounts.iter().enumerate() {
4377 let idx = (2 + i) as u16;
4378 if *account == config_account {
4379 config_account_idx = idx;
4380 } else if *account == root_registrar_account {
4381 root_registrar_account_idx = idx;
4382 }
4383 tx = tx.add_rw_account(*account);
4384 }
4385
4386 let base_ro_idx = 2 + rw_accounts.len() as u16;
4388 let mut name_service_program_idx = 0u16;
4389 let mut treasurer_account_idx = 0u16;
4390 let mut token_mint_account_idx = 0u16;
4391 let mut token_program_idx = 0u16;
4392
4393 for (i, account) in ro_accounts.iter().enumerate() {
4394 let idx = base_ro_idx + i as u16;
4395 if *account == name_service_program {
4396 name_service_program_idx = idx;
4397 } else if *account == root_registrar_account {
4398 root_registrar_account_idx = idx;
4399 } else if *account == treasurer_account {
4400 treasurer_account_idx = idx;
4401 } else if *account == token_mint_account {
4402 token_mint_account_idx = idx;
4403 } else if *account == token_program {
4404 token_program_idx = idx;
4405 }
4406 tx = tx.add_r_account(*account);
4407 }
4408
4409 let instruction_data = build_thru_registrar_initialize_registry_instruction(
4410 config_account_idx,
4411 name_service_program_idx,
4412 root_registrar_account_idx,
4413 treasurer_account_idx,
4414 token_mint_account_idx,
4415 token_program_idx,
4416 root_domain_name,
4417 price_per_year,
4418 config_proof,
4419 registrar_proof,
4420 )?;
4421
4422 Ok(tx.with_instructions(instruction_data))
4423 }
4424
4425 pub fn build_thru_registrar_purchase_domain(
4427 fee_payer: TnPubkey,
4428 thru_registrar_program: TnPubkey,
4429 config_account: TnPubkey,
4430 lease_account: TnPubkey,
4431 domain_account: TnPubkey,
4432 name_service_program: TnPubkey,
4433 root_registrar_account: TnPubkey,
4434 treasurer_account: TnPubkey,
4435 payer_token_account: TnPubkey,
4436 token_mint_account: TnPubkey,
4437 token_program: TnPubkey,
4438 domain_name: &str,
4439 years: u8,
4440 lease_proof: Vec<u8>,
4441 domain_proof: Vec<u8>,
4442 fee: u64,
4443 nonce: u64,
4444 start_slot: u64,
4445 ) -> Result<Transaction> {
4446 let mut tx = Transaction::new(fee_payer, thru_registrar_program, fee, nonce)
4447 .with_start_slot(start_slot)
4448 .with_expiry_after(100)
4449 .with_compute_units(500_000)
4450 .with_state_units(10_000)
4451 .with_memory_units(10_000);
4452
4453 let mut rw_accounts = vec![
4456 config_account,
4457 lease_account,
4458 domain_account,
4459 treasurer_account,
4460 payer_token_account,
4461 root_registrar_account,
4462 ];
4463 rw_accounts.sort();
4464
4465 let mut ro_accounts = vec![
4466 name_service_program,
4467 token_mint_account,
4468 token_program,
4469 ];
4470 ro_accounts.sort();
4471
4472 let mut config_account_idx = 0u16;
4474 let mut lease_account_idx = 0u16;
4475 let mut domain_account_idx = 0u16;
4476 let mut treasurer_account_idx = 0u16;
4477 let mut payer_token_account_idx = 0u16;
4478 let mut root_registrar_account_idx = 0u16;
4479 for (i, account) in rw_accounts.iter().enumerate() {
4480 let idx = (2 + i) as u16;
4481 if *account == config_account {
4482 config_account_idx = idx;
4483 } else if *account == lease_account {
4484 lease_account_idx = idx;
4485 } else if *account == domain_account {
4486 domain_account_idx = idx;
4487 } else if *account == treasurer_account {
4488 treasurer_account_idx = idx;
4489 } else if *account == payer_token_account {
4490 payer_token_account_idx = idx;
4491 } else if *account == root_registrar_account {
4492 root_registrar_account_idx = idx;
4493 }
4494 tx = tx.add_rw_account(*account);
4495 }
4496
4497 let base_ro_idx = 2 + rw_accounts.len() as u16;
4499 let mut name_service_program_idx = 0u16;
4500 let mut token_mint_account_idx = 0u16;
4501 let mut token_program_idx = 0u16;
4502
4503 for (i, account) in ro_accounts.iter().enumerate() {
4504 let idx = base_ro_idx + i as u16;
4505 if *account == config_account {
4506 config_account_idx = idx; } else if *account == name_service_program {
4508 name_service_program_idx = idx;
4509 } else if *account == root_registrar_account {
4510 root_registrar_account_idx = idx;
4511 } else if *account == treasurer_account {
4512 treasurer_account_idx = idx;
4513 } else if *account == payer_token_account {
4514 payer_token_account_idx = idx;
4515 } else if *account == token_mint_account {
4516 token_mint_account_idx = idx;
4517 } else if *account == token_program {
4518 token_program_idx = idx;
4519 }
4520 tx = tx.add_r_account(*account);
4521 }
4522
4523 let instruction_data = build_thru_registrar_purchase_domain_instruction(
4524 config_account_idx,
4525 lease_account_idx,
4526 domain_account_idx,
4527 name_service_program_idx,
4528 root_registrar_account_idx,
4529 treasurer_account_idx,
4530 payer_token_account_idx,
4531 token_mint_account_idx,
4532 token_program_idx,
4533 domain_name,
4534 years,
4535 lease_proof,
4536 domain_proof,
4537 )?;
4538
4539 Ok(tx.with_instructions(instruction_data))
4540 }
4541
4542 pub fn build_thru_registrar_renew_lease(
4544 fee_payer: TnPubkey,
4545 thru_registrar_program: TnPubkey,
4546 config_account: TnPubkey,
4547 lease_account: TnPubkey,
4548 treasurer_account: TnPubkey,
4549 payer_token_account: TnPubkey,
4550 token_mint_account: TnPubkey,
4551 token_program: TnPubkey,
4552 years: u8,
4553 fee: u64,
4554 nonce: u64,
4555 start_slot: u64,
4556 ) -> Result<Transaction> {
4557 let mut tx = Transaction::new(fee_payer, thru_registrar_program, fee, nonce)
4558 .with_start_slot(start_slot)
4559 .with_expiry_after(100)
4560 .with_compute_units(300_000)
4561 .with_state_units(10_000)
4562 .with_memory_units(10_000);
4563
4564 let mut rw_accounts = vec![lease_account, treasurer_account, payer_token_account];
4567 rw_accounts.sort();
4568
4569 let mut ro_accounts = vec![
4570 config_account,
4571 token_mint_account,
4572 token_program,
4573 ];
4574 ro_accounts.sort();
4575
4576 let mut lease_account_idx = 0u16;
4578 let mut treasurer_account_idx = 0u16;
4579 let mut payer_token_account_idx = 0u16;
4580 for (i, account) in rw_accounts.iter().enumerate() {
4581 let idx = (2 + i) as u16;
4582 if *account == lease_account {
4583 lease_account_idx = idx;
4584 } else if *account == treasurer_account {
4585 treasurer_account_idx = idx;
4586 } else if *account == payer_token_account {
4587 payer_token_account_idx = idx;
4588 }
4589 tx = tx.add_rw_account(*account);
4590 }
4591
4592 let base_ro_idx = 2 + rw_accounts.len() as u16;
4594 let mut config_account_idx = 0u16;
4595 let mut token_mint_account_idx = 0u16;
4596 let mut token_program_idx = 0u16;
4597
4598 for (i, account) in ro_accounts.iter().enumerate() {
4599 let idx = base_ro_idx + i as u16;
4600 if *account == config_account {
4601 config_account_idx = idx;
4602 } else if *account == token_mint_account {
4603 token_mint_account_idx = idx;
4604 } else if *account == token_program {
4605 token_program_idx = idx;
4606 }
4607 tx = tx.add_r_account(*account);
4608 }
4609
4610 let instruction_data = build_thru_registrar_renew_lease_instruction(
4611 config_account_idx,
4612 lease_account_idx,
4613 treasurer_account_idx,
4614 payer_token_account_idx,
4615 token_mint_account_idx,
4616 token_program_idx,
4617 years,
4618 )?;
4619
4620 Ok(tx.with_instructions(instruction_data))
4621 }
4622
4623 pub fn build_thru_registrar_claim_expired_domain(
4625 fee_payer: TnPubkey,
4626 thru_registrar_program: TnPubkey,
4627 config_account: TnPubkey,
4628 lease_account: TnPubkey,
4629 treasurer_account: TnPubkey,
4630 payer_token_account: TnPubkey,
4631 token_mint_account: TnPubkey,
4632 token_program: TnPubkey,
4633 years: u8,
4634 fee: u64,
4635 nonce: u64,
4636 start_slot: u64,
4637 ) -> Result<Transaction> {
4638 let mut tx = Transaction::new(fee_payer, thru_registrar_program, fee, nonce)
4639 .with_start_slot(start_slot)
4640 .with_expiry_after(100)
4641 .with_compute_units(300_000)
4642 .with_state_units(10_000)
4643 .with_memory_units(10_000);
4644
4645 let mut rw_accounts = vec![lease_account, treasurer_account, payer_token_account];
4648 rw_accounts.sort();
4649
4650 let mut ro_accounts = vec![
4651 config_account,
4652 token_mint_account,
4653 token_program,
4654 ];
4655 ro_accounts.sort();
4656
4657 let mut lease_account_idx = 0u16;
4659 let mut treasurer_account_idx = 0u16;
4660 let mut payer_token_account_idx = 0u16;
4661 for (i, account) in rw_accounts.iter().enumerate() {
4662 let idx = (2 + i) as u16;
4663 if *account == lease_account {
4664 lease_account_idx = idx;
4665 } else if *account == treasurer_account {
4666 treasurer_account_idx = idx;
4667 } else if *account == payer_token_account {
4668 payer_token_account_idx = idx;
4669 }
4670 tx = tx.add_rw_account(*account);
4671 }
4672
4673 let base_ro_idx = 2 + rw_accounts.len() as u16;
4675 let mut config_account_idx = 0u16;
4676 let mut token_mint_account_idx = 0u16;
4677 let mut token_program_idx = 0u16;
4678
4679 for (i, account) in ro_accounts.iter().enumerate() {
4680 let idx = base_ro_idx + i as u16;
4681 if *account == config_account {
4682 config_account_idx = idx;
4683 } else if *account == token_mint_account {
4684 token_mint_account_idx = idx;
4685 } else if *account == token_program {
4686 token_program_idx = idx;
4687 }
4688 tx = tx.add_r_account(*account);
4689 }
4690
4691 let instruction_data = build_thru_registrar_claim_expired_domain_instruction(
4692 config_account_idx,
4693 lease_account_idx,
4694 treasurer_account_idx,
4695 payer_token_account_idx,
4696 token_mint_account_idx,
4697 token_program_idx,
4698 years,
4699 )?;
4700
4701 Ok(tx.with_instructions(instruction_data))
4702 }
4703}
4704
4705fn build_token_initialize_mint_instruction(
4707 mint_account_idx: u16,
4708 decimals: u8,
4709 creator: TnPubkey,
4710 mint_authority: TnPubkey,
4711 freeze_authority: Option<TnPubkey>,
4712 ticker: &str,
4713 seed: [u8; 32],
4714 state_proof: Vec<u8>,
4715) -> Result<Vec<u8>> {
4716 let mut instruction_data = Vec::new();
4717
4718 instruction_data.push(TOKEN_INSTRUCTION_INITIALIZE_MINT);
4720
4721 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
4723
4724 instruction_data.push(decimals);
4726
4727 instruction_data.extend_from_slice(&creator);
4729
4730 instruction_data.extend_from_slice(&mint_authority);
4732
4733 let (freeze_auth, has_freeze_auth) = match freeze_authority {
4735 Some(auth) => (auth, 1u8),
4736 None => ([0u8; 32], 0u8),
4737 };
4738 instruction_data.extend_from_slice(&freeze_auth);
4739 instruction_data.push(has_freeze_auth);
4740
4741 let ticker_bytes = ticker.as_bytes();
4743 if ticker_bytes.len() > 8 {
4744 return Err(anyhow::anyhow!("Ticker must be 8 characters or less"));
4745 }
4746
4747 instruction_data.push(ticker_bytes.len() as u8);
4748 let mut ticker_padded = [0u8; 8];
4749 ticker_padded[..ticker_bytes.len()].copy_from_slice(ticker_bytes);
4750 instruction_data.extend_from_slice(&ticker_padded);
4751
4752 instruction_data.extend_from_slice(&seed);
4754
4755 instruction_data.extend_from_slice(&state_proof);
4757
4758 Ok(instruction_data)
4759}
4760
4761fn build_token_initialize_account_instruction(
4763 token_account_idx: u16,
4764 mint_account_idx: u16,
4765 owner_account_idx: u16,
4766 seed: [u8; 32],
4767 state_proof: Vec<u8>,
4768) -> Result<Vec<u8>> {
4769 let mut instruction_data = Vec::new();
4770
4771 instruction_data.push(TOKEN_INSTRUCTION_INITIALIZE_ACCOUNT);
4773
4774 instruction_data.extend_from_slice(&token_account_idx.to_le_bytes());
4776
4777 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
4779
4780 instruction_data.extend_from_slice(&owner_account_idx.to_le_bytes());
4782
4783 instruction_data.extend_from_slice(&seed);
4785
4786 instruction_data.extend_from_slice(&state_proof);
4788
4789 Ok(instruction_data)
4790}
4791
4792fn build_token_transfer_instruction(
4794 source_account_idx: u16,
4795 dest_account_idx: u16,
4796 amount: u64,
4797) -> Result<Vec<u8>> {
4798 let mut instruction_data = Vec::new();
4799
4800 instruction_data.push(TOKEN_INSTRUCTION_TRANSFER);
4802
4803 instruction_data.extend_from_slice(&source_account_idx.to_le_bytes());
4805
4806 instruction_data.extend_from_slice(&dest_account_idx.to_le_bytes());
4808
4809 instruction_data.extend_from_slice(&amount.to_le_bytes());
4811
4812 Ok(instruction_data)
4813}
4814
4815fn build_token_mint_to_instruction(
4817 mint_account_idx: u16,
4818 dest_account_idx: u16,
4819 authority_idx: u16,
4820 amount: u64,
4821) -> Result<Vec<u8>> {
4822 let mut instruction_data = Vec::new();
4823
4824 instruction_data.push(TOKEN_INSTRUCTION_MINT_TO);
4826
4827 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
4829
4830 instruction_data.extend_from_slice(&dest_account_idx.to_le_bytes());
4832
4833 instruction_data.extend_from_slice(&authority_idx.to_le_bytes());
4835
4836 instruction_data.extend_from_slice(&amount.to_le_bytes());
4838
4839 Ok(instruction_data)
4840}
4841
4842fn build_token_burn_instruction(
4844 token_account_idx: u16,
4845 mint_account_idx: u16,
4846 authority_idx: u16,
4847 amount: u64,
4848) -> Result<Vec<u8>> {
4849 let mut instruction_data = Vec::new();
4850
4851 instruction_data.push(TOKEN_INSTRUCTION_BURN);
4853
4854 instruction_data.extend_from_slice(&token_account_idx.to_le_bytes());
4856
4857 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
4859
4860 instruction_data.extend_from_slice(&authority_idx.to_le_bytes());
4862
4863 instruction_data.extend_from_slice(&amount.to_le_bytes());
4865
4866 Ok(instruction_data)
4867}
4868
4869fn build_token_freeze_account_instruction(
4871 token_account_idx: u16,
4872 mint_account_idx: u16,
4873 authority_idx: u16,
4874) -> Result<Vec<u8>> {
4875 let mut instruction_data = Vec::new();
4876
4877 instruction_data.push(TOKEN_INSTRUCTION_FREEZE_ACCOUNT);
4879
4880 instruction_data.extend_from_slice(&token_account_idx.to_le_bytes());
4882
4883 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
4885
4886 instruction_data.extend_from_slice(&authority_idx.to_le_bytes());
4888
4889 Ok(instruction_data)
4890}
4891
4892fn build_token_thaw_account_instruction(
4894 token_account_idx: u16,
4895 mint_account_idx: u16,
4896 authority_idx: u16,
4897) -> Result<Vec<u8>> {
4898 let mut instruction_data = Vec::new();
4899
4900 instruction_data.push(TOKEN_INSTRUCTION_THAW_ACCOUNT);
4902
4903 instruction_data.extend_from_slice(&token_account_idx.to_le_bytes());
4905
4906 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
4908
4909 instruction_data.extend_from_slice(&authority_idx.to_le_bytes());
4911
4912 Ok(instruction_data)
4913}
4914
4915fn build_token_close_account_instruction(
4917 token_account_idx: u16,
4918 destination_idx: u16,
4919 authority_idx: u16,
4920) -> Result<Vec<u8>> {
4921 let mut instruction_data = Vec::new();
4922
4923 instruction_data.push(TOKEN_INSTRUCTION_CLOSE_ACCOUNT);
4925
4926 instruction_data.extend_from_slice(&token_account_idx.to_le_bytes());
4928
4929 instruction_data.extend_from_slice(&destination_idx.to_le_bytes());
4931
4932 instruction_data.extend_from_slice(&authority_idx.to_le_bytes());
4934
4935 Ok(instruction_data)
4936}
4937
4938fn build_wthru_initialize_mint_instruction(
4939 token_program_idx: u16,
4940 mint_account_idx: u16,
4941 vault_account_idx: u16,
4942 decimals: u8,
4943 mint_seed: [u8; 32],
4944 mint_proof: Vec<u8>,
4945 vault_proof: Vec<u8>,
4946) -> Result<Vec<u8>> {
4947 let mint_proof_len =
4948 u64::try_from(mint_proof.len()).map_err(|_| anyhow::anyhow!("mint proof too large"))?;
4949 let vault_proof_len =
4950 u64::try_from(vault_proof.len()).map_err(|_| anyhow::anyhow!("vault proof too large"))?;
4951
4952 let mut instruction_data = Vec::new();
4953 instruction_data.extend_from_slice(&TN_WTHRU_INSTRUCTION_INITIALIZE_MINT.to_le_bytes());
4954 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
4955 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
4956 instruction_data.extend_from_slice(&vault_account_idx.to_le_bytes());
4957 instruction_data.push(decimals);
4958 instruction_data.extend_from_slice(&mint_seed);
4959 instruction_data.extend_from_slice(&mint_proof_len.to_le_bytes());
4960 instruction_data.extend_from_slice(&vault_proof_len.to_le_bytes());
4961 instruction_data.extend_from_slice(&mint_proof);
4962 instruction_data.extend_from_slice(&vault_proof);
4963
4964 Ok(instruction_data)
4965}
4966
4967fn build_wthru_deposit_instruction(
4968 token_program_idx: u16,
4969 vault_account_idx: u16,
4970 mint_account_idx: u16,
4971 dest_account_idx: u16,
4972) -> Result<Vec<u8>> {
4973 let mut instruction_data = Vec::new();
4974 instruction_data.extend_from_slice(&TN_WTHRU_INSTRUCTION_DEPOSIT.to_le_bytes());
4975 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
4976 instruction_data.extend_from_slice(&vault_account_idx.to_le_bytes());
4977 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
4978 instruction_data.extend_from_slice(&dest_account_idx.to_le_bytes());
4979
4980 Ok(instruction_data)
4981}
4982
4983fn build_wthru_withdraw_instruction(
4984 token_program_idx: u16,
4985 vault_account_idx: u16,
4986 mint_account_idx: u16,
4987 wthru_token_account_idx: u16,
4988 owner_account_idx: u16,
4989 recipient_account_idx: u16,
4990 amount: u64,
4991) -> Result<Vec<u8>> {
4992 let mut instruction_data = Vec::new();
4993 instruction_data.extend_from_slice(&TN_WTHRU_INSTRUCTION_WITHDRAW.to_le_bytes());
4994 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
4995 instruction_data.extend_from_slice(&vault_account_idx.to_le_bytes());
4996 instruction_data.extend_from_slice(&mint_account_idx.to_le_bytes());
4997 instruction_data.extend_from_slice(&wthru_token_account_idx.to_le_bytes());
4998 instruction_data.extend_from_slice(&owner_account_idx.to_le_bytes());
4999 instruction_data.extend_from_slice(&recipient_account_idx.to_le_bytes());
5000 instruction_data.extend_from_slice(&amount.to_le_bytes());
5001
5002 Ok(instruction_data)
5003}
5004
5005fn build_faucet_deposit_instruction(
5007 faucet_account_idx: u16,
5008 depositor_account_idx: u16,
5009 eoa_program_idx: u16,
5010 amount: u64,
5011) -> Result<Vec<u8>> {
5012 let mut instruction_data = Vec::new();
5013
5014 instruction_data.extend_from_slice(&0u32.to_le_bytes());
5016
5017 instruction_data.extend_from_slice(&faucet_account_idx.to_le_bytes());
5020
5021 instruction_data.extend_from_slice(&depositor_account_idx.to_le_bytes());
5023
5024 instruction_data.extend_from_slice(&eoa_program_idx.to_le_bytes());
5026
5027 instruction_data.extend_from_slice(&amount.to_le_bytes());
5029
5030 Ok(instruction_data)
5031}
5032
5033fn build_faucet_withdraw_instruction(
5035 faucet_account_idx: u16,
5036 recipient_account_idx: u16,
5037 amount: u64,
5038) -> Result<Vec<u8>> {
5039 let mut instruction_data = Vec::new();
5040
5041 instruction_data.extend_from_slice(&1u32.to_le_bytes());
5043
5044 instruction_data.extend_from_slice(&faucet_account_idx.to_le_bytes());
5047
5048 instruction_data.extend_from_slice(&recipient_account_idx.to_le_bytes());
5050
5051 instruction_data.extend_from_slice(&amount.to_le_bytes());
5053
5054 Ok(instruction_data)
5055}
5056
5057fn build_activate_instruction(
5060 attestor_table_idx: u64,
5061 token_program_idx: u16,
5062 source_token_account_idx: u16,
5063 converted_vault_idx: u16,
5064 identity_idx: u16,
5065 bls_pk: [u8; 96],
5066 claim_authority: [u8; 32],
5067 token_amount: u64,
5068) -> Result<Vec<u8>> {
5069 let mut instruction_data = Vec::new();
5070
5071 instruction_data.extend_from_slice(&1u32.to_le_bytes());
5073
5074 instruction_data.extend_from_slice(&attestor_table_idx.to_le_bytes());
5077
5078 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
5080
5081 instruction_data.extend_from_slice(&source_token_account_idx.to_le_bytes());
5083
5084 instruction_data.extend_from_slice(&converted_vault_idx.to_le_bytes());
5086
5087 instruction_data.extend_from_slice(&identity_idx.to_le_bytes());
5089
5090 instruction_data.extend_from_slice(&bls_pk);
5092
5093 instruction_data.extend_from_slice(&claim_authority);
5095
5096 instruction_data.extend_from_slice(&token_amount.to_le_bytes());
5098
5099 Ok(instruction_data)
5100}
5101
5102#[repr(C, packed)]
5103struct NameServiceInitializeRootArgs {
5104 registrar_account_idx: u16,
5105 authority_account_idx: u16,
5106 root_name: [u8; TN_NAME_SERVICE_MAX_DOMAIN_LENGTH],
5107 root_name_length: u32,
5108}
5109
5110#[repr(C, packed)]
5111struct NameServiceRegisterSubdomainArgs {
5112 domain_account_idx: u16,
5113 parent_account_idx: u16,
5114 owner_account_idx: u16,
5115 authority_account_idx: u16,
5116 name: [u8; TN_NAME_SERVICE_MAX_DOMAIN_LENGTH],
5117 name_length: u32,
5118}
5119
5120#[repr(C, packed)]
5121struct NameServiceAppendRecordArgs {
5122 domain_account_idx: u16,
5123 owner_account_idx: u16,
5124 key_length: u32,
5125 key: [u8; TN_NAME_SERVICE_MAX_KEY_LENGTH],
5126 value_length: u32,
5127 value: [u8; TN_NAME_SERVICE_MAX_VALUE_LENGTH],
5128}
5129
5130#[repr(C, packed)]
5131struct NameServiceDeleteRecordArgs {
5132 domain_account_idx: u16,
5133 owner_account_idx: u16,
5134 key_length: u32,
5135 key: [u8; TN_NAME_SERVICE_MAX_KEY_LENGTH],
5136}
5137
5138#[repr(C, packed)]
5139struct NameServiceUnregisterSubdomainArgs {
5140 domain_account_idx: u16,
5141 owner_account_idx: u16,
5142}
5143
5144fn build_name_service_initialize_root_instruction(
5146 registrar_account_idx: u16,
5147 authority_account_idx: u16,
5148 root_name: &str,
5149 state_proof: Vec<u8>,
5150) -> Result<Vec<u8>> {
5151 let root_name_bytes = root_name.as_bytes();
5152 if root_name_bytes.is_empty()
5153 || root_name_bytes.len() > TN_NAME_SERVICE_MAX_DOMAIN_LENGTH
5154 {
5155 return Err(anyhow::anyhow!(
5156 "Root name length must be between 1 and {}",
5157 TN_NAME_SERVICE_MAX_DOMAIN_LENGTH
5158 ));
5159 }
5160
5161 let mut args = NameServiceInitializeRootArgs {
5162 registrar_account_idx,
5163 authority_account_idx,
5164 root_name: [0u8; TN_NAME_SERVICE_MAX_DOMAIN_LENGTH],
5165 root_name_length: root_name_bytes.len() as u32,
5166 };
5167 args.root_name[..root_name_bytes.len()].copy_from_slice(root_name_bytes);
5168
5169 let mut instruction_data = Vec::new();
5170 instruction_data.extend_from_slice(&TN_NAME_SERVICE_INSTRUCTION_INITIALIZE_ROOT.to_le_bytes());
5171
5172 let args_bytes = unsafe {
5173 std::slice::from_raw_parts(
5174 &args as *const _ as *const u8,
5175 std::mem::size_of::<NameServiceInitializeRootArgs>(),
5176 )
5177 };
5178 instruction_data.extend_from_slice(args_bytes);
5179
5180 instruction_data.extend_from_slice(&TN_NAME_SERVICE_PROOF_INLINE.to_le_bytes());
5181 instruction_data.extend_from_slice(&state_proof);
5182
5183 Ok(instruction_data)
5184}
5185
5186fn build_name_service_register_subdomain_instruction(
5188 domain_account_idx: u16,
5189 parent_account_idx: u16,
5190 owner_account_idx: u16,
5191 authority_account_idx: u16,
5192 domain_name: &str,
5193 state_proof: Vec<u8>,
5194) -> Result<Vec<u8>> {
5195 let domain_bytes = domain_name.as_bytes();
5196 if domain_bytes.is_empty()
5197 || domain_bytes.len() > TN_NAME_SERVICE_MAX_DOMAIN_LENGTH
5198 {
5199 return Err(anyhow::anyhow!(
5200 "Domain name length must be between 1 and {}",
5201 TN_NAME_SERVICE_MAX_DOMAIN_LENGTH
5202 ));
5203 }
5204
5205 let mut args = NameServiceRegisterSubdomainArgs {
5206 domain_account_idx,
5207 parent_account_idx,
5208 owner_account_idx,
5209 authority_account_idx,
5210 name: [0u8; TN_NAME_SERVICE_MAX_DOMAIN_LENGTH],
5211 name_length: domain_bytes.len() as u32,
5212 };
5213 args.name[..domain_bytes.len()].copy_from_slice(domain_bytes);
5214
5215 let mut instruction_data = Vec::new();
5216 instruction_data.extend_from_slice(&TN_NAME_SERVICE_INSTRUCTION_REGISTER_SUBDOMAIN.to_le_bytes());
5217
5218 let args_bytes = unsafe {
5219 std::slice::from_raw_parts(
5220 &args as *const _ as *const u8,
5221 std::mem::size_of::<NameServiceRegisterSubdomainArgs>(),
5222 )
5223 };
5224 instruction_data.extend_from_slice(args_bytes);
5225
5226 instruction_data.extend_from_slice(&TN_NAME_SERVICE_PROOF_INLINE.to_le_bytes());
5227 instruction_data.extend_from_slice(&state_proof);
5228
5229 Ok(instruction_data)
5230}
5231
5232fn build_name_service_append_record_instruction(
5234 domain_account_idx: u16,
5235 owner_account_idx: u16,
5236 key: &[u8],
5237 value: &[u8],
5238) -> Result<Vec<u8>> {
5239 if key.is_empty() || key.len() > TN_NAME_SERVICE_MAX_KEY_LENGTH {
5240 return Err(anyhow::anyhow!(
5241 "Key length must be between 1 and {} bytes",
5242 TN_NAME_SERVICE_MAX_KEY_LENGTH
5243 ));
5244 }
5245 if value.len() > TN_NAME_SERVICE_MAX_VALUE_LENGTH {
5246 return Err(anyhow::anyhow!(
5247 "Value length must be <= {} bytes",
5248 TN_NAME_SERVICE_MAX_VALUE_LENGTH
5249 ));
5250 }
5251
5252 let mut args = NameServiceAppendRecordArgs {
5253 domain_account_idx,
5254 owner_account_idx,
5255 key_length: key.len() as u32,
5256 key: [0u8; TN_NAME_SERVICE_MAX_KEY_LENGTH],
5257 value_length: value.len() as u32,
5258 value: [0u8; TN_NAME_SERVICE_MAX_VALUE_LENGTH],
5259 };
5260 args.key[..key.len()].copy_from_slice(key);
5261 args.value[..value.len()].copy_from_slice(value);
5262
5263 let mut instruction_data = Vec::new();
5264 instruction_data.extend_from_slice(&TN_NAME_SERVICE_INSTRUCTION_APPEND_RECORD.to_le_bytes());
5265
5266 let args_bytes = unsafe {
5267 std::slice::from_raw_parts(
5268 &args as *const _ as *const u8,
5269 std::mem::size_of::<NameServiceAppendRecordArgs>(),
5270 )
5271 };
5272 instruction_data.extend_from_slice(args_bytes);
5273
5274 Ok(instruction_data)
5275}
5276
5277fn build_name_service_delete_record_instruction(
5279 domain_account_idx: u16,
5280 owner_account_idx: u16,
5281 key: &[u8],
5282) -> Result<Vec<u8>> {
5283 if key.is_empty() || key.len() > TN_NAME_SERVICE_MAX_KEY_LENGTH {
5284 return Err(anyhow::anyhow!(
5285 "Key length must be between 1 and {} bytes",
5286 TN_NAME_SERVICE_MAX_KEY_LENGTH
5287 ));
5288 }
5289
5290 let mut args = NameServiceDeleteRecordArgs {
5291 domain_account_idx,
5292 owner_account_idx,
5293 key_length: key.len() as u32,
5294 key: [0u8; TN_NAME_SERVICE_MAX_KEY_LENGTH],
5295 };
5296 args.key[..key.len()].copy_from_slice(key);
5297
5298 let mut instruction_data = Vec::new();
5299 instruction_data.extend_from_slice(&TN_NAME_SERVICE_INSTRUCTION_DELETE_RECORD.to_le_bytes());
5300
5301 let args_bytes = unsafe {
5302 std::slice::from_raw_parts(
5303 &args as *const _ as *const u8,
5304 std::mem::size_of::<NameServiceDeleteRecordArgs>(),
5305 )
5306 };
5307 instruction_data.extend_from_slice(args_bytes);
5308
5309 Ok(instruction_data)
5310}
5311
5312fn build_name_service_unregister_subdomain_instruction(
5314 domain_account_idx: u16,
5315 owner_account_idx: u16,
5316) -> Result<Vec<u8>> {
5317 let args = NameServiceUnregisterSubdomainArgs {
5318 domain_account_idx,
5319 owner_account_idx,
5320 };
5321
5322 let mut instruction_data = Vec::new();
5323 instruction_data.extend_from_slice(&TN_NAME_SERVICE_INSTRUCTION_UNREGISTER.to_le_bytes());
5324
5325 let args_bytes = unsafe {
5326 std::slice::from_raw_parts(
5327 &args as *const _ as *const u8,
5328 std::mem::size_of::<NameServiceUnregisterSubdomainArgs>(),
5329 )
5330 };
5331 instruction_data.extend_from_slice(args_bytes);
5332
5333 Ok(instruction_data)
5334}
5335
5336fn build_thru_registrar_initialize_registry_instruction(
5338 config_account_idx: u16,
5339 name_service_program_idx: u16,
5340 root_registrar_account_idx: u16,
5341 treasurer_account_idx: u16,
5342 token_mint_account_idx: u16,
5343 token_program_idx: u16,
5344 root_domain_name: &str,
5345 price_per_year: u64,
5346 config_proof: Vec<u8>,
5347 registrar_proof: Vec<u8>,
5348) -> Result<Vec<u8>> {
5349 let mut instruction_data = Vec::new();
5350
5351 instruction_data.extend_from_slice(&TN_THRU_REGISTRAR_INSTRUCTION_INITIALIZE_REGISTRY.to_le_bytes());
5353
5354 instruction_data.extend_from_slice(&config_account_idx.to_le_bytes());
5357 instruction_data.extend_from_slice(&name_service_program_idx.to_le_bytes());
5359 instruction_data.extend_from_slice(&root_registrar_account_idx.to_le_bytes());
5361 instruction_data.extend_from_slice(&treasurer_account_idx.to_le_bytes());
5363 instruction_data.extend_from_slice(&token_mint_account_idx.to_le_bytes());
5365 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
5367 let domain_bytes = root_domain_name.as_bytes();
5369 if domain_bytes.len() > 64 {
5370 return Err(anyhow::anyhow!("Root domain name must be 64 characters or less"));
5371 }
5372 let mut domain_padded = [0u8; 64];
5373 domain_padded[..domain_bytes.len()].copy_from_slice(domain_bytes);
5374 instruction_data.extend_from_slice(&domain_padded);
5375 instruction_data.extend_from_slice(&(domain_bytes.len() as u32).to_le_bytes());
5377 instruction_data.extend_from_slice(&price_per_year.to_le_bytes());
5379
5380 instruction_data.extend_from_slice(&config_proof);
5383 instruction_data.extend_from_slice(®istrar_proof);
5385
5386 Ok(instruction_data)
5387}
5388
5389fn build_thru_registrar_purchase_domain_instruction(
5391 config_account_idx: u16,
5392 lease_account_idx: u16,
5393 domain_account_idx: u16,
5394 name_service_program_idx: u16,
5395 root_registrar_account_idx: u16,
5396 treasurer_account_idx: u16,
5397 payer_token_account_idx: u16,
5398 token_mint_account_idx: u16,
5399 token_program_idx: u16,
5400 domain_name: &str,
5401 years: u8,
5402 lease_proof: Vec<u8>,
5403 domain_proof: Vec<u8>,
5404) -> Result<Vec<u8>> {
5405 let mut instruction_data = Vec::new();
5406
5407 instruction_data.extend_from_slice(&TN_THRU_REGISTRAR_INSTRUCTION_PURCHASE_DOMAIN.to_le_bytes());
5409
5410 instruction_data.extend_from_slice(&config_account_idx.to_le_bytes());
5413 instruction_data.extend_from_slice(&lease_account_idx.to_le_bytes());
5415 instruction_data.extend_from_slice(&domain_account_idx.to_le_bytes());
5417 instruction_data.extend_from_slice(&name_service_program_idx.to_le_bytes());
5419 instruction_data.extend_from_slice(&root_registrar_account_idx.to_le_bytes());
5421 instruction_data.extend_from_slice(&treasurer_account_idx.to_le_bytes());
5423 instruction_data.extend_from_slice(&payer_token_account_idx.to_le_bytes());
5425 instruction_data.extend_from_slice(&token_mint_account_idx.to_le_bytes());
5427 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
5429 let domain_bytes = domain_name.as_bytes();
5431 if domain_bytes.len() > 64 {
5432 return Err(anyhow::anyhow!("Domain name must be 64 characters or less"));
5433 }
5434 let mut domain_padded = [0u8; 64];
5435 domain_padded[..domain_bytes.len()].copy_from_slice(domain_bytes);
5436 instruction_data.extend_from_slice(&domain_padded);
5437 instruction_data.extend_from_slice(&(domain_bytes.len() as u32).to_le_bytes());
5439 instruction_data.push(years);
5441
5442 instruction_data.extend_from_slice(&lease_proof);
5445 instruction_data.extend_from_slice(&domain_proof);
5447
5448 Ok(instruction_data)
5449}
5450
5451fn build_thru_registrar_renew_lease_instruction(
5453 config_account_idx: u16,
5454 lease_account_idx: u16,
5455 treasurer_account_idx: u16,
5456 payer_token_account_idx: u16,
5457 token_mint_account_idx: u16,
5458 token_program_idx: u16,
5459 years: u8,
5460) -> Result<Vec<u8>> {
5461 let mut instruction_data = Vec::new();
5462
5463 instruction_data.extend_from_slice(&TN_THRU_REGISTRAR_INSTRUCTION_RENEW_LEASE.to_le_bytes());
5465
5466 instruction_data.extend_from_slice(&config_account_idx.to_le_bytes());
5469 instruction_data.extend_from_slice(&lease_account_idx.to_le_bytes());
5471 instruction_data.extend_from_slice(&treasurer_account_idx.to_le_bytes());
5473 instruction_data.extend_from_slice(&payer_token_account_idx.to_le_bytes());
5475 instruction_data.extend_from_slice(&token_mint_account_idx.to_le_bytes());
5477 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
5479 instruction_data.push(years);
5481
5482 Ok(instruction_data)
5483}
5484
5485fn build_thru_registrar_claim_expired_domain_instruction(
5487 config_account_idx: u16,
5488 lease_account_idx: u16,
5489 treasurer_account_idx: u16,
5490 payer_token_account_idx: u16,
5491 token_mint_account_idx: u16,
5492 token_program_idx: u16,
5493 years: u8,
5494) -> Result<Vec<u8>> {
5495 let mut instruction_data = Vec::new();
5496
5497 instruction_data.extend_from_slice(&TN_THRU_REGISTRAR_INSTRUCTION_CLAIM_EXPIRED_DOMAIN.to_le_bytes());
5499
5500 instruction_data.extend_from_slice(&config_account_idx.to_le_bytes());
5503 instruction_data.extend_from_slice(&lease_account_idx.to_le_bytes());
5505 instruction_data.extend_from_slice(&treasurer_account_idx.to_le_bytes());
5507 instruction_data.extend_from_slice(&payer_token_account_idx.to_le_bytes());
5509 instruction_data.extend_from_slice(&token_mint_account_idx.to_le_bytes());
5511 instruction_data.extend_from_slice(&token_program_idx.to_le_bytes());
5513 instruction_data.push(years);
5515
5516 Ok(instruction_data)
5517}