Skip to main content

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