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

Commit eba709b

Browse files
authored
stake-pool: Support stake redelegation (#3856)
* stake-pool: Add redelegate implementation * Remove rent account from instruction * Update validator searching due to rebase * Use new blockhash in test to avoid timeout in CI * Clarify error message * Fix instruction comment * Refresh blockhash in failing test more often
1 parent 4a8e7a0 commit eba709b

File tree

9 files changed

+1760
-35
lines changed

9 files changed

+1760
-35
lines changed

stake-pool/program/src/instruction.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,57 @@ pub enum StakePoolInstruction {
473473
/// seed used to create ephemeral account.
474474
ephemeral_stake_seed: u64,
475475
},
476+
477+
/// (Staker only) Redelegate active stake on a validator, eventually moving it to another
478+
///
479+
/// Internally, this instruction splits a validator stake account into its
480+
/// corresponding transient stake account, redelegates it to an ephemeral stake
481+
/// account, then merges that stake into the destination transient stake account.
482+
///
483+
/// In order to rebalance the pool without taking custody, the staker needs
484+
/// a way of reducing the stake on a stake account. This instruction splits
485+
/// some amount of stake, up to the total activated stake, from the canonical
486+
/// validator stake account, into its "transient" stake account.
487+
///
488+
/// The instruction only succeeds if the source transient stake account and
489+
/// ephemeral stake account do not exist.
490+
///
491+
/// The amount of lamports to move must be at least twice rent-exemption
492+
/// plus the minimum delegation amount. Rent-exemption is required for the
493+
/// source transient stake account, and rent-exemption plus minimum delegation
494+
/// is required for the destination ephemeral stake account.
495+
///
496+
/// 0. `[]` Stake pool
497+
/// 1. `[s]` Stake pool staker
498+
/// 2. `[]` Stake pool withdraw authority
499+
/// 3. `[w]` Validator list
500+
/// 4. `[w]` Source canonical stake account to split from
501+
/// 5. `[w]` Source transient stake account to receive split and be redelegated
502+
/// 6. `[w]` Uninitialized ephemeral stake account to receive redelegation
503+
/// 7. `[w]` Destination transient stake account to receive ephemeral stake by merge
504+
/// 8. `[]` Destination stake account to receive transient stake after activation
505+
/// 9. `[]` Destination validator vote account
506+
/// 10. `[]` Clock sysvar
507+
/// 11. `[]` Stake History sysvar
508+
/// 12. `[]` Stake Config sysvar
509+
/// 13. `[]` System program
510+
/// 14. `[]` Stake program
511+
Redelegate {
512+
/// Amount of lamports to redelegate
513+
#[allow(dead_code)] // but it's not
514+
lamports: u64,
515+
/// Seed used to create source transient stake account
516+
#[allow(dead_code)] // but it's not
517+
source_transient_stake_seed: u64,
518+
/// Seed used to create destination ephemeral account.
519+
#[allow(dead_code)] // but it's not
520+
ephemeral_stake_seed: u64,
521+
/// Seed used to create destination transient stake account. If there is
522+
/// already transient stake, this must match the current seed, otherwise
523+
/// it can be anything
524+
#[allow(dead_code)] // but it's not
525+
destination_transient_stake_seed: u64,
526+
},
476527
}
477528

478529
/// Creates an 'initialize' instruction.
@@ -756,6 +807,55 @@ pub fn increase_additional_validator_stake(
756807
}
757808
}
758809

810+
/// Creates `Redelegate` instruction (rebalance from one validator account to another)
811+
pub fn redelegate(
812+
program_id: &Pubkey,
813+
stake_pool: &Pubkey,
814+
staker: &Pubkey,
815+
stake_pool_withdraw_authority: &Pubkey,
816+
validator_list: &Pubkey,
817+
source_validator_stake: &Pubkey,
818+
source_transient_stake: &Pubkey,
819+
ephemeral_stake: &Pubkey,
820+
destination_transient_stake: &Pubkey,
821+
destination_validator_stake: &Pubkey,
822+
validator: &Pubkey,
823+
lamports: u64,
824+
source_transient_stake_seed: u64,
825+
ephemeral_stake_seed: u64,
826+
destination_transient_stake_seed: u64,
827+
) -> Instruction {
828+
let accounts = vec![
829+
AccountMeta::new_readonly(*stake_pool, false),
830+
AccountMeta::new_readonly(*staker, true),
831+
AccountMeta::new_readonly(*stake_pool_withdraw_authority, false),
832+
AccountMeta::new(*validator_list, false),
833+
AccountMeta::new(*source_validator_stake, false),
834+
AccountMeta::new(*source_transient_stake, false),
835+
AccountMeta::new(*ephemeral_stake, false),
836+
AccountMeta::new(*destination_transient_stake, false),
837+
AccountMeta::new_readonly(*destination_validator_stake, false),
838+
AccountMeta::new_readonly(*validator, false),
839+
AccountMeta::new_readonly(sysvar::clock::id(), false),
840+
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
841+
AccountMeta::new_readonly(stake::config::id(), false),
842+
AccountMeta::new_readonly(system_program::id(), false),
843+
AccountMeta::new_readonly(stake::program::id(), false),
844+
];
845+
Instruction {
846+
program_id: *program_id,
847+
accounts,
848+
data: StakePoolInstruction::Redelegate {
849+
lamports,
850+
source_transient_stake_seed,
851+
ephemeral_stake_seed,
852+
destination_transient_stake_seed,
853+
}
854+
.try_to_vec()
855+
.unwrap(),
856+
}
857+
}
858+
759859
/// Creates `SetPreferredDepositValidator` instruction
760860
pub fn set_preferred_validator(
761861
program_id: &Pubkey,

0 commit comments

Comments
 (0)