hermes-cli-components 0.1.0

Implementation of an IBC Relayer in Rust, as a library
Documentation
use core::fmt::Debug;
use core::marker::PhantomData;

use cgp::prelude::*;
use hermes_error::traits::wrap::CanWrapError;
use hermes_logging_components::traits::has_logger::HasLogger;
use hermes_logging_components::traits::logger::CanLog;
use hermes_logging_components::types::level::LevelInfo;
use hermes_relayer_components::build::traits::builders::chain_builder::CanBuildChain;
use hermes_relayer_components::build::traits::builders::relay_builder::CanBuildRelay;
use hermes_relayer_components::chain::traits::types::chain_id::HasChainIdType;
use hermes_relayer_components::chain::traits::types::create_client::{
    CreateClientMessageOptionsOf, CreateClientPayloadOptionsOf, HasCreateClientMessageOptionsType,
    HasCreateClientPayloadOptionsType,
};
use hermes_relayer_components::chain::traits::types::ibc::HasIbcChainTypes;
use hermes_relayer_components::multi::traits::chain_at::{ChainAt, HasChainTypeAt};
use hermes_relayer_components::multi::types::index::Index;
use hermes_relayer_components::relay::traits::chains::HasRelayChains;
use hermes_relayer_components::relay::traits::client_creator::CanCreateClient;
use hermes_relayer_components::relay::traits::target::SourceTarget;

use crate::traits::build::{BuilderOf, CanLoadBuilder, HasBuilderType};
use crate::traits::command::CommandRunner;
use crate::traits::output::CanProduceOutput;
use crate::traits::parse::CanParseArg;

pub struct RunCreateClientCommand;

impl<App, Args, Builder, Chain, Counterparty, Relay> CommandRunner<App, Args>
    for RunCreateClientCommand
where
    App: CanLoadBuilder<Builder = Builder>
        + CanProduceOutput<Chain::ClientId>
        + HasLogger
        + CanParseCreateClientOptions<Args, 0, 1>
        + CanParseArg<Args, symbol!("target_chain_id"), Parsed = Chain::ChainId>
        + CanParseArg<Args, symbol!("counterparty_chain_id"), Parsed = Counterparty::ChainId>
        + CanRaiseError<Relay::Error>
        + CanRaiseError<Builder::Error>
        + CanWrapError<String>,
    Builder: CanBuildChain<0, Chain = Chain>
        + CanBuildChain<1, Chain = Counterparty>
        + CanBuildRelay<0, 1, Relay = Relay>,
    Chain: HasIbcChainTypes<Counterparty>
        + HasCreateClientMessageOptionsType<Counterparty>
        + HasErrorType,
    Counterparty: HasChainIdType + HasCreateClientPayloadOptionsType<Chain> + HasErrorType,
    Relay:
        HasRelayChains<SrcChain = Chain, DstChain = Counterparty> + CanCreateClient<SourceTarget>,
    Args: Async,
    Chain::CreateClientMessageOptions: Debug,
    Counterparty::CreateClientPayloadOptions: Debug,
    App::Logger: CanLog<LevelInfo>,
{
    async fn run_command(app: &App, args: &Args) -> Result<App::Output, App::Error> {
        let target_chain_id = app.parse_arg(args, PhantomData::<symbol!("target_chain_id")>)?;
        let counterparty_chain_id =
            app.parse_arg(args, PhantomData::<symbol!("counterparty_chain_id")>)?;

        let logger = app.logger();
        let builder = app.load_builder().await?;

        let target_chain = builder
            .build_chain(Index::<0>, &target_chain_id)
            .await
            .map_err(App::raise_error)?;

        let counterparty_chain = builder
            .build_chain(Index::<1>, &counterparty_chain_id)
            .await
            .map_err(App::raise_error)?;

        let (message_options, payload_options) = app
            .parse_create_client_options(args, &target_chain, &counterparty_chain)
            .await?;

        logger.log(
            &format!(
                "Creating client on target chain `{}` with counterparty chain `{}`. Create options: {:?}, {:?}",
                target_chain_id,
                counterparty_chain_id,
                message_options,
                payload_options,
            ),
            &LevelInfo).await;

        let client_id = Relay::create_client(
            SourceTarget,
            &target_chain,
            &counterparty_chain,
            &payload_options,
            &message_options,
        )
        .await
        .map_err(|e| {
            App::wrap_error(
                format!(
                    "Failed to create client on target chain {}",
                    target_chain_id
                ),
                App::raise_error(e),
            )
        })?;

        logger
            .log(
                &format!(
                    "Successfully created client {} on target chain `{}`",
                    client_id, target_chain_id
                ),
                &LevelInfo,
            )
            .await;

        Ok(app.produce_output(client_id))
    }
}

#[derive_component(CreateClientOptionsParserComponent, CreateClientOptionsParser<App>)]
#[async_trait]
pub trait CanParseCreateClientOptions<Args: Async, const TARGET: usize, const COUNTERPARTY: usize>:
    HasBuilderType<
        Builder: HasChainTypeAt<
            TARGET,
            Chain: HasCreateClientMessageOptionsType<ChainAt<BuilderOf<Self>, COUNTERPARTY>>,
        > + HasChainTypeAt<
            COUNTERPARTY,
            Chain: HasCreateClientPayloadOptionsType<ChainAt<BuilderOf<Self>, TARGET>>,
        >,
    > + HasErrorType
{
    async fn parse_create_client_options(
        &self,
        args: &Args,
        target_chain: &ChainAt<BuilderOf<Self>, TARGET>,
        counterparty_chain: &ChainAt<BuilderOf<Self>, COUNTERPARTY>,
    ) -> Result<
        (
            CreateClientMessageOptionsOf<
                ChainAt<BuilderOf<Self>, TARGET>,
                ChainAt<BuilderOf<Self>, COUNTERPARTY>,
            >,
            CreateClientPayloadOptionsOf<
                ChainAt<BuilderOf<Self>, COUNTERPARTY>,
                ChainAt<BuilderOf<Self>, TARGET>,
            >,
        ),
        Self::Error,
    >;
}