Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit f35ca3c

Browse files
authored
stake-pool-cli: Address feedback (#2057)
* Fix signer parameters (staker, manager, depositor, fee-payer, and token-owner) * On deposit / withdraw / add / remove validator, show the validator stake account and where the stake is going to
1 parent b209d4d commit f35ca3c

File tree

3 files changed

+100
-69
lines changed

3 files changed

+100
-69
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

stake-pool/cli/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ solana-clap-utils = "=1.7.4"
1717
solana-cli-config = "=1.7.4"
1818
solana-client = "=1.7.4"
1919
solana-logger = "=1.7.4"
20-
solana-sdk = "=1.7.4"
2120
solana-program = "=1.7.4"
21+
solana-remote-wallet = "=1.7.4"
22+
solana-sdk = "=1.7.4"
2223
spl-associated-token-account = { version = "1.0", path="../../associated-token-account/program", features = [ "no-entrypoint" ] }
2324
spl-stake-pool = { version = "0.3", path="../program", features = [ "no-entrypoint" ] }
2425
spl-token = { version = "3.1", path="../../token/program", features = [ "no-entrypoint" ] }

stake-pool/cli/src/main.rs

Lines changed: 97 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use {
77
crate::client::*,
88
clap::{
99
crate_description, crate_name, crate_version, value_t, value_t_or_exit, App, AppSettings,
10-
Arg, ArgGroup, SubCommand,
10+
Arg, ArgGroup, ArgMatches, SubCommand,
1111
},
1212
solana_clap_utils::{
1313
input_parsers::{keypair_of, pubkey_of},
@@ -23,6 +23,7 @@ use {
2323
program_pack::Pack,
2424
pubkey::Pubkey,
2525
},
26+
solana_remote_wallet::remote_wallet::RemoteWalletManager,
2627
solana_sdk::{
2728
commitment_config::CommitmentConfig,
2829
native_token::{self, Sol},
@@ -38,7 +39,7 @@ use {
3839
stake_program::{self, StakeState},
3940
state::{Fee, StakePool, ValidatorList},
4041
},
41-
std::process::exit,
42+
std::{process::exit, sync::Arc},
4243
};
4344

4445
struct Config {
@@ -83,6 +84,24 @@ fn check_fee_payer_balance(config: &Config, required_balance: u64) -> Result<(),
8384
}
8485
}
8586

87+
fn get_signer(
88+
matches: &ArgMatches<'_>,
89+
keypair_name: &str,
90+
keypair_path: &str,
91+
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
92+
) -> Box<dyn Signer> {
93+
signer_from_path(
94+
matches,
95+
matches.value_of(keypair_name).unwrap_or(keypair_path),
96+
keypair_name,
97+
wallet_manager,
98+
)
99+
.unwrap_or_else(|e| {
100+
eprintln!("error: {}", e);
101+
exit(1);
102+
})
103+
}
104+
86105
fn send_transaction_no_wait(
87106
config: &Config,
88107
transaction: Transaction,
@@ -316,16 +335,22 @@ fn command_vsa_create(
316335
stake_pool_address: &Pubkey,
317336
vote_account: &Pubkey,
318337
) -> CommandResult {
319-
println!("Creating stake account on {}", vote_account);
338+
let (stake_account, _) =
339+
find_stake_program_address(&spl_stake_pool::id(), vote_account, stake_pool_address);
340+
println!(
341+
"Creating stake account {}, delegated to {}",
342+
stake_account, vote_account
343+
);
320344
let transaction = checked_transaction_with_signers(
321345
config,
322346
&[
323347
// Create new validator stake account address
324-
spl_stake_pool::instruction::create_validator_stake_account_with_vote(
348+
spl_stake_pool::instruction::create_validator_stake_account(
325349
&spl_stake_pool::id(),
326350
stake_pool_address,
327351
&config.staker.pubkey(),
328352
&config.fee_payer.pubkey(),
353+
&stake_account,
329354
vote_account,
330355
),
331356
],
@@ -342,6 +367,10 @@ fn command_vsa_add(
342367
) -> CommandResult {
343368
let (stake_account_address, _) =
344369
find_stake_program_address(&spl_stake_pool::id(), vote_account, stake_pool_address);
370+
println!(
371+
"Adding stake account {}, delegated to {}",
372+
stake_account_address, vote_account
373+
);
345374
let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?;
346375
let validator_list = get_validator_list(&config.rpc_client, &stake_pool.validator_list)?;
347376
if validator_list.contains(vote_account) {
@@ -399,6 +428,13 @@ fn command_vsa_remove(
399428
command_update(config, stake_pool_address, false, false)?;
400429
}
401430

431+
let (stake_account_address, _) =
432+
find_stake_program_address(&spl_stake_pool::id(), vote_account, stake_pool_address);
433+
println!(
434+
"Removing stake account {}, delegated to {}",
435+
stake_account_address, vote_account
436+
);
437+
402438
let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?;
403439

404440
let staker_pubkey = config.staker.pubkey();
@@ -522,7 +558,7 @@ fn add_associated_token_account(
522558
// Account for tokens not specified, creating one
523559
let account = get_associated_token_address(&config.fee_payer.pubkey(), mint);
524560
if get_token_account(&config.rpc_client, &account, mint).is_err() {
525-
println!("Creating account to receive tokens {}", account);
561+
println!("Creating associated token account {} to receive stake pool tokens of mint {}, owned by {}", account, mint, config.fee_payer.pubkey());
526562

527563
let min_account_balance = config
528564
.rpc_client
@@ -536,6 +572,8 @@ fn add_associated_token_account(
536572
));
537573

538574
*rent_free_balances += min_account_balance;
575+
} else {
576+
println!("Using existing associated token account {} to receive stake pool tokens of mint {}, owned by {}", account, mint, config.fee_payer.pubkey());
539577
}
540578

541579
account
@@ -573,7 +611,10 @@ fn command_deposit(
573611
find_stake_program_address(&spl_stake_pool::id(), &vote_account, stake_pool_address);
574612

575613
let validator_stake_state = get_stake_state(&config.rpc_client, &validator_stake_account)?;
576-
println!("Depositing into stake account {}", validator_stake_account);
614+
println!(
615+
"Depositing stake {} into stake pool account {}",
616+
stake, validator_stake_account
617+
);
577618
if config.verbose {
578619
println!("{:?}", validator_stake_state);
579620
}
@@ -797,7 +838,8 @@ fn command_update(
797838

798839
#[derive(PartialEq, Debug)]
799840
struct WithdrawAccount {
800-
address: Pubkey,
841+
stake_address: Pubkey,
842+
vote_address: Option<Pubkey>,
801843
pool_amount: u64,
802844
}
803845

@@ -823,7 +865,7 @@ fn prepare_withdraw_accounts(
823865
let mut remaining_amount = pool_amount;
824866

825867
// Go through available accounts and withdraw from largest to smallest
826-
for (address, lamports, _) in accounts {
868+
for (stake_address, lamports, stake) in accounts {
827869
if lamports <= min_balance {
828870
continue;
829871
}
@@ -834,7 +876,8 @@ fn prepare_withdraw_accounts(
834876

835877
// Those accounts will be withdrawn completely with `claim` instruction
836878
withdraw_from.push(WithdrawAccount {
837-
address,
879+
stake_address,
880+
vote_address: stake.delegation().map(|x| x.voter_pubkey),
838881
pool_amount,
839882
});
840883
remaining_amount -= pool_amount;
@@ -898,7 +941,8 @@ fn command_withdraw(
898941

899942
let withdraw_accounts = if use_reserve {
900943
vec![WithdrawAccount {
901-
address: stake_pool.reserve_stake,
944+
stake_address: stake_pool.reserve_stake,
945+
vote_address: None,
902946
pool_amount,
903947
}]
904948
} else if let Some(vote_account_address) = vote_account_address {
@@ -919,7 +963,8 @@ fn command_withdraw(
919963
.into());
920964
}
921965
vec![WithdrawAccount {
922-
address: stake_account_address,
966+
stake_address: stake_account_address,
967+
vote_address: Some(*vote_account_address),
923968
pool_amount,
924969
}]
925970
} else {
@@ -940,7 +985,7 @@ fn command_withdraw(
940985
config.token_owner.as_ref(),
941986
&user_transfer_authority,
942987
];
943-
let stake_receiver_account = Keypair::new(); // Will be added to signers if creating new account
988+
let mut new_stake_keypairs = vec![];
944989

945990
instructions.push(
946991
// Approve spending token
@@ -954,9 +999,6 @@ fn command_withdraw(
954999
)?,
9551000
);
9561001

957-
// Use separate mutable variable because withdraw might create a new account
958-
let mut stake_receiver: Option<Pubkey> = *stake_receiver_param;
959-
9601002
let mut total_rent_free_balances = 0;
9611003

9621004
// Go through prepared accounts and withdraw/claim them
@@ -967,48 +1009,52 @@ fn command_withdraw(
9671009
.unwrap();
9681010

9691011
println!(
970-
"Withdrawing from account {}, amount {}, {} pool tokens",
971-
withdraw_account.address,
1012+
"Withdrawing {}, or {} pool tokens, from stake account {}, delegated to {:?}, stake / withdraw authority {}",
9721013
Sol(sol_withdraw_amount),
9731014
spl_token::amount_to_ui_amount(withdraw_account.pool_amount, pool_mint.decimals),
1015+
withdraw_account.stake_address,
1016+
withdraw_account.vote_address,
1017+
config.staker.pubkey(),
9741018
);
9751019

976-
if stake_receiver.is_none() {
1020+
// Use separate mutable variable because withdraw might create a new account
1021+
let stake_receiver = stake_receiver_param.unwrap_or_else(|| {
9771022
// Account for tokens not specified, creating one
1023+
let stake_receiver_account = Keypair::new(); // Will be added to signers if creating new account
1024+
let stake_receiver_pubkey = stake_receiver_account.pubkey();
9781025
println!(
9791026
"Creating account to receive stake {}",
980-
stake_receiver_account.pubkey()
1027+
stake_receiver_pubkey
9811028
);
9821029

9831030
let stake_receiver_account_balance = config
9841031
.rpc_client
985-
.get_minimum_balance_for_rent_exemption(STAKE_STATE_LEN)?;
1032+
.get_minimum_balance_for_rent_exemption(STAKE_STATE_LEN)
1033+
.unwrap();
9861034

9871035
instructions.push(
9881036
// Creating new account
9891037
system_instruction::create_account(
9901038
&config.fee_payer.pubkey(),
991-
&stake_receiver_account.pubkey(),
1039+
&stake_receiver_pubkey,
9921040
stake_receiver_account_balance,
9931041
STAKE_STATE_LEN as u64,
9941042
&stake_program::id(),
9951043
),
9961044
);
9971045

998-
signers.push(&stake_receiver_account);
999-
10001046
total_rent_free_balances += stake_receiver_account_balance;
1001-
1002-
stake_receiver = Some(stake_receiver_account.pubkey());
1003-
}
1047+
new_stake_keypairs.push(stake_receiver_account);
1048+
stake_receiver_pubkey
1049+
});
10041050

10051051
instructions.push(spl_stake_pool::instruction::withdraw(
10061052
&spl_stake_pool::id(),
10071053
stake_pool_address,
10081054
&stake_pool.validator_list,
10091055
&pool_withdraw_authority,
1010-
&withdraw_account.address,
1011-
&stake_receiver.unwrap(), // Cannot be none at this point
1056+
&withdraw_account.stake_address,
1057+
&stake_receiver,
10121058
&config.staker.pubkey(),
10131059
&user_transfer_authority.pubkey(),
10141060
&pool_token_account,
@@ -1026,6 +1072,9 @@ fn command_withdraw(
10261072
config,
10271073
total_rent_free_balances + fee_calculator.calculate_fee(transaction.message()),
10281074
)?;
1075+
for new_stake_keypair in &new_stake_keypairs {
1076+
signers.push(new_stake_keypair);
1077+
}
10291078
unique_signers!(signers);
10301079
transaction.sign(&signers, recent_blockhash);
10311080
send_transaction(config, transaction)?;
@@ -1562,6 +1611,7 @@ fn main() {
15621611
.validator(is_pubkey)
15631612
.value_name("STAKE_ACCOUNT_ADDRESS")
15641613
.takes_value(true)
1614+
.requires("withdraw_from")
15651615
.help("Stake account to receive SOL from the stake pool. Defaults to a new stake account."),
15661616
)
15671617
.arg(
@@ -1679,62 +1729,41 @@ fn main() {
16791729
let json_rpc_url = value_t!(matches, "json_rpc_url", String)
16801730
.unwrap_or_else(|_| cli_config.json_rpc_url.clone());
16811731

1682-
let staker = signer_from_path(
1732+
let staker = get_signer(
16831733
&matches,
1684-
&cli_config.keypair_path,
16851734
"staker",
1735+
&cli_config.keypair_path,
16861736
&mut wallet_manager,
1687-
)
1688-
.unwrap_or_else(|e| {
1689-
eprintln!("error: {}", e);
1690-
exit(1);
1691-
});
1737+
);
1738+
16921739
let depositor = if matches.is_present("depositor") {
1693-
Some(
1694-
signer_from_path(
1695-
&matches,
1696-
&cli_config.keypair_path,
1697-
"depositor",
1698-
&mut wallet_manager,
1699-
)
1700-
.unwrap_or_else(|e| {
1701-
eprintln!("error: {}", e);
1702-
exit(1);
1703-
}),
1704-
)
1740+
Some(get_signer(
1741+
&matches,
1742+
"depositor",
1743+
&cli_config.keypair_path,
1744+
&mut wallet_manager,
1745+
))
17051746
} else {
17061747
None
17071748
};
1708-
let manager = signer_from_path(
1749+
let manager = get_signer(
17091750
&matches,
1710-
&cli_config.keypair_path,
17111751
"manager",
1752+
&cli_config.keypair_path,
17121753
&mut wallet_manager,
1713-
)
1714-
.unwrap_or_else(|e| {
1715-
eprintln!("error: {}", e);
1716-
exit(1);
1717-
});
1718-
let token_owner = signer_from_path(
1754+
);
1755+
let token_owner = get_signer(
17191756
&matches,
1720-
&cli_config.keypair_path,
17211757
"token_owner",
1758+
&cli_config.keypair_path,
17221759
&mut wallet_manager,
1723-
)
1724-
.unwrap_or_else(|e| {
1725-
eprintln!("error: {}", e);
1726-
exit(1);
1727-
});
1728-
let fee_payer = signer_from_path(
1760+
);
1761+
let fee_payer = get_signer(
17291762
&matches,
1730-
&cli_config.keypair_path,
17311763
"fee_payer",
1764+
&cli_config.keypair_path,
17321765
&mut wallet_manager,
1733-
)
1734-
.unwrap_or_else(|e| {
1735-
eprintln!("error: {}", e);
1736-
exit(1);
1737-
});
1766+
);
17381767
let verbose = matches.is_present("verbose");
17391768
let dry_run = matches.is_present("dry_run");
17401769
let no_update = matches.is_present("no_update");

0 commit comments

Comments
 (0)