Skip to content

Commit

Permalink
ICS29: Add fee transfer command (#2682)
Browse files Browse the repository at this point in the history
* WIP: Add `fee transfer` command

* Added config override in order to change  used to transfer tokens with fee

* Added  unit tests for command argument parsing

* Updated  command in order to send a pay message for each transfer message

* Cargo fmt and cargo clippy fixes

* Use main branch of `ibc-proto`

* Update guide templates and fix script

* Added changelog entry

* Added comments in the body of the 'check_can_send_on_channel' function

* Moved imports to top level in 'cli_utils.rs'

* Removed branch specification for ibc-proto repo in no-std-check Cargo.toml

* Added warning when not GNU sed is used

Co-authored-by: Luca Joss <luca@informal.systems>
  • Loading branch information
romac and ljoss17 authored Oct 10, 2022
1 parent 36bea73 commit 4878f8b
Show file tree
Hide file tree
Showing 21 changed files with 1,091 additions and 136 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- New command `fee transfer` which transfers tokens with fees
([#2714](https://github.com/informalsystems/ibc-rs/issues/2714))
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ exclude = [
]

[patch.crates-io]
ibc-proto = { git = "https://github.com/cosmos/ibc-proto-rs", branch = "romac/ibc-v5" }
ibc-proto = { git = "https://github.com/cosmos/ibc-proto-rs" }
# tendermint = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" }
# tendermint-rpc = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" }
# tendermint-proto = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" }
Expand Down
2 changes: 1 addition & 1 deletion ci/no-std-check/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ substrate-std = [
]

[patch.crates-io]
ibc-proto = { git = "https://github.com/cosmos/ibc-proto-rs", branch = "romac/ibc-v5" }
ibc-proto = { git = "https://github.com/cosmos/ibc-proto-rs" }
# tendermint = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" }
# tendermint-proto = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" }
# tendermint-light-client-verifier = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" }
88 changes: 86 additions & 2 deletions crates/relayer-cli/src/cli_utils.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
//! Various utilities for the Hermes CLI
use alloc::sync::Arc;

use eyre::eyre;
use tokio::runtime::Runtime as TokioRuntime;
use tracing::debug;

use ibc::core::ics02_client::client_state::ClientState;
use ibc::core::ics24_host::identifier::{ChainId, ChannelId, PortId};

use ibc_relayer::chain::requests::{
IncludeProof, QueryChannelRequest, QueryClientStateRequest, QueryConnectionRequest, QueryHeight,
};
use ibc_relayer::{
chain::{
counterparty::{channel_connection_client, ChannelConnectionClient},
Expand Down Expand Up @@ -102,3 +105,84 @@ pub fn spawn_chain_counterparty<Chain: ChainHandle>(
channel_connection_client,
))
}

/// Check that the relayer can send on the given channel and ensure that channels and chain identifiers match.
/// To do this, fetch from the source chain the channel end, then the associated connection
/// end, and then the underlying client state; finally, check that this client is verifying
/// headers for the destination chain.
pub fn check_can_send_on_channel<Chain: ChainHandle>(
src_chain: &Chain,
src_channel_id: &ChannelId,
src_port_id: &PortId,
dst_chain_id: &ChainId,
) -> Result<(), eyre::Report> {
// Fetch from the source chain the channel end and check that it is open.
let (channel_end_src, _) = src_chain.query_channel(
QueryChannelRequest {
port_id: src_port_id.clone(),
channel_id: src_channel_id.clone(),
height: QueryHeight::Latest,
},
IncludeProof::No,
)?;

if !channel_end_src.is_open() {
return Err(eyre!(
"the requested port/channel ('{}'/'{}') on chain id '{}' is in state '{}'; expected 'open' state",
src_port_id,
src_channel_id,
src_chain.id(),
channel_end_src.state
));
}

let conn_id = match channel_end_src.connection_hops.first() {
Some(cid) => cid,
None => {
return Err(eyre!(
"could not retrieve the connection hop underlying port/channel '{}'/'{}' on chain '{}'",
src_port_id, src_channel_id, src_chain.id()
));
}
};

// Fetch the associated connection end.
let (conn_end, _) = src_chain.query_connection(
QueryConnectionRequest {
connection_id: conn_id.clone(),
height: QueryHeight::Latest,
},
IncludeProof::No,
)?;

debug!("connection hop underlying the channel: {:?}", conn_end);

// Fetch the underlying client state.
let (src_chain_client_state, _) = src_chain.query_client_state(
QueryClientStateRequest {
client_id: conn_end.client_id().clone(),
height: QueryHeight::Latest,
},
IncludeProof::No,
)?;

debug!(
"client state underlying the channel: {:?}",
src_chain_client_state
);

// Check that this client is verifying headers for the destination chain.
if &src_chain_client_state.chain_id() != dst_chain_id {
return Err(eyre!(
"the requested port/channel ('{}'/'{}') provides a path from chain '{}' to \
chain '{}' (not to the destination chain '{}'). Bailing due to mismatching arguments.",
src_port_id,
src_channel_id,
src_chain.id(),
src_chain_client_state.chain_id(),
dst_chain_id
));
}

Ok(())
}
1 change: 1 addition & 0 deletions crates/relayer-cli/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ impl Configurable<Config> for CliCmd {

match self {
CliCmd::Tx(cmd) => cmd.override_config(config),
CliCmd::Fee(cmd) => cmd.override_config(config),
// CliCmd::Help(cmd) => cmd.override_config(config),
// CliCmd::Keys(cmd) => cmd.override_config(config),
// CliCmd::Create(cmd) => cmd.override_config(config),
Expand Down
22 changes: 19 additions & 3 deletions crates/relayer-cli/src/commands/fee.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,35 @@
//! `fee` subcommand
use abscissa_core::clap::Parser;
use abscissa_core::{Command, Runnable};
use abscissa_core::{config::Override, Command, Runnable};
use ibc_relayer::config::Config;

use register_counterparty_payee::RegisterCounterpartyPayeeCmd;
use register_payee::RegisterPayeeCmd;
use self::register_counterparty_payee::RegisterCounterpartyPayeeCmd;
use self::register_payee::RegisterPayeeCmd;
use self::transfer::FeeTransferCmd;

pub mod register_counterparty_payee;
pub mod register_payee;
pub mod transfer;

#[allow(clippy::large_enum_variant)]
#[derive(Command, Debug, Parser, Runnable)]
pub enum FeeCmd {
/// Register a payee for a channel
RegisterPayee(RegisterPayeeCmd),

/// Register a counterparty payee for a channel
RegisterCounterpartyPayee(RegisterCounterpartyPayeeCmd),

/// Perform a token transfer supported with a fee
Transfer(FeeTransferCmd),
}

impl Override<Config> for FeeCmd {
fn override_config(&self, config: Config) -> Result<Config, abscissa_core::FrameworkError> {
match self {
Self::Transfer(cmd) => cmd.override_config(config),
_ => Ok(config),
}
}
}
Loading

0 comments on commit 4878f8b

Please sign in to comment.