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

Commit 671590d

Browse files
authored
- reimplement prepare_withdraw_accounts according to the documentation (#2513)
* - reimplement prepare_withdraw_accounts according to the docu * - add preferred withdraw validator * - fix clippy issues * - fix styling
1 parent e8b7009 commit 671590d

File tree

2 files changed

+75
-48
lines changed

2 files changed

+75
-48
lines changed

stake-pool/cli/src/client.rs

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -77,43 +77,6 @@ pub(crate) fn get_stake_state(
7777
Ok(stake_state)
7878
}
7979

80-
pub(crate) fn get_stake_accounts_by_withdraw_authority(
81-
rpc_client: &RpcClient,
82-
withdraw_authority: &Pubkey,
83-
) -> Result<Vec<(Pubkey, u64, stake_program::StakeState)>, ClientError> {
84-
rpc_client
85-
.get_program_accounts_with_config(
86-
&stake_program::id(),
87-
#[allow(clippy::needless_update)] // TODO: Remove after updating to solana >=1.6.10
88-
RpcProgramAccountsConfig {
89-
filters: Some(vec![RpcFilterType::Memcmp(Memcmp {
90-
offset: 44, // 44 is Withdrawer authority offset in stake account stake
91-
bytes: MemcmpEncodedBytes::Binary(format!("{}", withdraw_authority)),
92-
encoding: None,
93-
})]),
94-
account_config: RpcAccountInfoConfig {
95-
encoding: Some(UiAccountEncoding::Base64),
96-
..RpcAccountInfoConfig::default()
97-
},
98-
..RpcProgramAccountsConfig::default()
99-
},
100-
)
101-
.map(|accounts| {
102-
accounts
103-
.into_iter()
104-
.filter_map(
105-
|(address, account)| match deserialize(account.data.as_slice()) {
106-
Ok(stake_state) => Some((address, account.lamports, stake_state)),
107-
Err(err) => {
108-
eprintln!("Invalid stake account data for {}: {}", address, err);
109-
None
110-
}
111-
},
112-
)
113-
.collect()
114-
})
115-
}
116-
11780
pub(crate) fn get_stake_pools(
11881
rpc_client: &RpcClient,
11982
) -> Result<Vec<(Pubkey, StakePool, ValidatorList)>, ClientError> {

stake-pool/cli/src/main.rs

Lines changed: 75 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use {
3131
transaction::Transaction,
3232
},
3333
spl_associated_token_account::{create_associated_token_account, get_associated_token_address},
34+
spl_stake_pool::state::ValidatorStakeInfo,
3435
spl_stake_pool::{
3536
self, find_stake_program_address, find_transient_stake_program_address,
3637
find_withdraw_authority_program_address,
@@ -39,6 +40,7 @@ use {
3940
state::{Fee, FeeType, StakePool, ValidatorList},
4041
MINIMUM_ACTIVE_STAKE,
4142
},
43+
std::cmp::Ordering,
4244
std::{process::exit, sync::Arc},
4345
};
4446

@@ -1061,31 +1063,93 @@ struct WithdrawAccount {
10611063
pool_amount: u64,
10621064
}
10631065

1066+
fn sorted_accounts<F>(
1067+
validator_list: &ValidatorList,
1068+
stake_pool: &StakePool,
1069+
get_pubkey: F,
1070+
) -> Vec<(Pubkey, u64, Option<Pubkey>)>
1071+
where
1072+
F: Fn(&ValidatorStakeInfo) -> Pubkey,
1073+
{
1074+
let mut result: Vec<(Pubkey, u64, Option<Pubkey>)> = validator_list
1075+
.validators
1076+
.iter()
1077+
.map(|validator| {
1078+
(
1079+
get_pubkey(validator),
1080+
validator.active_stake_lamports,
1081+
Some(validator.vote_account_address),
1082+
)
1083+
})
1084+
.collect::<Vec<_>>();
1085+
1086+
result.sort_by(|left, right| {
1087+
if left.2 == stake_pool.preferred_withdraw_validator_vote_address {
1088+
Ordering::Less
1089+
} else if right.2 == stake_pool.preferred_withdraw_validator_vote_address {
1090+
Ordering::Greater
1091+
} else {
1092+
right.1.cmp(&left.1)
1093+
}
1094+
});
1095+
1096+
result
1097+
}
1098+
10641099
fn prepare_withdraw_accounts(
10651100
rpc_client: &RpcClient,
10661101
stake_pool: &StakePool,
1067-
pool_withdraw_authority: &Pubkey,
10681102
pool_amount: u64,
1103+
stake_pool_address: &Pubkey,
10691104
) -> Result<Vec<WithdrawAccount>, Error> {
1070-
let mut accounts =
1071-
get_stake_accounts_by_withdraw_authority(rpc_client, pool_withdraw_authority)?;
1072-
if accounts.is_empty() {
1073-
return Err("No accounts found.".to_string().into());
1074-
}
10751105
let min_balance = rpc_client
10761106
.get_minimum_balance_for_rent_exemption(STAKE_STATE_LEN)?
10771107
.saturating_add(MINIMUM_ACTIVE_STAKE);
10781108
let pool_mint = get_token_mint(rpc_client, &stake_pool.pool_mint)?;
10791109

1080-
// Sort from highest to lowest balance
1081-
accounts.sort_by(|a, b| b.1.cmp(&a.1));
1110+
let validator_list: ValidatorList = get_validator_list(rpc_client, &stake_pool.validator_list)?;
1111+
1112+
let mut accounts: Vec<(Pubkey, u64, Option<Pubkey>)> = Vec::new();
1113+
1114+
accounts.append(&mut sorted_accounts(
1115+
&validator_list,
1116+
stake_pool,
1117+
|validator| {
1118+
let (stake_account_address, _) = find_stake_program_address(
1119+
&spl_stake_pool::id(),
1120+
&validator.vote_account_address,
1121+
stake_pool_address,
1122+
);
1123+
1124+
stake_account_address
1125+
},
1126+
));
1127+
1128+
accounts.append(&mut sorted_accounts(
1129+
&validator_list,
1130+
stake_pool,
1131+
|validator| {
1132+
let (transient_stake_account_address, _) = find_transient_stake_program_address(
1133+
&spl_stake_pool::id(),
1134+
&validator.vote_account_address,
1135+
stake_pool_address,
1136+
validator.transient_seed_suffix_start,
1137+
);
1138+
1139+
transient_stake_account_address
1140+
},
1141+
));
1142+
1143+
let reserve_stake = rpc_client.get_account(&stake_pool.reserve_stake)?;
1144+
1145+
accounts.push((stake_pool.reserve_stake, reserve_stake.lamports, None));
10821146

10831147
// Prepare the list of accounts to withdraw from
10841148
let mut withdraw_from: Vec<WithdrawAccount> = vec![];
10851149
let mut remaining_amount = pool_amount;
10861150

10871151
// Go through available accounts and withdraw from largest to smallest
1088-
for (stake_address, lamports, stake) in accounts {
1152+
for (stake_address, lamports, vote_address_opt) in accounts {
10891153
if lamports <= min_balance {
10901154
continue;
10911155
}
@@ -1099,7 +1163,7 @@ fn prepare_withdraw_accounts(
10991163
// Those accounts will be withdrawn completely with `claim` instruction
11001164
withdraw_from.push(WithdrawAccount {
11011165
stake_address,
1102-
vote_address: stake.delegation().map(|x| x.voter_pubkey),
1166+
vote_address: vote_address_opt,
11031167
pool_amount,
11041168
});
11051169
remaining_amount -= pool_amount;
@@ -1204,8 +1268,8 @@ fn command_withdraw_stake(
12041268
prepare_withdraw_accounts(
12051269
&config.rpc_client,
12061270
&stake_pool,
1207-
&pool_withdraw_authority,
12081271
pool_amount,
1272+
stake_pool_address,
12091273
)?
12101274
};
12111275

0 commit comments

Comments
 (0)