31
31
transaction:: Transaction ,
32
32
} ,
33
33
spl_associated_token_account:: { create_associated_token_account, get_associated_token_address} ,
34
+ spl_stake_pool:: state:: ValidatorStakeInfo ,
34
35
spl_stake_pool:: {
35
36
self , find_stake_program_address, find_transient_stake_program_address,
36
37
find_withdraw_authority_program_address,
39
40
state:: { Fee , FeeType , StakePool , ValidatorList } ,
40
41
MINIMUM_ACTIVE_STAKE ,
41
42
} ,
43
+ std:: cmp:: Ordering ,
42
44
std:: { process:: exit, sync:: Arc } ,
43
45
} ;
44
46
@@ -1061,31 +1063,93 @@ struct WithdrawAccount {
1061
1063
pool_amount : u64 ,
1062
1064
}
1063
1065
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
+
1064
1099
fn prepare_withdraw_accounts (
1065
1100
rpc_client : & RpcClient ,
1066
1101
stake_pool : & StakePool ,
1067
- pool_withdraw_authority : & Pubkey ,
1068
1102
pool_amount : u64 ,
1103
+ stake_pool_address : & Pubkey ,
1069
1104
) -> 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
- }
1075
1105
let min_balance = rpc_client
1076
1106
. get_minimum_balance_for_rent_exemption ( STAKE_STATE_LEN ) ?
1077
1107
. saturating_add ( MINIMUM_ACTIVE_STAKE ) ;
1078
1108
let pool_mint = get_token_mint ( rpc_client, & stake_pool. pool_mint ) ?;
1079
1109
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 ) ) ;
1082
1146
1083
1147
// Prepare the list of accounts to withdraw from
1084
1148
let mut withdraw_from: Vec < WithdrawAccount > = vec ! [ ] ;
1085
1149
let mut remaining_amount = pool_amount;
1086
1150
1087
1151
// 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 {
1089
1153
if lamports <= min_balance {
1090
1154
continue ;
1091
1155
}
@@ -1099,7 +1163,7 @@ fn prepare_withdraw_accounts(
1099
1163
// Those accounts will be withdrawn completely with `claim` instruction
1100
1164
withdraw_from. push ( WithdrawAccount {
1101
1165
stake_address,
1102
- vote_address : stake . delegation ( ) . map ( |x| x . voter_pubkey ) ,
1166
+ vote_address : vote_address_opt ,
1103
1167
pool_amount,
1104
1168
} ) ;
1105
1169
remaining_amount -= pool_amount;
@@ -1204,8 +1268,8 @@ fn command_withdraw_stake(
1204
1268
prepare_withdraw_accounts (
1205
1269
& config. rpc_client ,
1206
1270
& stake_pool,
1207
- & pool_withdraw_authority,
1208
1271
pool_amount,
1272
+ stake_pool_address,
1209
1273
) ?
1210
1274
} ;
1211
1275
0 commit comments