hermes_cli/commands/keys/
balance.rs1use core::fmt::Write;
2
3use hermes_cli_components::traits::build::CanLoadBuilder;
4use hermes_cli_framework::command::CommandRunner;
5use hermes_cli_framework::output::{json, Output};
6use ibc_relayer::chain::handle::ChainHandle;
7use ibc_relayer::config::ChainConfig;
8use ibc_relayer_types::core::ics24_host::identifier::ChainId;
9use oneline_eyre::eyre::eyre;
10
11use crate::contexts::app::HermesApp;
12
13#[derive(Debug, clap::Parser)]
23pub struct KeysBalanceCmd {
24 #[clap(
25 long = "chain",
26 required = true,
27 value_name = "CHAIN_ID",
28 help_heading = "REQUIRED",
29 help = "Identifier of the chain"
30 )]
31 chain_id: ChainId,
32
33 #[clap(
34 long = "key-name",
35 value_name = "KEY_NAME",
36 help = "(optional) name of the key (defaults to the `key_name` defined in the config)"
37 )]
38 key_name: Option<String>,
39
40 #[clap(
41 long = "denom",
42 value_name = "DENOM",
43 help = "(optional) query the balance for the given denom (defaults to the `denom` defined in the config for the gas price)"
44 )]
45 denom: Option<String>,
46
47 #[clap(
48 long = "all",
49 help = "(optional) query the balance for all denom. This flag overwrites the `--denom` flag (defaults to false)"
50 )]
51 all: bool,
52}
53
54impl CommandRunner<HermesApp> for KeysBalanceCmd {
55 async fn run(&self, app: &HermesApp) -> hermes_cli_framework::Result<Output> {
56 let builder = app.load_builder().await?;
57
58 let chain = builder.build_chain(&self.chain_id).await?;
59 let key_name = self.key_name.clone();
60
61 if self.all {
62 match get_balances(chain.handle.clone(), key_name) {
63 Ok(success_msg) => success_msg.exit(),
64 Err(e) => Output::error(format!("`keys balance` command failed: {}", e)).exit(),
65 }
66 } else {
67 match get_balance(chain.handle.clone(), key_name, self.denom.clone()) {
68 Ok(success_msg) => success_msg.exit(),
69 Err(e) => Output::error(format!("`keys balance` command failed: {}", e)).exit(),
70 }
71 }
72 }
73}
74
75fn get_balance(
76 chain: impl ChainHandle,
77 key_name: Option<String>,
78 denom: Option<String>,
79) -> eyre::Result<Output> {
80 match chain.query_balance(key_name.clone(), denom) {
81 Ok(balance) if json() => Ok(Output::success(balance)),
82 Ok(balance) => {
83 let key_name = key_name.unwrap_or_else(|| {
85 let chain_config = chain.config().expect(
86 "`keys balance` command failed due to an error retrieving chain config",
87 );
88
89 let ChainConfig::CosmosSdk(cosmos_config) = chain_config;
90
91 cosmos_config.key_name
92 });
93
94 Ok(Output::success_msg(format!(
95 "balance for key `{key_name}`: {} {}",
96 balance.amount, balance.denom
97 )))
98 }
99 Err(e) => Err(e.1.wrap_err("`keys balance` command failed")),
100 }
101}
102
103fn get_balances(chain: impl ChainHandle, key_name: Option<String>) -> eyre::Result<Output> {
104 match chain.query_all_balances(key_name.clone()) {
105 Ok(balances) if json() => Ok(Output::success(balances)),
106 Ok(balances) => {
107 let key_name = key_name.unwrap_or_else(|| {
109 let chain_config = chain.config().expect(
110 "`keys balance` command failed due to an error retrieving chain config",
111 );
112
113 let ChainConfig::CosmosSdk(cosmos_config) = chain_config;
114
115 cosmos_config.key_name
116 });
117
118 let mut pretty_output = format!("Balances for key `{key_name}`:");
119
120 for balance in balances {
121 write!(pretty_output, "\n\t{} {}", balance.amount, balance.denom)
122 .map_err(|_| eyre!("failed to write balance output"))?;
123 }
124
125 Ok(Output::success_msg(pretty_output))
126 }
127 Err(e) => Err(e
128 .1
129 .wrap_err("`keys balance` command failed due to a problem querying the balance")),
130 }
131}