Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit 53c8649

Browse files
authored
stake-pool: Add reserve stake and decrease / increase validator stake instruction (#1617)
* Add reserve stake account * Add decrease validator stake instruction * Cargo fmt * Add increase instruction * Add more increase tests * Fix set fee tests * Fix clippy in tests * Add test-bpf feature to increase / decrease tests
1 parent 40ebfc6 commit 53c8649

19 files changed

+1780
-128
lines changed

stake-pool/cli/src/main.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ fn send_transaction(
9595
}
9696

9797
fn command_create_pool(config: &Config, fee: Fee, max_validators: u32) -> CommandResult {
98+
let reserve_stake = Keypair::new();
99+
println!("Creating reserve stake {}", reserve_stake.pubkey());
100+
98101
let mint_account = Keypair::new();
99102
println!("Creating mint {}", mint_account.pubkey());
100103

@@ -109,6 +112,10 @@ fn command_create_pool(config: &Config, fee: Fee, max_validators: u32) -> Comman
109112

110113
let validator_list = Keypair::new();
111114

115+
let reserve_stake_balance = config
116+
.rpc_client
117+
.get_minimum_balance_for_rent_exemption(STAKE_STATE_LEN)?
118+
+ 1;
112119
let mint_account_balance = config
113120
.rpc_client
114121
.get_minimum_balance_for_rent_exemption(spl_token::state::Mint::LEN)?;
@@ -123,7 +130,8 @@ fn command_create_pool(config: &Config, fee: Fee, max_validators: u32) -> Comman
123130
let validator_list_balance = config
124131
.rpc_client
125132
.get_minimum_balance_for_rent_exemption(validator_list_size)?;
126-
let total_rent_free_balances = mint_account_balance
133+
let total_rent_free_balances = reserve_stake_balance
134+
+ mint_account_balance
127135
+ pool_fee_account_balance
128136
+ stake_pool_account_lamports
129137
+ validator_list_balance;
@@ -142,6 +150,22 @@ fn command_create_pool(config: &Config, fee: Fee, max_validators: u32) -> Comman
142150

143151
let mut transaction = Transaction::new_with_payer(
144152
&[
153+
// Account for the stake pool reserve
154+
system_instruction::create_account(
155+
&config.fee_payer.pubkey(),
156+
&reserve_stake.pubkey(),
157+
reserve_stake_balance,
158+
STAKE_STATE_LEN as u64,
159+
&stake_program::id(),
160+
),
161+
stake_program::initialize(
162+
&reserve_stake.pubkey(),
163+
&stake_program::Authorized {
164+
staker: withdraw_authority,
165+
withdrawer: withdraw_authority,
166+
},
167+
&stake_program::Lockup::default(),
168+
),
145169
// Account for the stake pool mint
146170
system_instruction::create_account(
147171
&config.fee_payer.pubkey(),
@@ -196,6 +220,7 @@ fn command_create_pool(config: &Config, fee: Fee, max_validators: u32) -> Comman
196220
&config.manager.pubkey(),
197221
&config.staker.pubkey(),
198222
&validator_list.pubkey(),
223+
&reserve_stake.pubkey(),
199224
&mint_account.pubkey(),
200225
&pool_fee_account.pubkey(),
201226
&spl_token::id(),

stake-pool/program/src/instruction.rs

+77-20
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,10 @@ pub enum StakePoolInstruction {
4848
/// 3. `[w]` Stake account to be created
4949
/// 4. `[]` Validator this stake account will vote for
5050
/// 5. `[]` Rent sysvar
51-
/// 6. `[]` System program
52-
/// 7. `[]` Stake program
51+
/// 6. `[]` Stake History sysvar
52+
/// 7. `[]` Stake Config sysvar
53+
/// 8. `[]` System program
54+
/// 9. `[]` Stake program
5355
CreateValidatorStakeAccount,
5456

5557
/// (Staker only) Adds stake account delegated to validator to the pool's
@@ -98,29 +100,23 @@ pub enum StakePoolInstruction {
98100
/// In order to rebalance the pool without taking custody, the staker needs
99101
/// a way of reducing the stake on a stake account. This instruction splits
100102
/// some amount of stake, up to the total activated stake, from the canonical
101-
/// validator stake account, into its "transient" stake account, defined by:
102-
///
103-
/// ```ignore
104-
/// Pubkey::find_program_address(
105-
/// &[&stake_account_address.to_bytes()[..32],], program_id,
106-
/// )
107-
/// ```
103+
/// validator stake account, into its "transient" stake account.
108104
///
109105
/// The instruction only succeeds if the transient stake account does not
110106
/// exist. The amount of lamports to move must be at least rent-exemption
111107
/// plus 1 lamport.
112108
///
113109
/// 0. `[]` Stake pool
114110
/// 1. `[s]` Stake pool staker
115-
/// 2. `[]` Validator list
116-
/// 3. `[]` Stake pool withdraw authority
111+
/// 2. `[]` Stake pool withdraw authority
112+
/// 3. `[]` Validator list
117113
/// 5. `[w]` Canonical stake account to split from
118114
/// 5. `[w]` Transient stake account to receive split
119115
/// 6. `[]` Clock sysvar
120116
/// 7. `[]` Rent sysvar
121117
/// 8. `[]` System program
122118
/// 9. `[]` Stake program
123-
/// userdata: amount of lamports to split
119+
/// userdata: amount of lamports to split into the transient stake account
124120
DecreaseValidatorStake(u64),
125121

126122
/// (Staker only) Increase stake on a validator from the reserve account
@@ -135,13 +131,18 @@ pub enum StakePoolInstruction {
135131
///
136132
/// 0. `[]` Stake pool
137133
/// 1. `[s]` Stake pool staker
138-
/// 2. `[]` Validator list
139-
/// 3. `[]` Stake pool withdraw authority
134+
/// 2. `[]` Stake pool withdraw authority
135+
/// 3. `[]` Validator list
140136
/// 4. `[w]` Stake pool reserve stake
141137
/// 5. `[w]` Transient stake account
142-
/// 6. `[]` Canonical stake account
138+
/// 6. `[]` Validator vote account to delegate to
143139
/// 7. '[]' Clock sysvar
144-
/// 8. `[]` Stake program
140+
/// 8. '[]' Rent sysvar
141+
/// 9. `[]` Stake History sysvar
142+
/// 10. `[]` Stake Config sysvar
143+
/// 11. `[]` System program
144+
/// 12. `[]` Stake program
145+
/// userdata: amount of lamports to split into the transient stake account
145146
IncreaseValidatorStake(u64),
146147

147148
/// Updates balances of validator and transient stake accounts in the pool
@@ -249,6 +250,7 @@ pub fn initialize(
249250
manager: &Pubkey,
250251
staker: &Pubkey,
251252
validator_list: &Pubkey,
253+
reserve_stake: &Pubkey,
252254
pool_mint: &Pubkey,
253255
manager_pool_account: &Pubkey,
254256
token_program_id: &Pubkey,
@@ -265,6 +267,7 @@ pub fn initialize(
265267
AccountMeta::new_readonly(*manager, true),
266268
AccountMeta::new_readonly(*staker, false),
267269
AccountMeta::new(*validator_list, false),
270+
AccountMeta::new_readonly(*reserve_stake, false),
268271
AccountMeta::new_readonly(*pool_mint, false),
269272
AccountMeta::new_readonly(*manager_pool_account, false),
270273
AccountMeta::new_readonly(sysvar::clock::id(), false),
@@ -364,14 +367,68 @@ pub fn remove_validator_from_pool(
364367

365368
/// Creates `DecreaseValidatorStake` instruction (rebalance from validator account to
366369
/// transient account)
367-
pub fn decrease_validator_stake() -> Result<Instruction, ProgramError> {
368-
Err(ProgramError::IncorrectProgramId)
370+
pub fn decrease_validator_stake(
371+
program_id: &Pubkey,
372+
stake_pool: &Pubkey,
373+
staker: &Pubkey,
374+
stake_pool_withdraw_authority: &Pubkey,
375+
validator_list: &Pubkey,
376+
validator_stake: &Pubkey,
377+
transient_stake: &Pubkey,
378+
lamports: u64,
379+
) -> Result<Instruction, ProgramError> {
380+
let accounts = vec![
381+
AccountMeta::new_readonly(*stake_pool, false),
382+
AccountMeta::new_readonly(*staker, true),
383+
AccountMeta::new_readonly(*stake_pool_withdraw_authority, false),
384+
AccountMeta::new_readonly(*validator_list, false),
385+
AccountMeta::new(*validator_stake, false),
386+
AccountMeta::new(*transient_stake, false),
387+
AccountMeta::new_readonly(sysvar::clock::id(), false),
388+
AccountMeta::new_readonly(sysvar::rent::id(), false),
389+
AccountMeta::new_readonly(system_program::id(), false),
390+
AccountMeta::new_readonly(stake_program::id(), false),
391+
];
392+
Ok(Instruction {
393+
program_id: *program_id,
394+
accounts,
395+
data: StakePoolInstruction::DecreaseValidatorStake(lamports).try_to_vec()?,
396+
})
369397
}
370398

371399
/// Creates `IncreaseValidatorStake` instruction (rebalance from reserve account to
372400
/// transient account)
373-
pub fn increase_validator_stake() -> Result<Instruction, ProgramError> {
374-
Err(ProgramError::IncorrectProgramId)
401+
pub fn increase_validator_stake(
402+
program_id: &Pubkey,
403+
stake_pool: &Pubkey,
404+
staker: &Pubkey,
405+
stake_pool_withdraw_authority: &Pubkey,
406+
validator_list: &Pubkey,
407+
reserve_stake: &Pubkey,
408+
transient_stake: &Pubkey,
409+
validator: &Pubkey,
410+
lamports: u64,
411+
) -> Result<Instruction, ProgramError> {
412+
let accounts = vec![
413+
AccountMeta::new_readonly(*stake_pool, false),
414+
AccountMeta::new_readonly(*staker, true),
415+
AccountMeta::new_readonly(*stake_pool_withdraw_authority, false),
416+
AccountMeta::new_readonly(*validator_list, false),
417+
AccountMeta::new(*reserve_stake, false),
418+
AccountMeta::new(*transient_stake, false),
419+
AccountMeta::new_readonly(*validator, false),
420+
AccountMeta::new_readonly(sysvar::clock::id(), false),
421+
AccountMeta::new_readonly(sysvar::rent::id(), false),
422+
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
423+
AccountMeta::new_readonly(stake_program::config_id(), false),
424+
AccountMeta::new_readonly(system_program::id(), false),
425+
AccountMeta::new_readonly(stake_program::id(), false),
426+
];
427+
Ok(Instruction {
428+
program_id: *program_id,
429+
accounts,
430+
data: StakePoolInstruction::IncreaseValidatorStake(lamports).try_to_vec()?,
431+
})
375432
}
376433

377434
/// Creates `UpdateValidatorListBalance` instruction (update validator stake account balances)

stake-pool/program/src/lib.rs

+19
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ const AUTHORITY_DEPOSIT: &[u8] = b"deposit";
2525
/// Seed for withdraw authority seed
2626
const AUTHORITY_WITHDRAW: &[u8] = b"withdraw";
2727

28+
/// Seed for transient stake account
29+
const TRANSIENT_STAKE_SEED: &[u8] = b"transient";
30+
2831
/// Minimum amount of staked SOL required in a validator stake account to allow
2932
/// for merges without a mismatch on credits observed
3033
pub const MINIMUM_ACTIVE_STAKE: u64 = LAMPORTS_PER_SOL;
@@ -73,4 +76,20 @@ pub fn find_stake_program_address(
7376
)
7477
}
7578

79+
/// Generates the stake program address for a validator's vote account
80+
pub fn find_transient_stake_program_address(
81+
program_id: &Pubkey,
82+
vote_account_address: &Pubkey,
83+
stake_pool_address: &Pubkey,
84+
) -> (Pubkey, u8) {
85+
Pubkey::find_program_address(
86+
&[
87+
TRANSIENT_STAKE_SEED,
88+
&vote_account_address.to_bytes()[..32],
89+
&stake_pool_address.to_bytes()[..32],
90+
],
91+
program_id,
92+
)
93+
}
94+
7695
solana_program::declare_id!("poo1B9L9nR3CrcaziKVYVpRX6A9Y1LAXYasjjfCbApj");

0 commit comments

Comments
 (0)