diff --git a/cli/src/spend_utils.rs b/cli/src/spend_utils.rs index 62f7a8dfd1f05f..c98f2facc78ff6 100644 --- a/cli/src/spend_utils.rs +++ b/cli/src/spend_utils.rs @@ -2,6 +2,7 @@ use { crate::{ checks::{check_account_for_balance_with_commitment, get_fee_for_messages}, cli::CliError, + stake, }, clap::ArgMatches, solana_clap_utils::{input_parsers::lamports_of_sol, offline::SIGN_ONLY_ARG}, @@ -96,15 +97,39 @@ where )?; Ok((message, spend)) } else { - let from_balance = rpc_client - .get_balance_with_commitment(from_pubkey, commitment)? - .value; let from_rent_exempt_minimum = if amount == SpendAmount::RentExempt { let data = rpc_client.get_account_data(from_pubkey)?; rpc_client.get_minimum_balance_for_rent_exemption(data.len())? } else { 0 }; + + let mut from_balance: u64 = 0; + if let Some(account) = rpc_client + .get_account_with_commitment(from_pubkey, commitment)? + .value + { + if account.owner == solana_sdk::stake::program::id() { + let state = stake::get_account_stake_state( + rpc_client, + from_pubkey, + account, + true, + None, + false, + )?; + from_balance = state.account_balance; + if let Some(active_stake) = state.active_stake { + from_balance = from_balance.saturating_sub(active_stake); + } + } + } + if from_balance == 0 { + from_balance = rpc_client + .get_balance_with_commitment(from_pubkey, commitment)? + .value; + } + let (message, SpendAndFee { spend, fee }) = resolve_spend_message( rpc_client, amount, diff --git a/cli/src/stake.rs b/cli/src/stake.rs index f4bb8329278d94..670c8969abbaaa 100644 --- a/cli/src/stake.rs +++ b/cli/src/stake.rs @@ -2529,6 +2529,25 @@ pub fn process_show_stake_account( use_csv: bool, ) -> ProcessResult { let stake_account = rpc_client.get_account(stake_account_address)?; + let state = get_account_stake_state( + rpc_client, + stake_account_address, + stake_account, + use_lamports_unit, + with_rewards, + use_csv, + )?; + return Ok(config.output_format.formatted_string(&state)); +} + +pub fn get_account_stake_state( + rpc_client: &RpcClient, + stake_account_address: &Pubkey, + stake_account: solana_sdk::account::Account, + use_lamports_unit: bool, + with_rewards: Option, + use_csv: bool, +) -> Result { if stake_account.owner != stake::program::id() { return Err(CliError::RpcRequestError(format!( "{stake_account_address:?} is not a stake account", @@ -2572,7 +2591,7 @@ pub fn process_show_stake_account( }); state.epoch_rewards = epoch_rewards; } - Ok(config.output_format.formatted_string(&state)) + Ok(state) } Err(err) => Err(CliError::RpcRequestError(format!( "Account data could not be deserialized to stake state: {err}"