Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Gorc's CLI UX #378

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
41 changes: 31 additions & 10 deletions orchestrator/gorc/src/commands/cosmos_to_eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,33 @@ const TIMEOUT: Duration = Duration::from_secs(60);

/// This command, send Cosmos to Ethereum
#[derive(Command, Debug, Default, Parser)]
#[clap(
long_about = "DESCRIPTION \n\n Send Cosmos token to Eth chain.\n This command sends Cosmos token to the Eth chain via the Gravity bridge. \n This command takes the Gravity denom, tx amount, Cosmos keyname, Eth destination, number of times \n transaction should be made and if the transaction should be made immediately or wait for the next \n batch."
)]
pub struct CosmosToEthCmd {
pub args: Vec<String>,
/// Gravity denom
#[clap(short, long)]
gravity_denom: String,

/// Tx amount.
#[clap(short, long)]
amount: String,

/// Cosmos keyname.
#[clap(short, long)]
pub flag_no_batch: bool,
cosmos_key: String,

/// Ethereum address
#[clap(short, long)]
eth_dest: String,

/// The number of times transactions should repeat itself, default is 1.
#[clap(short, long, default_value = "1")]
times: String,

/// Boolean, True if you want to wait until someone requests a batch for this token type and False if you want to request a batch to push transaction along immediately.
#[clap(short = 'f', long)]
pub wait_for_batch: bool,
}

