hermes_cli/commands/channel/
create.rs1use 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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[clap(
82 long = "ordering",
83 value_name = "ORDERING",
84 default_value_t = Ordering::Unordered,
85 )]
86 ordering: Ordering,
87
88 #[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}