2021-07-28 18:43:32 +03:00
|
|
|
use clap::{crate_description, crate_name, value_t_or_exit, ArgMatches};
|
2019-08-07 13:17:11 -06:00
|
|
|
use console::style;
|
2020-03-13 00:20:49 -06:00
|
|
|
use solana_clap_utils::{
|
2021-07-28 18:43:32 +03:00
|
|
|
input_validators::normalize_to_url_if_moniker,
|
|
|
|
keypair::{CliSigners, DefaultSigner},
|
2020-09-22 15:25:10 -06:00
|
|
|
DisplayError,
|
2020-03-13 00:20:49 -06:00
|
|
|
};
|
2021-07-28 18:43:32 +03:00
|
|
|
use solana_cli::{
|
|
|
|
clap_app::get_clap_app,
|
|
|
|
cli::{parse_command, process_command, CliCommandInfo, CliConfig, SettingType},
|
2019-09-03 10:38:12 -07:00
|
|
|
};
|
2021-07-28 18:43:32 +03:00
|
|
|
use solana_cli_config::Config;
|
2020-09-22 18:29:11 -06:00
|
|
|
use solana_cli_output::{display::println_name_value, OutputFormat};
|
2020-06-17 12:18:48 -06:00
|
|
|
use solana_client::rpc_config::RpcSendTransactionConfig;
|
2020-04-18 12:54:21 -06:00
|
|
|
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
2020-07-23 09:21:59 -06:00
|
|
|
use std::{collections::HashMap, error, path::PathBuf, sync::Arc, time::Duration};
|
2018-06-29 11:38:00 -06:00
|
|
|
|
2020-09-22 18:29:11 -06:00
|
|
|
pub fn println_name_value_or(name: &str, value: &str, setting_type: SettingType) {
|
|
|
|
let description = match setting_type {
|
|
|
|
SettingType::Explicit => "",
|
|
|
|
SettingType::Computed => "(computed)",
|
|
|
|
SettingType::SystemDefault => "(default)",
|
|
|
|
};
|
|
|
|
|
|
|
|
println!(
|
|
|
|
"{} {} {}",
|
|
|
|
style(name).bold(),
|
|
|
|
style(value),
|
|
|
|
style(description).italic(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-04-18 12:54:21 -06:00
|
|
|
fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error>> {
|
2019-08-07 13:17:11 -06:00
|
|
|
let parse_args = match matches.subcommand() {
|
2020-06-17 23:09:33 -07:00
|
|
|
("config", Some(matches)) => {
|
|
|
|
let config_file = match matches.value_of("config_file") {
|
|
|
|
None => {
|
|
|
|
println!(
|
|
|
|
"{} Either provide the `--config` arg or ensure home directory exists to use the default config location",
|
|
|
|
style("No config file found.").bold()
|
|
|
|
);
|
|
|
|
return Ok(false);
|
|
|
|
}
|
|
|
|
Some(config_file) => config_file,
|
|
|
|
};
|
|
|
|
let mut config = Config::load(config_file).unwrap_or_default();
|
2020-02-29 11:39:07 -05:00
|
|
|
|
2020-06-17 23:09:33 -07:00
|
|
|
match matches.subcommand() {
|
|
|
|
("get", Some(subcommand_matches)) => {
|
2020-02-29 11:39:07 -05:00
|
|
|
let (url_setting_type, json_rpc_url) =
|
2020-03-09 12:14:17 -07:00
|
|
|
CliConfig::compute_json_rpc_url_setting("", &config.json_rpc_url);
|
2020-02-29 11:39:07 -05:00
|
|
|
let (ws_setting_type, websocket_url) = CliConfig::compute_websocket_url_setting(
|
|
|
|
"",
|
|
|
|
&config.websocket_url,
|
|
|
|
"",
|
2020-03-09 12:14:17 -07:00
|
|
|
&config.json_rpc_url,
|
2020-02-29 11:39:07 -05:00
|
|
|
);
|
|
|
|
let (keypair_setting_type, keypair_path) =
|
|
|
|
CliConfig::compute_keypair_path_setting("", &config.keypair_path);
|
2021-01-20 09:48:10 -07:00
|
|
|
let (commitment_setting_type, commitment) =
|
|
|
|
CliConfig::compute_commitment_config("", &config.commitment);
|
2020-02-29 11:39:07 -05:00
|
|
|
|
2020-01-20 23:06:47 -07:00
|
|
|
if let Some(field) = subcommand_matches.value_of("specific_setting") {
|
2020-02-29 11:39:07 -05:00
|
|
|
let (field_name, value, setting_type) = match field {
|
|
|
|
"json_rpc_url" => ("RPC URL", json_rpc_url, url_setting_type),
|
2020-03-16 09:24:59 -06:00
|
|
|
"websocket_url" => ("WebSocket URL", websocket_url, ws_setting_type),
|
2020-02-29 11:39:07 -05:00
|
|
|
"keypair" => ("Key Path", keypair_path, keypair_setting_type),
|
2021-01-20 09:48:10 -07:00
|
|
|
"commitment" => (
|
|
|
|
"Commitment",
|
|
|
|
commitment.commitment.to_string(),
|
|
|
|
commitment_setting_type,
|
|
|
|
),
|
2020-01-20 23:06:47 -07:00
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
2020-02-29 11:39:07 -05:00
|
|
|
println_name_value_or(&format!("{}:", field_name), &value, setting_type);
|
2020-01-20 23:06:47 -07:00
|
|
|
} else {
|
2020-02-05 11:14:44 -07:00
|
|
|
println_name_value("Config File:", config_file);
|
2020-02-29 11:39:07 -05:00
|
|
|
println_name_value_or("RPC URL:", &json_rpc_url, url_setting_type);
|
2020-03-16 09:24:59 -06:00
|
|
|
println_name_value_or("WebSocket URL:", &websocket_url, ws_setting_type);
|
2020-02-29 11:39:07 -05:00
|
|
|
println_name_value_or("Keypair Path:", &keypair_path, keypair_setting_type);
|
2021-01-20 09:48:10 -07:00
|
|
|
println_name_value_or(
|
|
|
|
"Commitment:",
|
|
|
|
&commitment.commitment.to_string(),
|
|
|
|
commitment_setting_type,
|
|
|
|
);
|
2020-01-20 23:06:47 -07:00
|
|
|
}
|
2019-08-07 13:17:11 -06:00
|
|
|
}
|
2020-06-17 23:09:33 -07:00
|
|
|
("set", Some(subcommand_matches)) => {
|
2020-01-20 23:06:47 -07:00
|
|
|
if let Some(url) = subcommand_matches.value_of("json_rpc_url") {
|
2021-02-03 00:33:02 -07:00
|
|
|
config.json_rpc_url = normalize_to_url_if_moniker(url);
|
2020-03-10 14:09:59 -07:00
|
|
|
// Revert to a computed `websocket_url` value when `json_rpc_url` is
|
|
|
|
// changed
|
|
|
|
config.websocket_url = "".to_string();
|
2020-01-20 23:06:47 -07:00
|
|
|
}
|
2020-02-29 11:39:07 -05:00
|
|
|
if let Some(url) = subcommand_matches.value_of("websocket_url") {
|
|
|
|
config.websocket_url = url.to_string();
|
|
|
|
}
|
2020-01-20 23:06:47 -07:00
|
|
|
if let Some(keypair) = subcommand_matches.value_of("keypair") {
|
|
|
|
config.keypair_path = keypair.to_string();
|
|
|
|
}
|
2021-01-20 09:48:10 -07:00
|
|
|
if let Some(commitment) = subcommand_matches.value_of("commitment") {
|
|
|
|
config.commitment = commitment.to_string();
|
|
|
|
}
|
2020-06-17 23:09:33 -07:00
|
|
|
|
2020-01-20 23:06:47 -07:00
|
|
|
config.save(config_file)?;
|
2020-02-29 11:39:07 -05:00
|
|
|
|
|
|
|
let (url_setting_type, json_rpc_url) =
|
2020-03-09 12:14:17 -07:00
|
|
|
CliConfig::compute_json_rpc_url_setting("", &config.json_rpc_url);
|
2020-02-29 11:39:07 -05:00
|
|
|
let (ws_setting_type, websocket_url) = CliConfig::compute_websocket_url_setting(
|
|
|
|
"",
|
|
|
|
&config.websocket_url,
|
|
|
|
"",
|
2020-03-09 12:14:17 -07:00
|
|
|
&config.json_rpc_url,
|
2020-02-29 11:39:07 -05:00
|
|
|
);
|
|
|
|
let (keypair_setting_type, keypair_path) =
|
|
|
|
CliConfig::compute_keypair_path_setting("", &config.keypair_path);
|
2021-01-20 09:48:10 -07:00
|
|
|
let (commitment_setting_type, commitment) =
|
|
|
|
CliConfig::compute_commitment_config("", &config.commitment);
|
2020-02-29 11:39:07 -05:00
|
|
|
|
2020-02-05 11:14:44 -07:00
|
|
|
println_name_value("Config File:", config_file);
|
2020-02-29 11:39:07 -05:00
|
|
|
println_name_value_or("RPC URL:", &json_rpc_url, url_setting_type);
|
2020-03-16 09:24:59 -06:00
|
|
|
println_name_value_or("WebSocket URL:", &websocket_url, ws_setting_type);
|
2020-02-29 11:39:07 -05:00
|
|
|
println_name_value_or("Keypair Path:", &keypair_path, keypair_setting_type);
|
2021-01-20 09:48:10 -07:00
|
|
|
println_name_value_or(
|
|
|
|
"Commitment:",
|
|
|
|
&commitment.commitment.to_string(),
|
|
|
|
commitment_setting_type,
|
|
|
|
);
|
2019-08-07 13:17:11 -06:00
|
|
|
}
|
2020-06-17 23:09:33 -07:00
|
|
|
("import-address-labels", Some(subcommand_matches)) => {
|
|
|
|
let filename = value_t_or_exit!(subcommand_matches, "filename", PathBuf);
|
|
|
|
config.import_address_labels(&filename)?;
|
|
|
|
config.save(config_file)?;
|
|
|
|
println!("Address labels imported from {:?}", filename);
|
|
|
|
}
|
|
|
|
("export-address-labels", Some(subcommand_matches)) => {
|
|
|
|
let filename = value_t_or_exit!(subcommand_matches, "filename", PathBuf);
|
|
|
|
config.export_address_labels(&filename)?;
|
|
|
|
println!("Address labels exported to {:?}", filename);
|
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
2019-08-07 13:17:11 -06:00
|
|
|
}
|
2020-06-17 23:09:33 -07:00
|
|
|
false
|
|
|
|
}
|
2020-04-18 12:54:21 -06:00
|
|
|
_ => true,
|
2019-08-07 13:17:11 -06:00
|
|
|
};
|
|
|
|
Ok(parse_args)
|
|
|
|
}
|
|
|
|
|
2020-02-24 17:03:30 -07:00
|
|
|
pub fn parse_args<'a>(
|
|
|
|
matches: &ArgMatches<'_>,
|
2020-04-18 12:54:21 -06:00
|
|
|
mut wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
2020-02-24 17:03:30 -07:00
|
|
|
) -> Result<(CliConfig<'a>, CliSigners), Box<dyn error::Error>> {
|
2019-08-07 13:17:11 -06:00
|
|
|
let config = if let Some(config_file) = matches.value_of("config_file") {
|
|
|
|
Config::load(config_file).unwrap_or_default()
|
|
|
|
} else {
|
|
|
|
Config::default()
|
|
|
|
};
|
2020-02-29 11:39:07 -05:00
|
|
|
let (_, json_rpc_url) = CliConfig::compute_json_rpc_url_setting(
|
|
|
|
matches.value_of("json_rpc_url").unwrap_or(""),
|
2020-03-09 12:14:17 -07:00
|
|
|
&config.json_rpc_url,
|
2020-02-29 11:39:07 -05:00
|
|
|
);
|
2020-07-23 09:21:59 -06:00
|
|
|
|
|
|
|
let rpc_timeout = value_t_or_exit!(matches, "rpc_timeout", u64);
|
|
|
|
let rpc_timeout = Duration::from_secs(rpc_timeout);
|
|
|
|
|
2021-06-29 19:08:45 -06:00
|
|
|
let confirm_transaction_initial_timeout =
|
|
|
|
value_t_or_exit!(matches, "confirm_transaction_initial_timeout", u64);
|
|
|
|
let confirm_transaction_initial_timeout =
|
|
|
|
Duration::from_secs(confirm_transaction_initial_timeout);
|
|
|
|
|
2020-02-29 11:39:07 -05:00
|
|
|
let (_, websocket_url) = CliConfig::compute_websocket_url_setting(
|
|
|
|
matches.value_of("websocket_url").unwrap_or(""),
|
|
|
|
&config.websocket_url,
|
|
|
|
matches.value_of("json_rpc_url").unwrap_or(""),
|
2020-03-09 12:14:17 -07:00
|
|
|
&config.json_rpc_url,
|
2020-02-29 11:39:07 -05:00
|
|
|
);
|
2021-05-27 18:04:48 -06:00
|
|
|
let default_signer_arg_name = "keypair".to_string();
|
2020-02-29 11:39:07 -05:00
|
|
|
let (_, default_signer_path) = CliConfig::compute_keypair_path_setting(
|
2021-05-27 18:04:48 -06:00
|
|
|
matches.value_of(&default_signer_arg_name).unwrap_or(""),
|
2020-02-29 11:39:07 -05:00
|
|
|
&config.keypair_path,
|
|
|
|
);
|
2018-09-14 02:58:39 -06:00
|
|
|
|
2021-05-28 01:42:55 -06:00
|
|
|
let default_signer = DefaultSigner::new(default_signer_arg_name, &default_signer_path);
|
2020-09-21 21:53:15 -06:00
|
|
|
|
2021-01-21 23:31:33 -07:00
|
|
|
let CliCommandInfo {
|
|
|
|
command,
|
|
|
|
mut signers,
|
2021-06-18 15:34:46 +02:00
|
|
|
} = parse_command(matches, &default_signer, &mut wallet_manager)?;
|
2021-01-21 23:31:33 -07:00
|
|
|
|
|
|
|
if signers.is_empty() {
|
|
|
|
if let Ok(signer_info) =
|
|
|
|
default_signer.generate_unique_signers(vec![None], matches, &mut wallet_manager)
|
|
|
|
{
|
|
|
|
signers.extend(signer_info.signers);
|
|
|
|
}
|
|
|
|
}
|
2020-02-24 17:03:30 -07:00
|
|
|
|
2020-12-02 15:02:52 -07:00
|
|
|
let verbose = matches.is_present("verbose");
|
2021-07-27 22:21:23 -06:00
|
|
|
let output_format = OutputFormat::from_matches(matches, "output_format", verbose);
|
2020-04-14 13:10:25 -06:00
|
|
|
|
2021-01-20 09:48:10 -07:00
|
|
|
let (_, commitment) = CliConfig::compute_commitment_config(
|
|
|
|
matches.value_of("commitment").unwrap_or(""),
|
|
|
|
&config.commitment,
|
|
|
|
);
|
2020-06-17 12:18:48 -06:00
|
|
|
|
2020-06-17 23:09:33 -07:00
|
|
|
let address_labels = if matches.is_present("no_address_labels") {
|
|
|
|
HashMap::new()
|
|
|
|
} else {
|
|
|
|
config.address_labels
|
|
|
|
};
|
|
|
|
|
2020-02-24 17:03:30 -07:00
|
|
|
Ok((
|
|
|
|
CliConfig {
|
|
|
|
command,
|
|
|
|
json_rpc_url,
|
2020-02-29 11:39:07 -05:00
|
|
|
websocket_url,
|
2020-02-24 17:03:30 -07:00
|
|
|
signers: vec![],
|
|
|
|
keypair_path: default_signer_path,
|
|
|
|
rpc_client: None,
|
2020-07-23 09:21:59 -06:00
|
|
|
rpc_timeout,
|
2020-12-02 15:02:52 -07:00
|
|
|
verbose,
|
2020-04-14 13:10:25 -06:00
|
|
|
output_format,
|
2020-06-17 12:18:48 -06:00
|
|
|
commitment,
|
2020-12-15 17:29:35 -08:00
|
|
|
send_transaction_config: RpcSendTransactionConfig {
|
|
|
|
preflight_commitment: Some(commitment.commitment),
|
|
|
|
..RpcSendTransactionConfig::default()
|
|
|
|
},
|
2021-06-29 19:08:45 -06:00
|
|
|
confirm_transaction_initial_timeout,
|
2020-06-17 23:09:33 -07:00
|
|
|
address_labels,
|
2020-02-24 17:03:30 -07:00
|
|
|
},
|
|
|
|
signers,
|
|
|
|
))
|
2018-06-29 11:38:00 -06:00
|
|
|
}
|
|
|
|
|
2018-12-08 22:44:20 -07:00
|
|
|
fn main() -> Result<(), Box<dyn error::Error>> {
|
2021-01-22 18:20:58 -07:00
|
|
|
solana_logger::setup_with_default("off");
|
2021-07-28 18:43:32 +03:00
|
|
|
let matches = get_clap_app(
|
2019-11-14 13:10:38 +09:00
|
|
|
crate_name!(),
|
|
|
|
crate_description!(),
|
2020-05-11 15:02:01 -07:00
|
|
|
solana_version::version!(),
|
2019-11-14 13:10:38 +09:00
|
|
|
)
|
|
|
|
.get_matches();
|
2018-06-26 23:52:34 -06:00
|
|
|
|
2020-04-18 12:54:21 -06:00
|
|
|
do_main(&matches).map_err(|err| DisplayError::new_as_boxed(err).into())
|
2020-03-13 00:20:49 -06:00
|
|
|
}
|
|
|
|
|
2020-04-18 12:54:21 -06:00
|
|
|
fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
|
2021-06-18 15:34:46 +02:00
|
|
|
if parse_settings(matches)? {
|
2020-04-18 12:54:21 -06:00
|
|
|
let mut wallet_manager = None;
|
2020-02-24 17:03:30 -07:00
|
|
|
|
2021-06-18 15:34:46 +02:00
|
|
|
let (mut config, signers) = parse_args(matches, &mut wallet_manager)?;
|
2020-02-24 17:03:30 -07:00
|
|
|
config.signers = signers.iter().map(|s| s.as_ref()).collect();
|
2019-08-07 13:17:11 -06:00
|
|
|
let result = process_command(&config)?;
|
2020-05-07 07:21:48 +03:00
|
|
|
println!("{}", result);
|
2020-03-13 00:20:49 -06:00
|
|
|
};
|
2018-09-17 13:15:26 -06:00
|
|
|
Ok(())
|
2018-06-29 11:38:00 -06:00
|
|
|
}
|