ibc-relayer-cli 1.13.2

Hermes is an IBC Relayer written in Rust
use abscissa_core::clap::Parser;
use abscissa_core::{Command, Runnable};
use core::str::FromStr;
use ibc_relayer::chain::handle::ChainHandle;
use ibc_relayer::chain::tracking::TrackedMsgs;
use ibc_relayer_types::applications::ics29_fee::msgs::register_payee::build_register_counterparty_payee_message;
use ibc_relayer_types::core::ics24_host::identifier::{ChainId, ChannelId, PortId};
use ibc_relayer_types::signer::Signer;

use crate::application::app_config;
use crate::cli_utils::spawn_chain_runtime;
use crate::conclude::{exit_with_unrecoverable_error, Output};
use crate::error::Error;

#[derive(Clone, Command, Debug, Parser, PartialEq, Eq)]
pub struct RegisterCounterpartyPayeeCmd {
    #[clap(
        long = "chain",
        required = true,
        value_name = "CHAIN_ID",
        help_heading = "FLAGS",
        help = "Identifier of the chain"
    )]
    chain_id: ChainId,

    #[clap(
        long = "channel",
        visible_alias = "chan",
        required = true,
        value_name = "CHANNEL_ID",
        help_heading = "FLAGS",
        help = "Identifier of the channel"
    )]
    channel_id: ChannelId,

    #[clap(
        long = "port",
        required = true,
        value_name = "PORT_ID",
        help_heading = "FLAGS",
        help = "Identifier of the port"
    )]
    port_id: PortId,

    #[clap(
        long = "counterparty-payee",
        required = true,
        value_name = "COUNTERPARTY_PAYEE_ADDRESS",
        help_heading = "FLAGS",
        help = "Address of the counterparty payee.\n\nNote that there exists a configuration \
        parameter `auto_register_counterparty_payee` that can be enabled in order to have \
        Hermes automatically register the counterparty payee on the destination chain to the \
        relayer's address on the source chain. This option can be used for simple configuration \
        of the relayer to receive fees for relaying RecvPackets on fee-enabled channels."
    )]
    counterparty_payee_address: String,
}

impl Runnable for RegisterCounterpartyPayeeCmd {
    fn run(&self) {
        run_register_counterparty_payee_command(
            &self.chain_id,
            &self.channel_id,
            &self.port_id,
            &self.counterparty_payee_address,
        )
        .unwrap_or_else(exit_with_unrecoverable_error);

        Output::success_msg("Successfully registered counterparty payee").exit()
    }
}

fn run_register_counterparty_payee_command(
    chain_id: &ChainId,
    channel_id: &ChannelId,
    port_id: &PortId,
    counterparty_payee_address: &str,
) -> Result<(), Error> {
    let counterparty_payee = Signer::from_str(counterparty_payee_address).map_err(Error::signer)?;

    let config = app_config();

    let chain_handle = spawn_chain_runtime(&config, chain_id)?;

    let signer = chain_handle.get_signer().map_err(Error::relayer)?;

    let message = build_register_counterparty_payee_message(
        &signer,
        &counterparty_payee,
        channel_id,
        port_id,
    )
    .map_err(Error::fee)?;

    let messages = TrackedMsgs::new_static(vec![message], "cli");

    chain_handle
        .send_messages_and_wait_commit(messages)
        .map_err(Error::relayer)?;

    Ok(())
}

#[cfg(test)]
mod tests {

    use super::RegisterCounterpartyPayeeCmd;

    use abscissa_core::clap::Parser;
    use std::str::FromStr;

    use ibc_relayer_types::core::ics24_host::identifier::{ChainId, ChannelId, PortId};

    #[test]
    fn test_register_counterparty_payee() {
        assert_eq!(
            RegisterCounterpartyPayeeCmd {
                chain_id: ChainId::from_string("chain_a"),
                channel_id: ChannelId::from_str("channel_a").unwrap(),
                port_id: PortId::from_str("port_a").unwrap(),
                counterparty_payee_address: "counterparty_address_hash".to_owned(),
            },
            RegisterCounterpartyPayeeCmd::parse_from([
                "test",
                "--chain",
                "chain_a",
                "--channel",
                "channel_a",
                "--port",
                "port_a",
                "--counterparty-payee",
                "counterparty_address_hash"
            ])
        )
    }

    #[test]
    fn test_register_counterparty_payee_alias() {
        assert_eq!(
            RegisterCounterpartyPayeeCmd {
                chain_id: ChainId::from_string("chain_a"),
                channel_id: ChannelId::from_str("channel_a").unwrap(),
                port_id: PortId::from_str("port_a").unwrap(),
                counterparty_payee_address: "counterparty_address_hash".to_owned(),
            },
            RegisterCounterpartyPayeeCmd::parse_from([
                "test",
                "--chain",
                "chain_a",
                "--chan",
                "channel_a",
                "--port",
                "port_a",
                "--counterparty-payee",
                "counterparty_address_hash"
            ])
        )
    }

    #[test]
    fn test_register_counterparty_payee_no_counterparty_payee() {
        assert!(RegisterCounterpartyPayeeCmd::try_parse_from([
            "test",
            "--chain",
            "chain_a",
            "--channel",
            "channel_a",
            "--port",
            "port_a"
        ])
        .is_err())
    }

    #[test]
    fn test_register_counterparty_payee_no_port() {
        assert!(RegisterCounterpartyPayeeCmd::try_parse_from([
            "test",
            "--chain",
            "chain_a",
            "--channel",
            "channel_a",
            "--counterparty-payee",
            "counterparty_address_hash"
        ])
        .is_err())
    }

    #[test]
    fn test_register_counterparty_payee_no_channel() {
        assert!(RegisterCounterpartyPayeeCmd::try_parse_from([
            "test",
            "--chain",
            "chain_a",
            "--port",
            "port_a",
            "--counterparty-payee",
            "counterparty_address_hash"
        ])
        .is_err())
    }

    #[test]
    fn test_register_counterparty_payee_no_chain() {
        assert!(RegisterCounterpartyPayeeCmd::try_parse_from([
            "test",
            "--channel",
            "channel_a",
            "--port",
            "port_a",
            "--counterparty-payee",
            "counterparty_address_hash"
        ])
        .is_err())
    }
}