diff --git a/.changelog/unreleased/miscellaneous/1738-refactor-cli.md b/.changelog/unreleased/miscellaneous/1738-refactor-cli.md new file mode 100644 index 0000000000..ef201074db --- /dev/null +++ b/.changelog/unreleased/miscellaneous/1738-refactor-cli.md @@ -0,0 +1,2 @@ +- Refactored CLI into libraries for future re-use in integration tests and + to enable generic IO. ([\#1738](https://github.com/anoma/namada/pull/1738)) \ No newline at end of file diff --git a/apps/src/bin/namada-client/cli.rs b/apps/src/bin/namada-client/cli.rs deleted file mode 100644 index 609588045d..0000000000 --- a/apps/src/bin/namada-client/cli.rs +++ /dev/null @@ -1,461 +0,0 @@ -//! Namada client CLI. - -use color_eyre::eyre::{eyre, Report, Result}; -use namada::ledger::eth_bridge::bridge_pool; -use namada::ledger::rpc::wait_until_node_is_synched; -use namada::ledger::{signing, tx as sdk_tx}; -use namada::types::control_flow::ProceedOrElse; -use namada_apps::cli; -use namada_apps::cli::args::CliToSdk; -use namada_apps::cli::cmds::*; -use namada_apps::client::{rpc, tx, utils}; -use namada_apps::facade::tendermint_rpc::HttpClient; - -fn error() -> Report { - eyre!("Fatal error") -} - -pub async fn main() -> Result<()> { - match cli::namada_client_cli()? { - cli::NamadaClient::WithContext(cmd_box) => { - let (cmd, mut ctx) = *cmd_box; - use NamadaClientWithContext as Sub; - match cmd { - // Ledger cmds - Sub::TxCustom(TxCustom(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - let dry_run = args.tx.dry_run; - tx::submit_custom::(&client, &mut ctx, args) - .await?; - if !dry_run { - namada_apps::wallet::save(&ctx.wallet) - .unwrap_or_else(|err| eprintln!("{}", err)); - } else { - println!( - "Transaction dry run. No addresses have been \ - saved." - ) - } - } - Sub::TxTransfer(TxTransfer(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_transfer(&client, ctx, args).await?; - } - Sub::TxIbcTransfer(TxIbcTransfer(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_ibc_transfer::(&client, ctx, args) - .await?; - } - Sub::TxUpdateVp(TxUpdateVp(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_update_vp::(&client, &mut ctx, args) - .await?; - } - Sub::TxInitAccount(TxInitAccount(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - let dry_run = args.tx.dry_run; - tx::submit_init_account::( - &client, &mut ctx, args, - ) - .await?; - if !dry_run { - namada_apps::wallet::save(&ctx.wallet) - .unwrap_or_else(|err| eprintln!("{}", err)); - } else { - println!( - "Transaction dry run. No addresses have been \ - saved." - ) - } - } - Sub::TxInitValidator(TxInitValidator(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_init_validator::(&client, ctx, args) - .await?; - } - Sub::TxInitProposal(TxInitProposal(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_init_proposal::(&client, ctx, args) - .await?; - } - Sub::TxVoteProposal(TxVoteProposal(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_vote_proposal::(&client, ctx, args) - .await?; - } - Sub::TxRevealPk(TxRevealPk(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_reveal_pk::(&client, &mut ctx, args) - .await?; - } - Sub::Bond(Bond(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_bond::(&client, &mut ctx, args) - .await?; - } - Sub::Unbond(Unbond(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_unbond::(&client, &mut ctx, args) - .await?; - } - Sub::Withdraw(Withdraw(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - tx::submit_withdraw::(&client, ctx, args) - .await?; - } - Sub::TxCommissionRateChange(TxCommissionRateChange( - mut args, - )) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client).await; - let args = args.to_sdk(&mut ctx); - tx::submit_validator_commission_change::( - &client, ctx, args, - ) - .await?; - } - // Eth bridge - Sub::AddToEthBridgePool(args) => { - let mut args = args.0; - let client = HttpClient::new(utils::take_config_address( - &mut args.tx.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - let tx_args = args.tx.clone(); - let (mut tx, addr, pk) = bridge_pool::build_bridge_pool_tx( - &client, - &mut ctx.wallet, - args, - ) - .await - .unwrap(); - tx::submit_reveal_aux( - &client, - &mut ctx, - &tx_args, - addr, - pk.clone(), - &mut tx, - ) - .await?; - signing::sign_tx(&mut ctx.wallet, &mut tx, &tx_args, &pk) - .await?; - sdk_tx::process_tx(&client, &mut ctx.wallet, &tx_args, tx) - .await?; - } - // Ledger queries - Sub::QueryEpoch(QueryEpoch(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - rpc::query_and_print_epoch(&client).await; - } - Sub::QueryTransfers(QueryTransfers(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_transfers( - &client, - &mut ctx.wallet, - &mut ctx.shielded, - args, - ) - .await; - } - Sub::QueryConversions(QueryConversions(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_conversions(&client, &mut ctx.wallet, args) - .await; - } - Sub::QueryBlock(QueryBlock(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - rpc::query_block(&client).await; - } - Sub::QueryBalance(QueryBalance(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_balance( - &client, - &mut ctx.wallet, - &mut ctx.shielded, - args, - ) - .await; - } - Sub::QueryBonds(QueryBonds(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_bonds(&client, &mut ctx.wallet, args) - .await - .expect("expected successful query of bonds"); - } - Sub::QueryBondedStake(QueryBondedStake(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_bonded_stake(&client, args).await; - } - Sub::QueryCommissionRate(QueryCommissionRate(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_and_print_commission_rate( - &client, - &mut ctx.wallet, - args, - ) - .await; - } - Sub::QuerySlashes(QuerySlashes(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_slashes(&client, &mut ctx.wallet, args).await; - } - Sub::QueryDelegations(QueryDelegations(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_delegations(&client, &mut ctx.wallet, args) - .await; - } - Sub::QueryFindValidator(QueryFindValidator(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_find_validator(&client, args).await; - } - Sub::QueryResult(QueryResult(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_result(&client, args).await; - } - Sub::QueryRawBytes(QueryRawBytes(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_raw_bytes(&client, args).await; - } - - Sub::QueryProposal(QueryProposal(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_proposal(&client, args).await; - } - Sub::QueryProposalResult(QueryProposalResult(mut args)) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_proposal_result(&client, args).await; - } - Sub::QueryProtocolParameters(QueryProtocolParameters( - mut args, - )) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk(&mut ctx); - rpc::query_protocol_parameters(&client, args).await; - } - } - } - cli::NamadaClient::WithoutContext(cmd, global_args) => match cmd { - // Utils cmds - Utils::JoinNetwork(JoinNetwork(args)) => { - utils::join_network(global_args, args).await - } - Utils::FetchWasms(FetchWasms(args)) => { - utils::fetch_wasms(global_args, args).await - } - Utils::InitNetwork(InitNetwork(args)) => { - utils::init_network(global_args, args) - } - Utils::InitGenesisValidator(InitGenesisValidator(args)) => { - utils::init_genesis_validator(global_args, args) - } - Utils::PkToTmAddress(PkToTmAddress(args)) => { - utils::pk_to_tm_address(global_args, args) - } - Utils::DefaultBaseDir(DefaultBaseDir(args)) => { - utils::default_base_dir(global_args, args) - } - }, - } - Ok(()) -} diff --git a/apps/src/bin/namada-client/main.rs b/apps/src/bin/namada-client/main.rs index ccdc0bb2eb..a9e1fb4948 100644 --- a/apps/src/bin/namada-client/main.rs +++ b/apps/src/bin/namada-client/main.rs @@ -1,7 +1,7 @@ -mod cli; - use color_eyre::eyre::Result; -use namada_apps::logging; +use namada_apps::cli::api::CliApi; +use namada_apps::facade::tendermint_rpc::HttpClient; +use namada_apps::{cli, logging}; use tracing_subscriber::filter::LevelFilter; #[tokio::main] @@ -13,5 +13,9 @@ async fn main() -> Result<()> { let _log_guard = logging::init_from_env_or(LevelFilter::INFO)?; // run the CLI - cli::main().await + CliApi::<()>::handle_client_command::( + None, + cli::namada_client_cli()?, + ) + .await } diff --git a/apps/src/bin/namada-relayer/cli.rs b/apps/src/bin/namada-relayer/cli.rs deleted file mode 100644 index fa816dbeae..0000000000 --- a/apps/src/bin/namada-relayer/cli.rs +++ /dev/null @@ -1,143 +0,0 @@ -//! Namada relayer CLI. - -use std::sync::Arc; - -use color_eyre::eyre::{eyre, Report, Result}; -use namada::eth_bridge::ethers::providers::{Http, Provider}; -use namada::ledger::eth_bridge::{bridge_pool, validator_set}; -use namada::ledger::rpc::wait_until_node_is_synched; -use namada::types::control_flow::ProceedOrElse; -use namada_apps::cli::args::CliToSdkCtxless; -use namada_apps::cli::{self, cmds}; -use namada_apps::client::utils; -use namada_apps::facade::tendermint_rpc::HttpClient; - -fn error() -> Report { - eyre!("Fatal error") -} - -pub async fn main() -> Result<()> { - let (cmd, _) = cli::namada_relayer_cli()?; - match cmd { - cmds::NamadaRelayer::EthBridgePool(sub) => match sub { - cmds::EthBridgePool::RecommendBatch(mut args) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk_ctxless(); - bridge_pool::recommend_batch(&client, args) - .await - .proceed_or_else(error)?; - } - cmds::EthBridgePool::ConstructProof(mut args) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk_ctxless(); - bridge_pool::construct_proof(&client, args) - .await - .proceed_or_else(error)?; - } - cmds::EthBridgePool::RelayProof(mut args) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let eth_client = Arc::new( - Provider::::try_from(&args.eth_rpc_endpoint).unwrap(), - ); - let args = args.to_sdk_ctxless(); - bridge_pool::relay_bridge_pool_proof(eth_client, &client, args) - .await - .proceed_or_else(error)?; - } - cmds::EthBridgePool::QueryPool(mut query) => { - let client = HttpClient::new(utils::take_config_address( - &mut query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - bridge_pool::query_bridge_pool(&client).await; - } - cmds::EthBridgePool::QuerySigned(mut query) => { - let client = HttpClient::new(utils::take_config_address( - &mut query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - bridge_pool::query_signed_bridge_pool(&client) - .await - .proceed_or_else(error)?; - } - cmds::EthBridgePool::QueryRelays(mut query) => { - let client = HttpClient::new(utils::take_config_address( - &mut query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - bridge_pool::query_relay_progress(&client).await; - } - }, - cmds::NamadaRelayer::ValidatorSet(sub) => match sub { - cmds::ValidatorSet::ConsensusValidatorSet(mut args) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk_ctxless(); - validator_set::query_validator_set_args(&client, args).await; - } - cmds::ValidatorSet::ValidatorSetProof(mut args) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let args = args.to_sdk_ctxless(); - validator_set::query_validator_set_update_proof(&client, args) - .await; - } - cmds::ValidatorSet::ValidatorSetUpdateRelay(mut args) => { - let client = HttpClient::new(utils::take_config_address( - &mut args.query.ledger_address, - )) - .unwrap(); - wait_until_node_is_synched(&client) - .await - .proceed_or_else(error)?; - let eth_client = Arc::new( - Provider::::try_from(&args.eth_rpc_endpoint).unwrap(), - ); - let args = args.to_sdk_ctxless(); - validator_set::relay_validator_set_update( - eth_client, &client, args, - ) - .await - .proceed_or_else(error)?; - } - }, - } - Ok(()) -} diff --git a/apps/src/bin/namada-relayer/main.rs b/apps/src/bin/namada-relayer/main.rs index 73876fe7d2..0b314cb9fa 100644 --- a/apps/src/bin/namada-relayer/main.rs +++ b/apps/src/bin/namada-relayer/main.rs @@ -1,7 +1,7 @@ -mod cli; - use color_eyre::eyre::Result; -use namada_apps::logging; +use namada::tendermint_rpc::HttpClient; +use namada_apps::cli::api::CliApi; +use namada_apps::{cli, logging}; use tracing_subscriber::filter::LevelFilter; #[tokio::main] @@ -12,6 +12,7 @@ async fn main() -> Result<()> { // init logging logging::init_from_env_or(LevelFilter::INFO)?; + let (cmd, _) = cli::namada_relayer_cli()?; // run the CLI - cli::main().await + CliApi::<()>::handle_relayer_command::(None, cmd).await } diff --git a/apps/src/bin/namada-wallet/main.rs b/apps/src/bin/namada-wallet/main.rs index 252ecb7b88..7459234c79 100644 --- a/apps/src/bin/namada-wallet/main.rs +++ b/apps/src/bin/namada-wallet/main.rs @@ -1,9 +1,10 @@ -mod cli; use color_eyre::eyre::Result; +use namada_apps::cli; +use namada_apps::cli::api::CliApi; pub fn main() -> Result<()> { color_eyre::install()?; - + let (cmd, ctx) = cli::namada_wallet_cli()?; // run the CLI - cli::main() + CliApi::<()>::handle_wallet_command(cmd, ctx) } diff --git a/apps/src/lib/cli.rs b/apps/src/lib/cli.rs index 06d6f3f406..699a2b7f17 100644 --- a/apps/src/lib/cli.rs +++ b/apps/src/lib/cli.rs @@ -6,8 +6,12 @@ //! client can be dispatched via `namada node ...` or `namada client ...`, //! respectively. +pub mod api; +pub mod client; pub mod context; +pub mod relayer; mod utils; +pub mod wallet; use clap::{ArgGroup, ArgMatches, ColorChoice}; use color_eyre::eyre::Result; diff --git a/apps/src/lib/cli/api.rs b/apps/src/lib/cli/api.rs new file mode 100644 index 0000000000..c22fe39fd3 --- /dev/null +++ b/apps/src/lib/cli/api.rs @@ -0,0 +1,29 @@ +use std::marker::PhantomData; + +use namada::ledger::queries::Client; +use namada::ledger::rpc::wait_until_node_is_synched; +use namada::tendermint_rpc::HttpClient; +use namada::types::control_flow::Halt; +use tendermint_config::net::Address as TendermintAddress; + +use crate::client::utils; + +/// Trait for clients that can be used with the CLI. +#[async_trait::async_trait(?Send)] +pub trait CliClient: Client + Sync { + fn from_tendermint_address(address: &mut TendermintAddress) -> Self; + async fn wait_until_node_is_synced(&self) -> Halt<()>; +} + +#[async_trait::async_trait(?Send)] +impl CliClient for HttpClient { + fn from_tendermint_address(address: &mut TendermintAddress) -> Self { + HttpClient::new(utils::take_config_address(address)).unwrap() + } + + async fn wait_until_node_is_synced(&self) -> Halt<()> { + wait_until_node_is_synched(self).await + } +} + +pub struct CliApi(PhantomData); diff --git a/apps/src/lib/cli/client.rs b/apps/src/lib/cli/client.rs new file mode 100644 index 0000000000..fb7d01559b --- /dev/null +++ b/apps/src/lib/cli/client.rs @@ -0,0 +1,525 @@ +use color_eyre::eyre::{eyre, Report, Result}; +use namada::ledger::eth_bridge::bridge_pool; +use namada::ledger::{signing, tx as sdk_tx}; +use namada::types::control_flow::ProceedOrElse; + +use crate::cli; +use crate::cli::api::{CliApi, CliClient}; +use crate::cli::args::CliToSdk; +use crate::cli::cmds::*; +use crate::client::{rpc, tx, utils}; + +fn error() -> Report { + eyre!("Fatal error") +} + +impl CliApi { + pub async fn handle_client_command( + client: Option, + cmd: cli::NamadaClient, + ) -> Result<()> + where + C: CliClient, + { + match cmd { + cli::NamadaClient::WithContext(cmd_box) => { + let (cmd, mut ctx) = *cmd_box; + use NamadaClientWithContext as Sub; + match cmd { + // Ledger cmds + Sub::TxCustom(TxCustom(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.tx.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + let dry_run = args.tx.dry_run; + tx::submit_custom(&client, &mut ctx, args).await?; + if !dry_run { + crate::wallet::save(&ctx.wallet) + .unwrap_or_else(|err| eprintln!("{}", err)); + } else { + println!( + "Transaction dry run. No addresses have been \ + saved." + ) + } + } + Sub::TxTransfer(TxTransfer(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.tx.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + tx::submit_transfer(&client, ctx, args).await?; + } + Sub::TxIbcTransfer(TxIbcTransfer(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.tx.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + tx::submit_ibc_transfer(&client, ctx, args).await?; + } + Sub::TxUpdateVp(TxUpdateVp(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.tx.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + tx::submit_update_vp(&client, &mut ctx, args).await?; + } + Sub::TxInitAccount(TxInitAccount(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.tx.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + let dry_run = args.tx.dry_run; + tx::submit_init_account(&client, &mut ctx, args) + .await?; + if !dry_run { + crate::wallet::save(&ctx.wallet) + .unwrap_or_else(|err| eprintln!("{}", err)); + } else { + println!( + "Transaction dry run. No addresses have been \ + saved." + ) + } + } + Sub::TxInitValidator(TxInitValidator(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.tx.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + tx::submit_init_validator(&client, ctx, args).await?; + } + Sub::TxInitProposal(TxInitProposal(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.tx.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + tx::submit_init_proposal(&client, ctx, args).await?; + } + Sub::TxVoteProposal(TxVoteProposal(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.tx.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + tx::submit_vote_proposal(&client, ctx, args).await?; + } + Sub::TxRevealPk(TxRevealPk(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.tx.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + tx::submit_reveal_pk(&client, &mut ctx, args).await?; + } + Sub::Bond(Bond(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.tx.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + tx::submit_bond(&client, &mut ctx, args).await?; + } + Sub::Unbond(Unbond(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.tx.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + tx::submit_unbond(&client, &mut ctx, args).await?; + } + Sub::Withdraw(Withdraw(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.tx.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + tx::submit_withdraw(&client, ctx, args).await?; + } + Sub::TxCommissionRateChange(TxCommissionRateChange( + mut args, + )) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.tx.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + tx::submit_validator_commission_change( + &client, ctx, args, + ) + .await?; + } + // Eth bridge + Sub::AddToEthBridgePool(args) => { + let mut args = args.0; + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.tx.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + let tx_args = args.tx.clone(); + let (mut tx, addr, pk) = + bridge_pool::build_bridge_pool_tx( + &client, + &mut ctx.wallet, + args, + ) + .await + .unwrap(); + tx::submit_reveal_aux( + &client, + &mut ctx, + &tx_args, + addr, + pk.clone(), + &mut tx, + ) + .await?; + signing::sign_tx( + &mut ctx.wallet, + &mut tx, + &tx_args, + &pk, + ) + .await?; + sdk_tx::process_tx( + &client, + &mut ctx.wallet, + &tx_args, + tx, + ) + .await?; + } + // Ledger queries + Sub::QueryEpoch(QueryEpoch(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address(&mut args.ledger_address) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + rpc::query_and_print_epoch(&client).await; + } + Sub::QueryTransfers(QueryTransfers(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + rpc::query_transfers( + &client, + &mut ctx.wallet, + &mut ctx.shielded, + args, + ) + .await; + } + Sub::QueryConversions(QueryConversions(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + rpc::query_conversions(&client, &mut ctx.wallet, args) + .await; + } + Sub::QueryBlock(QueryBlock(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address(&mut args.ledger_address) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + rpc::query_block(&client).await; + } + Sub::QueryBalance(QueryBalance(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + rpc::query_balance( + &client, + &mut ctx.wallet, + &mut ctx.shielded, + args, + ) + .await; + } + Sub::QueryBonds(QueryBonds(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + rpc::query_bonds(&client, &mut ctx.wallet, args) + .await + .expect("expected successful query of bonds"); + } + Sub::QueryBondedStake(QueryBondedStake(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + rpc::query_bonded_stake(&client, args).await; + } + Sub::QueryCommissionRate(QueryCommissionRate(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + rpc::query_and_print_commission_rate( + &client, + &mut ctx.wallet, + args, + ) + .await; + } + Sub::QuerySlashes(QuerySlashes(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + rpc::query_slashes(&client, &mut ctx.wallet, args) + .await; + } + Sub::QueryDelegations(QueryDelegations(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + rpc::query_delegations(&client, &mut ctx.wallet, args) + .await; + } + Sub::QueryFindValidator(QueryFindValidator(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + rpc::query_find_validator(&client, args).await; + } + Sub::QueryResult(QueryResult(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + rpc::query_result(&client, args).await; + } + Sub::QueryRawBytes(QueryRawBytes(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + rpc::query_raw_bytes(&client, args).await; + } + + Sub::QueryProposal(QueryProposal(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + rpc::query_proposal(&client, args).await; + } + Sub::QueryProposalResult(QueryProposalResult(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + rpc::query_proposal_result(&client, args).await; + } + Sub::QueryProtocolParameters(QueryProtocolParameters( + mut args, + )) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk(&mut ctx); + rpc::query_protocol_parameters(&client, args).await; + } + } + } + cli::NamadaClient::WithoutContext(cmd, global_args) => match cmd { + // Utils cmds + Utils::JoinNetwork(JoinNetwork(args)) => { + utils::join_network(global_args, args).await + } + Utils::FetchWasms(FetchWasms(args)) => { + utils::fetch_wasms(global_args, args).await + } + Utils::InitNetwork(InitNetwork(args)) => { + utils::init_network(global_args, args) + } + Utils::InitGenesisValidator(InitGenesisValidator(args)) => { + utils::init_genesis_validator(global_args, args) + } + Utils::PkToTmAddress(PkToTmAddress(args)) => { + utils::pk_to_tm_address(global_args, args) + } + Utils::DefaultBaseDir(DefaultBaseDir(args)) => { + utils::default_base_dir(global_args, args) + } + }, + } + Ok(()) + } +} diff --git a/apps/src/lib/cli/relayer.rs b/apps/src/lib/cli/relayer.rs new file mode 100644 index 0000000000..531051d27a --- /dev/null +++ b/apps/src/lib/cli/relayer.rs @@ -0,0 +1,166 @@ +use std::sync::Arc; + +use color_eyre::eyre::{eyre, Report, Result}; +use namada::eth_bridge::ethers::providers::{Http, Provider}; +use namada::ledger::eth_bridge::{bridge_pool, validator_set}; +use namada::types::control_flow::ProceedOrElse; + +use crate::cli::api::{CliApi, CliClient}; +use crate::cli::args::CliToSdkCtxless; +use crate::cli::cmds; + +fn error() -> Report { + eyre!("Fatal error") +} + +impl CliApi { + pub async fn handle_relayer_command( + client: Option, + cmd: cmds::NamadaRelayer, + ) -> Result<()> + where + C: CliClient, + { + match cmd { + cmds::NamadaRelayer::EthBridgePool(sub) => match sub { + cmds::EthBridgePool::RecommendBatch(mut args) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk_ctxless(); + bridge_pool::recommend_batch(&client, args) + .await + .proceed_or_else(error)?; + } + cmds::EthBridgePool::ConstructProof(mut args) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk_ctxless(); + bridge_pool::construct_proof(&client, args) + .await + .proceed_or_else(error)?; + } + cmds::EthBridgePool::RelayProof(mut args) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let eth_client = Arc::new( + Provider::::try_from(&args.eth_rpc_endpoint) + .unwrap(), + ); + let args = args.to_sdk_ctxless(); + bridge_pool::relay_bridge_pool_proof( + eth_client, &client, args, + ) + .await + .proceed_or_else(error)?; + } + cmds::EthBridgePool::QueryPool(mut query) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address(&mut query.ledger_address) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + bridge_pool::query_bridge_pool(&client).await; + } + cmds::EthBridgePool::QuerySigned(mut query) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address(&mut query.ledger_address) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + bridge_pool::query_signed_bridge_pool(&client) + .await + .proceed_or_else(error)?; + } + cmds::EthBridgePool::QueryRelays(mut query) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address(&mut query.ledger_address) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + bridge_pool::query_relay_progress(&client).await; + } + }, + cmds::NamadaRelayer::ValidatorSet(sub) => match sub { + cmds::ValidatorSet::ConsensusValidatorSet(mut args) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk_ctxless(); + validator_set::query_validator_set_args(&client, args) + .await; + } + cmds::ValidatorSet::ValidatorSetProof(mut args) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let args = args.to_sdk_ctxless(); + validator_set::query_validator_set_update_proof( + &client, args, + ) + .await; + } + cmds::ValidatorSet::ValidatorSetUpdateRelay(mut args) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client + .wait_until_node_is_synced() + .await + .proceed_or_else(error)?; + let eth_client = Arc::new( + Provider::::try_from(&args.eth_rpc_endpoint) + .unwrap(), + ); + let args = args.to_sdk_ctxless(); + validator_set::relay_validator_set_update( + eth_client, &client, args, + ) + .await + .proceed_or_else(error)?; + } + }, + } + Ok(()) + } +} diff --git a/apps/src/bin/namada-wallet/cli.rs b/apps/src/lib/cli/wallet.rs similarity index 83% rename from apps/src/bin/namada-wallet/cli.rs rename to apps/src/lib/cli/wallet.rs index 685ed7f116..7505c59efe 100644 --- a/apps/src/bin/namada-wallet/cli.rs +++ b/apps/src/lib/cli/wallet.rs @@ -11,68 +11,78 @@ use namada::ledger::masp::find_valid_diversifier; use namada::ledger::wallet::{DecryptionError, FindKeyError}; use namada::types::key::*; use namada::types::masp::{MaspValue, PaymentAddress}; -use namada_apps::cli; -use namada_apps::cli::args::CliToSdk; -use namada_apps::cli::{args, cmds, Context}; -use namada_apps::wallet::{ - read_and_confirm_encryption_password, CliWalletUtils, -}; use rand_core::OsRng; -pub fn main() -> Result<()> { - let (cmd, mut ctx) = cli::namada_wallet_cli()?; - match cmd { - cmds::NamadaWallet::Key(sub) => match sub { - cmds::WalletKey::Restore(cmds::KeyRestore(args)) => { - key_and_address_restore(ctx, args) - } - cmds::WalletKey::Gen(cmds::KeyGen(args)) => { - key_and_address_gen(ctx, args) - } - cmds::WalletKey::Find(cmds::KeyFind(args)) => key_find(ctx, args), - cmds::WalletKey::List(cmds::KeyList(args)) => key_list(ctx, args), - cmds::WalletKey::Export(cmds::Export(args)) => { - key_export(ctx, args) - } - }, - cmds::NamadaWallet::Address(sub) => match sub { - cmds::WalletAddress::Gen(cmds::AddressGen(args)) => { - key_and_address_gen(ctx, args) - } - cmds::WalletAddress::Restore(cmds::AddressRestore(args)) => { - key_and_address_restore(ctx, args) - } - cmds::WalletAddress::Find(cmds::AddressOrAliasFind(args)) => { - address_or_alias_find(ctx, args) - } - cmds::WalletAddress::List(cmds::AddressList) => address_list(ctx), - cmds::WalletAddress::Add(cmds::AddressAdd(args)) => { - address_add(ctx, args) - } - }, - cmds::NamadaWallet::Masp(sub) => match sub { - cmds::WalletMasp::GenSpendKey(cmds::MaspGenSpendKey(args)) => { - spending_key_gen(ctx, args) - } - cmds::WalletMasp::GenPayAddr(cmds::MaspGenPayAddr(args)) => { - let args = args.to_sdk(&mut ctx); - payment_address_gen(ctx, args) - } - cmds::WalletMasp::AddAddrKey(cmds::MaspAddAddrKey(args)) => { - address_key_add(ctx, args) - } - cmds::WalletMasp::ListPayAddrs(cmds::MaspListPayAddrs) => { - payment_addresses_list(ctx) - } - cmds::WalletMasp::ListKeys(cmds::MaspListKeys(args)) => { - spending_keys_list(ctx, args) - } - cmds::WalletMasp::FindAddrKey(cmds::MaspFindAddrKey(args)) => { - address_key_find(ctx, args) - } - }, +use crate::cli; +use crate::cli::api::CliApi; +use crate::cli::args::CliToSdk; +use crate::cli::{args, cmds, Context}; +use crate::wallet::{read_and_confirm_encryption_password, CliWalletUtils}; + +impl CliApi { + pub fn handle_wallet_command( + cmd: cmds::NamadaWallet, + mut ctx: Context, + ) -> Result<()> { + match cmd { + cmds::NamadaWallet::Key(sub) => match sub { + cmds::WalletKey::Restore(cmds::KeyRestore(args)) => { + key_and_address_restore(ctx, args) + } + cmds::WalletKey::Gen(cmds::KeyGen(args)) => { + key_and_address_gen(ctx, args) + } + cmds::WalletKey::Find(cmds::KeyFind(args)) => { + key_find(ctx, args) + } + cmds::WalletKey::List(cmds::KeyList(args)) => { + key_list(ctx, args) + } + cmds::WalletKey::Export(cmds::Export(args)) => { + key_export(ctx, args) + } + }, + cmds::NamadaWallet::Address(sub) => match sub { + cmds::WalletAddress::Gen(cmds::AddressGen(args)) => { + key_and_address_gen(ctx, args) + } + cmds::WalletAddress::Restore(cmds::AddressRestore(args)) => { + key_and_address_restore(ctx, args) + } + cmds::WalletAddress::Find(cmds::AddressOrAliasFind(args)) => { + address_or_alias_find(ctx, args) + } + cmds::WalletAddress::List(cmds::AddressList) => { + address_list(ctx) + } + cmds::WalletAddress::Add(cmds::AddressAdd(args)) => { + address_add(ctx, args) + } + }, + cmds::NamadaWallet::Masp(sub) => match sub { + cmds::WalletMasp::GenSpendKey(cmds::MaspGenSpendKey(args)) => { + spending_key_gen(ctx, args) + } + cmds::WalletMasp::GenPayAddr(cmds::MaspGenPayAddr(args)) => { + let args = args.to_sdk(&mut ctx); + payment_address_gen(ctx, args) + } + cmds::WalletMasp::AddAddrKey(cmds::MaspAddAddrKey(args)) => { + address_key_add(ctx, args) + } + cmds::WalletMasp::ListPayAddrs(cmds::MaspListPayAddrs) => { + payment_addresses_list(ctx) + } + cmds::WalletMasp::ListKeys(cmds::MaspListKeys(args)) => { + spending_keys_list(ctx, args) + } + cmds::WalletMasp::FindAddrKey(cmds::MaspFindAddrKey(args)) => { + address_key_find(ctx, args) + } + }, + } + Ok(()) } - Ok(()) } /// Find shielded address or key @@ -213,8 +223,7 @@ fn spending_key_gen( let alias = alias.to_lowercase(); let password = read_and_confirm_encryption_password(unsafe_dont_encrypt); let (alias, _key) = wallet.gen_spending_key(alias, password, alias_force); - namada_apps::wallet::save(&wallet) - .unwrap_or_else(|err| eprintln!("{}", err)); + crate::wallet::save(&wallet).unwrap_or_else(|err| eprintln!("{}", err)); println!( "Successfully added a spending key with alias: \"{}\"", alias @@ -248,8 +257,7 @@ fn payment_address_gen( eprintln!("Payment address not added"); cli::safe_exit(1); }); - namada_apps::wallet::save(&wallet) - .unwrap_or_else(|err| eprintln!("{}", err)); + crate::wallet::save(&wallet).unwrap_or_else(|err| eprintln!("{}", err)); println!( "Successfully generated a payment address with the following alias: {}", alias, @@ -306,8 +314,7 @@ fn address_key_add( (alias, "payment address") } }; - namada_apps::wallet::save(&ctx.wallet) - .unwrap_or_else(|err| eprintln!("{}", err)); + crate::wallet::save(&ctx.wallet).unwrap_or_else(|err| eprintln!("{}", err)); println!( "Successfully added a {} with the following alias to wallet: {}", typ, alias, @@ -345,8 +352,7 @@ fn key_and_address_restore( println!("No changes are persisted. Exiting."); cli::safe_exit(0); }); - namada_apps::wallet::save(&wallet) - .unwrap_or_else(|err| eprintln!("{}", err)); + crate::wallet::save(&wallet).unwrap_or_else(|err| eprintln!("{}", err)); println!( "Successfully added a key and an address with alias: \"{}\"", alias @@ -387,8 +393,7 @@ fn key_and_address_gen( println!("No changes are persisted. Exiting."); cli::safe_exit(0); }); - namada_apps::wallet::save(&wallet) - .unwrap_or_else(|err| eprintln!("{}", err)); + crate::wallet::save(&wallet).unwrap_or_else(|err| eprintln!("{}", err)); println!( "Successfully added a key and an address with alias: \"{}\"", alias @@ -573,8 +578,7 @@ fn address_add(ctx: Context, args: args::AddressAdd) { eprintln!("Address not added"); cli::safe_exit(1); } - namada_apps::wallet::save(&wallet) - .unwrap_or_else(|err| eprintln!("{}", err)); + crate::wallet::save(&wallet).unwrap_or_else(|err| eprintln!("{}", err)); println!( "Successfully added a key and an address with alias: \"{}\"", args.alias.to_lowercase() diff --git a/apps/src/lib/client/rpc.rs b/apps/src/lib/client/rpc.rs index 44955967d0..a2d2ffbd50 100644 --- a/apps/src/lib/client/rpc.rs +++ b/apps/src/lib/client/rpc.rs @@ -111,7 +111,7 @@ pub async fn query_results( /// Query the specified accepted transfers from the ledger pub async fn query_transfers< C: namada::ledger::queries::Client + Sync, - U: ShieldedUtils, + U: ShieldedUtils, >( client: &C, wallet: &mut Wallet, @@ -263,7 +263,7 @@ pub async fn query_raw_bytes( /// Query token balance(s) pub async fn query_balance< C: namada::ledger::queries::Client + Sync, - U: ShieldedUtils, + U: ShieldedUtils, >( client: &C, wallet: &mut Wallet, @@ -397,7 +397,7 @@ pub async fn query_transparent_balance< /// Query the token pinned balance(s) pub async fn query_pinned_balance< C: namada::ledger::queries::Client + Sync, - U: ShieldedUtils, + U: ShieldedUtils, >( client: &C, wallet: &mut Wallet, @@ -761,7 +761,7 @@ pub async fn query_proposal( /// Query token shielded balance(s) pub async fn query_shielded_balance< C: namada::ledger::queries::Client + Sync, - U: ShieldedUtils, + U: ShieldedUtils, >( client: &C, wallet: &mut Wallet, diff --git a/apps/src/lib/client/tx.rs b/apps/src/lib/client/tx.rs index d70f8c7e6f..e2683babba 100644 --- a/apps/src/lib/client/tx.rs +++ b/apps/src/lib/client/tx.rs @@ -10,6 +10,7 @@ use borsh::{BorshDeserialize, BorshSerialize}; use data_encoding::HEXLOWER_PERMISSIVE; use masp_proofs::prover::LocalTxProver; use namada::ledger::governance::storage as gov_storage; +use namada::ledger::queries::Client; use namada::ledger::rpc::{TxBroadcastData, TxResponse}; use namada::ledger::signing::TxSigningKey; use namada::ledger::wallet::{Wallet, WalletUtils}; @@ -35,7 +36,6 @@ use crate::client::signing::find_pk; use crate::client::tx::tx::ProcessTxResponse; use crate::config::TendermintMode; use crate::facade::tendermint_rpc::endpoint::broadcast::tx_sync::Response; -use crate::facade::tendermint_rpc::HttpClient; use crate::node::ledger::tendermint_node; use crate::wallet::{gen_validator_keys, read_and_confirm_encryption_password}; @@ -463,8 +463,6 @@ impl Default for CLIShieldedUtils { #[async_trait(?Send)] impl masp::ShieldedUtils for CLIShieldedUtils { - type C = crate::facade::tendermint_rpc::HttpClient; - fn local_tx_prover(&self) -> LocalTxProver { if let Ok(params_dir) = env::var(masp::ENV_VAR_MASP_PARAMS_DIR) { let params_dir = PathBuf::from(params_dir); @@ -525,8 +523,8 @@ impl masp::ShieldedUtils for CLIShieldedUtils { } } -pub async fn submit_transfer( - client: &HttpClient, +pub async fn submit_transfer( + client: &C, mut ctx: Context, args: args::TxTransfer, ) -> Result<(), tx::Error> { diff --git a/shared/src/ledger/masp.rs b/shared/src/ledger/masp.rs index b6ccd8672b..28e1fd8e13 100644 --- a/shared/src/ledger/masp.rs +++ b/shared/src/ledger/masp.rs @@ -345,9 +345,6 @@ impl pub trait ShieldedUtils: Sized + BorshDeserialize + BorshSerialize + Default + Clone { - /// The type of the Tendermint client to make queries with - type C: crate::ledger::queries::Client + std::marker::Sync; - /// Get a MASP transaction prover fn local_tx_prover(&self) -> LocalTxProver; @@ -631,9 +628,9 @@ impl ShieldedContext { /// Fetch the current state of the multi-asset shielded pool into a /// ShieldedContext - pub async fn fetch( + pub async fn fetch( &mut self, - client: &U::C, + client: &C, sks: &[ExtendedSpendingKey], fvks: &[ViewingKey], ) { @@ -699,8 +696,8 @@ impl ShieldedContext { /// transactions as a vector. More concretely, the HEAD_TX_KEY location /// stores the index of the last accepted transaction and each transaction /// is stored at a key derived from its index. - pub async fn fetch_shielded_transfers( - client: &U::C, + pub async fn fetch_shielded_transfers( + client: &C, last_txidx: u64, ) -> BTreeMap<(BlockHeight, TxIndex), (Epoch, Transfer, Transaction)> { // The address of the MASP account @@ -710,7 +707,7 @@ impl ShieldedContext { .push(&HEAD_TX_KEY.to_owned()) .expect("Cannot obtain a storage key"); // Query for the index of the last accepted transaction - let head_txidx = query_storage_value::(client, &head_tx_key) + let head_txidx = query_storage_value::(client, &head_tx_key) .await .unwrap_or(0); let mut shielded_txs = BTreeMap::new(); @@ -723,7 +720,7 @@ impl ShieldedContext { // Obtain the current transaction let (tx_epoch, tx_height, tx_index, current_tx, current_stx) = query_storage_value::< - U::C, + C, (Epoch, BlockHeight, TxIndex, Transfer, Transaction), >(client, ¤t_tx_key) .await @@ -744,10 +741,10 @@ impl ShieldedContext { /// associated to notes, memos, and diversifiers. And the set of notes that /// we have spent are updated. The witness map is maintained to make it /// easier to construct note merkle paths in other code. See - /// . - pub async fn scan_tx( + /// + pub async fn scan_tx( &mut self, - client: &U::C, + client: &C, height: BlockHeight, index: TxIndex, epoch: Epoch, @@ -883,9 +880,9 @@ impl ShieldedContext { /// Compute the total unspent notes associated with the viewing key in the /// context. If the key is not in the context, then we do not know the /// balance and hence we return None. - pub async fn compute_shielded_balance( + pub async fn compute_shielded_balance( &mut self, - client: &U::C, + client: &C, vk: &ViewingKey, ) -> Option { // Cannot query the balance of a key that's not in the map @@ -913,9 +910,9 @@ impl ShieldedContext { /// Query the ledger for the decoding of the given asset type and cache it /// if it is found. - pub async fn decode_asset_type( + pub async fn decode_asset_type( &mut self, - client: &U::C, + client: &C, asset_type: AssetType, ) -> Option<(Address, Option, MaspDenom, Epoch)> { // Try to find the decoding in the cache @@ -938,9 +935,9 @@ impl ShieldedContext { /// Query the ledger for the conversion that is allowed for the given asset /// type and cache it. - async fn query_allowed_conversion<'a>( + async fn query_allowed_conversion<'a, C: Client + Sync>( &'a mut self, - client: &U::C, + client: &C, asset_type: AssetType, conversions: &'a mut Conversions, ) { @@ -963,9 +960,9 @@ impl ShieldedContext { /// context and express that value in terms of the currently timestamped /// asset types. If the key is not in the context, then we do not know the /// balance and hence we return None. - pub async fn compute_exchanged_balance( + pub async fn compute_exchanged_balance( &mut self, - client: &U::C, + client: &C, vk: &ViewingKey, target_epoch: Epoch, ) -> Option { @@ -993,9 +990,9 @@ impl ShieldedContext { /// the trace amount that could not be converted is moved from input to /// output. #[allow(clippy::too_many_arguments)] - async fn apply_conversion( + async fn apply_conversion( &mut self, - client: &U::C, + client: &C, conv: AllowedConversion, asset_type: (Epoch, TokenAddress, MaspDenom), value: i128, @@ -1047,9 +1044,9 @@ impl ShieldedContext { /// note of the conversions that were used. Note that this function does /// not assume that allowed conversions from the ledger are expressed in /// terms of the latest asset types. - pub async fn compute_exchanged_amount( + pub async fn compute_exchanged_amount( &mut self, - client: &U::C, + client: &C, mut input: MaspAmount, target_epoch: Epoch, mut conversions: Conversions, @@ -1156,9 +1153,9 @@ impl ShieldedContext { /// of the specified asset type. Return the total value accumulated plus /// notes and the corresponding diversifiers/merkle paths that were used to /// achieve the total value. - pub async fn collect_unspent_notes( + pub async fn collect_unspent_notes( &mut self, - client: &U::C, + client: &C, vk: &ViewingKey, target: Amount, target_epoch: Epoch, @@ -1226,8 +1223,8 @@ impl ShieldedContext { /// keys to try to decrypt the output notes. If no transaction is pinned at /// the given payment address fails with /// `PinnedBalanceError::NoTransactionPinned`. - pub async fn compute_pinned_balance( - client: &U::C, + pub async fn compute_pinned_balance( + client: &C, owner: PaymentAddress, viewing_key: &ViewingKey, ) -> Result<(Amount, Epoch), PinnedBalanceError> { @@ -1249,7 +1246,7 @@ impl ShieldedContext { .push(&(PIN_KEY_PREFIX.to_owned() + &owner.hash())) .expect("Cannot obtain a storage key"); // Obtain the transaction pointer at the key - let txidx = rpc::query_storage_value::(client, &pin_key) + let txidx = rpc::query_storage_value::(client, &pin_key) .await .ok_or(PinnedBalanceError::NoTransactionPinned)?; // Construct the key for where the pinned transaction is stored @@ -1259,7 +1256,7 @@ impl ShieldedContext { // Obtain the pointed to transaction let (tx_epoch, _tx_height, _tx_index, _tx, shielded) = rpc::query_storage_value::< - U::C, + C, (Epoch, BlockHeight, TxIndex, Transfer, Transaction), >(client, &tx_key) .await @@ -1297,9 +1294,9 @@ impl ShieldedContext { /// the epoch of the transaction or even before, so exchange all these /// amounts to the epoch of the transaction in order to get the value that /// would have been displayed in the epoch of the transaction. - pub async fn compute_exchanged_pinned_balance( + pub async fn compute_exchanged_pinned_balance( &mut self, - client: &U::C, + client: &C, owner: PaymentAddress, viewing_key: &ViewingKey, ) -> Result<(MaspAmount, Epoch), PinnedBalanceError> { @@ -1322,9 +1319,9 @@ impl ShieldedContext { /// Convert an amount whose units are AssetTypes to one whose units are /// Addresses that they decode to. All asset types not corresponding to /// the given epoch are ignored. - pub async fn decode_amount( + pub async fn decode_amount( &mut self, - client: &U::C, + client: &C, amt: Amount, target_epoch: Epoch, ) -> HashMap { @@ -1355,9 +1352,9 @@ impl ShieldedContext { /// Convert an amount whose units are AssetTypes to one whose units are /// Addresses that they decode to. - pub async fn decode_all_amounts( + pub async fn decode_all_amounts( &mut self, - client: &U::C, + client: &C, amt: Amount, ) -> MaspAmount { let mut res: HashMap<(Epoch, TokenAddress), Change> = @@ -1394,9 +1391,9 @@ impl ShieldedContext { /// understood that transparent account changes are effected only by the /// amounts and signatures specified by the containing Transfer object. #[cfg(feature = "masp-tx-gen")] - pub async fn gen_shielded_transfer( + pub async fn gen_shielded_transfer( &mut self, - client: &U::C, + client: &C, args: &args::TxTransfer, shielded_gas: bool, ) -> Result< @@ -1611,9 +1608,9 @@ impl ShieldedContext { /// transactions. If an owner is specified, then restrict the set to only /// transactions crediting/debiting the given owner. If token is specified, /// then restrict set to only transactions involving the given token. - pub async fn query_tx_deltas( + pub async fn query_tx_deltas( &mut self, - client: &U::C, + client: &C, query_owner: &Either>, query_token: &Option
, viewing_keys: &HashMap, diff --git a/shared/src/ledger/tx.rs b/shared/src/ledger/tx.rs index 36644a3e14..7bceb09a09 100644 --- a/shared/src/ledger/tx.rs +++ b/shared/src/ledger/tx.rs @@ -1241,7 +1241,7 @@ pub async fn build_ibc_transfer< /// Returns true only if a new decoding has been added to the given set. async fn add_asset_type< C: crate::ledger::queries::Client + Sync, - U: ShieldedUtils, + U: ShieldedUtils, >( asset_types: &mut HashSet<(Address, Option, MaspDenom, Epoch)>, shielded: &mut ShieldedContext, @@ -1262,7 +1262,7 @@ async fn add_asset_type< /// type information. async fn used_asset_types< C: crate::ledger::queries::Client + Sync, - U: ShieldedUtils, + U: ShieldedUtils, P, R, K, @@ -1314,7 +1314,7 @@ async fn used_asset_types< pub async fn build_transfer< C: crate::ledger::queries::Client + Sync, V: WalletUtils, - U: ShieldedUtils, + U: ShieldedUtils, >( client: &C, wallet: &mut Wallet,