solana/wallet/src/main.rs

407 lines
14 KiB
Rust
Raw Normal View History

use clap::{
crate_description, crate_name, crate_version, App, AppSettings, Arg, ArgMatches, SubCommand,
};
2019-03-20 15:20:31 -07:00
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{gen_keypair_file, read_keypair, KeypairUtil};
use solana_wallet::wallet::{parse_command, process_command, WalletConfig, WalletError};
use std::error;
pub fn parse_args(matches: &ArgMatches<'_>) -> Result<WalletConfig, Box<dyn error::Error>> {
2019-04-13 19:34:27 -07:00
let host = solana_netutil::parse_host(matches.value_of("host").unwrap()).or_else(|err| {
Err(WalletError::BadParameter(format!(
"Invalid host: {:?}",
err
)))
})?;
let drone_host = if let Some(drone_host) = matches.value_of("drone_host") {
2019-04-13 19:34:27 -07:00
Some(solana_netutil::parse_host(drone_host).or_else(|err| {
Err(WalletError::BadParameter(format!(
"Invalid drone host: {:?}",
err
)))
})?)
} else {
None
};
let rpc_host = if let Some(rpc_host) = matches.value_of("rpc_host") {
2019-04-13 19:34:27 -07:00
Some(solana_netutil::parse_host(rpc_host).or_else(|err| {
Err(WalletError::BadParameter(format!(
"Invalid rpc host: {:?}",
err
)))
})?)
} else {
None
};
let drone_port = matches
.value_of("drone_port")
.unwrap()
.parse()
2019-04-13 19:34:27 -07:00
.or_else(|err| {
Err(WalletError::BadParameter(format!(
"Invalid drone port: {:?}",
err
)))
})?;
let rpc_port = matches
.value_of("rpc_port")
.unwrap()
.parse()
2019-04-13 19:34:27 -07:00
.or_else(|err| {
Err(WalletError::BadParameter(format!(
"Invalid rpc port: {:?}",
err
)))
})?;
2018-11-09 14:10:44 -08:00
let mut path = dirs::home_dir().expect("home directory");
let id_path = if matches.is_present("keypair") {
matches.value_of("keypair").unwrap()
} else {
path.extend(&[".config", "solana", "id.json"]);
if !path.exists() {
gen_keypair_file(path.to_str().unwrap().to_string())?;
println!("New keypair generated at: {:?}", path.to_str().unwrap());
}
path.to_str().unwrap()
};
2019-04-02 06:08:11 -07:00
let keypair = read_keypair(id_path).or_else(|err| {
Err(WalletError::BadParameter(format!(
"{}: Unable to open keypair file: {}",
err, id_path
)))
})?;
2019-04-02 06:08:11 -07:00
let command = parse_command(&keypair.pubkey(), &matches)?;
Ok(WalletConfig {
2019-04-02 06:08:11 -07:00
keypair,
command,
drone_host,
drone_port,
host,
rpc_client: None,
rpc_host,
rpc_port,
rpc_tls: matches.is_present("rpc_tls"),
})
}
2019-03-20 15:20:31 -07:00
// Return an error if a pubkey cannot be parsed.
fn is_pubkey(string: String) -> Result<(), String> {
match string.parse::<Pubkey>() {
Ok(_) => Ok(()),
Err(err) => Err(format!("{:?}", err)),
}
}
fn main() -> Result<(), Box<dyn error::Error>> {
solana_logger::setup();
let (default_host, default_rpc_port, default_drone_port) = {
let defaults = WalletConfig::default();
(
defaults.host.to_string(),
defaults.rpc_port.to_string(),
defaults.drone_port.to_string(),
)
};
let matches = App::new(crate_name!())
.about(crate_description!())
.version(crate_version!())
.setting(AppSettings::ArgRequiredElseHelp)
.arg(
Arg::with_name("host")
2018-09-14 17:12:10 -07:00
.short("n")
.long("host")
.value_name("IP ADDRESS")
.takes_value(true)
.default_value(&default_host)
.help("Host to use for both RPC and drone"),
)
.arg(
Arg::with_name("rpc_host")
.long("rpc-host")
.value_name("IP ADDRESS")
.takes_value(true)
.help("RPC host to use [default: same as --host]"),
)
.arg(
Arg::with_name("rpc_port")
.long("rpc-port")
.value_name("PORT")
.takes_value(true)
.default_value(&default_rpc_port)
.help("RPC port to use"),
)
.arg(
Arg::with_name("rpc_tps")
.long("rpc-tls")
.help("Enable TLS for the RPC endpoint"),
)
.arg(
Arg::with_name("drone_host")
.long("drone-host")
.value_name("IP ADDRESS")
.takes_value(true)
.help("Drone host to use [default: same as --host]"),
)
.arg(
Arg::with_name("drone_port")
.long("drone-port")
.value_name("PORT")
.takes_value(true)
.default_value(&default_drone_port)
.help("Drone port to use"),
)
.arg(
2018-07-12 15:02:14 -07:00
Arg::with_name("keypair")
.short("k")
.long("keypair")
.value_name("PATH")
.takes_value(true)
2018-07-12 15:02:14 -07:00
.help("/path/to/id.json"),
)
.subcommand(SubCommand::with_name("address").about("Get your public key"))
.subcommand(
SubCommand::with_name("airdrop")
2019-03-05 17:22:46 -08:00
.about("Request a batch of lamports")
.arg(
2019-03-05 17:22:46 -08:00
Arg::with_name("lamports")
.index(1)
2018-09-14 15:32:57 -07:00
.value_name("NUM")
.takes_value(true)
.required(true)
2019-03-05 17:22:46 -08:00
.help("The number of lamports to request"),
),
)
2019-03-20 09:44:16 -07:00
.subcommand(
SubCommand::with_name("balance")
.about("Get your balance")
.arg(
Arg::with_name("pubkey")
.index(1)
.value_name("PUBKEY")
.takes_value(true)
.validator(is_pubkey)
.help("The public key of the balance to check"),
),
)
.subcommand(
SubCommand::with_name("cancel")
.about("Cancel a transfer")
.arg(
2019-03-07 16:00:12 -08:00
Arg::with_name("process_id")
.index(1)
.value_name("PROCESS_ID")
.takes_value(true)
.required(true)
2019-03-20 15:20:31 -07:00
.validator(is_pubkey)
.help("The process id of the transfer to cancel"),
),
)
.subcommand(
SubCommand::with_name("confirm")
.about("Confirm transaction by signature")
.arg(
Arg::with_name("signature")
.index(1)
.value_name("SIGNATURE")
.takes_value(true)
.required(true)
.help("The transaction signature to confirm"),
),
)
2019-03-06 17:02:20 -08:00
.subcommand(
SubCommand::with_name("authorize-voter")
.about("Authorize a different voter for this account")
2019-03-06 17:02:20 -08:00
.arg(
Arg::with_name("authorized-voter-id")
.index(1)
2019-03-06 17:02:20 -08:00
.value_name("PUBKEY")
.takes_value(true)
.required(true)
2019-03-20 15:20:31 -07:00
.validator(is_pubkey)
2019-03-06 17:02:20 -08:00
.help("Vote signer to authorize"),
),
)
.subcommand(
SubCommand::with_name("create-vote-account")
2019-03-06 17:02:20 -08:00
.about("Create staking account for node")
.arg(
2019-03-07 16:00:12 -08:00
Arg::with_name("voting_account_id")
2019-03-06 17:02:20 -08:00
.index(1)
.value_name("PUBKEY")
.takes_value(true)
.required(true)
2019-03-20 15:20:31 -07:00
.validator(is_pubkey)
2019-03-06 17:02:20 -08:00
.help("Staking account address to fund"),
)
.arg(
Arg::with_name("node_id")
2019-03-06 17:02:20 -08:00
.index(2)
.value_name("PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey)
.help("Staking account address to fund"),
)
.arg(
Arg::with_name("lamports")
.index(3)
2019-03-06 17:02:20 -08:00
.value_name("NUM")
.takes_value(true)
.required(true)
.help("The number of lamports to send to staking account"),
)
.arg(
Arg::with_name("commission")
.value_name("NUM")
.takes_value(true)
.help("The commission on rewards this vote account should take, defaults to zero")
2019-03-06 17:02:20 -08:00
),
2019-03-06 17:02:20 -08:00
)
2019-04-17 07:45:07 -07:00
.subcommand(
SubCommand::with_name("show-vote-account")
.about("Show the contents of a vote account")
.arg(
Arg::with_name("voting_account_id")
.index(1)
.value_name("PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey)
.help("Vote account pubkey"),
)
)
.subcommand(
2018-10-22 21:21:33 -07:00
SubCommand::with_name("deploy")
.about("Deploy a program")
.arg(
2019-03-07 16:00:12 -08:00
Arg::with_name("program_location")
2018-10-22 21:21:33 -07:00
.index(1)
.value_name("PATH")
.takes_value(true)
.required(true)
.help("/path/to/program.o"),
), // TODO: Add "loader" argument; current default is bpf_loader
)
.subcommand(
SubCommand::with_name("get-transaction-count").about("Get current transaction count"),
)
.subcommand(
SubCommand::with_name("pay")
.about("Send a payment")
.arg(
Arg::with_name("to")
.index(1)
.value_name("PUBKEY")
.takes_value(true)
.required(true)
2019-03-20 15:20:31 -07:00
.validator(is_pubkey)
.help("The pubkey of recipient"),
)
.arg(
2019-03-05 17:22:46 -08:00
Arg::with_name("lamports")
.index(2)
2018-09-14 15:32:57 -07:00
.value_name("NUM")
.takes_value(true)
.required(true)
2019-03-05 17:22:46 -08:00
.help("The number of lamports to send"),
)
.arg(
Arg::with_name("timestamp")
.long("after")
.value_name("DATETIME")
.takes_value(true)
.help("A timestamp after which transaction will execute"),
)
.arg(
2019-03-07 16:00:12 -08:00
Arg::with_name("timestamp_pubkey")
.long("require-timestamp-from")
.value_name("PUBKEY")
.takes_value(true)
.requires("timestamp")
2019-03-20 15:20:31 -07:00
.validator(is_pubkey)
.help("Require timestamp from this third party"),
)
.arg(
Arg::with_name("witness")
.long("require-signature-from")
.value_name("PUBKEY")
.takes_value(true)
.multiple(true)
.use_delimiter(true)
2019-03-20 15:20:31 -07:00
.validator(is_pubkey)
2019-03-05 17:22:46 -08:00
.help("Any third party signatures required to unlock the lamports"),
)
.arg(
2018-09-21 18:51:42 -07:00
Arg::with_name("cancelable")
.long("cancelable")
.takes_value(false),
),
)
.subcommand(
SubCommand::with_name("send-signature")
.about("Send a signature to authorize a transfer")
.arg(
2018-09-24 09:23:16 -07:00
Arg::with_name("to")
.index(1)
2018-09-24 09:23:16 -07:00
.value_name("PUBKEY")
.takes_value(true)
.required(true)
2019-03-20 15:20:31 -07:00
.validator(is_pubkey)
2018-09-24 09:23:16 -07:00
.help("The pubkey of recipient"),
)
.arg(
2019-03-07 16:00:12 -08:00
Arg::with_name("process_id")
2018-09-24 09:23:16 -07:00
.index(2)
.value_name("PROCESS_ID")
.takes_value(true)
.required(true)
.help("The process id of the transfer to authorize"),
),
)
.subcommand(
SubCommand::with_name("send-timestamp")
.about("Send a timestamp to unlock a transfer")
.arg(
Arg::with_name("to")
.index(1)
.value_name("PUBKEY")
.takes_value(true)
.required(true)
2019-03-20 15:20:31 -07:00
.validator(is_pubkey)
.help("The pubkey of recipient"),
)
.arg(
2019-03-07 16:00:12 -08:00
Arg::with_name("process_id")
.index(2)
.value_name("PROCESS_ID")
.takes_value(true)
.required(true)
.help("The process id of the transfer to unlock"),
)
.arg(
Arg::with_name("datetime")
.long("date")
.value_name("DATETIME")
.takes_value(true)
.help("Optional arbitrary timestamp to apply"),
),
)
.get_matches();
2018-06-26 22:52:34 -07:00
let config = parse_args(&matches)?;
2018-09-20 22:27:06 -07:00
let result = process_command(&config)?;
println!("{}", result);
Ok(())
}