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