Skip to content

Commit

Permalink
stake-pool-cli: Improve deposit and withdraw UX (solana-labs#2530)
Browse files Browse the repository at this point in the history
  • Loading branch information
joncinque authored Oct 19, 2021
1 parent c9a918f commit 203db7b
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 35 deletions.
23 changes: 14 additions & 9 deletions docs/src/stake-pool.md
Original file line number Diff line number Diff line change
Expand Up @@ -734,23 +734,25 @@ Stake pools allow SOL withdrawals directly from the reserve and into a normal
SOL wallet account, and in exchange burns the provided pool tokens.

```console
$ spl-stake-pool withdraw-sol Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 2
$ spl-stake-pool withdraw-sol Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 7VXPpSxneL6JLj18Naw2gkukXtjBZfbmPh18cnoUCMD8 2
Signature: 4bqZKUUrjVspqTGqGqX4zxnHnJB67WbeukKUZRmxJ2yFmr275CtHPjZNzQJD9Pe7Q6mSxnUpcVv9FUdAbGP9RyBc
```

The stake pool burned 2 pool tokens. In return, the stake pool sent SOL to the
fee payer for the transaction. You can check that the pool tokens have been burned:
The stake pool has burned 2 pool tokens, and in return, sent SOL to
`7VXPpSxneL6JLj18Naw2gkukXtjBZfbmPh18cnoUCMD8`.

You can check that the pool tokens have been burned:

```console
$ spl-token balance BoNneHKDrX9BHjjvSpPfnQyRjsnc9WFH71v8wrgCd7LB
98.00000000
```

And you can check that the fee payer has been credited:
And you can check that the recipient has been credited:

```console
$ solana balance
49.660334743 SOL
$ solana balance 7VXPpSxneL6JLj18Naw2gkukXtjBZfbmPh18cnoUCMD8
2 SOL
```

### Deposit stake
Expand Down Expand Up @@ -788,12 +790,15 @@ Signature: 45x2UtA1b49eBPtRHdkvA3k8JneZzfwjptNN1kKQZaPABYiJ4hSA8qwi7qLNN5b3Fr4Z6
```

The CLI will default to using the fee payer's
[Associated Token Account](associated-token-account.md) for stake pool tokens.
[Associated Token Account](associated-token-account.md) for stake pool tokens
and the withdraw authority on the deposited stake account.

Alternatively, you can create an SPL token account yourself and pass it as the
`token-receiver` for the command.
`token-receiver` for the command, and specify the withdraw authority on the
stake account using the `withdraw-authority` flag.

```console
$ spl-stake-pool deposit-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 97wBBiLVA7fUViEew8yV8R6tTdKithZDVz8LHLfF9sTJ --token-receiver 34XMHa3JUPv46ftU4dGHvemZ9oKVjnciRePYMcX3rjEF
$ spl-stake-pool deposit-stake Zg5YBPAk8RqBR9kaLLSoN5C8Uv7nErBz1WC63HTsCPR 97wBBiLVA7fUViEew8yV8R6tTdKithZDVz8LHLfF9sTJ --token-receiver 34XMHa3JUPv46ftU4dGHvemZ9oKVjnciRePYMcX3rjEF --withdraw-authority authority.json
Depositing stake 97wBBiLVA7fUViEew8yV8R6tTdKithZDVz8LHLfF9sTJ into stake pool account F8e8Ympp4MkDSPZdvRxdQUZXRkMBDdyqgHa363GShAPt
Signature: 4AESGZzqBVfj5xQnMiPWAwzJnAtQDRFK1Ha6jqKKTs46Zm5fw3LqgU1mRAT6CKTywVfFMHZCLm1hcQNScSMwVvjQ
```
Expand Down
98 changes: 72 additions & 26 deletions stake-pool/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ use {
input_parsers::{keypair_of, pubkey_of},
input_validators::{
is_amount, is_keypair, is_keypair_or_ask_keyword, is_parsable, is_pubkey, is_url,
is_valid_percentage,
is_valid_percentage, is_valid_pubkey,
},
keypair::signer_from_path,
keypair::{signer_from_path_with_config, SignerFromPathConfig},
},
solana_client::rpc_client::RpcClient,
solana_program::{
Expand Down Expand Up @@ -88,12 +88,14 @@ fn get_signer(
keypair_name: &str,
keypair_path: &str,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
signer_from_path_config: SignerFromPathConfig,
) -> Box<dyn Signer> {
signer_from_path(
signer_from_path_with_config(
matches,
matches.value_of(keypair_name).unwrap_or(keypair_path),
keypair_name,
wallet_manager,
&signer_from_path_config,
)
.unwrap_or_else(|e| {
eprintln!("error: {}", e);
Expand Down Expand Up @@ -596,6 +598,7 @@ fn command_deposit_stake(
config: &Config,
stake_pool_address: &Pubkey,
stake: &Pubkey,
withdraw_authority: Box<dyn Signer>,
pool_token_receiver_account: &Option<Pubkey>,
referrer_token_account: &Option<Pubkey>,
) -> CommandResult {
Expand Down Expand Up @@ -634,7 +637,7 @@ fn command_deposit_stake(
}

let mut instructions: Vec<Instruction> = vec![];
let mut signers = vec![config.fee_payer.as_ref(), config.staker.as_ref()];
let mut signers = vec![config.fee_payer.as_ref(), withdraw_authority.as_ref()];

let mut total_rent_free_balances: u64 = 0;

Expand Down Expand Up @@ -672,7 +675,7 @@ fn command_deposit_stake(
&stake_deposit_authority.pubkey(),
&pool_withdraw_authority,
stake,
&config.staker.pubkey(),
&withdraw_authority.pubkey(),
&validator_stake_account,
&stake_pool.reserve_stake,
&pool_token_receiver_account,
Expand All @@ -688,7 +691,7 @@ fn command_deposit_stake(
&stake_pool.validator_list,
&pool_withdraw_authority,
stake,
&config.staker.pubkey(),
&withdraw_authority.pubkey(),
&validator_stake_account,
&stake_pool.reserve_stake,
&pool_token_receiver_account,
Expand Down Expand Up @@ -1371,8 +1374,8 @@ fn command_withdraw_stake(
fn command_withdraw_sol(
config: &Config,
stake_pool_address: &Pubkey,
sol_receiver: &Option<Pubkey>,
pool_token_account: &Option<Pubkey>,
sol_receiver: &Pubkey,
pool_amount: f64,
) -> CommandResult {
if !config.no_update {
Expand All @@ -1383,7 +1386,6 @@ fn command_withdraw_sol(
let pool_mint = get_token_mint(&config.rpc_client, &stake_pool.pool_mint)?;
let pool_amount = spl_token::ui_amount_to_amount(pool_amount, pool_mint.decimals);

let sol_receiver = sol_receiver.unwrap_or_else(|| config.fee_payer.pubkey());
let pool_token_account = pool_token_account.unwrap_or(get_associated_token_address(
&config.token_owner.pubkey(),
&stake_pool.pool_mint,
Expand Down Expand Up @@ -1450,7 +1452,7 @@ fn command_withdraw_sol(
&user_transfer_authority.pubkey(),
&pool_token_account,
&stake_pool.reserve_stake,
&sol_receiver,
sol_receiver,
&stake_pool.manager_fee_account,
&stake_pool.pool_mint,
&spl_token::id(),
Expand All @@ -1464,7 +1466,7 @@ fn command_withdraw_sol(
&user_transfer_authority.pubkey(),
&pool_token_account,
&stake_pool.reserve_stake,
&sol_receiver,
sol_receiver,
&stake_pool.manager_fee_account,
&stake_pool.pool_mint,
&spl_token::id(),
Expand Down Expand Up @@ -2011,6 +2013,15 @@ fn main() {
.required(true)
.help("Stake address to join the pool"),
)
.arg(
Arg::with_name("withdraw_authority")
.long("withdraw-authority")
.validator(is_keypair)
.value_name("KEYPAIR")
.takes_value(true)
.help("Withdraw authority for the stake account to be deposited. \
Defaults to the fee payer."),
)
.arg(
Arg::with_name("token_receiver")
.long("token-receiver")
Expand Down Expand Up @@ -2181,8 +2192,17 @@ fn main() {
.help("Stake pool address."),
)
.arg(
Arg::with_name("amount")
Arg::with_name("sol_receiver")
.index(2)
.validator(is_valid_pubkey)
.value_name("SYSTEM_ACCOUNT_ADDRESS_OR_KEYPAIR")
.takes_value(true)
.required(true)
.help("System account to receive SOL from the stake pool. Defaults to the payer."),
)
.arg(
Arg::with_name("amount")
.index(3)
.validator(is_amount)
.value_name("AMOUNT")
.takes_value(true)
Expand All @@ -2197,14 +2217,6 @@ fn main() {
.takes_value(true)
.help("Pool token account to withdraw tokens from. Defaults to the token-owner's associated token account."),
)
.arg(
Arg::with_name("sol_receiver")
.long("sol-receiver")
.validator(is_pubkey)
.value_name("SYSTEM_ACCOUNT_ADDRESS")
.takes_value(true)
.help("System account to receive SOL from the stake pool. Defaults to the payer."),
)
)
.subcommand(SubCommand::with_name("set-manager")
.about("Change manager or fee receiver account for the stake pool. Must be signed by the current manager.")
Expand Down Expand Up @@ -2373,12 +2385,12 @@ fn main() {
.get_matches();

let mut wallet_manager = None;
let cli_config = if let Some(config_file) = matches.value_of("config_file") {
solana_cli_config::Config::load(config_file).unwrap_or_default()
} else {
solana_cli_config::Config::default()
};
let config = {
let cli_config = if let Some(config_file) = matches.value_of("config_file") {
solana_cli_config::Config::load(config_file).unwrap_or_default()
} else {
solana_cli_config::Config::default()
};
let json_rpc_url = value_t!(matches, "json_rpc_url", String)
.unwrap_or_else(|_| cli_config.json_rpc_url.clone());

Expand All @@ -2387,6 +2399,9 @@ fn main() {
"staker",
&cli_config.keypair_path,
&mut wallet_manager,
SignerFromPathConfig {
allow_null_signer: false,
},
);

let funding_authority = if matches.is_present("funding_authority") {
Expand All @@ -2395,6 +2410,9 @@ fn main() {
"funding_authority",
&cli_config.keypair_path,
&mut wallet_manager,
SignerFromPathConfig {
allow_null_signer: false,
},
))
} else {
None
Expand All @@ -2404,18 +2422,27 @@ fn main() {
"manager",
&cli_config.keypair_path,
&mut wallet_manager,
SignerFromPathConfig {
allow_null_signer: false,
},
);
let token_owner = get_signer(
&matches,
"token_owner",
&cli_config.keypair_path,
&mut wallet_manager,
SignerFromPathConfig {
allow_null_signer: false,
},
);
let fee_payer = get_signer(
&matches,
"fee_payer",
&cli_config.keypair_path,
&mut wallet_manager,
SignerFromPathConfig {
allow_null_signer: false,
},
);
let verbose = matches.is_present("verbose");
let dry_run = matches.is_present("dry_run");
Expand Down Expand Up @@ -2523,10 +2550,20 @@ fn main() {
let stake_account = pubkey_of(arg_matches, "stake_account").unwrap();
let token_receiver: Option<Pubkey> = pubkey_of(arg_matches, "token_receiver");
let referrer: Option<Pubkey> = pubkey_of(arg_matches, "referrer");
let withdraw_authority = get_signer(
arg_matches,
"withdraw_authority",
&cli_config.keypair_path,
&mut wallet_manager,
SignerFromPathConfig {
allow_null_signer: false,
},
);
command_deposit_stake(
&config,
&stake_pool_address,
&stake_account,
withdraw_authority,
&token_receiver,
&referrer,
)
Expand Down Expand Up @@ -2577,12 +2614,21 @@ fn main() {
let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap();
let pool_account = pubkey_of(arg_matches, "pool_account");
let pool_amount = value_t_or_exit!(arg_matches, "amount", f64);
let sol_receiver = pubkey_of(arg_matches, "sol_receiver");
let sol_receiver = get_signer(
arg_matches,
"sol_receiver",
&cli_config.keypair_path,
&mut wallet_manager,
SignerFromPathConfig {
allow_null_signer: true,
},
)
.pubkey();
command_withdraw_sol(
&config,
&stake_pool_address,
&sol_receiver,
&pool_account,
&sol_receiver,
pool_amount,
)
}
Expand Down

0 comments on commit 203db7b

Please sign in to comment.