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 USER_STAKE_SEED_PREFIX: &[u8] = b"user_stake";
38
39pub const MINIMUM_ACTIVE_STAKE: u64 = 1_000_000;
42
43pub const MINIMUM_RESERVE_LAMPORTS: u64 = 0;
45
46pub const MAX_VALIDATORS_TO_UPDATE: usize = 4;
49
50pub const MAX_WITHDRAWAL_FEE_INCREASE: Fee = Fee {
54 numerator: 3,
55 denominator: 2,
56};
57pub const WITHDRAWAL_BASELINE_FEE: Fee = Fee {
59 numerator: 1,
60 denominator: 1000,
61};
62
63pub const MAX_TRANSIENT_STAKE_ACCOUNTS: usize = 10;
66
67pub const MAX_VALIDATORS_IN_POOL: u32 = 20_000;
70
71#[inline]
74pub fn minimum_stake_lamports(meta: &Meta, stake_program_minimum_delegation: u64) -> u64 {
75 meta.rent_exempt_reserve
76 .saturating_add(minimum_delegation(stake_program_minimum_delegation))
77}
78
79#[inline]
81pub fn minimum_delegation(stake_program_minimum_delegation: u64) -> u64 {
82 std::cmp::max(stake_program_minimum_delegation, MINIMUM_ACTIVE_STAKE)
83}
84
85#[inline]
88pub fn minimum_reserve_lamports(meta: &Meta) -> u64 {
89 meta.rent_exempt_reserve
90 .saturating_add(MINIMUM_RESERVE_LAMPORTS)
91}
92
93pub fn find_deposit_authority_program_address(
95 program_id: &Pubkey,
96 stake_pool_address: &Pubkey,
97) -> (Pubkey, u8) {
98 Pubkey::find_program_address(
99 &[stake_pool_address.as_ref(), AUTHORITY_DEPOSIT],
100 program_id,
101 )
102}
103
104pub fn find_withdraw_authority_program_address(
106 program_id: &Pubkey,
107 stake_pool_address: &Pubkey,
108) -> (Pubkey, u8) {
109 Pubkey::find_program_address(
110 &[stake_pool_address.as_ref(), AUTHORITY_WITHDRAW],
111 program_id,
112 )
113}
114
115pub fn find_stake_program_address(
117 program_id: &Pubkey,
118 vote_account_address: &Pubkey,
119 stake_pool_address: &Pubkey,
120 seed: Option<NonZeroU32>,
121) -> (Pubkey, u8) {
122 let seed = seed.map(|s| s.get().to_le_bytes());
123 Pubkey::find_program_address(
124 &[
125 vote_account_address.as_ref(),
126 stake_pool_address.as_ref(),
127 seed.as_ref().map(|s| s.as_slice()).unwrap_or(&[]),
128 ],
129 program_id,
130 )
131}
132
133pub fn find_transient_stake_program_address(
135 program_id: &Pubkey,
136 vote_account_address: &Pubkey,
137 stake_pool_address: &Pubkey,
138 seed: u64,
139) -> (Pubkey, u8) {
140 Pubkey::find_program_address(
141 &[
142 TRANSIENT_STAKE_SEED_PREFIX,
143 vote_account_address.as_ref(),
144 stake_pool_address.as_ref(),
145 &seed.to_le_bytes(),
146 ],
147 program_id,
148 )
149}
150
151pub fn find_ephemeral_stake_program_address(
153 program_id: &Pubkey,
154 stake_pool_address: &Pubkey,
155 seed: u64,
156) -> (Pubkey, u8) {
157 Pubkey::find_program_address(
158 &[
159 EPHEMERAL_STAKE_SEED_PREFIX,
160 stake_pool_address.as_ref(),
161 &seed.to_le_bytes(),
162 ],
163 program_id,
164 )
165}
166
167pub fn find_user_stake_program_address(
170 program_id: &Pubkey,
171 user_wallet: &Pubkey,
172 seed: u64,
173) -> (Pubkey, u8) {
174 Pubkey::find_program_address(
175 &[
176 USER_STAKE_SEED_PREFIX,
177 user_wallet.as_ref(),
178 &seed.to_le_bytes(),
179 ],
180 program_id,
181 )
182}
183
184solana_program::declare_id!("SP1s4uFeTAX9jsXXmwyDs1gxYYf7cdDZ8qHUHVxE1yr");
185pub mod devnet {
187 solana_program::declare_id!("DPoo15wWDqpPJJtS2MUZ49aRxqz5ZaaJCJP4z8bLuib");
188}
189
190#[cfg(test)]
191mod test {
192 use super::*;
193
194 #[test]
195 fn validator_stake_account_derivation() {
196 let vote = Pubkey::new_unique();
197 let stake_pool = Pubkey::new_unique();
198 let function_derived = find_stake_program_address(&id(), &vote, &stake_pool, None);
199 let hand_derived =
200 Pubkey::find_program_address(&[vote.as_ref(), stake_pool.as_ref()], &id());
201 assert_eq!(function_derived, hand_derived);
202 }
203}