diff --git a/Cargo.lock b/Cargo.lock index 33b8e32274..8e8da7388b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4812,42 +4812,6 @@ dependencies = [ "tiny-keccak", ] -[[package]] -name = "ethereum-light-client" -version = "0.1.0" -dependencies = [ - "alloy", - "base64 0.21.7", - "beacon-api-types", - "bytes", - "cosmwasm-schema 1.5.3", - "cosmwasm-std 1.5.2", - "cw-storage-plus 1.2.0", - "ethereum-light-client-types", - "ethereum-sync-protocol", - "ethers-contract-derive", - "ethers-core", - "evm-storage-verifier", - "hex", - "hex-literal", - "ibc-solidity", - "ics008-wasm-client", - "lazy_static", - "prost 0.12.6", - "protos", - "rlp", - "schemars", - "serde", - "serde-json-wasm 1.0.1", - "serde-utils", - "serde_json", - "sha3 0.10.8", - "thiserror", - "tiny-keccak", - "union-ibc", - "unionlabs", -] - [[package]] name = "ethereum-light-client-types" version = "0.1.0" @@ -13194,6 +13158,7 @@ dependencies = [ "ethabi", "go-parse-duration", "hex", + "ibc-solidity", "prost 0.12.6", "protos", "schemars", @@ -13207,6 +13172,7 @@ dependencies = [ "tracing", "tracing-subscriber 0.3.18", "ucs01-relay-api", + "union-ibc-msg", "unionlabs", ] @@ -13350,6 +13316,7 @@ dependencies = [ "sha2 0.10.8", "sha3 0.10.8", "thiserror", + "union-ibc-msg", "unionlabs", ] @@ -13381,6 +13348,15 @@ dependencies = [ "unionlabs", ] +[[package]] +name = "union-ibc-msg" +version = "1.0.0" +dependencies = [ + "ibc-solidity", + "serde", + "unionlabs", +] + [[package]] name = "unionlabs" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 941a54a242..ea9b0b92f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = [ "cosmwasm/ucs01-relay-api", "cosmwasm/ucs02-nft", "cosmwasm/union-ibc", + "cosmwasm/union-ibc-msg", "devnet-compose", @@ -75,7 +76,7 @@ members = [ "light-clients/cometbls-light-client", "light-clients/cometbls-light-client/types", - "light-clients/ethereum-light-client", + # "light-clients/ethereum-light-client", "light-clients/ethereum-light-client/types", # "light-clients/evm-in-cosmos-light-client", @@ -132,7 +133,7 @@ members = [ "drip", - "light-clients/movement-light-client", + # "light-clients/movement-light-client", "light-clients/movement-light-client/types", "lib/aptos-verifier", @@ -181,7 +182,7 @@ scroll-light-client-types = { path = "light-clients/scroll-light-client/types", contracts = { path = "generated/rust/contracts", default-features = false } -ethereum-light-client = { path = "light-clients/ethereum-light-client", default-features = false } +# ethereum-light-client = { path = "light-clients/ethereum-light-client", default-features = false } ethereum-light-client-types = { path = "light-clients/ethereum-light-client/types", default-features = false } ethereum-sync-protocol = { path = "lib/ethereum-sync-protocol", default-features = false } evm-storage-verifier = { path = "lib/evm-storage-verifier", default-features = false } @@ -201,8 +202,9 @@ linea-light-client-types = { path = "light-clients/linea-light-client/types", de linea-verifier = { path = "lib/linea-verifier", default-features = false } linea-zktrie = { path = "lib/linea-zktrie", default-features = false } -ibc-solidity = { path = "lib/ibc-solidity", default-features = false } -union-ibc = { path = "cosmwasm/union-ibc", default-features = false } +ibc-solidity = { path = "lib/ibc-solidity", default-features = false } +union-ibc = { path = "cosmwasm/union-ibc", default-features = false } +union-ibc-msg = { path = "cosmwasm/union-ibc-msg", default-features = false } gnark-key-parser = { path = "lib/gnark-key-parser", default-features = false } gnark-mimc = { path = "lib/gnark-mimc", default-features = false } diff --git a/cosmwasm/ucs01-relay-api/src/middleware.rs b/cosmwasm/ucs01-relay-api/src/middleware.rs index d330f41fe0..a189229855 100644 --- a/cosmwasm/ucs01-relay-api/src/middleware.rs +++ b/cosmwasm/ucs01-relay-api/src/middleware.rs @@ -1,8 +1,8 @@ -use cosmwasm_std::{Addr, Event, IbcPacket}; +use cosmwasm_std::{to_json_string, Addr, Event, IbcPacket, StdError}; use serde::{Deserialize, Serialize}; use thiserror::Error; use unionlabs::{ - id::{ChannelId, PortId}, + id::PortId, validated::{Validate, Validated}, }; @@ -16,12 +16,8 @@ pub const PFM_MODULE_NAME: &str = "packetforwardmiddleware"; pub const PFM_ERROR_EVENT: &str = "packet_forward_error"; pub const PFM_HOP_EVENT: &str = "packet_forward_hop"; -pub const RECV_SEQUENCE_ATTR: &str = "recv_sequence"; -pub const SENT_SEQUENCE_ATTR: &str = "sent_sequence"; -pub const DEST_CHANNEL_ATTR: &str = "dest_channel"; -pub const DEST_PORT_ATTR: &str = "dest_port"; -pub const SRC_CHANNEL_ATTR: &str = "src_channel"; -pub const SRC_PORT_ATTR: &str = "src_port"; +pub const SRC_PACKET: &str = "src_packet"; +pub const DEST_PACKET: &str = "dst_packet"; #[derive(Error, Debug, PartialEq)] pub enum MiddlewareError { @@ -71,21 +67,14 @@ pub struct InFlightPfmPacket { /// This is the protocol of the channel between A -> B, such that if there is a failure between B -> C then we know how to write the acknowledgement for the origin channel. pub origin_protocol_version: String, pub origin_packet: IbcPacket, - pub forward_src_channel_id: String, - pub forward_src_port_id: String, - - pub forward_timeout: u64, + pub forward_packet: IbcPacket, } impl InFlightPfmPacket { - pub fn create_hop_event(&self, sent_sequence: u64) -> Event { - Event::new(PFM_HOP_EVENT) - .add_attribute(RECV_SEQUENCE_ATTR, self.origin_packet.sequence.to_string()) - .add_attribute(DEST_CHANNEL_ATTR, self.forward_src_channel_id.clone()) - .add_attribute(DEST_PORT_ATTR, self.forward_src_port_id.clone()) - .add_attribute(SENT_SEQUENCE_ATTR, sent_sequence.to_string()) - .add_attribute(SRC_CHANNEL_ATTR, self.origin_packet.src.channel_id.clone()) - .add_attribute(SRC_PORT_ATTR, self.origin_packet.src.port_id.clone()) + pub fn create_hop_event(&self) -> Result { + Ok(Event::new(PFM_HOP_EVENT) + .add_attribute(SRC_PACKET, to_json_string(&self.origin_packet)?) + .add_attribute(DEST_PACKET, to_json_string(&self.forward_packet)?)) } } @@ -100,7 +89,7 @@ pub enum Memo { pub struct PacketForward { pub receiver: PfmReceiver, pub port: PortId, - pub channel: ChannelId, + pub channel: String, #[serde(default = "default_pfm_timeout")] pub timeout: String, #[serde(default = "default_pfm_retries")] diff --git a/cosmwasm/ucs01-relay-api/src/protocol.rs b/cosmwasm/ucs01-relay-api/src/protocol.rs index dd543d7bfd..be1b45c89e 100644 --- a/cosmwasm/ucs01-relay-api/src/protocol.rs +++ b/cosmwasm/ucs01-relay-api/src/protocol.rs @@ -2,8 +2,8 @@ use std::{collections::btree_map::Entry, fmt::Debug}; use cosmwasm_std::{ Addr, Attribute, Binary, CheckedMultiplyRatioError, Coin, CosmosMsg, Event, IbcBasicResponse, - IbcEndpoint, IbcMsg, IbcOrder, IbcPacket, IbcPacketAckMsg, IbcReceiveResponse, Response, - SubMsg, Timestamp, + IbcOrder, IbcPacket, IbcPacketAckMsg, IbcReceiveResponse, IbcTimeout, Response, SubMsg, + Timestamp, }; use thiserror::Error; use unionlabs::encoding::{self, Decode, DecodeErrorOf, Encode}; @@ -138,14 +138,24 @@ pub trait TransferProtocol { fn load_channel_protocol_version(&self, channel_id: &str) -> Result; - fn channel_endpoint(&self) -> &IbcEndpoint; - fn caller(&self) -> &Addr; fn self_addr(&self) -> &Addr; fn self_addr_canonical(&self) -> Result, Self::Error>; + fn send_packet( + &self, + data: Binary, + timeout: IbcTimeout, + ) -> Result, Self::Error>; + + fn write_acknowledgement( + &self, + packet: &IbcPacket, + ack: Binary, + ) -> Result, Self::Error>; + // TODO: Remove use of Encoding Error fn common_to_protocol_packet( &self, @@ -210,14 +220,12 @@ pub trait TransferProtocol { }; let tokens = packet.tokens(); - let sub = SubMsg::reply_always( - IbcMsg::SendPacket { - channel_id: self.channel_endpoint().channel_id.clone(), - data: packet.encode().into(), - timeout: input.current_time.plus_seconds(input.timeout_delta).into(), - }, - IBC_SEND_ID, - ); + let send_packet_msg = self.send_packet( + packet.encode().into(), + input.current_time.plus_seconds(input.timeout_delta).into(), + )?; + let sub = SubMsg::reply_always(send_packet_msg, IBC_SEND_ID); + Ok(Response::new() .add_messages(send_msgs) .add_submessage(sub) diff --git a/cosmwasm/ucs01-relay/Cargo.toml b/cosmwasm/ucs01-relay/Cargo.toml index ff7fdcb14a..57d498d6e7 100644 --- a/cosmwasm/ucs01-relay/Cargo.toml +++ b/cosmwasm/ucs01-relay/Cargo.toml @@ -27,6 +27,7 @@ dlmalloc = { workspace = true, features = ["global"] } ethabi = { workspace = true } go-parse-duration = { workspace = true } hex = { workspace = true } +ibc-solidity = { workspace = true, features = ["serde"] } prost = { workspace = true } protos = { workspace = true } schemars = { workspace = true } @@ -40,6 +41,7 @@ token-factory-api = { workspace = true } tracing = { workspace = true } tracing-subscriber = { workspace = true } ucs01-relay-api = { workspace = true } +union-ibc-msg = { workspace = true } unionlabs = { workspace = true } [dev-dependencies] diff --git a/cosmwasm/ucs01-relay/src/bin/schema.rs b/cosmwasm/ucs01-relay/src/bin/schema.rs deleted file mode 100644 index 1209f2e076..0000000000 --- a/cosmwasm/ucs01-relay/src/bin/schema.rs +++ /dev/null @@ -1,10 +0,0 @@ -use cosmwasm_schema::write_api; -use ucs01_relay::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; - -fn main() { - write_api! { - instantiate: InstantiateMsg, - execute: ExecuteMsg, - query: QueryMsg, - } -} diff --git a/cosmwasm/ucs01-relay/src/contract.rs b/cosmwasm/ucs01-relay/src/contract.rs index db47854a72..4a55769454 100644 --- a/cosmwasm/ucs01-relay/src/contract.rs +++ b/cosmwasm/ucs01-relay/src/contract.rs @@ -1,8 +1,8 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - to_json_binary, Addr, Binary, Coins, Deps, DepsMut, Env, IbcEndpoint, IbcQuery, MessageInfo, - Order, PortIdResponse, Response, StdError, StdResult, + to_json_binary, Addr, Binary, Coins, Deps, DepsMut, Env, IbcChannel, IbcEndpoint, IbcQuery, + ListChannelsResponse, MessageInfo, Order, PortIdResponse, Response, StdError, StdResult, }; use cw2::set_contract_version; use token_factory_api::TokenFactoryMsg; @@ -14,16 +14,13 @@ use unionlabs::hash::H256; use crate::{ error::ContractError, - ibc::enforce_order_and_version, + ibc::{enforce_order_and_version, execute_union_ibc}, msg::{ - ChannelResponse, ConfigResponse, ExecuteMsg, InstantiateMsg, ListChannelsResponse, - MigrateMsg, PortResponse, QueryMsg, TransferMsg, + ChannelBalances, ConfigResponse, ExecuteMsg, InstantiateMsg, MigrateMsg, PortResponse, + QueryMsg, TransferMsg, }, protocol::{encode_denom_hash, Ics20Protocol, ProtocolCommon, Ucs01Protocol}, - state::{ - ChannelInfo, Config, ADMIN, CHANNEL_INFO, CHANNEL_STATE, CONFIG, FOREIGN_DENOM_TO_HASH, - HASH_TO_FOREIGN_DENOM, - }, + state::{Config, ADMIN, CHANNEL_STATE, CONFIG, FOREIGN_DENOM_TO_HASH, HASH_TO_FOREIGN_DENOM}, }; // REVIEW: This isn't on crates.io, what else should we use? @@ -38,10 +35,12 @@ pub fn instantiate( msg: InstantiateMsg, ) -> Result, ContractError> { set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + let ibc_host = deps.api.addr_validate(&msg.ibc_host)?; CONFIG.save( deps.storage, &Config { default_timeout: msg.default_timeout, + ibc_host, }, )?; @@ -53,13 +52,6 @@ pub fn instantiate( // would depend on the contract's address before it's initialization. channel.endpoint.port_id = format!("wasm.{}", env.contract.address); enforce_order_and_version(&channel, None)?; - let info = ChannelInfo { - endpoint: channel.endpoint, - counterparty_endpoint: channel.counterparty_endpoint, - connection_id: channel.connection_id, - protocol_version: channel.version, - }; - CHANNEL_INFO.save(deps.storage, &info.endpoint.channel_id, &info)?; } Ok(Response::default()) @@ -73,6 +65,7 @@ pub fn execute( msg: ExecuteMsg, ) -> Result, ContractError> { match msg { + ExecuteMsg::UnionIbcMsg(msg) => execute_union_ibc(deps, env, info, msg), ExecuteMsg::Transfer(msg) => execute_transfer(deps, env, info, msg), ExecuteMsg::UpdateAdmin { admin } => { let admin = deps.api.addr_validate(&admin)?; @@ -132,8 +125,6 @@ pub fn execute_transfer( return Err(ContractError::NoFunds {}); } - let channel_info = CHANNEL_INFO.load(deps.storage, &msg.channel)?; - let config = CONFIG.load(deps.storage)?; let input = TransferInput { @@ -144,13 +135,15 @@ pub fn execute_transfer( tokens, }; - match channel_info.protocol_version.as_str() { + let channel = query_ibc_channel(deps.as_ref(), msg.channel.clone())?; + + match channel.version.as_ref() { Ics20Protocol::VERSION => Ics20Protocol { common: ProtocolCommon { deps, env, info, - channel: channel_info, + channel, }, } .send(input, msg.memo), @@ -159,7 +152,7 @@ pub fn execute_transfer( deps, env, info, - channel: channel_info, + channel, }, } .send(input, msg.memo), @@ -176,13 +169,13 @@ pub fn migrate(_: DepsMut, _: Env, _: MigrateMsg) -> Result StdResult { +pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result { match msg { - QueryMsg::Port {} => to_json_binary(&query_port(deps)?), - QueryMsg::ListChannels {} => to_json_binary(&query_list(deps)?), - QueryMsg::Channel { id } => to_json_binary(&query_channel(deps, id)?), - QueryMsg::Config {} => to_json_binary(&query_config(deps)?), - QueryMsg::Admin {} => to_json_binary(&ADMIN.query_admin(deps)?), + QueryMsg::Port {} => Ok(to_json_binary(&query_port(deps)?)?), + QueryMsg::ListChannels {} => Ok(to_json_binary(&query_list(deps)?)?), + QueryMsg::Channel { id } => Ok(to_json_binary(&query_channel(deps, id)?)?), + QueryMsg::Config {} => Ok(to_json_binary(&query_config(deps)?)?), + QueryMsg::Admin {} => Ok(to_json_binary(&ADMIN.query_admin(deps)?)?), QueryMsg::ForeignDenomToLocal { source_channel, denom, @@ -204,37 +197,51 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { &env.contract.address, &encode_denom_hash(foreign_denom_hash), ); - to_json_binary(&factory_denom) + Ok(to_json_binary(&factory_denom)?) } } } -fn query_port(deps: Deps) -> StdResult { +fn query_port(deps: Deps) -> Result { let query = IbcQuery::PortId {}.into(); let PortIdResponse { port_id, .. } = deps.querier.query(&query)?; Ok(PortResponse { port_id }) } -fn query_list(deps: Deps) -> StdResult { - let channels = CHANNEL_INFO - .range_raw(deps.storage, None, None, Order::Ascending) - .map(|r| r.map(|(_, v)| v)) - .collect::>()?; - Ok(ListChannelsResponse { channels }) +fn query_list(deps: Deps) -> Result { + Ok(deps + .querier + .query(&cosmwasm_std::QueryRequest::Ibc(IbcQuery::ListChannels { + port_id: None, + }))?) +} + +pub fn query_ibc_channel(deps: Deps, id: String) -> Result { + let channel = deps + .querier + .query::(&cosmwasm_std::QueryRequest::Ibc( + IbcQuery::Channel { + channel_id: id.clone(), + port_id: None, + }, + ))? + .channel + .ok_or(ContractError::NoSuchChannel { id })?; + Ok(channel) } // make public for ibc tests -pub fn query_channel(deps: Deps, id: String) -> StdResult { - let info = CHANNEL_INFO.load(deps.storage, &id)?; +pub fn query_channel(deps: Deps, id: String) -> Result { + let channel = query_ibc_channel(deps, id.clone())?; let balances = CHANNEL_STATE .prefix(&id) .range(deps.storage, None, None, Order::Ascending) .map(|r| r.map(|(denom, v)| (denom.clone(), v.outstanding))) .collect::>>()?; - Ok(ChannelResponse { info, balances }) + Ok(ChannelBalances { channel, balances }) } -fn query_config(deps: Deps) -> StdResult { +fn query_config(deps: Deps) -> Result { let cfg = CONFIG.load(deps.storage)?; let admin = ADMIN.get(deps)?.unwrap_or_else(|| Addr::unchecked("")); let res = ConfigResponse { diff --git a/cosmwasm/ucs01-relay/src/error.rs b/cosmwasm/ucs01-relay/src/error.rs index 1038bad302..4388381d1e 100644 --- a/cosmwasm/ucs01-relay/src/error.rs +++ b/cosmwasm/ucs01-relay/src/error.rs @@ -66,14 +66,23 @@ pub enum ContractError { #[error("Only myself is able to trigger this message")] Unauthorized, + #[error("The operation is not supported")] + Unsupported, + #[error(transparent)] MiddlewareError(#[from] MiddlewareError), - #[error("unable to decode json value")] + #[error("Unable to decode json value")] SerdeJson(#[from] serde_json_wasm::de::Error), #[error(transparent)] Arithmetic(#[from] CheckedMultiplyRatioError), + + #[error("Only the IBC host is able to perform this operation")] + OnlyIBCHost, + + #[error("The reply was invalid")] + InvalidReply, } impl From for ContractError { diff --git a/cosmwasm/ucs01-relay/src/ibc.rs b/cosmwasm/ucs01-relay/src/ibc.rs index 2d5271f832..608c8a5231 100644 --- a/cosmwasm/ucs01-relay/src/ibc.rs +++ b/cosmwasm/ucs01-relay/src/ibc.rs @@ -1,10 +1,13 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - DepsMut, Env, Ibc3ChannelOpenResponse, IbcBasicResponse, IbcChannel, IbcChannelCloseMsg, - IbcChannelConnectMsg, IbcChannelOpenMsg, IbcPacketAckMsg, IbcPacketReceiveMsg, - IbcPacketTimeoutMsg, IbcReceiveResponse, MessageInfo, Reply, Response, SubMsgResult, + from_json, wasm_execute, Addr, DepsMut, Env, Ibc3ChannelOpenResponse, IbcAcknowledgement, + IbcBasicResponse, IbcChannel, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, + IbcEndpoint, IbcPacket, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, + IbcReceiveResponse, IbcTimeout, IbcTimeoutBlock, MessageInfo, Reply, Response, SubMsgResult, + Timestamp, }; +use ibc_solidity::cosmwasm::types::ibc::{Channel, Packet}; use prost::{Message, Name}; use protos::cosmwasm::wasm::v1::MsgIbcSendResponse; use token_factory_api::TokenFactoryMsg; @@ -12,18 +15,21 @@ use ucs01_relay_api::{ middleware::InFlightPfmPacket, protocol::{TransferProtocol, IBC_SEND_ID}, }; +use union_ibc_msg::{ + module::UnionIbcMsg, + msg::{ExecuteMsg as UnionIbcHostMsg, MsgWriteAcknowledgement}, + query::QueryMsg as UnionIbcQuery, +}; pub type IbcResponse = IbcBasicResponse; use crate::{ + contract::query_ibc_channel, error::ContractError, - protocol::{protocol_ordering, Ics20Protocol, ProtocolCommon, Ucs01Protocol}, - state::{ChannelInfo, PfmRefundPacketKey, CHANNEL_INFO, IN_FLIGHT_PFM_PACKETS}, + protocol::{packet_key, protocol_ordering, Ics20Protocol, ProtocolCommon, Ucs01Protocol}, + state::{CONFIG, IN_FLIGHT_PFM_PACKETS}, }; -#[cfg(test)] -mod tests; - fn to_response( IbcReceiveResponse { acknowledgement, @@ -66,33 +72,36 @@ pub fn reply( return Ok(Response::new()); } - let msg_response = value - .msg_responses - .iter() - .find(|msg_response| msg_response.type_url == MsgIbcSendResponse::type_url()) - .expect("type url is correct and exists"); - - let send_response = - MsgIbcSendResponse::decode(msg_response.value.as_slice()).expect("is type url"); - - let in_flight_packet = + let mut in_flight_packet = serde_json_wasm::from_slice::(reply.payload.as_slice()) .expect("binary is type"); - let refund_packet_key = PfmRefundPacketKey { - channel_id: in_flight_packet.forward_src_channel_id.clone(), - port_id: in_flight_packet.forward_src_port_id.clone(), - sequence: send_response.sequence, + match value + .msg_responses + .iter() + .find(|msg_response| msg_response.type_url == MsgIbcSendResponse::type_url()) + { + Some(msg_response) => { + let send_response = MsgIbcSendResponse::decode(msg_response.value.as_slice()) + .expect("is type url"); + in_flight_packet.forward_packet.sequence = send_response.sequence; + } + None => + { + #[allow(deprecated)] + if from_json::(value.data.unwrap_or_default()).is_err() { + return Err(ContractError::InvalidReply); + } + } }; + let refund_packet_key = packet_key(&in_flight_packet.forward_packet); + IN_FLIGHT_PFM_PACKETS - .save(deps.storage, refund_packet_key.clone(), &in_flight_packet) + .save(deps.storage, refund_packet_key, &in_flight_packet) .expect("infallible update"); - Ok( - Response::new() - .add_event(in_flight_packet.create_hop_event(send_response.sequence)), - ) + Ok(Response::new().add_event(in_flight_packet.create_hop_event()?)) } (IBC_SEND_ID, SubMsgResult::Err(err)) => { // this means this is not pfm @@ -131,22 +140,12 @@ pub fn ibc_channel_open( } #[cfg_attr(not(feature = "library"), entry_point)] -/// record the channel in CHANNEL_INFO pub fn ibc_channel_connect( - deps: DepsMut, + _deps: DepsMut, _env: Env, msg: IbcChannelConnectMsg, ) -> Result { enforce_order_and_version(msg.channel(), msg.counterparty_version())?; - let channel: IbcChannel = msg.into(); - let info = ChannelInfo { - endpoint: channel.endpoint, - counterparty_endpoint: channel.counterparty_endpoint, - connection_id: channel.connection_id, - protocol_version: channel.version, - }; - CHANNEL_INFO.save(deps.storage, &info.endpoint.channel_id, &info)?; - Ok(IbcResponse::default()) } @@ -200,20 +199,20 @@ pub fn ibc_packet_receive( env: Env, msg: IbcPacketReceiveMsg, ) -> Result, ContractError> { - let channel_info = CHANNEL_INFO.load(deps.storage, &msg.packet.dest.channel_id)?; + let channel = query_ibc_channel(deps.as_ref(), msg.packet.dest.channel_id.clone())?; let info = MessageInfo { sender: msg.relayer, funds: Default::default(), }; - match channel_info.protocol_version.as_str() { + match channel.version.as_ref() { Ics20Protocol::VERSION => Ok((Ics20Protocol { common: ProtocolCommon { deps, env, info, - channel: channel_info, + channel, }, }) .receive(msg.packet)), @@ -222,7 +221,7 @@ pub fn ibc_packet_receive( deps, env, info, - channel: channel_info, + channel, }, }) .receive(msg.packet)), @@ -240,20 +239,20 @@ pub fn ibc_packet_ack( env: Env, msg: IbcPacketAckMsg, ) -> Result { - let channel_info = CHANNEL_INFO.load(deps.storage, &msg.original_packet.src.channel_id)?; + let channel = query_ibc_channel(deps.as_ref(), msg.original_packet.src.channel_id.clone())?; let info = MessageInfo { sender: msg.relayer.clone(), funds: Default::default(), }; - match channel_info.protocol_version.as_str() { + match channel.version.as_str() { Ics20Protocol::VERSION => (Ics20Protocol { common: ProtocolCommon { deps, env, info, - channel: channel_info, + channel, }, }) .send_ack(msg), @@ -262,7 +261,7 @@ pub fn ibc_packet_ack( deps, env, info, - channel: channel_info, + channel, }, }) .send_ack(msg), @@ -280,20 +279,20 @@ pub fn ibc_packet_timeout( env: Env, msg: IbcPacketTimeoutMsg, ) -> Result { - let channel_info = CHANNEL_INFO.load(deps.storage, &msg.packet.src.channel_id)?; + let channel = query_ibc_channel(deps.as_ref(), msg.packet.src.channel_id.clone())?; let info = MessageInfo { sender: msg.relayer, funds: Default::default(), }; - match channel_info.protocol_version.as_str() { + match channel.version.as_str() { Ics20Protocol::VERSION => (Ics20Protocol { common: ProtocolCommon { deps, env, info, - channel: channel_info, + channel, }, }) .send_timeout(msg.packet), @@ -302,7 +301,7 @@ pub fn ibc_packet_timeout( deps, env, info, - channel: channel_info, + channel, }, }) .send_timeout(msg.packet), @@ -312,3 +311,310 @@ pub fn ibc_packet_timeout( }), } } + +pub(crate) fn execute_union_ibc( + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: UnionIbcMsg, +) -> Result, ContractError> { + let ibc_host = CONFIG.load(deps.storage)?.ibc_host; + if info.sender != ibc_host { + return Err(ContractError::OnlyIBCHost); + } + match msg { + UnionIbcMsg::OnChannelOpenInit { + channel_id, + version, + .. + } => { + if version != Ucs01Protocol::VERSION { + return Err(ContractError::UnknownProtocol { + channel_id: channel_id.to_string(), + protocol_version: version.to_string(), + }); + } + Ok(Response::new()) + } + UnionIbcMsg::OnChannelOpenTry { + channel_id, + version, + counterparty_version, + .. + } => { + if version != Ucs01Protocol::VERSION { + return Err(ContractError::UnknownProtocol { + channel_id: channel_id.to_string(), + protocol_version: version.to_string(), + }); + } + if counterparty_version != Ucs01Protocol::VERSION { + return Err(ContractError::UnknownProtocol { + channel_id: channel_id.to_string(), + protocol_version: counterparty_version.to_string(), + }); + } + Ok(Response::new()) + } + UnionIbcMsg::OnChannelOpenAck { .. } => Ok(Response::new()), + UnionIbcMsg::OnChannelOpenConfirm { .. } => Ok(Response::new()), + UnionIbcMsg::OnChannelCloseInit { .. } => Err(ContractError::Unauthorized), + UnionIbcMsg::OnChannelCloseConfirm { .. } => Err(ContractError::Unauthorized), + UnionIbcMsg::OnIntentRecvPacket { .. } => Err(ContractError::Unsupported), + UnionIbcMsg::OnRecvPacket { + packet, relayer, .. + } => { + let channel = deps.querier.query_wasm_smart::( + &ibc_host, + &UnionIbcQuery::GetChannel { + channel_id: packet.destinationChannel, + }, + )?; + + let info = MessageInfo { + sender: Addr::unchecked(relayer), + funds: Default::default(), + }; + + let ibc_endpoint_src = IbcEndpoint { + port_id: hex::encode(channel.counterpartyPortId), + channel_id: packet.sourceChannel.to_string(), + }; + + let ibc_endpoint_dst = IbcEndpoint { + port_id: format!("wasm.{}", env.contract.address), + channel_id: packet.destinationChannel.to_string(), + }; + + let ibc_channel = IbcChannel::new( + ibc_endpoint_dst.clone(), + ibc_endpoint_src.clone(), + cosmwasm_std::IbcOrder::Ordered, + channel.version.clone(), + channel.connectionId.to_string(), + ); + + let ibc_packet = IbcPacket::new( + packet.data.to_vec(), + ibc_endpoint_src, + ibc_endpoint_dst, + 0, + IbcTimeout::with_both( + IbcTimeoutBlock { + revision: 0, + height: packet.timeoutHeight, + }, + Timestamp::from_nanos(packet.timeoutTimestamp), + ), + ); + + let msg = match channel.version.as_ref() { + Ics20Protocol::VERSION => Ok((Ics20Protocol { + common: ProtocolCommon { + deps, + env, + info, + channel: ibc_channel, + }, + }) + .receive(ibc_packet)), + Ucs01Protocol::VERSION => Ok((Ucs01Protocol { + common: ProtocolCommon { + deps, + env, + info, + channel: ibc_channel, + }, + }) + .receive(ibc_packet)), + v => Err(ContractError::UnknownProtocol { + channel_id: packet.destinationChannel.to_string(), + protocol_version: v.into(), + }), + }?; + + // Marshal back the message to a base Response + let mut response = Response::new() + .add_submessages(msg.messages) + .add_events(msg.events) + .add_attributes(msg.attributes); + + // Instantly dispatches the acknowledgement back to the host if not async. + if let Some(ack) = msg.acknowledgement { + response = response.add_message(wasm_execute( + &ibc_host, + &UnionIbcHostMsg::WriteAcknowledgement(MsgWriteAcknowledgement { + channel_id: packet.destinationChannel, + packet, + acknowledgement: Vec::from(ack).into(), + }), + vec![], + )?); + } + + Ok(response) + } + UnionIbcMsg::OnAcknowledgementPacket { + packet, + relayer, + acknowledgement, + } => { + let relayer = Addr::unchecked(relayer); + + let channel = deps.querier.query_wasm_smart::( + &ibc_host, + &UnionIbcQuery::GetChannel { + channel_id: packet.destinationChannel, + }, + )?; + + let info = MessageInfo { + sender: relayer.clone(), + funds: Default::default(), + }; + + let ibc_endpoint_src = IbcEndpoint { + port_id: hex::encode(channel.counterpartyPortId), + channel_id: packet.sourceChannel.to_string(), + }; + + let ibc_endpoint_dst = IbcEndpoint { + port_id: format!("wasm.{}", env.contract.address), + channel_id: packet.destinationChannel.to_string(), + }; + + let ibc_channel = IbcChannel::new( + ibc_endpoint_src.clone(), + ibc_endpoint_dst.clone(), + cosmwasm_std::IbcOrder::Ordered, + channel.version.clone(), + channel.connectionId.to_string(), + ); + + let ibc_packet = IbcPacket::new( + packet.data.to_vec(), + ibc_endpoint_src, + ibc_endpoint_dst, + 0, + IbcTimeout::with_both( + IbcTimeoutBlock { + revision: 0, + height: packet.timeoutHeight, + }, + Timestamp::from_nanos(packet.timeoutTimestamp), + ), + ); + + let msg = IbcPacketAckMsg::new( + IbcAcknowledgement::new(acknowledgement.to_vec()), + ibc_packet, + relayer, + ); + + let response = match channel.version.as_ref() { + Ics20Protocol::VERSION => Ok((Ics20Protocol { + common: ProtocolCommon { + deps, + env, + info, + channel: ibc_channel, + }, + }) + .send_ack(msg)), + Ucs01Protocol::VERSION => Ok((Ucs01Protocol { + common: ProtocolCommon { + deps, + env, + info, + channel: ibc_channel, + }, + }) + .send_ack(msg)), + v => Err(ContractError::UnknownProtocol { + channel_id: packet.destinationChannel.to_string(), + protocol_version: v.into(), + }), + }??; + + Ok(Response::new() + .add_submessages(response.messages) + .add_events(response.events) + .add_attributes(response.attributes)) + } + UnionIbcMsg::OnTimeoutPacket { packet, relayer } => { + let channel = deps.querier.query_wasm_smart::( + &ibc_host, + &UnionIbcQuery::GetChannel { + channel_id: packet.destinationChannel, + }, + )?; + + let info = MessageInfo { + sender: Addr::unchecked(relayer), + funds: Default::default(), + }; + + let ibc_endpoint_src = IbcEndpoint { + port_id: hex::encode(channel.counterpartyPortId), + channel_id: packet.sourceChannel.to_string(), + }; + + let ibc_endpoint_dst = IbcEndpoint { + port_id: format!("wasm.{}", env.contract.address), + channel_id: packet.destinationChannel.to_string(), + }; + + let ibc_channel = IbcChannel::new( + ibc_endpoint_src.clone(), + ibc_endpoint_dst.clone(), + cosmwasm_std::IbcOrder::Ordered, + channel.version.clone(), + channel.connectionId.to_string(), + ); + + let ibc_packet = IbcPacket::new( + packet.data.to_vec(), + ibc_endpoint_src, + ibc_endpoint_dst, + 0, + IbcTimeout::with_both( + IbcTimeoutBlock { + revision: 0, + height: packet.timeoutHeight, + }, + Timestamp::from_nanos(packet.timeoutTimestamp), + ), + ); + + let response = match channel.version.as_ref() { + Ics20Protocol::VERSION => Ok((Ics20Protocol { + common: ProtocolCommon { + deps, + env, + info, + channel: ibc_channel, + }, + }) + .send_timeout(ibc_packet)), + Ucs01Protocol::VERSION => Ok((Ucs01Protocol { + common: ProtocolCommon { + deps, + env, + info, + channel: ibc_channel, + }, + }) + .send_timeout(ibc_packet)), + v => Err(ContractError::UnknownProtocol { + channel_id: packet.destinationChannel.to_string(), + protocol_version: v.into(), + }), + }??; + + Ok(Response::new() + .add_submessages(response.messages) + .add_events(response.events) + .add_attributes(response.attributes)) + } + } +} diff --git a/cosmwasm/ucs01-relay/src/ibc/tests.rs b/cosmwasm/ucs01-relay/src/ibc/tests.rs deleted file mode 100644 index 03ed3a9035..0000000000 --- a/cosmwasm/ucs01-relay/src/ibc/tests.rs +++ /dev/null @@ -1,1049 +0,0 @@ -use cosmwasm_std::{ - coin, coins, - testing::{MockApi, MockStorage}, - Addr, Api, Binary, BlockInfo, Coin, CustomMsg, CustomQuery, Empty, IbcEndpoint, IbcOrder, - IbcTimeout, Querier, Storage, Uint128, -}; -use cw_multi_test::{ - error::AnyResult, - ibc::{ - relayer::{create_channel, create_connection, ChannelCreationResult}, - types::IbcPacketData, - IbcSimpleModule, - }, - App, AppBuilder, AppResponse, BankKeeper, BankSudo, ContractWrapper, CosmosRouter, - DistributionKeeper, Executor, GovFailingModule, Module, StakeKeeper, StargateFailing, SudoMsg, - WasmKeeper, -}; -use serde::de::DeserializeOwned; -use token_factory_api::TokenFactoryMsg; -use ucs01_relay_api::{ - middleware::{Memo, PacketForward}, - protocol::TransferProtocol, - types::make_foreign_denom, -}; -use unionlabs::{ - id::{ChannelId, PortId}, - validated::Validated, -}; - -use crate::{ - contract::{execute, instantiate, query}, - error::ContractError, - ibc::{ - enforce_order_and_version, ibc_channel_close, ibc_channel_connect, ibc_channel_open, - ibc_packet_ack, ibc_packet_receive, ibc_packet_timeout, reply, IbcChannel, - }, - msg::{ExecuteMsg, InstantiateMsg, TransferMsg}, - protocol::{encode_denom_hash, hash_denom, Ics20Protocol, Ucs01Protocol}, - state::{ChannelInfo, CHANNEL_INFO}, -}; - -// cspell:ignore jvcc -const MOCK_CREATOR: &str = "src1a0j2w49wgs4f9wwk09t4qp35ls2vpx88jvcc2z"; -const MOCK_CREATOR_DEST: &str = "dst1a0j2w49wgs4f9wwk09t4qp35ls2vpx88jvcc2z"; - -/// Creates a new BasicApp instance with a custom message type. -/// -/// # Safety -/// -/// This function uses `unsafe` to transmute the type of `BasicAppBuilder` to one with a different `CustomMsg` type. -/// The `unsafe` block is necessary because the fields of `BasicAppBuilder` are private, and its initialization -/// functions are implemented only for a specific `CustomMsg` type. By using `std::mem::transmute`, we bypass the -/// type safety checks, which is generally unsafe and should be avoided if possible. -/// -/// This pattern is required because `cw-multi-test` does not currently support initializing `BasicAppBuilder` -/// with a generic `CustomMsg` type directly. An issue has been opened on the `cw-multi-test` repository -/// to address this limitation and explore potential solutions. -/// -fn create_app(prefix: &'static str) -> BasicApp { - let application = cw_multi_test::BasicAppBuilder::::new_custom(); - let application: BasicAppBuilder = - unsafe { std::mem::transmute(application) }; - application - .with_custom(CustomCrossChainTransferModule) - .with_api(MockApi::default().with_prefix(prefix)) - .with_ibc(IbcSimpleModule) - .build(|_, _, _| {}) -} - -pub struct CustomCrossChainTransferModule; - -pub type BasicApp = App< - BankKeeper, - MockApi, - MockStorage, - CustomCrossChainTransferModule, - WasmKeeper, - StakeKeeper, - DistributionKeeper, - IbcSimpleModule, - GovFailingModule, - StargateFailing, ->; - -pub type BasicAppBuilder = AppBuilder< - BankKeeper, - MockApi, - MockStorage, - CustomCrossChainTransferModule, - WasmKeeper, - StakeKeeper, - DistributionKeeper, - IbcSimpleModule, - GovFailingModule, - StargateFailing, ->; - -impl Module for CustomCrossChainTransferModule { - type ExecT = TokenFactoryMsg; - type QueryT = Empty; - type SudoT = Empty; - - fn execute( - &self, - api: &dyn Api, - storage: &mut dyn Storage, - router: &dyn CosmosRouter, - block: &BlockInfo, - _sender: Addr, - msg: Self::ExecT, - ) -> AnyResult - where - ExecC: CustomMsg + DeserializeOwned + 'static, - QueryC: CustomQuery + DeserializeOwned + 'static, - { - match msg { - TokenFactoryMsg::MintTokens { - denom, - amount, - mint_to_address, - } => router.sudo( - api, - storage, - block, - SudoMsg::Bank(BankSudo::Mint { - amount: coins(amount.into(), denom), - to_address: mint_to_address, - }), - ), - // TokenFactoryMsg::BurnTokens { denom, amount, burn_from_address } => - // { - // println!("burning tokens, denom: {}, amount: {}, burn_from_address: {}", denom, amount, burn_from_address); - // router.sudo( - // api, - // storage, - // block, - // SudoMsg::Bank(BankSudo::Burn { - // amount: coins(amount.into(), denom), - // from_address: burn_from_address, - // }), - // ) - // } - _ => Ok(AppResponse::default()), - } - } - - fn query( - &self, - _api: &dyn Api, - _storage: &dyn Storage, - _querier: &dyn Querier, - _block: &BlockInfo, - _request: Self::QueryT, - ) -> AnyResult { - unimplemented!() - } - - fn sudo( - &self, - _api: &dyn Api, - _storage: &mut dyn Storage, - _router: &dyn CosmosRouter, - _block: &BlockInfo, - _msg: Self::SudoT, - ) -> AnyResult - where - ExecC: CustomMsg + DeserializeOwned + 'static, - QueryC: CustomQuery + DeserializeOwned + 'static, - { - unimplemented!() - } -} - -fn store_and_instantiate_contract( - app: &mut BasicApp, - creator_addr: &str, - funds: Vec, - gov_contract: &str, -) -> (String, Addr) { - let creator_addr = app.api().addr_make(creator_addr); - let gov_contract = app.api().addr_make(gov_contract); - - app.init_modules(|router, _api, storage| { - router - .bank - .init_balance(storage, &creator_addr, funds.clone()) - .unwrap(); - }); - - let contract: Box<_> = Box::new( - ContractWrapper::new(execute, instantiate, query) - .with_reply(reply) - .with_ibc( - ibc_channel_open, - ibc_channel_connect, - ibc_channel_close, - ibc_packet_receive, - ibc_packet_ack, - ibc_packet_timeout, - ), - ); - - let code_id = app.store_code_with_creator(creator_addr.clone(), contract); - assert_eq!(1, code_id); - - let instantiate_msg = InstantiateMsg { - channel: None, - default_timeout: 1000, - gov_contract: gov_contract.to_string(), - }; - - let contract_addr = app - .instantiate_contract( - code_id, - creator_addr.clone(), - &instantiate_msg, - &[], - "contract", - None, - ) - .unwrap(); - - (creator_addr.to_string(), contract_addr) -} - -fn create_ibc_connection_and_channel( - app1: &mut BasicApp, - app2: &mut BasicApp, - contract_addr1: &Addr, - contract_addr2: &Addr, -) -> (String, String, String, String, String, String) { - let port1 = "wasm.".to_string() + contract_addr1.as_str(); - let port2 = "wasm.".to_string() + contract_addr2.as_str(); - - let (src_connection_id, dest_connection_id) = create_connection(app1, app2).unwrap(); - - let ChannelCreationResult { - src_channel, - dst_channel, - .. - } = create_channel( - app1, - app2, - src_connection_id.clone(), - port1.clone(), - port2.clone(), - Ics20Protocol::VERSION.to_string(), - IbcOrder::Unordered, - ) - .unwrap(); - - ( - src_connection_id, - dest_connection_id, - src_channel, - dst_channel, - port1, - port2, - ) -} - -fn create_factory_denom(contract_addr: &Addr, foreign_denom: &str) -> String { - let hashed_denom = hash_denom(foreign_denom); - - let normalized_denom: String = encode_denom_hash(hashed_denom); - format!("factory/{}/{}", contract_addr, normalized_denom) -} -fn send_ibc_packet( - app: &mut BasicApp, - sender_addr: Addr, - contract_addr: Addr, - msg: ExecuteMsg, - funds: Vec, -) -> AppResponse { - app.execute_contract(sender_addr, contract_addr, &msg, &funds) - .unwrap() -} - -fn receive_ibc_packet( - app: &mut BasicApp, - src_port_id: String, - src_channel_id: String, - dst_port_id: String, - dst_channel_id: String, - packet_data: Vec, - timeout: IbcTimeout, -) -> AppResponse { - let res = app.sudo(cw_multi_test::SudoMsg::Ibc( - cw_multi_test::ibc::IbcPacketRelayingMsg::Receive { - packet: IbcPacketData { - ack: None, - src_port_id, - src_channel_id, - dst_port_id, - dst_channel_id, - sequence: 1, - data: packet_data.into(), - timeout, - }, - }, - )); - res.unwrap() -} - -fn assert_balance( - app: &BasicApp, - addr: &str, - denom: &str, - expected_balance: Uint128, - error_msg: &str, -) { - let balance_creator = app.wrap().query_balance(addr, denom).unwrap(); - - assert_eq!( - balance_creator.amount, expected_balance, - "Balance of {} should be {} {}. Error: {}", - addr, expected_balance, denom, error_msg - ); -} - -#[allow(clippy::too_many_arguments)] -fn transfer_tokens( - src_app: &mut BasicApp, - dst_app: &mut BasicApp, - src_creator_addr: &str, - src_contract_addr: &Addr, - dst_contract_addr: &Addr, - src_port: &str, - dst_port: &str, - src_channel: &str, - dst_channel: &str, - denom: &str, - amount: Uint128, -) { - // Transfer message - let transfer_msg = ExecuteMsg::Transfer(TransferMsg { - channel: src_channel.to_string(), - receiver: dst_contract_addr.to_string(), - timeout: None, - memo: "".to_string(), - fees: None, - }); - - // Execute transfer - let res = send_ibc_packet( - src_app, - Addr::unchecked(src_creator_addr.to_string()), - src_contract_addr.clone(), - transfer_msg, - vec![coin(amount.u128(), denom)], - ); - - let packet_data_hex = res - .events - .iter() - .find(|event| event.ty == "send_packet") - .and_then(|event| { - event - .attributes - .iter() - .find(|attr| attr.key == "packet_data_hex") - }) - .map(|attr| attr.value.clone()) - .expect("packet_data_hex should be present"); - - let packet_data_bytes = - hex::decode(packet_data_hex).expect("Decoding packet_data_hex should succeed"); - - let timeout = IbcTimeout::with_timestamp(dst_app.block_info().time.plus_seconds(60)); - - receive_ibc_packet( - dst_app, - src_port.to_string(), - src_channel.to_string(), - dst_port.to_string(), - dst_channel.to_string(), - packet_data_bytes, - timeout, - ); -} - -#[test] -fn simple_transfer() { - let funds = vec![coin(100_000, "muno")]; - let denom = "muno"; - - // Create two apps - let mut src_app = create_app("src"); - let mut dst_app = create_app("dst"); - - // Store and instantiate contracts in both apps - let (src_creator_addr, src_contract_addr) = - store_and_instantiate_contract(&mut src_app, MOCK_CREATOR, funds.clone(), MOCK_CREATOR); - - let (_, dst_contract_addr) = - store_and_instantiate_contract(&mut dst_app, MOCK_CREATOR_DEST, vec![], MOCK_CREATOR_DEST); - - // Create IBC connection and channel - let (_, _, src_channel, dst_channel, src_port, dst_port) = create_ibc_connection_and_channel( - &mut src_app, - &mut dst_app, - &src_contract_addr, - &dst_contract_addr, - ); - - let endpoint = IbcEndpoint { - port_id: dst_port.clone(), - channel_id: dst_channel.clone(), - }; - let foreign_denom = make_foreign_denom(&endpoint, denom); - let factory_denom: String = create_factory_denom(&dst_contract_addr, &foreign_denom); - - // Check initial balances - assert_balance( - &src_app, - &src_creator_addr, - denom, - Uint128::new(100_000), - "initial source balance is not 100k", - ); - assert_balance( - &dst_app, - dst_contract_addr.as_str(), - &factory_denom, - Uint128::new(0), - "initial destination balance is not 0", - ); - - // Transfer tokens from src_app to dst_app - transfer_tokens( - &mut src_app, - &mut dst_app, - &src_creator_addr, - &src_contract_addr, - &dst_contract_addr, - &src_port, - &dst_port, - &src_channel, - &dst_channel, - denom, - Uint128::new(100_000), - ); - - // Check balances after transfer - assert_balance( - &src_app, - &src_creator_addr, - denom, - Uint128::new(0), - "source balance is not 0 after transfer", - ); - assert_balance( - &dst_app, - dst_contract_addr.as_str(), - &factory_denom, - Uint128::new(100_000), - "destination balance is not 100k after transfer", - ); -} -#[test] -fn send_back_wrapped_tokens() { - // Setup apps, instantiate contracts, create connection and channels - let funds = vec![coin(100_000, "muno")]; - let denom = "muno"; - - let mut src_app = create_app("src"); - let mut dst_app = create_app("dst"); - - let (src_creator_addr, src_contract_addr) = - store_and_instantiate_contract(&mut src_app, MOCK_CREATOR, funds.clone(), MOCK_CREATOR); - - let (_, dst_contract_addr) = - store_and_instantiate_contract(&mut dst_app, MOCK_CREATOR_DEST, vec![], MOCK_CREATOR_DEST); - - let (_, _, src_channel, dst_channel, src_port, dst_port) = create_ibc_connection_and_channel( - &mut src_app, - &mut dst_app, - &src_contract_addr, - &dst_contract_addr, - ); - - let endpoint = IbcEndpoint { - port_id: dst_port.clone(), - channel_id: dst_channel.clone(), - }; - let foreign_denom = make_foreign_denom(&endpoint, denom); - let factory_denom: String = create_factory_denom(&dst_contract_addr, &foreign_denom); - - // Perform initial transfer from src_app to dst_app - transfer_tokens( - &mut src_app, - &mut dst_app, - &src_creator_addr, - &src_contract_addr, - &dst_contract_addr, - &src_port, - &dst_port, - &src_channel, - &dst_channel, - denom, - Uint128::new(100_000), - ); - - // Check balances after transfer - assert_balance( - &src_app, - &src_creator_addr, - denom, - Uint128::new(0), - "source balance is not 0 after transfer", - ); - assert_balance( - &dst_app, - dst_contract_addr.as_str(), - &factory_denom, - Uint128::new(100_000), - "destination balance is not 100k after transfer", - ); - - // Perform transfer back from dst_app to src_app - transfer_tokens( - &mut dst_app, - &mut src_app, - dst_contract_addr.as_str(), - &dst_contract_addr, - &Addr::unchecked(src_creator_addr.clone()), - &dst_port, - &src_port, - &dst_channel, - &src_channel, - &factory_denom, - Uint128::new(100_000), - ); - - // Check balances after transfer - assert_balance( - &src_app, - &src_creator_addr, - denom, - Uint128::new(100_000), - "source balance is not 100k after transferring wrapped token back", - ); - - // it can't be 0 because we don't have burn functionality so we can't burn - // the locked tokens in app2, lets assume it will work anyway. - // assert_balance(&dst_app, &dst_contract_addr, &factory_denom, Uint128::new(100_000)); -} - -#[test] -fn test_pfm_valid_memo() { - let funds = vec![coin(100_000, "muno")]; - let mut src_app = create_app("src"); - let mut dst_app = create_app("dst"); - let mut fwd_app = create_app("fwd"); - - let (src_creator_addr, src_contract_addr) = - store_and_instantiate_contract(&mut src_app, MOCK_CREATOR, funds.clone(), MOCK_CREATOR); - - let (_, dst_contract_addr) = - store_and_instantiate_contract(&mut dst_app, MOCK_CREATOR_DEST, vec![], MOCK_CREATOR_DEST); - - let (_, fwd_contract_addr) = store_and_instantiate_contract( - &mut fwd_app, - "fwd1a0j2w49wgs4f9wwk09t4qp35ls2vpx88jvcc2z", - vec![], - "fwd1a0j2w49wgs4f9wwk09t4qp35ls2vpx88jvcc2z", - ); - - let (_, _, src_channel, dst_channel, src_port, dst_port) = create_ibc_connection_and_channel( - &mut src_app, - &mut dst_app, - &src_contract_addr, - &dst_contract_addr, - ); - - let (_, _, dst_src_channel, fwd_dst_channel, dst_src_port, fwd_dst_port) = - create_ibc_connection_and_channel( - &mut dst_app, - &mut fwd_app, - &dst_contract_addr, - &fwd_contract_addr, - ); - - // Save the channel info for forward channels - let dst_channel_info = ChannelInfo { - endpoint: IbcEndpoint { - port_id: dst_src_port.clone(), - channel_id: dst_src_channel.clone(), - }, - counterparty_endpoint: IbcEndpoint { - port_id: src_port.clone(), - channel_id: src_channel.clone(), - }, - connection_id: "connection-0".to_string(), - protocol_version: Ics20Protocol::VERSION.to_string(), - }; - - CHANNEL_INFO - .save(dst_app.storage_mut(), &dst_src_channel, &dst_channel_info) - .unwrap(); - - let fwd_channel_info = ChannelInfo { - endpoint: IbcEndpoint { - port_id: fwd_dst_port.clone(), - channel_id: fwd_dst_channel.clone(), - }, - counterparty_endpoint: IbcEndpoint { - port_id: dst_src_port.clone(), - channel_id: dst_src_channel.clone(), - }, - connection_id: "connection-0".to_string(), - protocol_version: Ics20Protocol::VERSION.to_string(), - }; - - CHANNEL_INFO - .save(fwd_app.storage_mut(), &fwd_dst_channel, &fwd_channel_info) - .unwrap(); - - let memo = serde_json_wasm::to_string( - &(Memo::Forward { - forward: PacketForward { - receiver: Validated::new(fwd_contract_addr.to_string()).unwrap(), - port: PortId::new(fwd_dst_port.clone()).unwrap(), - channel: ChannelId::from_str_prefixed(&fwd_dst_channel).unwrap(), - next: None, - retries: 1, - return_info: None, - timeout: "1m".to_string(), - fees: None, - }, - }), - ) - .expect("can convert pfm memo to json string"); - - let endpoint = IbcEndpoint { - port_id: dst_port.clone(), - channel_id: dst_channel.clone(), - }; - let foreign_denom = make_foreign_denom(&endpoint, "muno"); - let factory_denom: String = create_factory_denom(&dst_contract_addr, &foreign_denom); - - let transfer_msg = ExecuteMsg::Transfer(TransferMsg { - channel: src_channel.clone(), - receiver: dst_contract_addr.to_string(), - timeout: None, - memo: memo.to_string(), - fees: None, - }); - - let res = send_ibc_packet( - &mut src_app, - Addr::unchecked(src_creator_addr.clone()), - src_contract_addr.clone(), - transfer_msg, - vec![coin(100_000, "muno")], - ); - - let packet_data_hex = res - .events - .iter() - .find(|event| event.ty == "send_packet") - .and_then(|event| { - event - .attributes - .iter() - .find(|attr| attr.key == "packet_data_hex") - }) - .map(|attr| attr.value.clone()) - .expect("packet_data_hex should be present"); - - let packet_data_bytes = - hex::decode(packet_data_hex).expect("Decoding packet_data_hex should succeed"); - - let timeout = IbcTimeout::with_timestamp(dst_app.block_info().time.plus_seconds(60)); - - receive_ibc_packet( - &mut dst_app, - src_port.clone(), - src_channel.clone(), - dst_port.clone(), - dst_channel.clone(), - packet_data_bytes.clone(), - timeout.clone(), - ); - - assert_balance( - &dst_app, - dst_contract_addr.as_str(), - &factory_denom, - Uint128::new(100_000), - "destination balance on hop chain is not 100k right before PFM execution", - ); - - receive_ibc_packet( - &mut fwd_app, - dst_src_port.clone(), - dst_src_channel.clone(), - fwd_dst_port.clone(), - fwd_dst_channel.clone(), - packet_data_bytes, - timeout, - ); - - let endpoint_forwarded = IbcEndpoint { - port_id: fwd_dst_port.clone(), - channel_id: fwd_dst_channel.clone(), - }; - let foreign_denom_forwarded = make_foreign_denom(&endpoint_forwarded, "muno"); - let factory_denom_forwarded = - create_factory_denom(&fwd_contract_addr, &foreign_denom_forwarded); - - assert_balance( - &fwd_app, - fwd_contract_addr.as_str(), - &factory_denom_forwarded, - Uint128::new(100_000), - "destination balance is not 100k after PFM", - ); -} - -#[test] -fn test_pfm_broken_memo() { - let funds = vec![coin(100_000, "muno")]; - let mut src_app = create_app("src"); - let mut dst_app = create_app("dst"); - let mut fwd_app = create_app("fwd"); - - let (src_creator_addr, src_contract_addr) = - store_and_instantiate_contract(&mut src_app, MOCK_CREATOR, funds.clone(), MOCK_CREATOR); - - let (_, dst_contract_addr) = - store_and_instantiate_contract(&mut dst_app, MOCK_CREATOR_DEST, vec![], MOCK_CREATOR_DEST); - - let (_, fwd_contract_addr) = store_and_instantiate_contract( - &mut fwd_app, - "fwd1a0j2w49wgs4f9wwk09t4qp35ls2vpx88jvcc2z", - vec![], - "fwd1a0j2w49wgs4f9wwk09t4qp35ls2vpx88jvcc2z", - ); - - let (_, _, src_channel, dst_channel, src_port, dst_port) = create_ibc_connection_and_channel( - &mut src_app, - &mut dst_app, - &src_contract_addr, - &dst_contract_addr, - ); - - let (_, _, dst_src_channel, fwd_dst_channel, dst_src_port, fwd_dst_port) = - create_ibc_connection_and_channel( - &mut dst_app, - &mut fwd_app, - &dst_contract_addr, - &fwd_contract_addr, - ); - - // Save the channel info for forward channels - let dst_channel_info = ChannelInfo { - endpoint: IbcEndpoint { - port_id: dst_src_port.clone(), - channel_id: dst_src_channel.clone(), - }, - counterparty_endpoint: IbcEndpoint { - port_id: src_port.clone(), - channel_id: src_channel.clone(), - }, - connection_id: "connection-0".to_string(), - protocol_version: Ics20Protocol::VERSION.to_string(), - }; - - CHANNEL_INFO - .save(dst_app.storage_mut(), &dst_src_channel, &dst_channel_info) - .unwrap(); - - let fwd_channel_info = ChannelInfo { - endpoint: IbcEndpoint { - port_id: fwd_dst_port.clone(), - channel_id: fwd_dst_channel.clone(), - }, - counterparty_endpoint: IbcEndpoint { - port_id: dst_src_port.clone(), - channel_id: dst_src_channel.clone(), - }, - connection_id: "connection-0".to_string(), - protocol_version: Ics20Protocol::VERSION.to_string(), - }; - - CHANNEL_INFO - .save(fwd_app.storage_mut(), &fwd_dst_channel, &fwd_channel_info) - .unwrap(); - - let broken_memo: String = format!( - "{{\"forward\":{{\"receiver\":\"{}\",\"port\":\"{}\",\"channel\":\"{}\"}}}}This_is_broken_json", - fwd_contract_addr, - fwd_dst_port, - fwd_dst_channel - ); - - let endpoint = IbcEndpoint { - port_id: dst_port.clone(), - channel_id: dst_channel.clone(), - }; - let foreign_denom = make_foreign_denom(&endpoint, "muno"); - let factory_denom: String = create_factory_denom(&dst_contract_addr, &foreign_denom); - - let transfer_msg = ExecuteMsg::Transfer(TransferMsg { - channel: src_channel.clone(), - receiver: dst_contract_addr.to_string(), - timeout: None, - memo: broken_memo.to_string(), - fees: None, - }); - - let res = send_ibc_packet( - &mut src_app, - Addr::unchecked(src_creator_addr.clone()), - src_contract_addr.clone(), - transfer_msg, - vec![coin(100_000, "muno")], - ); - - let packet_data_hex = res - .events - .iter() - .find(|event| event.ty == "send_packet") - .and_then(|event| { - event - .attributes - .iter() - .find(|attr| attr.key == "packet_data_hex") - }) - .map(|attr| attr.value.clone()) - .expect("packet_data_hex should be present"); - - let packet_data_bytes = - hex::decode(packet_data_hex).expect("Decoding packet_data_hex should succeed"); - - let timeout = IbcTimeout::with_timestamp(dst_app.block_info().time.plus_seconds(60)); - - receive_ibc_packet( - &mut dst_app, - src_port.clone(), - src_channel.clone(), - dst_port.clone(), - dst_channel.clone(), - packet_data_bytes.clone(), - timeout.clone(), - ); - - assert_balance( - &dst_app, - dst_contract_addr.as_str(), - &factory_denom, - Uint128::new(100_000), - "destination balance on hop chain is not 100k right before PFM execution", - ); - - receive_ibc_packet( - &mut fwd_app, - dst_src_port.clone(), - dst_src_channel.clone(), - fwd_dst_port.clone(), - fwd_dst_channel.clone(), - packet_data_bytes, - timeout, - ); - - let endpoint_forwarded = IbcEndpoint { - port_id: fwd_dst_port.clone(), - channel_id: fwd_dst_channel.clone(), - }; - let foreign_denom_forwarded = make_foreign_denom(&endpoint_forwarded, "muno"); - let factory_denom_forwarded = - create_factory_denom(&fwd_contract_addr, &foreign_denom_forwarded); - - assert_balance( - &fwd_app, - fwd_contract_addr.as_str(), - &factory_denom_forwarded, - Uint128::new(0), - "destination balance should be 0 after PFM because pfm message was wrong.", - ); -} - -#[test] -fn enforce_channel_version_ucs01() { - let port_id = "port-1"; - let channel_id = "channel-1"; - let connection_id = "connection-1"; - let protocol_version = Ucs01Protocol::VERSION; - let counterparty_port_id = "port-2"; - let counterparty_channel_id = "channel-2"; - enforce_order_and_version( - &IbcChannel::new( - IbcEndpoint { - port_id: port_id.into(), - channel_id: channel_id.into(), - }, - IbcEndpoint { - port_id: counterparty_port_id.into(), - channel_id: counterparty_channel_id.into(), - }, - cosmwasm_std::IbcOrder::Unordered, - protocol_version, - connection_id, - ), - None, - ) - .unwrap(); -} - -#[test] -fn enforce_channel_version_ics20() { - let port_id = "port-1"; - let channel_id = "channel-1"; - let connection_id = "connection-1"; - let protocol_version = Ics20Protocol::VERSION; - let counterparty_port_id = "port-2"; - let counterparty_channel_id = "channel-2"; - enforce_order_and_version( - &IbcChannel::new( - IbcEndpoint { - port_id: port_id.into(), - channel_id: channel_id.into(), - }, - IbcEndpoint { - port_id: counterparty_port_id.into(), - channel_id: counterparty_channel_id.into(), - }, - cosmwasm_std::IbcOrder::Unordered, - protocol_version, - connection_id, - ), - None, - ) - .unwrap() -} - -#[test] -fn enforce_channel_wrong_version() { - let port_id = "port-1"; - let channel_id = "channel-1"; - let connection_id = "connection-1"; - let protocol_version = "ucs01-0999"; - let counterparty_port_id = "port-2"; - let counterparty_channel_id = "channel-2"; - match enforce_order_and_version( - &IbcChannel::new( - IbcEndpoint { - port_id: port_id.into(), - channel_id: channel_id.into(), - }, - IbcEndpoint { - port_id: counterparty_port_id.into(), - channel_id: counterparty_channel_id.into(), - }, - cosmwasm_std::IbcOrder::Unordered, - protocol_version, - connection_id, - ), - None, - ) { - Err(ContractError::UnknownProtocol { - channel_id: unknown_channel_id, - protocol_version: unknown_protocol_version, - }) => { - assert_eq!(unknown_channel_id, channel_id); - assert_eq!(unknown_protocol_version, protocol_version); - } - _ => panic!(), - } -} - -#[test] -fn enforce_channel_counterparty_wrong_version() { - let port_id = "port-1"; - let channel_id = "channel-1"; - let connection_id = "connection-1"; - let protocol_version = Ucs01Protocol::VERSION; - let counterparty_port_id = "port-2"; - let counterparty_channel_id = "channel-2"; - let counterparty_protocol_version = "ucs01-0999"; - match enforce_order_and_version( - &IbcChannel::new( - IbcEndpoint { - port_id: port_id.into(), - channel_id: channel_id.into(), - }, - IbcEndpoint { - port_id: counterparty_port_id.into(), - channel_id: counterparty_channel_id.into(), - }, - cosmwasm_std::IbcOrder::Unordered, - protocol_version, - connection_id, - ), - Some(counterparty_protocol_version), - ) { - Err(ContractError::UnknownProtocol { - channel_id: unknown_channel_id, - protocol_version: unknown_protocol_version, - }) => { - assert_eq!(unknown_channel_id, channel_id); - assert_eq!(unknown_protocol_version, counterparty_protocol_version); - } - _ => panic!(), - } -} - -#[test] -fn enforce_channel_protocol_mismatch() { - let port_id = "port-1"; - let channel_id = "channel-1"; - let connection_id = "connection-1"; - let protocol_version = Ucs01Protocol::VERSION; - let counterparty_port_id = "port-2"; - let counterparty_channel_id = "channel-2"; - let counterparty_protocol_version = Ics20Protocol::VERSION; - let mismatch = enforce_order_and_version( - &IbcChannel::new( - IbcEndpoint { - port_id: port_id.into(), - channel_id: channel_id.into(), - }, - IbcEndpoint { - port_id: counterparty_port_id.into(), - channel_id: counterparty_channel_id.into(), - }, - cosmwasm_std::IbcOrder::Unordered, - protocol_version, - connection_id, - ), - Some(counterparty_protocol_version), - ); - match mismatch { - Err(ContractError::ProtocolMismatch { - channel_id: mismatch_channel_id, - protocol_version: mismatch_protocol_version, - counterparty_protocol_version: mismatch_counterparty_protocol_version, - }) => { - assert_eq!(mismatch_channel_id, channel_id); - assert_eq!(mismatch_protocol_version, protocol_version); - assert_eq!( - mismatch_counterparty_protocol_version, - counterparty_protocol_version - ); - } - _ => panic!(), - } -} diff --git a/cosmwasm/ucs01-relay/src/msg.rs b/cosmwasm/ucs01-relay/src/msg.rs index 0ce9d3b4eb..2c3ca9b69e 100644 --- a/cosmwasm/ucs01-relay/src/msg.rs +++ b/cosmwasm/ucs01-relay/src/msg.rs @@ -1,9 +1,8 @@ -use cosmwasm_schema::{cw_serde, QueryResponses}; +use cosmwasm_schema::cw_serde; use cosmwasm_std::{Binary, CosmosMsg, IbcChannel, IbcEndpoint, Uint512}; use token_factory_api::TokenFactoryMsg; use ucs01_relay_api::types::Fees; - -use crate::state::ChannelInfo; +use union_ibc_msg::module::UnionIbcMsg; #[cw_serde] pub struct InstantiateMsg { @@ -13,12 +12,14 @@ pub struct InstantiateMsg { pub gov_contract: String, /// If set, contract will setup the channel pub channel: Option, + // the union ibc stack host + pub ibc_host: String, } #[cw_serde] pub struct MigrateMsg {} -#[cw_serde] +#[derive(serde::Serialize, serde::Deserialize)] pub enum ExecuteMsg { /// This allows us to transfer native tokens Transfer(TransferMsg), @@ -29,10 +30,13 @@ pub enum ExecuteMsg { hash: Binary, }, /// Change the admin (must be called by current admin) - UpdateAdmin { admin: String }, + UpdateAdmin { + admin: String, + }, BatchExecute { msgs: Vec>, }, + UnionIbcMsg(UnionIbcMsg), } /// This is the message we accept via Receive @@ -51,23 +55,18 @@ pub struct TransferMsg { } #[cw_serde] -#[derive(QueryResponses)] pub enum QueryMsg { /// Return the port ID bound by this contract. - #[returns(PortResponse)] Port {}, /// Show all channels we have connected to. - #[returns(ListChannelsResponse)] ListChannels {}, /// Returns the details of the name channel, error if not created. - #[returns(ChannelResponse)] - Channel { id: String }, + Channel { + id: String, + }, /// Show the Config. - #[returns(ConfigResponse)] Config {}, - #[returns(cw_controllers::AdminResponse)] Admin {}, - #[returns(String)] ForeignDenomToLocal { source_channel: String, denom: String, @@ -75,14 +74,9 @@ pub enum QueryMsg { } #[cw_serde] -pub struct ListChannelsResponse { - pub channels: Vec, -} - -#[cw_serde] -pub struct ChannelResponse { +pub struct ChannelBalances { /// Information on the channel's connection - pub info: ChannelInfo, + pub channel: IbcChannel, /// How many tokens we currently have pending over this channel pub balances: Vec<(String, Uint512)>, } diff --git a/cosmwasm/ucs01-relay/src/protocol.rs b/cosmwasm/ucs01-relay/src/protocol.rs index 1b2b75f4d3..415023748c 100644 --- a/cosmwasm/ucs01-relay/src/protocol.rs +++ b/cosmwasm/ucs01-relay/src/protocol.rs @@ -1,9 +1,11 @@ use base58::{FromBase58, ToBase58}; use cosmwasm_std::{ - wasm_execute, Addr, Attribute, BankMsg, Binary, Coin, CosmosMsg, DepsMut, Env, HexBinary, - IbcAcknowledgement, IbcEndpoint, IbcMsg, IbcOrder, IbcPacket, IbcReceiveResponse, MessageInfo, - Uint128, Uint512, + from_json, wasm_execute, Addr, Attribute, BankMsg, Binary, Coin, CosmosMsg, DepsMut, Env, + HexBinary, IbcAcknowledgement, IbcChannel, IbcEndpoint, IbcMsg, IbcOrder, IbcPacket, + IbcReceiveResponse, IbcTimeout, IbcTimeoutBlock, MessageInfo, StdError, Timestamp, Uint128, + Uint512, WasmMsg, }; +use ibc_solidity::cosmwasm::types::ibc::{Channel, Packet}; use sha2::{Digest, Sha256}; use token_factory_api::TokenFactoryMsg; use ucs01_relay_api::{ @@ -18,34 +20,59 @@ use ucs01_relay_api::{ Ucs01TransferPacket, }, }; -use unionlabs::encoding; +use union_ibc_msg::{ + msg::{ExecuteMsg as UnionIbcHostMsg, MsgSendPacket, MsgWriteAcknowledgement}, + query::QueryMsg as UnionIbcQuery, +}; +use unionlabs::{encoding, ethereum::keccak256}; use crate::{ - contract::execute_transfer, + contract::{execute_transfer, query_ibc_channel}, error::ContractError, msg::{ExecuteMsg, TransferMsg}, state::{ - ChannelInfo, DenomHash, PfmRefundPacketKey, CHANNEL_INFO, CHANNEL_STATE, - FOREIGN_DENOM_TO_HASH, HASH_TO_FOREIGN_DENOM, IN_FLIGHT_PFM_PACKETS, MAX_SUBDENOM_LENGTH, + DenomHash, PfmRefundPacketKey, CHANNEL_STATE, CONFIG, FOREIGN_DENOM_TO_HASH, + HASH_TO_FOREIGN_DENOM, IN_FLIGHT_PFM_PACKETS, MAX_SUBDENOM_LENGTH, }, }; +pub fn packet_key(packet: &IbcPacket) -> PfmRefundPacketKey { + let timeout_block = packet.timeout.block().unwrap_or(IbcTimeoutBlock { + revision: 0, + height: 0, + }); + keccak256( + [ + &packet.data, + packet.src.channel_id.as_bytes(), + packet.src.port_id.as_bytes(), + packet.dest.channel_id.as_bytes(), + packet.dest.port_id.as_bytes(), + &packet.sequence.to_be_bytes(), + &timeout_block.revision.to_be_bytes(), + &timeout_block.height.to_be_bytes(), + &packet + .timeout + .timestamp() + .unwrap_or(Timestamp::from_nanos(0)) + .nanos() + .to_be_bytes(), + ] + .concat(), + ) + .into() +} + pub trait TransferProtocolExt<'a>: - TransferProtocol, CustomMsg = TokenFactoryMsg> + TransferProtocol + From, CustomMsg = TokenFactoryMsg> { fn common(&self) -> &ProtocolCommon<'a>; fn common_mut(&mut self) -> &mut ProtocolCommon<'a>; fn do_get_in_flight_packet(&self, forward_packet: IbcPacket) -> Option { - let refund_key = PfmRefundPacketKey { - channel_id: forward_packet.src.channel_id, - port_id: forward_packet.src.port_id, - sequence: forward_packet.sequence, - }; - IN_FLIGHT_PFM_PACKETS - .load(self.common().deps.storage, refund_key.clone()) + .load(self.common().deps.storage, packet_key(&forward_packet)) .ok() } @@ -83,21 +110,11 @@ pub trait TransferProtocolExt<'a>: ), }; - ack_msgs.push(CosmosMsg::Ibc(IbcMsg::WriteAcknowledgement { - channel_id: refund_info.origin_packet.dest.channel_id.clone(), - packet_sequence: refund_info.origin_packet.sequence, - ack: IbcAcknowledgement::new(ack_bytes), - })); + ack_msgs.push(self.write_acknowledgement(&refund_info.origin_packet, ack_bytes.into())?); + ack_attrs.push(Attribute::new(ATTR_PFM, ATTR_VALUE_PFM_ACK.to_string())); - IN_FLIGHT_PFM_PACKETS.remove( - self.common_mut().deps.storage, - PfmRefundPacketKey { - channel_id: ibc_packet.src.channel_id, - port_id: ibc_packet.src.port_id, - sequence: ibc_packet.sequence, - }, - ); + IN_FLIGHT_PFM_PACKETS.remove(self.common_mut().deps.storage, packet_key(&ibc_packet)); Ok((ack_msgs, ack_attrs)) } @@ -125,7 +142,7 @@ pub trait TransferProtocolExt<'a>: }; let transfer_msg = TransferMsg { - channel: forward.channel.clone().to_string_prefixed(), + channel: forward.channel.clone().to_string(), receiver: forward.receiver.value(), timeout: Some(timeout), memo, @@ -141,20 +158,93 @@ pub trait TransferProtocolExt<'a>: transfer_msg, )?; - let in_flight_packet = InFlightPfmPacket { - origin_sender_addr: self.common().info.sender.clone(), - origin_packet: original_packet, - forward_timeout: timeout, - forward_src_channel_id: forward.channel.to_string_prefixed(), - forward_src_port_id: forward.port.to_string(), - origin_protocol_version: Self::VERSION.to_string(), - }; - if let Some(reply_sub) = transfer .messages .iter_mut() .find(|sub| sub.id == IBC_SEND_ID) { + let forward_packet = match &reply_sub.msg { + CosmosMsg::Ibc(IbcMsg::SendPacket { + channel_id, + data, + timeout, + }) => { + let ibc_channel = + query_ibc_channel(self.common().deps.as_ref(), channel_id.clone())?; + Ok::<_, Self::Error>(IbcPacket::new( + data.to_vec(), + ibc_channel.endpoint, + ibc_channel.counterparty_endpoint, + 0, + timeout.clone(), + )) + } + CosmosMsg::Wasm(WasmMsg::Execute { msg, .. }) => { + match from_json::(msg) { + Ok(UnionIbcHostMsg::PacketSend(MsgSendPacket { + source_channel, + timeout_height, + timeout_timestamp, + data, + })) => { + let ibc_host = + CONFIG.load(self.common().deps.as_ref().storage)?.ibc_host; + let channel = self.common().deps.querier.query_wasm_smart::( + &ibc_host, + &UnionIbcQuery::GetChannel { + channel_id: source_channel, + }, + )?; + let ibc_endpoint_src = IbcEndpoint { + port_id: hex::encode(channel.counterpartyPortId), + channel_id: source_channel.to_string(), + }; + let ibc_endpoint_dst = IbcEndpoint { + port_id: format!("wasm.{}", self.common().env.contract.address), + channel_id: channel.counterpartyChannelId.to_string(), + }; + let ibc_packet = IbcPacket::new( + data.to_vec(), + ibc_endpoint_src, + ibc_endpoint_dst, + 0, + IbcTimeout::with_both( + IbcTimeoutBlock { + revision: 0, + height: timeout_height, + }, + Timestamp::from_nanos(timeout_timestamp), + ), + ); + Ok(ibc_packet) + } + _ => { + return Err(ContractError::MiddlewareError( + MiddlewareError::PacketForward( + PacketForwardError::NoReplyMessageInStack, + ), + ) + .into()) + } + } + } + _ => { + return Err( + ContractError::MiddlewareError(MiddlewareError::PacketForward( + PacketForwardError::NoReplyMessageInStack, + )) + .into(), + ) + } + }?; + + let in_flight_packet = InFlightPfmPacket { + origin_sender_addr: self.common().info.sender.clone(), + origin_packet: original_packet, + origin_protocol_version: Self::VERSION.to_string(), + forward_packet, + }; + *reply_sub = reply_sub .clone() .with_payload(serde_json_wasm::to_vec(&in_flight_packet).expect("can serialize")); @@ -659,7 +749,7 @@ pub struct ProtocolCommon<'a> { pub deps: DepsMut<'a>, pub env: Env, pub info: MessageInfo, - pub channel: ChannelInfo, + pub channel: IbcChannel, } pub struct Ics20Protocol<'a> { @@ -677,8 +767,30 @@ impl TransferProtocol for Ics20Protocol<'_> { type Error = ContractError; type Encoding = JsonWasm; - fn channel_endpoint(&self) -> &cosmwasm_std::IbcEndpoint { - &self.common.channel.endpoint + fn send_packet( + &self, + data: Binary, + timeout: IbcTimeout, + ) -> Result, Self::Error> { + Ok(IbcMsg::SendPacket { + channel_id: self.common.channel.endpoint.channel_id.clone(), + data, + timeout, + } + .into()) + } + + fn write_acknowledgement( + &self, + packet: &IbcPacket, + ack: Binary, + ) -> Result, Self::Error> { + Ok(IbcMsg::WriteAcknowledgement { + channel_id: packet.dest.channel_id.clone(), + packet_sequence: packet.sequence, + ack: IbcAcknowledgement::new(ack), + } + .into()) } fn caller(&self) -> &cosmwasm_std::Addr { @@ -843,9 +955,7 @@ impl TransferProtocol for Ics20Protocol<'_> { } fn load_channel_protocol_version(&self, channel_id: &str) -> Result { - Ok(CHANNEL_INFO - .load(self.common.deps.storage, channel_id)? - .protocol_version) + Ok(query_ibc_channel(self.common.deps.as_ref(), channel_id.to_string())?.version) } fn protocol_switch_result( @@ -875,8 +985,79 @@ impl TransferProtocol for Ucs01Protocol<'_> { type Error = ContractError; type Encoding = encoding::EthAbi; - fn channel_endpoint(&self) -> &cosmwasm_std::IbcEndpoint { - &self.common.channel.endpoint + fn send_packet( + &self, + data: Binary, + timeout: IbcTimeout, + ) -> Result, Self::Error> { + let ibc_host = CONFIG.load(self.common.deps.storage)?.ibc_host; + Ok(wasm_execute( + ibc_host, + &UnionIbcHostMsg::PacketSend(MsgSendPacket { + source_channel: self + .common + .channel + .endpoint + .channel_id + .parse() + .expect("impossible"), + timeout_height: timeout + .block() + .unwrap_or(IbcTimeoutBlock { + revision: 0, + height: 0, + }) + .height, + timeout_timestamp: timeout + .timestamp() + .unwrap_or(Timestamp::from_nanos(0)) + .nanos(), + data: data.to_vec().into(), + }), + vec![], + )? + .into()) + } + + fn write_acknowledgement( + &self, + packet: &IbcPacket, + ack: Binary, + ) -> Result, Self::Error> { + let ibc_host = CONFIG.load(self.common.deps.storage)?.ibc_host; + Ok(wasm_execute( + ibc_host, + &UnionIbcHostMsg::WriteAcknowledgement(MsgWriteAcknowledgement { + channel_id: self + .common + .channel + .endpoint + .channel_id + .parse() + .expect("impossible"), + packet: Packet { + sourceChannel: packet.src.channel_id.parse().expect("impossible"), + destinationChannel: packet.dest.channel_id.parse().expect("impossible"), + data: packet.data.to_vec().into(), + timeoutHeight: packet + .timeout + .block() + .unwrap_or(IbcTimeoutBlock { + revision: 0, + height: 0, + }) + .height, + timeoutTimestamp: packet + .timeout + .timestamp() + .unwrap_or(Timestamp::from_nanos(0)) + .nanos(), + }, + acknowledgement: ack.to_vec().into(), + }), + vec![], + )? + .into()) } fn caller(&self) -> &cosmwasm_std::Addr { @@ -1073,9 +1254,7 @@ impl TransferProtocol for Ucs01Protocol<'_> { } fn load_channel_protocol_version(&self, channel_id: &str) -> Result { - Ok(CHANNEL_INFO - .load(self.common.deps.storage, channel_id)? - .protocol_version) + Ok(query_ibc_channel(self.common.deps.as_ref(), channel_id.to_string())?.version) } fn protocol_switch_result( @@ -1094,7 +1273,7 @@ impl TransferProtocol for Ucs01Protocol<'_> { mod tests { use cosmwasm_std::{ testing::{message_info, mock_dependencies, mock_env}, - wasm_execute, Addr, BankMsg, Coin, CosmosMsg, IbcEndpoint, Uint128, + wasm_execute, Addr, BankMsg, Coin, CosmosMsg, IbcChannel, IbcEndpoint, Uint128, }; use token_factory_api::TokenFactoryMsg; use ucs01_relay_api::{ @@ -1107,7 +1286,7 @@ mod tests { error::ContractError, msg::ExecuteMsg, protocol::{encode_denom_hash, normalize_for_ibc_transfer, Ics20Protocol}, - state::{ChannelInfo, DenomHash}, + state::DenomHash, }; #[test] @@ -1120,18 +1299,19 @@ mod tests { deps: deps.as_mut(), env: mock_env(), info: message_info(&Addr::unchecked(""), &[]), - channel: ChannelInfo { - endpoint: IbcEndpoint { + channel: IbcChannel::new( + IbcEndpoint { port_id: "".to_string(), - channel_id: String::new(), + channel_id: String::new() }, - counterparty_endpoint: IbcEndpoint { + IbcEndpoint { port_id: "".to_string(), - channel_id: String::new(), + channel_id: String::new() }, - connection_id: "".into(), - protocol_version: "".into(), - }, + cosmwasm_std::IbcOrder::Ordered, + "", + "" + ), }, } .convert_ack_to_foreign_protocol("ucs01-relay-1", Ok(vec![1])) diff --git a/cosmwasm/ucs01-relay/src/state.rs b/cosmwasm/ucs01-relay/src/state.rs index 11e49cadc9..fdabe8e942 100644 --- a/cosmwasm/ucs01-relay/src/state.rs +++ b/cosmwasm/ucs01-relay/src/state.rs @@ -1,5 +1,5 @@ use cosmwasm_schema::cw_serde; -use cosmwasm_std::{IbcEndpoint, Uint512}; +use cosmwasm_std::{Addr, IbcEndpoint, Uint512}; use cw_controllers::Admin; use cw_storage_plus::{Item, KeyDeserialize, Map, Prefixer, PrimaryKey}; use serde::{Deserialize, Serialize}; @@ -10,9 +10,6 @@ pub const ADMIN: Admin = Admin::new("admin"); pub const CONFIG: Item = Item::new("config"); -/// static info on one channel that doesn't change -pub const CHANNEL_INFO: Map<&str, ChannelInfo> = Map::new("channel_info"); - /// indexed by (channel_id, denom) maintaining the balance of the channel in that currency pub const CHANNEL_STATE: Map<(&str, &str), ChannelState> = Map::new("channel_state"); @@ -29,49 +26,27 @@ pub const MAX_SUBDENOM_LENGTH: usize = 44; /// /// All of the information in this key is available both when the packet is sent, and when /// the acknowledgement is received for this packet. -#[derive(Debug, Clone)] -pub struct PfmRefundPacketKey { - /// The source channel of the hop between B -> C. - pub channel_id: String, - /// The source port of the hop between B -> C. - pub port_id: String, - /// The send sequence for this packet (the MsgIbcSendResponse.sequence when doing the forward, and the - pub sequence: u64, -} - -impl Prefixer<'_> for PfmRefundPacketKey { - fn prefix(&self) -> Vec { - let mut res = self.sequence.prefix(); - res.extend(self.port_id.prefix()); - res.extend(self.channel_id.prefix()); - res - } -} - -impl KeyDeserialize for PfmRefundPacketKey { - type Output = <(String, String, u64) as KeyDeserialize>::Output; +#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[repr(transparent)] +pub struct PfmRefundPacketKey(pub(crate) H256); - fn from_vec(value: Vec) -> cosmwasm_std::StdResult { - <(String, String, u64) as KeyDeserialize>::from_vec(value) +impl From for PfmRefundPacketKey { + fn from(value: H256) -> Self { + Self(value) } - - const KEY_ELEMS: u16 = 4; } impl<'a> PrimaryKey<'a> for PfmRefundPacketKey { - type Prefix = <(String, String, u64) as PrimaryKey<'a>>::Prefix; + type Prefix = <[u8; 32] as PrimaryKey<'a>>::Prefix; - type SubPrefix = <(String, String, u64) as PrimaryKey<'a>>::SubPrefix; + type SubPrefix = <[u8; 32] as PrimaryKey<'a>>::SubPrefix; - type Suffix = <(String, String, u64) as PrimaryKey<'a>>::Suffix; + type Suffix = <[u8; 32] as PrimaryKey<'a>>::Suffix; - type SuperSuffix = <(String, String, u64) as PrimaryKey<'a>>::SuperSuffix; + type SuperSuffix = <[u8; 32] as PrimaryKey<'a>>::SuperSuffix; fn key(&self) -> Vec { - let mut res = self.sequence.prefix(); - res.extend(self.port_id.prefix()); - res.extend(self.channel_id.prefix()); - res + self.0.get().key() } } @@ -160,15 +135,5 @@ pub struct ChannelState { #[cw_serde] pub struct Config { pub default_timeout: u64, -} - -#[cw_serde] -pub struct ChannelInfo { - pub endpoint: IbcEndpoint, - /// the remote channel/port we connect to - pub counterparty_endpoint: IbcEndpoint, - /// the connection this exists on (you can use to query client/consensus info) - pub connection_id: String, - /// the protocol version, used to branch on the implementation - pub protocol_version: String, + pub ibc_host: Addr, } diff --git a/cosmwasm/union-ibc-msg/Cargo.toml b/cosmwasm/union-ibc-msg/Cargo.toml new file mode 100644 index 0000000000..6cafb58c34 --- /dev/null +++ b/cosmwasm/union-ibc-msg/Cargo.toml @@ -0,0 +1,18 @@ +[package] +authors = ["Hussein Ait Lahcen "] +edition = { workspace = true } +license-file = { workspace = true } +name = "union-ibc-msg" +repository = "https://github.com/unionlabs/union" +version = "1.0.0" + +[lints] +workspace = true + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +ibc-solidity = { workspace = true, features = ["serde"] } +serde = { workspace = true, features = ["derive"] } +unionlabs = { workspace = true, features = ["ethabi"] } diff --git a/cosmwasm/union-ibc-msg/src/lib.rs b/cosmwasm/union-ibc-msg/src/lib.rs new file mode 100644 index 0000000000..3540baa519 --- /dev/null +++ b/cosmwasm/union-ibc-msg/src/lib.rs @@ -0,0 +1,4 @@ +pub mod lightclient; +pub mod module; +pub mod msg; +pub mod query; diff --git a/cosmwasm/union-ibc-msg/src/lightclient.rs b/cosmwasm/union-ibc-msg/src/lightclient.rs new file mode 100644 index 0000000000..b45f2b19f4 --- /dev/null +++ b/cosmwasm/union-ibc-msg/src/lightclient.rs @@ -0,0 +1,55 @@ +use unionlabs::bytes::Bytes; + +#[derive(serde::Serialize, serde::Deserialize)] +pub enum Status { + Active, + Expired, + Frozen, +} + +#[derive(serde::Serialize, serde::Deserialize)] +pub struct VerifyClientMessageUpdate { + pub height: u64, + pub consensus_state: Bytes, + pub client_state: Bytes, +} + +#[derive(serde::Serialize, serde::Deserialize)] +pub enum QueryMsg { + GetTimestamp { + client_id: u32, + height: u64, + }, + GetLatestHeight { + client_id: u32, + }, + GetStatus { + client_id: u32, + }, + VerifyCreation { + client_id: u32, + client_state: Bytes, + consensus_state: Bytes, + }, + VerifyMembership { + client_id: u32, + height: u64, + proof: Bytes, + path: Bytes, + value: Bytes, + }, + VerifyNonMembership { + client_id: u32, + height: u64, + proof: Bytes, + path: Bytes, + }, + VerifyClientMessage { + client_id: u32, + message: Bytes, + }, + Misbehaviour { + client_id: u32, + message: Bytes, + }, +} diff --git a/cosmwasm/union-ibc/src/module/msg.rs b/cosmwasm/union-ibc-msg/src/module.rs similarity index 72% rename from cosmwasm/union-ibc/src/module/msg.rs rename to cosmwasm/union-ibc-msg/src/module.rs index 786c2b83ab..5b363fbc16 100644 --- a/cosmwasm/union-ibc/src/module/msg.rs +++ b/cosmwasm/union-ibc-msg/src/module.rs @@ -1,5 +1,5 @@ -use cosmwasm_std::{Addr, Binary}; use ibc_solidity::cosmwasm::types::ibc::Packet; +use unionlabs::bytes::Bytes; #[derive(serde::Serialize, serde::Deserialize)] pub enum UnionIbcMsg { @@ -7,51 +7,51 @@ pub enum UnionIbcMsg { connection_id: u32, channel_id: u32, version: String, - relayer: Addr, + relayer: String, }, OnChannelOpenTry { connection_id: u32, channel_id: u32, version: String, counterparty_version: String, - relayer: Addr, + relayer: String, }, OnChannelOpenAck { channel_id: u32, counterparty_channel_id: u32, counterparty_version: String, - relayer: Addr, + relayer: String, }, OnChannelOpenConfirm { channel_id: u32, - relayer: Addr, + relayer: String, }, OnChannelCloseInit { channel_id: u32, - relayer: Addr, + relayer: String, }, OnChannelCloseConfirm { channel_id: u32, - relayer: Addr, + relayer: String, }, OnIntentRecvPacket { packet: Packet, - market_maker: Addr, - market_maker_msg: Binary, + market_maker: String, + market_maker_msg: Bytes, }, OnRecvPacket { packet: Packet, - relayer: Addr, - relayer_msg: Binary, + relayer: String, + relayer_msg: Bytes, }, OnAcknowledgementPacket { packet: Packet, - acknowledgement: Binary, - relayer: Addr, + acknowledgement: Bytes, + relayer: String, }, OnTimeoutPacket { packet: Packet, - relayer: Addr, + relayer: String, }, } diff --git a/cosmwasm/union-ibc/src/msg.rs b/cosmwasm/union-ibc-msg/src/msg.rs similarity index 95% rename from cosmwasm/union-ibc/src/msg.rs rename to cosmwasm/union-ibc-msg/src/msg.rs index e33c9827b2..b277aa0b55 100644 --- a/cosmwasm/union-ibc/src/msg.rs +++ b/cosmwasm/union-ibc-msg/src/msg.rs @@ -5,6 +5,7 @@ use ibc_solidity::cosmwasm::types::ibc::{ MsgIntentPacketRecv, MsgPacketAcknowledgement, MsgPacketRecv, MsgPacketTimeout, MsgUpdateClient, Packet, }; +use unionlabs::bytes::Bytes; #[derive(serde::Serialize, serde::Deserialize)] pub struct InitMsg {} @@ -44,7 +45,7 @@ pub enum ExecuteMsg { pub struct MsgWriteAcknowledgement { pub channel_id: u32, pub packet: Packet, - pub acknowledgement: Vec, + pub acknowledgement: Bytes, } #[derive(serde::Serialize, serde::Deserialize)] @@ -52,5 +53,5 @@ pub struct MsgSendPacket { pub source_channel: u32, pub timeout_height: u64, pub timeout_timestamp: u64, - pub data: Vec, + pub data: Bytes, } diff --git a/cosmwasm/union-ibc/src/query.rs b/cosmwasm/union-ibc-msg/src/query.rs similarity index 85% rename from cosmwasm/union-ibc/src/query.rs rename to cosmwasm/union-ibc-msg/src/query.rs index 19b23488fa..e121c19ff4 100644 --- a/cosmwasm/union-ibc/src/query.rs +++ b/cosmwasm/union-ibc-msg/src/query.rs @@ -1,5 +1,3 @@ -use cosmwasm_std::Addr; - #[derive(serde::Serialize, serde::Deserialize)] pub enum QueryMsg { GetTimestampAtHeight { client_id: u32, height: u64 }, @@ -9,5 +7,5 @@ pub enum QueryMsg { GetStatus { client_id: u32 }, GetClientType { client_id: u32 }, GetChannel { channel_id: u32 }, - GetChannels { contract: Addr }, + GetChannels { contract: String }, } diff --git a/cosmwasm/union-ibc/Cargo.toml b/cosmwasm/union-ibc/Cargo.toml index 8637bfd0df..8729d60b31 100644 --- a/cosmwasm/union-ibc/Cargo.toml +++ b/cosmwasm/union-ibc/Cargo.toml @@ -29,4 +29,5 @@ serde_json = { workspace = true } sha2 = { workspace = true } sha3 = { workspace = true } thiserror = { workspace = true } +union-ibc-msg = { workspace = true } unionlabs = { workspace = true, features = ["ethabi"] } diff --git a/cosmwasm/union-ibc/src/contract.rs b/cosmwasm/union-ibc/src/contract.rs index 68d78411ad..be727cc6aa 100644 --- a/cosmwasm/union-ibc/src/contract.rs +++ b/cosmwasm/union-ibc/src/contract.rs @@ -14,6 +14,12 @@ use ibc_solidity::cosmwasm::types::ibc::{ MsgConnectionOpenInit, MsgConnectionOpenTry, MsgCreateClient, MsgIntentPacketRecv, MsgPacketAcknowledgement, MsgPacketRecv, MsgPacketTimeout, MsgUpdateClient, Packet, }; +use union_ibc_msg::{ + lightclient::{QueryMsg as LightClientQuery, Status, VerifyClientMessageUpdate}, + module::{ExecuteMsg as ModuleMsg, UnionIbcMsg}, + msg::{ExecuteMsg, InitMsg, MsgRegisterClient, MsgSendPacket, MsgWriteAcknowledgement}, + query::QueryMsg, +}; use unionlabs::{ ethereum::keccak256, hash::{hash_v2::HexPrefixed, H256}, @@ -21,10 +27,6 @@ use unionlabs::{ }; use crate::{ - lightclient::query::{QueryMsg as LightClientQuery, Status, VerifyClientMessageUpdate}, - module::msg::{ExecuteMsg as ModuleMsg, UnionIbcMsg}, - msg::{ExecuteMsg, InitMsg, MsgRegisterClient, MsgSendPacket, MsgWriteAcknowledgement}, - query::QueryMsg, state::{ CHANNELS, CHANNEL_OWNER, CLIENT_CONSENSUS_STATES, CLIENT_IMPLS, CLIENT_REGISTRY, CLIENT_STATES, CLIENT_TYPES, CONNECTIONS, CONTRACT_CHANNELS, NEXT_CHANNEL_ID, @@ -348,7 +350,7 @@ pub fn execute( info.sender, channel_id, packet, - acknowledgement, + acknowledgement.into_vec(), ), ExecuteMsg::PacketSend(MsgSendPacket { source_channel, @@ -361,7 +363,7 @@ pub fn execute( source_channel, timeout_height, timeout_timestamp, - data, + data.into_vec(), ), ExecuteMsg::BatchSend(MsgBatchSend { sourceChannel, @@ -506,7 +508,10 @@ fn timeout_packet( ])) .add_message(wasm_execute( port_id, - &ModuleMsg::UnionIbcMsg(UnionIbcMsg::OnTimeoutPacket { packet, relayer }), + &ModuleMsg::UnionIbcMsg(UnionIbcMsg::OnTimeoutPacket { + packet, + relayer: relayer.into(), + }), vec![], )?)) } @@ -565,7 +570,7 @@ fn acknowledge_packet( &ModuleMsg::UnionIbcMsg(UnionIbcMsg::OnAcknowledgementPacket { packet, acknowledgement: ack.to_vec().into(), - relayer: relayer.clone(), + relayer: relayer.clone().into(), }), vec![], )?); @@ -919,7 +924,7 @@ fn channel_open_init( connection_id, channel_id, version, - relayer, + relayer: relayer.into(), }), vec![], )?)) @@ -993,7 +998,7 @@ fn channel_open_try( channel_id, version: channel.version, counterparty_version, - relayer, + relayer: relayer.into(), }), vec![], )?)) @@ -1061,7 +1066,7 @@ fn channel_open_ack( channel_id, counterparty_channel_id, counterparty_version, - relayer, + relayer: relayer.into(), }), vec![], )?)) @@ -1123,7 +1128,7 @@ fn channel_open_confirm( port_id, &ModuleMsg::UnionIbcMsg(UnionIbcMsg::OnChannelOpenConfirm { channel_id, - relayer, + relayer: relayer.into(), }), vec![], )?)) @@ -1158,7 +1163,7 @@ fn channel_close_init(mut deps: DepsMut, channel_id: u32, relayer: Addr) -> Cont port_id, &ModuleMsg::UnionIbcMsg(UnionIbcMsg::OnChannelCloseInit { channel_id, - relayer, + relayer: relayer.into(), }), vec![], )?)) @@ -1224,7 +1229,7 @@ fn channel_close_confirm( port_id, &ModuleMsg::UnionIbcMsg(UnionIbcMsg::OnChannelOpenConfirm { channel_id, - relayer, + relayer: relayer.into(), }), vec![], )?)) @@ -1309,7 +1314,7 @@ fn process_receive( port_id.clone(), &ModuleMsg::UnionIbcMsg(UnionIbcMsg::OnIntentRecvPacket { packet, - market_maker: deps.api.addr_validate(&relayer)?, + market_maker: deps.api.addr_validate(&relayer)?.into(), market_maker_msg: relayer_msg.to_vec().into(), }), vec![], @@ -1328,7 +1333,7 @@ fn process_receive( port_id.clone(), &ModuleMsg::UnionIbcMsg(UnionIbcMsg::OnRecvPacket { packet, - relayer: deps.api.addr_validate(&relayer)?, + relayer: deps.api.addr_validate(&relayer)?.into(), relayer_msg: relayer_msg.to_vec().into(), }), vec![], @@ -1607,6 +1612,7 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result { + let contract = deps.api.addr_validate(&contract)?; let channels = CONTRACT_CHANNELS.load(deps.storage, contract)?; Ok(to_json_binary(&channels)?) } diff --git a/cosmwasm/union-ibc/src/lib.rs b/cosmwasm/union-ibc/src/lib.rs index 77f575ae0c..8f23a0367c 100644 --- a/cosmwasm/union-ibc/src/lib.rs +++ b/cosmwasm/union-ibc/src/lib.rs @@ -1,8 +1,4 @@ pub mod contract; -pub mod lightclient; -pub mod module; -pub mod msg; -pub mod query; pub mod state; use cosmwasm_std::StdError; diff --git a/cosmwasm/union-ibc/src/lightclient/mod.rs b/cosmwasm/union-ibc/src/lightclient/mod.rs deleted file mode 100644 index 67350db2a2..0000000000 --- a/cosmwasm/union-ibc/src/lightclient/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod query; diff --git a/cosmwasm/union-ibc/src/lightclient/query.rs b/cosmwasm/union-ibc/src/lightclient/query.rs deleted file mode 100644 index cebb3eda2f..0000000000 --- a/cosmwasm/union-ibc/src/lightclient/query.rs +++ /dev/null @@ -1,52 +0,0 @@ -use cosmwasm_schema::{cw_serde, QueryResponses}; -use cosmwasm_std::Binary; - -#[cw_serde] -pub enum Status { - Active, - Expired, - Frozen, -} - -#[cw_serde] -pub struct VerifyClientMessageUpdate { - pub height: u64, - pub consensus_state: Binary, - pub client_state: Binary, -} - -#[cw_serde] -#[derive(QueryResponses)] -pub enum QueryMsg { - #[returns(u64)] - GetTimestamp { client_id: u32, height: u64 }, - #[returns(u64)] - GetLatestHeight { client_id: u32 }, - #[returns(Status)] - GetStatus { client_id: u32 }, - #[returns(u64)] - VerifyCreation { - client_id: u32, - client_state: Binary, - consensus_state: Binary, - }, - #[returns(())] - VerifyMembership { - client_id: u32, - height: u64, - proof: Binary, - path: Binary, - value: Binary, - }, - #[returns(())] - VerifyNonMembership { - client_id: u32, - height: u64, - proof: Binary, - path: Binary, - }, - #[returns(VerifyClientMessageUpdate)] - VerifyClientMessage { client_id: u32, message: Binary }, - #[returns(())] - Misbehaviour { client_id: u32, message: Binary }, -} diff --git a/cosmwasm/union-ibc/src/module/mod.rs b/cosmwasm/union-ibc/src/module/mod.rs deleted file mode 100644 index d0e87a0d30..0000000000 --- a/cosmwasm/union-ibc/src/module/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod msg; diff --git a/flake.nix b/flake.nix index a4f81c1828..9f7c100b87 100644 --- a/flake.nix +++ b/flake.nix @@ -218,7 +218,7 @@ ./site/site.nix ./lib/near/near.nix ./typescript-sdk/typescript-sdk.nix - ./light-clients/ethereum-light-client/ethereum-light-client.nix + # ./light-clients/ethereum-light-client/ethereum-light-client.nix ./light-clients/cometbls-light-client/cometbls-light-client.nix ./light-clients/tendermint-light-client/tendermint-light-client.nix # ./light-clients/scroll-light-client/scroll-light-client.nix diff --git a/networks/devnet.nix b/networks/devnet.nix index 28f8a3e323..d78794770d 100644 --- a/networks/devnet.nix +++ b/networks/devnet.nix @@ -76,7 +76,7 @@ }; }; lightClients = [ - self'.packages.ethereum-light-client + # self'.packages.ethereum-light-client # self'.packages.scroll-light-client # self'.packages.arbitrum-light-client # self'.packages.berachain-light-client