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
15pub use solana_program;
18use {
19 crate::state::Fee,
20 solana_program::{pubkey::Pubkey, stake::state::Meta},
21 std::num::NonZeroU32,
22};
23
24const AUTHORITY_DEPOSIT: &[u8] = b"deposit";
26
27const AUTHORITY_WITHDRAW: &[u8] = b"withdraw";
29
30const TRANSIENT_STAKE_SEED_PREFIX: &[u8] = b"transient";
32
33const EPHEMERAL_STAKE_SEED_PREFIX: &[u8] = b"ephemeral";
35
36pub const MINIMUM_ACTIVE_STAKE: u64 = 1_000_000;
39
40pub const MINIMUM_RESERVE_LAMPORTS: u64 = 0;
42
43pub const MAX_VALIDATORS_TO_UPDATE: usize = 4;
46
47pub const MAX_WITHDRAWAL_FEE_INCREASE: Fee = Fee {
51 numerator: 3,
52 denominator: 2,
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
64#[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#[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#[inline]
81pub fn minimum_reserve_lamports(meta: &Meta) -> u64 {
82 meta.rent_exempt_reserve
83 .saturating_add(MINIMUM_RESERVE_LAMPORTS)
84}
85
86pub 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
97pub 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
108pub 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
126pub 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
144pub 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");
161pub 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}