From ec9961cd7fd5f4811e563871b04a956a603d45b5 Mon Sep 17 00:00:00 2001 From: Trent Nelson Date: Thu, 24 Sep 2020 19:27:54 -0600 Subject: [PATCH] spl-token-cli: Add 'account-info' subcommand --- Cargo.lock | 77 +++++++++++++++++++++++++++------------- token/cli/Cargo.toml | 1 + token/cli/src/main.rs | 81 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 134 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 696e5ff4..0d4126c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -239,7 +239,7 @@ dependencies = [ "quote 1.0.7", "serde", "serde_json", - "syn 1.0.31", + "syn 1.0.41", "tempfile", "toml", ] @@ -454,7 +454,7 @@ checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f" dependencies = [ "proc-macro2 1.0.19", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.41", ] [[package]] @@ -565,7 +565,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" dependencies = [ "atty", - "humantime", + "humantime 1.3.0", "log", "regex", "termcolor", @@ -589,7 +589,7 @@ checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" dependencies = [ "proc-macro2 1.0.19", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.41", "synstructure", ] @@ -678,7 +678,7 @@ dependencies = [ "proc-macro-hack", "proc-macro2 1.0.19", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.41", ] [[package]] @@ -881,6 +881,12 @@ dependencies = [ "quick-error", ] +[[package]] +name = "humantime" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c1ad908cc71012b7bea4d0c53ba96a8cba9962f048fa68d143376143d863b7a" + [[package]] name = "hyper" version = "0.13.7" @@ -1249,7 +1255,7 @@ checksum = "6f09b9841adb6b5e1f89ef7087ea636e0fd94b2851f887c1e3eb5d5f8228fab3" dependencies = [ "proc-macro2 1.0.19", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.41", ] [[package]] @@ -1300,7 +1306,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2 1.0.19", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.41", ] [[package]] @@ -1452,7 +1458,7 @@ checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f" dependencies = [ "proc-macro2 1.0.19", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.41", ] [[package]] @@ -1768,7 +1774,7 @@ checksum = "b9bdc5e856e51e685846fb6c13a1f5e5432946c2c90501bdc76a1319f19e29da" dependencies = [ "proc-macro2 1.0.19", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.41", ] [[package]] @@ -1843,9 +1849,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.112" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736aac72d1eafe8e5962d1d1c3d99b0df526015ba40915cb3c49d042e92ec243" +checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" dependencies = [ "serde_derive", ] @@ -1861,13 +1867,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.112" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf0343ce212ac0d3d6afd9391ac8e9c9efe06b533c8d33f660f6390cc4093f57" +checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" dependencies = [ "proc-macro2 1.0.19", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.41", ] [[package]] @@ -2033,6 +2039,28 @@ dependencies = [ "url", ] +[[package]] +name = "solana-cli-output" +version = "1.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed68c386972c9765bd94b472672d83f1f61a8e35e4ead9f0a0bc0f52b1f8923" +dependencies = [ + "Inflector", + "chrono", + "console 0.11.3", + "humantime 2.0.1", + "indicatif", + "serde", + "serde_derive", + "serde_json", + "solana-clap-utils", + "solana-client", + "solana-sdk", + "solana-stake-program", + "solana-transaction-status", + "solana-vote-program", +] + [[package]] name = "solana-client" version = "1.3.13" @@ -2095,7 +2123,7 @@ dependencies = [ "reqwest", "serde", "syn 0.15.44", - "syn 1.0.31", + "syn 1.0.41", "tokio 0.1.22", "winapi 0.3.9", ] @@ -2220,7 +2248,7 @@ dependencies = [ "proc-macro2 1.0.19", "quote 1.0.7", "rustversion", - "syn 1.0.31", + "syn 1.0.41", ] [[package]] @@ -2233,7 +2261,7 @@ dependencies = [ "proc-macro2 1.0.19", "quote 1.0.7", "rustc_version", - "syn 1.0.31", + "syn 1.0.41", ] [[package]] @@ -2376,6 +2404,7 @@ dependencies = [ "solana-account-decoder", "solana-clap-utils", "solana-cli-config", + "solana-cli-output", "solana-client", "solana-logger", "solana-sdk", @@ -2441,9 +2470,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.31" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6" +checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b" dependencies = [ "proc-macro2 1.0.19", "quote 1.0.7", @@ -2458,7 +2487,7 @@ checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" dependencies = [ "proc-macro2 1.0.19", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.41", "unicode-xid 0.2.0", ] @@ -2541,7 +2570,7 @@ checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793" dependencies = [ "proc-macro2 1.0.19", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.41", ] [[package]] @@ -3015,7 +3044,7 @@ dependencies = [ "log", "proc-macro2 1.0.19", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.41", "wasm-bindgen-shared", ] @@ -3049,7 +3078,7 @@ checksum = "841a6d1c35c6f596ccea1f82504a192a60378f64b3bb0261904ad8f2f5657556" dependencies = [ "proc-macro2 1.0.19", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.41", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3177,6 +3206,6 @@ checksum = "de251eec69fc7c1bc3923403d18ececb929380e016afe103da75f396704f8ca2" dependencies = [ "proc-macro2 1.0.19", "quote 1.0.7", - "syn 1.0.31", + "syn 1.0.41", "synstructure", ] diff --git a/token/cli/Cargo.toml b/token/cli/Cargo.toml index 406b438f..6a1f0e46 100644 --- a/token/cli/Cargo.toml +++ b/token/cli/Cargo.toml @@ -15,6 +15,7 @@ serde_json = "1.0.57" solana-account-decoder = { version = "=1.3.13" } solana-clap-utils = { version = "=1.3.13"} solana-cli-config = { version = "=1.3.13" } +solana-cli-output = { version = "=1.3.13" } solana-client = { version = "=1.3.13" } solana-logger = { version = "=1.3.13" } solana-sdk = { version = "=1.3.13" } diff --git a/token/cli/src/main.rs b/token/cli/src/main.rs index d551a2e4..b7612ae1 100644 --- a/token/cli/src/main.rs +++ b/token/cli/src/main.rs @@ -4,7 +4,7 @@ use clap::{ }; use console::Emoji; use solana_account_decoder::{ - parse_token::{TokenAccountType, UiAccountState}, + parse_token::{TokenAccountType, UiAccountState, UiTokenAmount}, UiAccountData, }; use solana_clap_utils::{ @@ -12,6 +12,7 @@ use solana_clap_utils::{ input_validators::{is_amount, is_keypair, is_pubkey_or_keypair, is_url}, keypair::signer_from_path, }; +use solana_cli_output::display::println_name_value; use solana_client::{rpc_client::RpcClient, rpc_request::TokenAccountsFilter}; use solana_sdk::{ commitment_config::CommitmentConfig, @@ -546,6 +547,67 @@ fn command_accounts(config: &Config, token: Option) -> CommandResult { Ok(None) } +fn stringify_ui_token_amount(amount: &UiTokenAmount) -> String { + let decimals = amount.decimals as usize; + if decimals > 0 { + let amount = u64::from_str(&amount.amount).unwrap(); + + // Left-pad zeros to decimals + 1, so we at least have an integer zero + let mut s = format!("{:01$}", amount, decimals + 1); + + // Add the decimal point (Sorry, "," locales!) + s.insert(s.len() - decimals, '.'); + s + } else { + amount.amount.clone() + } +} + +fn stringify_ui_token_amount_trimmed(amount: &UiTokenAmount) -> String { + let s = stringify_ui_token_amount(amount); + let zeros_trimmed = s.trim_end_matches('0'); + let decimal_trimmed = zeros_trimmed.trim_end_matches('.'); + decimal_trimmed.to_string() +} + +fn command_account(config: &Config, address: Pubkey) -> CommandResult { + let account = config + .rpc_client + .get_token_account_with_commitment(&address, config.commitment_config)? + .value + .unwrap(); + println!(); + println_name_value("Address:", &address.to_string()); + println_name_value( + "Balance:", + &stringify_ui_token_amount_trimmed(&account.token_amount), + ); + let mint = format!( + "{}{}", + account.mint, + if account.is_native { " (native)" } else { "" } + ); + println_name_value("Mint:", &mint); + println_name_value("Owner:", &account.owner); + println_name_value("State:", &format!("{:?}", account.state)); + if let Some(delegate) = &account.delegate { + println!("Delegation:"); + println_name_value(" Delegate:", delegate); + let allowance = account.delegated_amount.as_ref().unwrap(); + println_name_value( + " Allowance:", + &stringify_ui_token_amount_trimmed(&allowance), + ); + } else { + println_name_value("Delegation:", ""); + } + println_name_value( + "Close authority:", + &account.close_authority.as_ref().unwrap_or(&String::new()), + ); + Ok(None) +} + fn main() { let default_decimals = &format!("{}", native_mint::DECIMALS); let matches = App::new(crate_name!()) @@ -864,6 +926,19 @@ fn main() { .help("The address of the token account to unwrap"), ), ) + .subcommand( + SubCommand::with_name("account-info") + .about("Query details of an SPL Token account by address") + .arg( + Arg::with_name("address") + .validator(is_pubkey_or_keypair) + .value_name("TOKEN_ACCOUNT_ADDRESS") + .takes_value(true) + .index(1) + .required(true) + .help("The address of the SPL Token account to query"), + ), + ) .get_matches(); let mut wallet_manager = None; @@ -1010,6 +1085,10 @@ fn main() { let token = pubkey_of(arg_matches, "token"); command_accounts(&config, token) } + ("account-info", Some(arg_matches)) => { + let address = pubkey_of(arg_matches, "address").unwrap(); + command_account(&config, address) + } _ => unreachable!(), } .and_then(|transaction| {