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

Commit cd63580

Browse files
JulI0-concertoJulien PiccalugaCriesofCarrots
authored
Implement multiple output format for spl-stake-pool list-all (#2558)
* Implement json output formats for spl-stake-pool list-all * Implement --output json or json-compact or display in list-all cmd * cleanup: use destructuring instead of tuple * Fix related to PR comments * Add json and json-compact output for list command * implement list command display with Display and VerboseDisplay * make CliStakePool->details optional * cleanup use * Update stake-pool/cli/src/main.rs Co-authored-by: Tyera Eulberg <[email protected]> * Update stake-pool/cli/src/main.rs Co-authored-by: Tyera Eulberg <[email protected]> * clippished * fix use * fix fmt issue Co-authored-by: Julien Piccaluga <[email protected]> Co-authored-by: Tyera Eulberg <[email protected]>
1 parent 707382e commit cd63580

File tree

5 files changed

+581
-146
lines changed

5 files changed

+581
-146
lines changed

Cargo.lock

Lines changed: 3 additions & 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: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@ version = "0.6.3"
1111
[dependencies]
1212
borsh = "0.9"
1313
clap = "2.33.3"
14+
serde = "1.0.130"
15+
serde_derive = "1.0.130"
1416
serde_json = "1.0.68"
1517
solana-account-decoder = "=1.8.1"
1618
solana-clap-utils = "=1.8.1"
1719
solana-cli-config = "=1.8.1"
20+
solana-cli-output = "1.8.1"
1821
solana-client = "=1.8.1"
1922
solana-logger = "=1.8.1"
2023
solana-program = "=1.8.1"

stake-pool/cli/src/client.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ use {
88
rpc_filter::{Memcmp, MemcmpEncodedBytes, RpcFilterType},
99
},
1010
solana_program::{borsh::try_from_slice_unchecked, program_pack::Pack, pubkey::Pubkey, stake},
11-
spl_stake_pool::state::{StakePool, ValidatorList},
11+
spl_stake_pool::{
12+
find_withdraw_authority_program_address,
13+
state::{StakePool, ValidatorList},
14+
},
1215
};
1316

