Skip to main content

anchor_spl/
stake.rs

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
16// CPI functions
17
18pub 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// CPI accounts
81
82#[derive(Accounts)]
83pub struct Authorize<'info> {
84    /// The stake account to be updated
85    pub stake: AccountInfo<'info>,
86
87    /// The existing authority
88    pub authorized: AccountInfo<'info>,
89
90    /// The new authority to replace the existing authority
91    pub new_authorized: AccountInfo<'info>,
92
93    /// Clock sysvar
94    pub clock: AccountInfo<'info>,
95}
96
97#[derive(Accounts)]
98pub struct Withdraw<'info> {
99    /// The stake account to be updated
100    pub stake: AccountInfo<'info>,
101
102    /// The stake account's withdraw authority
103    pub withdrawer: AccountInfo<'info>,
104
105    /// Account to send withdrawn lamports to
106    pub to: AccountInfo<'info>,
107
108    /// Clock sysvar
109    pub clock: AccountInfo<'info>,
110
111    /// StakeHistory sysvar
112    pub stake_history: AccountInfo<'info>,
113}
114
115#[derive(Accounts)]
116pub struct DeactivateStake<'info> {
117    /// The stake account to be deactivated
118    pub stake: AccountInfo<'info>,
119
120    /// The stake account's stake authority
121    pub staker: AccountInfo<'info>,
122
123    /// Clock sysvar
124    pub clock: AccountInfo<'info>,
125}
126
127// State
128
129#[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}