hermes_cli/commands/keys/
delete.rs

1use 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            // This case should never trigger.
54            // The 'required' parameter for the flags will trigger an error if both flags have not been given.
55            // And the 'group' parameter for the flags will trigger an error if both flags are given.
56            _ => 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}