1417
type Error = Box<dyn std::error::Error>;
@@ -76,7 +79,7 @@ pub(crate) fn get_stake_state(
7679

7780
pub(crate) fn get_stake_pools(
7881
rpc_client: &RpcClient,
79-
) -> Result<Vec<(Pubkey, StakePool, ValidatorList)>, ClientError> {
82+
) -> Result<Vec<(Pubkey, StakePool, ValidatorList, Pubkey)>, ClientError> {
8083
rpc_client
8184
.get_program_accounts_with_config(
8285
&spl_stake_pool::id(),
@@ -97,10 +100,14 @@ pub(crate) fn get_stake_pools(
97100
accounts
98101
.into_iter()
99102
.filter_map(|(address, account)| {
103+
let pool_withdraw_authority =
104+
find_withdraw_authority_program_address(&spl_stake_pool::id(), &address).0;
100105
match try_from_slice_unchecked::<StakePool>(account.data.as_slice()) {
101106
Ok(stake_pool) => {
102107
get_validator_list(rpc_client, &stake_pool.validator_list)
103-
.map(|v| (address, stake_pool, v))
108+
.map(|validator_list| {
109+
(address, stake_pool, validator_list, pool_withdraw_authority)
110+
})
104111
.ok()
105112
}
106113
Err(err) => {

stake-pool/cli/src/main.rs

Lines changed: 84 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
mod client;
2+
mod output;
23

34
use {
4-
crate::client::*,
5+
crate::{
6+
client::*,
7+
output::{CliStakePool, CliStakePoolDetails, CliStakePoolStakeAccountInfo, CliStakePools},
8+
},
59
clap::{
610
crate_description, crate_name, crate_version, value_t, value_t_or_exit, App, AppSettings,
711
Arg, ArgGroup, ArgMatches, SubCommand,
@@ -14,6 +18,7 @@ use {
1418
},
1519
keypair::{signer_from_path_with_config, SignerFromPathConfig},
1620
},
21+
solana_cli_output::OutputFormat,
1722
solana_client::rpc_client::RpcClient,
1823
solana_program::{
1924
borsh::{get_instance_packed_len, get_packed_len},
@@ -44,9 +49,10 @@ use {
4449
std::{process::exit, sync::Arc},
4550
};
4651

47-
struct Config {
52+
pub(crate) struct Config {
4853
rpc_client: RpcClient,
4954
verbose: bool,
55+
output_format: OutputFormat,
5056
manager: Box<dyn Signer>,
5157
staker: Box<dyn Signer>,
5258
funding_authority: Option<Box<dyn Signer>>,
@@ -852,96 +858,25 @@ fn command_deposit_sol(
852858

853859
fn command_list(config: &Config, stake_pool_address: &Pubkey) -> CommandResult {
854860
let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?;
861+
let reserve_stake_account_address = stake_pool.reserve_stake.to_string();
862+
let total_lamports = stake_pool.total_lamports;
863+
let last_update_epoch = stake_pool.last_update_epoch;
855864
let validator_list = get_validator_list(&config.rpc_client, &stake_pool.validator_list)?;
865+
let max_number_of_validators = validator_list.header.max_validators;
866+
let current_number_of_validators = validator_list.validators.len();
856867
let pool_mint = get_token_mint(&config.rpc_client, &stake_pool.pool_mint)?;
857868
let epoch_info = config.rpc_client.get_epoch_info()?;
858869
let pool_withdraw_authority =
859870
find_withdraw_authority_program_address(&spl_stake_pool::id(), stake_pool_address).0;
860-
let sol_deposit_authority = stake_pool
861-
.sol_deposit_authority
862-
.map_or("None".into(), |pubkey| pubkey.to_string());
863-
let sol_withdraw_authority = stake_pool
864-
.sol_withdraw_authority
865-
.map_or("None".into(), |pubkey| pubkey.to_string());
866-
867-
if config.verbose {
868-
println!("Stake Pool Info");
869-
println!("===============");
870-
println!("Stake Pool: {}", stake_pool_address);
871-
println!("Validator List: {}", stake_pool.validator_list);
872-
println!("Manager: {}", stake_pool.manager);
873-
println!("Staker: {}", stake_pool.staker);
874-
println!("Depositor: {}", stake_pool.stake_deposit_authority);
875-
println!("SOL Deposit Authority: {}", sol_deposit_authority);
876-
println!("SOL Withdraw Authority: {}", sol_withdraw_authority);
877-
println!("Withdraw Authority: {}", pool_withdraw_authority);
878-
println!("Pool Token Mint: {}", stake_pool.pool_mint);
879-
println!("Fee Account: {}", stake_pool.manager_fee_account);
880-
} else {
881-
println!("Stake Pool: {}", stake_pool_address);
882-
println!("Validator List: {}", stake_pool.validator_list);
883-
println!("Pool Token Mint: {}", stake_pool.pool_mint);
884-
}
885-
886-
if let Some(preferred_deposit_validator) = stake_pool.preferred_deposit_validator_vote_address {
887-
println!(
888-
"Preferred Deposit Validator: {}",
889-
preferred_deposit_validator
890-
);
891-
}
892-
if let Some(preferred_withdraw_validator) = stake_pool.preferred_withdraw_validator_vote_address
893-
{
894-
println!(
895-
"Preferred Withraw Validator: {}",
896-
preferred_withdraw_validator
897-
);
898-
}
899-
900-
// Display fees information
901-
println!("Epoch Fee: {} of epoch rewards", stake_pool.epoch_fee);
902-
println!(
903-
"Stake Withdrawal Fee: {} of withdrawal amount",
904-
stake_pool.stake_withdrawal_fee
905-
);
906-
println!(
907-
"SOL Withdrawal Fee: {} of withdrawal amount",
908-
stake_pool.sol_withdrawal_fee
909-
);
910-
println!(
911-
"Stake Deposit Fee: {} of deposit amount",
912-
stake_pool.stake_deposit_fee
913-
);
914-
println!(
915-
"SOL Deposit Fee: {} of deposit amount",
916-
stake_pool.sol_deposit_fee
917-
);
918-
println!(
919-
"Stake Deposit Referral Fee: {}% of Stake Deposit Fee",
920-
stake_pool.stake_referral_fee
921-
);
922-
println!(
923-
"SOL Deposit Referral Fee: {}% of SOL Deposit Fee",
924-
stake_pool.sol_referral_fee
925-
);
926-
927-
if config.verbose {
928-
println!();
929-
println!("Stake Accounts");
930-
println!("--------------");
931-
}
932871
let reserve_stake = config.rpc_client.get_account(&stake_pool.reserve_stake)?;
933872
let minimum_reserve_stake_balance = config
934873
.rpc_client
935874
.get_minimum_balance_for_rent_exemption(STAKE_STATE_LEN)?
936875
+ 1;
937-
println!(
938-
"Reserve Account: {}\tAvailable Balance: {}",
939-
stake_pool.reserve_stake,
940-
Sol(reserve_stake.lamports - minimum_reserve_stake_balance),
941-
);
942-
943-
for validator in &validator_list.validators {
944-
if config.verbose {
876+
let cli_stake_pool_stake_account_infos = validator_list
877+
.validators
878+
.iter()
879+
.map(|validator| {
945880
let (stake_account_address, _) = find_stake_program_address(
946881
&spl_stake_pool::id(),
947882
&validator.vote_account_address,
@@ -953,55 +888,42 @@ fn command_list(config: &Config, stake_pool_address: &Pubkey) -> CommandResult {
953888
stake_pool_address,
954889
validator.transient_seed_suffix_start,
955890
);
956-
println!(
957-
"Vote Account: {}\tStake Account: {}\tActive Balance: {}\tTransient Stake Account: {}\tTransient Balance: {}\tLast Update Epoch: {}{}",
958-
validator.vote_account_address,
959-
stake_account_address,
960-
Sol(validator.active_stake_lamports),
961-
transient_stake_account_address,
962-
Sol(validator.transient_stake_lamports),
963-
validator.last_update_epoch,
964-
if validator.last_update_epoch != epoch_info.epoch {
965-
" [UPDATE REQUIRED]"
966-
} else {
967-
""
968-
}
969-
);
970-
} else {
971-
println!(
972-
"Vote Account: {}\tBalance: {}\tLast Update Epoch: {}",
973-
validator.vote_account_address,
974-
Sol(validator.stake_lamports()),
975-
validator.last_update_epoch,
976-
);
977-
}
978-
}
979-
980-
if config.verbose {
981-
println!();
982-
}
983-
println!(
984-
"Total Pool Stake: {}{}",
985-
Sol(stake_pool.total_lamports),
986-
if stake_pool.last_update_epoch != epoch_info.epoch {
987-
" [UPDATE REQUIRED]"
988-
} else {
989-
""
990-
}
991-
);
992-
println!(
993-
"Total Pool Tokens: {}",
994-
spl_token::amount_to_ui_amount(stake_pool.pool_token_supply, pool_mint.decimals)
995-
);
996-
println!(
997-
"Current Number of Validators: {}",
998-
validator_list.validators.len()
999-
);
1000-
println!(
1001-
"Max Number of Validators: {}",
1002-
validator_list.header.max_validators
1003-
);
1004-
891+
let update_required = validator.last_update_epoch != epoch_info.epoch;
892+
CliStakePoolStakeAccountInfo {
893+
vote_account_address: stake_pool_address.to_string(),
894+
stake_account_address: stake_account_address.to_string(),
895+
validator_active_stake_lamports: validator.active_stake_lamports,
896+
validator_last_update_epoch: validator.last_update_epoch,
897+
validator_lamports: validator.stake_lamports(),
898+
validator_transient_stake_account_address: transient_stake_account_address
899+
.to_string(),
900+
validator_transient_stake_lamports: validator.transient_stake_lamports,
901+
update_required,
902+
}
903+
})
904+
.collect();
905+
let total_pool_tokens =
906+
spl_token::amount_to_ui_amount(stake_pool.pool_token_supply, pool_mint.decimals);
907+
let mut cli_stake_pool = CliStakePool::from((
908+
*stake_pool_address,
909+
stake_pool,
910+
validator_list,
911+
pool_withdraw_authority,
912+
));
913+
let update_required = last_update_epoch != epoch_info.epoch;
914+
let cli_stake_pool_details = CliStakePoolDetails {
915+
reserve_stake_account_address,
916+
reserve_stake_lamports: reserve_stake.lamports,
917+
minimum_reserve_stake_balance,
918+
stake_accounts: cli_stake_pool_stake_account_infos,
919+
total_lamports,
920+
total_pool_tokens,
921+
current_number_of_validators: current_number_of_validators as u32,
922+
max_number_of_validators,
923+
update_required,
924+
};
925+
cli_stake_pool.details = Some(cli_stake_pool_details);
926+
println!("{}", config.output_format.formatted_string(&cli_stake_pool));
1005927
Ok(())
1006928
}
1007929

@@ -1626,18 +1548,15 @@ fn command_set_fee(
16261548

16271549
fn command_list_all_pools(config: &Config) -> CommandResult {
16281550
let all_pools = get_stake_pools(&config.rpc_client)?;
1629-
let count = all_pools.len();
1630-
for (address, stake_pool, validator_list) in all_pools {
1631-
println!(
1632-
"Address: {}\tManager: {}\tLamports: {}\tPool tokens: {}\tValidators: {}",
1633-
address,
1634-
stake_pool.manager,
1635-
stake_pool.total_lamports,
1636-
stake_pool.pool_token_supply,
1637-
validator_list.validators.len()
1638-
);
1639-
}
1640-
println!("Total number of pools: {}", count);
1551+
let cli_stake_pool_vec: Vec<CliStakePool> =
1552+
all_pools.into_iter().map(CliStakePool::from).collect();
1553+
let cli_stake_pools = CliStakePools {
1554+
pools: cli_stake_pool_vec,
1555+
};
1556+
println!(
1557+
"{}",
1558+
config.output_format.formatted_string(&cli_stake_pools)
1559+
);
16411560
Ok(())
16421561
}
16431562

@@ -1670,6 +1589,15 @@ fn main() {
16701589
.global(true)
16711590
.help("Show additional information"),
16721591
)
1592+
.arg(
1593+
Arg::with_name("output_format")
1594+
.long("output")
1595+
.value_name("FORMAT")
1596+
.global(true)
1597+
.takes_value(true)
1598+
.possible_values(&["json", "json-compact"])
1599+
.help("Return information in specified output format"),
1600+
)
16731601
.arg(
16741602
Arg::with_name("dry_run")
16751603
.long("dry-run")
@@ -2477,12 +2405,25 @@ fn main() {
24772405
},
24782406
);
24792407
let verbose = matches.is_present("verbose");
2408+
let output_format = matches
2409+
.value_of("output_format")
2410+
.map(|value| match value {
2411+
"json" => OutputFormat::Json,
2412+
"json-compact" => OutputFormat::JsonCompact,
2413+
_ => unreachable!(),
2414+
})
2415+
.unwrap_or(if verbose {
2416+
OutputFormat::DisplayVerbose
2417+
} else {
2418+
OutputFormat::Display
2419+
});
24802420
let dry_run = matches.is_present("dry_run");
24812421
let no_update = matches.is_present("no_update");
24822422

24832423
Config {
24842424
rpc_client: RpcClient::new_with_commitment(json_rpc_url, CommitmentConfig::confirmed()),
24852425
verbose,
2426+
output_format,
24862427
manager,
24872428
staker,
24882429
funding_authority,

0 commit comments

Comments
 (0)