@@ -844,10 +844,9 @@ impl Processor {
844
844
if header. max_validators == validator_list. len ( ) {
845
845
return Err ( ProgramError :: AccountDataTooSmall ) ;
846
846
}
847
- let maybe_validator_stake_info = validator_list. find :: < ValidatorStakeInfo > (
848
- validator_vote_info. key . as_ref ( ) ,
849
- ValidatorStakeInfo :: memcmp_pubkey,
850
- ) ;
847
+ let maybe_validator_stake_info = validator_list. find :: < ValidatorStakeInfo , _ > ( |x| {
848
+ ValidatorStakeInfo :: memcmp_pubkey ( x, validator_vote_info. key )
849
+ } ) ;
851
850
if maybe_validator_stake_info. is_some ( ) {
852
851
return Err ( StakePoolError :: ValidatorAlreadyAdded . into ( ) ) ;
853
852
}
@@ -994,10 +993,9 @@ impl Processor {
994
993
995
994
let ( meta, stake) = get_stake_state ( stake_account_info) ?;
996
995
let vote_account_address = stake. delegation . voter_pubkey ;
997
- let maybe_validator_stake_info = validator_list. find_mut :: < ValidatorStakeInfo > (
998
- vote_account_address. as_ref ( ) ,
999
- ValidatorStakeInfo :: memcmp_pubkey,
1000
- ) ;
996
+ let maybe_validator_stake_info = validator_list. find_mut :: < ValidatorStakeInfo , _ > ( |x| {
997
+ ValidatorStakeInfo :: memcmp_pubkey ( x, & vote_account_address)
998
+ } ) ;
1001
999
if maybe_validator_stake_info. is_none ( ) {
1002
1000
msg ! (
1003
1001
"Vote account {} not found in stake pool" ,
@@ -1154,10 +1152,9 @@ impl Processor {
1154
1152
let ( meta, stake) = get_stake_state ( validator_stake_account_info) ?;
1155
1153
let vote_account_address = stake. delegation . voter_pubkey ;
1156
1154
1157
- let maybe_validator_stake_info = validator_list. find_mut :: < ValidatorStakeInfo > (
1158
- vote_account_address. as_ref ( ) ,
1159
- ValidatorStakeInfo :: memcmp_pubkey,
1160
- ) ;
1155
+ let maybe_validator_stake_info = validator_list. find_mut :: < ValidatorStakeInfo , _ > ( |x| {
1156
+ ValidatorStakeInfo :: memcmp_pubkey ( x, & vote_account_address)
1157
+ } ) ;
1161
1158
if maybe_validator_stake_info. is_none ( ) {
1162
1159
msg ! (
1163
1160
"Vote account {} not found in stake pool" ,
@@ -1316,10 +1313,9 @@ impl Processor {
1316
1313
1317
1314
let vote_account_address = validator_vote_account_info. key ;
1318
1315
1319
- let maybe_validator_stake_info = validator_list. find_mut :: < ValidatorStakeInfo > (
1320
- vote_account_address. as_ref ( ) ,
1321
- ValidatorStakeInfo :: memcmp_pubkey,
1322
- ) ;
1316
+ let maybe_validator_stake_info = validator_list. find_mut :: < ValidatorStakeInfo , _ > ( |x| {
1317
+ ValidatorStakeInfo :: memcmp_pubkey ( x, vote_account_address)
1318
+ } ) ;
1323
1319
if maybe_validator_stake_info. is_none ( ) {
1324
1320
msg ! (
1325
1321
"Vote account {} not found in stake pool" ,
@@ -1481,10 +1477,9 @@ impl Processor {
1481
1477
}
1482
1478
1483
1479
if let Some ( vote_account_address) = vote_account_address {
1484
- let maybe_validator_stake_info = validator_list. find :: < ValidatorStakeInfo > (
1485
- vote_account_address. as_ref ( ) ,
1486
- ValidatorStakeInfo :: memcmp_pubkey,
1487
- ) ;
1480
+ let maybe_validator_stake_info = validator_list. find :: < ValidatorStakeInfo , _ > ( |x| {
1481
+ ValidatorStakeInfo :: memcmp_pubkey ( x, & vote_account_address)
1482
+ } ) ;
1488
1483
match maybe_validator_stake_info {
1489
1484
Some ( vsi) => {
1490
1485
if vsi. status != StakeStatus :: Active {
@@ -2031,10 +2026,9 @@ impl Processor {
2031
2026
}
2032
2027
2033
2028
let mut validator_stake_info = validator_list
2034
- . find_mut :: < ValidatorStakeInfo > (
2035
- vote_account_address. as_ref ( ) ,
2036
- ValidatorStakeInfo :: memcmp_pubkey,
2037
- )
2029
+ . find_mut :: < ValidatorStakeInfo , _ > ( |x| {
2030
+ ValidatorStakeInfo :: memcmp_pubkey ( x, & vote_account_address)
2031
+ } )
2038
2032
. ok_or ( StakePoolError :: ValidatorNotFound ) ?;
2039
2033
check_validator_stake_address (
2040
2034
program_id,
@@ -2428,7 +2422,7 @@ impl Processor {
2428
2422
. checked_sub ( pool_tokens_fee)
2429
2423
. ok_or ( StakePoolError :: CalculationFailure ) ?;
2430
2424
2431
- let withdraw_lamports = stake_pool
2425
+ let mut withdraw_lamports = stake_pool
2432
2426
. calc_lamports_withdraw_amount ( pool_tokens_burnt)
2433
2427
. ok_or ( StakePoolError :: CalculationFailure ) ?;
2434
2428
@@ -2442,17 +2436,27 @@ impl Processor {
2442
2436
let meta = stake_state. meta ( ) . ok_or ( StakePoolError :: WrongStakeState ) ?;
2443
2437
let required_lamports = minimum_stake_lamports ( & meta, stake_minimum_delegation) ;
2444
2438
2439
+ let lamports_per_pool_token = stake_pool
2440
+ . get_lamports_per_pool_token ( )
2441
+ . ok_or ( StakePoolError :: CalculationFailure ) ?;
2442
+ let minimum_lamports_with_tolerance =
2443
+ required_lamports. saturating_add ( lamports_per_pool_token) ;
2444
+
2445
2445
let has_active_stake = validator_list
2446
- . find :: < ValidatorStakeInfo > (
2447
- & required_lamports. to_le_bytes ( ) ,
2448
- ValidatorStakeInfo :: active_lamports_not_equal,
2449
- )
2446
+ . find :: < ValidatorStakeInfo , _ > ( |x| {
2447
+ ValidatorStakeInfo :: active_lamports_greater_than (
2448
+ x,
2449
+ & minimum_lamports_with_tolerance,
2450
+ )
2451
+ } )
2450
2452
. is_some ( ) ;
2451
2453
let has_transient_stake = validator_list
2452
- . find :: < ValidatorStakeInfo > (
2453
- & 0u64 . to_le_bytes ( ) ,
2454
- ValidatorStakeInfo :: transient_lamports_not_equal,
2455
- )
2454
+ . find :: < ValidatorStakeInfo , _ > ( |x| {
2455
+ ValidatorStakeInfo :: transient_lamports_greater_than (
2456
+ x,
2457
+ & minimum_lamports_with_tolerance,
2458
+ )
2459
+ } )
2456
2460
. is_some ( ) ;
2457
2461
2458
2462
let validator_list_item_info = if * stake_split_from. key == stake_pool. reserve_stake {
@@ -2478,25 +2482,23 @@ impl Processor {
2478
2482
stake_pool. preferred_withdraw_validator_vote_address
2479
2483
{
2480
2484
let preferred_validator_info = validator_list
2481
- . find :: < ValidatorStakeInfo > (
2482
- preferred_withdraw_validator. as_ref ( ) ,
2483
- ValidatorStakeInfo :: memcmp_pubkey,
2484
- )
2485
+ . find :: < ValidatorStakeInfo , _ > ( |x| {
2486
+ ValidatorStakeInfo :: memcmp_pubkey ( x, & preferred_withdraw_validator)
2487
+ } )
2485
2488
. ok_or ( StakePoolError :: ValidatorNotFound ) ?;
2486
2489
let available_lamports = preferred_validator_info
2487
2490
. active_stake_lamports
2488
- . saturating_sub ( required_lamports ) ;
2491
+ . saturating_sub ( minimum_lamports_with_tolerance ) ;
2489
2492
if preferred_withdraw_validator != vote_account_address && available_lamports > 0 {
2490
2493
msg ! ( "Validator vote address {} is preferred for withdrawals, it currently has {} lamports available. Please withdraw those before using other validator stake accounts." , preferred_withdraw_validator, preferred_validator_info. active_stake_lamports) ;
2491
2494
return Err ( StakePoolError :: IncorrectWithdrawVoteAddress . into ( ) ) ;
2492
2495
}
2493
2496
}
2494
2497
2495
2498
let validator_stake_info = validator_list
2496
- . find_mut :: < ValidatorStakeInfo > (
2497
- vote_account_address. as_ref ( ) ,
2498
- ValidatorStakeInfo :: memcmp_pubkey,
2499
- )
2499
+ . find_mut :: < ValidatorStakeInfo , _ > ( |x| {
2500
+ ValidatorStakeInfo :: memcmp_pubkey ( x, & vote_account_address)
2501
+ } )
2500
2502
. ok_or ( StakePoolError :: ValidatorNotFound ) ?;
2501
2503
2502
2504
let withdraw_source = if has_active_stake {
@@ -2548,11 +2550,21 @@ impl Processor {
2548
2550
}
2549
2551
}
2550
2552
StakeWithdrawSource :: ValidatorRemoval => {
2551
- if withdraw_lamports != stake_split_from. lamports ( ) {
2552
- msg ! ( "Cannot withdraw a whole account worth {} lamports, must withdraw exactly {} lamports worth of pool tokens" ,
2553
- withdraw_lamports, stake_split_from. lamports( ) ) ;
2553
+ let split_from_lamports = stake_split_from. lamports ( ) ;
2554
+ let upper_bound = split_from_lamports. saturating_add ( lamports_per_pool_token) ;
2555
+ if withdraw_lamports < split_from_lamports || withdraw_lamports > upper_bound {
2556
+ msg ! (
2557
+ "Cannot withdraw a whole account worth {} lamports, \
2558
+ must withdraw at least {} lamports worth of pool tokens \
2559
+ with a margin of {} lamports",
2560
+ withdraw_lamports,
2561
+ split_from_lamports,
2562
+ lamports_per_pool_token
2563
+ ) ;
2554
2564
return Err ( StakePoolError :: StakeLamportsNotEqualToMinimum . into ( ) ) ;
2555
2565
}
2566
+ // truncate the lamports down to the amount in the account
2567
+ withdraw_lamports = split_from_lamports;
2556
2568
}
2557
2569
}
2558
2570
Some ( ( validator_stake_info, withdraw_source) )
0 commit comments