@@ -916,6 +916,10 @@ async fn fail_withdraw_from_transient() {
916916 . await
917917 . unwrap ( ) ;
918918
919+ let stake_minimum_delegation =
920+ stake_get_minimum_delegation ( & mut context. banks_client , & context. payer , & last_blockhash)
921+ . await ;
922+
919923 let rent = context. banks_client . get_rent ( ) . await . unwrap ( ) ;
920924 let stake_rent = rent. minimum_balance ( std:: mem:: size_of :: < stake:: state:: StakeStateV2 > ( ) ) ;
921925
@@ -927,7 +931,7 @@ async fn fail_withdraw_from_transient() {
927931 & last_blockhash,
928932 & validator_stake_account. stake_account ,
929933 & validator_stake_account. transient_stake_account ,
930- deposit_info. stake_lamports + stake_rent - 2 ,
934+ deposit_info. stake_lamports + stake_rent - stake_minimum_delegation - 2 ,
931935 validator_stake_account. transient_stake_seed ,
932936 DecreaseInstruction :: Reserve ,
933937 )
@@ -1531,3 +1535,96 @@ async fn success_remove_preferred_validator_resets_preference() {
15311535 "User should receive all lamports from removed validator"
15321536 ) ;
15331537}
1538+
1539+ #[ tokio:: test]
1540+ async fn fail_withdrawal_minimum_in_preferred ( ) {
1541+ let stake_pool_accounts = StakePoolAccounts :: new_without_fees ( ) ;
1542+
1543+ let (
1544+ mut context,
1545+ validator_stake,
1546+ deposit_info,
1547+ user_transfer_authority,
1548+ user_stake_recipient,
1549+ tokens_to_burn,
1550+ ) = setup_for_withdraw_with_accounts ( & stake_pool_accounts, 0 ) . await ;
1551+
1552+ stake_pool_accounts
1553+ . set_preferred_validator (
1554+ & mut context. banks_client ,
1555+ & context. payer ,
1556+ & context. last_blockhash ,
1557+ instruction:: PreferredValidatorType :: Withdraw ,
1558+ Some ( validator_stake. vote . pubkey ( ) ) ,
1559+ )
1560+ . await ;
1561+
1562+ // Warp forward to activation
1563+ let first_normal_slot = context. genesis_config ( ) . epoch_schedule . first_normal_slot ;
1564+ let slot = first_normal_slot + 1 ;
1565+ context. warp_to_slot ( slot) . unwrap ( ) ;
1566+ let error = stake_pool_accounts
1567+ . update_all (
1568+ & mut context. banks_client ,
1569+ & context. payer ,
1570+ & context. last_blockhash ,
1571+ false ,
1572+ )
1573+ . await ;
1574+ assert ! ( error. is_none( ) ) ;
1575+
1576+ // Withdraw some from preferred, get it down to 2x + 1
1577+ let stake_minimum_delegation = stake_get_minimum_delegation (
1578+ & mut context. banks_client ,
1579+ & context. payer ,
1580+ & context. last_blockhash ,
1581+ )
1582+ . await ;
1583+
1584+ let new_authority = Pubkey :: new_unique ( ) ;
1585+ let error = stake_pool_accounts
1586+ . withdraw_stake (
1587+ & mut context. banks_client ,
1588+ & context. payer ,
1589+ & context. last_blockhash ,
1590+ & user_stake_recipient. pubkey ( ) ,
1591+ & user_transfer_authority,
1592+ & deposit_info. pool_account . pubkey ( ) ,
1593+ & validator_stake. stake_account ,
1594+ & new_authority,
1595+ tokens_to_burn - stake_minimum_delegation,
1596+ )
1597+ . await ;
1598+ assert ! ( error. is_none( ) , "{:?}" , error) ;
1599+
1600+ // preferred is not empty, withdrawing from non-preferred fails
1601+ let user_stake_recipient = Keypair :: new ( ) ;
1602+ create_blank_stake_account (
1603+ & mut context. banks_client ,
1604+ & context. payer ,
1605+ & context. last_blockhash ,
1606+ & user_stake_recipient,
1607+ )
1608+ . await ;
1609+ let error = stake_pool_accounts
1610+ . withdraw_stake (
1611+ & mut context. banks_client ,
1612+ & context. payer ,
1613+ & context. last_blockhash ,
1614+ & user_stake_recipient. pubkey ( ) ,
1615+ & user_transfer_authority,
1616+ & deposit_info. pool_account . pubkey ( ) ,
1617+ & validator_stake. stake_account ,
1618+ & new_authority,
1619+ stake_minimum_delegation,
1620+ )
1621+ . await ;
1622+ let transaction_error = error. unwrap ( ) . unwrap ( ) ;
1623+ assert_eq ! (
1624+ transaction_error,
1625+ TransactionError :: InstructionError (
1626+ 0 ,
1627+ InstructionError :: Custom ( StakePoolError :: StakeLamportsNotEqualToMinimum as u32 )
1628+ )
1629+ ) ;
1630+ }
0 commit comments