1use crate::{
4 ata::{get_associated_token_address_with_program, TokenProgram},
5 error::{Result, TallyError},
6 pda, program_id,
7 program_types::{
8 AdminWithdrawFeesArgs, CancelSubscriptionArgs, CreatePlanArgs, InitConfigArgs,
9 InitMerchantArgs, Merchant, Plan, StartSubscriptionArgs, UpdateConfigArgs, UpdatePlanArgs,
10 UpdatePlanTermsArgs,
11 },
12};
13use anchor_client::solana_sdk::instruction::{AccountMeta, Instruction};
14use anchor_lang::prelude::*;
15use anchor_lang::system_program;
16use spl_token::instruction::{approve_checked as approve_checked_token, revoke as revoke_token};
17use spl_token_2022::instruction::{
18 approve_checked as approve_checked_token2022, revoke as revoke_token2022,
19};
20
21#[derive(Clone, Debug, Default)]
23pub struct StartSubscriptionBuilder {
24 plan: Option<Pubkey>,
25 subscriber: Option<Pubkey>,
26 payer: Option<Pubkey>,
27 allowance_periods: Option<u8>,
28 token_program: Option<TokenProgram>,
29 program_id: Option<Pubkey>,
30}
31
32#[derive(Clone, Debug, Default)]
34pub struct CancelSubscriptionBuilder {
35 plan: Option<Pubkey>,
36 subscriber: Option<Pubkey>,
37 payer: Option<Pubkey>,
38 token_program: Option<TokenProgram>,
39 program_id: Option<Pubkey>,
40}
41
42#[derive(Clone, Debug, Default)]
44pub struct CreateMerchantBuilder {
45 authority: Option<Pubkey>,
46 payer: Option<Pubkey>,
47 usdc_mint: Option<Pubkey>,
48 treasury_ata: Option<Pubkey>,
49 platform_fee_bps: Option<u16>,
50 program_id: Option<Pubkey>,
51}
52
53#[derive(Clone, Debug, Default)]
55pub struct CreatePlanBuilder {
56 authority: Option<Pubkey>,
57 payer: Option<Pubkey>,
58 plan_args: Option<CreatePlanArgs>,
59 program_id: Option<Pubkey>,
60}
61
62#[derive(Clone, Debug, Default)]
64pub struct UpdatePlanBuilder {
65 authority: Option<Pubkey>,
66 payer: Option<Pubkey>,
67 plan_key: Option<Pubkey>,
68 update_args: Option<UpdatePlanArgs>,
69 program_id: Option<Pubkey>,
70}
71
72#[derive(Clone, Debug, Default)]
74pub struct AdminWithdrawFeesBuilder {
75 platform_authority: Option<Pubkey>,
76 platform_treasury_ata: Option<Pubkey>,
77 destination_ata: Option<Pubkey>,
78 usdc_mint: Option<Pubkey>,
79 amount: Option<u64>,
80 program_id: Option<Pubkey>,
81}
82
83#[derive(Clone, Debug, Default)]
85pub struct InitConfigBuilder {
86 authority: Option<Pubkey>,
87 payer: Option<Pubkey>,
88 config_args: Option<InitConfigArgs>,
89 program_id: Option<Pubkey>,
90}
91
92#[derive(Clone, Debug, Default)]
94pub struct RenewSubscriptionBuilder {
95 plan: Option<Pubkey>,
96 subscriber: Option<Pubkey>,
97 keeper: Option<Pubkey>,
98 keeper_ata: Option<Pubkey>,
99 token_program: Option<TokenProgram>,
100 program_id: Option<Pubkey>,
101}
102
103#[derive(Clone, Debug, Default)]
105pub struct CloseSubscriptionBuilder {
106 plan: Option<Pubkey>,
107 subscriber: Option<Pubkey>,
108 program_id: Option<Pubkey>,
109}
110
111#[derive(Clone, Debug, Default)]
113pub struct TransferAuthorityBuilder {
114 platform_authority: Option<Pubkey>,
115 new_authority: Option<Pubkey>,
116 program_id: Option<Pubkey>,
117}
118
119#[derive(Clone, Debug, Default)]
121pub struct AcceptAuthorityBuilder {
122 new_authority: Option<Pubkey>,
123 program_id: Option<Pubkey>,
124}
125
126#[derive(Clone, Debug, Default)]
128pub struct CancelAuthorityTransferBuilder {
129 platform_authority: Option<Pubkey>,
130 program_id: Option<Pubkey>,
131}
132
133#[derive(Clone, Debug, Default)]
135pub struct PauseBuilder {
136 platform_authority: Option<Pubkey>,
137 program_id: Option<Pubkey>,
138}
139
140#[derive(Clone, Debug, Default)]
142pub struct UnpauseBuilder {
143 platform_authority: Option<Pubkey>,
144 program_id: Option<Pubkey>,
145}
146
147#[derive(Clone, Debug, Default)]
149pub struct UpdateConfigBuilder {
150 platform_authority: Option<Pubkey>,
151 keeper_fee_bps: Option<u16>,
152 max_withdrawal_amount: Option<u64>,
153 max_grace_period_seconds: Option<u64>,
154 min_platform_fee_bps: Option<u16>,
155 max_platform_fee_bps: Option<u16>,
156 min_period_seconds: Option<u64>,
157 default_allowance_periods: Option<u8>,
158 program_id: Option<Pubkey>,
159}
160
161#[derive(Clone, Debug, Default)]
163pub struct UpdateMerchantTierBuilder {
164 authority: Option<Pubkey>,
165 merchant: Option<Pubkey>,
166 new_tier: Option<u8>,
167 program_id: Option<Pubkey>,
168}
169
170#[derive(Clone, Debug, Default)]
172pub struct UpdatePlanTermsBuilder {
173 authority: Option<Pubkey>,
174 plan_key: Option<Pubkey>,
175 price_usdc: Option<u64>,
176 period_secs: Option<u64>,
177 grace_secs: Option<u64>,
178 name: Option<String>,
179 program_id: Option<Pubkey>,
180}
181
182impl StartSubscriptionBuilder {
183 #[must_use]
185 pub fn new() -> Self {
186 Self::default()
187 }
188
189 #[must_use]
191 pub const fn plan(mut self, plan: Pubkey) -> Self {
192 self.plan = Some(plan);
193 self
194 }
195
196 #[must_use]
198 pub const fn subscriber(mut self, subscriber: Pubkey) -> Self {
199 self.subscriber = Some(subscriber);
200 self
201 }
202
203 #[must_use]
205 pub const fn payer(mut self, payer: Pubkey) -> Self {
206 self.payer = Some(payer);
207 self
208 }
209
210 #[must_use]
212 pub const fn allowance_periods(mut self, periods: u8) -> Self {
213 self.allowance_periods = Some(periods);
214 self
215 }
216
217 #[must_use]
219 pub const fn token_program(mut self, token_program: TokenProgram) -> Self {
220 self.token_program = Some(token_program);
221 self
222 }
223
224 #[must_use]
226 pub const fn program_id(mut self, program_id: Pubkey) -> Self {
227 self.program_id = Some(program_id);
228 self
229 }
230
231 pub fn build_instructions(
242 self,
243 merchant: &Merchant,
244 plan_data: &Plan,
245 platform_treasury_ata: &Pubkey,
246 ) -> Result<Vec<Instruction>> {
247 let plan = self.plan.ok_or("Plan not set")?;
248 let subscriber = self.subscriber.ok_or("Subscriber not set")?;
249 let _payer = self.payer.unwrap_or(subscriber);
250 let allowance_periods = self.allowance_periods.unwrap_or(3);
251 let token_program = self.token_program.unwrap_or(TokenProgram::Token);
252
253 let program_id = self.program_id.unwrap_or_else(program_id);
254
255 let config_pda = pda::config_address_with_program_id(&program_id);
257 let merchant_pda = pda::merchant_address_with_program_id(&merchant.authority, &program_id);
258 let subscription_pda =
259 pda::subscription_address_with_program_id(&plan, &subscriber, &program_id);
260 let delegate_pda = pda::delegate_address_with_program_id(&merchant_pda, &program_id);
261 let subscriber_ata = get_associated_token_address_with_program(
262 &subscriber,
263 &merchant.usdc_mint,
264 token_program,
265 )?;
266
267 let allowance_amount = plan_data
269 .price_usdc
270 .checked_mul(u64::from(allowance_periods))
271 .ok_or_else(|| TallyError::Generic("Arithmetic overflow".to_string()))?;
272
273 let approve_ix = match token_program {
275 TokenProgram::Token => approve_checked_token(
276 &token_program.program_id(),
277 &subscriber_ata,
278 &merchant.usdc_mint,
279 &delegate_pda, &subscriber, &[], allowance_amount,
283 6, )?,
285 TokenProgram::Token2022 => approve_checked_token2022(
286 &token_program.program_id(),
287 &subscriber_ata,
288 &merchant.usdc_mint,
289 &delegate_pda, &subscriber, &[], allowance_amount,
293 6, )?,
295 };
296
297 let start_sub_accounts = vec![
299 AccountMeta::new_readonly(config_pda, false), AccountMeta::new(subscription_pda, false), AccountMeta::new_readonly(plan, false), AccountMeta::new_readonly(merchant_pda, false), AccountMeta::new(subscriber, true), AccountMeta::new(subscriber_ata, false), AccountMeta::new(merchant.treasury_ata, false), AccountMeta::new(*platform_treasury_ata, false), AccountMeta::new_readonly(merchant.usdc_mint, false), AccountMeta::new_readonly(delegate_pda, false), AccountMeta::new_readonly(token_program.program_id(), false), AccountMeta::new_readonly(system_program::ID, false), ];
312
313 let start_sub_args = StartSubscriptionArgs { allowance_periods };
314 let start_sub_data = {
315 let mut data = Vec::new();
316 data.extend_from_slice(&[167, 59, 160, 222, 194, 175, 3, 13]);
318 borsh::to_writer(&mut data, &start_sub_args)
319 .map_err(|e| TallyError::Generic(format!("Failed to serialize args: {e}")))?;
320 data
321 };
322
323 let start_sub_ix = Instruction {
324 program_id,
325 accounts: start_sub_accounts,
326 data: start_sub_data,
327 };
328
329 Ok(vec![approve_ix, start_sub_ix])
330 }
331}
332
333impl CancelSubscriptionBuilder {
334 #[must_use]
336 pub fn new() -> Self {
337 Self::default()
338 }
339
340 #[must_use]
342 pub const fn plan(mut self, plan: Pubkey) -> Self {
343 self.plan = Some(plan);
344 self
345 }
346
347 #[must_use]
349 pub const fn subscriber(mut self, subscriber: Pubkey) -> Self {
350 self.subscriber = Some(subscriber);
351 self
352 }
353
354 #[must_use]
356 pub const fn payer(mut self, payer: Pubkey) -> Self {
357 self.payer = Some(payer);
358 self
359 }
360
361 #[must_use]
363 pub const fn token_program(mut self, token_program: TokenProgram) -> Self {
364 self.token_program = Some(token_program);
365 self
366 }
367
368 #[must_use]
370 pub const fn program_id(mut self, program_id: Pubkey) -> Self {
371 self.program_id = Some(program_id);
372 self
373 }
374
375 pub fn build_instructions(self, merchant: &Merchant) -> Result<Vec<Instruction>> {
384 let plan = self.plan.ok_or("Plan not set")?;
385 let subscriber = self.subscriber.ok_or("Subscriber not set")?;
386 let _payer = self.payer.unwrap_or(subscriber);
387 let token_program = self.token_program.unwrap_or(TokenProgram::Token);
388
389 let program_id = self.program_id.unwrap_or_else(program_id);
390
391 let subscription_pda =
393 pda::subscription_address_with_program_id(&plan, &subscriber, &program_id);
394 let subscriber_ata = get_associated_token_address_with_program(
395 &subscriber,
396 &merchant.usdc_mint,
397 token_program,
398 )?;
399
400 let revoke_ix = match token_program {
402 TokenProgram::Token => revoke_token(
403 &token_program.program_id(),
404 &subscriber_ata,
405 &subscriber, &[], )?,
408 TokenProgram::Token2022 => revoke_token2022(
409 &token_program.program_id(),
410 &subscriber_ata,
411 &subscriber, &[], )?,
414 };
415
416 let merchant_pda = pda::merchant_address_with_program_id(&merchant.authority, &program_id);
418 let cancel_sub_accounts = vec![
419 AccountMeta::new(subscription_pda, false), AccountMeta::new_readonly(plan, false), AccountMeta::new_readonly(merchant_pda, false), AccountMeta::new_readonly(subscriber, true), ];
424
425 let cancel_sub_args = CancelSubscriptionArgs;
426 let cancel_sub_data = {
427 let mut data = Vec::new();
428 data.extend_from_slice(&[60, 139, 189, 242, 191, 208, 143, 18]);
430 borsh::to_writer(&mut data, &cancel_sub_args)
431 .map_err(|e| TallyError::Generic(format!("Failed to serialize args: {e}")))?;
432 data
433 };
434
435 let cancel_sub_ix = Instruction {
436 program_id,
437 accounts: cancel_sub_accounts,
438 data: cancel_sub_data,
439 };
440
441 Ok(vec![revoke_ix, cancel_sub_ix])
442 }
443}
444
445impl CreateMerchantBuilder {
446 #[must_use]
448 pub fn new() -> Self {
449 Self::default()
450 }
451
452 #[must_use]
454 pub const fn authority(mut self, authority: Pubkey) -> Self {
455 self.authority = Some(authority);
456 self
457 }
458
459 #[must_use]
461 pub const fn payer(mut self, payer: Pubkey) -> Self {
462 self.payer = Some(payer);
463 self
464 }
465
466 #[must_use]
468 pub const fn usdc_mint(mut self, usdc_mint: Pubkey) -> Self {
469 self.usdc_mint = Some(usdc_mint);
470 self
471 }
472
473 #[must_use]
475 pub const fn treasury_ata(mut self, treasury_ata: Pubkey) -> Self {
476 self.treasury_ata = Some(treasury_ata);
477 self
478 }
479
480 #[must_use]
482 pub const fn platform_fee_bps(mut self, fee_bps: u16) -> Self {
483 self.platform_fee_bps = Some(fee_bps);
484 self
485 }
486
487 #[must_use]
489 pub const fn program_id(mut self, program_id: Pubkey) -> Self {
490 self.program_id = Some(program_id);
491 self
492 }
493
494 pub fn build_instruction(self) -> Result<Instruction> {
500 let authority = self.authority.ok_or("Authority not set")?;
501 let usdc_mint = self.usdc_mint.ok_or("USDC mint not set")?;
502 let treasury_ata = self.treasury_ata.ok_or("Treasury ATA not set")?;
503 let platform_fee_bps = self.platform_fee_bps.unwrap_or(0);
504
505 let program_id = self.program_id.unwrap_or_else(program_id);
506
507 let config_pda = pda::config_address_with_program_id(&program_id);
509 let merchant_pda = pda::merchant_address_with_program_id(&authority, &program_id);
510
511 let accounts = vec![
512 AccountMeta::new_readonly(config_pda, false), AccountMeta::new(merchant_pda, false), AccountMeta::new(authority, true), AccountMeta::new_readonly(usdc_mint, false), AccountMeta::new_readonly(treasury_ata, false), AccountMeta::new_readonly(spl_token::id(), false), AccountMeta::new_readonly(spl_associated_token_account::id(), false), AccountMeta::new_readonly(system_program::ID, false), ];
521
522 let args = InitMerchantArgs {
523 usdc_mint,
524 treasury_ata,
525 platform_fee_bps,
526 };
527
528 let data = {
529 let mut data = Vec::new();
530 data.extend_from_slice(&[209, 11, 214, 195, 222, 157, 124, 192]);
532 borsh::to_writer(&mut data, &args)
533 .map_err(|e| TallyError::Generic(format!("Failed to serialize args: {e}")))?;
534 data
535 };
536
537 Ok(Instruction {
538 program_id,
539 accounts,
540 data,
541 })
542 }
543}
544
545impl CreatePlanBuilder {
546 #[must_use]
548 pub fn new() -> Self {
549 Self::default()
550 }
551
552 #[must_use]
554 pub const fn authority(mut self, authority: Pubkey) -> Self {
555 self.authority = Some(authority);
556 self
557 }
558
559 #[must_use]
561 pub const fn payer(mut self, payer: Pubkey) -> Self {
562 self.payer = Some(payer);
563 self
564 }
565
566 #[must_use]
568 pub fn plan_args(mut self, args: CreatePlanArgs) -> Self {
569 self.plan_args = Some(args);
570 self
571 }
572
573 #[must_use]
575 pub const fn program_id(mut self, program_id: Pubkey) -> Self {
576 self.program_id = Some(program_id);
577 self
578 }
579
580 pub fn build_instruction(self) -> Result<Instruction> {
586 let authority = self.authority.ok_or("Authority not set")?;
587 let _payer = self.payer.unwrap_or(authority);
588 let plan_args = self.plan_args.ok_or("Plan args not set")?;
589
590 let program_id = self.program_id.unwrap_or_else(program_id);
591
592 let config_pda = pda::config_address_with_program_id(&program_id);
594 let merchant_pda = pda::merchant_address_with_program_id(&authority, &program_id);
595 let plan_pda =
596 pda::plan_address_with_program_id(&merchant_pda, &plan_args.plan_id_bytes, &program_id);
597
598 let accounts = vec![
599 AccountMeta::new_readonly(config_pda, false), AccountMeta::new(plan_pda, false), AccountMeta::new_readonly(merchant_pda, false), AccountMeta::new(authority, true), AccountMeta::new_readonly(system_program::ID, false), ];
605
606 let data = {
607 let mut data = Vec::new();
608 data.extend_from_slice(&[77, 43, 141, 254, 212, 118, 41, 186]);
610 borsh::to_writer(&mut data, &plan_args)
611 .map_err(|e| TallyError::Generic(format!("Failed to serialize args: {e}")))?;
612 data
613 };
614
615 Ok(Instruction {
616 program_id,
617 accounts,
618 data,
619 })
620 }
621}
622
623impl UpdatePlanBuilder {
624 #[must_use]
626 pub fn new() -> Self {
627 Self::default()
628 }
629
630 #[must_use]
632 pub const fn authority(mut self, authority: Pubkey) -> Self {
633 self.authority = Some(authority);
634 self
635 }
636
637 #[must_use]
639 pub const fn payer(mut self, payer: Pubkey) -> Self {
640 self.payer = Some(payer);
641 self
642 }
643
644 #[must_use]
646 pub const fn plan_key(mut self, plan_key: Pubkey) -> Self {
647 self.plan_key = Some(plan_key);
648 self
649 }
650
651 #[must_use]
653 pub fn update_args(mut self, args: UpdatePlanArgs) -> Self {
654 self.update_args = Some(args);
655 self
656 }
657
658 #[must_use]
660 pub const fn program_id(mut self, program_id: Pubkey) -> Self {
661 self.program_id = Some(program_id);
662 self
663 }
664
665 pub fn build_instruction(self, merchant: &Merchant) -> Result<Instruction> {
674 let authority = self.authority.ok_or("Authority not set")?;
675 let plan_key = self.plan_key.ok_or("Plan key not set")?;
676 let update_args = self.update_args.ok_or("Update args not set")?;
677
678 if authority != merchant.authority {
680 return Err(TallyError::Generic(
681 "Authority does not match merchant authority".to_string(),
682 ));
683 }
684
685 if !update_args.has_updates() {
687 return Err(TallyError::Generic(
688 "No updates specified in UpdatePlanArgs".to_string(),
689 ));
690 }
691
692 let program_id = self.program_id.unwrap_or_else(program_id);
693
694 let config_pda = pda::config_address_with_program_id(&program_id);
696 let merchant_pda = pda::merchant_address_with_program_id(&authority, &program_id);
697
698 let accounts = vec![
699 AccountMeta::new_readonly(config_pda, false), AccountMeta::new(plan_key, false), AccountMeta::new_readonly(merchant_pda, false), AccountMeta::new(authority, true), ];
704
705 let data = {
706 let mut data = Vec::new();
707 data.extend_from_slice(&[219, 200, 88, 176, 158, 63, 253, 127]);
709 borsh::to_writer(&mut data, &update_args)
710 .map_err(|e| TallyError::Generic(format!("Failed to serialize args: {e}")))?;
711 data
712 };
713
714 Ok(Instruction {
715 program_id,
716 accounts,
717 data,
718 })
719 }
720}
721
722impl AdminWithdrawFeesBuilder {
723 #[must_use]
725 pub fn new() -> Self {
726 Self::default()
727 }
728
729 #[must_use]
731 pub const fn platform_authority(mut self, platform_authority: Pubkey) -> Self {
732 self.platform_authority = Some(platform_authority);
733 self
734 }
735
736 #[must_use]
738 pub const fn platform_treasury_ata(mut self, platform_treasury_ata: Pubkey) -> Self {
739 self.platform_treasury_ata = Some(platform_treasury_ata);
740 self
741 }
742
743 #[must_use]
745 pub const fn destination_ata(mut self, destination_ata: Pubkey) -> Self {
746 self.destination_ata = Some(destination_ata);
747 self
748 }
749
750 #[must_use]
752 pub const fn usdc_mint(mut self, usdc_mint: Pubkey) -> Self {
753 self.usdc_mint = Some(usdc_mint);
754 self
755 }
756
757 #[must_use]
759 pub const fn amount(mut self, amount: u64) -> Self {
760 self.amount = Some(amount);
761 self
762 }
763
764 #[must_use]
766 pub const fn program_id(mut self, program_id: Pubkey) -> Self {
767 self.program_id = Some(program_id);
768 self
769 }
770
771 pub fn build_instruction(self) -> Result<Instruction> {
777 let platform_authority = self
778 .platform_authority
779 .ok_or("Platform authority not set")?;
780 let platform_treasury_ata = self
781 .platform_treasury_ata
782 .ok_or("Platform treasury ATA not set")?;
783 let destination_ata = self.destination_ata.ok_or("Destination ATA not set")?;
784 let usdc_mint = self.usdc_mint.ok_or("USDC mint not set")?;
785 let amount = self.amount.ok_or("Amount not set")?;
786
787 let program_id = self.program_id.unwrap_or_else(program_id);
788
789 let config_pda = pda::config_address_with_program_id(&program_id);
791
792 let accounts = vec![
793 AccountMeta::new_readonly(config_pda, false), AccountMeta::new(platform_authority, true), AccountMeta::new(platform_treasury_ata, false), AccountMeta::new(destination_ata, false), AccountMeta::new_readonly(usdc_mint, false), AccountMeta::new_readonly(spl_token::id(), false), ];
800
801 let args = AdminWithdrawFeesArgs { amount };
802
803 let data = {
804 let mut data = Vec::new();
805 data.extend_from_slice(&[236, 186, 208, 151, 204, 142, 168, 30]);
807 borsh::to_writer(&mut data, &args)
808 .map_err(|e| TallyError::Generic(format!("Failed to serialize args: {e}")))?;
809 data
810 };
811
812 Ok(Instruction {
813 program_id,
814 accounts,
815 data,
816 })
817 }
818}
819
820impl InitConfigBuilder {
821 #[must_use]
823 pub fn new() -> Self {
824 Self::default()
825 }
826
827 #[must_use]
829 pub const fn authority(mut self, authority: Pubkey) -> Self {
830 self.authority = Some(authority);
831 self
832 }
833
834 #[must_use]
836 pub const fn payer(mut self, payer: Pubkey) -> Self {
837 self.payer = Some(payer);
838 self
839 }
840
841 #[must_use]
843 pub const fn config_args(mut self, args: InitConfigArgs) -> Self {
844 self.config_args = Some(args);
845 self
846 }
847
848 #[must_use]
850 pub const fn program_id(mut self, program_id: Pubkey) -> Self {
851 self.program_id = Some(program_id);
852 self
853 }
854
855 pub fn build_instruction(self) -> Result<Instruction> {
861 let authority = self.authority.ok_or("Authority not set")?;
862 let config_args = self.config_args.ok_or("Config args not set")?;
863
864 let program_id = self.program_id.unwrap_or_else(program_id);
865
866 let config_pda = pda::config_address_with_program_id(&program_id);
868
869 let accounts = vec![
870 AccountMeta::new(config_pda, false), AccountMeta::new(authority, true), AccountMeta::new_readonly(system_program::ID, false), ];
874
875 let data = {
876 let mut data = Vec::new();
877 data.extend_from_slice(&[23, 235, 115, 232, 168, 96, 1, 231]);
879 borsh::to_writer(&mut data, &config_args)
880 .map_err(|e| TallyError::Generic(format!("Failed to serialize args: {e}")))?;
881 data
882 };
883
884 Ok(Instruction {
885 program_id,
886 accounts,
887 data,
888 })
889 }
890}
891
892impl RenewSubscriptionBuilder {
893 #[must_use]
895 pub fn new() -> Self {
896 Self::default()
897 }
898
899 #[must_use]
901 pub const fn plan(mut self, plan: Pubkey) -> Self {
902 self.plan = Some(plan);
903 self
904 }
905
906 #[must_use]
908 pub const fn subscriber(mut self, subscriber: Pubkey) -> Self {
909 self.subscriber = Some(subscriber);
910 self
911 }
912
913 #[must_use]
915 pub const fn keeper(mut self, keeper: Pubkey) -> Self {
916 self.keeper = Some(keeper);
917 self
918 }
919
920 #[must_use]
922 pub const fn keeper_ata(mut self, keeper_ata: Pubkey) -> Self {
923 self.keeper_ata = Some(keeper_ata);
924 self
925 }
926
927 #[must_use]
929 pub const fn token_program(mut self, token_program: TokenProgram) -> Self {
930 self.token_program = Some(token_program);
931 self
932 }
933
934 #[must_use]
936 pub const fn program_id(mut self, program_id: Pubkey) -> Self {
937 self.program_id = Some(program_id);
938 self
939 }
940
941 pub fn build_instruction(
952 self,
953 merchant: &Merchant,
954 _plan_data: &Plan,
955 platform_treasury_ata: &Pubkey,
956 ) -> Result<Instruction> {
957 let plan = self.plan.ok_or("Plan not set")?;
958 let subscriber = self.subscriber.ok_or("Subscriber not set")?;
959 let keeper = self.keeper.ok_or("Keeper not set")?;
960 let keeper_ata = self.keeper_ata.ok_or("Keeper ATA not set")?;
961 let token_program = self.token_program.unwrap_or(TokenProgram::Token);
962
963 let program_id = self.program_id.unwrap_or_else(program_id);
964
965 let config_pda = pda::config_address_with_program_id(&program_id);
967 let merchant_pda = pda::merchant_address_with_program_id(&merchant.authority, &program_id);
968 let subscription_pda =
969 pda::subscription_address_with_program_id(&plan, &subscriber, &program_id);
970 let delegate_pda = pda::delegate_address_with_program_id(&merchant_pda, &program_id);
971 let subscriber_ata = get_associated_token_address_with_program(
972 &subscriber,
973 &merchant.usdc_mint,
974 token_program,
975 )?;
976
977 let renew_sub_accounts = vec![
979 AccountMeta::new_readonly(config_pda, false), AccountMeta::new(subscription_pda, false), AccountMeta::new_readonly(plan, false), AccountMeta::new_readonly(merchant_pda, false), AccountMeta::new(subscriber_ata, false), AccountMeta::new(merchant.treasury_ata, false), AccountMeta::new(*platform_treasury_ata, false), AccountMeta::new(keeper, true), AccountMeta::new(keeper_ata, false), AccountMeta::new_readonly(merchant.usdc_mint, false), AccountMeta::new_readonly(delegate_pda, false), AccountMeta::new_readonly(token_program.program_id(), false), ];
992
993 let renew_sub_args = crate::program_types::RenewSubscriptionArgs {};
994 let renew_sub_data = {
995 let mut data = Vec::new();
996 data.extend_from_slice(&[45, 75, 154, 194, 160, 10, 111, 183]);
998 borsh::to_writer(&mut data, &renew_sub_args)
999 .map_err(|e| TallyError::Generic(format!("Failed to serialize args: {e}")))?;
1000 data
1001 };
1002
1003 Ok(Instruction {
1004 program_id,
1005 accounts: renew_sub_accounts,
1006 data: renew_sub_data,
1007 })
1008 }
1009}
1010
1011impl CloseSubscriptionBuilder {
1012 #[must_use]
1014 pub fn new() -> Self {
1015 Self::default()
1016 }
1017
1018 #[must_use]
1020 pub const fn plan(mut self, plan: Pubkey) -> Self {
1021 self.plan = Some(plan);
1022 self
1023 }
1024
1025 #[must_use]
1027 pub const fn subscriber(mut self, subscriber: Pubkey) -> Self {
1028 self.subscriber = Some(subscriber);
1029 self
1030 }
1031
1032 #[must_use]
1034 pub const fn program_id(mut self, program_id: Pubkey) -> Self {
1035 self.program_id = Some(program_id);
1036 self
1037 }
1038
1039 pub fn build_instruction(self) -> Result<Instruction> {
1045 let plan = self.plan.ok_or("Plan not set")?;
1046 let subscriber = self.subscriber.ok_or("Subscriber not set")?;
1047
1048 let program_id = self.program_id.unwrap_or_else(program_id);
1049
1050 let subscription_pda =
1052 pda::subscription_address_with_program_id(&plan, &subscriber, &program_id);
1053
1054 let close_sub_accounts = vec![
1056 AccountMeta::new(subscription_pda, false), AccountMeta::new(subscriber, true), ];
1059
1060 let close_sub_args = crate::program_types::CloseSubscriptionArgs {};
1061 let close_sub_data = {
1062 let mut data = Vec::new();
1063 data.extend_from_slice(&[33, 214, 169, 135, 35, 127, 78, 7]);
1065 borsh::to_writer(&mut data, &close_sub_args)
1066 .map_err(|e| TallyError::Generic(format!("Failed to serialize args: {e}")))?;
1067 data
1068 };
1069
1070 Ok(Instruction {
1071 program_id,
1072 accounts: close_sub_accounts,
1073 data: close_sub_data,
1074 })
1075 }
1076}
1077
1078impl TransferAuthorityBuilder {
1079 #[must_use]
1081 pub fn new() -> Self {
1082 Self::default()
1083 }
1084
1085 #[must_use]
1087 pub const fn platform_authority(mut self, platform_authority: Pubkey) -> Self {
1088 self.platform_authority = Some(platform_authority);
1089 self
1090 }
1091
1092 #[must_use]
1094 pub const fn new_authority(mut self, new_authority: Pubkey) -> Self {
1095 self.new_authority = Some(new_authority);
1096 self
1097 }
1098
1099 #[must_use]
1101 pub const fn program_id(mut self, program_id: Pubkey) -> Self {
1102 self.program_id = Some(program_id);
1103 self
1104 }
1105
1106 pub fn build_instruction(self) -> Result<Instruction> {
1112 let platform_authority = self
1113 .platform_authority
1114 .ok_or("Platform authority not set")?;
1115 let new_authority = self.new_authority.ok_or("New authority not set")?;
1116
1117 let program_id = self.program_id.unwrap_or_else(program_id);
1118
1119 let config_pda = pda::config_address_with_program_id(&program_id);
1121
1122 let accounts = vec![
1123 AccountMeta::new(config_pda, false), AccountMeta::new_readonly(platform_authority, true), ];
1126
1127 let args = crate::program_types::TransferAuthorityArgs { new_authority };
1128
1129 let data = {
1130 let mut data = Vec::new();
1131 data.extend_from_slice(&[48, 169, 76, 72, 229, 180, 55, 161]);
1133 borsh::to_writer(&mut data, &args)
1134 .map_err(|e| TallyError::Generic(format!("Failed to serialize args: {e}")))?;
1135 data
1136 };
1137
1138 Ok(Instruction {
1139 program_id,
1140 accounts,
1141 data,
1142 })
1143 }
1144}
1145
1146impl AcceptAuthorityBuilder {
1147 #[must_use]
1149 pub fn new() -> Self {
1150 Self::default()
1151 }
1152
1153 #[must_use]
1155 pub const fn new_authority(mut self, new_authority: Pubkey) -> Self {
1156 self.new_authority = Some(new_authority);
1157 self
1158 }
1159
1160 #[must_use]
1162 pub const fn program_id(mut self, program_id: Pubkey) -> Self {
1163 self.program_id = Some(program_id);
1164 self
1165 }
1166
1167 pub fn build_instruction(self) -> Result<Instruction> {
1173 let new_authority = self.new_authority.ok_or("New authority not set")?;
1174
1175 let program_id = self.program_id.unwrap_or_else(program_id);
1176
1177 let config_pda = pda::config_address_with_program_id(&program_id);
1179
1180 let accounts = vec![
1181 AccountMeta::new(config_pda, false), AccountMeta::new_readonly(new_authority, true), ];
1184
1185 let args = crate::program_types::AcceptAuthorityArgs::default();
1186
1187 let data = {
1188 let mut data = Vec::new();
1189 data.extend_from_slice(&[107, 86, 198, 91, 33, 12, 107, 160]);
1191 borsh::to_writer(&mut data, &args)
1192 .map_err(|e| TallyError::Generic(format!("Failed to serialize args: {e}")))?;
1193 data
1194 };
1195
1196 Ok(Instruction {
1197 program_id,
1198 accounts,
1199 data,
1200 })
1201 }
1202}
1203
1204impl CancelAuthorityTransferBuilder {
1205 #[must_use]
1207 pub fn new() -> Self {
1208 Self::default()
1209 }
1210
1211 #[must_use]
1213 pub const fn platform_authority(mut self, platform_authority: Pubkey) -> Self {
1214 self.platform_authority = Some(platform_authority);
1215 self
1216 }
1217
1218 #[must_use]
1220 pub const fn program_id(mut self, program_id: Pubkey) -> Self {
1221 self.program_id = Some(program_id);
1222 self
1223 }
1224
1225 pub fn build_instruction(self) -> Result<Instruction> {
1231 let platform_authority = self
1232 .platform_authority
1233 .ok_or("Platform authority not set")?;
1234
1235 let program_id = self.program_id.unwrap_or_else(program_id);
1236
1237 let config_pda = pda::config_address_with_program_id(&program_id);
1239
1240 let accounts = vec![
1241 AccountMeta::new(config_pda, false), AccountMeta::new_readonly(platform_authority, true), ];
1244
1245 let args = crate::program_types::CancelAuthorityTransferArgs::default();
1246
1247 let data = {
1248 let mut data = Vec::new();
1249 data.extend_from_slice(&[94, 131, 125, 184, 183, 24, 125, 229]);
1251 borsh::to_writer(&mut data, &args)
1252 .map_err(|e| TallyError::Generic(format!("Failed to serialize args: {e}")))?;
1253 data
1254 };
1255
1256 Ok(Instruction {
1257 program_id,
1258 accounts,
1259 data,
1260 })
1261 }
1262}
1263
1264impl PauseBuilder {
1265 #[must_use]
1267 pub fn new() -> Self {
1268 Self::default()
1269 }
1270
1271 #[must_use]
1273 pub const fn platform_authority(mut self, platform_authority: Pubkey) -> Self {
1274 self.platform_authority = Some(platform_authority);
1275 self
1276 }
1277
1278 #[must_use]
1280 pub const fn program_id(mut self, program_id: Pubkey) -> Self {
1281 self.program_id = Some(program_id);
1282 self
1283 }
1284
1285 pub fn build_instruction(self) -> Result<Instruction> {
1291 let platform_authority = self
1292 .platform_authority
1293 .ok_or("Platform authority not set")?;
1294
1295 let program_id = self.program_id.unwrap_or_else(program_id);
1296
1297 let config_pda = pda::config_address_with_program_id(&program_id);
1299
1300 let accounts = vec![
1301 AccountMeta::new(config_pda, false), AccountMeta::new_readonly(platform_authority, true), ];
1304
1305 let args = crate::program_types::PauseArgs {};
1306
1307 let data = {
1308 let mut data = Vec::new();
1309 data.extend_from_slice(&[211, 22, 221, 251, 74, 121, 193, 47]);
1311 borsh::to_writer(&mut data, &args)
1312 .map_err(|e| TallyError::Generic(format!("Failed to serialize args: {e}")))?;
1313 data
1314 };
1315
1316 Ok(Instruction {
1317 program_id,
1318 accounts,
1319 data,
1320 })
1321 }
1322}
1323
1324impl UnpauseBuilder {
1325 #[must_use]
1327 pub fn new() -> Self {
1328 Self::default()
1329 }
1330
1331 #[must_use]
1333 pub const fn platform_authority(mut self, platform_authority: Pubkey) -> Self {
1334 self.platform_authority = Some(platform_authority);
1335 self
1336 }
1337
1338 #[must_use]
1340 pub const fn program_id(mut self, program_id: Pubkey) -> Self {
1341 self.program_id = Some(program_id);
1342 self
1343 }
1344
1345 pub fn build_instruction(self) -> Result<Instruction> {
1351 let platform_authority = self
1352 .platform_authority
1353 .ok_or("Platform authority not set")?;
1354
1355 let program_id = self.program_id.unwrap_or_else(program_id);
1356
1357 let config_pda = pda::config_address_with_program_id(&program_id);
1359
1360 let accounts = vec![
1361 AccountMeta::new(config_pda, false), AccountMeta::new_readonly(platform_authority, true), ];
1364
1365 let args = crate::program_types::UnpauseArgs {};
1366
1367 let data = {
1368 let mut data = Vec::new();
1369 data.extend_from_slice(&[169, 144, 4, 38, 10, 141, 188, 255]);
1371 borsh::to_writer(&mut data, &args)
1372 .map_err(|e| TallyError::Generic(format!("Failed to serialize args: {e}")))?;
1373 data
1374 };
1375
1376 Ok(Instruction {
1377 program_id,
1378 accounts,
1379 data,
1380 })
1381 }
1382}
1383
1384impl UpdateConfigBuilder {
1385 #[must_use]
1387 pub fn new() -> Self {
1388 Self::default()
1389 }
1390
1391 #[must_use]
1393 pub const fn platform_authority(mut self, platform_authority: Pubkey) -> Self {
1394 self.platform_authority = Some(platform_authority);
1395 self
1396 }
1397
1398 #[must_use]
1400 pub const fn keeper_fee_bps(mut self, keeper_fee_bps: u16) -> Self {
1401 self.keeper_fee_bps = Some(keeper_fee_bps);
1402 self
1403 }
1404
1405 #[must_use]
1407 pub const fn max_withdrawal_amount(mut self, max_withdrawal_amount: u64) -> Self {
1408 self.max_withdrawal_amount = Some(max_withdrawal_amount);
1409 self
1410 }
1411
1412 #[must_use]
1414 pub const fn max_grace_period_seconds(mut self, max_grace_period_seconds: u64) -> Self {
1415 self.max_grace_period_seconds = Some(max_grace_period_seconds);
1416 self
1417 }
1418
1419 #[must_use]
1421 pub const fn min_platform_fee_bps(mut self, min_platform_fee_bps: u16) -> Self {
1422 self.min_platform_fee_bps = Some(min_platform_fee_bps);
1423 self
1424 }
1425
1426 #[must_use]
1428 pub const fn max_platform_fee_bps(mut self, max_platform_fee_bps: u16) -> Self {
1429 self.max_platform_fee_bps = Some(max_platform_fee_bps);
1430 self
1431 }
1432
1433 #[must_use]
1435 pub const fn min_period_seconds(mut self, min_period_seconds: u64) -> Self {
1436 self.min_period_seconds = Some(min_period_seconds);
1437 self
1438 }
1439
1440 #[must_use]
1442 pub const fn default_allowance_periods(mut self, default_allowance_periods: u8) -> Self {
1443 self.default_allowance_periods = Some(default_allowance_periods);
1444 self
1445 }
1446
1447 #[must_use]
1449 pub const fn program_id(mut self, program_id: Pubkey) -> Self {
1450 self.program_id = Some(program_id);
1451 self
1452 }
1453
1454 pub fn build_instruction(self) -> Result<Instruction> {
1467 let platform_authority = self
1468 .platform_authority
1469 .ok_or("Platform authority not set")?;
1470
1471 let program_id = self.program_id.unwrap_or_else(program_id);
1472
1473 let has_update = self.keeper_fee_bps.is_some()
1475 || self.max_withdrawal_amount.is_some()
1476 || self.max_grace_period_seconds.is_some()
1477 || self.min_platform_fee_bps.is_some()
1478 || self.max_platform_fee_bps.is_some()
1479 || self.min_period_seconds.is_some()
1480 || self.default_allowance_periods.is_some();
1481
1482 if !has_update {
1483 return Err("At least one configuration field must be set for update".into());
1484 }
1485
1486 if let Some(keeper_fee) = self.keeper_fee_bps {
1488 if keeper_fee > 100 {
1489 return Err("Keeper fee must be <= 100 basis points (1%)".into());
1490 }
1491 }
1492
1493 if let Some(min_fee) = self.min_platform_fee_bps {
1495 if let Some(max_fee) = self.max_platform_fee_bps {
1496 if min_fee > max_fee {
1497 return Err("Minimum platform fee must be <= maximum platform fee".into());
1498 }
1499 }
1500 }
1501
1502 if let Some(max_withdrawal) = self.max_withdrawal_amount {
1504 if max_withdrawal == 0 {
1505 return Err("Maximum withdrawal amount must be > 0".into());
1506 }
1507 }
1508
1509 if let Some(max_grace) = self.max_grace_period_seconds {
1510 if max_grace == 0 {
1511 return Err("Maximum grace period must be > 0".into());
1512 }
1513 }
1514
1515 if let Some(min_period) = self.min_period_seconds {
1516 if min_period == 0 {
1517 return Err("Minimum period must be > 0".into());
1518 }
1519 }
1520
1521 if let Some(allowance_periods) = self.default_allowance_periods {
1522 if allowance_periods == 0 {
1523 return Err("Default allowance periods must be > 0".into());
1524 }
1525 }
1526
1527 let config_pda = pda::config_address_with_program_id(&program_id);
1529
1530 let accounts = vec![
1531 AccountMeta::new(config_pda, false), AccountMeta::new_readonly(platform_authority, true), ];
1534
1535 let args = UpdateConfigArgs {
1536 keeper_fee_bps: self.keeper_fee_bps,
1537 max_withdrawal_amount: self.max_withdrawal_amount,
1538 max_grace_period_seconds: self.max_grace_period_seconds,
1539 min_platform_fee_bps: self.min_platform_fee_bps,
1540 max_platform_fee_bps: self.max_platform_fee_bps,
1541 min_period_seconds: self.min_period_seconds,
1542 default_allowance_periods: self.default_allowance_periods,
1543 };
1544
1545 let data = {
1546 let mut data = Vec::new();
1547 data.extend_from_slice(&[29, 158, 252, 191, 10, 83, 219, 99]);
1549 borsh::to_writer(&mut data, &args)
1550 .map_err(|e| TallyError::Generic(format!("Failed to serialize args: {e}")))?;
1551 data
1552 };
1553
1554 Ok(Instruction {
1555 program_id,
1556 accounts,
1557 data,
1558 })
1559 }
1560}
1561
1562impl UpdateMerchantTierBuilder {
1563 #[must_use]
1565 pub fn new() -> Self {
1566 Self::default()
1567 }
1568
1569 #[must_use]
1571 pub const fn authority(mut self, authority: Pubkey) -> Self {
1572 self.authority = Some(authority);
1573 self
1574 }
1575
1576 #[must_use]
1578 pub const fn merchant(mut self, merchant: Pubkey) -> Self {
1579 self.merchant = Some(merchant);
1580 self
1581 }
1582
1583 #[must_use]
1585 pub const fn new_tier(mut self, new_tier: u8) -> Self {
1586 self.new_tier = Some(new_tier);
1587 self
1588 }
1589
1590 #[must_use]
1592 pub const fn program_id(mut self, program_id: Pubkey) -> Self {
1593 self.program_id = Some(program_id);
1594 self
1595 }
1596
1597 pub fn build_instruction(self) -> Result<Instruction> {
1608 let authority = self.authority.ok_or("Authority not set")?;
1609 let merchant = self.merchant.ok_or("Merchant not set")?;
1610 let new_tier = self.new_tier.ok_or("New tier not set")?;
1611
1612 if new_tier > 2 {
1614 return Err("New tier must be 0 (Free), 1 (Pro), or 2 (Enterprise)".into());
1615 }
1616
1617 let program_id = self.program_id.unwrap_or_else(program_id);
1618
1619 let config_pda = pda::config_address_with_program_id(&program_id);
1621
1622 let accounts = vec![
1623 AccountMeta::new_readonly(config_pda, false), AccountMeta::new(merchant, false), AccountMeta::new_readonly(authority, true), ];
1627
1628 let args = crate::program_types::UpdateMerchantTierArgs { new_tier };
1629
1630 let data = {
1631 let mut data = Vec::new();
1632 data.extend_from_slice(&[24, 54, 190, 70, 221, 93, 3, 64]);
1634 borsh::to_writer(&mut data, &args)
1635 .map_err(|e| TallyError::Generic(format!("Failed to serialize args: {e}")))?;
1636 data
1637 };
1638
1639 Ok(Instruction {
1640 program_id,
1641 accounts,
1642 data,
1643 })
1644 }
1645}
1646
1647impl UpdatePlanTermsBuilder {
1648 #[must_use]
1650 pub fn new() -> Self {
1651 Self::default()
1652 }
1653
1654 #[must_use]
1656 pub const fn authority(mut self, authority: Pubkey) -> Self {
1657 self.authority = Some(authority);
1658 self
1659 }
1660
1661 #[must_use]
1663 pub const fn plan_key(mut self, plan_key: Pubkey) -> Self {
1664 self.plan_key = Some(plan_key);
1665 self
1666 }
1667
1668 #[must_use]
1670 pub const fn price_usdc(mut self, price_usdc: u64) -> Self {
1671 self.price_usdc = Some(price_usdc);
1672 self
1673 }
1674
1675 #[must_use]
1677 pub const fn period_secs(mut self, period_secs: u64) -> Self {
1678 self.period_secs = Some(period_secs);
1679 self
1680 }
1681
1682 #[must_use]
1684 pub const fn grace_secs(mut self, grace_secs: u64) -> Self {
1685 self.grace_secs = Some(grace_secs);
1686 self
1687 }
1688
1689 #[must_use]
1691 pub fn name(mut self, name: String) -> Self {
1692 self.name = Some(name);
1693 self
1694 }
1695
1696 #[must_use]
1698 pub const fn program_id(mut self, program_id: Pubkey) -> Self {
1699 self.program_id = Some(program_id);
1700 self
1701 }
1702
1703 pub fn build_instruction(self) -> Result<Instruction> {
1724 const MAX_PLAN_PRICE_USDC: u64 = 1_000_000_000_000; let authority = self.authority.ok_or("Authority not set")?;
1727 let plan_key = self.plan_key.ok_or("Plan key not set")?;
1728 let program_id = self.program_id.unwrap_or_else(program_id);
1729
1730 let has_update = self.price_usdc.is_some()
1732 || self.period_secs.is_some()
1733 || self.grace_secs.is_some()
1734 || self.name.is_some();
1735
1736 if !has_update {
1737 return Err("At least one field must be set for update".into());
1738 }
1739
1740 if let Some(price) = self.price_usdc {
1742 if price == 0 {
1743 return Err("Price must be > 0".into());
1744 }
1745 if price > MAX_PLAN_PRICE_USDC {
1746 return Err("Price must be <= 1,000,000 USDC".into());
1747 }
1748 }
1749
1750 if let (Some(grace), Some(period)) = (self.grace_secs, self.period_secs) {
1752 let max_grace = period
1753 .checked_mul(3)
1754 .and_then(|v| v.checked_div(10))
1755 .ok_or("Arithmetic overflow calculating max grace period")?;
1756
1757 if grace > max_grace {
1758 return Err("Grace period must be <= 30% of billing period".into());
1759 }
1760 }
1761
1762 if let Some(ref name) = self.name {
1764 if name.is_empty() {
1765 return Err("Name must not be empty".into());
1766 }
1767 if name.len() > 32 {
1768 return Err("Name must be <= 32 bytes".into());
1769 }
1770 }
1771
1772 let config_pda = pda::config_address_with_program_id(&program_id);
1774 let merchant_pda = pda::merchant_address_with_program_id(&authority, &program_id);
1775
1776 let accounts = vec![
1777 AccountMeta::new_readonly(config_pda, false), AccountMeta::new(plan_key, false), AccountMeta::new_readonly(merchant_pda, false), AccountMeta::new_readonly(authority, true), ];
1782
1783 let args = UpdatePlanTermsArgs {
1784 price_usdc: self.price_usdc,
1785 period_secs: self.period_secs,
1786 grace_secs: self.grace_secs,
1787 name: self.name,
1788 };
1789
1790 let data = {
1791 let mut data = Vec::new();
1792 data.extend_from_slice(&[224, 68, 224, 41, 169, 52, 124, 221]);
1794 borsh::to_writer(&mut data, &args)
1795 .map_err(|e| TallyError::Generic(format!("Failed to serialize args: {e}")))?;
1796 data
1797 };
1798
1799 Ok(Instruction {
1800 program_id,
1801 accounts,
1802 data,
1803 })
1804 }
1805}
1806
1807#[must_use]
1811pub fn start_subscription() -> StartSubscriptionBuilder {
1812 StartSubscriptionBuilder::new()
1813}
1814
1815#[must_use]
1817pub fn cancel_subscription() -> CancelSubscriptionBuilder {
1818 CancelSubscriptionBuilder::new()
1819}
1820
1821#[must_use]
1823pub fn create_merchant() -> CreateMerchantBuilder {
1824 CreateMerchantBuilder::new()
1825}
1826
1827#[must_use]
1829pub fn create_plan() -> CreatePlanBuilder {
1830 CreatePlanBuilder::new()
1831}
1832
1833#[must_use]
1835pub fn admin_withdraw_fees() -> AdminWithdrawFeesBuilder {
1836 AdminWithdrawFeesBuilder::new()
1837}
1838
1839#[must_use]
1841pub fn init_config() -> InitConfigBuilder {
1842 InitConfigBuilder::new()
1843}
1844
1845#[must_use]
1847pub fn update_plan() -> UpdatePlanBuilder {
1848 UpdatePlanBuilder::new()
1849}
1850
1851#[must_use]
1853pub fn renew_subscription() -> RenewSubscriptionBuilder {
1854 RenewSubscriptionBuilder::new()
1855}
1856
1857#[must_use]
1859pub fn close_subscription() -> CloseSubscriptionBuilder {
1860 CloseSubscriptionBuilder::new()
1861}
1862
1863#[must_use]
1865pub fn transfer_authority() -> TransferAuthorityBuilder {
1866 TransferAuthorityBuilder::new()
1867}
1868
1869#[must_use]
1871pub fn accept_authority() -> AcceptAuthorityBuilder {
1872 AcceptAuthorityBuilder::new()
1873}
1874
1875#[must_use]
1877pub fn cancel_authority_transfer() -> CancelAuthorityTransferBuilder {
1878 CancelAuthorityTransferBuilder::new()
1879}
1880
1881#[must_use]
1883pub fn pause() -> PauseBuilder {
1884 PauseBuilder::new()
1885}
1886
1887#[must_use]
1889pub fn unpause() -> UnpauseBuilder {
1890 UnpauseBuilder::new()
1891}
1892
1893#[must_use]
1895pub fn update_config() -> UpdateConfigBuilder {
1896 UpdateConfigBuilder::new()
1897}
1898
1899#[must_use]
1901pub fn update_merchant_tier() -> UpdateMerchantTierBuilder {
1902 UpdateMerchantTierBuilder::new()
1903}
1904
1905#[must_use]
1907pub fn update_plan_terms() -> UpdatePlanTermsBuilder {
1908 UpdatePlanTermsBuilder::new()
1909}
1910
1911#[cfg(test)]
1912mod tests {
1913 use super::*;
1914 use anchor_client::solana_sdk::signature::{Keypair, Signer};
1915 use std::str::FromStr;
1916
1917 fn create_test_merchant() -> Merchant {
1918 Merchant {
1919 authority: Pubkey::from(Keypair::new().pubkey().to_bytes()),
1920 usdc_mint: Pubkey::from_str("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v").unwrap(),
1921 treasury_ata: Pubkey::from(Keypair::new().pubkey().to_bytes()),
1922 platform_fee_bps: 50,
1923 tier: 0, bump: 255,
1925 }
1926 }
1927
1928 fn create_test_plan() -> Plan {
1929 let merchant = Pubkey::from(Keypair::new().pubkey().to_bytes());
1930 let mut plan_id = [0u8; 32];
1931 plan_id[..12].copy_from_slice(b"premium_plan");
1932 let mut name = [0u8; 32];
1933 name[..12].copy_from_slice(b"Premium Plan");
1934
1935 Plan {
1936 merchant,
1937 plan_id,
1938 price_usdc: 5_000_000, period_secs: 2_592_000, grace_secs: 432_000, name,
1942 active: true,
1943 }
1944 }
1945
1946 #[test]
1947 fn test_start_subscription_builder() {
1948 let merchant = create_test_merchant();
1949 let plan_data = create_test_plan();
1950 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
1951 let subscriber = Pubkey::from(Keypair::new().pubkey().to_bytes());
1952 let platform_treasury_ata = Pubkey::from(Keypair::new().pubkey().to_bytes());
1953
1954 let instructions = start_subscription()
1955 .plan(plan_key)
1956 .subscriber(subscriber)
1957 .allowance_periods(3) .build_instructions(&merchant, &plan_data, &platform_treasury_ata)
1959 .unwrap();
1960
1961 assert_eq!(instructions.len(), 2);
1962
1963 assert_eq!(instructions[0].program_id, spl_token::id());
1965
1966 let program_id = program_id();
1968 assert_eq!(instructions[1].program_id, program_id);
1969 }
1970
1971 #[test]
1972 fn test_cancel_subscription_builder() {
1973 let merchant = create_test_merchant();
1974 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
1975 let subscriber = Pubkey::from(Keypair::new().pubkey().to_bytes());
1976
1977 let instructions = cancel_subscription()
1978 .plan(plan_key)
1979 .subscriber(subscriber)
1980 .build_instructions(&merchant)
1981 .unwrap();
1982
1983 assert_eq!(instructions.len(), 2);
1984
1985 assert_eq!(instructions[0].program_id, spl_token::id());
1987
1988 let program_id = program_id();
1990 assert_eq!(instructions[1].program_id, program_id);
1991 }
1992
1993 #[test]
1994 fn test_create_merchant_builder() {
1995 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
1996 let usdc_mint = Pubkey::from_str("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v").unwrap();
1997 let treasury_ata = Pubkey::from(Keypair::new().pubkey().to_bytes());
1998
1999 let instruction = create_merchant()
2000 .authority(authority)
2001 .usdc_mint(usdc_mint)
2002 .treasury_ata(treasury_ata)
2003 .platform_fee_bps(50)
2004 .build_instruction()
2005 .unwrap();
2006
2007 let program_id = program_id();
2008 assert_eq!(instruction.program_id, program_id);
2009 assert_eq!(instruction.accounts.len(), 8);
2010 }
2011
2012 #[test]
2013 fn test_create_plan_builder() {
2014 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2015 let plan_id_bytes = {
2016 let mut bytes = [0u8; 32];
2017 let id_bytes = b"premium";
2018 let len = id_bytes.len().min(32);
2019 bytes[..len].copy_from_slice(&id_bytes[..len]);
2020 bytes
2021 };
2022
2023 let plan_args = CreatePlanArgs {
2024 plan_id: "premium".to_string(),
2025 plan_id_bytes,
2026 price_usdc: 5_000_000,
2027 period_secs: 2_592_000,
2028 grace_secs: 432_000,
2029 name: "Premium Plan".to_string(),
2030 };
2031
2032 let instruction = create_plan()
2033 .authority(authority)
2034 .plan_args(plan_args)
2035 .build_instruction()
2036 .unwrap();
2037
2038 let program_id = program_id();
2039 assert_eq!(instruction.program_id, program_id);
2040 assert_eq!(instruction.accounts.len(), 5);
2041 }
2042
2043 #[test]
2044 fn test_builder_missing_required_fields() {
2045 let merchant = create_test_merchant();
2046 let plan_data = create_test_plan();
2047 let platform_treasury_ata = Pubkey::from(Keypair::new().pubkey().to_bytes());
2048
2049 let result = start_subscription()
2051 .subscriber(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2052 .allowance_periods(3)
2053 .build_instructions(&merchant, &plan_data, &platform_treasury_ata);
2054 assert!(result.is_err());
2055 assert!(result.unwrap_err().to_string().contains("Plan not set"));
2056
2057 let result = start_subscription()
2059 .plan(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2060 .allowance_periods(3)
2061 .build_instructions(&merchant, &plan_data, &platform_treasury_ata);
2062 assert!(result.is_err());
2063 assert!(result
2064 .unwrap_err()
2065 .to_string()
2066 .contains("Subscriber not set"));
2067 }
2068
2069 #[test]
2070 fn test_token_program_variants() {
2071 let merchant_token = Merchant {
2073 authority: Pubkey::from(Keypair::new().pubkey().to_bytes()),
2074 usdc_mint: Pubkey::from(Keypair::new().pubkey().to_bytes()), treasury_ata: Pubkey::from(Keypair::new().pubkey().to_bytes()),
2076 platform_fee_bps: 50,
2077 tier: 0, bump: 255,
2079 };
2080
2081 let merchant_token2022 = Merchant {
2082 authority: Pubkey::from(Keypair::new().pubkey().to_bytes()),
2083 usdc_mint: Pubkey::from(Keypair::new().pubkey().to_bytes()), treasury_ata: Pubkey::from(Keypair::new().pubkey().to_bytes()),
2085 platform_fee_bps: 50,
2086 tier: 0, bump: 255,
2088 };
2089
2090 let plan_data = create_test_plan();
2091 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
2092 let subscriber = Pubkey::from(Keypair::new().pubkey().to_bytes());
2093 let platform_treasury_ata = Pubkey::from(Keypair::new().pubkey().to_bytes());
2094
2095 let instructions_token2022 = start_subscription()
2097 .plan(plan_key)
2098 .subscriber(subscriber)
2099 .allowance_periods(3)
2100 .token_program(TokenProgram::Token2022)
2101 .build_instructions(&merchant_token2022, &plan_data, &platform_treasury_ata)
2102 .unwrap();
2103
2104 let instructions_token = start_subscription()
2106 .plan(plan_key)
2107 .subscriber(subscriber)
2108 .allowance_periods(3)
2109 .token_program(TokenProgram::Token)
2110 .build_instructions(&merchant_token, &plan_data, &platform_treasury_ata)
2111 .unwrap();
2112
2113 assert_eq!(instructions_token2022[0].program_id, spl_token_2022::id());
2115 assert_eq!(instructions_token[0].program_id, spl_token::id());
2116 }
2117
2118 #[test]
2119 fn test_init_config_builder() {
2120 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2121 let config_args = InitConfigArgs {
2122 platform_authority: authority,
2123 max_platform_fee_bps: 1000,
2124 fee_basis_points_divisor: 10000,
2125 min_period_seconds: 86400,
2126 default_allowance_periods: 3,
2127 };
2128
2129 let instruction = init_config()
2130 .authority(authority)
2131 .config_args(config_args)
2132 .build_instruction()
2133 .unwrap();
2134
2135 let program_id = program_id();
2136 assert_eq!(instruction.program_id, program_id);
2137 assert_eq!(instruction.accounts.len(), 3);
2138
2139 assert!(!instruction.accounts[0].is_signer); assert!(instruction.accounts[0].is_writable); assert!(instruction.accounts[1].is_signer); assert!(instruction.accounts[1].is_writable); assert!(!instruction.accounts[2].is_signer); assert!(!instruction.accounts[2].is_writable); }
2147
2148 #[test]
2149 fn test_init_config_missing_required_fields() {
2150 let result = init_config()
2152 .config_args(InitConfigArgs {
2153 platform_authority: Pubkey::from(Keypair::new().pubkey().to_bytes()),
2154 max_platform_fee_bps: 1000,
2155 fee_basis_points_divisor: 10000,
2156 min_period_seconds: 86400,
2157 default_allowance_periods: 3,
2158 })
2159 .build_instruction();
2160 assert!(result.is_err());
2161 assert!(result
2162 .unwrap_err()
2163 .to_string()
2164 .contains("Authority not set"));
2165
2166 let result = init_config()
2168 .authority(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2169 .build_instruction();
2170 assert!(result.is_err());
2171 assert!(result
2172 .unwrap_err()
2173 .to_string()
2174 .contains("Config args not set"));
2175 }
2176
2177 #[test]
2178 fn test_update_plan_builder() {
2179 let merchant = create_test_merchant();
2180 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
2181
2182 let update_args = UpdatePlanArgs::new()
2183 .with_name("Updated Plan".to_string())
2184 .with_active(false)
2185 .with_price_usdc(10_000_000); let instruction = update_plan()
2188 .authority(merchant.authority)
2189 .plan_key(plan_key)
2190 .update_args(update_args)
2191 .build_instruction(&merchant)
2192 .unwrap();
2193
2194 let program_id = program_id();
2195 assert_eq!(instruction.program_id, program_id);
2196 assert_eq!(instruction.accounts.len(), 4);
2197
2198 assert!(!instruction.accounts[0].is_signer); assert!(!instruction.accounts[0].is_writable); assert!(!instruction.accounts[1].is_signer); assert!(instruction.accounts[1].is_writable); assert!(!instruction.accounts[2].is_signer); assert!(!instruction.accounts[2].is_writable); assert!(instruction.accounts[3].is_signer); assert!(instruction.accounts[3].is_writable); }
2208
2209 #[test]
2210 fn test_update_plan_builder_missing_required_fields() {
2211 let merchant = create_test_merchant();
2212 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
2213 let update_args = UpdatePlanArgs::new().with_name("Test".to_string());
2214
2215 let result = update_plan()
2217 .plan_key(plan_key)
2218 .update_args(update_args.clone())
2219 .build_instruction(&merchant);
2220 assert!(result.is_err());
2221 assert!(result
2222 .unwrap_err()
2223 .to_string()
2224 .contains("Authority not set"));
2225
2226 let result = update_plan()
2228 .authority(merchant.authority)
2229 .update_args(update_args)
2230 .build_instruction(&merchant);
2231 assert!(result.is_err());
2232 assert!(result.unwrap_err().to_string().contains("Plan key not set"));
2233
2234 let result = update_plan()
2236 .authority(merchant.authority)
2237 .plan_key(plan_key)
2238 .build_instruction(&merchant);
2239 assert!(result.is_err());
2240 assert!(result
2241 .unwrap_err()
2242 .to_string()
2243 .contains("Update args not set"));
2244 }
2245
2246 #[test]
2247 fn test_update_plan_builder_validation() {
2248 let merchant = create_test_merchant();
2249 let wrong_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2250 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
2251
2252 let update_args = UpdatePlanArgs::new().with_name("Test".to_string());
2254 let result = update_plan()
2255 .authority(wrong_authority)
2256 .plan_key(plan_key)
2257 .update_args(update_args)
2258 .build_instruction(&merchant);
2259 assert!(result.is_err());
2260 assert!(result
2261 .unwrap_err()
2262 .to_string()
2263 .contains("Authority does not match merchant authority"));
2264
2265 let empty_args = UpdatePlanArgs::new();
2267 let result = update_plan()
2268 .authority(merchant.authority)
2269 .plan_key(plan_key)
2270 .update_args(empty_args)
2271 .build_instruction(&merchant);
2272 assert!(result.is_err());
2273 assert!(result
2274 .unwrap_err()
2275 .to_string()
2276 .contains("No updates specified"));
2277 }
2278
2279 #[test]
2280 fn test_update_plan_args_functionality() {
2281 let args = UpdatePlanArgs::new()
2283 .with_name("New Plan Name".to_string())
2284 .with_active(true)
2285 .with_price_usdc(5_000_000)
2286 .with_period_secs(2_592_000)
2287 .with_grace_secs(432_000);
2288
2289 assert!(args.has_updates());
2290 assert_eq!(args.name, Some("New Plan Name".to_string()));
2291 assert_eq!(args.active, Some(true));
2292 assert_eq!(args.price_usdc, Some(5_000_000));
2293 assert_eq!(args.period_secs, Some(2_592_000));
2294 assert_eq!(args.grace_secs, Some(432_000));
2295
2296 let name_bytes = args.name_bytes().unwrap();
2298 let expected_name = "New Plan Name";
2299 assert_eq!(&name_bytes[..expected_name.len()], expected_name.as_bytes());
2300 for &byte in &name_bytes[expected_name.len()..] {
2302 assert_eq!(byte, 0);
2303 }
2304
2305 let empty_args = UpdatePlanArgs::new();
2307 assert!(!empty_args.has_updates());
2308 assert!(empty_args.name_bytes().is_none());
2309
2310 let default_args = UpdatePlanArgs::default();
2312 assert!(!default_args.has_updates());
2313 }
2314
2315 #[test]
2316 fn test_renew_subscription_builder() {
2317 let merchant = create_test_merchant();
2318 let plan_data = create_test_plan();
2319 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
2320 let subscriber = Pubkey::from(Keypair::new().pubkey().to_bytes());
2321 let keeper = Pubkey::from(Keypair::new().pubkey().to_bytes());
2322 let keeper_ata = Pubkey::from(Keypair::new().pubkey().to_bytes());
2323 let platform_treasury_ata = Pubkey::from(Keypair::new().pubkey().to_bytes());
2324
2325 let instruction = renew_subscription()
2326 .plan(plan_key)
2327 .subscriber(subscriber)
2328 .keeper(keeper)
2329 .keeper_ata(keeper_ata)
2330 .build_instruction(&merchant, &plan_data, &platform_treasury_ata)
2331 .unwrap();
2332
2333 let program_id = program_id();
2334 assert_eq!(instruction.program_id, program_id);
2335 assert_eq!(instruction.accounts.len(), 12);
2336
2337 assert_eq!(
2339 &instruction.data[..8],
2340 &[45, 75, 154, 194, 160, 10, 111, 183]
2341 );
2342
2343 verify_renew_readonly_accounts(&instruction);
2345 verify_renew_mutable_accounts(&instruction);
2347 verify_renew_signer_accounts(&instruction);
2349 }
2350
2351 fn verify_renew_readonly_accounts(instruction: &Instruction) {
2352 assert!(!instruction.accounts[0].is_writable); assert!(!instruction.accounts[2].is_writable); assert!(!instruction.accounts[3].is_writable); assert!(!instruction.accounts[9].is_writable); assert!(!instruction.accounts[10].is_writable); assert!(!instruction.accounts[11].is_writable); }
2359
2360 fn verify_renew_mutable_accounts(instruction: &Instruction) {
2361 assert!(instruction.accounts[1].is_writable); assert!(instruction.accounts[4].is_writable); assert!(instruction.accounts[5].is_writable); assert!(instruction.accounts[6].is_writable); assert!(instruction.accounts[7].is_writable); assert!(instruction.accounts[8].is_writable); }
2368
2369 fn verify_renew_signer_accounts(instruction: &Instruction) {
2370 assert!(!instruction.accounts[0].is_signer); assert!(!instruction.accounts[1].is_signer); assert!(!instruction.accounts[2].is_signer); assert!(!instruction.accounts[3].is_signer); assert!(!instruction.accounts[4].is_signer); assert!(!instruction.accounts[5].is_signer); assert!(!instruction.accounts[6].is_signer); assert!(instruction.accounts[7].is_signer); assert!(!instruction.accounts[8].is_signer); assert!(!instruction.accounts[9].is_signer); assert!(!instruction.accounts[10].is_signer); assert!(!instruction.accounts[11].is_signer); }
2383
2384 #[test]
2385 fn test_renew_subscription_builder_missing_required_fields() {
2386 let merchant = create_test_merchant();
2387 let plan_data = create_test_plan();
2388 let platform_treasury_ata = Pubkey::from(Keypair::new().pubkey().to_bytes());
2389
2390 let result = renew_subscription()
2392 .subscriber(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2393 .keeper(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2394 .keeper_ata(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2395 .build_instruction(&merchant, &plan_data, &platform_treasury_ata);
2396 assert!(result.is_err());
2397 assert!(result.unwrap_err().to_string().contains("Plan not set"));
2398
2399 let result = renew_subscription()
2401 .plan(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2402 .keeper(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2403 .keeper_ata(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2404 .build_instruction(&merchant, &plan_data, &platform_treasury_ata);
2405 assert!(result.is_err());
2406 assert!(result
2407 .unwrap_err()
2408 .to_string()
2409 .contains("Subscriber not set"));
2410
2411 let result = renew_subscription()
2413 .plan(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2414 .subscriber(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2415 .keeper_ata(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2416 .build_instruction(&merchant, &plan_data, &platform_treasury_ata);
2417 assert!(result.is_err());
2418 assert!(result.unwrap_err().to_string().contains("Keeper not set"));
2419
2420 let result = renew_subscription()
2422 .plan(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2423 .subscriber(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2424 .keeper(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2425 .build_instruction(&merchant, &plan_data, &platform_treasury_ata);
2426 assert!(result.is_err());
2427 assert!(result
2428 .unwrap_err()
2429 .to_string()
2430 .contains("Keeper ATA not set"));
2431 }
2432
2433 #[test]
2434 fn test_renew_subscription_token_program_variants() {
2435 let merchant_token = Merchant {
2437 authority: Pubkey::from(Keypair::new().pubkey().to_bytes()),
2438 usdc_mint: Pubkey::from(Keypair::new().pubkey().to_bytes()),
2439 treasury_ata: Pubkey::from(Keypair::new().pubkey().to_bytes()),
2440 platform_fee_bps: 50,
2441 tier: 0,
2442 bump: 255,
2443 };
2444
2445 let merchant_token2022 = Merchant {
2446 authority: Pubkey::from(Keypair::new().pubkey().to_bytes()),
2447 usdc_mint: Pubkey::from(Keypair::new().pubkey().to_bytes()),
2448 treasury_ata: Pubkey::from(Keypair::new().pubkey().to_bytes()),
2449 platform_fee_bps: 50,
2450 tier: 0,
2451 bump: 255,
2452 };
2453
2454 let plan_data = create_test_plan();
2455 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
2456 let subscriber = Pubkey::from(Keypair::new().pubkey().to_bytes());
2457 let keeper = Pubkey::from(Keypair::new().pubkey().to_bytes());
2458 let keeper_ata = Pubkey::from(Keypair::new().pubkey().to_bytes());
2459 let platform_treasury_ata = Pubkey::from(Keypair::new().pubkey().to_bytes());
2460
2461 let instruction_token2022 = renew_subscription()
2463 .plan(plan_key)
2464 .subscriber(subscriber)
2465 .keeper(keeper)
2466 .keeper_ata(keeper_ata)
2467 .token_program(TokenProgram::Token2022)
2468 .build_instruction(&merchant_token2022, &plan_data, &platform_treasury_ata)
2469 .unwrap();
2470
2471 let instruction_token = renew_subscription()
2473 .plan(plan_key)
2474 .subscriber(subscriber)
2475 .keeper(keeper)
2476 .keeper_ata(keeper_ata)
2477 .token_program(TokenProgram::Token)
2478 .build_instruction(&merchant_token, &plan_data, &platform_treasury_ata)
2479 .unwrap();
2480
2481 assert_eq!(
2483 instruction_token2022.accounts[11].pubkey,
2484 spl_token_2022::id()
2485 );
2486 assert_eq!(instruction_token.accounts[11].pubkey, spl_token::id());
2487 }
2488
2489 #[test]
2490 fn test_close_subscription_builder() {
2491 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
2492 let subscriber = Pubkey::from(Keypair::new().pubkey().to_bytes());
2493
2494 let instruction = close_subscription()
2495 .plan(plan_key)
2496 .subscriber(subscriber)
2497 .build_instruction()
2498 .unwrap();
2499
2500 let program_id = program_id();
2501 assert_eq!(instruction.program_id, program_id);
2502 assert_eq!(instruction.accounts.len(), 2);
2503
2504 assert_eq!(&instruction.data[..8], &[33, 214, 169, 135, 35, 127, 78, 7]);
2506
2507 assert!(instruction.accounts[0].is_writable); assert!(!instruction.accounts[0].is_signer); assert!(instruction.accounts[1].is_writable); assert!(instruction.accounts[1].is_signer); }
2513
2514 #[test]
2515 fn test_close_subscription_builder_missing_required_fields() {
2516 let result = close_subscription()
2518 .subscriber(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2519 .build_instruction();
2520 assert!(result.is_err());
2521 assert!(result.unwrap_err().to_string().contains("Plan not set"));
2522
2523 let result = close_subscription()
2525 .plan(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2526 .build_instruction();
2527 assert!(result.is_err());
2528 assert!(result
2529 .unwrap_err()
2530 .to_string()
2531 .contains("Subscriber not set"));
2532 }
2533
2534 #[test]
2535 fn test_close_subscription_builder_custom_program_id() {
2536 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
2537 let subscriber = Pubkey::from(Keypair::new().pubkey().to_bytes());
2538 let custom_program_id = Pubkey::from(Keypair::new().pubkey().to_bytes());
2539
2540 let instruction = close_subscription()
2541 .plan(plan_key)
2542 .subscriber(subscriber)
2543 .program_id(custom_program_id)
2544 .build_instruction()
2545 .unwrap();
2546
2547 assert_eq!(instruction.program_id, custom_program_id);
2548 }
2549
2550 #[test]
2551 fn test_close_subscription_builder_pda_computation() {
2552 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
2553 let subscriber = Pubkey::from(Keypair::new().pubkey().to_bytes());
2554
2555 let instruction = close_subscription()
2556 .plan(plan_key)
2557 .subscriber(subscriber)
2558 .build_instruction()
2559 .unwrap();
2560
2561 let program_id = program_id();
2563 let expected_subscription_pda =
2564 pda::subscription_address_with_program_id(&plan_key, &subscriber, &program_id);
2565
2566 assert_eq!(instruction.accounts[0].pubkey, expected_subscription_pda);
2567 assert_eq!(instruction.accounts[1].pubkey, subscriber);
2568 }
2569
2570 #[test]
2571 fn test_transfer_authority_builder() {
2572 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2573 let new_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2574
2575 let instruction = transfer_authority()
2576 .platform_authority(platform_authority)
2577 .new_authority(new_authority)
2578 .build_instruction()
2579 .unwrap();
2580
2581 let program_id = program_id();
2582 assert_eq!(instruction.program_id, program_id);
2583 assert_eq!(instruction.accounts.len(), 2);
2584
2585 assert_eq!(
2587 &instruction.data[..8],
2588 &[48, 169, 76, 72, 229, 180, 55, 161]
2589 );
2590
2591 assert!(instruction.accounts[0].is_writable); assert!(!instruction.accounts[0].is_signer); assert!(!instruction.accounts[1].is_writable); assert!(instruction.accounts[1].is_signer); assert_eq!(
2599 instruction.accounts[0].pubkey,
2600 pda::config_address_with_program_id(&program_id)
2601 );
2602 assert_eq!(instruction.accounts[1].pubkey, platform_authority);
2603 }
2604
2605 #[test]
2606 fn test_transfer_authority_builder_missing_required_fields() {
2607 let result = transfer_authority()
2609 .new_authority(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2610 .build_instruction();
2611 assert!(result.is_err());
2612 assert!(result
2613 .unwrap_err()
2614 .to_string()
2615 .contains("Platform authority not set"));
2616
2617 let result = transfer_authority()
2619 .platform_authority(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2620 .build_instruction();
2621 assert!(result.is_err());
2622 assert!(result
2623 .unwrap_err()
2624 .to_string()
2625 .contains("New authority not set"));
2626 }
2627
2628 #[test]
2629 fn test_transfer_authority_builder_custom_program_id() {
2630 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2631 let new_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2632 let custom_program_id = Pubkey::from(Keypair::new().pubkey().to_bytes());
2633
2634 let instruction = transfer_authority()
2635 .platform_authority(platform_authority)
2636 .new_authority(new_authority)
2637 .program_id(custom_program_id)
2638 .build_instruction()
2639 .unwrap();
2640
2641 assert_eq!(instruction.program_id, custom_program_id);
2642 }
2643
2644 #[test]
2645 fn test_transfer_authority_builder_pda_computation() {
2646 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2647 let new_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2648
2649 let instruction = transfer_authority()
2650 .platform_authority(platform_authority)
2651 .new_authority(new_authority)
2652 .build_instruction()
2653 .unwrap();
2654
2655 let program_id = program_id();
2657 let expected_config_pda = pda::config_address_with_program_id(&program_id);
2658
2659 assert_eq!(instruction.accounts[0].pubkey, expected_config_pda);
2660 assert_eq!(instruction.accounts[1].pubkey, platform_authority);
2661 }
2662
2663 #[test]
2664 fn test_transfer_authority_args_serialization() {
2665 let new_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2666
2667 let instruction = transfer_authority()
2669 .platform_authority(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2670 .new_authority(new_authority)
2671 .build_instruction()
2672 .unwrap();
2673
2674 assert!(instruction.data.len() > 8);
2676
2677 let args_data = &instruction.data[8..];
2679 let deserialized_args =
2680 crate::program_types::TransferAuthorityArgs::try_from_slice(args_data).unwrap();
2681 assert_eq!(deserialized_args.new_authority, new_authority);
2682 }
2683
2684 #[test]
2685 fn test_transfer_authority_builder_clone_debug() {
2686 let builder = transfer_authority()
2687 .platform_authority(Pubkey::from(Keypair::new().pubkey().to_bytes()))
2688 .new_authority(Pubkey::from(Keypair::new().pubkey().to_bytes()));
2689
2690 let cloned_builder = builder.clone();
2692 assert_eq!(
2693 cloned_builder.platform_authority,
2694 builder.platform_authority
2695 );
2696 assert_eq!(cloned_builder.new_authority, builder.new_authority);
2697
2698 let debug_str = format!("{builder:?}");
2700 assert!(debug_str.contains("TransferAuthorityBuilder"));
2701 }
2702
2703 #[test]
2704 fn test_accept_authority_builder() {
2705 let new_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2706
2707 let instruction = accept_authority()
2708 .new_authority(new_authority)
2709 .build_instruction()
2710 .unwrap();
2711
2712 let program_id = program_id();
2713 assert_eq!(instruction.program_id, program_id);
2714 assert_eq!(instruction.accounts.len(), 2);
2715
2716 assert_eq!(
2718 &instruction.data[..8],
2719 &[107, 86, 198, 91, 33, 12, 107, 160]
2720 );
2721
2722 assert!(instruction.accounts[0].is_writable); assert!(!instruction.accounts[0].is_signer); assert!(!instruction.accounts[1].is_writable); assert!(instruction.accounts[1].is_signer); assert_eq!(
2730 instruction.accounts[0].pubkey,
2731 pda::config_address_with_program_id(&program_id)
2732 );
2733 assert_eq!(instruction.accounts[1].pubkey, new_authority);
2734 }
2735
2736 #[test]
2737 fn test_accept_authority_builder_missing_required_fields() {
2738 let result = accept_authority().build_instruction();
2740 assert!(result.is_err());
2741 assert!(result
2742 .unwrap_err()
2743 .to_string()
2744 .contains("New authority not set"));
2745 }
2746
2747 #[test]
2748 fn test_accept_authority_builder_custom_program_id() {
2749 let new_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2750 let custom_program_id = Pubkey::from(Keypair::new().pubkey().to_bytes());
2751
2752 let instruction = accept_authority()
2753 .new_authority(new_authority)
2754 .program_id(custom_program_id)
2755 .build_instruction()
2756 .unwrap();
2757
2758 assert_eq!(instruction.program_id, custom_program_id);
2759 }
2760
2761 #[test]
2762 fn test_accept_authority_builder_pda_computation() {
2763 let new_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2764
2765 let instruction = accept_authority()
2766 .new_authority(new_authority)
2767 .build_instruction()
2768 .unwrap();
2769
2770 let program_id = program_id();
2772 let expected_config_pda = pda::config_address_with_program_id(&program_id);
2773
2774 assert_eq!(instruction.accounts[0].pubkey, expected_config_pda);
2775 assert_eq!(instruction.accounts[1].pubkey, new_authority);
2776 }
2777
2778 #[test]
2779 fn test_accept_authority_args_serialization() {
2780 let new_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2781
2782 let instruction = accept_authority()
2784 .new_authority(new_authority)
2785 .build_instruction()
2786 .unwrap();
2787
2788 assert_eq!(instruction.data.len(), 8);
2791
2792 assert_eq!(
2794 &instruction.data[..8],
2795 &[107, 86, 198, 91, 33, 12, 107, 160]
2796 );
2797 }
2798
2799 #[test]
2800 fn test_accept_authority_builder_clone_debug() {
2801 let builder =
2802 accept_authority().new_authority(Pubkey::from(Keypair::new().pubkey().to_bytes()));
2803
2804 let cloned_builder = builder.clone();
2806 assert_eq!(cloned_builder.new_authority, builder.new_authority);
2807
2808 let debug_str = format!("{builder:?}");
2810 assert!(debug_str.contains("AcceptAuthorityBuilder"));
2811 }
2812
2813 #[test]
2814 fn test_accept_authority_builder_default() {
2815 let builder = AcceptAuthorityBuilder::default();
2816 assert!(builder.new_authority.is_none());
2817 assert!(builder.program_id.is_none());
2818 }
2819
2820 #[test]
2821 fn test_accept_authority_convenience_function() {
2822 let new_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2823
2824 let instruction = accept_authority()
2826 .new_authority(new_authority)
2827 .build_instruction()
2828 .unwrap();
2829
2830 let direct_instruction = AcceptAuthorityBuilder::new()
2832 .new_authority(new_authority)
2833 .build_instruction()
2834 .unwrap();
2835
2836 assert_eq!(instruction.program_id, direct_instruction.program_id);
2837 assert_eq!(
2838 instruction.accounts.len(),
2839 direct_instruction.accounts.len()
2840 );
2841 assert_eq!(instruction.data, direct_instruction.data);
2842 }
2843
2844 #[test]
2845 fn test_cancel_authority_transfer_builder() {
2846 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2847
2848 let instruction = cancel_authority_transfer()
2849 .platform_authority(platform_authority)
2850 .build_instruction()
2851 .unwrap();
2852
2853 let program_id = program_id();
2854 assert_eq!(instruction.program_id, program_id);
2855 assert_eq!(instruction.accounts.len(), 2);
2856
2857 assert_eq!(
2859 &instruction.data[..8],
2860 &[94, 131, 125, 184, 183, 24, 125, 229]
2861 );
2862
2863 assert!(instruction.accounts[0].is_writable); assert!(!instruction.accounts[0].is_signer); assert!(!instruction.accounts[1].is_writable); assert!(instruction.accounts[1].is_signer); assert_eq!(
2871 instruction.accounts[0].pubkey,
2872 pda::config_address_with_program_id(&program_id)
2873 );
2874 assert_eq!(instruction.accounts[1].pubkey, platform_authority);
2875 }
2876
2877 #[test]
2878 fn test_cancel_authority_transfer_builder_missing_required_fields() {
2879 let result = cancel_authority_transfer().build_instruction();
2881 assert!(result.is_err());
2882 assert!(result
2883 .unwrap_err()
2884 .to_string()
2885 .contains("Platform authority not set"));
2886 }
2887
2888 #[test]
2889 fn test_cancel_authority_transfer_builder_custom_program_id() {
2890 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2891 let custom_program_id = Pubkey::from(Keypair::new().pubkey().to_bytes());
2892
2893 let instruction = cancel_authority_transfer()
2894 .platform_authority(platform_authority)
2895 .program_id(custom_program_id)
2896 .build_instruction()
2897 .unwrap();
2898
2899 assert_eq!(instruction.program_id, custom_program_id);
2900 }
2901
2902 #[test]
2903 fn test_cancel_authority_transfer_builder_pda_computation() {
2904 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2905
2906 let instruction = cancel_authority_transfer()
2907 .platform_authority(platform_authority)
2908 .build_instruction()
2909 .unwrap();
2910
2911 let program_id = program_id();
2913 let expected_config_pda = pda::config_address_with_program_id(&program_id);
2914
2915 assert_eq!(instruction.accounts[0].pubkey, expected_config_pda);
2916 assert_eq!(instruction.accounts[1].pubkey, platform_authority);
2917 }
2918
2919 #[test]
2920 fn test_cancel_authority_transfer_args_serialization() {
2921 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2922
2923 let instruction = cancel_authority_transfer()
2925 .platform_authority(platform_authority)
2926 .build_instruction()
2927 .unwrap();
2928
2929 assert_eq!(instruction.data.len(), 8);
2932
2933 assert_eq!(
2935 &instruction.data[..8],
2936 &[94, 131, 125, 184, 183, 24, 125, 229]
2937 );
2938 }
2939
2940 #[test]
2941 fn test_cancel_authority_transfer_builder_clone_debug() {
2942 let builder = cancel_authority_transfer()
2943 .platform_authority(Pubkey::from(Keypair::new().pubkey().to_bytes()));
2944
2945 let cloned_builder = builder.clone();
2947 assert_eq!(
2948 cloned_builder.platform_authority,
2949 builder.platform_authority
2950 );
2951
2952 let debug_str = format!("{builder:?}");
2954 assert!(debug_str.contains("CancelAuthorityTransferBuilder"));
2955 }
2956
2957 #[test]
2958 fn test_cancel_authority_transfer_builder_default() {
2959 let builder = CancelAuthorityTransferBuilder::default();
2960 assert!(builder.platform_authority.is_none());
2961 assert!(builder.program_id.is_none());
2962 }
2963
2964 #[test]
2965 fn test_cancel_authority_transfer_convenience_function() {
2966 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2967
2968 let instruction = cancel_authority_transfer()
2970 .platform_authority(platform_authority)
2971 .build_instruction()
2972 .unwrap();
2973
2974 let direct_instruction = CancelAuthorityTransferBuilder::new()
2976 .platform_authority(platform_authority)
2977 .build_instruction()
2978 .unwrap();
2979
2980 assert_eq!(instruction.program_id, direct_instruction.program_id);
2981 assert_eq!(
2982 instruction.accounts.len(),
2983 direct_instruction.accounts.len()
2984 );
2985 assert_eq!(instruction.data, direct_instruction.data);
2986 }
2987
2988 #[test]
2989 fn test_pause_builder() {
2990 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
2991
2992 let instruction = pause()
2993 .platform_authority(platform_authority)
2994 .build_instruction()
2995 .unwrap();
2996
2997 let program_id = program_id();
2998 assert_eq!(instruction.program_id, program_id);
2999 assert_eq!(instruction.accounts.len(), 2);
3000
3001 assert_eq!(
3003 &instruction.data[..8],
3004 &[211, 22, 221, 251, 74, 121, 193, 47]
3005 );
3006
3007 assert!(instruction.accounts[0].is_writable); assert!(!instruction.accounts[0].is_signer); assert!(!instruction.accounts[1].is_writable); assert!(instruction.accounts[1].is_signer); assert_eq!(
3015 instruction.accounts[0].pubkey,
3016 pda::config_address_with_program_id(&program_id)
3017 );
3018 assert_eq!(instruction.accounts[1].pubkey, platform_authority);
3019 }
3020
3021 #[test]
3022 fn test_pause_builder_missing_required_fields() {
3023 let result = pause().build_instruction();
3025 assert!(result.is_err());
3026 assert!(result
3027 .unwrap_err()
3028 .to_string()
3029 .contains("Platform authority not set"));
3030 }
3031
3032 #[test]
3033 fn test_pause_builder_custom_program_id() {
3034 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3035 let custom_program_id = Pubkey::from(Keypair::new().pubkey().to_bytes());
3036
3037 let instruction = pause()
3038 .platform_authority(platform_authority)
3039 .program_id(custom_program_id)
3040 .build_instruction()
3041 .unwrap();
3042
3043 assert_eq!(instruction.program_id, custom_program_id);
3044 }
3045
3046 #[test]
3047 fn test_pause_builder_pda_computation() {
3048 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3049
3050 let instruction = pause()
3051 .platform_authority(platform_authority)
3052 .build_instruction()
3053 .unwrap();
3054
3055 let program_id = program_id();
3057 let expected_config_pda = pda::config_address_with_program_id(&program_id);
3058
3059 assert_eq!(instruction.accounts[0].pubkey, expected_config_pda);
3060 assert_eq!(instruction.accounts[1].pubkey, platform_authority);
3061 }
3062
3063 #[test]
3064 fn test_pause_args_serialization() {
3065 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3066
3067 let instruction = pause()
3069 .platform_authority(platform_authority)
3070 .build_instruction()
3071 .unwrap();
3072
3073 assert_eq!(instruction.data.len(), 8);
3076
3077 assert_eq!(
3079 &instruction.data[..8],
3080 &[211, 22, 221, 251, 74, 121, 193, 47]
3081 );
3082 }
3083
3084 #[test]
3085 fn test_pause_builder_clone_debug() {
3086 let builder = pause().platform_authority(Pubkey::from(Keypair::new().pubkey().to_bytes()));
3087
3088 let cloned_builder = builder.clone();
3090 assert_eq!(
3091 cloned_builder.platform_authority,
3092 builder.platform_authority
3093 );
3094
3095 let debug_str = format!("{builder:?}");
3097 assert!(debug_str.contains("PauseBuilder"));
3098 }
3099
3100 #[test]
3101 fn test_pause_builder_default() {
3102 let builder = PauseBuilder::default();
3103 assert!(builder.platform_authority.is_none());
3104 assert!(builder.program_id.is_none());
3105 }
3106
3107 #[test]
3108 fn test_pause_convenience_function() {
3109 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3110
3111 let instruction = pause()
3113 .platform_authority(platform_authority)
3114 .build_instruction()
3115 .unwrap();
3116
3117 let direct_instruction = PauseBuilder::new()
3119 .platform_authority(platform_authority)
3120 .build_instruction()
3121 .unwrap();
3122
3123 assert_eq!(instruction.program_id, direct_instruction.program_id);
3124 assert_eq!(
3125 instruction.accounts.len(),
3126 direct_instruction.accounts.len()
3127 );
3128 assert_eq!(instruction.data, direct_instruction.data);
3129 }
3130
3131 #[test]
3132 fn test_unpause_builder() {
3133 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3134
3135 let instruction = unpause()
3136 .platform_authority(platform_authority)
3137 .build_instruction()
3138 .unwrap();
3139
3140 let program_id = program_id();
3141 assert_eq!(instruction.program_id, program_id);
3142 assert_eq!(instruction.accounts.len(), 2);
3143
3144 assert_eq!(
3146 &instruction.data[..8],
3147 &[169, 144, 4, 38, 10, 141, 188, 255]
3148 );
3149
3150 assert!(instruction.accounts[0].is_writable); assert!(!instruction.accounts[0].is_signer); assert!(!instruction.accounts[1].is_writable); assert!(instruction.accounts[1].is_signer); assert_eq!(
3158 instruction.accounts[0].pubkey,
3159 pda::config_address_with_program_id(&program_id)
3160 );
3161 assert_eq!(instruction.accounts[1].pubkey, platform_authority);
3162 }
3163
3164 #[test]
3165 fn test_unpause_builder_missing_required_fields() {
3166 let result = unpause().build_instruction();
3168 assert!(result.is_err());
3169 assert!(result
3170 .unwrap_err()
3171 .to_string()
3172 .contains("Platform authority not set"));
3173 }
3174
3175 #[test]
3176 fn test_unpause_builder_custom_program_id() {
3177 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3178 let custom_program_id = Pubkey::from(Keypair::new().pubkey().to_bytes());
3179
3180 let instruction = unpause()
3181 .platform_authority(platform_authority)
3182 .program_id(custom_program_id)
3183 .build_instruction()
3184 .unwrap();
3185
3186 assert_eq!(instruction.program_id, custom_program_id);
3187 }
3188
3189 #[test]
3190 fn test_unpause_builder_pda_computation() {
3191 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3192
3193 let instruction = unpause()
3194 .platform_authority(platform_authority)
3195 .build_instruction()
3196 .unwrap();
3197
3198 let program_id = program_id();
3200 let expected_config_pda = pda::config_address_with_program_id(&program_id);
3201
3202 assert_eq!(instruction.accounts[0].pubkey, expected_config_pda);
3203 assert_eq!(instruction.accounts[1].pubkey, platform_authority);
3204 }
3205
3206 #[test]
3207 fn test_unpause_args_serialization() {
3208 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3209
3210 let instruction = unpause()
3212 .platform_authority(platform_authority)
3213 .build_instruction()
3214 .unwrap();
3215
3216 assert_eq!(instruction.data.len(), 8);
3219
3220 assert_eq!(
3222 &instruction.data[..8],
3223 &[169, 144, 4, 38, 10, 141, 188, 255]
3224 );
3225 }
3226
3227 #[test]
3228 fn test_unpause_builder_clone_debug() {
3229 let builder =
3230 unpause().platform_authority(Pubkey::from(Keypair::new().pubkey().to_bytes()));
3231
3232 let cloned_builder = builder.clone();
3234 assert_eq!(
3235 cloned_builder.platform_authority,
3236 builder.platform_authority
3237 );
3238
3239 let debug_str = format!("{builder:?}");
3241 assert!(debug_str.contains("UnpauseBuilder"));
3242 }
3243
3244 #[test]
3245 fn test_unpause_builder_default() {
3246 let builder = UnpauseBuilder::default();
3247 assert!(builder.platform_authority.is_none());
3248 assert!(builder.program_id.is_none());
3249 }
3250
3251 #[test]
3252 fn test_unpause_convenience_function() {
3253 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3254
3255 let instruction = unpause()
3257 .platform_authority(platform_authority)
3258 .build_instruction()
3259 .unwrap();
3260
3261 let direct_instruction = UnpauseBuilder::new()
3263 .platform_authority(platform_authority)
3264 .build_instruction()
3265 .unwrap();
3266
3267 assert_eq!(instruction.program_id, direct_instruction.program_id);
3268 assert_eq!(
3269 instruction.accounts.len(),
3270 direct_instruction.accounts.len()
3271 );
3272 assert_eq!(instruction.data, direct_instruction.data);
3273 }
3274
3275 #[test]
3278 fn test_update_config_builder_basic() {
3279 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3280
3281 let instruction = update_config()
3282 .platform_authority(platform_authority)
3283 .keeper_fee_bps(25)
3284 .build_instruction()
3285 .unwrap();
3286
3287 assert_eq!(instruction.program_id, program_id());
3288 assert_eq!(instruction.accounts.len(), 2);
3289
3290 let expected_config_pda = pda::config_address_with_program_id(&program_id());
3292 assert_eq!(instruction.accounts[0].pubkey, expected_config_pda);
3293 assert!(instruction.accounts[0].is_writable);
3294 assert!(!instruction.accounts[0].is_signer);
3295
3296 assert_eq!(instruction.accounts[1].pubkey, platform_authority);
3298 assert!(!instruction.accounts[1].is_writable);
3299 assert!(instruction.accounts[1].is_signer);
3300 }
3301
3302 #[test]
3303 fn test_update_config_builder_all_fields() {
3304 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3305
3306 let instruction = update_config()
3307 .platform_authority(platform_authority)
3308 .keeper_fee_bps(50)
3309 .max_withdrawal_amount(1_000_000_000)
3310 .max_grace_period_seconds(604_800)
3311 .min_platform_fee_bps(50)
3312 .max_platform_fee_bps(1000)
3313 .min_period_seconds(86_400)
3314 .default_allowance_periods(5)
3315 .build_instruction()
3316 .unwrap();
3317
3318 assert_eq!(instruction.program_id, program_id());
3319 assert_eq!(instruction.accounts.len(), 2);
3320 }
3321
3322 #[test]
3323 fn test_update_config_builder_missing_authority() {
3324 let result = update_config().keeper_fee_bps(25).build_instruction();
3325
3326 assert!(result.is_err());
3327 assert!(result
3328 .unwrap_err()
3329 .to_string()
3330 .contains("Platform authority not set"));
3331 }
3332
3333 #[test]
3334 fn test_update_config_builder_no_updates() {
3335 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3336
3337 let result = update_config()
3338 .platform_authority(platform_authority)
3339 .build_instruction();
3340
3341 assert!(result.is_err());
3342 assert!(result
3343 .unwrap_err()
3344 .to_string()
3345 .contains("At least one configuration field must be set"));
3346 }
3347
3348 #[test]
3349 fn test_update_config_builder_keeper_fee_too_high() {
3350 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3351
3352 let result = update_config()
3353 .platform_authority(platform_authority)
3354 .keeper_fee_bps(101)
3355 .build_instruction();
3356
3357 assert!(result.is_err());
3358 assert!(result
3359 .unwrap_err()
3360 .to_string()
3361 .contains("Keeper fee must be <= 100"));
3362 }
3363
3364 #[test]
3365 fn test_update_config_builder_min_fee_greater_than_max() {
3366 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3367
3368 let result = update_config()
3369 .platform_authority(platform_authority)
3370 .min_platform_fee_bps(200)
3371 .max_platform_fee_bps(100)
3372 .build_instruction();
3373
3374 assert!(result.is_err());
3375 assert!(result
3376 .unwrap_err()
3377 .to_string()
3378 .contains("Minimum platform fee must be <= maximum platform fee"));
3379 }
3380
3381 #[test]
3382 fn test_update_config_builder_zero_max_withdrawal() {
3383 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3384
3385 let result = update_config()
3386 .platform_authority(platform_authority)
3387 .max_withdrawal_amount(0)
3388 .build_instruction();
3389
3390 assert!(result.is_err());
3391 assert!(result
3392 .unwrap_err()
3393 .to_string()
3394 .contains("Maximum withdrawal amount must be > 0"));
3395 }
3396
3397 #[test]
3398 fn test_update_config_builder_zero_max_grace_period() {
3399 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3400
3401 let result = update_config()
3402 .platform_authority(platform_authority)
3403 .max_grace_period_seconds(0)
3404 .build_instruction();
3405
3406 assert!(result.is_err());
3407 assert!(result
3408 .unwrap_err()
3409 .to_string()
3410 .contains("Maximum grace period must be > 0"));
3411 }
3412
3413 #[test]
3414 fn test_update_config_builder_zero_min_period() {
3415 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3416
3417 let result = update_config()
3418 .platform_authority(platform_authority)
3419 .min_period_seconds(0)
3420 .build_instruction();
3421
3422 assert!(result.is_err());
3423 assert!(result
3424 .unwrap_err()
3425 .to_string()
3426 .contains("Minimum period must be > 0"));
3427 }
3428
3429 #[test]
3430 fn test_update_config_builder_zero_allowance_periods() {
3431 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3432
3433 let result = update_config()
3434 .platform_authority(platform_authority)
3435 .default_allowance_periods(0)
3436 .build_instruction();
3437
3438 assert!(result.is_err());
3439 assert!(result
3440 .unwrap_err()
3441 .to_string()
3442 .contains("Default allowance periods must be > 0"));
3443 }
3444
3445 #[test]
3446 fn test_update_config_builder_custom_program_id() {
3447 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3448 let custom_program_id = Pubkey::from(Keypair::new().pubkey().to_bytes());
3449
3450 let instruction = update_config()
3451 .platform_authority(platform_authority)
3452 .keeper_fee_bps(25)
3453 .program_id(custom_program_id)
3454 .build_instruction()
3455 .unwrap();
3456
3457 assert_eq!(instruction.program_id, custom_program_id);
3458 }
3459
3460 #[test]
3461 fn test_update_config_builder_pda_computation() {
3462 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3463
3464 let instruction = update_config()
3465 .platform_authority(platform_authority)
3466 .keeper_fee_bps(25)
3467 .build_instruction()
3468 .unwrap();
3469
3470 let program_id = program_id();
3472 let expected_config_pda = pda::config_address_with_program_id(&program_id);
3473
3474 assert_eq!(instruction.accounts[0].pubkey, expected_config_pda);
3475 assert_eq!(instruction.accounts[1].pubkey, platform_authority);
3476 }
3477
3478 #[test]
3479 fn test_update_config_args_serialization() {
3480 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3481
3482 let instruction = update_config()
3484 .platform_authority(platform_authority)
3485 .keeper_fee_bps(25)
3486 .max_withdrawal_amount(1_000_000)
3487 .build_instruction()
3488 .unwrap();
3489
3490 assert!(instruction.data.len() > 8);
3492
3493 assert_eq!(
3495 &instruction.data[..8],
3496 &[29, 158, 252, 191, 10, 83, 219, 99]
3497 );
3498 }
3499
3500 #[test]
3501 fn test_update_config_builder_clone_debug() {
3502 let builder = update_config()
3503 .platform_authority(Pubkey::from(Keypair::new().pubkey().to_bytes()))
3504 .keeper_fee_bps(25);
3505
3506 let cloned_builder = builder.clone();
3508 assert_eq!(
3509 cloned_builder.platform_authority,
3510 builder.platform_authority
3511 );
3512 assert_eq!(cloned_builder.keeper_fee_bps, builder.keeper_fee_bps);
3513
3514 let debug_str = format!("{builder:?}");
3516 assert!(debug_str.contains("UpdateConfigBuilder"));
3517 }
3518
3519 #[test]
3520 fn test_update_config_builder_default() {
3521 let builder = UpdateConfigBuilder::default();
3522 assert!(builder.platform_authority.is_none());
3523 assert!(builder.keeper_fee_bps.is_none());
3524 assert!(builder.max_withdrawal_amount.is_none());
3525 assert!(builder.max_grace_period_seconds.is_none());
3526 assert!(builder.min_platform_fee_bps.is_none());
3527 assert!(builder.max_platform_fee_bps.is_none());
3528 assert!(builder.min_period_seconds.is_none());
3529 assert!(builder.default_allowance_periods.is_none());
3530 assert!(builder.program_id.is_none());
3531 }
3532
3533 #[test]
3534 fn test_update_config_convenience_function() {
3535 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3536
3537 let instruction = update_config()
3539 .platform_authority(platform_authority)
3540 .keeper_fee_bps(25)
3541 .build_instruction()
3542 .unwrap();
3543
3544 let direct_instruction = UpdateConfigBuilder::new()
3546 .platform_authority(platform_authority)
3547 .keeper_fee_bps(25)
3548 .build_instruction()
3549 .unwrap();
3550
3551 assert_eq!(instruction.program_id, direct_instruction.program_id);
3552 assert_eq!(
3553 instruction.accounts.len(),
3554 direct_instruction.accounts.len()
3555 );
3556 assert_eq!(instruction.data, direct_instruction.data);
3557 }
3558
3559 #[test]
3560 fn test_update_config_builder_partial_updates() {
3561 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3562
3563 let instruction1 = update_config()
3565 .platform_authority(platform_authority)
3566 .keeper_fee_bps(30)
3567 .build_instruction()
3568 .unwrap();
3569 assert_eq!(instruction1.accounts.len(), 2);
3570
3571 let instruction2 = update_config()
3573 .platform_authority(platform_authority)
3574 .max_withdrawal_amount(5_000_000)
3575 .build_instruction()
3576 .unwrap();
3577 assert_eq!(instruction2.accounts.len(), 2);
3578
3579 let instruction3 = update_config()
3581 .platform_authority(platform_authority)
3582 .min_platform_fee_bps(100)
3583 .max_platform_fee_bps(500)
3584 .build_instruction()
3585 .unwrap();
3586 assert_eq!(instruction3.accounts.len(), 2);
3587 }
3588
3589 #[test]
3590 fn test_update_config_builder_edge_cases() {
3591 let platform_authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3592
3593 let instruction1 = update_config()
3595 .platform_authority(platform_authority)
3596 .keeper_fee_bps(100)
3597 .build_instruction()
3598 .unwrap();
3599 assert_eq!(instruction1.accounts.len(), 2);
3600
3601 let instruction2 = update_config()
3603 .platform_authority(platform_authority)
3604 .min_platform_fee_bps(100)
3605 .max_platform_fee_bps(100)
3606 .build_instruction()
3607 .unwrap();
3608 assert_eq!(instruction2.accounts.len(), 2);
3609
3610 let instruction3 = update_config()
3612 .platform_authority(platform_authority)
3613 .max_withdrawal_amount(1)
3614 .max_grace_period_seconds(1)
3615 .min_period_seconds(1)
3616 .default_allowance_periods(1)
3617 .build_instruction()
3618 .unwrap();
3619 assert_eq!(instruction3.accounts.len(), 2);
3620 }
3621
3622 #[test]
3623 fn test_update_merchant_tier_builder() {
3624 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3625 let merchant = Pubkey::from(Keypair::new().pubkey().to_bytes());
3626
3627 let instruction = update_merchant_tier()
3628 .authority(authority)
3629 .merchant(merchant)
3630 .new_tier(1) .build_instruction()
3632 .unwrap();
3633
3634 let program_id = program_id();
3635 assert_eq!(instruction.program_id, program_id);
3636 assert_eq!(instruction.accounts.len(), 3);
3637
3638 assert_eq!(
3640 &instruction.data[..8],
3641 &[24, 54, 190, 70, 221, 93, 3, 64]
3642 );
3643
3644 assert!(!instruction.accounts[0].is_writable); assert!(!instruction.accounts[0].is_signer); assert!(instruction.accounts[1].is_writable); assert!(!instruction.accounts[1].is_signer); assert!(!instruction.accounts[2].is_writable); assert!(instruction.accounts[2].is_signer); assert_eq!(
3654 instruction.accounts[0].pubkey,
3655 pda::config_address_with_program_id(&program_id)
3656 );
3657 assert_eq!(instruction.accounts[1].pubkey, merchant);
3658 assert_eq!(instruction.accounts[2].pubkey, authority);
3659 }
3660
3661 #[test]
3662 fn test_update_merchant_tier_builder_all_tiers() {
3663 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3664 let merchant = Pubkey::from(Keypair::new().pubkey().to_bytes());
3665
3666 let instruction_free = update_merchant_tier()
3668 .authority(authority)
3669 .merchant(merchant)
3670 .new_tier(0)
3671 .build_instruction()
3672 .unwrap();
3673 assert_eq!(instruction_free.accounts.len(), 3);
3674
3675 let instruction_pro = update_merchant_tier()
3677 .authority(authority)
3678 .merchant(merchant)
3679 .new_tier(1)
3680 .build_instruction()
3681 .unwrap();
3682 assert_eq!(instruction_pro.accounts.len(), 3);
3683
3684 let instruction_enterprise = update_merchant_tier()
3686 .authority(authority)
3687 .merchant(merchant)
3688 .new_tier(2)
3689 .build_instruction()
3690 .unwrap();
3691 assert_eq!(instruction_enterprise.accounts.len(), 3);
3692 }
3693
3694 #[test]
3695 fn test_update_merchant_tier_builder_missing_required_fields() {
3696 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3697 let merchant = Pubkey::from(Keypair::new().pubkey().to_bytes());
3698
3699 let result = update_merchant_tier()
3701 .merchant(merchant)
3702 .new_tier(1)
3703 .build_instruction();
3704 assert!(result.is_err());
3705 assert!(result
3706 .unwrap_err()
3707 .to_string()
3708 .contains("Authority not set"));
3709
3710 let result = update_merchant_tier()
3712 .authority(authority)
3713 .new_tier(1)
3714 .build_instruction();
3715 assert!(result.is_err());
3716 assert!(result
3717 .unwrap_err()
3718 .to_string()
3719 .contains("Merchant not set"));
3720
3721 let result = update_merchant_tier()
3723 .authority(authority)
3724 .merchant(merchant)
3725 .build_instruction();
3726 assert!(result.is_err());
3727 assert!(result
3728 .unwrap_err()
3729 .to_string()
3730 .contains("New tier not set"));
3731 }
3732
3733 #[test]
3734 fn test_update_merchant_tier_builder_invalid_tier() {
3735 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3736 let merchant = Pubkey::from(Keypair::new().pubkey().to_bytes());
3737
3738 let result = update_merchant_tier()
3740 .authority(authority)
3741 .merchant(merchant)
3742 .new_tier(3)
3743 .build_instruction();
3744 assert!(result.is_err());
3745 assert!(result
3746 .unwrap_err()
3747 .to_string()
3748 .contains("New tier must be 0 (Free), 1 (Pro), or 2 (Enterprise)"));
3749
3750 let result = update_merchant_tier()
3752 .authority(authority)
3753 .merchant(merchant)
3754 .new_tier(255)
3755 .build_instruction();
3756 assert!(result.is_err());
3757 }
3758
3759 #[test]
3760 fn test_update_merchant_tier_builder_custom_program_id() {
3761 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3762 let merchant = Pubkey::from(Keypair::new().pubkey().to_bytes());
3763 let custom_program_id = Pubkey::from(Keypair::new().pubkey().to_bytes());
3764
3765 let instruction = update_merchant_tier()
3766 .authority(authority)
3767 .merchant(merchant)
3768 .new_tier(1)
3769 .program_id(custom_program_id)
3770 .build_instruction()
3771 .unwrap();
3772
3773 assert_eq!(instruction.program_id, custom_program_id);
3774 }
3775
3776 #[test]
3777 fn test_update_merchant_tier_builder_pda_computation() {
3778 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3779 let merchant = Pubkey::from(Keypair::new().pubkey().to_bytes());
3780
3781 let instruction = update_merchant_tier()
3782 .authority(authority)
3783 .merchant(merchant)
3784 .new_tier(1)
3785 .build_instruction()
3786 .unwrap();
3787
3788 let program_id = program_id();
3790 let expected_config_pda = pda::config_address_with_program_id(&program_id);
3791
3792 assert_eq!(instruction.accounts[0].pubkey, expected_config_pda);
3793 assert_eq!(instruction.accounts[1].pubkey, merchant);
3794 assert_eq!(instruction.accounts[2].pubkey, authority);
3795 }
3796
3797 #[test]
3798 fn test_update_merchant_tier_args_serialization() {
3799 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3800 let merchant = Pubkey::from(Keypair::new().pubkey().to_bytes());
3801
3802 let instruction = update_merchant_tier()
3804 .authority(authority)
3805 .merchant(merchant)
3806 .new_tier(1) .build_instruction()
3808 .unwrap();
3809
3810 assert_eq!(instruction.data.len(), 9);
3813
3814 assert_eq!(
3816 &instruction.data[..8],
3817 &[24, 54, 190, 70, 221, 93, 3, 64]
3818 );
3819
3820 assert_eq!(instruction.data[8], 1); }
3823
3824 #[test]
3825 fn test_update_merchant_tier_builder_clone_debug() {
3826 let builder = update_merchant_tier()
3827 .authority(Pubkey::from(Keypair::new().pubkey().to_bytes()))
3828 .merchant(Pubkey::from(Keypair::new().pubkey().to_bytes()))
3829 .new_tier(1);
3830
3831 let cloned_builder = builder.clone();
3833 assert_eq!(cloned_builder.authority, builder.authority);
3834 assert_eq!(cloned_builder.merchant, builder.merchant);
3835 assert_eq!(cloned_builder.new_tier, builder.new_tier);
3836
3837 let debug_str = format!("{builder:?}");
3839 assert!(debug_str.contains("UpdateMerchantTierBuilder"));
3840 }
3841
3842 #[test]
3843 fn test_update_merchant_tier_builder_default() {
3844 let builder = UpdateMerchantTierBuilder::default();
3845 assert!(builder.authority.is_none());
3846 assert!(builder.merchant.is_none());
3847 assert!(builder.new_tier.is_none());
3848 assert!(builder.program_id.is_none());
3849 }
3850
3851 #[test]
3852 fn test_update_merchant_tier_convenience_function() {
3853 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3854 let merchant = Pubkey::from(Keypair::new().pubkey().to_bytes());
3855
3856 let instruction = update_merchant_tier()
3858 .authority(authority)
3859 .merchant(merchant)
3860 .new_tier(1)
3861 .build_instruction()
3862 .unwrap();
3863
3864 let direct_instruction = UpdateMerchantTierBuilder::new()
3866 .authority(authority)
3867 .merchant(merchant)
3868 .new_tier(1)
3869 .build_instruction()
3870 .unwrap();
3871
3872 assert_eq!(instruction.program_id, direct_instruction.program_id);
3873 assert_eq!(
3874 instruction.accounts.len(),
3875 direct_instruction.accounts.len()
3876 );
3877 assert_eq!(instruction.data, direct_instruction.data);
3878 }
3879
3880 #[test]
3881 fn test_update_plan_terms_builder_all_fields() {
3882 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3883 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
3884
3885 let instruction = update_plan_terms()
3886 .authority(authority)
3887 .plan_key(plan_key)
3888 .price_usdc(10_000_000) .period_secs(2_592_000) .grace_secs(777_600) .name("Updated Plan".to_string())
3892 .build_instruction()
3893 .unwrap();
3894
3895 let program_id = program_id();
3896 assert_eq!(instruction.program_id, program_id);
3897 assert_eq!(instruction.accounts.len(), 4);
3898
3899 assert_eq!(&instruction.data[..8], &[224, 68, 224, 41, 169, 52, 124, 221]);
3901 }
3902
3903 #[test]
3904 fn test_update_plan_terms_builder_single_field() {
3905 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3906 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
3907
3908 let instruction = update_plan_terms()
3910 .authority(authority)
3911 .plan_key(plan_key)
3912 .price_usdc(20_000_000)
3913 .build_instruction()
3914 .unwrap();
3915
3916 assert_eq!(instruction.program_id, program_id());
3917 assert_eq!(instruction.accounts.len(), 4);
3918
3919 let instruction = update_plan_terms()
3921 .authority(authority)
3922 .plan_key(plan_key)
3923 .period_secs(604_800) .build_instruction()
3925 .unwrap();
3926
3927 assert_eq!(instruction.program_id, program_id());
3928 assert_eq!(instruction.accounts.len(), 4);
3929
3930 let instruction = update_plan_terms()
3932 .authority(authority)
3933 .plan_key(plan_key)
3934 .grace_secs(86_400) .build_instruction()
3936 .unwrap();
3937
3938 assert_eq!(instruction.program_id, program_id());
3939 assert_eq!(instruction.accounts.len(), 4);
3940
3941 let instruction = update_plan_terms()
3943 .authority(authority)
3944 .plan_key(plan_key)
3945 .name("New Name".to_string())
3946 .build_instruction()
3947 .unwrap();
3948
3949 assert_eq!(instruction.program_id, program_id());
3950 assert_eq!(instruction.accounts.len(), 4);
3951 }
3952
3953 #[test]
3954 fn test_update_plan_terms_validation_no_fields() {
3955 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3956 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
3957
3958 let result = update_plan_terms()
3959 .authority(authority)
3960 .plan_key(plan_key)
3961 .build_instruction();
3962
3963 assert!(result.is_err());
3964 assert!(result
3965 .unwrap_err()
3966 .to_string()
3967 .contains("At least one field must be set"));
3968 }
3969
3970 #[test]
3971 fn test_update_plan_terms_validation_missing_authority() {
3972 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
3973
3974 let result = update_plan_terms()
3975 .plan_key(plan_key)
3976 .price_usdc(10_000_000)
3977 .build_instruction();
3978
3979 assert!(result.is_err());
3980 assert!(result.unwrap_err().to_string().contains("Authority not set"));
3981 }
3982
3983 #[test]
3984 fn test_update_plan_terms_validation_missing_plan() {
3985 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3986
3987 let result = update_plan_terms()
3988 .authority(authority)
3989 .price_usdc(10_000_000)
3990 .build_instruction();
3991
3992 assert!(result.is_err());
3993 assert!(result.unwrap_err().to_string().contains("Plan key not set"));
3994 }
3995
3996 #[test]
3997 fn test_update_plan_terms_validation_zero_price() {
3998 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
3999 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
4000
4001 let result = update_plan_terms()
4002 .authority(authority)
4003 .plan_key(plan_key)
4004 .price_usdc(0)
4005 .build_instruction();
4006
4007 assert!(result.is_err());
4008 assert!(result.unwrap_err().to_string().contains("Price must be > 0"));
4009 }
4010
4011 #[test]
4012 fn test_update_plan_terms_validation_max_price() {
4013 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
4014 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
4015
4016 let result = update_plan_terms()
4017 .authority(authority)
4018 .plan_key(plan_key)
4019 .price_usdc(1_000_000_000_001) .build_instruction();
4021
4022 assert!(result.is_err());
4023 assert!(result
4024 .unwrap_err()
4025 .to_string()
4026 .contains("Price must be <= 1,000,000 USDC"));
4027 }
4028
4029 #[test]
4030 fn test_update_plan_terms_validation_grace_exceeds_30_percent() {
4031 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
4032 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
4033
4034 let result = update_plan_terms()
4035 .authority(authority)
4036 .plan_key(plan_key)
4037 .period_secs(2_592_000) .grace_secs(800_000) .build_instruction();
4040
4041 assert!(result.is_err());
4042 assert!(result
4043 .unwrap_err()
4044 .to_string()
4045 .contains("Grace period must be <= 30%"));
4046 }
4047
4048 #[test]
4049 fn test_update_plan_terms_validation_empty_name() {
4050 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
4051 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
4052
4053 let result = update_plan_terms()
4054 .authority(authority)
4055 .plan_key(plan_key)
4056 .name(String::new())
4057 .build_instruction();
4058
4059 assert!(result.is_err());
4060 assert!(result
4061 .unwrap_err()
4062 .to_string()
4063 .contains("Name must not be empty"));
4064 }
4065
4066 #[test]
4067 fn test_update_plan_terms_validation_name_too_long() {
4068 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
4069 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
4070
4071 let long_name = "a".repeat(33); let result = update_plan_terms()
4074 .authority(authority)
4075 .plan_key(plan_key)
4076 .name(long_name)
4077 .build_instruction();
4078
4079 assert!(result.is_err());
4080 assert!(result
4081 .unwrap_err()
4082 .to_string()
4083 .contains("Name must be <= 32 bytes"));
4084 }
4085
4086 #[test]
4087 fn test_update_plan_terms_convenience_function() {
4088 let authority = Pubkey::from(Keypair::new().pubkey().to_bytes());
4089 let plan_key = Pubkey::from(Keypair::new().pubkey().to_bytes());
4090
4091 let instruction = update_plan_terms()
4092 .authority(authority)
4093 .plan_key(plan_key)
4094 .price_usdc(15_000_000)
4095 .build_instruction()
4096 .unwrap();
4097
4098 let direct_instruction = UpdatePlanTermsBuilder::new()
4100 .authority(authority)
4101 .plan_key(plan_key)
4102 .price_usdc(15_000_000)
4103 .build_instruction()
4104 .unwrap();
4105
4106 assert_eq!(instruction.program_id, direct_instruction.program_id);
4107 assert_eq!(
4108 instruction.accounts.len(),
4109 direct_instruction.accounts.len()
4110 );
4111 assert_eq!(instruction.data, direct_instruction.data);
4112 }
4113}