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