hermes_cli_components/impls/commands/client/
create.rs1use core::fmt::Debug;
2use core::marker::PhantomData;
3
4use cgp::prelude::*;
5use hermes_error::traits::wrap::CanWrapError;
6use hermes_logging_components::traits::has_logger::HasLogger;
7use hermes_logging_components::traits::logger::CanLog;
8use hermes_logging_components::types::level::LevelInfo;
9use hermes_relayer_components::build::traits::builders::chain_builder::CanBuildChain;
10use hermes_relayer_components::build::traits::builders::relay_builder::CanBuildRelay;
11use hermes_relayer_components::chain::traits::types::chain_id::HasChainIdType;
12use hermes_relayer_components::chain::traits::types::create_client::{
13 CreateClientMessageOptionsOf, CreateClientPayloadOptionsOf, HasCreateClientMessageOptionsType,
14 HasCreateClientPayloadOptionsType,
15};
16use hermes_relayer_components::chain::traits::types::ibc::HasIbcChainTypes;
17use hermes_relayer_components::multi::traits::chain_at::{ChainAt, HasChainTypeAt};
18use hermes_relayer_components::multi::types::index::Index;
19use hermes_relayer_components::relay::traits::chains::HasRelayChains;
20use hermes_relayer_components::relay::traits::client_creator::CanCreateClient;
21use hermes_relayer_components::relay::traits::target::SourceTarget;
22
23use crate::traits::build::{BuilderOf, CanLoadBuilder, HasBuilderType};
24use crate::traits::command::CommandRunner;
25use crate::traits::output::CanProduceOutput;
26use crate::traits::parse::CanParseArg;
27
28pub struct RunCreateClientCommand;
29
30impl<App, Args, Builder, Chain, Counterparty, Relay> CommandRunner<App, Args>
31 for RunCreateClientCommand
32where
33 App: CanLoadBuilder<Builder = Builder>
34 + CanProduceOutput<Chain::ClientId>
35 + HasLogger
36 + CanParseCreateClientOptions<Args, 0, 1>
37 + CanParseArg<Args, symbol!("target_chain_id"), Parsed = Chain::ChainId>
38 + CanParseArg<Args, symbol!("counterparty_chain_id"), Parsed = Counterparty::ChainId>
39 + CanRaiseError<Relay::Error>
40 + CanRaiseError<Builder::Error>
41 + CanWrapError<String>,
42 Builder: CanBuildChain<0, Chain = Chain>
43 + CanBuildChain<1, Chain = Counterparty>
44 + CanBuildRelay<0, 1, Relay = Relay>,
45 Chain: HasIbcChainTypes<Counterparty>
46 + HasCreateClientMessageOptionsType<Counterparty>
47 + HasErrorType,
48 Counterparty: HasChainIdType + HasCreateClientPayloadOptionsType<Chain> + HasErrorType,
49 Relay:
50 HasRelayChains<SrcChain = Chain, DstChain = Counterparty> + CanCreateClient<SourceTarget>,
51 Args: Async,
52 Chain::CreateClientMessageOptions: Debug,
53 Counterparty::CreateClientPayloadOptions: Debug,
54 App::Logger: CanLog<LevelInfo>,
55{
56 async fn run_command(app: &App, args: &Args) -> Result<App::Output, App::Error> {
57 let target_chain_id = app.parse_arg(args, PhantomData::<symbol!("target_chain_id")>)?;
58 let counterparty_chain_id =
59 app.parse_arg(args, PhantomData::<symbol!("counterparty_chain_id")>)?;
60
61 let logger = app.logger();
62 let builder = app.load_builder().await?;
63
64 let target_chain = builder
65 .build_chain(Index::<0>, &target_chain_id)
66 .await
67 .map_err(App::raise_error)?;
68
69 let counterparty_chain = builder
70 .build_chain(Index::<1>, &counterparty_chain_id)
71 .await
72 .map_err(App::raise_error)?;
73
74 let (message_options, payload_options) = app
75 .parse_create_client_options(args, &target_chain, &counterparty_chain)
76 .await?;
77
78 logger.log(
79 &format!(
80 "Creating client on target chain `{}` with counterparty chain `{}`. Create options: {:?}, {:?}",
81 target_chain_id,
82 counterparty_chain_id,
83 message_options,
84 payload_options,
85 ),
86 &LevelInfo).await;
87
88 let client_id = Relay::create_client(
89 SourceTarget,
90 &target_chain,
91 &counterparty_chain,
92 &payload_options,
93 &message_options,
94 )
95 .await
96 .map_err(|e| {
97 App::wrap_error(
98 format!(
99 "Failed to create client on target chain {}",
100 target_chain_id
101 ),
102 App::raise_error(e),
103 )
104 })?;
105
106 logger
107 .log(
108 &format!(
109 "Successfully created client {} on target chain `{}`",
110 client_id, target_chain_id
111 ),
112 &LevelInfo,
113 )
114 .await;
115
116 Ok(app.produce_output(client_id))
117 }
118}
119
120#[derive_component(CreateClientOptionsParserComponent, CreateClientOptionsParser<App>)]
121#[async_trait]
122pub trait CanParseCreateClientOptions<Args: Async, const TARGET: usize, const COUNTERPARTY: usize>:
123 HasBuilderType<
124 Builder: HasChainTypeAt<
125 TARGET,
126 Chain: HasCreateClientMessageOptionsType<ChainAt<BuilderOf<Self>, COUNTERPARTY>>,
127 > + HasChainTypeAt<
128 COUNTERPARTY,
129 Chain: HasCreateClientPayloadOptionsType<ChainAt<BuilderOf<Self>, TARGET>>,
130 >,
131 > + HasErrorType
132{
133 async fn parse_create_client_options(
134 &self,
135 args: &Args,
136 target_chain: &ChainAt<BuilderOf<Self>, TARGET>,
137 counterparty_chain: &ChainAt<BuilderOf<Self>, COUNTERPARTY>,
138 ) -> Result<
139 (
140 CreateClientMessageOptionsOf<
141 ChainAt<BuilderOf<Self>, TARGET>,
142 ChainAt<BuilderOf<Self>, COUNTERPARTY>,
143 >,
144 CreateClientPayloadOptionsOf<
145 ChainAt<BuilderOf<Self>, COUNTERPARTY>,
146 ChainAt<BuilderOf<Self>, TARGET>,
147 >,
148 ),
149 Self::Error,
150 >;
151}