1use {
2 anchor_lang::{
3 context::CpiContext,
4 solana_program::{account_info::AccountInfo, pubkey::Pubkey},
5 Accounts, Result,
6 },
7 borsh::BorshDeserialize,
8 solana_stake_interface::{
9 self as stake,
10 program::ID,
11 state::{StakeAuthorize, StakeStateV2},
12 },
13 std::ops::Deref,
14};
15
16pub fn authorize<'info>(
19 ctx: CpiContext<'_, '_, '_, 'info, Authorize<'info>>,
20 stake_authorize: StakeAuthorize,
21 custodian: Option<AccountInfo<'info>>,
22) -> Result<()> {
23 let ix = stake::instruction::authorize(
24 ctx.accounts.stake.key,
25 ctx.accounts.authorized.key,
26 ctx.accounts.new_authorized.key,
27 stake_authorize,
28 custodian.as_ref().map(|c| c.key),
29 );
30 let mut account_infos = vec![
31 ctx.accounts.stake,
32 ctx.accounts.clock,
33 ctx.accounts.authorized,
34 ];
35 if let Some(c) = custodian {
36 account_infos.push(c);
37 }
38 anchor_lang::solana_program::program::invoke_signed(&ix, &account_infos, ctx.signer_seeds)
39 .map_err(Into::into)
40}
41
42pub fn withdraw<'info>(
43 ctx: CpiContext<'_, '_, '_, 'info, Withdraw<'info>>,
44 amount: u64,
45 custodian: Option<AccountInfo<'info>>,
46) -> Result<()> {
47 let ix = stake::instruction::withdraw(
48 ctx.accounts.stake.key,
49 ctx.accounts.withdrawer.key,
50 ctx.accounts.to.key,
51 amount,
52 custodian.as_ref().map(|c| c.key),
53 );
54 let mut account_infos = vec![
55 ctx.accounts.stake,
56 ctx.accounts.to,
57 ctx.accounts.clock,
58 ctx.accounts.stake_history,
59 ctx.accounts.withdrawer,
60 ];
61 if let Some(c) = custodian {
62 account_infos.push(c);
63 }
64 anchor_lang::solana_program::program::invoke_signed(&ix, &account_infos, ctx.signer_seeds)
65 .map_err(Into::into)
66}
67
68pub fn deactivate_stake<'info>(
69 ctx: CpiContext<'_, '_, '_, 'info, DeactivateStake<'info>>,
70) -> Result<()> {
71 let ix = stake::instruction::deactivate_stake(ctx.accounts.stake.key, ctx.accounts.staker.key);
72 anchor_lang::solana_program::program::invoke_signed(
73 &ix,
74 &[ctx.accounts.stake, ctx.accounts.clock, ctx.accounts.staker],
75 ctx.signer_seeds,
76 )
77 .map_err(Into::into)
78}
79
80#[derive(Accounts)]
83pub struct Authorize<'info> {
84 pub stake: AccountInfo<'info>,
86
87 pub authorized: AccountInfo<'info>,
89
90 pub new_authorized: AccountInfo<'info>,
92
93 pub clock: AccountInfo<'info>,
95}
96
97#[derive(Accounts)]
98pub struct Withdraw<'info> {
99 pub stake: AccountInfo<'info>,
101
102 pub withdrawer: AccountInfo<'info>,
104
105 pub to: AccountInfo<'info>,
107
108 pub clock: AccountInfo<'info>,
110
111 pub stake_history: AccountInfo<'info>,
113}
114
115#[derive(Accounts)]
116pub struct DeactivateStake<'info> {
117 pub stake: AccountInfo<'info>,
119
120 pub staker: AccountInfo<'info>,
122
123 pub clock: AccountInfo<'info>,
125}
126
127#[derive(Clone)]
130pub struct StakeAccount(StakeStateV2);
131
132impl anchor_lang::AccountDeserialize for StakeAccount {
133 fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
134 Self::try_deserialize_unchecked(buf)
135 }
136
137 fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
138 StakeStateV2::deserialize(buf).map(Self).map_err(Into::into)
139 }
140}
141
142impl anchor_lang::AccountSerialize for StakeAccount {}
143
144impl anchor_lang::Owner for StakeAccount {
145 fn owner() -> Pubkey {
146 ID
147 }
148}
149
150impl Deref for StakeAccount {
151 type Target = StakeStateV2;
152
153 fn deref(&self) -> &Self::Target {
154 &self.0
155 }
156}
157
158#[derive(Clone)]
159pub struct Stake;
160
161impl anchor_lang::Id for Stake {
162 fn id() -> Pubkey {
163 ID
164 }
165}