hermes_cli/commands/channel/
create.rs

1use hermes_cli_components::traits::build::CanLoadBuilder;
2use hermes_cli_framework::command::CommandRunner;
3use hermes_cli_framework::output::Output;
4use hermes_cosmos_chain_components::types::channel::CosmosInitChannelOptions;
5use hermes_relayer_components::build::traits::builders::relay_builder::CanBuildRelay;
6use hermes_relayer_components::multi::types::index::Twindex;
7use hermes_relayer_components::relay::impls::channel::bootstrap::CanBootstrapChannel;
8use ibc_relayer::channel::version::Version;
9use ibc_relayer_types::core::ics04_channel::channel::Ordering;
10use ibc_relayer_types::core::ics24_host::identifier::{ChainId, ClientId, ConnectionId, PortId};
11use oneline_eyre::eyre::eyre;
12use tracing::info;
13
14use crate::contexts::app::HermesApp;
15use crate::Result;
16
17#[derive(Debug, clap::Parser)]
18pub struct ChannelCreate {
19    /// Identifier of chain A
20    #[clap(
21        long = "chain-a",
22        required = true,
23        value_name = "CHAIN_ID_A",
24        help_heading = "REQUIRED"
25    )]
26    chain_id_a: ChainId,
27
28    /// Identifier of client A
29    #[clap(
30        long = "client-a",
31        required = true,
32        value_name = "CLIENT_ID_A",
33        help_heading = "REQUIRED"
34    )]
35    client_id_a: ClientId,
36
37    /// Identifier of the connection on A
38    #[clap(
39        long = "connection-a",
40        required = true,
41        value_name = "CONNECTION_ID_A",
42        help_heading = "REQUIRED"
43    )]
44    connection_id_a: ConnectionId,
45
46    /// Port identifier on chain A
47    #[clap(
48        long = "port-a",
49        value_name = "PORT_ID_A",
50        default_value_t = PortId::transfer(),
51    )]
52    port_id_a: PortId,
53
54    /// Identifier of chain B
55    #[clap(
56        long = "chain-b",
57        required = true,
58        value_name = "CHAIN_ID_B",
59        help_heading = "REQUIRED"
60    )]
61    chain_id_b: ChainId,
62
63    /// Identifier of client B
64    #[clap(
65        long = "client-b",
66        required = true,
67        value_name = "CLIENT_ID_B",
68        help_heading = "REQUIRED"
69    )]
70    client_id_b: ClientId,
71
72    /// Port identifier on chain B
73    #[clap(
74        long = "port-b",
75        value_name = "PORT_ID_B",
76        default_value_t = PortId::transfer(),
77    )]
78    port_id_b: PortId,
79
80    /// Ordering of the channel
81    #[clap(
82        long = "ordering",
83        value_name = "ORDERING",
84        default_value_t = Ordering::Unordered,
85    )]
86    ordering: Ordering,
87
88    /// Version of the channel
89    #[clap(
90        long = "version",
91        value_name = "VERSION",
92        default_value_t = Version::ics20(),
93    )]
94    version: Version,
95}
96
97impl CommandRunner<HermesApp> for ChannelCreate {
98    async fn run(&self, app: &HermesApp) -> Result<Output> {
99        let builder = app.load_builder().await?;
100
101        let relay = builder
102            .build_relay(
103                Twindex::<0, 1>,
104                &self.chain_id_a,
105                &self.chain_id_b,
106                &self.client_id_a,
107                &self.client_id_b,
108            )
109            .await
110            .map_err(|e| eyre!("Failed to build relay: {e}"))?;
111
112        let options = CosmosInitChannelOptions {
113            ordering: self.ordering,
114            connection_hops: vec![self.connection_id_a.clone()],
115            channel_version: self.version.clone(),
116        };
117
118        info!(
119            ?options,
120            "Creating channel between {}:{} and {}:{} on connection {}...",
121            self.chain_id_a,
122            self.client_id_a,
123            self.chain_id_b,
124            self.client_id_b,
125            self.connection_id_a,
126        );
127
128        let (channel_id_a, channel_id_b) = relay
129            .bootstrap_channel(&self.port_id_a, &self.port_id_b, &options)
130            .await
131            .map_err(|e| eyre!("Failed to create channel: channel handshake failed: {e}"))?;
132
133        info!(
134            %channel_id_a, %channel_id_b,
135            "Channel successfully created between {} and {}",
136            self.chain_id_a, self.chain_id_b,
137        );
138
139        Ok(Output::success_msg("Done"))
140    }
141}