spl_stake_pool/
lib.rs

1#![deny(missing_docs)]
2
3//! A program for creating and managing pools of stake
4
5pub mod big_vec;
6pub mod error;
7pub mod inline_mpl_token_metadata;
8pub mod instruction;
9pub mod processor;
10pub mod state;
11
12#[cfg(not(feature = "no-entrypoint"))]
13pub mod entrypoint;
14
15// Export current sdk types for downstream users building with a different sdk
16// version
17pub use solana_program;
18use {
19    crate::state::Fee,
20    solana_program::{pubkey::Pubkey, stake::state::Meta},
21    std::num::NonZeroU32,
22};
23
24/// Seed for deposit authority seed
25const AUTHORITY_DEPOSIT: &[u8] = b"deposit";
26
27/// Seed for withdraw authority seed
28const AUTHORITY_WITHDRAW: &[u8] = b"withdraw";
29
30/// Seed for transient stake account
31const TRANSIENT_STAKE_SEED_PREFIX: &[u8] = b"transient";
32
33/// Seed for ephemeral stake account
34const EPHEMERAL_STAKE_SEED_PREFIX: &[u8] = b"ephemeral";
35
36/// Minimum amount of staked lamports required in a validator stake account to
37/// allow for merges without a mismatch on credits observed
38pub const MINIMUM_ACTIVE_STAKE: u64 = 1_000_000;
39
40/// Minimum amount of lamports in the reserve
41pub const MINIMUM_RESERVE_LAMPORTS: u64 = 0;
42
43/// Maximum amount of validator stake accounts to update per
44/// `UpdateValidatorListBalance` instruction, based on compute limits
45pub const MAX_VALIDATORS_TO_UPDATE: usize = 4;
46
47/// Maximum factor by which a withdrawal fee can be increased per epoch
48/// protecting stakers from malicious users.
49/// If current fee is 0, `WITHDRAWAL_BASELINE_FEE` is used as the baseline
50pub const MAX_WITHDRAWAL_FEE_INCREASE: Fee = Fee {
51    numerator: 3,
52    denominator: 2,
53};
54/// Drop-in baseline fee when evaluating withdrawal fee increases when fee is 0
55pub const WITHDRAWAL_BASELINE_FEE: Fee = Fee {
56    numerator: 1,
57    denominator: 1000,
58};
59
60/// The maximum number of transient stake accounts respecting
61/// transaction account limits.
62pub const MAX_TRANSIENT_STAKE_ACCOUNTS: usize = 10;
63
64/// Get the stake amount under consideration when calculating pool token
65/// conversions
66#[inline]
67pub fn minimum_stake_lamports(meta: &Meta, stake_program_minimum_delegation: u64) -> u64 {
68    meta.rent_exempt_reserve
69        .saturating_add(minimum_delegation(stake_program_minimum_delegation))
70}
71
72/// Get the minimum delegation required by a stake account in a stake pool
73#[inline]
74pub fn minimum_delegation(stake_program_minimum_delegation: u64) -> u64 {
75    std::cmp::max(stake_program_minimum_delegation, MINIMUM_ACTIVE_STAKE)
76}
77
78/// Get the stake amount under consideration when calculating pool token
79/// conversions
80#[inline]
81pub fn minimum_reserve_lamports(meta: &Meta) -> u64 {
82    meta.rent_exempt_reserve
83        .saturating_add(MINIMUM_RESERVE_LAMPORTS)
84}
85
86/// Generates the deposit authority program address for the stake pool
87pub fn find_deposit_authority_program_address(
88    program_id: &Pubkey,
89    stake_pool_address: &Pubkey,
90) -> (Pubkey, u8) {
91    Pubkey::find_program_address(
92        &[stake_pool_address.as_ref(), AUTHORITY_DEPOSIT],
93        program_id,
94    )
95}
96
97/// Generates the withdraw authority program address for the stake pool
98pub fn find_withdraw_authority_program_address(
99    program_id: &Pubkey,
100    stake_pool_address: &Pubkey,
101) -> (Pubkey, u8) {
102    Pubkey::find_program_address(
103        &[stake_pool_address.as_ref(), AUTHORITY_WITHDRAW],
104        program_id,
105    )
106}
107
108/// Generates the stake program address for a validator's vote account
109pub fn find_stake_program_address(
110    program_id: &Pubkey,
111    vote_account_address: &Pubkey,
112    stake_pool_address: &Pubkey,
113    seed: Option<NonZeroU32>,
114) -> (Pubkey, u8) {
115    let seed = seed.map(|s| s.get().to_le_bytes());
116    Pubkey::find_program_address(
117        &[
118            vote_account_address.as_ref(),
119            stake_pool_address.as_ref(),
120            seed.as_ref().map(|s| s.as_slice()).unwrap_or(&[]),
121        ],
122        program_id,
123    )
124}
125
126/// Generates the stake program address for a validator's vote account
127pub fn find_transient_stake_program_address(
128    program_id: &Pubkey,
129    vote_account_address: &Pubkey,
130    stake_pool_address: &Pubkey,
131    seed: u64,
132) -> (Pubkey, u8) {
133    Pubkey::find_program_address(
134        &[
135            TRANSIENT_STAKE_SEED_PREFIX,
136            vote_account_address.as_ref(),
137            stake_pool_address.as_ref(),
138            &seed.to_le_bytes(),
139        ],
140        program_id,
141    )
142}
143
144/// Generates the ephemeral program address for stake pool redelegation
145pub fn find_ephemeral_stake_program_address(
146    program_id: &Pubkey,
147    stake_pool_address: &Pubkey,
148    seed: u64,
149) -> (Pubkey, u8) {
150    Pubkey::find_program_address(
151        &[
152            EPHEMERAL_STAKE_SEED_PREFIX,
153            stake_pool_address.as_ref(),
154            &seed.to_le_bytes(),
155        ],
156        program_id,
157    )
158}
159
160solana_program::declare_id!("SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy");
161/// Program id for devnet
162pub mod devnet {
163    solana_program::declare_id!("DPoo15wWDqpPJJtS2MUZ49aRxqz5ZaaJCJP4z8bLuib");
164}
165
166#[cfg(test)]
167mod test {
168    use super::*;
169
170    #[test]
171    fn validator_stake_account_derivation() {
172        let vote = Pubkey::new_unique();
173        let stake_pool = Pubkey::new_unique();
174        let function_derived = find_stake_program_address(&id(), &vote, &stake_pool, None);
175        let hand_derived =
176            Pubkey::find_program_address(&[vote.as_ref(), stake_pool.as_ref()], &id());
177        assert_eq!(function_derived, hand_derived);
178    }
179}