diff --git a/stake-pool/program/src/processor.rs b/stake-pool/program/src/processor.rs index e7fdc8dfec1..ff476abeb51 100644 --- a/stake-pool/program/src/processor.rs +++ b/stake-pool/program/src/processor.rs @@ -1019,7 +1019,7 @@ impl Processor { return Err(StakePoolError::InvalidState.into()); } - let (_meta, stake) = get_stake_state(validator_stake_account_info)?; + let (meta, stake) = get_stake_state(validator_stake_account_info)?; let vote_account_address = stake.delegation.voter_pubkey; check_validator_stake_address( program_id, @@ -1069,6 +1069,20 @@ impl Processor { return Err(ProgramError::AccountNotRentExempt); } + let remaining_lamports = validator_stake_account_info + .lamports() + .checked_sub(lamports) + .ok_or(ProgramError::InsufficientFunds)?; + let required_lamports = minimum_stake_lamports(&meta); + if remaining_lamports < required_lamports { + msg!("Need at least {} lamports in the stake account after decrease, {} requested, {} is the current possible maximum", + required_lamports, + lamports, + validator_stake_account_info.lamports().checked_sub(required_lamports).ok_or(StakePoolError::CalculationFailure)? + ); + return Err(ProgramError::InsufficientFunds); + } + create_transient_stake_account( transient_stake_account_info.clone(), transient_stake_account_signer_seeds, diff --git a/stake-pool/program/tests/decrease.rs b/stake-pool/program/tests/decrease.rs index e34008917f7..20c73fbf840 100644 --- a/stake-pool/program/tests/decrease.rs +++ b/stake-pool/program/tests/decrease.rs @@ -367,7 +367,7 @@ async fn fail_with_small_lamport_amount() { } #[tokio::test] -async fn fail_overdraw_validator() { +async fn fail_big_overdraw() { let ( mut banks_client, payer, @@ -392,8 +392,43 @@ async fn fail_overdraw_validator() { .unwrap() .unwrap(); - match error { - TransactionError::InstructionError(_, InstructionError::InsufficientFunds) => {} - _ => panic!("Wrong error occurs while overdrawing stake account on decrease"), - } + assert_eq!( + error, + TransactionError::InstructionError(0, InstructionError::InsufficientFunds) + ); +} + +#[tokio::test] +async fn fail_overdraw() { + let ( + mut banks_client, + payer, + recent_blockhash, + stake_pool_accounts, + validator_stake, + deposit_info, + _decrease_lamports, + ) = setup().await; + + let rent = banks_client.get_rent().await.unwrap(); + let stake_rent = rent.minimum_balance(std::mem::size_of::()); + + let error = stake_pool_accounts + .decrease_validator_stake( + &mut banks_client, + &payer, + &recent_blockhash, + &validator_stake.stake_account, + &validator_stake.transient_stake_account, + deposit_info.stake_lamports + stake_rent + 1, + validator_stake.transient_stake_seed, + ) + .await + .unwrap() + .unwrap(); + + assert_eq!( + error, + TransactionError::InstructionError(0, InstructionError::InsufficientFunds) + ); }