hermes_cli/commands/keys/
delete.rs1use hermes_cli_components::traits::build::CanLoadBuilder;
2use hermes_cli_framework::command::CommandRunner;
3use hermes_cli_framework::output::Output;
4use ibc_relayer::chain::cosmos::config::CosmosSdkConfig;
5use ibc_relayer::keyring::{KeyRing, Store};
6use ibc_relayer_types::core::ics24_host::identifier::ChainId;
7use oneline_eyre::eyre::{eyre, Context};
8use tracing::warn;
9
10use crate::contexts::app::HermesApp;
11
12#[derive(Debug, clap::Parser)]
13#[clap(
14 override_usage = "hermes keys delete --chain <CHAIN_ID> --key-name <KEY_NAME>
15
16 hermes keys delete --chain <CHAIN_ID> --all"
17)]
18pub struct KeysDeleteCmd {
19 #[clap(
20 long = "chain",
21 required = true,
22 value_name = "CHAIN_ID",
23 help_heading = "FLAGS",
24 help = "Identifier of the chain"
25 )]
26 chain_id: ChainId,
27
28 #[clap(
29 long = "key-name",
30 required = true,
31 value_name = "KEY_NAME",
32 group = "delete_mode",
33 help_heading = "FLAGS",
34 help = "Name of the key"
35 )]
36 key_name: Option<String>,
37
38 #[clap(
39 long = "all",
40 required = true,
41 group = "delete_mode",
42 help_heading = "FLAGS",
43 help = "Delete all keys"
44 )]
45 all: bool,
46}
47
48impl KeysDeleteCmd {
49 fn options(&self, config: &CosmosSdkConfig) -> eyre::Result<KeysDeleteOptions<'_>> {
50 let id = match (self.all, &self.key_name) {
51 (true, None) => KeysDeleteId::All,
52 (false, Some(ref key_name)) => KeysDeleteId::Named(key_name),
53 _ => Output::error("--key-name and --all can't both be set or both None".to_string())
57 .exit(),
58 };
59
60 Ok(KeysDeleteOptions {
61 config: config.clone(),
62 id,
63 })
64 }
65}
66
67#[derive(Clone, Debug)]
68struct KeysDeleteOptions<'a> {
69 id: KeysDeleteId<'a>,
70 config: CosmosSdkConfig,
71}
72
73#[derive(Clone, Debug)]
74enum KeysDeleteId<'a> {
75 All,
76 Named(&'a str),
77}
78
79impl CommandRunner<HermesApp> for KeysDeleteCmd {
80 async fn run(&self, app: &HermesApp) -> hermes_cli_framework::Result<Output> {
81 let builder = app.load_builder().await?;
82
83 let chain_config = builder
84 .config_map
85 .get(&self.chain_id)
86 .ok_or_else(|| eyre!("chain `{}` not found in configuration file", self.chain_id))?;
87
88 let opts = match self.options(chain_config) {
89 Err(e) => Output::error(e).exit(),
90 Ok(opts) => opts,
91 };
92
93 match opts.id {
94 KeysDeleteId::All => match delete_all_keys(&opts.config) {
95 Ok(_) => {
96 Output::success(format!("Removed all keys on chain `{}`", opts.config.id,))
97 .exit()
98 }
99 Err(e) => Output::error(format!(
100 "`keys delete` command failed to delete all keys: {}",
101 e
102 ))
103 .exit(),
104 },
105 KeysDeleteId::Named(key_name) => match delete_key(&opts.config, key_name) {
106 Ok(_) => Output::success_msg(format!(
107 "Removed key `{key_name}` on chain `{}`",
108 opts.config.id
109 ))
110 .exit(),
111 Err(e) => Output::error(format!(
112 "`keys delete` command failed to delete key `{key_name}`: {}",
113 e
114 ))
115 .exit(),
116 },
117 }
118 }
119}
120
121fn delete_key(config: &CosmosSdkConfig, key_name: &str) -> eyre::Result<()> {
122 let mut keyring = KeyRing::new_secp256k1(
123 Store::Test,
124 &config.account_prefix,
125 &config.id,
126 &config.key_store_folder,
127 )?;
128
129 keyring.remove_key(key_name)?;
130
131 Ok(())
132}
133
134fn delete_all_keys(config: &CosmosSdkConfig) -> eyre::Result<()> {
135 let mut keyring = KeyRing::new_secp256k1(
136 Store::Test,
137 &config.account_prefix,
138 &config.id,
139 &config.key_store_folder,
140 )?;
141
142 let keys = keyring
143 .keys()
144 .wrap_err("failed to fetch keys from keyring")?;
145
146 for (key_name, _) in keys {
147 if let Err(e) = keyring.remove_key(&key_name) {
148 warn!("failed to remove key `{key_name}` from keyring: {e}");
149 continue;
150 }
151 }
152
153 Ok(())
154}