Skip to content

Commit

Permalink
feat: migrate applications module under the ibc crate into `ibc-a…
Browse files Browse the repository at this point in the history
…pps` (#967)

* feat: restructure and split off applications codebase into ibc-apps dir

* imp: rename transfer dir to ics20_transfer

* feat: add ibc-apps crate

* fix: remove redundant dep + fix cargo doc

* docs: add README and descriptions

* docs: update main README page

* nit: docstrings

* nit: docstrings

* imp: rename folder to ics20-transfer

* chore: move serializers into ics20-transfer/types

* fix: apply reviewer comments

* imp: add docstring for cosmos_adr028_escrow_address

* fix: add missing features + use workspace deps for ibc crates

* imp: place re-exports under mod

* nit: apply suggestions from code review

Co-authored-by: Sean Chen <seanchen11235@gmail.com>
Signed-off-by: Farhad Shabani <Farhad.Shabani@gmail.com>

* fix: cargo fmt

---------

Signed-off-by: Farhad Shabani <Farhad.Shabani@gmail.com>
Co-authored-by: Sean Chen <seanchen11235@gmail.com>
  • Loading branch information
Farhad-Shabani and seanchen1991 committed Nov 17, 2023
1 parent bf77378 commit 68b4ca6
Show file tree
Hide file tree
Showing 40 changed files with 674 additions and 403 deletions.
9 changes: 8 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
resolver = "2"
members = [
"crates/ibc",
"crates/ibc-apps",
"crates/ibc-apps/ics20-transfer",
"crates/ibc-apps/ics20-transfer/types",
"crates/ibc-derive",
"crates/ibc-testkit",
"crates/ibc-query",
Expand Down Expand Up @@ -45,7 +48,11 @@ tracing-subscriber = { version = "0.3.17", features = ["fmt", "env-filter", "jso
typed-builder = { version = "0.18.0"}

# ibc dependencies
ibc-derive = { version = "0.3.0", path = "../ibc-derive" }
ibc = { version = "0.47.0", path = "./crates/ibc", default-features = false }
ibc-testkit = { version = "0.47.0", path = "./crates/ibc-testkit", default-features = false}
ibc-app-transfer = { version = "0.47.0", path = "./crates/ibc-apps/ics20-transfer", default-features = false }
ibc-app-transfer-types = { version = "0.47.0", path = "./crates/ibc-apps/ics20-transfer/types", default-features = false }
ibc-derive = { version = "0.3.0", path = "./crates/ibc-derive" }
ibc-proto = { version = "0.38.0", default-features = false }
ics23 = { version = "0.11", default-features = false }

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ the `ibc` rust crate which defines the main data structures and on-chain logic f
## Libraries

- [ibc](crates/ibc/README.md) - Data structures and on-chain logic for the IBC protocol.
- [ibc-apps](crates/ibc-apps/README.md) - Contains implementations of various IBC applications.
- [ibc-derive](crates/ibc-derive/README.md) - Derive macros for `ClientState`
and `ConsensusState` traits, reducing boilerplate.
- [ibc-testkit](crates/ibc-testkit/README.md) - Testing toolkit to aid `ibc-rs` and host chains in writing integration tests.
Expand Down
9 changes: 9 additions & 0 deletions clippy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
disallowed-types = [
# { path = "usize", reason = "variable size" }, # cannot on now, because mocks use it and serde, even if there is no usize in type
{ path = "f64", reason = "not supported in CosmWasm" },
{ path = "f32", reason = "not supported in CosmWasm" },
]

disallowed-methods = [
"std::time::Duration::as_secs_f64",
]
37 changes: 37 additions & 0 deletions crates/ibc-apps/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
[package]
name = "ibc-apps"
version = { workspace = true }
authors = { workspace = true }
edition = { workspace = true }
rust-version = { workspace = true }
license = { workspace = true }
repository = { workspace = true }
keywords = ["blockchain", "cosmos", "ibc", "applications"]
readme = "README.md"
description = """
`ibc-apps` provides a comprehensive set of libraries for IBC applications,
facilitating seamless integration of IBC business logic into any blockchain system.
"""

[package.metadata.docs.rs]
all-features = true

[dependencies]
ibc-app-transfer = { workspace = true }

[features]
default = ["std"]
std = [
"ibc-app-transfer/std",
]
serde = [
"ibc-app-transfer/serde",
]
schema = [
"ibc-app-transfer/schema",
"serde",
"std",
]
borsh = [
"ibc-app-transfer/borsh",
]
48 changes: 48 additions & 0 deletions crates/ibc-apps/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# `ibc-apps`

This crate is a top-level library that re-exports Inter-Blockchain
Communication (IBC) applications implemented in Rust. It serves as a centralized hub,
simplifying the process of importing and integrating various IBC applications
into your blockchain. IBC is a distributed protocol that enables communication
between distinct sovereign blockchains. IBC applications abstract away the core
transport and authentication layers, letter blockchain app developers
focus solely on business logic implementation.

The structure within the `ibc-apps` crate is designed to provide flexibility for
external users. It allows users to either utilize the entire `ibc-apps` crate,
or selectively import specific sub-crates, whether you need a certain IBC
application (e.g. `ibc-app-transfer` crate) or only their associated data
structures (e.g. `ibc-app-transfer-types`). This versatility empowers hosts,
including chain integrators, relayers, or any IBC tooling projects, to build
their solutions on top of the layers that best suit their requirements.

## Libraries

Currently, the `ibc-apps` crate contains the implementation of the following IBC
applications:

### ICS-20: Fungible Token Transfer Application

- [ibc-app-transfer](crates/ibc-apps/ics20-transfer)
- [ibc-app-transfer-types](crates/ibc-apps/ics20-transfer/types)

## Contributing

IBC is specified in English in the [cosmos/ibc repo][ibc]. Any
protocol changes or clarifications should be contributed there.

If you're interested in contributing, please comment on an issue or open a new
one!

See also [CONTRIBUTING.md](./../../CONTRIBUTING.md).

## Resources

- [IBC Website][ibc-homepage]
- [IBC Specification][ibc]
- [IBC Go implementation][ibc-go]

[//]: # (general links)
[ibc]: https://github.com/cosmos/ibc
[ibc-go]: https://github.com/cosmos/ibc-go
[ibc-homepage]: https://cosmos.network/ibc
57 changes: 57 additions & 0 deletions crates/ibc-apps/ics20-transfer/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
[package]
name = "ibc-app-transfer"
version = { workspace = true }
authors = { workspace = true }
edition = { workspace = true }
rust-version = { workspace = true }
license = { workspace = true }
repository = { workspace = true }
keywords = ["blockchain", "cosmos", "ibc", "transfer", "ics20"]
readme = "./../README.md"
description = """
Contains the core implementation of the ICS-20 token transfer application logic
along with re-exporting the data structures from `ibc-app-transfer-types` crate.
"""

[package.metadata.docs.rs]
all-features = true

[dependencies]
# external dependencies
serde_json = { workspace = true, optional = true }
sha2 = { workspace = true }

# ibc dependencies
ibc = { workspace = true }
ibc-app-transfer-types = { workspace = true }

[dev-dependencies]
subtle-encoding = { workspace = true }

[features]
default = ["std"]
std = [
"ibc-app-transfer-types/std",
"ibc/std",
"serde_json/std",
"sha2/std",
]
serde = [
"ibc-app-transfer-types/serde",
"ibc/serde",
"serde_json"
]
schema = [
"ibc-app-transfer-types/schema",
"ibc/schema",
"serde",
"std",
]
borsh = [
"ibc-app-transfer-types/borsh",
"ibc/borsh",
]
parity-scale-codec = [
"ibc-app-transfer-types/parity-scale-codec",
"ibc/parity-scale-codec",
]
136 changes: 136 additions & 0 deletions crates/ibc-apps/ics20-transfer/src/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
//! Defines the main context traits and IBC module callbacks

use ibc::core::ics24_host::identifier::{ChannelId, PortId};
use ibc::prelude::*;
use ibc::Signer;
use ibc_app_transfer_types::error::TokenTransferError;
use ibc_app_transfer_types::{PrefixedCoin, PrefixedDenom, VERSION};
use sha2::{Digest, Sha256};

/// Methods required in token transfer validation, to be implemented by the host
pub trait TokenTransferValidationContext {
type AccountId: TryFrom<Signer>;

/// get_port returns the portID for the transfer module.
fn get_port(&self) -> Result<PortId, TokenTransferError>;

/// Returns the escrow account id for a port and channel combination
fn get_escrow_account(
&self,
port_id: &PortId,
channel_id: &ChannelId,
) -> Result<Self::AccountId, TokenTransferError>;

/// Returns Ok() if the host chain supports sending coins.
fn can_send_coins(&self) -> Result<(), TokenTransferError>;

/// Returns Ok() if the host chain supports receiving coins.
fn can_receive_coins(&self) -> Result<(), TokenTransferError>;

/// Validates the sender and receiver accounts and the coin inputs
fn send_coins_validate(
&self,
from_account: &Self::AccountId,
to_account: &Self::AccountId,
coin: &PrefixedCoin,
) -> Result<(), TokenTransferError>;

/// Validates the receiver account and the coin input
fn mint_coins_validate(
&self,
account: &Self::AccountId,
coin: &PrefixedCoin,
) -> Result<(), TokenTransferError>;

/// Validates the sender account and the coin input
fn burn_coins_validate(
&self,
account: &Self::AccountId,
coin: &PrefixedCoin,
) -> Result<(), TokenTransferError>;

/// Returns a hash of the prefixed denom.
/// Implement only if the host chain supports hashed denominations.
fn denom_hash_string(&self, _denom: &PrefixedDenom) -> Option<String> {
None
}
}

/// Methods required in token transfer execution, to be implemented by the host
pub trait TokenTransferExecutionContext: TokenTransferValidationContext {
/// This function should enable sending ibc fungible tokens from one account to another
fn send_coins_execute(
&mut self,
from_account: &Self::AccountId,
to_account: &Self::AccountId,
coin: &PrefixedCoin,
) -> Result<(), TokenTransferError>;

/// This function to enable minting ibc tokens to a user account
fn mint_coins_execute(
&mut self,
account: &Self::AccountId,
coin: &PrefixedCoin,
) -> Result<(), TokenTransferError>;

/// This function should enable burning of minted tokens in a user account
fn burn_coins_execute(
&mut self,
account: &Self::AccountId,
coin: &PrefixedCoin,
) -> Result<(), TokenTransferError>;
}

/// Helper function to generate an escrow address for a given port and channel
/// ids according to the format specified in the Cosmos SDK
/// [`ADR-028`](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-028-public-key-addresses.md)
pub fn cosmos_adr028_escrow_address(port_id: &PortId, channel_id: &ChannelId) -> Vec<u8> {
let contents = format!("{port_id}/{channel_id}");

let mut hasher = Sha256::new();
hasher.update(VERSION.as_bytes());
hasher.update([0]);
hasher.update(contents.as_bytes());

let mut hash = hasher.finalize().to_vec();
hash.truncate(20);
hash
}

#[cfg(test)]
mod tests {
use subtle_encoding::bech32;

use super::*;
use crate::context::cosmos_adr028_escrow_address;

#[test]
fn test_cosmos_escrow_address() {
fn assert_eq_escrow_address(port_id: &str, channel_id: &str, address: &str) {
let port_id = port_id.parse().unwrap();
let channel_id = channel_id.parse().unwrap();
let gen_address = {
let addr = cosmos_adr028_escrow_address(&port_id, &channel_id);
bech32::encode("cosmos", addr)
};
assert_eq!(gen_address, address.to_owned())
}

// addresses obtained using `gaiad query ibc-transfer escrow-address [port-id] [channel-id]`
assert_eq_escrow_address(
"transfer",
"channel-141",
"cosmos1x54ltnyg88k0ejmk8ytwrhd3ltm84xehrnlslf",
);
assert_eq_escrow_address(
"transfer",
"channel-207",
"cosmos1ju6tlfclulxumtt2kglvnxduj5d93a64r5czge",
);
assert_eq_escrow_address(
"transfer",
"channel-187",
"cosmos177x69sver58mcfs74x6dg0tv6ls4s3xmmcaw53",
);
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
//! Implements the processing logic for ICS20 (token transfer) message.

use super::context::{TokenTransferExecutionContext, TokenTransferValidationContext};
use crate::applications::transfer::error::TokenTransferError;
use crate::applications::transfer::is_sender_chain_source;
use crate::applications::transfer::packet::PacketData;
use crate::core::ics04_channel::packet::Packet;
use crate::prelude::*;

pub mod on_recv_packet;
pub mod send_transfer;

use ibc::core::ics04_channel::packet::Packet;
use ibc::prelude::*;
use ibc_app_transfer_types::error::TokenTransferError;
use ibc_app_transfer_types::is_sender_chain_source;
use ibc_app_transfer_types::packet::PacketData;

use crate::context::{TokenTransferExecutionContext, TokenTransferValidationContext};

pub fn refund_packet_token_execute(
ctx_a: &mut impl TokenTransferExecutionContext,
packet: &Packet,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use crate::applications::transfer::context::TokenTransferExecutionContext;
use crate::applications::transfer::error::TokenTransferError;
use crate::applications::transfer::events::DenomTraceEvent;
use crate::applications::transfer::packet::PacketData;
use crate::applications::transfer::{is_receiver_chain_source, TracePrefix};
use crate::core::ics04_channel::packet::Packet;
use crate::core::router::ModuleExtras;
use crate::prelude::*;
use ibc::core::ics04_channel::packet::Packet;
use ibc::core::router::ModuleExtras;
use ibc::prelude::*;
use ibc_app_transfer_types::error::TokenTransferError;
use ibc_app_transfer_types::events::DenomTraceEvent;
use ibc_app_transfer_types::packet::PacketData;
use ibc_app_transfer_types::{is_receiver_chain_source, TracePrefix};

use crate::context::TokenTransferExecutionContext;

/// This function handles the transfer receiving logic.
///
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
use crate::applications::transfer::context::{
TokenTransferExecutionContext, TokenTransferValidationContext,
};
use crate::applications::transfer::error::TokenTransferError;
use crate::applications::transfer::events::TransferEvent;
use crate::applications::transfer::msgs::transfer::MsgTransfer;
use crate::applications::transfer::{is_sender_chain_source, MODULE_ID_STR};
use crate::core::events::{MessageEvent, ModuleEvent};
use crate::core::ics04_channel::context::{
SendPacketExecutionContext, SendPacketValidationContext,
};
use crate::core::ics04_channel::handler::send_packet::{send_packet_execute, send_packet_validate};
use crate::core::ics04_channel::packet::Packet;
use crate::core::ics24_host::path::{ChannelEndPath, SeqSendPath};
use crate::prelude::*;
use ibc::core::events::{MessageEvent, ModuleEvent};
use ibc::core::ics04_channel::context::{SendPacketExecutionContext, SendPacketValidationContext};
use ibc::core::ics04_channel::handler::send_packet::{send_packet_execute, send_packet_validate};
use ibc::core::ics04_channel::packet::Packet;
use ibc::core::ics24_host::path::{ChannelEndPath, SeqSendPath};
use ibc::prelude::*;
use ibc_app_transfer_types::error::TokenTransferError;
use ibc_app_transfer_types::events::TransferEvent;
use ibc_app_transfer_types::msgs::transfer::MsgTransfer;
use ibc_app_transfer_types::{is_sender_chain_source, MODULE_ID_STR};

use crate::context::{TokenTransferExecutionContext, TokenTransferValidationContext};

/// Initiate a token transfer. Equivalent to calling [`send_transfer_validate`], followed by [`send_transfer_execute`].
pub fn send_transfer<SendPacketCtx, TokenCtx>(
Expand Down
Loading

0 comments on commit 68b4ca6

Please sign in to comment.