1#![allow(deprecated)]
5
6#[cfg(feature = "codama")]
7use codama_macros::{CodamaInstructions, CodamaType};
8use {
9 crate::state::{Authorized, Lockup, StakeAuthorize},
10 solana_clock::{Epoch, UnixTimestamp},
11 solana_pubkey::Pubkey,
12};
13#[cfg(feature = "bincode")]
14use {
15 crate::{config, program::ID, state::StakeStateV2},
16 solana_instruction::{AccountMeta, Instruction},
17};
18
19#[cfg(feature = "bincode")]
25const CLOCK_ID: Pubkey = Pubkey::from_str_const("SysvarC1ock11111111111111111111111111111111");
26
27#[cfg(feature = "bincode")]
28const RENT_ID: Pubkey = Pubkey::from_str_const("SysvarRent111111111111111111111111111111111");
29
30#[cfg(feature = "bincode")]
31const STAKE_HISTORY_ID: Pubkey =
32 Pubkey::from_str_const("SysvarStakeHistory1111111111111111111111111");
33
34#[cfg_attr(
39 feature = "serde",
40 derive(serde_derive::Deserialize, serde_derive::Serialize)
41)]
42#[cfg_attr(feature = "codama", derive(CodamaInstructions))]
43#[derive(Debug, PartialEq, Eq, Clone)]
44pub enum StakeInstruction {
45 #[cfg_attr(
55 feature = "codama",
56 codama(account(name = "stake", writable, docs = "Uninitialized stake account")),
57 codama(account(name = "rent_sysvar", docs = "Rent sysvar", default_value = sysvar("rent")))
58 )]
59 Initialize(Authorized, Lockup),
60
61 #[cfg_attr(
70 feature = "codama",
71 codama(account(name = "stake", writable, docs = "Stake account to be updated")),
72 codama(account(name = "clock_sysvar", docs = "Clock sysvar", default_value = sysvar("clock"))),
73 codama(account(name = "authority", signer, docs = "The stake or withdraw authority")),
74 codama(account(
75 name = "lockup_authority",
76 optional,
77 signer,
78 docs = "Lockup authority, if updating `StakeAuthorize::Withdrawer` before lockup expiration"
79 ))
80 )]
81 Authorize(Pubkey, StakeAuthorize),
82
83 #[cfg_attr(
96 feature = "codama",
97 codama(account(
98 name = "stake",
99 writable,
100 docs = "Initialized stake account to be delegated"
101 )),
102 codama(account(
103 name = "vote",
104 docs = "Vote account to which this stake will be delegated"
105 )),
106 codama(account(name = "clock_sysvar", docs = "Clock sysvar", default_value = sysvar("clock"))),
107 codama(account(
108 name = "stake_history",
109 docs = "Stake history sysvar that carries stake warmup/cooldown history",
110 default_value = sysvar("stake_history")
111 )),
112 codama(account(name = "unused", docs = "Unused account, formerly the stake config")),
113 codama(account(name = "stake_authority", signer, docs = "Stake authority"))
114 )]
115 DelegateStake,
116
117 #[cfg_attr(
124 feature = "codama",
125 codama(account(
126 name = "stake",
127 writable,
128 docs = "Stake account to be split; must be in the Initialized or Stake state"
129 )),
130 codama(account(
131 name = "split_stake",
132 writable,
133 docs = "Uninitialized stake account that will take the split-off amount"
134 )),
135 codama(account(name = "stake_authority", signer, docs = "Stake authority"))
136 )]
137 Split(#[cfg_attr(feature = "codama", codama(name = "args"))] u64),
140
141 #[cfg_attr(
154 feature = "codama",
155 codama(account(
156 name = "stake",
157 writable,
158 docs = "Stake account from which to withdraw"
159 )),
160 codama(account(name = "recipient", writable, docs = "Recipient account")),
161 codama(account(name = "clock_sysvar", docs = "Clock sysvar", default_value = sysvar("clock"))),
162 codama(account(
163 name = "stake_history",
164 docs = "Stake history sysvar that carries stake warmup/cooldown history",
165 default_value = sysvar("stake_history")
166 )),
167 codama(account(name = "withdraw_authority", signer, docs = "Withdraw authority")),
168 codama(account(
169 name = "lockup_authority",
170 optional,
171 signer,
172 docs = "Lockup authority, if before lockup expiration"
173 ))
174 )]
175 Withdraw(#[cfg_attr(feature = "codama", codama(name = "args"))] u64),
178
179 #[cfg_attr(
186 feature = "codama",
187 codama(account(
188 name = "stake",
189 writable,
190 docs = "Delegated stake account to be deactivated"
191 )),
192 codama(account(name = "clock_sysvar", docs = "Clock sysvar", default_value = sysvar("clock"))),
193 codama(account(name = "stake_authority", signer, docs = "Stake authority"))
194 )]
195 Deactivate,
196
197 #[cfg_attr(
206 feature = "codama",
207 codama(account(name = "stake", writable, docs = "Initialized stake account")),
208 codama(account(
209 name = "authority",
210 signer,
211 docs = "Lockup authority or withdraw authority"
212 ))
213 )]
214 SetLockup(LockupArgs),
215
216 #[cfg_attr(
241 feature = "codama",
242 codama(account(
243 name = "destination_stake",
244 writable,
245 docs = "Destination stake account for the merge"
246 )),
247 codama(account(
248 name = "source_stake",
249 writable,
250 docs = "Source stake account for to merge. This account will be drained"
251 )),
252 codama(account(name = "clock_sysvar", docs = "Clock sysvar", default_value = sysvar("clock"))),
253 codama(account(
254 name = "stake_history",
255 docs = "Stake history sysvar that carries stake warmup/cooldown history",
256 default_value = sysvar("stake_history")
257 )),
258 codama(account(name = "stake_authority", signer, docs = "Stake authority"))
259 )]
260 Merge,
261
262 #[cfg_attr(
271 feature = "codama",
272 codama(account(name = "stake", writable, docs = "Stake account to be updated")),
273 codama(account(
274 name = "base",
275 signer,
276 docs = "Base key of stake or withdraw authority"
277 )),
278 codama(account(name = "clock_sysvar", docs = "Clock sysvar", default_value = sysvar("clock"))),
279 codama(account(
280 name = "lockup_authority",
281 optional,
282 signer,
283 docs = "Lockup authority, if updating `StakeAuthorize::Withdrawer` before lockup expiration"
284 ))
285 )]
286 AuthorizeWithSeed(AuthorizeWithSeedArgs),
287
288 #[cfg_attr(
299 feature = "codama",
300 codama(account(name = "stake", writable, docs = "Uninitialized stake account")),
301 codama(account(name = "rent_sysvar", docs = "Rent sysvar", default_value = sysvar("rent"))),
302 codama(account(name = "stake_authority", docs = "The stake authority")),
303 codama(account(name = "withdraw_authority", signer, docs = "The withdraw authority"))
304 )]
305 InitializeChecked,
306
307 #[cfg_attr(
320 feature = "codama",
321 codama(account(name = "stake", writable, docs = "Stake account to be updated")),
322 codama(account(name = "clock_sysvar", docs = "Clock sysvar", default_value = sysvar("clock"))),
323 codama(account(name = "authority", signer, docs = "The stake or withdraw authority")),
324 codama(account(
325 name = "new_authority",
326 signer,
327 docs = "The new stake or withdraw authority"
328 )),
329 codama(account(
330 name = "lockup_authority",
331 optional,
332 signer,
333 docs = "Lockup authority, if updating `StakeAuthorize::Withdrawer` before lockup expiration"
334 ))
335 )]
336 AuthorizeChecked(
337 #[cfg_attr(feature = "codama", codama(name = "stakeAuthorize"))] StakeAuthorize,
338 ),
339
340 #[cfg_attr(
353 feature = "codama",
354 codama(account(name = "stake", writable, docs = "Stake account to be updated")),
355 codama(account(
356 name = "base",
357 signer,
358 docs = "Base key of stake or withdraw authority"
359 )),
360 codama(account(name = "clock_sysvar", docs = "Clock sysvar", default_value = sysvar("clock"))),
361 codama(account(
362 name = "new_authority",
363 signer,
364 docs = "The new stake or withdraw authority"
365 )),
366 codama(account(
367 name = "lockup_authority",
368 optional,
369 signer,
370 docs = "Lockup authority, if updating `StakeAuthorize::Withdrawer` before lockup expiration"
371 ))
372 )]
373 AuthorizeCheckedWithSeed(AuthorizeCheckedWithSeedArgs),
374
375 #[cfg_attr(
388 feature = "codama",
389 codama(account(name = "stake", writable, docs = "Initialized stake account")),
390 codama(account(
391 name = "authority",
392 signer,
393 docs = "Lockup authority or withdraw authority"
394 )),
395 codama(account(
396 name = "new_authority",
397 optional,
398 signer,
399 docs = "New lockup authority"
400 ))
401 )]
402 SetLockupChecked(LockupCheckedArgs),
403
404 GetMinimumDelegation,
415
416 #[cfg_attr(
428 feature = "codama",
429 codama(account(name = "stake", writable, docs = "Delegated stake account")),
430 codama(account(
431 name = "delinquent_vote",
432 docs = "Delinquent vote account for the delegated stake account"
433 )),
434 codama(account(
435 name = "reference_vote",
436 docs = "Reference vote account that has voted at least once in the last `MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION` epochs"
437 ))
438 )]
439 DeactivateDelinquent,
440
441 #[deprecated(since = "2.1.0", note = "Redelegate will not be enabled")]
462 Redelegate,
464
465 #[cfg_attr(
485 feature = "codama",
486 codama(account(name = "sourceStake", writable, docs = "Active source stake account")),
487 codama(account(
488 name = "destinationStake",
489 writable,
490 docs = "Active or inactive destination stake account"
491 )),
492 codama(account(name = "stake_authority", signer, docs = "Stake authority"))
493 )]
494 MoveStake(#[cfg_attr(feature = "codama", codama(name = "args"))] u64),
496
497 #[cfg_attr(
511 feature = "codama",
512 codama(account(
513 name = "source_stake",
514 writable,
515 docs = "Active or inactive source stake account"
516 )),
517 codama(account(
518 name = "destination_stake",
519 writable,
520 docs = "Mergeable destination stake account"
521 )),
522 codama(account(name = "stake_authority", signer, docs = "Stake authority"))
523 )]
524 MoveLamports(#[cfg_attr(feature = "codama", codama(name = "args"))] u64),
526}
527
528#[cfg_attr(feature = "codama", derive(CodamaType), codama(name = "lockupParams"))]
529#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
530#[cfg_attr(
531 feature = "serde",
532 derive(serde_derive::Deserialize, serde_derive::Serialize)
533)]
534pub struct LockupArgs {
535 pub unix_timestamp: Option<UnixTimestamp>,
536 pub epoch: Option<Epoch>,
537 pub custodian: Option<Pubkey>,
538}
539
540#[cfg_attr(
541 feature = "codama",
542 derive(CodamaType),
543 codama(name = "lockupCheckedParams")
544)]
545#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
546#[cfg_attr(
547 feature = "serde",
548 derive(serde_derive::Deserialize, serde_derive::Serialize)
549)]
550pub struct LockupCheckedArgs {
551 pub unix_timestamp: Option<UnixTimestamp>,
552 pub epoch: Option<Epoch>,
553}
554
555#[cfg_attr(
556 feature = "codama",
557 derive(CodamaType),
558 codama(name = "authorizeWithSeedParams")
559)]
560#[derive(Debug, PartialEq, Eq, Clone)]
561#[cfg_attr(
562 feature = "serde",
563 derive(serde_derive::Deserialize, serde_derive::Serialize)
564)]
565pub struct AuthorizeWithSeedArgs {
566 pub new_authorized_pubkey: Pubkey,
567 pub stake_authorize: StakeAuthorize,
568 pub authority_seed: String,
569 pub authority_owner: Pubkey,
570}
571
572#[cfg_attr(
573 feature = "codama",
574 derive(CodamaType),
575 codama(name = "authorizeCheckedWithSeedParams")
576)]
577#[derive(Debug, PartialEq, Eq, Clone)]
578#[cfg_attr(
579 feature = "serde",
580 derive(serde_derive::Deserialize, serde_derive::Serialize)
581)]
582pub struct AuthorizeCheckedWithSeedArgs {
583 pub stake_authorize: StakeAuthorize,
584 pub authority_seed: String,
585 pub authority_owner: Pubkey,
586}
587
588#[cfg(feature = "bincode")]
589pub fn initialize(stake_pubkey: &Pubkey, authorized: &Authorized, lockup: &Lockup) -> Instruction {
590 Instruction::new_with_bincode(
591 ID,
592 &StakeInstruction::Initialize(*authorized, *lockup),
593 vec![
594 AccountMeta::new(*stake_pubkey, false),
595 AccountMeta::new_readonly(RENT_ID, false),
596 ],
597 )
598}
599
600#[cfg(feature = "bincode")]
601pub fn initialize_checked(stake_pubkey: &Pubkey, authorized: &Authorized) -> Instruction {
602 Instruction::new_with_bincode(
603 ID,
604 &StakeInstruction::InitializeChecked,
605 vec![
606 AccountMeta::new(*stake_pubkey, false),
607 AccountMeta::new_readonly(RENT_ID, false),
608 AccountMeta::new_readonly(authorized.staker, false),
609 AccountMeta::new_readonly(authorized.withdrawer, true),
610 ],
611 )
612}
613
614#[cfg(feature = "bincode")]
615pub fn create_account_with_seed(
616 from_pubkey: &Pubkey,
617 stake_pubkey: &Pubkey,
618 base: &Pubkey,
619 seed: &str,
620 authorized: &Authorized,
621 lockup: &Lockup,
622 lamports: u64,
623) -> Vec<Instruction> {
624 vec![
625 solana_system_interface::instruction::create_account_with_seed(
626 from_pubkey,
627 stake_pubkey,
628 base,
629 seed,
630 lamports,
631 StakeStateV2::size_of() as u64,
632 &ID,
633 ),
634 initialize(stake_pubkey, authorized, lockup),
635 ]
636}
637
638#[cfg(feature = "bincode")]
639pub fn create_account(
640 from_pubkey: &Pubkey,
641 stake_pubkey: &Pubkey,
642 authorized: &Authorized,
643 lockup: &Lockup,
644 lamports: u64,
645) -> Vec<Instruction> {
646 vec![
647 solana_system_interface::instruction::create_account(
648 from_pubkey,
649 stake_pubkey,
650 lamports,
651 StakeStateV2::size_of() as u64,
652 &ID,
653 ),
654 initialize(stake_pubkey, authorized, lockup),
655 ]
656}
657
658#[cfg(feature = "bincode")]
659pub fn create_account_with_seed_checked(
660 from_pubkey: &Pubkey,
661 stake_pubkey: &Pubkey,
662 base: &Pubkey,
663 seed: &str,
664 authorized: &Authorized,
665 lamports: u64,
666) -> Vec<Instruction> {
667 vec![
668 solana_system_interface::instruction::create_account_with_seed(
669 from_pubkey,
670 stake_pubkey,
671 base,
672 seed,
673 lamports,
674 StakeStateV2::size_of() as u64,
675 &ID,
676 ),
677 initialize_checked(stake_pubkey, authorized),
678 ]
679}
680
681#[cfg(feature = "bincode")]
682pub fn create_account_checked(
683 from_pubkey: &Pubkey,
684 stake_pubkey: &Pubkey,
685 authorized: &Authorized,
686 lamports: u64,
687) -> Vec<Instruction> {
688 vec![
689 solana_system_interface::instruction::create_account(
690 from_pubkey,
691 stake_pubkey,
692 lamports,
693 StakeStateV2::size_of() as u64,
694 &ID,
695 ),
696 initialize_checked(stake_pubkey, authorized),
697 ]
698}
699
700#[cfg(feature = "bincode")]
701fn _split(
702 stake_pubkey: &Pubkey,
703 authorized_pubkey: &Pubkey,
704 lamports: u64,
705 split_stake_pubkey: &Pubkey,
706) -> Instruction {
707 let account_metas = vec![
708 AccountMeta::new(*stake_pubkey, false),
709 AccountMeta::new(*split_stake_pubkey, false),
710 AccountMeta::new_readonly(*authorized_pubkey, true),
711 ];
712
713 Instruction::new_with_bincode(ID, &StakeInstruction::Split(lamports), account_metas)
714}
715
716#[cfg(feature = "bincode")]
717pub fn split(
718 stake_pubkey: &Pubkey,
719 authorized_pubkey: &Pubkey,
720 lamports: u64,
721 split_stake_pubkey: &Pubkey,
722) -> Vec<Instruction> {
723 vec![
724 solana_system_interface::instruction::allocate(
725 split_stake_pubkey,
726 StakeStateV2::size_of() as u64,
727 ),
728 solana_system_interface::instruction::assign(split_stake_pubkey, &ID),
729 _split(
730 stake_pubkey,
731 authorized_pubkey,
732 lamports,
733 split_stake_pubkey,
734 ),
735 ]
736}
737
738#[cfg(feature = "bincode")]
739pub fn split_with_seed(
740 stake_pubkey: &Pubkey,
741 authorized_pubkey: &Pubkey,
742 lamports: u64,
743 split_stake_pubkey: &Pubkey, base: &Pubkey, seed: &str, ) -> Vec<Instruction> {
747 vec![
748 solana_system_interface::instruction::allocate_with_seed(
749 split_stake_pubkey,
750 base,
751 seed,
752 StakeStateV2::size_of() as u64,
753 &ID,
754 ),
755 _split(
756 stake_pubkey,
757 authorized_pubkey,
758 lamports,
759 split_stake_pubkey,
760 ),
761 ]
762}
763
764#[cfg(feature = "bincode")]
765pub fn merge(
766 destination_stake_pubkey: &Pubkey,
767 source_stake_pubkey: &Pubkey,
768 authorized_pubkey: &Pubkey,
769) -> Vec<Instruction> {
770 let account_metas = vec![
771 AccountMeta::new(*destination_stake_pubkey, false),
772 AccountMeta::new(*source_stake_pubkey, false),
773 AccountMeta::new_readonly(CLOCK_ID, false),
774 AccountMeta::new_readonly(STAKE_HISTORY_ID, false),
775 AccountMeta::new_readonly(*authorized_pubkey, true),
776 ];
777
778 vec![Instruction::new_with_bincode(
779 ID,
780 &StakeInstruction::Merge,
781 account_metas,
782 )]
783}
784
785#[cfg(feature = "bincode")]
786pub fn create_account_and_delegate_stake(
787 from_pubkey: &Pubkey,
788 stake_pubkey: &Pubkey,
789 vote_pubkey: &Pubkey,
790 authorized: &Authorized,
791 lockup: &Lockup,
792 lamports: u64,
793) -> Vec<Instruction> {
794 let mut instructions = create_account(from_pubkey, stake_pubkey, authorized, lockup, lamports);
795 instructions.push(delegate_stake(
796 stake_pubkey,
797 &authorized.staker,
798 vote_pubkey,
799 ));
800 instructions
801}
802
803#[cfg(feature = "bincode")]
804#[allow(clippy::too_many_arguments)]
805pub fn create_account_with_seed_and_delegate_stake(
806 from_pubkey: &Pubkey,
807 stake_pubkey: &Pubkey,
808 base: &Pubkey,
809 seed: &str,
810 vote_pubkey: &Pubkey,
811 authorized: &Authorized,
812 lockup: &Lockup,
813 lamports: u64,
814) -> Vec<Instruction> {
815 let mut instructions = create_account_with_seed(
816 from_pubkey,
817 stake_pubkey,
818 base,
819 seed,
820 authorized,
821 lockup,
822 lamports,
823 );
824 instructions.push(delegate_stake(
825 stake_pubkey,
826 &authorized.staker,
827 vote_pubkey,
828 ));
829 instructions
830}
831
832#[cfg(feature = "bincode")]
833pub fn authorize(
834 stake_pubkey: &Pubkey,
835 authorized_pubkey: &Pubkey,
836 new_authorized_pubkey: &Pubkey,
837 stake_authorize: StakeAuthorize,
838 custodian_pubkey: Option<&Pubkey>,
839) -> Instruction {
840 let mut account_metas = vec![
841 AccountMeta::new(*stake_pubkey, false),
842 AccountMeta::new_readonly(CLOCK_ID, false),
843 AccountMeta::new_readonly(*authorized_pubkey, true),
844 ];
845
846 if let Some(custodian_pubkey) = custodian_pubkey {
847 account_metas.push(AccountMeta::new_readonly(*custodian_pubkey, true));
848 }
849
850 Instruction::new_with_bincode(
851 ID,
852 &StakeInstruction::Authorize(*new_authorized_pubkey, stake_authorize),
853 account_metas,
854 )
855}
856
857#[cfg(feature = "bincode")]
858pub fn authorize_checked(
859 stake_pubkey: &Pubkey,
860 authorized_pubkey: &Pubkey,
861 new_authorized_pubkey: &Pubkey,
862 stake_authorize: StakeAuthorize,
863 custodian_pubkey: Option<&Pubkey>,
864) -> Instruction {
865 let mut account_metas = vec![
866 AccountMeta::new(*stake_pubkey, false),
867 AccountMeta::new_readonly(CLOCK_ID, false),
868 AccountMeta::new_readonly(*authorized_pubkey, true),
869 AccountMeta::new_readonly(*new_authorized_pubkey, true),
870 ];
871
872 if let Some(custodian_pubkey) = custodian_pubkey {
873 account_metas.push(AccountMeta::new_readonly(*custodian_pubkey, true));
874 }
875
876 Instruction::new_with_bincode(
877 ID,
878 &StakeInstruction::AuthorizeChecked(stake_authorize),
879 account_metas,
880 )
881}
882
883#[cfg(feature = "bincode")]
884pub fn authorize_with_seed(
885 stake_pubkey: &Pubkey,
886 authority_base: &Pubkey,
887 authority_seed: String,
888 authority_owner: &Pubkey,
889 new_authorized_pubkey: &Pubkey,
890 stake_authorize: StakeAuthorize,
891 custodian_pubkey: Option<&Pubkey>,
892) -> Instruction {
893 let mut account_metas = vec![
894 AccountMeta::new(*stake_pubkey, false),
895 AccountMeta::new_readonly(*authority_base, true),
896 AccountMeta::new_readonly(CLOCK_ID, false),
897 ];
898
899 if let Some(custodian_pubkey) = custodian_pubkey {
900 account_metas.push(AccountMeta::new_readonly(*custodian_pubkey, true));
901 }
902
903 let args = AuthorizeWithSeedArgs {
904 new_authorized_pubkey: *new_authorized_pubkey,
905 stake_authorize,
906 authority_seed,
907 authority_owner: *authority_owner,
908 };
909
910 Instruction::new_with_bincode(
911 ID,
912 &StakeInstruction::AuthorizeWithSeed(args),
913 account_metas,
914 )
915}
916
917#[cfg(feature = "bincode")]
918pub fn authorize_checked_with_seed(
919 stake_pubkey: &Pubkey,
920 authority_base: &Pubkey,
921 authority_seed: String,
922 authority_owner: &Pubkey,
923 new_authorized_pubkey: &Pubkey,
924 stake_authorize: StakeAuthorize,
925 custodian_pubkey: Option<&Pubkey>,
926) -> Instruction {
927 let mut account_metas = vec![
928 AccountMeta::new(*stake_pubkey, false),
929 AccountMeta::new_readonly(*authority_base, true),
930 AccountMeta::new_readonly(CLOCK_ID, false),
931 AccountMeta::new_readonly(*new_authorized_pubkey, true),
932 ];
933
934 if let Some(custodian_pubkey) = custodian_pubkey {
935 account_metas.push(AccountMeta::new_readonly(*custodian_pubkey, true));
936 }
937
938 let args = AuthorizeCheckedWithSeedArgs {
939 stake_authorize,
940 authority_seed,
941 authority_owner: *authority_owner,
942 };
943
944 Instruction::new_with_bincode(
945 ID,
946 &StakeInstruction::AuthorizeCheckedWithSeed(args),
947 account_metas,
948 )
949}
950
951#[cfg(feature = "bincode")]
952pub fn delegate_stake(
953 stake_pubkey: &Pubkey,
954 authorized_pubkey: &Pubkey,
955 vote_pubkey: &Pubkey,
956) -> Instruction {
957 let account_metas = vec![
958 AccountMeta::new(*stake_pubkey, false),
959 AccountMeta::new_readonly(*vote_pubkey, false),
960 AccountMeta::new_readonly(CLOCK_ID, false),
961 AccountMeta::new_readonly(STAKE_HISTORY_ID, false),
962 AccountMeta::new_readonly(config::ID, false),
964 AccountMeta::new_readonly(*authorized_pubkey, true),
965 ];
966 Instruction::new_with_bincode(ID, &StakeInstruction::DelegateStake, account_metas)
967}
968
969#[cfg(feature = "bincode")]
970pub fn withdraw(
971 stake_pubkey: &Pubkey,
972 withdrawer_pubkey: &Pubkey,
973 to_pubkey: &Pubkey,
974 lamports: u64,
975 custodian_pubkey: Option<&Pubkey>,
976) -> Instruction {
977 let mut account_metas = vec![
978 AccountMeta::new(*stake_pubkey, false),
979 AccountMeta::new(*to_pubkey, false),
980 AccountMeta::new_readonly(CLOCK_ID, false),
981 AccountMeta::new_readonly(STAKE_HISTORY_ID, false),
982 AccountMeta::new_readonly(*withdrawer_pubkey, true),
983 ];
984
985 if let Some(custodian_pubkey) = custodian_pubkey {
986 account_metas.push(AccountMeta::new_readonly(*custodian_pubkey, true));
987 }
988
989 Instruction::new_with_bincode(ID, &StakeInstruction::Withdraw(lamports), account_metas)
990}
991
992#[cfg(feature = "bincode")]
993pub fn deactivate_stake(stake_pubkey: &Pubkey, authorized_pubkey: &Pubkey) -> Instruction {
994 let account_metas = vec![
995 AccountMeta::new(*stake_pubkey, false),
996 AccountMeta::new_readonly(CLOCK_ID, false),
997 AccountMeta::new_readonly(*authorized_pubkey, true),
998 ];
999 Instruction::new_with_bincode(ID, &StakeInstruction::Deactivate, account_metas)
1000}
1001
1002#[cfg(feature = "bincode")]
1003pub fn set_lockup(
1004 stake_pubkey: &Pubkey,
1005 lockup: &LockupArgs,
1006 custodian_pubkey: &Pubkey,
1007) -> Instruction {
1008 let account_metas = vec![
1009 AccountMeta::new(*stake_pubkey, false),
1010 AccountMeta::new_readonly(*custodian_pubkey, true),
1011 ];
1012 Instruction::new_with_bincode(ID, &StakeInstruction::SetLockup(*lockup), account_metas)
1013}
1014
1015#[cfg(feature = "bincode")]
1016pub fn set_lockup_checked(
1017 stake_pubkey: &Pubkey,
1018 lockup: &LockupArgs,
1019 custodian_pubkey: &Pubkey,
1020) -> Instruction {
1021 let mut account_metas = vec![
1022 AccountMeta::new(*stake_pubkey, false),
1023 AccountMeta::new_readonly(*custodian_pubkey, true),
1024 ];
1025
1026 let lockup_checked = LockupCheckedArgs {
1027 unix_timestamp: lockup.unix_timestamp,
1028 epoch: lockup.epoch,
1029 };
1030 if let Some(new_custodian) = lockup.custodian {
1031 account_metas.push(AccountMeta::new_readonly(new_custodian, true));
1032 }
1033 Instruction::new_with_bincode(
1034 ID,
1035 &StakeInstruction::SetLockupChecked(lockup_checked),
1036 account_metas,
1037 )
1038}
1039
1040#[cfg(feature = "bincode")]
1041pub fn get_minimum_delegation() -> Instruction {
1042 Instruction::new_with_bincode(ID, &StakeInstruction::GetMinimumDelegation, Vec::default())
1043}
1044
1045#[cfg(feature = "bincode")]
1046pub fn deactivate_delinquent_stake(
1047 stake_account: &Pubkey,
1048 delinquent_vote_account: &Pubkey,
1049 reference_vote_account: &Pubkey,
1050) -> Instruction {
1051 let account_metas = vec![
1052 AccountMeta::new(*stake_account, false),
1053 AccountMeta::new_readonly(*delinquent_vote_account, false),
1054 AccountMeta::new_readonly(*reference_vote_account, false),
1055 ];
1056 Instruction::new_with_bincode(ID, &StakeInstruction::DeactivateDelinquent, account_metas)
1057}
1058
1059#[cfg(feature = "bincode")]
1060fn _redelegate(
1061 stake_pubkey: &Pubkey,
1062 authorized_pubkey: &Pubkey,
1063 vote_pubkey: &Pubkey,
1064 uninitialized_stake_pubkey: &Pubkey,
1065) -> Instruction {
1066 let account_metas = vec![
1067 AccountMeta::new(*stake_pubkey, false),
1068 AccountMeta::new(*uninitialized_stake_pubkey, false),
1069 AccountMeta::new_readonly(*vote_pubkey, false),
1070 AccountMeta::new_readonly(config::ID, false),
1072 AccountMeta::new_readonly(*authorized_pubkey, true),
1073 ];
1074 Instruction::new_with_bincode(ID, &StakeInstruction::Redelegate, account_metas)
1075}
1076
1077#[cfg(feature = "bincode")]
1078#[deprecated(since = "2.1.0", note = "Redelegate will not be enabled")]
1079pub fn redelegate(
1080 stake_pubkey: &Pubkey,
1081 authorized_pubkey: &Pubkey,
1082 vote_pubkey: &Pubkey,
1083 uninitialized_stake_pubkey: &Pubkey,
1084) -> Vec<Instruction> {
1085 vec![
1086 solana_system_interface::instruction::allocate(
1087 uninitialized_stake_pubkey,
1088 StakeStateV2::size_of() as u64,
1089 ),
1090 solana_system_interface::instruction::assign(uninitialized_stake_pubkey, &ID),
1091 _redelegate(
1092 stake_pubkey,
1093 authorized_pubkey,
1094 vote_pubkey,
1095 uninitialized_stake_pubkey,
1096 ),
1097 ]
1098}
1099
1100#[cfg(feature = "bincode")]
1101#[deprecated(since = "2.1.0", note = "Redelegate will not be enabled")]
1102pub fn redelegate_with_seed(
1103 stake_pubkey: &Pubkey,
1104 authorized_pubkey: &Pubkey,
1105 vote_pubkey: &Pubkey,
1106 uninitialized_stake_pubkey: &Pubkey, base: &Pubkey, seed: &str, ) -> Vec<Instruction> {
1110 vec![
1111 solana_system_interface::instruction::allocate_with_seed(
1112 uninitialized_stake_pubkey,
1113 base,
1114 seed,
1115 StakeStateV2::size_of() as u64,
1116 &ID,
1117 ),
1118 _redelegate(
1119 stake_pubkey,
1120 authorized_pubkey,
1121 vote_pubkey,
1122 uninitialized_stake_pubkey,
1123 ),
1124 ]
1125}
1126
1127#[cfg(feature = "bincode")]
1128pub fn move_stake(
1129 source_stake_pubkey: &Pubkey,
1130 destination_stake_pubkey: &Pubkey,
1131 authorized_pubkey: &Pubkey,
1132 lamports: u64,
1133) -> Instruction {
1134 let account_metas = vec![
1135 AccountMeta::new(*source_stake_pubkey, false),
1136 AccountMeta::new(*destination_stake_pubkey, false),
1137 AccountMeta::new_readonly(*authorized_pubkey, true),
1138 ];
1139
1140 Instruction::new_with_bincode(ID, &StakeInstruction::MoveStake(lamports), account_metas)
1141}
1142
1143#[cfg(feature = "bincode")]
1144pub fn move_lamports(
1145 source_stake_pubkey: &Pubkey,
1146 destination_stake_pubkey: &Pubkey,
1147 authorized_pubkey: &Pubkey,
1148 lamports: u64,
1149) -> Instruction {
1150 let account_metas = vec![
1151 AccountMeta::new(*source_stake_pubkey, false),
1152 AccountMeta::new(*destination_stake_pubkey, false),
1153 AccountMeta::new_readonly(*authorized_pubkey, true),
1154 ];
1155
1156 Instruction::new_with_bincode(ID, &StakeInstruction::MoveLamports(lamports), account_metas)
1157}
1158
1159#[cfg(feature = "bincode")]
1160#[cfg(test)]
1161mod tests {
1162 use super::*;
1163
1164 #[allow(deprecated)]
1165 #[test]
1166 fn test_constants() {
1167 assert_eq!(CLOCK_ID, solana_sdk_ids::sysvar::clock::ID);
1169
1170 assert_eq!(STAKE_HISTORY_ID, solana_sdk_ids::sysvar::stake_history::ID);
1172
1173 assert_eq!(RENT_ID, solana_sdk_ids::sysvar::rent::ID);
1175 }
1176}