1#![deny(missing_docs)]
2
3pub 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
17const AUTHORITY_DEPOSIT: &[u8] = b"deposit";
19
20const AUTHORITY_WITHDRAW: &[u8] = b"withdraw";
22
23const TRANSIENT_STAKE_SEED_PREFIX: &[u8] = b"transient";
25
26const EPHEMERAL_STAKE_SEED_PREFIX: &[u8] = b"ephemeral";
28
29pub const MINIMUM_ACTIVE_STAKE: u64 = 1_000_000;
32
33pub const MINIMUM_RESERVE_LAMPORTS: u64 = 0;
35
36pub const MAX_VALIDATORS_TO_UPDATE: usize = 4;
39
40pub const MAX_WITHDRAWAL_FEE_INCREASE_FACTOR: Fee = Fee {
44 numerator: 3,
45 denominator: 2,
46};
47pub const MAX_WITHDRAWAL_FEE_INCREASE: Fee = Fee {
51 numerator: 1,
52 denominator: 200,
53};
54pub const WITHDRAWAL_BASELINE_FEE: Fee = Fee {
56 numerator: 1,
57 denominator: 1000,
58};
59
60pub const MAX_TRANSIENT_STAKE_ACCOUNTS: usize = 10;
63
64pub const MAX_VALIDATORS_IN_POOL: u32 = 20_000;
67
68#[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#[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#[inline]
87pub fn minimum_reserve_lamports(rent_exempt_reserve: u64) -> u64 {
88 rent_exempt_reserve.saturating_add(MINIMUM_RESERVE_LAMPORTS)
89}
90
91pub 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
102pub 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
113pub 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
131pub 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
149pub 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");
166pub 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}