Skip to content

Commit

Permalink
Cli stake-split: adjust transfer amount if recipient has lamports (#266)
Browse files Browse the repository at this point in the history
* Remove incorrect check

* Move to closure

* Use match statement instead

* Adjust rent_exempt_reserve by existing balance

* Only transfer lamports if rent_exempt_reserve needs are greater than 0

* Rename variable for clarity

* Add minimum-delegation check

* Bump test split amount to meet arbitrary mock minimum-delegation amount
  • Loading branch information
CriesofCarrots authored Mar 21, 2024
1 parent 792d745 commit dff99d0
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 34 deletions.
2 changes: 1 addition & 1 deletion cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2254,7 +2254,7 @@ mod tests {
memo: None,
split_stake_account: 1,
seed: None,
lamports: 30,
lamports: 200_000_000,
fee_payer: 0,
compute_unit_price: None,
rent_exempt_reserve: None,
Expand Down
79 changes: 46 additions & 33 deletions cli/src/stake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,14 @@ use {
},
solana_rpc_client_nonce_utils::blockhash_query::BlockhashQuery,
solana_sdk::{
account::from_account,
account::{from_account, Account},
account_utils::StateMut,
clock::{Clock, UnixTimestamp, SECONDS_PER_DAY},
commitment_config::CommitmentConfig,
epoch_schedule::EpochSchedule,
feature_set,
message::Message,
native_token::Sol,
pubkey::Pubkey,
stake::{
self,
Expand Down Expand Up @@ -1980,40 +1981,49 @@ pub fn process_split_stake(
};

let rent_exempt_reserve = if !sign_only {
if let Ok(stake_account) = rpc_client.get_account(&split_stake_account_address) {
if stake_account.owner == stake::program::id() {
return Err(CliError::BadParameter(format!(
let stake_minimum_delegation = rpc_client.get_stake_minimum_delegation()?;
if lamports < stake_minimum_delegation {
let lamports = Sol(lamports);
let stake_minimum_delegation = Sol(stake_minimum_delegation);
return Err(CliError::BadParameter(format!(
"need at least {stake_minimum_delegation} for minimum stake delegation, \
provided: {lamports}"
))
.into());
}

let check_stake_account = |account: Account| -> Result<u64, CliError> {
match account.owner {
owner if owner == stake::program::id() => Err(CliError::BadParameter(format!(
"Stake account {split_stake_account_address} already exists"
))
.into());
} else if stake_account.owner == system_program::id() {
if !stake_account.data.is_empty() {
return Err(CliError::BadParameter(format!(
"Account {split_stake_account_address} has data and cannot be used to split stake"
))
.into());
))),
owner if owner == system_program::id() => {
if !account.data.is_empty() {
Err(CliError::BadParameter(format!(
"Account {split_stake_account_address} has data and cannot be used to split stake"
)))
} else {
// if `stake_account`'s owner is the system_program and its data is
// empty, `stake_account` is allowed to receive the stake split
Ok(account.lamports)
}
}
// if `stake_account`'s owner is the system_program and its data is
// empty, `stake_account` is allowed to receive the stake split
} else {
return Err(CliError::BadParameter(format!(
_ => Err(CliError::BadParameter(format!(
"Account {split_stake_account_address} already exists and cannot be used to split stake"
))
.into());
)))
}
}
};
let current_balance =
if let Ok(stake_account) = rpc_client.get_account(&split_stake_account_address) {
check_stake_account(stake_account)?
} else {
0
};

let minimum_balance =
let rent_exempt_reserve =
rpc_client.get_minimum_balance_for_rent_exemption(StakeStateV2::size_of())?;

if lamports < minimum_balance {
return Err(CliError::BadParameter(format!(
"need at least {minimum_balance} lamports for stake account to be rent exempt, \
provided lamports: {lamports}"
))
.into());
}
minimum_balance
rent_exempt_reserve.saturating_sub(current_balance)
} else {
rent_exempt_reserve
.cloned()
Expand All @@ -2022,11 +2032,14 @@ pub fn process_split_stake(

let recent_blockhash = blockhash_query.get_blockhash(rpc_client, config.commitment)?;

let mut ixs = vec![system_instruction::transfer(
&fee_payer.pubkey(),
&split_stake_account_address,
rent_exempt_reserve,
)];
let mut ixs = vec![];
if rent_exempt_reserve > 0 {
ixs.push(system_instruction::transfer(
&fee_payer.pubkey(),
&split_stake_account_address,
rent_exempt_reserve,
));
}
if let Some(seed) = split_stake_account_seed {
ixs.append(
&mut stake_instruction::split_with_seed(
Expand Down

0 comments on commit dff99d0

Please sign in to comment.