Skip to content

Commit

Permalink
Basic transfer with pay packet is working
Browse files Browse the repository at this point in the history
  • Loading branch information
soareschen committed May 11, 2022
1 parent 9bbc35a commit 099d9fa
Show file tree
Hide file tree
Showing 14 changed files with 254 additions and 32 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions modules/src/applications/ics29_fee/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mod msgs;
3 changes: 3 additions & 0 deletions modules/src/applications/ics29_fee/msgs/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod pay_packet;

pub use pay_packet::*;
21 changes: 21 additions & 0 deletions modules/src/applications/ics29_fee/msgs/pay_packet.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use ibc_proto::ibc::applications::fee::v1::MsgPayPacketFee;

use crate::prelude::*;
use crate::tx_msg::Msg;

pub const TYPE_URL: &str = "/ibc.applications.transfer.v1.MsgTransfer";

pub enum Error {}

impl Msg for MsgPayPacketFee {
type ValidationError = Error;
type Raw = MsgPayPacketFee;

fn route(&self) -> String {
crate::keys::ROUTER_KEY.to_string()
}

fn type_url(&self) -> String {
TYPE_URL.to_string()
}
}
1 change: 1 addition & 0 deletions modules/src/applications/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! Various packet encoding semantics which underpin the various types of transactions.
pub mod ics20_fungible_token_transfer;
pub mod ics29_fee;
5 changes: 5 additions & 0 deletions proto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ pub mod ibc {
include_proto!("ibc.applications.transfer.v1.rs");
}
}
pub mod fee {
pub mod v1 {
include_proto!("ibc.applications.fee.v1.rs");
}
}
pub mod interchain_accounts {
pub mod v1 {
include_proto!("ibc.applications.interchain_accounts.v1.rs");
Expand Down
24 changes: 11 additions & 13 deletions relayer/src/transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use ibc::signer::Signer;
use ibc::timestamp::{Timestamp, TimestampOverflowError};
use ibc::tx_msg::Msg;
use ibc::Height;
use ibc_proto::cosmos::base::v1beta1::Coin;
use ibc_proto::google::protobuf::Any;
use uint::FromStrRadixErr;

Expand Down Expand Up @@ -150,7 +151,7 @@ pub fn build_transfer_message(
let msg = MsgTransfer {
source_port: packet_src_port_id,
source_channel: packet_src_channel_id,
token: Some(ibc_proto::cosmos::base::v1beta1::Coin {
token: Some(Coin {
denom,
amount: amount.to_string(),
}),
Expand Down Expand Up @@ -185,21 +186,18 @@ pub fn build_and_send_transfer_messages<SrcChain: ChainHandle, DstChain: ChainHa
&destination_chain_status,
)?;

let msg = MsgTransfer {
source_port: opts.packet_src_port_id.clone(),
source_channel: opts.packet_src_channel_id,
token: Some(ibc_proto::cosmos::base::v1beta1::Coin {
denom: opts.denom.clone(),
amount: opts.amount.to_string(),
}),
let message = build_transfer_message(
opts.packet_src_port_id.clone(),
opts.packet_src_channel_id,
opts.amount,
opts.denom.clone(),
sender,
receiver,
timeout_height: timeout.timeout_height,
timeout_timestamp: timeout.timeout_timestamp,
};
timeout.timeout_height,
timeout.timeout_timestamp,
);

let raw_msg = msg.to_any();
let msgs = vec![raw_msg; opts.number_msgs];
let msgs = vec![message; opts.number_msgs];

let events = packet_src_chain
.send_messages_and_wait_commit(TrackedMsgs::new(msgs, "ft-transfer"))
Expand Down
88 changes: 85 additions & 3 deletions tools/integration-test/src/tests/fee_middleware.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use ibc::core::ics04_channel::Version;
use ibc_test_framework::prelude::*;
use ibc_test_framework::relayer::fee::ibc_token_transfer_with_fee;

#[test]
fn test_channel_with_fee() -> Result<(), Error> {
Expand All @@ -19,9 +20,90 @@ impl BinaryChannelTest for ChannelWithFeeTest {
&self,
_config: &TestConfig,
_relayer: RelayerDriver,
_chains: ConnectedChains<ChainA, ChainB>,
_channel: ConnectedChannel<ChainA, ChainB>,
chains: ConnectedChains<ChainA, ChainB>,
channel: ConnectedChannel<ChainA, ChainB>,
) -> Result<(), Error> {
Ok(())
let chain_driver_a = chains.node_a.chain_driver();
let chain_driver_b = chains.node_b.chain_driver();

let denom_a = chains.node_a.denom();
let tx_config_a = chain_driver_a.tx_config();

let port_a = &channel.port_a.as_ref();
let channel_id_a = &channel.channel_id_a.as_ref();

let wallets_a = chains.node_a.wallets();
let wallets_b = chains.node_b.wallets();

let user_a1 = wallets_a.user1();
let user_b1 = wallets_b.user1();

let relayer_a = wallets_a.relayer();

let balance_a = chain_driver_a.query_balance(&user_a1.address(), &denom_a)?;

let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?;

let send_amount = 1000;
let receive_fee = 300;
let ack_fee = 200;
let timeout_fee = 100;

let total_sent = send_amount + receive_fee + ack_fee + timeout_fee;

chain_driver_a
.value()
.runtime
.block_on(ibc_token_transfer_with_fee(
&tx_config_a,
port_a,
channel_id_a,
&user_a1,
&user_b1.address(),
&denom_a,
send_amount,
receive_fee,
ack_fee,
timeout_fee,
))?;

let denom_b = derive_ibc_denom(
&channel.port_b.as_ref(),
&channel.channel_id_b.as_ref(),
&denom_a,
)?;

info!(
"User A's balance after transfer: {}",
balance_a - total_sent
);

chain_driver_a.assert_eventual_wallet_amount(
&user_a1.address(),
balance_a - total_sent,
&denom_a,
)?;

chain_driver_b.assert_eventual_wallet_amount(
&user_b1.address(),
send_amount,
&denom_b.as_ref(),
)?;

// // receive fee and timeout fee should be refunded,
// // as there is no counterparty address registered.
// chain_driver_a.assert_eventual_wallet_amount(
// &user_a1.address(),
// balance_a - send_amount - ack_fee,
// &denom_a,
// )?;

// chain_driver_a.assert_eventual_wallet_amount(
// &relayer_a.address(),
// relayer_balance_a + ack_fee,
// &denom_a,
// )?;

suspend()
}
}
1 change: 0 additions & 1 deletion tools/integration-test/src/tests/transfer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use ibc_test_framework::ibc::denom::derive_ibc_denom;
use ibc_test_framework::prelude::*;
use ibc_test_framework::util::random::random_u64_range;

Expand Down
1 change: 1 addition & 0 deletions tools/test-framework/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ sha2 = "0.10.2"
crossbeam-channel = "0.5.4"
semver = "1.0.7"
flex-error = "0.4.4"
prost = { version = "0.10" }
1 change: 1 addition & 0 deletions tools/test-framework/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub use crate::framework::nary::connection::{
pub use crate::framework::nary::node::{run_nary_node_test, NaryNodeTest, RunNaryNodeTest};
pub use crate::framework::overrides::TestOverrides;
pub use crate::framework::supervisor::RunWithSupervisor;
pub use crate::ibc::denom::derive_ibc_denom;
pub use crate::ibc::denom::Denom;
pub use crate::relayer::channel::TaggedChannelEndExt;
pub use crate::relayer::connection::{TaggedConnectionEndExt, TaggedConnectionExt};
Expand Down
96 changes: 96 additions & 0 deletions tools/test-framework/src/relayer/fee.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use ibc_proto::cosmos::base::v1beta1::Coin;
use ibc_proto::google::protobuf::Any;
use ibc_proto::ibc::applications::fee::v1::{Fee, MsgPayPacketFee};
use ibc_relayer::chain::cosmos::types::config::TxConfig;
use prost::{EncodeError, Message};

use crate::error::{handle_generic_error, Error};
use crate::ibc::denom::Denom;
use crate::relayer::transfer::build_transfer_message;
use crate::relayer::tx::simple_send_tx;
use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef};
use crate::types::tagged::MonoTagged;
use crate::types::wallet::TaggedWallet;
use crate::types::wallet::{Wallet, WalletAddress};

fn encode_message<M: Message>(message: &M) -> Result<Vec<u8>, EncodeError> {
let mut buf = Vec::new();
Message::encode(message, &mut buf)?;
Ok(buf)
}

pub fn build_pay_packet_message<Chain, Counterparty>(
port_id: &TaggedPortIdRef<Chain, Counterparty>,
channel_id: &TaggedChannelIdRef<Chain, Counterparty>,
payer: &MonoTagged<Chain, &WalletAddress>,
denom: &MonoTagged<Chain, &Denom>,
receive_fee: u64,
ack_fee: u64,
timeout_fee: u64,
) -> Result<Any, Error> {
const TYPE_URL: &str = "/ibc.applications.fee.v1.MsgPayPacketFee";

let denom_str = denom.value().to_string();

let fee = Fee {
recv_fee: vec![Coin {
denom: denom_str.clone(),
amount: receive_fee.to_string(),
}],
ack_fee: vec![Coin {
denom: denom_str.clone(),
amount: ack_fee.to_string(),
}],
timeout_fee: vec![Coin {
denom: denom_str,
amount: timeout_fee.to_string(),
}],
};

let message = MsgPayPacketFee {
fee: Some(fee),
source_port_id: port_id.value().to_string(),
source_channel_id: channel_id.value().to_string(),
signer: payer.value().0.clone(),
relayers: Vec::new(),
};

let encoded = encode_message(&message).map_err(handle_generic_error)?;

Ok(Any {
type_url: TYPE_URL.to_string(),
value: encoded,
})
}

pub async fn ibc_token_transfer_with_fee<SrcChain, DstChain>(
tx_config: &MonoTagged<SrcChain, &TxConfig>,
port_id: &TaggedPortIdRef<'_, SrcChain, DstChain>,
channel_id: &TaggedChannelIdRef<'_, SrcChain, DstChain>,
sender: &MonoTagged<SrcChain, &Wallet>,
recipient: &MonoTagged<DstChain, &WalletAddress>,
denom: &MonoTagged<SrcChain, &Denom>,
send_amount: u64,
receive_fee: u64,
ack_fee: u64,
timeout_fee: u64,
) -> Result<(), Error> {
let transfer_message =
build_transfer_message(port_id, channel_id, sender, recipient, denom, send_amount)?;

let pay_message = build_pay_packet_message(
port_id,
channel_id,
&sender.address(),
denom,
receive_fee,
ack_fee,
timeout_fee,
)?;

let messages = vec![transfer_message, pay_message];

simple_send_tx(tx_config.value(), &sender.value().key, messages).await?;

Ok(())
}
1 change: 1 addition & 0 deletions tools/test-framework/src/relayer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub mod chain;
pub mod channel;
pub mod connection;
pub mod driver;
pub mod fee;
pub mod foreign_client;
pub mod refresh;
pub mod transfer;
Expand Down
42 changes: 27 additions & 15 deletions tools/test-framework/src/relayer/transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ use core::time::Duration;
use ibc::signer::Signer;
use ibc::timestamp::Timestamp;
use ibc::Height;
use ibc_proto::google::protobuf::Any;
use ibc_relayer::chain::cosmos::types::config::TxConfig;
use ibc_relayer::transfer::build_transfer_message;
use ibc_relayer::transfer::build_transfer_message as raw_build_transfer_message;

use crate::error::{handle_generic_error, Error};
use crate::ibc::denom::Denom;
Expand All @@ -18,6 +19,30 @@ use crate::types::id::{TaggedChannelIdRef, TaggedPortIdRef};
use crate::types::tagged::*;
use crate::types::wallet::{Wallet, WalletAddress};

pub fn build_transfer_message<SrcChain, DstChain>(
port_id: &TaggedPortIdRef<'_, SrcChain, DstChain>,
channel_id: &TaggedChannelIdRef<'_, SrcChain, DstChain>,
sender: &MonoTagged<SrcChain, &Wallet>,
recipient: &MonoTagged<DstChain, &WalletAddress>,
denom: &MonoTagged<SrcChain, &Denom>,
amount: u64,
) -> Result<Any, Error> {
let timeout_timestamp = Timestamp::now()
.add(Duration::from_secs(60))
.map_err(handle_generic_error)?;

Ok(raw_build_transfer_message(
(*port_id.value()).clone(),
**channel_id.value(),
amount.into(),
denom.value().to_string(),
Signer::new(sender.value().address.0.clone()),
Signer::new(recipient.value().0.clone()),
Height::zero(),
timeout_timestamp,
))
}

/**
Perform a simplified version of IBC token transfer for testing purpose.
Expand All @@ -44,20 +69,7 @@ pub async fn ibc_token_transfer<SrcChain, DstChain>(
denom: &MonoTagged<SrcChain, &Denom>,
amount: u64,
) -> Result<(), Error> {
let timeout_timestamp = Timestamp::now()
.add(Duration::from_secs(60))
.map_err(handle_generic_error)?;

let message = build_transfer_message(
(*port_id.value()).clone(),
**channel_id.value(),
amount.into(),
denom.value().to_string(),
Signer::new(sender.value().address.0.clone()),
Signer::new(recipient.value().0.clone()),
Height::zero(),
timeout_timestamp,
);
let message = build_transfer_message(port_id, channel_id, sender, recipient, denom, amount)?;

simple_send_tx(tx_config.value(), &sender.value().key, vec![message]).await?;

Expand Down

0 comments on commit 099d9fa

Please sign in to comment.