hermes_cli_components/impls/commands/client/
create.rs

1use 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}