pub fn one_eth() -> f64 {
Expand Down Expand Up @@ -45,15 +67,14 @@ pub fn print_eth(input: Uint256) -> String {
impl Runnable for CosmosToEthCmd {
fn run(&self) {
let config = APP.config();
let gravity_denom = self.args.get(0).expect("denom is required");
let gravity_denom = gravity_denom.to_string();
let gravity_denom = self.gravity_denom.clone();
let is_cosmos_originated = !gravity_denom.starts_with("gravity");

let amount = self.args.get(1).expect("amount is required");
let amount = self.amount.clone();
let amount: Uint256 = amount.parse().expect("cannot parse amount");

let cosmos_key = self.args.get(2).expect("name is required");
let cosmos_key = config.load_deep_space_key(cosmos_key.to_string());
let cosmos_key = self.cosmos_key.clone();
let cosmos_key = config.load_deep_space_key(cosmos_key);

let cosmos_prefix = config.cosmos.prefix.trim();
let cosmos_address = cosmos_key.to_address(cosmos_prefix).unwrap();
Expand Down Expand Up @@ -98,7 +119,7 @@ impl Runnable for CosmosToEthCmd {
denom: gravity_denom.clone(),
};

let eth_dest = self.args.get(3).expect("ethereum destination is required");
let eth_dest = self.eth_dest.clone();
let eth_dest: EthAddress = eth_dest.parse().expect("cannot parse ethereum address");
check_for_fee_denom(&gravity_denom, cosmos_address, &contact).await;

Expand All @@ -115,7 +136,7 @@ impl Runnable for CosmosToEthCmd {

println!("Cosmos balances {:?}", balances);

let times = self.args.get(4).expect("times is required");
let times = self.times.clone();
let times = times.parse::<usize>().expect("cannot parse times");

match found {
Expand Down Expand Up @@ -164,7 +185,7 @@ impl Runnable for CosmosToEthCmd {
}

if successful_sends > 0 {
if !self.flag_no_batch {
if !self.wait_for_batch {
println!("Requesting a batch to push transaction along immediately");
send_request_batch_tx(cosmos_key, gravity_denom,config.cosmos.gas_price.as_tuple(), &contact,config.cosmos.gas_adjustment)
.await
Expand Down
13 changes: 9 additions & 4 deletions orchestrator/gorc/src/commands/deploy/erc20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,17 @@ use tokio::time::sleep as delay_for;

/// Deploy Erc20
#[derive(Command, Debug, Parser)]
#[clap(
long_about = "DESCRIPTION \n\n Deploy ERC20 tokens via the Gravity Bridge.\n This command takes a token denom, Ethereum key and gas multiplier."
)]
pub struct Erc20 {
args: Vec<String>,

/// Erc20 token denom.
#[clap(short, long)]
denom: String,
/// Ethereum ID representing a Keystore entry.
#[clap(short, long)]
ethereum_key: String,

/// Ethereum gas multiplier, default is 1.
#[clap(short, long, default_value_t = 1.0)]
gas_multiplier: f64,
}
Expand All @@ -38,7 +43,7 @@ impl Runnable for Erc20 {

impl Erc20 {
async fn deploy(&self) {
let denom = self.args.get(0).expect("denom is required");
let denom = self.denom.clone();

let config = APP.config();

Expand Down
53 changes: 38 additions & 15 deletions orchestrator/gorc/src/commands/eth_to_cosmos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,49 @@ const TIMEOUT: Duration = Duration::from_secs(60);

/// This command send Ethereum to Cosmos
#[derive(Command, Debug, Default, Parser)]
#[clap(
long_about = "DESCRIPTION \n\n Send Eth token to Cosmos chain.\n This command sends Eth token to the Cosmos chain via the Gravity bridge. \n It takes the tx amount, Eth keyname, contract address, Cosmos token destination, number of times \n and the ERC20 token contract address."
)]
pub struct EthToCosmosCmd {
pub args: Vec<String>,
/// Erc20 contract address.
#[clap(short = 'E', long)]
erc20_address: String,

/// Tx amount.
#[clap(short, long)]
init_amount: String,

/// Eth keyname.
#[clap(short, long)]
ethereum_key: String,

/// Cosmos address
#[clap(short, long)]
cosmos_dest: String,

/// The number of times transactions should repeat itself, default is 1.
#[clap(short, long, default_value = "1")]
times: String,

/// Contract address.
#[clap(short = 'C', long)]
contract_address: String,
}

impl Runnable for EthToCosmosCmd {
fn run(&self) {
let config = APP.config();
let erc20_address = self.args.get(0).expect("erc20 address is required");
let erc20_address = self.erc20_address.clone();
let erc20_address: EthAddress = erc20_address
.parse()
.expect("Invalid ERC20 contract address!");

let ethereum_key = self.args.get(1).expect("key is required");
let ethereum_wallet = config.load_ethers_wallet(ethereum_key.clone());
let ethereum_wallet = config.load_ethers_wallet(self.ethereum_key.clone());

let contract_address = self.args.get(2).expect("contract address is required");
let contract_address: EthAddress =
contract_address.parse().expect("Invalid contract address!");
let contract_address: EthAddress = self
.contract_address
.parse()
.expect("Invalid contract address!");

let cosmos_prefix = config.cosmos.prefix.trim();
let eth_rpc = config.ethereum.rpc.trim();
Expand All @@ -56,22 +81,20 @@ impl Runnable for EthToCosmosCmd {
let eth_client =
SignerMiddleware::new(provider, ethereum_wallet.clone().with_chain_id(chain_id));
let eth_client = Arc::new(eth_client);
let cosmos_dest = self.args.get(3).expect("cosmos destination is required");
let cosmos_dest: CosmosAddress = cosmos_dest.parse().unwrap();
let cosmos_dest: CosmosAddress = self.cosmos_dest.parse().unwrap();
let ethereum_address = eth_client.address();
check_for_eth(ethereum_address, eth_client.clone()).await;

let init_amount = self.args.get(4).expect("amount is required");
let amount = U256::from_dec_str(init_amount).expect("cannot parse amount as U256");
let amount =
U256::from_dec_str(&self.init_amount).expect("cannot parse amount as U256");

let erc20_balance =
get_erc20_balance(erc20_address, ethereum_address, eth_client.clone())
.await
.expect("Failed to get balance, check ERC20 contract address");

let times = self.args.get(5).expect("times is required");
let times = self.times.clone();
let times_usize = times.parse::<usize>().expect("cannot parse times as usize");
let times_u256 = U256::from_dec_str(times).expect("cannot parse times as U256");
let times_u256 = U256::from_dec_str(&times).expect("cannot parse times as U256");

if erc20_balance == 0u8.into() {
panic!(
Expand All @@ -89,7 +112,7 @@ impl Runnable for EthToCosmosCmd {
for _ in 0..times_usize {
println!(
"Sending {} / {} to Cosmos from {} to {}",
init_amount.parse::<f64>().unwrap(),
self.init_amount.parse::<f64>().unwrap(),
erc20_address,
ethereum_address,
cosmos_dest
Expand Down
7 changes: 4 additions & 3 deletions orchestrator/gorc/src/commands/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ use crate::commands::keys::eth::EthKeysCmd;

#[derive(Command, Debug, Parser, Runnable)]
pub enum KeysCmd {
#[clap(subcommand)]
Cosmos(CosmosKeysCmd),

/// Manage Ethereum keys.
#[clap(subcommand)]
Eth(EthKeysCmd),
/// Manage Cosmos keys.
#[clap(subcommand)]
Cosmos(CosmosKeysCmd),
}
14 changes: 9 additions & 5 deletions orchestrator/gorc/src/commands/keys/cosmos/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ use std::path;

/// Add a new Cosmos Key
#[derive(Command, Debug, Default, Parser)]
#[clap(
long_about = "DESCRIPTION \n\n Create a new Cosmos Key.\n This command creates a new Cosmos key. When provided an overwrite option, which if set to true,\n overwrites an existing key in the keystore with the same keyname."
)]
pub struct AddCosmosKeyCmd {
pub args: Vec<String>,
/// Cosmos keyname
pub name: String,

/// Overwrite key with the same name in the keystore when set to true. Takes a Boolean.
#[clap(short, long)]
pub overwrite: bool,
}
Expand All @@ -21,8 +26,7 @@ impl Runnable for AddCosmosKeyCmd {
let keystore = path::Path::new(&config.keystore);
let keystore = FsKeyStore::create_or_open(keystore).expect("Could not open keystore");

let name = self.args.get(0).expect("name is required");
let name = name.parse().expect("Could not parse name");
let name = self.name.parse().expect("Could not parse name");
if let Ok(_info) = keystore.info(&name) {
if !self.overwrite {
eprintln!("Key already exists, exiting.");
Expand All @@ -49,8 +53,8 @@ impl Runnable for AddCosmosKeyCmd {

keystore.store(&name, &key).expect("Could not store key");

let args = vec![name.to_string()];
let show_cmd = ShowCosmosKeyCmd { args };
let name = name.to_string();
let show_cmd = ShowCosmosKeyCmd { name };
show_cmd.run();
}
}
11 changes: 7 additions & 4 deletions orchestrator/gorc/src/commands/keys/cosmos/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,23 @@ use std::path::Path;

/// Delete a Cosmos Key
#[derive(Command, Debug, Default, Parser)]
#[clap(
long_about = "DESCRIPTION \n\n Delete a Cosmos Key.\n This command deletes a Cosmos key from your keystore when provided with the keyname."
)]
pub struct DeleteCosmosKeyCmd {
pub args: Vec<String>,
/// Cosmos keyname in keystore.
pub name: String,
}

/// The `gork keys cosmos delete [name] ` subcommand: delete the given key
/// The `gorc keys cosmos delete [name] ` subcommand: delete the given key
impl Runnable for DeleteCosmosKeyCmd {
fn run(&self) {
let config = APP.config();
// Path where key is stored.
let keystore = Path::new(&config.keystore);
let keystore = signatory::FsKeyStore::create_or_open(keystore).unwrap();
// Collect key name from args.
let name = self.args.get(0).expect("name is required");
let name = name.parse().expect("Could not parse name");
let name = self.name.parse().expect("Could not parse name");
// Delete keyname after locating file from path and key name.
let _delete_key = FsKeyStore::delete(&keystore, &name).unwrap();
}
Expand Down
7 changes: 5 additions & 2 deletions orchestrator/gorc/src/commands/keys/cosmos/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ use std::path::Path;

/// List all Cosmos Keys
#[derive(Command, Debug, Default, Parser)]
#[clap(
long_about = "DESCRIPTION \n\n List all Cosmos keys in keystore.\n This command lists all Cosmos keys and their addresses from the keystore."
)]
pub struct ListCosmosKeyCmd {}

// Entry point for `gorc keys cosmos list`
Expand All @@ -20,8 +23,8 @@ impl Runnable for ListCosmosKeyCmd {
if extension == "pem" {
let name = path.file_stem().unwrap();
let name = name.to_str().unwrap();
let args = vec![name.to_string()];
let show_cmd = ShowCosmosKeyCmd { args };
let name = name.to_string();
let show_cmd = ShowCosmosKeyCmd { name };
show_cmd.run();
}
}
Expand Down
21 changes: 14 additions & 7 deletions orchestrator/gorc/src/commands/keys/cosmos/recover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,19 @@ use std::path;

/// Recover a Cosmos Key
#[derive(Command, Debug, Default, Parser)]
#[clap(
long_about = "DESCRIPTION \n\n Recover an external Cosmos key.\n This command will recover a Cosmos key, storing it in the keystore. \n It takes a keyname and bip39-mnemonic."
)]
pub struct RecoverCosmosKeyCmd {
pub args: Vec<String>,
/// Cosmos keyname.
pub name: String,

/// Overwrite key with the same name in the keystore when set to true. Takes a Boolean.
#[clap(short, long)]
pub overwrite: bool,

/// bip39-mnemonic optional. When absent you'll be prompted to enter it.
pub mnemonic: Option<String>,
}

// `gorc keys cosmos recover [name] (bip39-mnemonic)`
Expand All @@ -23,17 +31,16 @@ impl Runnable for RecoverCosmosKeyCmd {
let keystore = path::Path::new(&config.keystore);
let keystore = FsKeyStore::create_or_open(keystore).expect("Could not open keystore");

let name = self.args.get(0).expect("name is required");
let name = name.parse().expect("Could not parse name");
let name = self.name.parse().expect("Could not parse name");
if let Ok(_info) = keystore.info(&name) {
if !self.overwrite {
eprintln!("Key already exists, exiting.");
return;
}
}

let mnemonic = match self.args.get(1) {
Some(mnemonic) => mnemonic.clone(),
let mnemonic = match self.mnemonic.clone() {
Some(mnemonic) => mnemonic,
None => rpassword::read_password_from_tty(Some("> Enter your bip39-mnemonic:\n"))
.expect("Could not read mnemonic"),
};
Expand All @@ -56,8 +63,8 @@ impl Runnable for RecoverCosmosKeyCmd {

keystore.store(&name, &key).expect("Could not store key");

let args = vec![name.to_string()];
let show_cmd = ShowCosmosKeyCmd { args };
let name = name.to_string();
let show_cmd = ShowCosmosKeyCmd { name };
show_cmd.run();
}
}
16 changes: 11 additions & 5 deletions orchestrator/gorc/src/commands/keys/cosmos/rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,17 @@ use std::path;

/// Rename a Cosmos Key
#[derive(Command, Debug, Default, Parser)]
#[clap(
long_about = "DESCRIPTION \n\n Rename a Cosmos key.\n This command will rename a Cosmos key in the keystore. It takes the existing keyname and new \n keyname."
)]
pub struct RenameCosmosKeyCmd {
pub args: Vec<String>,
/// Cosmos keyname in keystore.
pub name: String,

/// New keyname to replace name in keystore.
pub new_name: String,

/// Overwrite key with the same name in the keystore when set to true. Takes a Boolean.
#[clap(short, long)]
pub overwrite: bool,
}
Expand All @@ -18,11 +26,9 @@ impl Runnable for RenameCosmosKeyCmd {
let keystore = path::Path::new(&config.keystore);
let keystore = signatory::FsKeyStore::create_or_open(keystore).unwrap();

let name = self.args.get(0).expect("name is required");
let name = name.parse().expect("Could not parse name");
let name = self.name.parse().expect("Could not parse name");

let new_name = self.args.get(1).expect("new_name is required");
let new_name = new_name.parse().expect("Could not parse new_name");
let new_name = self.new_name.parse().expect("Could not parse new_name");
if let Ok(_info) = keystore.info(&new_name) {
if !self.overwrite {
println!("Key already exists, exiting.");
Expand Down
Loading