From bdeac89e1a34c3b95b5e479b5c3a2278e2754655 Mon Sep 17 00:00:00 2001 From: adairrr <32375605+adairrr@users.noreply.github.com> Date: Tue, 30 Jul 2024 23:58:25 +0200 Subject: [PATCH 01/12] Playing with callbacks --- contracts/client/src/dependencies.rs | 8 +- contracts/server/src/contract.rs | 4 +- contracts/server/src/handlers/execute.rs | 13 +- contracts/server/src/handlers/ibc_callback.rs | 119 ++++++++++++++++++ contracts/server/src/handlers/mod.rs | 3 +- contracts/server/src/handlers/module_ibc.rs | 15 ++- packages/ibcmail/src/lib.rs | 1 + packages/ibcmail/src/server/error.rs | 4 + packages/ibcmail/src/server/mod.rs | 1 + packages/ibcmail/src/server/msg.rs | 11 +- packages/ibcmail/src/server/state.rs | 5 + tests/src/client.rs | 62 ++++++++- 12 files changed, 234 insertions(+), 12 deletions(-) create mode 100644 contracts/server/src/handlers/ibc_callback.rs create mode 100644 packages/ibcmail/src/server/state.rs diff --git a/contracts/client/src/dependencies.rs b/contracts/client/src/dependencies.rs index 9546150..36fb76d 100644 --- a/contracts/client/src/dependencies.rs +++ b/contracts/client/src/dependencies.rs @@ -21,6 +21,12 @@ impl abstract_app::abstract_interface::Depen None, ); - Ok(vec![adapter_install_config]) + // The IBC client is depended upon by the server + let ibc_client = ModuleInstallConfig::new( + ModuleInfo::from_id_latest("abstract:ibc-client")?, + None, + ); + + Ok(vec![adapter_install_config, ibc_client]) } } diff --git a/contracts/server/src/contract.rs b/contracts/server/src/contract.rs index 75b44af..26dbb34 100644 --- a/contracts/server/src/contract.rs +++ b/contracts/server/src/contract.rs @@ -8,6 +8,7 @@ use crate::{handlers, APP_VERSION}; use abstract_adapter::objects::dependency::StaticDependency; pub const MAIL_CLIENT: StaticDependency = StaticDependency::new(IBCMAIL_CLIENT_ID, &[]); +pub const IBC_CLIENT: StaticDependency = StaticDependency::new("abstract:ibc-client", &[]); /// The type of the result returned by your client's entry points. pub type ServerResult = Result; @@ -15,7 +16,8 @@ pub type ServerResult = Result; const ADAPTER: Adapter = Adapter::new(IBCMAIL_SERVER_ID, APP_VERSION, None) .with_execute(handlers::execute_handler) .with_module_ibc(handlers::module_ibc_handler) - .with_dependencies(&[MAIL_CLIENT]); + .with_ibc_callback(handlers::ibc_callback_handler) + .with_dependencies(&[MAIL_CLIENT, IBC_CLIENT]); // Export handlers #[cfg(feature = "export")] diff --git a/contracts/server/src/handlers/execute.rs b/contracts/server/src/handlers/execute.rs index 8c0e94f..98e15ee 100644 --- a/contracts/server/src/handlers/execute.rs +++ b/contracts/server/src/handlers/execute.rs @@ -9,10 +9,9 @@ use abstract_adapter::std::{ version_control::NamespaceResponse, IBC_CLIENT, }; +use abstract_adapter::std::ibc::Callback; use abstract_adapter::traits::AbstractResponse; -use cosmwasm_std::{ - to_json_binary, wasm_execute, Addr, CosmosMsg, Deps, DepsMut, Env, MessageInfo, -}; +use cosmwasm_std::{to_json_binary, wasm_execute, Addr, CosmosMsg, Deps, DepsMut, Env, MessageInfo, Empty}; use ibcmail::client::api::MailClient; use ibcmail::{ client::api::ClientInterface, @@ -22,7 +21,8 @@ use ibcmail::{ }, Header, IbcMailMessage, Recipient, Route, }; - +use ibcmail::server::msg::ServerCallbackMessage; +use ibcmail::server::state::AWAITING; use crate::{ contract::{Adapter, ServerResult}, error::ServerError, @@ -142,13 +142,16 @@ pub(crate) fn route_msg( hop: header.current_hop, })?; + // Awaiting callback + AWAITING.save(deps.storage, &msg.id, dest_chain)?; + // ANCHOR: ibc_client // Call IBC client let ibc_client_msg = ibc_client::ExecuteMsg::ModuleIbcAction { host_chain: dest_chain.clone(), target_module: current_module_info, msg: to_json_binary(&ServerIbcMessage::RouteMessage { msg, header })?, - callback: None, + callback: Some(Callback::new(&Empty {})?) }; let ibc_client_addr: Addr = app diff --git a/contracts/server/src/handlers/ibc_callback.rs b/contracts/server/src/handlers/ibc_callback.rs new file mode 100644 index 0000000..ee0f9ef --- /dev/null +++ b/contracts/server/src/handlers/ibc_callback.rs @@ -0,0 +1,119 @@ +use abstract_adapter::objects::module::ModuleInfo; +use abstract_adapter::sdk::{AbstractResponse, ModuleRegistryInterface}; +use abstract_adapter::std::ibc::{Callback, IbcResult, ModuleIbcInfo}; +use abstract_adapter::std::ibc_client; +use abstract_adapter::traits::ModuleIdentification; +use cosmwasm_std::{from_json, Binary, DepsMut, Env, Response, wasm_execute, Addr, to_json_binary, CosmosMsg}; + +use ibcmail::{server::{error::ServerError, msg::ServerIbcMessage, ServerAdapter}, IBCMAIL_SERVER_ID, MessageStatus, MessageHash}; +use ibcmail::server::state::AWAITING; +use crate::{contract::ServerResult, handlers::execute::route_msg}; +use crate::contract::IBC_CLIENT; + +// ANCHOR: ibc_callback_handler +pub fn ibc_callback_handler( + deps: DepsMut, + _env: Env, + mut app: ServerAdapter, + callback: Callback, + ibc_result: IbcResult +) -> ServerResult { + // panic!("ibc_callback_handler: {:?}", callback); + println!("ibc_callback_handler callback: {:?} result, env: {:?}", callback, _env); + + // let events = ibc_result.get_execute_events(); + // panic!("ibc_callback_handler events: {:?}", events); + // let chain = events.into_iter().find(|e| { + // e.ty == "abstract-wasm" + // && e.attributes + // .iter() + // .any(|a| a.key == "contract" && a.value == "abstract:ibc-host") + // }); + + + let msgs = match ibc_result { + IbcResult::Execute { result: Ok(e), initiator_msg } => { + let origin_msg: ServerIbcMessage = from_json(initiator_msg)?; + + match origin_msg { + ServerIbcMessage::RouteMessage { msg, header } => { + println!("ibc_callback_handler success route_msg id: {:?}, header: {:?}", msg.id, header); + if header.current_hop > 0 { + vec![send_update(deps, &mut app, msg.id, MessageStatus::Received)?] + } else { + // Sent + AWAITING.remove(deps.storage, &msg.id); + vec![] + } + }, + ServerIbcMessage::UpdateMessage { id, status } => { + println!("ibc_callback_handler success update_msg: {:?}", id); + vec![] + } + _ => { + println!("Unknown message"); + vec![] + }, + } + }, + IbcResult::Execute { result: Err(e), initiator_msg } => { + let origin_msg: ServerIbcMessage = from_json(initiator_msg)?; + match origin_msg { + ServerIbcMessage::RouteMessage { msg, header } => { + println!("ibc_callback_handler success route_msg id: {:?}, header: {:?}", msg.id, header); + vec![send_update(deps, &mut app, msg.id, MessageStatus::Failed)?] + }, + ServerIbcMessage::UpdateMessage { id, status } => { + println!("ibc_callback_handler error update_msg: {:?}", id); + vec![] + } + _ => { + println!("unknown message") + vec![] + }, + }; + println!("ibc_callback_handler error: {:?}", e); + + }, + IbcResult::FatalError(e) => { + println!("ibc_callback_handler fatal error: {:?}", e); + vec![] + }, + _ => { + println!("unexpected callback result"); + vec![] + } + }; + Ok(Response::default()) +} +// ANCHOR_END: ibc_callback_handler + +/// We only want to send a message if we're in the middle +pub(crate) fn send_update( + deps: DepsMut, + module: &mut ServerAdapter, + id: MessageHash, + status: MessageStatus, +) -> ServerResult { + println!("updating message: {:?}, status: {:?}", id, status); + let from_chain = AWAITING.load(deps.storage, &id).map_err(|_| ServerError::AwaitedMsgNotFound(id))?; + + let current_module_info = ModuleInfo::from_id(module.module_id(), module.version().into())?; + + // Call IBC client + let ibc_client_msg = ibc_client::ExecuteMsg::ModuleIbcAction { + host_chain: from_chain.clone(), + target_module: current_module_info, + msg: to_json_binary(&ServerIbcMessage::UpdateMessage { id, status })?, + callback: None + }; + + let ibc_client_addr: Addr = module + .module_registry(deps.as_ref())? + .query_module(ModuleInfo::from_id_latest(IBC_CLIENT.id)?)? + .reference + .unwrap_native()?; + + let msg: CosmosMsg = wasm_execute(ibc_client_addr, &ibc_client_msg, vec![])?.into(); + Ok::(msg) +} diff --git a/contracts/server/src/handlers/mod.rs b/contracts/server/src/handlers/mod.rs index efe2c62..a59c30d 100644 --- a/contracts/server/src/handlers/mod.rs +++ b/contracts/server/src/handlers/mod.rs @@ -1,4 +1,5 @@ pub mod execute; pub mod module_ibc; +pub mod ibc_callback; -pub use crate::handlers::{execute::execute_handler, module_ibc::module_ibc_handler}; +pub use crate::handlers::{execute::execute_handler, module_ibc::module_ibc_handler, ibc_callback::ibc_callback_handler}; diff --git a/contracts/server/src/handlers/module_ibc.rs b/contracts/server/src/handlers/module_ibc.rs index 7d9ea07..7bb7b83 100644 --- a/contracts/server/src/handlers/module_ibc.rs +++ b/contracts/server/src/handlers/module_ibc.rs @@ -1,12 +1,12 @@ use abstract_adapter::sdk::AbstractResponse; use abstract_adapter::std::ibc::ModuleIbcInfo; -use cosmwasm_std::{from_json, Binary, DepsMut, Env}; +use cosmwasm_std::{from_json, Binary, DepsMut, Env, StdResult}; use ibcmail::{ server::{error::ServerError, msg::ServerIbcMessage, ServerAdapter}, IBCMAIL_SERVER_ID, }; - +use ibcmail::server::state::AWAITING; use crate::{contract::ServerResult, handlers::execute::route_msg}; // ANCHOR: module_ibc_handler @@ -32,6 +32,17 @@ pub fn module_ibc_handler( Ok(app.response("module_ibc").add_message(msg)) } + ServerIbcMessage::UpdateMessage { id, status } => { + + println!("module_ibc_handler update_msg: {:?}, status: {:?}", id, status); + // TODO: custom error + let from_chain = AWAITING.load(deps.storage, &id)?; + AWAITING.remove(deps.storage, &id); + + let msg = route_update_msg(deps, msg, header, &mut app)?; + + Ok(app.response("module_ibc").add_message(msg)) + _ => Err(ServerError::UnauthorizedIbcMessage {}), } } diff --git a/packages/ibcmail/src/lib.rs b/packages/ibcmail/src/lib.rs index 261d7d2..4070245 100644 --- a/packages/ibcmail/src/lib.rs +++ b/packages/ibcmail/src/lib.rs @@ -109,4 +109,5 @@ impl Sender { pub enum MessageStatus { Sent, Received, + Failed, } diff --git a/packages/ibcmail/src/server/error.rs b/packages/ibcmail/src/server/error.rs index f188b92..e2e18c0 100644 --- a/packages/ibcmail/src/server/error.rs +++ b/packages/ibcmail/src/server/error.rs @@ -7,6 +7,7 @@ use cosmwasm_std::StdError; use cw_asset::AssetError; use cw_controllers::AdminError; use thiserror::Error; +use crate::MessageHash; #[derive(Error, Debug, PartialEq)] pub enum ServerError { @@ -42,4 +43,7 @@ pub enum ServerError { #[error("Unclaimed namespace: {0}")] UnclaimedNamespace(Namespace), + + #[error("Awaited message not found: {0}")] + AwaitedMsgNotFound(MessageHash), } diff --git a/packages/ibcmail/src/server/mod.rs b/packages/ibcmail/src/server/mod.rs index 63ea5f0..294af68 100644 --- a/packages/ibcmail/src/server/mod.rs +++ b/packages/ibcmail/src/server/mod.rs @@ -8,6 +8,7 @@ use crate::server::{ pub mod api; pub mod error; pub mod msg; +pub mod state; /// The type of the client that is used to build your client and access the Abstract SDK features. pub type ServerAdapter = diff --git a/packages/ibcmail/src/server/msg.rs b/packages/ibcmail/src/server/msg.rs index ff63277..0c89a81 100644 --- a/packages/ibcmail/src/server/msg.rs +++ b/packages/ibcmail/src/server/msg.rs @@ -1,6 +1,6 @@ use cosmwasm_schema::QueryResponses; -use crate::{server::ServerAdapter, Header, IbcMailMessage, Route}; +use crate::{server::ServerAdapter, Header, IbcMailMessage, Route, MessageHash, MessageStatus}; // This is used for type safety and re-exporting the contract endpoint structs. abstract_adapter::adapter_msg_types!(ServerAdapter, ServerExecuteMsg, ServerQueryMsg); @@ -25,6 +25,15 @@ pub enum ServerExecuteMsg { pub enum ServerIbcMessage { /// Route a message RouteMessage { msg: IbcMailMessage, header: Header }, + UpdateMessage { id: MessageHash, status: MessageStatus }, +} + +/// App execute messages +#[non_exhaustive] +#[cosmwasm_schema::cw_serde] +pub enum ServerCallbackMessage { + /// Update a message + UpdateMessage { id: MessageHash, header: Header }, } /// App query messages diff --git a/packages/ibcmail/src/server/state.rs b/packages/ibcmail/src/server/state.rs new file mode 100644 index 0000000..9687505 --- /dev/null +++ b/packages/ibcmail/src/server/state.rs @@ -0,0 +1,5 @@ +use abstract_app::objects::TruncatedChainId; +use cw_storage_plus::Map; +use crate::MessageHash; + +pub const AWAITING: Map<&MessageHash, TruncatedChainId> = Map::new("awaiting"); \ No newline at end of file diff --git a/tests/src/client.rs b/tests/src/client.rs index a8a501f..fffa8c6 100644 --- a/tests/src/client.rs +++ b/tests/src/client.rs @@ -153,9 +153,11 @@ mod send_msg { use abstract_app::{objects::account::AccountTrace, std::version_control::ExecuteMsgFns}; use abstract_app::objects::TruncatedChainId; + use abstract_cw_orch_polytone::{Polytone, PolytoneConnection}; + use abstract_interface::Abstract; use cw_orch_interchain::{InterchainEnv, MockBech32InterchainEnv}; - use ibcmail::{IBCMAIL_CLIENT_ID, Message, MessageStatus, server::error::ServerError}; + use ibcmail::{IBCMAIL_CLIENT_ID, Message, MessageStatus, Route, server::error::ServerError}; use super::*; @@ -312,6 +314,64 @@ mod send_msg { Ok(()) } + #[test] + fn send_remote_message_account_dne_callback() -> anyhow::Result<()> { + // Create a sender and mock env + let interchain = MockBech32InterchainEnv::new(vec![ + ("juno-1", "juno"), + ( + "archway-1", + "archway", + ), + ( + "neutron-1", + "neutron", + ), + ]); + + // /Users/adair/.cargo/registry/src/index.crates.io-6f17d22bba15001f/cw-orch-mock-0.22.0/src/queriers/env.rs:12:70: + // index out of bounds: the len is 1 but the index is 1 (when initializing with "juno") + let arch_env = TestEnv::setup(interchain.get_chain("archway-1")?)?; + let juno_env = TestEnv::setup(interchain.get_chain("juno-1")?)?; + let neutron_env = TestEnv::setup(interchain.get_chain("neutron-1")?)?; + + arch_env.abs.connect_to(&juno_env.abs, &interchain)?; + juno_env.abs.connect_to(&neutron_env.abs, &interchain)?; + + let arch_client = arch_env.client1; + let juno_client = juno_env.client1; + + // the trait `From<&str>` is not implemented for `abstract_app::objects::chain_name::TruncatedChainId` + let arch_to_juno_msg = Message::new( + Recipient::account( + AccountId::local(420), + Some(TruncatedChainId::from_string("neutron".into())?), + ), + "test-subject", + "test-body", + ); + + let res = arch_client.send_message(arch_to_juno_msg, Some(Route::Remote(vec![TruncatedChainId::from_string("juno".into())?, TruncatedChainId::from_string("neutron".into())?]))); + + assert_that!(res).is_ok(); + + let server = ServerInterface::new(IBCMAIL_SERVER_ID, arch_env.env.clone()); + println!("server: {:?}", server.address()?); + let abstr = Abstract::new(arch_env.env.clone()); + println!("ibc_host: {:?}", abstr.ibc.host.address()?); + let poly = PolytoneConnection::load_from( + arch_env.env.clone(), + juno_env.env.clone(), + ); + println!("poly_note: {:?}", poly.note.address()?); + + let packets = interchain.await_packets("archway-1", res?)?; + + // println!("packets: {:?}", packets); + + Ok(()) + } + #[test] fn can_send_remote_message_2_hop() -> anyhow::Result<()> { // Create a sender and mock env From 0d52d1e99cc6e8966c16f0f19d514dcfabc83c03 Mon Sep 17 00:00:00 2001 From: adairrr <32375605+adairrr@users.noreply.github.com> Date: Sat, 3 Aug 2024 01:06:23 +0200 Subject: [PATCH 02/12] Initial callback + routing --- contracts/client/src/handlers/execute.rs | 61 ++++--- contracts/server/src/handlers/execute.rs | 163 +++++++++++------- contracts/server/src/handlers/ibc_callback.rs | 92 +++------- contracts/server/src/handlers/module_ibc.rs | 17 +- packages/ibcmail/src/client/api.rs | 13 +- packages/ibcmail/src/client/error.rs | 4 + packages/ibcmail/src/client/msg.rs | 7 +- packages/ibcmail/src/client/state.rs | 3 +- packages/ibcmail/src/lib.rs | 37 ++++ packages/ibcmail/src/server/msg.rs | 7 +- tests/src/client.rs | 6 +- 11 files changed, 241 insertions(+), 169 deletions(-) diff --git a/contracts/client/src/handlers/execute.rs b/contracts/client/src/handlers/execute.rs index fae994e..ce61525 100644 --- a/contracts/client/src/handlers/execute.rs +++ b/contracts/client/src/handlers/execute.rs @@ -4,16 +4,12 @@ use abstract_app::{ traits::{AbstractResponse, AccountIdentification}, }; use base64::prelude::*; -use cosmwasm_std::{ensure_eq, CosmosMsg, Deps, DepsMut, Env, MessageInfo}; -use ibcmail::{ - client::{ - state::{RECEIVED, SENT}, - ClientApp, - }, - server::api::{MailServer, ServerInterface}, - IbcMailMessage, Message, Recipient, Route, Sender, IBCMAIL_SERVER_ID, -}; - +use cosmwasm_std::{ensure_eq, CosmosMsg, Deps, DepsMut, Env, MessageInfo, Addr}; +use ibcmail::{client::{ + state::{RECEIVED, SENT}, + ClientApp, +}, server::api::{MailServer, ServerInterface}, IbcMailMessage, Message, Recipient, Route, Sender, IBCMAIL_SERVER_ID, MessageHash, MessageStatus}; +use ibcmail::client::state::STATUS; use crate::{ contract::{App, ClientResult}, error::ClientError, @@ -32,7 +28,8 @@ pub fn execute_handler( ClientExecuteMsg::SendMessage { message, route } => { send_msg(deps, env, info, message, route, app) } - ClientExecuteMsg::ReceiveMessage(message) => receive_msg(deps, info, message, app), + ClientExecuteMsg::ReceiveMessage(message) => receive_msg(deps, info, app, message), + ClientExecuteMsg::UpdateMessageStatus { id, status } => update_msg_status(deps, info, app, id, status), } } // # ANCHOR_END: execute_handler @@ -76,16 +73,8 @@ fn send_msg( /// Receive a message from the server // # ANCHOR: receive_msg -fn receive_msg(deps: DepsMut, info: MessageInfo, msg: IbcMailMessage, app: App) -> ClientResult { - let sender_module = app - .module_registry(deps.as_ref())? - .module_info(info.sender) - .map_err(|_| ClientError::NotMailServer {})?; - ensure_eq!( - sender_module.info.id(), - IBCMAIL_SERVER_ID, - ClientError::NotMailServer {} - ); +fn receive_msg(deps: DepsMut, info: MessageInfo, app: App, msg: IbcMailMessage) -> ClientResult { + ensure_server_sender(deps.as_ref(), &app, info.sender)?; ensure_correct_recipient(deps.as_ref(), &msg.message.recipient, &app)?; @@ -97,6 +86,36 @@ fn receive_msg(deps: DepsMut, info: MessageInfo, msg: IbcMailMessage, app: App) } // # ANCHOR_END: receive_msg +fn update_msg_status( + deps: DepsMut, + info: MessageInfo, + app: App, + id: MessageHash, + status: MessageStatus, +) -> ClientResult { + ensure_server_sender(deps.as_ref(), &app, info.sender)?; + + // ensure that the message exists + SENT.load(deps.storage, id.clone()).map_err(|_| ClientError::MessageNotFound(id.clone()))?; + STATUS.save(deps.storage, id.clone(), &status)?; + + Ok(app.response("update_msg_status").add_attribute("message_id", &id).add_attribute("status", status.to_string())) +} + +fn ensure_server_sender(deps: Deps, app: &ClientApp, sender: Addr) -> Result<(), ClientError> { + let sender_module = app + .module_registry(deps)? + .module_info(sender) + .map_err(|_| ClientError::NotMailServer {})?; + + ensure_eq!( + sender_module.info.id(), + IBCMAIL_SERVER_ID, + ClientError::NotMailServer {} + ); + Ok(()) +} + fn ensure_correct_recipient( deps: Deps, recipient: &Recipient, diff --git a/contracts/server/src/handlers/execute.rs b/contracts/server/src/handlers/execute.rs index 98e15ee..1067370 100644 --- a/contracts/server/src/handlers/execute.rs +++ b/contracts/server/src/handlers/execute.rs @@ -1,32 +1,26 @@ use abstract_adapter::objects::TruncatedChainId; use abstract_adapter::sdk::{ - features::ModuleIdentification, AccountVerification, ModuleRegistryInterface, + AccountVerification, features::ModuleIdentification, ModuleRegistryInterface, }; -use abstract_adapter::std::version_control::AccountBase; use abstract_adapter::std::{ ibc_client, - objects::{account::AccountTrace, module::ModuleInfo}, - version_control::NamespaceResponse, IBC_CLIENT, + objects::{account::AccountTrace, module::ModuleInfo} + , }; use abstract_adapter::std::ibc::Callback; +use abstract_adapter::std::version_control::AccountBase; use abstract_adapter::traits::AbstractResponse; -use cosmwasm_std::{to_json_binary, wasm_execute, Addr, CosmosMsg, Deps, DepsMut, Env, MessageInfo, Empty}; +use cosmwasm_std::{Addr, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, to_json_binary, wasm_execute}; + +use ibcmail::{client::api::ClientInterface, Header, IbcMailMessage, MessageHash, MessageStatus, Recipient, Route, server::{ + msg::{ServerExecuteMsg, ServerIbcMessage}, + ServerAdapter, +}}; use ibcmail::client::api::MailClient; -use ibcmail::{ - client::api::ClientInterface, - server::{ - msg::{ServerExecuteMsg, ServerIbcMessage}, - ServerAdapter, - }, - Header, IbcMailMessage, Recipient, Route, -}; -use ibcmail::server::msg::ServerCallbackMessage; use ibcmail::server::state::AWAITING; -use crate::{ - contract::{Adapter, ServerResult}, - error::ServerError, -}; + +use crate::{contract::{Adapter, ServerResult}, error::ServerError}; // ANCHOR: execute_handler pub fn execute_handler( @@ -106,6 +100,7 @@ fn process_message( let metadata = Header { current_hop: 0, route, + recipient: msg.message.recipient.clone() }; let msg = route_msg(deps, msg, metadata, &mut app)?; @@ -122,17 +117,16 @@ pub(crate) fn route_msg( println!("routing message: {:?}, metadata: {:?}", msg, header); match header.route { - AccountTrace::Local => route_to_local_account(deps.as_ref(), msg, header, app), + AccountTrace::Local => route_to_local_account(deps.as_ref(), app, msg, header), AccountTrace::Remote(ref chains) => { println!("routing to chains: {:?}", chains); // check index of hop. If we are on the final hop, route to local account if header.current_hop == (chains.len() - 1) as u32 { println!("routing to local account: {:?}", chains); - return route_to_local_account(deps.as_ref(), msg.clone(), header, app); + return route_to_local_account(deps.as_ref(), app, msg.clone(), header); } // TODO verify that the chain is a valid chain - let current_module_info = ModuleInfo::from_id(app.module_id(), app.version().into())?; let dest_chain = chains @@ -145,67 +139,112 @@ pub(crate) fn route_msg( // Awaiting callback AWAITING.save(deps.storage, &msg.id, dest_chain)?; - // ANCHOR: ibc_client - // Call IBC client - let ibc_client_msg = ibc_client::ExecuteMsg::ModuleIbcAction { - host_chain: dest_chain.clone(), - target_module: current_module_info, - msg: to_json_binary(&ServerIbcMessage::RouteMessage { msg, header })?, - callback: Some(Callback::new(&Empty {})?) - }; - - let ibc_client_addr: Addr = app - .module_registry(deps.as_ref())? - .query_module(ModuleInfo::from_id_latest(IBC_CLIENT)?)? - .reference - .unwrap_native()?; - - let msg: CosmosMsg = wasm_execute(ibc_client_addr, &ibc_client_msg, vec![])?.into(); - // ANCHOR_END: ibc_client + let msg = remote_server_msg(deps, &app, &ServerIbcMessage::RouteMessage { msg, header: header.clone() }, dest_chain)?; Ok::(msg) } } } +/// Route a mail message to an account on the local chain fn route_to_local_account( deps: Deps, + app: &mut ServerAdapter, msg: IbcMailMessage, header: Header, - app: &mut ServerAdapter, ) -> ServerResult { println!("routing to local account: {:?}", msg.message.recipient); // This is a local message + let mail_client = get_recipient_mail_client(deps, app, &msg.message.recipient)?; + let receive_msg: CosmosMsg = mail_client.receive_msg(msg, header)?; - let recipient = msg.message.recipient.clone(); - - let account_id = match recipient { - Recipient::Account { id: account_id, .. } => Ok(account_id), - Recipient::Namespace { namespace, .. } => { - // TODO: this only allows for addressing recipients via namespace of their email account directly. - // If they have the email application installed on a sub-account, this will not be able to identify the sub-account. - let namespace_status = app - .module_registry(deps)? - .query_namespace(namespace.clone())?; - match namespace_status { - NamespaceResponse::Claimed(info) => Ok(info.account_id), - NamespaceResponse::Unclaimed {} => { - return Err(ServerError::UnclaimedNamespace(namespace)); - } + Ok(receive_msg) +} + +/// Route a mail message to an account on the local chain +fn update_local_message_status( + deps: Deps, + module: &mut ServerAdapter, + recipient: &Recipient, + id: MessageHash, + status: MessageStatus, +) -> ServerResult { + println!("updating local message status to local account: {:?}", recipient); + // This is a local message + let mail_client = get_recipient_mail_client(deps, module, recipient)?; + return Ok(mail_client.update_msg_status(id, status)?); +} + + +/// Send a status update for a given message. +pub(crate) fn update_message_status( + deps: DepsMut, + module: &mut ServerAdapter, + id: MessageHash, + header: Header, + status: MessageStatus, +) -> ServerResult { + println!("updating message: {:?}, header: {:?}, status: {:?}", id, header, status); + // let from_chain = AWAITING.load(deps.storage, &id).map_err(|_| ServerError::AwaitedMsgNotFound(id))?; + + match header.route { + AccountTrace::Local => update_local_message_status(deps.as_ref(), module, &header.recipient, id, status), + AccountTrace::Remote(ref chains) => { + // we need to take the route and do it in reverse + println!("updating to chains: {:?}", chains); + + // check index of hop. If we are on the final hop, route to local account + if header.current_hop == 0 { + println!("updating to local account: {:?}", chains); + return update_local_message_status(deps.as_ref(), module, &header.recipient, id, status); } + + let dest_chain = + chains + .get(header.current_hop as usize - 1) + .ok_or(ServerError::InvalidRoute { + route: header.route.clone(), + hop: header.current_hop, + })?; + + let msg = remote_server_msg(deps, &module, &ServerIbcMessage::UpdateMessage { id, header: header.clone(), status }, dest_chain)?; + Ok(msg) } - _ => Err(ServerError::NotImplemented( - "Non-account recipients not supported".to_string(), - )), - }?; + } +} + +/// Set the target account for the message and get the mail client for the recipient +fn get_recipient_mail_client<'a>(deps: Deps<'a>, app: &'a mut ServerAdapter, recipient: &Recipient) -> ServerResult> { + let account_id = recipient.resolve_account_id(app.module_registry(deps)?)?; // ANCHOR: set_acc_and_send // Set target account for actions, is used by APIs to retrieve mail client address. let recipient_acc: AccountBase = app.account_registry(deps)?.account_base(&account_id)?; app.target_account = Some(recipient_acc); - - let mail_client: MailClient<_> = app.mail_client(deps); - let msg: CosmosMsg = mail_client.receive_msg(msg, header)?; + Ok(app.mail_client::<'a>(deps)) // ANCHOR_END: set_acc_and_send +} + +/// Build a message to send to a server on the destination chain +fn remote_server_msg(deps: DepsMut, module: &ServerAdapter, msg: &ServerIbcMessage, dest_chain: &TruncatedChainId) -> ServerResult { + // ANCHOR: ibc_client + // Call IBC client + let current_module_info = ModuleInfo::from_id(module.module_id(), module.version().into())?; + + let ibc_client_msg = ibc_client::ExecuteMsg::ModuleIbcAction { + host_chain: dest_chain.clone(), + target_module: current_module_info, + msg: to_json_binary(msg)?, + callback: Some(Callback::new(&Empty {})?) + }; + + let ibc_client_addr: Addr = module + .module_registry(deps.as_ref())? + .query_module(ModuleInfo::from_id_latest(IBC_CLIENT)?)? + .reference + .unwrap_native()?; + + let msg: CosmosMsg = wasm_execute(ibc_client_addr, &ibc_client_msg, vec![])?.into(); + // ANCHOR_END: ibc_client Ok(msg) -} +} \ No newline at end of file diff --git a/contracts/server/src/handlers/ibc_callback.rs b/contracts/server/src/handlers/ibc_callback.rs index ee0f9ef..6400599 100644 --- a/contracts/server/src/handlers/ibc_callback.rs +++ b/contracts/server/src/handlers/ibc_callback.rs @@ -1,16 +1,14 @@ -use abstract_adapter::objects::module::ModuleInfo; -use abstract_adapter::sdk::{AbstractResponse, ModuleRegistryInterface}; -use abstract_adapter::std::ibc::{Callback, IbcResult, ModuleIbcInfo}; -use abstract_adapter::std::ibc_client; -use abstract_adapter::traits::ModuleIdentification; -use cosmwasm_std::{from_json, Binary, DepsMut, Env, Response, wasm_execute, Addr, to_json_binary, CosmosMsg}; +use abstract_adapter::std::ibc::{Callback, IbcResult}; +use cosmwasm_std::{DepsMut, Env, from_json, Response}; -use ibcmail::{server::{error::ServerError, msg::ServerIbcMessage, ServerAdapter}, IBCMAIL_SERVER_ID, MessageStatus, MessageHash}; +use ibcmail::{MessageStatus, server::{msg::ServerIbcMessage, ServerAdapter}}; use ibcmail::server::state::AWAITING; -use crate::{contract::ServerResult, handlers::execute::route_msg}; -use crate::contract::IBC_CLIENT; +use crate::contract::ServerResult; +use crate::handlers::execute; // ANCHOR: ibc_callback_handler +/// Handler for message callbacks. +/// We use this handler for sending message delivery updates to our clients. pub fn ibc_callback_handler( deps: DepsMut, _env: Env, @@ -21,32 +19,20 @@ pub fn ibc_callback_handler( // panic!("ibc_callback_handler: {:?}", callback); println!("ibc_callback_handler callback: {:?} result, env: {:?}", callback, _env); - // let events = ibc_result.get_execute_events(); - // panic!("ibc_callback_handler events: {:?}", events); - // let chain = events.into_iter().find(|e| { - // e.ty == "abstract-wasm" - // && e.attributes - // .iter() - // .any(|a| a.key == "contract" && a.value == "abstract:ibc-host") - // }); - - let msgs = match ibc_result { - IbcResult::Execute { result: Ok(e), initiator_msg } => { + // The destination server successfully processed the message + IbcResult::Execute { result: Ok(_response), initiator_msg } => { + println!("ibc_callback_handler execute success"); let origin_msg: ServerIbcMessage = from_json(initiator_msg)?; match origin_msg { + // We successfully routed a packet, and need to send an update to the sender ServerIbcMessage::RouteMessage { msg, header } => { println!("ibc_callback_handler success route_msg id: {:?}, header: {:?}", msg.id, header); - if header.current_hop > 0 { - vec![send_update(deps, &mut app, msg.id, MessageStatus::Received)?] - } else { - // Sent - AWAITING.remove(deps.storage, &msg.id); - vec![] - } + vec![execute::update_message_status(deps, &mut app, msg.id, header, MessageStatus::Received)?] }, - ServerIbcMessage::UpdateMessage { id, status } => { + // We successfully updated a message status, we shouldn't need to do anything now + ServerIbcMessage::UpdateMessage { id, status, header } => { println!("ibc_callback_handler success update_msg: {:?}", id); vec![] } @@ -55,24 +41,26 @@ pub fn ibc_callback_handler( vec![] }, } - }, + } + // The destination server failed to process the message IbcResult::Execute { result: Err(e), initiator_msg } => { + println!("ibc_callback_handler execute error: {:?}", e); let origin_msg: ServerIbcMessage = from_json(initiator_msg)?; match origin_msg { ServerIbcMessage::RouteMessage { msg, header } => { - println!("ibc_callback_handler success route_msg id: {:?}, header: {:?}", msg.id, header); - vec![send_update(deps, &mut app, msg.id, MessageStatus::Failed)?] + println!("ibc_callback_handler execute error route_msg id: {:?}, header: {:?}", msg.id, header); + vec![execute::update_message_status(deps, &mut app, msg.id, header, MessageStatus::Failed)?] }, - ServerIbcMessage::UpdateMessage { id, status } => { - println!("ibc_callback_handler error update_msg: {:?}", id); + // We failed to update a message... + ServerIbcMessage::UpdateMessage { id, header, status } => { + println!("ibc_callback_handler execute error update_msg: {:?}", id); vec![] } _ => { - println!("unknown message") + println!("unknown message"); vec![] }, - }; - println!("ibc_callback_handler error: {:?}", e); + } }, IbcResult::FatalError(e) => { @@ -84,36 +72,8 @@ pub fn ibc_callback_handler( vec![] } }; - Ok(Response::default()) + + Ok(Response::default().add_messages(msgs)) } // ANCHOR_END: ibc_callback_handler -/// We only want to send a message if we're in the middle -pub(crate) fn send_update( - deps: DepsMut, - module: &mut ServerAdapter, - id: MessageHash, - status: MessageStatus, -) -> ServerResult { - println!("updating message: {:?}, status: {:?}", id, status); - let from_chain = AWAITING.load(deps.storage, &id).map_err(|_| ServerError::AwaitedMsgNotFound(id))?; - - let current_module_info = ModuleInfo::from_id(module.module_id(), module.version().into())?; - - // Call IBC client - let ibc_client_msg = ibc_client::ExecuteMsg::ModuleIbcAction { - host_chain: from_chain.clone(), - target_module: current_module_info, - msg: to_json_binary(&ServerIbcMessage::UpdateMessage { id, status })?, - callback: None - }; - - let ibc_client_addr: Addr = module - .module_registry(deps.as_ref())? - .query_module(ModuleInfo::from_id_latest(IBC_CLIENT.id)?)? - .reference - .unwrap_native()?; - - let msg: CosmosMsg = wasm_execute(ibc_client_addr, &ibc_client_msg, vec![])?.into(); - Ok::(msg) -} diff --git a/contracts/server/src/handlers/module_ibc.rs b/contracts/server/src/handlers/module_ibc.rs index 7bb7b83..c7264a0 100644 --- a/contracts/server/src/handlers/module_ibc.rs +++ b/contracts/server/src/handlers/module_ibc.rs @@ -1,6 +1,6 @@ use abstract_adapter::sdk::AbstractResponse; use abstract_adapter::std::ibc::ModuleIbcInfo; -use cosmwasm_std::{from_json, Binary, DepsMut, Env, StdResult}; +use cosmwasm_std::{from_json, Binary, DepsMut, Env, StdResult, StdError}; use ibcmail::{ server::{error::ServerError, msg::ServerIbcMessage, ServerAdapter}, @@ -8,6 +8,7 @@ use ibcmail::{ }; use ibcmail::server::state::AWAITING; use crate::{contract::ServerResult, handlers::execute::route_msg}; +use crate::handlers::execute::update_message_status; // ANCHOR: module_ibc_handler pub fn module_ibc_handler( @@ -30,20 +31,18 @@ pub fn module_ibc_handler( let msg = route_msg(deps, msg, header, &mut app)?; - Ok(app.response("module_ibc").add_message(msg)) + Ok(app.response("module_ibc").add_attribute("method", "route").add_message(msg)) } - ServerIbcMessage::UpdateMessage { id, status } => { - + ServerIbcMessage::UpdateMessage { id, header, status } => { println!("module_ibc_handler update_msg: {:?}, status: {:?}", id, status); // TODO: custom error - let from_chain = AWAITING.load(deps.storage, &id)?; + let from_chain = AWAITING.load(deps.storage, &id).map_err(|_| ServerError::Std(StdError::generic_err(format!("Message not found: {:?}", id))))?; AWAITING.remove(deps.storage, &id); - let msg = route_update_msg(deps, msg, header, &mut app)?; - - Ok(app.response("module_ibc").add_message(msg)) + let msg = update_message_status(deps, &mut app, id, header, status)?; + Ok(app.response("module_ibc").add_attribute("method", "update_status").add_message(msg)) + } _ => Err(ServerError::UnauthorizedIbcMessage {}), } } -// ANCHOR_END: module_ibc_handler diff --git a/packages/ibcmail/src/client/api.rs b/packages/ibcmail/src/client/api.rs index 13408a1..88f8eac 100644 --- a/packages/ibcmail/src/client/api.rs +++ b/packages/ibcmail/src/client/api.rs @@ -4,9 +4,7 @@ use abstract_app::sdk::AppInterface; use cosmwasm_std::{CosmosMsg, Deps}; -use crate::{ - client::msg::ClientExecuteMsg, Header, IbcMailMessage, Message, Route, IBCMAIL_CLIENT_ID, -}; +use crate::{client::msg::ClientExecuteMsg, Header, IbcMailMessage, Message, Route, IBCMAIL_CLIENT_ID, MessageHash, MessageStatus}; // API for Abstract SDK users pub trait ClientInterface: AppInterface { @@ -54,4 +52,13 @@ impl<'a, T: ClientInterface> MailClient<'a, T> { ) -> AbstractSdkResult { self.request(ClientExecuteMsg::ReceiveMessage(message)) } + + /// Receive message + pub fn update_msg_status( + &self, + id: MessageHash, + status: MessageStatus, + ) -> AbstractSdkResult { + self.request(ClientExecuteMsg::UpdateMessageStatus { id, status }) + } } diff --git a/packages/ibcmail/src/client/error.rs b/packages/ibcmail/src/client/error.rs index 125f673..6ea3ea2 100644 --- a/packages/ibcmail/src/client/error.rs +++ b/packages/ibcmail/src/client/error.rs @@ -3,6 +3,7 @@ use cosmwasm_std::StdError; use cw_asset::AssetError; use cw_controllers::AdminError; use thiserror::Error; +use crate::MessageHash; #[derive(Error, Debug, PartialEq)] pub enum ClientError { @@ -30,6 +31,9 @@ pub enum ClientError { #[error("Recipient is not the current account")] NotRecipient {}, + #[error("Message not found: {0}")] + MessageNotFound(MessageHash), + #[error("{0} is not implemented")] NotImplemented(String), } diff --git a/packages/ibcmail/src/client/msg.rs b/packages/ibcmail/src/client/msg.rs index 585aa60..75c0076 100644 --- a/packages/ibcmail/src/client/msg.rs +++ b/packages/ibcmail/src/client/msg.rs @@ -17,8 +17,13 @@ pub struct ClientInstantiateMsg {} #[derive(cw_orch::ExecuteFns)] #[cw_orch(impl_into(ExecuteMsg))] pub enum ClientExecuteMsg { - /// Receive a message from the server + /// Receive a message from the server. ReceiveMessage(IbcMailMessage), + /// Update the status of a message. only callable by the server + UpdateMessageStatus { + id: MessageHash, + status: MessageStatus, + }, /// Send a message SendMessage { message: Message, diff --git a/packages/ibcmail/src/client/state.rs b/packages/ibcmail/src/client/state.rs index ae07a43..db863a9 100644 --- a/packages/ibcmail/src/client/state.rs +++ b/packages/ibcmail/src/client/state.rs @@ -1,7 +1,8 @@ use cw_storage_plus::Map; -use crate::{IbcMailMessage, MessageHash}; +use crate::{IbcMailMessage, MessageHash, MessageStatus}; // TODO: use an indexed map in the future pub const RECEIVED: Map = Map::new("received"); pub const SENT: Map = Map::new("sent"); +pub const STATUS: Map = Map::new("status"); \ No newline at end of file diff --git a/packages/ibcmail/src/lib.rs b/packages/ibcmail/src/lib.rs index 4070245..a21ebb5 100644 --- a/packages/ibcmail/src/lib.rs +++ b/packages/ibcmail/src/lib.rs @@ -1,11 +1,17 @@ pub mod client; pub mod server; +use std::fmt; +use std::fmt::{Display, Formatter}; +use abstract_adapter::sdk::ModuleRegistryInterface; +use abstract_adapter::std::version_control::NamespaceResponse; use abstract_app::objects::TruncatedChainId; +use abstract_app::sdk::ModuleRegistry; use abstract_app::std::objects::AccountId; use abstract_app::std::objects::{account::AccountTrace, namespace::Namespace}; use const_format::concatcp; use cosmwasm_std::Timestamp; +use crate::server::error::ServerError; pub const IBCMAIL_NAMESPACE: &str = "ibcmail"; pub const IBCMAIL_CLIENT_ID: &str = concatcp!(IBCMAIL_NAMESPACE, ":", "client"); @@ -48,6 +54,7 @@ pub struct IbcMailMessage { pub struct Header { pub current_hop: u32, pub route: Route, + pub recipient: Recipient } pub type Route = AccountTrace; @@ -84,6 +91,26 @@ impl Recipient { pub fn namespace(namespace: Namespace, chain: Option) -> Self { Recipient::Namespace { namespace, chain } } + + pub fn resolve_account_id(&self, module_registry: ModuleRegistry) -> Result { + Ok(match self { + Recipient::Account { id: account_id, .. } => Ok(account_id.clone()), + Recipient::Namespace { namespace, .. } => { + // TODO: this only allows for addressing recipients via namespace of their email account directly. + // If they have the email application installed on a sub-account, this will not be able to identify the sub-account. + let namespace_status = module_registry.query_namespace(namespace.clone())?; + match namespace_status { + NamespaceResponse::Claimed(info) => Ok(info.account_id), + NamespaceResponse::Unclaimed {} => { + return Err(ServerError::UnclaimedNamespace(namespace.clone())); + } + } + } + _ => Err(ServerError::NotImplemented( + "Non-account recipients not supported".to_string(), + )), + }?) + } } #[non_exhaustive] @@ -111,3 +138,13 @@ pub enum MessageStatus { Received, Failed, } + +impl Display for MessageStatus { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + MessageStatus::Sent => write!(f, "Sent"), + MessageStatus::Received => write!(f, "Received"), + MessageStatus::Failed => write!(f, "Failed"), + } + } +} \ No newline at end of file diff --git a/packages/ibcmail/src/server/msg.rs b/packages/ibcmail/src/server/msg.rs index 0c89a81..9dabbef 100644 --- a/packages/ibcmail/src/server/msg.rs +++ b/packages/ibcmail/src/server/msg.rs @@ -12,7 +12,7 @@ pub struct ServerInstantiateMsg {} /// App execute messages #[cosmwasm_schema::cw_serde] pub enum ServerExecuteMsg { - /// Route a message + /// Process a message sent by the client ProcessMessage { msg: IbcMailMessage, route: Option, @@ -25,7 +25,8 @@ pub enum ServerExecuteMsg { pub enum ServerIbcMessage { /// Route a message RouteMessage { msg: IbcMailMessage, header: Header }, - UpdateMessage { id: MessageHash, status: MessageStatus }, + /// Send a status update for a message + UpdateMessage { id: MessageHash, header: Header, status: MessageStatus }, } /// App execute messages @@ -33,7 +34,7 @@ pub enum ServerIbcMessage { #[cosmwasm_schema::cw_serde] pub enum ServerCallbackMessage { /// Update a message - UpdateMessage { id: MessageHash, header: Header }, + UpdateMessage { id: MessageHash, header: Header, status: MessageStatus }, } /// App query messages diff --git a/tests/src/client.rs b/tests/src/client.rs index fffa8c6..11120da 100644 --- a/tests/src/client.rs +++ b/tests/src/client.rs @@ -376,14 +376,14 @@ mod send_msg { fn can_send_remote_message_2_hop() -> anyhow::Result<()> { // Create a sender and mock env let interchain = MockBech32InterchainEnv::new(vec![ - ("juno-1", "juno18k2uq7srsr8lwrae6zr0qahpn29rsp7tw83nyx"), + ("juno-1", "juno"), ( "archway-1", - "archway18k2uq7srsr8lwrae6zr0qahpn29rsp7td7wvfd", + "arch", ), ( "neutron-1", - "neutron18k2uq7srsr8lwrae6zr0qahpn29rsp7tu2m2ea", + "neutron", ), ]); From 2c8bbeee33079d985073dbd6853ee0432f2e0a90 Mon Sep 17 00:00:00 2001 From: adairrr <32375605+adairrr@users.noreply.github.com> Date: Sat, 3 Aug 2024 03:30:50 +0200 Subject: [PATCH 03/12] Delivery status --- Cargo.toml | 1 + contracts/client/src/contract.rs | 1 + contracts/client/src/handlers/instantiate.rs | 13 ++ contracts/client/src/handlers/mod.rs | 3 +- contracts/client/src/lib.rs | 2 + contracts/server/src/contract.rs | 7 +- contracts/server/src/handlers/execute.rs | 122 +++++++----------- contracts/server/src/handlers/ibc_callback.rs | 58 ++++++--- contracts/server/src/handlers/instantiate.rs | 14 ++ contracts/server/src/handlers/mod.rs | 3 +- contracts/server/src/handlers/module_ibc.rs | 21 +-- contracts/server/src/lib.rs | 1 + contracts/server/src/replies/deliver_msg.rs | 40 ++++++ contracts/server/src/replies/mod.rs | 7 + packages/ibcmail/Cargo.toml | 2 +- packages/ibcmail/src/client/api.rs | 6 +- packages/ibcmail/src/client/state.rs | 5 +- packages/ibcmail/src/features.rs | 1 + packages/ibcmail/src/lib.rs | 45 ++++++- packages/ibcmail/src/server/error.rs | 3 + packages/ibcmail/src/server/msg.rs | 33 ++++- packages/ibcmail/src/server/state.rs | 7 +- tests/src/client.rs | 25 +++- 23 files changed, 299 insertions(+), 121 deletions(-) create mode 100644 contracts/client/src/handlers/instantiate.rs create mode 100644 contracts/server/src/handlers/instantiate.rs create mode 100644 contracts/server/src/replies/deliver_msg.rs create mode 100644 contracts/server/src/replies/mod.rs create mode 100644 packages/ibcmail/src/features.rs diff --git a/Cargo.toml b/Cargo.toml index 5a217f9..0d564c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ cw-controllers = "1.1.2" cw-storage-plus = "1.2.0" thiserror = "1.0.50" cw-paginate = "0.2.1" +cw-item-set = "0.7.1" schemars = "0.8" cw-asset = "3.0.0" cw-semver = { version = "1.0", features = ["serde"] } diff --git a/contracts/client/src/contract.rs b/contracts/client/src/contract.rs index d38dbf9..1cf98ee 100644 --- a/contracts/client/src/contract.rs +++ b/contracts/client/src/contract.rs @@ -8,6 +8,7 @@ use crate::{dependencies::MAIL_SERVER_DEP, error::ClientError, handlers, APP_VER pub type ClientResult = Result; const APP: App = App::new(IBCMAIL_CLIENT_ID, APP_VERSION, None) + .with_instantiate(handlers::instantiate_handler) .with_execute(handlers::execute_handler) .with_query(handlers::query_handler) .with_migrate(handlers::migrate_handler) diff --git a/contracts/client/src/handlers/instantiate.rs b/contracts/client/src/handlers/instantiate.rs new file mode 100644 index 0000000..3c4d341 --- /dev/null +++ b/contracts/client/src/handlers/instantiate.rs @@ -0,0 +1,13 @@ +use abstract_app::traits::AbstractResponse; +use cosmwasm_std::{DepsMut, Env, MessageInfo}; +use ibcmail::client::msg::ClientInstantiateMsg; +use ibcmail::client::state::FEATURES; +use crate::{CLIENT_FEATURES, contract::{App, ClientResult}, msg::AppMigrateMsg}; + +pub fn instantiate_handler(deps: DepsMut, _env: Env, info: MessageInfo, app: App, _msg: ClientInstantiateMsg) -> ClientResult { + for feature in CLIENT_FEATURES { + FEATURES.save(deps.storage, feature.to_string(), &true)?; + } + + Ok(app.response("instantiate").add_attribute("features", CLIENT_FEATURES.join(","))) +} diff --git a/contracts/client/src/handlers/mod.rs b/contracts/client/src/handlers/mod.rs index 0f15788..338860f 100644 --- a/contracts/client/src/handlers/mod.rs +++ b/contracts/client/src/handlers/mod.rs @@ -1,7 +1,8 @@ pub mod execute; pub mod migrate; pub mod query; +pub mod instantiate; pub use crate::handlers::{ - execute::execute_handler, migrate::migrate_handler, query::query_handler, + execute::execute_handler, migrate::migrate_handler, query::query_handler, instantiate::instantiate_handler }; diff --git a/contracts/client/src/lib.rs b/contracts/client/src/lib.rs index dc5ddc3..f4c64ef 100644 --- a/contracts/client/src/lib.rs +++ b/contracts/client/src/lib.rs @@ -4,9 +4,11 @@ mod handlers; /// The version of your app pub const APP_VERSION: &str = env!("CARGO_PKG_VERSION"); +pub const CLIENT_FEATURES: &[&str] = &[DELIVERY_STATUS_FEATURE]; #[cfg(feature = "interface")] pub use contract::interface::ClientInterface; #[cfg(feature = "interface")] pub use ibcmail::client::msg::{ClientExecuteMsgFns, ClientQueryMsgFns}; pub use ibcmail::client::{error, msg, state}; +use ibcmail::features::DELIVERY_STATUS_FEATURE; diff --git a/contracts/server/src/contract.rs b/contracts/server/src/contract.rs index 26dbb34..dadc329 100644 --- a/contracts/server/src/contract.rs +++ b/contracts/server/src/contract.rs @@ -3,9 +3,10 @@ pub use ibcmail::server::ServerAdapter as Adapter; use ibcmail::{server::error::ServerError, IBCMAIL_SERVER_ID}; use ibcmail::{server::msg::ServerInstantiateMsg, IBCMAIL_CLIENT_ID}; -use crate::{handlers, APP_VERSION}; +use crate::{handlers, APP_VERSION, replies}; use abstract_adapter::objects::dependency::StaticDependency; +use crate::replies::DELIVER_MESSAGE_REPLY; pub const MAIL_CLIENT: StaticDependency = StaticDependency::new(IBCMAIL_CLIENT_ID, &[]); pub const IBC_CLIENT: StaticDependency = StaticDependency::new("abstract:ibc-client", &[]); @@ -14,9 +15,13 @@ pub const IBC_CLIENT: StaticDependency = StaticDependency::new("abstract:ibc-cli pub type ServerResult = Result; const ADAPTER: Adapter = Adapter::new(IBCMAIL_SERVER_ID, APP_VERSION, None) + .with_instantiate(handlers::instantiate_handler) .with_execute(handlers::execute_handler) .with_module_ibc(handlers::module_ibc_handler) .with_ibc_callback(handlers::ibc_callback_handler) + .with_replies(&[ + (DELIVER_MESSAGE_REPLY, replies::deliver_message_reply), + ]) .with_dependencies(&[MAIL_CLIENT, IBC_CLIENT]); // Export handlers diff --git a/contracts/server/src/handlers/execute.rs b/contracts/server/src/handlers/execute.rs index 1067370..71ce01a 100644 --- a/contracts/server/src/handlers/execute.rs +++ b/contracts/server/src/handlers/execute.rs @@ -10,17 +10,21 @@ use abstract_adapter::std::{ }; use abstract_adapter::std::ibc::Callback; use abstract_adapter::std::version_control::AccountBase; -use abstract_adapter::traits::AbstractResponse; -use cosmwasm_std::{Addr, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, to_json_binary, wasm_execute}; +use abstract_adapter::traits::{AbstractResponse, AccountIdentification}; +use cosmwasm_std::{Addr, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, StdResult, SubMsg, to_json_binary, wasm_execute}; -use ibcmail::{client::api::ClientInterface, Header, IbcMailMessage, MessageHash, MessageStatus, Recipient, Route, server::{ +use ibcmail::{client::api::ClientInterface, Header, IbcMailMessage, Recipient, Route, Sender, server::{ msg::{ServerExecuteMsg, ServerIbcMessage}, ServerAdapter, }}; use ibcmail::client::api::MailClient; -use ibcmail::server::state::AWAITING; +use ibcmail::client::state::FEATURES; +use ibcmail::features::DELIVERY_STATUS_FEATURE; +use ibcmail::server::msg::ServerMessage; +use ibcmail::server::state::{AWAITING, AWAITING_DELIVERY}; use crate::{contract::{Adapter, ServerResult}, error::ServerError}; +use crate::replies::DELIVER_MESSAGE_REPLY; // ANCHOR: execute_handler pub fn execute_handler( @@ -48,7 +52,10 @@ fn process_message( ) -> ServerResult { println!("processing message: {:?} with route {:?}", msg, route); + let sender_acc_id = app.account_id(deps.as_ref()).map_err(|_| ServerError::NoSenderAccount)?; + let current_chain = TruncatedChainId::new(&env); + let sender = Sender::account(sender_acc_id, Some(current_chain.clone())); let route: Route = if let Some(route) = route { Ok::<_, ServerError>(match route { @@ -97,37 +104,38 @@ fn process_message( } }?; - let metadata = Header { + + let header = Header { current_hop: 0, route, - recipient: msg.message.recipient.clone() + recipient: msg.message.recipient.clone(), + sender, }; - let msg = route_msg(deps, msg, metadata, &mut app)?; + let msgs = route_msg(deps, &mut app, ServerMessage::mail(msg), header)?; - Ok(app.response("route").add_message(msg)) + Ok(app.response("route").add_submessages(msgs)) } pub(crate) fn route_msg( deps: DepsMut, - msg: IbcMailMessage, - header: Header, app: &mut ServerAdapter, -) -> ServerResult { + msg: ServerMessage, + header: Header, +) -> ServerResult> { println!("routing message: {:?}, metadata: {:?}", msg, header); match header.route { - AccountTrace::Local => route_to_local_account(deps.as_ref(), app, msg, header), + AccountTrace::Local => route_to_local_account(deps, app, msg, header), AccountTrace::Remote(ref chains) => { println!("routing to chains: {:?}", chains); // check index of hop. If we are on the final hop, route to local account if header.current_hop == (chains.len() - 1) as u32 { - println!("routing to local account: {:?}", chains); - return route_to_local_account(deps.as_ref(), app, msg.clone(), header); + println!("routing to local account: {:?}", chains.last().unwrap()); + return route_to_local_account(deps, app, msg.clone(), header); } // TODO verify that the chain is a valid chain - let dest_chain = chains .get(header.current_hop as usize + 1) @@ -137,81 +145,51 @@ pub(crate) fn route_msg( })?; // Awaiting callback - AWAITING.save(deps.storage, &msg.id, dest_chain)?; + // Save that we're awaiting callbacks from dest chain onwards. + AWAITING.save(deps.storage, &msg.id(), dest_chain)?; let msg = remote_server_msg(deps, &app, &ServerIbcMessage::RouteMessage { msg, header: header.clone() }, dest_chain)?; - Ok::(msg) + Ok::, ServerError>(vec![SubMsg::new(msg)]) } } } /// Route a mail message to an account on the local chain fn route_to_local_account( - deps: Deps, + deps: DepsMut, app: &mut ServerAdapter, - msg: IbcMailMessage, + msg: ServerMessage, header: Header, -) -> ServerResult { - println!("routing to local account: {:?}", msg.message.recipient); +) -> ServerResult> { + println!("routing to local account: {:?}", header.recipient); // This is a local message - let mail_client = get_recipient_mail_client(deps, app, &msg.message.recipient)?; - let receive_msg: CosmosMsg = mail_client.receive_msg(msg, header)?; - - Ok(receive_msg) -} - -/// Route a mail message to an account on the local chain -fn update_local_message_status( - deps: Deps, - module: &mut ServerAdapter, - recipient: &Recipient, - id: MessageHash, - status: MessageStatus, -) -> ServerResult { - println!("updating local message status to local account: {:?}", recipient); - // This is a local message - let mail_client = get_recipient_mail_client(deps, module, recipient)?; - return Ok(mail_client.update_msg_status(id, status)?); -} - - -/// Send a status update for a given message. -pub(crate) fn update_message_status( - deps: DepsMut, - module: &mut ServerAdapter, - id: MessageHash, - header: Header, - status: MessageStatus, -) -> ServerResult { - println!("updating message: {:?}, header: {:?}, status: {:?}", id, header, status); - // let from_chain = AWAITING.load(deps.storage, &id).map_err(|_| ServerError::AwaitedMsgNotFound(id))?; + match msg { + ServerMessage::Mail { message } => { + AWAITING_DELIVERY.update(deps.storage, |mut awaiting| -> StdResult> { + awaiting.push((message.id.clone(), header.clone())); + Ok(awaiting) + })?; + + let mail_client = get_recipient_mail_client(deps.as_ref(), app, &header.recipient)?; + Ok(vec![SubMsg::reply_always(mail_client.receive_msg(message, header)?, DELIVER_MESSAGE_REPLY)]) + } + ServerMessage::DeliveryStatus { id, status } => { + println!("updating local delivery message status: {:?}", header.recipient); - match header.route { - AccountTrace::Local => update_local_message_status(deps.as_ref(), module, &header.recipient, id, status), - AccountTrace::Remote(ref chains) => { - // we need to take the route and do it in reverse - println!("updating to chains: {:?}", chains); + let mail_client = get_recipient_mail_client(deps.as_ref(), app, &header.recipient)?; + let is_delivery_enabled = FEATURES.query(&deps.querier, mail_client.module_address()?, DELIVERY_STATUS_FEATURE.to_string()).is_ok_and(|f| f.is_some_and(|f| f)); - // check index of hop. If we are on the final hop, route to local account - if header.current_hop == 0 { - println!("updating to local account: {:?}", chains); - return update_local_message_status(deps.as_ref(), module, &header.recipient, id, status); + if is_delivery_enabled { + Ok(vec![SubMsg::new(mail_client.update_msg_status(id, status)?)]) + } else { + Ok(vec![]) } - - let dest_chain = - chains - .get(header.current_hop as usize - 1) - .ok_or(ServerError::InvalidRoute { - route: header.route.clone(), - hop: header.current_hop, - })?; - - let msg = remote_server_msg(deps, &module, &ServerIbcMessage::UpdateMessage { id, header: header.clone(), status }, dest_chain)?; - Ok(msg) } + _ => Err(ServerError::NotImplemented("Unknown message type".to_string())) } } + /// Set the target account for the message and get the mail client for the recipient fn get_recipient_mail_client<'a>(deps: Deps<'a>, app: &'a mut ServerAdapter, recipient: &Recipient) -> ServerResult> { let account_id = recipient.resolve_account_id(app.module_registry(deps)?)?; diff --git a/contracts/server/src/handlers/ibc_callback.rs b/contracts/server/src/handlers/ibc_callback.rs index 6400599..f86339a 100644 --- a/contracts/server/src/handlers/ibc_callback.rs +++ b/contracts/server/src/handlers/ibc_callback.rs @@ -1,7 +1,9 @@ +use abstract_adapter::objects::TruncatedChainId; use abstract_adapter::std::ibc::{Callback, IbcResult}; -use cosmwasm_std::{DepsMut, Env, from_json, Response}; +use cosmwasm_std::{CosmosMsg, DepsMut, Env, from_json, Response, SubMsg}; -use ibcmail::{MessageStatus, server::{msg::ServerIbcMessage, ServerAdapter}}; +use ibcmail::{Header, MessageStatus, Recipient, Route, Sender, server::{msg::ServerIbcMessage, ServerAdapter}}; +use ibcmail::server::msg::ServerMessage; use ibcmail::server::state::AWAITING; use crate::contract::ServerResult; use crate::handlers::execute; @@ -19,7 +21,7 @@ pub fn ibc_callback_handler( // panic!("ibc_callback_handler: {:?}", callback); println!("ibc_callback_handler callback: {:?} result, env: {:?}", callback, _env); - let msgs = match ibc_result { + let msgs: Vec = match ibc_result { // The destination server successfully processed the message IbcResult::Execute { result: Ok(_response), initiator_msg } => { println!("ibc_callback_handler execute success"); @@ -28,14 +30,10 @@ pub fn ibc_callback_handler( match origin_msg { // We successfully routed a packet, and need to send an update to the sender ServerIbcMessage::RouteMessage { msg, header } => { - println!("ibc_callback_handler success route_msg id: {:?}, header: {:?}", msg.id, header); - vec![execute::update_message_status(deps, &mut app, msg.id, header, MessageStatus::Received)?] - }, - // We successfully updated a message status, we shouldn't need to do anything now - ServerIbcMessage::UpdateMessage { id, status, header } => { - println!("ibc_callback_handler success update_msg: {:?}", id); + println!("ibc_callback_handler success route_msg id: {:?}, header: {:?}", msg.id(), header); vec![] - } + // vec![execute::update_message_status(deps, &mut app, msg.id, header, MessageStatus::Received)?] + }, _ => { println!("Unknown message"); vec![] @@ -48,14 +46,38 @@ pub fn ibc_callback_handler( let origin_msg: ServerIbcMessage = from_json(initiator_msg)?; match origin_msg { ServerIbcMessage::RouteMessage { msg, header } => { - println!("ibc_callback_handler execute error route_msg id: {:?}, header: {:?}", msg.id, header); - vec![execute::update_message_status(deps, &mut app, msg.id, header, MessageStatus::Failed)?] + println!("ibc_callback_handler execute error route_msg id: {:?}, header: {:?}", msg.id(), header); + match msg { + ServerMessage::Mail { ref message } => { + // archway juno neutron + // juno -> neutron failed current hop 1 + // expected: juno archway + // need to remove anything after the current hop + let status_header = Header { + current_hop: 0, + route: match header.route { + Route::Remote(mut chains) => { + chains.truncate(header.current_hop as usize); + chains.reverse(); + Route::Remote(chains) + }, + _ => Route::Local + }, + recipient: message.sender.clone().try_into()?, + sender: Sender::Server { + chain: TruncatedChainId::new(&_env), + address: _env.contract.address.to_string(), + } + }; + execute::route_msg(deps, &mut app, ServerMessage::delivery_status(msg.id(), MessageStatus::Failed), status_header)? + }, + _ => { + println!("ibc_callback_handler execute error route_msg unknown message"); + vec![] + }, + } + // We failed to route a message, we send a failed status update to the sender }, - // We failed to update a message... - ServerIbcMessage::UpdateMessage { id, header, status } => { - println!("ibc_callback_handler execute error update_msg: {:?}", id); - vec![] - } _ => { println!("unknown message"); vec![] @@ -73,7 +95,7 @@ pub fn ibc_callback_handler( } }; - Ok(Response::default().add_messages(msgs)) + Ok(Response::default().add_submessages(msgs)) } // ANCHOR_END: ibc_callback_handler diff --git a/contracts/server/src/handlers/instantiate.rs b/contracts/server/src/handlers/instantiate.rs new file mode 100644 index 0000000..0a499f7 --- /dev/null +++ b/contracts/server/src/handlers/instantiate.rs @@ -0,0 +1,14 @@ +use abstract_adapter::sdk::AbstractResponse; +use cosmwasm_std::{DepsMut, Env, MessageInfo}; + +use ibcmail::server::msg::ServerInstantiateMsg; +use ibcmail::server::ServerAdapter; +use ibcmail::server::state::AWAITING_DELIVERY; + +use crate::contract::ServerResult; + +pub fn instantiate_handler(deps: DepsMut, _env: Env, info: MessageInfo, app: ServerAdapter, _msg: ServerInstantiateMsg) -> ServerResult { + + AWAITING_DELIVERY.save(deps.storage, &vec![])?; + Ok(app.response("instantiate")) +} diff --git a/contracts/server/src/handlers/mod.rs b/contracts/server/src/handlers/mod.rs index a59c30d..4ea4d41 100644 --- a/contracts/server/src/handlers/mod.rs +++ b/contracts/server/src/handlers/mod.rs @@ -1,5 +1,6 @@ pub mod execute; pub mod module_ibc; pub mod ibc_callback; +pub mod instantiate; -pub use crate::handlers::{execute::execute_handler, module_ibc::module_ibc_handler, ibc_callback::ibc_callback_handler}; +pub use crate::handlers::{instantiate::instantiate_handler, execute::execute_handler, module_ibc::module_ibc_handler, ibc_callback::ibc_callback_handler}; diff --git a/contracts/server/src/handlers/module_ibc.rs b/contracts/server/src/handlers/module_ibc.rs index c7264a0..16d02d0 100644 --- a/contracts/server/src/handlers/module_ibc.rs +++ b/contracts/server/src/handlers/module_ibc.rs @@ -1,14 +1,13 @@ use abstract_adapter::sdk::AbstractResponse; use abstract_adapter::std::ibc::ModuleIbcInfo; -use cosmwasm_std::{from_json, Binary, DepsMut, Env, StdResult, StdError}; +use cosmwasm_std::{Binary, DepsMut, Env, from_json}; use ibcmail::{ - server::{error::ServerError, msg::ServerIbcMessage, ServerAdapter}, IBCMAIL_SERVER_ID, + server::{error::ServerError, msg::ServerIbcMessage, ServerAdapter}, }; -use ibcmail::server::state::AWAITING; + use crate::{contract::ServerResult, handlers::execute::route_msg}; -use crate::handlers::execute::update_message_status; // ANCHOR: module_ibc_handler pub fn module_ibc_handler( @@ -29,19 +28,9 @@ pub fn module_ibc_handler( ServerIbcMessage::RouteMessage { msg, mut header } => { header.current_hop += 1; - let msg = route_msg(deps, msg, header, &mut app)?; - - Ok(app.response("module_ibc").add_attribute("method", "route").add_message(msg)) - } - ServerIbcMessage::UpdateMessage { id, header, status } => { - println!("module_ibc_handler update_msg: {:?}, status: {:?}", id, status); - // TODO: custom error - let from_chain = AWAITING.load(deps.storage, &id).map_err(|_| ServerError::Std(StdError::generic_err(format!("Message not found: {:?}", id))))?; - AWAITING.remove(deps.storage, &id); - - let msg = update_message_status(deps, &mut app, id, header, status)?; + let msgs = route_msg(deps, &mut app, msg, header)?; - Ok(app.response("module_ibc").add_attribute("method", "update_status").add_message(msg)) + Ok(app.response("module_ibc").add_attribute("method", "route").add_submessages(msgs)) } _ => Err(ServerError::UnauthorizedIbcMessage {}), } diff --git a/contracts/server/src/lib.rs b/contracts/server/src/lib.rs index ba08141..18232c9 100644 --- a/contracts/server/src/lib.rs +++ b/contracts/server/src/lib.rs @@ -1,5 +1,6 @@ pub mod contract; mod handlers; +mod replies; #[cfg(feature = "interface")] pub use contract::interface::ServerInterface; diff --git a/contracts/server/src/replies/deliver_msg.rs b/contracts/server/src/replies/deliver_msg.rs new file mode 100644 index 0000000..37466d1 --- /dev/null +++ b/contracts/server/src/replies/deliver_msg.rs @@ -0,0 +1,40 @@ +use abstract_adapter::objects::TruncatedChainId; +use abstract_adapter::sdk::AbstractResponse; +use cosmwasm_std::{DepsMut, Env, Reply, SubMsgResult}; + +use ibcmail::{Header, MessageStatus, Sender}; +use ibcmail::server::msg::ServerMessage; +use ibcmail::server::ServerAdapter; +use ibcmail::server::state::AWAITING_DELIVERY; + +use crate::contract::ServerResult; +use crate::handlers::execute::route_msg; + +pub fn deliver_message_reply(deps: DepsMut, env: Env, mut app: ServerAdapter, reply: Reply) -> ServerResult { + let delivery_status = match reply.result { + SubMsgResult::Ok(_) => { + MessageStatus::Received + } + SubMsgResult::Err(_) => { + MessageStatus::Failed + } + }; + + // Load the awaiting message + let mut awaiting_msgs = AWAITING_DELIVERY.load(deps.storage)?; + let (message_id, origin_header) = awaiting_msgs.remove(0); + AWAITING_DELIVERY.save(deps.storage, &awaiting_msgs)?; + + let delivery_msg = ServerMessage::delivery_status(message_id.clone(), delivery_status); + let delivery_header = origin_header.reverse(Sender::Server { + address: env.contract.address.to_string(), + chain: TruncatedChainId::new(&env) + })?; + + let msg = route_msg(deps, &mut app, delivery_msg, delivery_header)?; + + Ok(app + .response("deliver_message_reply") + .add_attribute("message_id", message_id) + .add_submessages(msg)) +} diff --git a/contracts/server/src/replies/mod.rs b/contracts/server/src/replies/mod.rs new file mode 100644 index 0000000..1475331 --- /dev/null +++ b/contracts/server/src/replies/mod.rs @@ -0,0 +1,7 @@ +mod deliver_msg; + +pub use deliver_msg::{deliver_message_reply}; + +pub const DELIVER_MESSAGE_REPLY: u64 = 1u64; + +pub const STATUS_UPDATE_REPLY: u64 = 2u64; diff --git a/packages/ibcmail/Cargo.toml b/packages/ibcmail/Cargo.toml index 4a9f63c..81ff821 100644 --- a/packages/ibcmail/Cargo.toml +++ b/packages/ibcmail/Cargo.toml @@ -19,4 +19,4 @@ thiserror = { workspace = true } cw-asset = { workspace = true } cw-controllers = { workspace = true } cw-semver = { workspace = true } -const_format = { workspace = true } +const_format = { workspace = true } \ No newline at end of file diff --git a/packages/ibcmail/src/client/api.rs b/packages/ibcmail/src/client/api.rs index 88f8eac..990dfd9 100644 --- a/packages/ibcmail/src/client/api.rs +++ b/packages/ibcmail/src/client/api.rs @@ -2,7 +2,7 @@ use abstract_adapter::{sdk::AbstractSdkResult, std::objects::module::ModuleId}; use abstract_app::sdk::AppInterface; -use cosmwasm_std::{CosmosMsg, Deps}; +use cosmwasm_std::{Addr, CosmosMsg, Deps}; use crate::{client::msg::ClientExecuteMsg, Header, IbcMailMessage, Message, Route, IBCMAIL_CLIENT_ID, MessageHash, MessageStatus}; @@ -33,6 +33,10 @@ impl<'a, T: ClientInterface> MailClient<'a, T> { self.module_id } + pub fn module_address(&self) -> AbstractSdkResult { + self.base.modules(self.deps).module_address(self.module_id()) + } + // Execute a request on the ibc mail client fn request(&self, msg: ClientExecuteMsg) -> AbstractSdkResult { let apps = self.base.apps(self.deps); diff --git a/packages/ibcmail/src/client/state.rs b/packages/ibcmail/src/client/state.rs index db863a9..1aeae8c 100644 --- a/packages/ibcmail/src/client/state.rs +++ b/packages/ibcmail/src/client/state.rs @@ -5,4 +5,7 @@ use crate::{IbcMailMessage, MessageHash, MessageStatus}; // TODO: use an indexed map in the future pub const RECEIVED: Map = Map::new("received"); pub const SENT: Map = Map::new("sent"); -pub const STATUS: Map = Map::new("status"); \ No newline at end of file +pub const STATUS: Map = Map::new("status"); + +/// Set of features supported by the client +pub const FEATURES: Map = Map::new("features"); \ No newline at end of file diff --git a/packages/ibcmail/src/features.rs b/packages/ibcmail/src/features.rs new file mode 100644 index 0000000..01e642d --- /dev/null +++ b/packages/ibcmail/src/features.rs @@ -0,0 +1 @@ +pub const DELIVERY_STATUS_FEATURE: &str = "delivery"; \ No newline at end of file diff --git a/packages/ibcmail/src/lib.rs b/packages/ibcmail/src/lib.rs index a21ebb5..85a563f 100644 --- a/packages/ibcmail/src/lib.rs +++ b/packages/ibcmail/src/lib.rs @@ -1,5 +1,6 @@ pub mod client; pub mod server; +pub mod features; use std::fmt; use std::fmt::{Display, Formatter}; @@ -10,7 +11,7 @@ use abstract_app::sdk::ModuleRegistry; use abstract_app::std::objects::AccountId; use abstract_app::std::objects::{account::AccountTrace, namespace::Namespace}; use const_format::concatcp; -use cosmwasm_std::Timestamp; +use cosmwasm_std::{Addr, StdError, StdResult, Timestamp}; use crate::server::error::ServerError; pub const IBCMAIL_NAMESPACE: &str = "ibcmail"; @@ -54,7 +55,26 @@ pub struct IbcMailMessage { pub struct Header { pub current_hop: u32, pub route: Route, - pub recipient: Recipient + pub recipient: Recipient, + pub sender: Sender, +} + +impl Header { + pub fn reverse(self, sender: Sender) -> StdResult
{ + let reverse_route = match self.route { + Route::Remote(mut route) => { + route.reverse(); + Route::Remote(route) + } + Route::Local => Route::Local, + }; + Ok(Header { + current_hop: 0, + route: reverse_route, + recipient: self.sender.clone().try_into()?, + sender + }) + } } pub type Route = AccountTrace; @@ -70,6 +90,10 @@ pub enum Recipient { namespace: Namespace, chain: Option, }, + Server { + chain: TruncatedChainId, + address: String, + }, } impl From for Recipient { @@ -120,6 +144,11 @@ pub enum Sender { id: AccountId, chain: Option, }, + Server { + chain: TruncatedChainId, + // String because it's a different chain + address: String, + } } impl Sender { @@ -131,6 +160,18 @@ impl Sender { } } +impl TryFrom for Recipient { + type Error = StdError; + + fn try_from(sender: Sender) -> Result { + match sender { + Sender::Account { id, chain } => Ok(Recipient::Account { id, chain }), + Sender::Server { chain, address } => Ok(Recipient::Server { chain, address }), + _ => Err(StdError::generic_err("Cannot convert Sender to Recipient").into()), + } + } +} + #[non_exhaustive] #[cosmwasm_schema::cw_serde] pub enum MessageStatus { diff --git a/packages/ibcmail/src/server/error.rs b/packages/ibcmail/src/server/error.rs index e2e18c0..d760afa 100644 --- a/packages/ibcmail/src/server/error.rs +++ b/packages/ibcmail/src/server/error.rs @@ -46,4 +46,7 @@ pub enum ServerError { #[error("Awaited message not found: {0}")] AwaitedMsgNotFound(MessageHash), + + #[error("No sending account")] + NoSenderAccount, } diff --git a/packages/ibcmail/src/server/msg.rs b/packages/ibcmail/src/server/msg.rs index 9dabbef..f5b6f0e 100644 --- a/packages/ibcmail/src/server/msg.rs +++ b/packages/ibcmail/src/server/msg.rs @@ -19,14 +19,41 @@ pub enum ServerExecuteMsg { }, } +#[non_exhaustive] +#[cosmwasm_schema::cw_serde] +pub enum ServerMessage { + Mail { + message: IbcMailMessage, + }, + DeliveryStatus { + id: MessageHash, + status: MessageStatus, + } +} + +impl ServerMessage { + pub fn id(&self) -> MessageHash { + match self { + ServerMessage::Mail { message } => message.id.clone(), + ServerMessage::DeliveryStatus { id, .. } => id.clone(), + } + } + + pub fn mail(message: IbcMailMessage) -> Self { + ServerMessage::Mail { message } + } + + pub fn delivery_status(id: MessageHash, status: MessageStatus) -> Self { + ServerMessage::DeliveryStatus { id, status } + } +} + /// App execute messages #[non_exhaustive] #[cosmwasm_schema::cw_serde] pub enum ServerIbcMessage { /// Route a message - RouteMessage { msg: IbcMailMessage, header: Header }, - /// Send a status update for a message - UpdateMessage { id: MessageHash, header: Header, status: MessageStatus }, + RouteMessage { msg: ServerMessage, header: Header }, } /// App execute messages diff --git a/packages/ibcmail/src/server/state.rs b/packages/ibcmail/src/server/state.rs index 9687505..b4ad5e5 100644 --- a/packages/ibcmail/src/server/state.rs +++ b/packages/ibcmail/src/server/state.rs @@ -1,5 +1,6 @@ use abstract_app::objects::TruncatedChainId; -use cw_storage_plus::Map; -use crate::MessageHash; +use cw_storage_plus::{Item, Map}; +use crate::{Header, Message, MessageHash}; -pub const AWAITING: Map<&MessageHash, TruncatedChainId> = Map::new("awaiting"); \ No newline at end of file +pub const AWAITING: Map<&MessageHash, TruncatedChainId> = Map::new("awaiting"); +pub const AWAITING_DELIVERY: Item> = Item::new("awaiting_delivery"); \ No newline at end of file diff --git a/tests/src/client.rs b/tests/src/client.rs index 11120da..33f8ea2 100644 --- a/tests/src/client.rs +++ b/tests/src/client.rs @@ -182,6 +182,29 @@ mod send_msg { Ok(()) } + #[test] + fn local_message_gets_delivery_result() -> anyhow::Result<()> { + // Create a sender and mock env + let mock = MockBech32::new("mock"); + let env = TestEnv::setup(mock)?; + let client1 = env.client1; + let client2 = env.client2; + + let msg = Message::new( + Recipient::account(client2.account().id()?, None), + "test-subject", + "test-body", + ); + + let res = client1.send_message(msg, None); + assert_that!(res).is_ok(); + + let received_messages = client2.list_messages(MessageStatus::Received, None, None, None)?.messages; + assert_that!(received_messages).has_length(1); + + Ok(()) + } + #[test] fn can_send_local_message_to_namespace() -> anyhow::Result<()> { // Create a sender and mock env @@ -379,7 +402,7 @@ mod send_msg { ("juno-1", "juno"), ( "archway-1", - "arch", + "archway", ), ( "neutron-1", From f6c5c60fc75b6c8ba2960cd128e92e0a8c5fbb1a Mon Sep 17 00:00:00 2001 From: adairrr <32375605+adairrr@users.noreply.github.com> Date: Sat, 3 Aug 2024 03:54:37 +0200 Subject: [PATCH 04/12] Delivery failure separation --- contracts/client/src/handlers/execute.rs | 9 ++-- contracts/client/src/handlers/query.rs | 31 ++++++------ contracts/server/src/handlers/execute.rs | 2 +- contracts/server/src/handlers/ibc_callback.rs | 10 ++-- contracts/server/src/replies/deliver_msg.rs | 8 ++-- packages/ibcmail/src/client/api.rs | 6 +-- packages/ibcmail/src/client/msg.rs | 12 ++--- packages/ibcmail/src/client/state.rs | 4 +- packages/ibcmail/src/lib.rs | 48 ++++++++++++++++--- packages/ibcmail/src/server/msg.rs | 8 ++-- tests/src/client.rs | 40 ++++++++-------- 11 files changed, 103 insertions(+), 75 deletions(-) diff --git a/contracts/client/src/handlers/execute.rs b/contracts/client/src/handlers/execute.rs index ce61525..1f77c9e 100644 --- a/contracts/client/src/handlers/execute.rs +++ b/contracts/client/src/handlers/execute.rs @@ -8,7 +8,7 @@ use cosmwasm_std::{ensure_eq, CosmosMsg, Deps, DepsMut, Env, MessageInfo, Addr}; use ibcmail::{client::{ state::{RECEIVED, SENT}, ClientApp, -}, server::api::{MailServer, ServerInterface}, IbcMailMessage, Message, Recipient, Route, Sender, IBCMAIL_SERVER_ID, MessageHash, MessageStatus}; +}, server::api::{MailServer, ServerInterface}, IbcMailMessage, Message, Recipient, Route, Sender, IBCMAIL_SERVER_ID, MessageHash, DeliveryStatus}; use ibcmail::client::state::STATUS; use crate::{ contract::{App, ClientResult}, @@ -29,7 +29,7 @@ pub fn execute_handler( send_msg(deps, env, info, message, route, app) } ClientExecuteMsg::ReceiveMessage(message) => receive_msg(deps, info, app, message), - ClientExecuteMsg::UpdateMessageStatus { id, status } => update_msg_status(deps, info, app, id, status), + ClientExecuteMsg::UpdateDeliveryStatus { id, status } => update_delivery_status(deps, info, app, id, status), } } // # ANCHOR_END: execute_handler @@ -75,7 +75,6 @@ fn send_msg( // # ANCHOR: receive_msg fn receive_msg(deps: DepsMut, info: MessageInfo, app: App, msg: IbcMailMessage) -> ClientResult { ensure_server_sender(deps.as_ref(), &app, info.sender)?; - ensure_correct_recipient(deps.as_ref(), &msg.message.recipient, &app)?; RECEIVED.save(deps.storage, msg.id.clone(), &msg)?; @@ -86,12 +85,12 @@ fn receive_msg(deps: DepsMut, info: MessageInfo, app: App, msg: IbcMailMessage) } // # ANCHOR_END: receive_msg -fn update_msg_status( +fn update_delivery_status( deps: DepsMut, info: MessageInfo, app: App, id: MessageHash, - status: MessageStatus, + status: DeliveryStatus, ) -> ClientResult { ensure_server_sender(deps.as_ref(), &app, info.sender)?; diff --git a/contracts/client/src/handlers/query.rs b/contracts/client/src/handlers/query.rs index 9b38d3f..491c58d 100644 --- a/contracts/client/src/handlers/query.rs +++ b/contracts/client/src/handlers/query.rs @@ -1,14 +1,11 @@ use abstract_app::sdk::cw_helpers::load_many; use cosmwasm_std::{to_json_binary, Binary, Deps, Env}; use cw_storage_plus::Bound; -use ibcmail::{ - client::{ - error::ClientError, - msg::{MessageFilter, MessagesResponse}, - state::{RECEIVED, SENT}, - }, - MessageHash, MessageStatus, -}; +use ibcmail::{client::{ + error::ClientError, + msg::{MessageFilter, MessagesResponse}, + state::{RECEIVED, SENT}, +}, MessageHash, DeliveryStatus, MessageKind}; use crate::{ contract::{App, ClientResult}, @@ -22,11 +19,11 @@ pub fn query_handler( msg: ClientQueryMsg, ) -> ClientResult { match msg { - ClientQueryMsg::Messages { status, ids } => { + ClientQueryMsg::Messages { kind: status, ids } => { to_json_binary(&query_messages(deps, status, ids)?) } ClientQueryMsg::ListMessages { - status, + kind: status, filter, start_after, limit, @@ -43,12 +40,12 @@ pub fn query_handler( fn query_messages( deps: Deps, - status: MessageStatus, + kind: MessageKind, ids: Vec, ) -> ClientResult { - let map = match status { - MessageStatus::Received => RECEIVED, - MessageStatus::Sent => SENT, + let map = match kind { + MessageKind::Received => RECEIVED, + MessageKind::Sent => SENT, _ => return Err(ClientError::NotImplemented("message type".to_string())), }; @@ -60,14 +57,14 @@ fn query_messages( fn query_messages_list( deps: Deps, - status: MessageStatus, + status: MessageKind, _filter: Option, start: Option, limit: Option, ) -> ClientResult { let map = match status { - MessageStatus::Received => RECEIVED, - MessageStatus::Sent => SENT, + MessageKind::Received => RECEIVED, + MessageKind::Sent => SENT, _ => return Err(ClientError::NotImplemented("message type".to_string())), }; diff --git a/contracts/server/src/handlers/execute.rs b/contracts/server/src/handlers/execute.rs index 71ce01a..35595cd 100644 --- a/contracts/server/src/handlers/execute.rs +++ b/contracts/server/src/handlers/execute.rs @@ -174,7 +174,7 @@ fn route_to_local_account( Ok(vec![SubMsg::reply_always(mail_client.receive_msg(message, header)?, DELIVER_MESSAGE_REPLY)]) } ServerMessage::DeliveryStatus { id, status } => { - println!("updating local delivery message status: {:?}", header.recipient); + println!("updating local delivery message status: recipient: {:?} status: {:?}", header.recipient, status); let mail_client = get_recipient_mail_client(deps.as_ref(), app, &header.recipient)?; let is_delivery_enabled = FEATURES.query(&deps.querier, mail_client.module_address()?, DELIVERY_STATUS_FEATURE.to_string()).is_ok_and(|f| f.is_some_and(|f| f)); diff --git a/contracts/server/src/handlers/ibc_callback.rs b/contracts/server/src/handlers/ibc_callback.rs index f86339a..014eb70 100644 --- a/contracts/server/src/handlers/ibc_callback.rs +++ b/contracts/server/src/handlers/ibc_callback.rs @@ -2,7 +2,7 @@ use abstract_adapter::objects::TruncatedChainId; use abstract_adapter::std::ibc::{Callback, IbcResult}; use cosmwasm_std::{CosmosMsg, DepsMut, Env, from_json, Response, SubMsg}; -use ibcmail::{Header, MessageStatus, Recipient, Route, Sender, server::{msg::ServerIbcMessage, ServerAdapter}}; +use ibcmail::{Header, DeliveryStatus, Recipient, Route, Sender, server::{msg::ServerIbcMessage, ServerAdapter}, DeliveryFailure}; use ibcmail::server::msg::ServerMessage; use ibcmail::server::state::AWAITING; use crate::contract::ServerResult; @@ -42,7 +42,8 @@ pub fn ibc_callback_handler( } // The destination server failed to process the message IbcResult::Execute { result: Err(e), initiator_msg } => { - println!("ibc_callback_handler execute error: {:?}", e); + println!("ibc_callback_handler execute error"); + // println!("ibc_callback_handler execute error: {:?}", e); let origin_msg: ServerIbcMessage = from_json(initiator_msg)?; match origin_msg { ServerIbcMessage::RouteMessage { msg, header } => { @@ -57,7 +58,8 @@ pub fn ibc_callback_handler( current_hop: 0, route: match header.route { Route::Remote(mut chains) => { - chains.truncate(header.current_hop as usize); + // keep the current hop but remove everything after it + chains.truncate(header.current_hop as usize + 1); chains.reverse(); Route::Remote(chains) }, @@ -69,7 +71,7 @@ pub fn ibc_callback_handler( address: _env.contract.address.to_string(), } }; - execute::route_msg(deps, &mut app, ServerMessage::delivery_status(msg.id(), MessageStatus::Failed), status_header)? + execute::route_msg(deps, &mut app, ServerMessage::delivery_status(msg.id(), DeliveryFailure::Unknown(e).into()), status_header)? }, _ => { println!("ibc_callback_handler execute error route_msg unknown message"); diff --git a/contracts/server/src/replies/deliver_msg.rs b/contracts/server/src/replies/deliver_msg.rs index 37466d1..8c54b36 100644 --- a/contracts/server/src/replies/deliver_msg.rs +++ b/contracts/server/src/replies/deliver_msg.rs @@ -2,7 +2,7 @@ use abstract_adapter::objects::TruncatedChainId; use abstract_adapter::sdk::AbstractResponse; use cosmwasm_std::{DepsMut, Env, Reply, SubMsgResult}; -use ibcmail::{Header, MessageStatus, Sender}; +use ibcmail::{Header, DeliveryStatus, Sender, DeliveryFailure}; use ibcmail::server::msg::ServerMessage; use ibcmail::server::ServerAdapter; use ibcmail::server::state::AWAITING_DELIVERY; @@ -13,10 +13,10 @@ use crate::handlers::execute::route_msg; pub fn deliver_message_reply(deps: DepsMut, env: Env, mut app: ServerAdapter, reply: Reply) -> ServerResult { let delivery_status = match reply.result { SubMsgResult::Ok(_) => { - MessageStatus::Received + DeliveryStatus::Delivered } - SubMsgResult::Err(_) => { - MessageStatus::Failed + SubMsgResult::Err(error) => { + DeliveryFailure::Unknown(error).into() } }; diff --git a/packages/ibcmail/src/client/api.rs b/packages/ibcmail/src/client/api.rs index 990dfd9..261d75c 100644 --- a/packages/ibcmail/src/client/api.rs +++ b/packages/ibcmail/src/client/api.rs @@ -4,7 +4,7 @@ use abstract_app::sdk::AppInterface; use cosmwasm_std::{Addr, CosmosMsg, Deps}; -use crate::{client::msg::ClientExecuteMsg, Header, IbcMailMessage, Message, Route, IBCMAIL_CLIENT_ID, MessageHash, MessageStatus}; +use crate::{client::msg::ClientExecuteMsg, Header, IbcMailMessage, Message, Route, IBCMAIL_CLIENT_ID, MessageHash, DeliveryStatus}; // API for Abstract SDK users pub trait ClientInterface: AppInterface { @@ -61,8 +61,8 @@ impl<'a, T: ClientInterface> MailClient<'a, T> { pub fn update_msg_status( &self, id: MessageHash, - status: MessageStatus, + status: DeliveryStatus, ) -> AbstractSdkResult { - self.request(ClientExecuteMsg::UpdateMessageStatus { id, status }) + self.request(ClientExecuteMsg::UpdateDeliveryStatus { id, status }) } } diff --git a/packages/ibcmail/src/client/msg.rs b/packages/ibcmail/src/client/msg.rs index 75c0076..1c6816b 100644 --- a/packages/ibcmail/src/client/msg.rs +++ b/packages/ibcmail/src/client/msg.rs @@ -1,8 +1,6 @@ use cosmwasm_schema::QueryResponses; -use crate::{ - client::ClientApp, IbcMailMessage, Message, MessageHash, MessageStatus, Route, Sender, -}; +use crate::{client::ClientApp, IbcMailMessage, Message, MessageHash, DeliveryStatus, Route, Sender, MessageKind}; // This is used for type safety and re-exporting the contract endpoint structs. abstract_app::app_msg_types!(ClientApp, ClientExecuteMsg, ClientQueryMsg); @@ -20,9 +18,9 @@ pub enum ClientExecuteMsg { /// Receive a message from the server. ReceiveMessage(IbcMailMessage), /// Update the status of a message. only callable by the server - UpdateMessageStatus { + UpdateDeliveryStatus { id: MessageHash, - status: MessageStatus, + status: DeliveryStatus, }, /// Send a message SendMessage { @@ -40,14 +38,14 @@ pub enum ClientExecuteMsg { pub enum ClientQueryMsg { #[returns(MessagesResponse)] ListMessages { - status: MessageStatus, + kind: MessageKind, filter: Option, limit: Option, start_after: Option, }, #[returns(MessagesResponse)] Messages { - status: MessageStatus, + kind: MessageKind, ids: Vec, }, } diff --git a/packages/ibcmail/src/client/state.rs b/packages/ibcmail/src/client/state.rs index 1aeae8c..6529ccc 100644 --- a/packages/ibcmail/src/client/state.rs +++ b/packages/ibcmail/src/client/state.rs @@ -1,11 +1,11 @@ use cw_storage_plus::Map; -use crate::{IbcMailMessage, MessageHash, MessageStatus}; +use crate::{IbcMailMessage, MessageHash, DeliveryStatus}; // TODO: use an indexed map in the future pub const RECEIVED: Map = Map::new("received"); pub const SENT: Map = Map::new("sent"); -pub const STATUS: Map = Map::new("status"); +pub const STATUS: Map = Map::new("status"); /// Set of features supported by the client pub const FEATURES: Map = Map::new("features"); \ No newline at end of file diff --git a/packages/ibcmail/src/lib.rs b/packages/ibcmail/src/lib.rs index 85a563f..cdc8f1d 100644 --- a/packages/ibcmail/src/lib.rs +++ b/packages/ibcmail/src/lib.rs @@ -12,6 +12,7 @@ use abstract_app::std::objects::AccountId; use abstract_app::std::objects::{account::AccountTrace, namespace::Namespace}; use const_format::concatcp; use cosmwasm_std::{Addr, StdError, StdResult, Timestamp}; +use thiserror::Error; use crate::server::error::ServerError; pub const IBCMAIL_NAMESPACE: &str = "ibcmail"; @@ -172,20 +173,53 @@ impl TryFrom for Recipient { } } -#[non_exhaustive] #[cosmwasm_schema::cw_serde] -pub enum MessageStatus { +pub enum MessageKind { Sent, Received, - Failed, } -impl Display for MessageStatus { + +impl Display for MessageKind { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + MessageKind::Sent => write!(f, "Sent"), + MessageKind::Received => write!(f, "Received"), + } + } +} + +#[derive(Error)] +#[non_exhaustive] +#[cosmwasm_schema::cw_serde] +pub enum DeliveryFailure { + #[error("Recipient not found")] + RecipientNotFound, + #[error("Unknown failure: {0}")] + Unknown(String), +} + + +#[non_exhaustive] +#[cosmwasm_schema::cw_serde] +pub enum DeliveryStatus { + Sent, + Delivered, + Failure(DeliveryFailure), +} + +impl From for DeliveryStatus { + fn from(failure: DeliveryFailure) -> Self { + DeliveryStatus::Failure(failure) + } +} + +impl Display for DeliveryStatus { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - MessageStatus::Sent => write!(f, "Sent"), - MessageStatus::Received => write!(f, "Received"), - MessageStatus::Failed => write!(f, "Failed"), + DeliveryStatus::Sent => write!(f, "Sent"), + DeliveryStatus::Delivered => write!(f, "Received"), + DeliveryStatus::Failure(failure) => write!(f, "Failed: {}", failure), } } } \ No newline at end of file diff --git a/packages/ibcmail/src/server/msg.rs b/packages/ibcmail/src/server/msg.rs index f5b6f0e..211d451 100644 --- a/packages/ibcmail/src/server/msg.rs +++ b/packages/ibcmail/src/server/msg.rs @@ -1,6 +1,6 @@ use cosmwasm_schema::QueryResponses; -use crate::{server::ServerAdapter, Header, IbcMailMessage, Route, MessageHash, MessageStatus}; +use crate::{server::ServerAdapter, Header, IbcMailMessage, Route, MessageHash, DeliveryStatus}; // This is used for type safety and re-exporting the contract endpoint structs. abstract_adapter::adapter_msg_types!(ServerAdapter, ServerExecuteMsg, ServerQueryMsg); @@ -27,7 +27,7 @@ pub enum ServerMessage { }, DeliveryStatus { id: MessageHash, - status: MessageStatus, + status: DeliveryStatus, } } @@ -43,7 +43,7 @@ impl ServerMessage { ServerMessage::Mail { message } } - pub fn delivery_status(id: MessageHash, status: MessageStatus) -> Self { + pub fn delivery_status(id: MessageHash, status: DeliveryStatus) -> Self { ServerMessage::DeliveryStatus { id, status } } } @@ -61,7 +61,7 @@ pub enum ServerIbcMessage { #[cosmwasm_schema::cw_serde] pub enum ServerCallbackMessage { /// Update a message - UpdateMessage { id: MessageHash, header: Header, status: MessageStatus }, + UpdateMessage { id: MessageHash, header: Header, status: DeliveryStatus }, } /// App query messages diff --git a/tests/src/client.rs b/tests/src/client.rs index 33f8ea2..25cee9d 100644 --- a/tests/src/client.rs +++ b/tests/src/client.rs @@ -88,7 +88,7 @@ fn create_test_message(from: AccountId, to: AccountId) -> IbcMailMessage { mod receive_msg { use speculoos::assert_that; - use ibcmail::{IBCMAIL_SERVER_ID, MessageStatus}; + use ibcmail::{IBCMAIL_SERVER_ID, MessageKind}; use super::*; @@ -122,7 +122,7 @@ mod receive_msg { assert_that!(res).is_ok(); - let messages = app.list_messages(MessageStatus::Received, None, None, None)?; + let messages = app.list_messages(MessageKind::Received, None, None, None)?; assert_that!(messages.messages).has_length(1); Ok(()) @@ -157,7 +157,7 @@ mod send_msg { use abstract_interface::Abstract; use cw_orch_interchain::{InterchainEnv, MockBech32InterchainEnv}; - use ibcmail::{IBCMAIL_CLIENT_ID, Message, MessageStatus, Route, server::error::ServerError}; + use ibcmail::{IBCMAIL_CLIENT_ID, Message, Route, server::error::ServerError, MessageKind}; use super::*; @@ -199,7 +199,7 @@ mod send_msg { let res = client1.send_message(msg, None); assert_that!(res).is_ok(); - let received_messages = client2.list_messages(MessageStatus::Received, None, None, None)?.messages; + let received_messages = client2.list_messages(MessageKind::Received, None, None, None)?.messages; assert_that!(received_messages).has_length(1); Ok(()) @@ -261,10 +261,10 @@ mod send_msg { fn can_send_remote_message() -> anyhow::Result<()> { // Create a sender and mock env let interchain = MockBech32InterchainEnv::new(vec![ - ("juno-1", "juno18k2uq7srsr8lwrae6zr0qahpn29rsp7tw83nyx"), + ("juno-1", "juno"), ( "archway-1", - "archway18k2uq7srsr8lwrae6zr0qahpn29rsp7td7wvfd", + "archway", ), ]); @@ -294,7 +294,7 @@ mod send_msg { interchain.await_and_check_packets("archway-1", res?)?; - let arch_messages = arch_client.list_messages(MessageStatus::Received, None, None, None)?; + let arch_messages = arch_client.list_messages(MessageKind::Received, None, None, None)?; assert_that!(arch_messages.messages).is_empty(); let juno_client_1_module_addresses = juno_client @@ -323,22 +323,22 @@ mod send_msg { let juno_mail_client = ClientInterface::new(IBCMAIL_CLIENT_ID, juno_env.env.clone()); juno_mail_client.set_address(&juno_client_1_module_addresses.modules[0].1.clone()); let juno_mail_client_messages = - juno_mail_client.list_messages(MessageStatus::Received, None, None, None)?; + juno_mail_client.list_messages(MessageKind::Received, None, None, None)?; assert_that!(juno_mail_client_messages.messages).has_length(1); - let juno_messages = juno_client.list_messages(MessageStatus::Received, None, None, None)?; + let juno_messages = juno_client.list_messages(MessageKind::Received, None, None, None)?; assert_that!(juno_messages.messages).has_length(1); // Sanity check messages method let juno_message_id = juno_messages.messages.first().cloned().unwrap().id; - let juno_message = juno_client.messages(vec![juno_message_id], MessageStatus::Received)?; + let juno_message = juno_client.messages(vec![juno_message_id], MessageKind::Received)?; assert_that!(juno_message.messages).has_length(1); Ok(()) } #[test] - fn send_remote_message_account_dne_callback() -> anyhow::Result<()> { + fn send_remote_message_1_hop_account_dne_updates_status_to_failed() -> anyhow::Result<()> { // Create a sender and mock env let interchain = MockBech32InterchainEnv::new(vec![ ("juno-1", "juno"), @@ -346,20 +346,14 @@ mod send_msg { "archway-1", "archway", ), - ( - "neutron-1", - "neutron", - ), ]); // /Users/adair/.cargo/registry/src/index.crates.io-6f17d22bba15001f/cw-orch-mock-0.22.0/src/queriers/env.rs:12:70: // index out of bounds: the len is 1 but the index is 1 (when initializing with "juno") let arch_env = TestEnv::setup(interchain.get_chain("archway-1")?)?; let juno_env = TestEnv::setup(interchain.get_chain("juno-1")?)?; - let neutron_env = TestEnv::setup(interchain.get_chain("neutron-1")?)?; arch_env.abs.connect_to(&juno_env.abs, &interchain)?; - juno_env.abs.connect_to(&neutron_env.abs, &interchain)?; let arch_client = arch_env.client1; let juno_client = juno_env.client1; @@ -368,13 +362,13 @@ mod send_msg { let arch_to_juno_msg = Message::new( Recipient::account( AccountId::local(420), - Some(TruncatedChainId::from_string("neutron".into())?), + Some(TruncatedChainId::from_string("juno".into())?), ), "test-subject", "test-body", ); - let res = arch_client.send_message(arch_to_juno_msg, Some(Route::Remote(vec![TruncatedChainId::from_string("juno".into())?, TruncatedChainId::from_string("neutron".into())?]))); + let res = arch_client.send_message(arch_to_juno_msg, Some(Route::Remote(vec![TruncatedChainId::from_string("juno".into())?]))); assert_that!(res).is_ok(); @@ -390,6 +384,10 @@ mod send_msg { let packets = interchain.await_packets("archway-1", res?)?; + assert_that!(arch_client.list_messages(MessageKind::Received, None, None, None)?.messages).is_empty(); + assert_that!(juno_client.list_messages(MessageKind::Received, None, None, None)?.messages).is_empty(); + + // interchain.await_packets("archway-1", res?)?; // println!("packets: {:?}", packets); Ok(()) @@ -446,7 +444,7 @@ mod send_msg { interchain.await_and_check_packets("archway-1", res.clone())?; - let arch_messages = arch_client.list_messages(MessageStatus::Received, None, None, None)?; + let arch_messages = arch_client.list_messages(MessageKind::Received, None, None, None)?; assert_that!(arch_messages.messages).is_empty(); let neutron_client_1_module_addresses = neutron_client @@ -466,7 +464,7 @@ mod send_msg { let neutron_mail_client = ClientInterface::new(IBCMAIL_CLIENT_ID, neutron_env.env.clone()); neutron_mail_client.set_address(&neutron_client_1_module_addresses.modules[0].1.clone()); let neutron_mail_client_messages = - neutron_mail_client.list_messages(MessageStatus::Received, None, None, None)?; + neutron_mail_client.list_messages(MessageKind::Received, None, None, None)?; assert_that!(neutron_mail_client_messages.messages).has_length(1); // let juno_messages = neutron_client.list_messages(None, None, None)?; From 7adaf5eb8a7351c0a9815d70544b0f2ab4ff734c Mon Sep 17 00:00:00 2001 From: adairrr <32375605+adairrr@users.noreply.github.com> Date: Sat, 3 Aug 2024 03:54:54 +0200 Subject: [PATCH 05/12] Format --- contracts/client/src/dependencies.rs | 6 +- contracts/client/src/handlers/execute.rs | 35 ++++--- contracts/client/src/handlers/instantiate.rs | 18 +++- contracts/client/src/handlers/mod.rs | 5 +- contracts/client/src/handlers/query.rs | 13 ++- contracts/server/src/contract.rs | 8 +- contracts/server/src/handlers/execute.rs | 91 ++++++++++++++----- contracts/server/src/handlers/ibc_callback.rs | 78 +++++++++++----- contracts/server/src/handlers/instantiate.rs | 11 ++- contracts/server/src/handlers/mod.rs | 7 +- contracts/server/src/handlers/module_ibc.rs | 9 +- contracts/server/src/replies/deliver_msg.rs | 21 +++-- contracts/server/src/replies/mod.rs | 2 +- packages/ibcmail/Cargo.toml | 2 +- packages/ibcmail/src/client/api.rs | 9 +- packages/ibcmail/src/client/error.rs | 2 +- packages/ibcmail/src/client/msg.rs | 5 +- packages/ibcmail/src/client/state.rs | 4 +- packages/ibcmail/src/features.rs | 2 +- packages/ibcmail/src/lib.rs | 23 ++--- packages/ibcmail/src/server/error.rs | 2 +- packages/ibcmail/src/server/msg.rs | 10 +- packages/ibcmail/src/server/state.rs | 4 +- tests/src/bin/approve.rs | 5 +- tests/src/bin/full_demo.rs | 4 +- tests/src/client.rs | 72 +++++++-------- tests/src/lib.rs | 2 +- 27 files changed, 283 insertions(+), 167 deletions(-) diff --git a/contracts/client/src/dependencies.rs b/contracts/client/src/dependencies.rs index 36fb76d..7efe75e 100644 --- a/contracts/client/src/dependencies.rs +++ b/contracts/client/src/dependencies.rs @@ -22,10 +22,8 @@ impl abstract_app::abstract_interface::Depen ); // The IBC client is depended upon by the server - let ibc_client = ModuleInstallConfig::new( - ModuleInfo::from_id_latest("abstract:ibc-client")?, - None, - ); + let ibc_client = + ModuleInstallConfig::new(ModuleInfo::from_id_latest("abstract:ibc-client")?, None); Ok(vec![adapter_install_config, ibc_client]) } diff --git a/contracts/client/src/handlers/execute.rs b/contracts/client/src/handlers/execute.rs index 1f77c9e..6210f91 100644 --- a/contracts/client/src/handlers/execute.rs +++ b/contracts/client/src/handlers/execute.rs @@ -1,19 +1,24 @@ +use crate::{ + contract::{App, ClientResult}, + error::ClientError, + msg::ClientExecuteMsg, +}; use abstract_app::objects::TruncatedChainId; use abstract_app::{ sdk::ModuleRegistryInterface, traits::{AbstractResponse, AccountIdentification}, }; use base64::prelude::*; -use cosmwasm_std::{ensure_eq, CosmosMsg, Deps, DepsMut, Env, MessageInfo, Addr}; -use ibcmail::{client::{ - state::{RECEIVED, SENT}, - ClientApp, -}, server::api::{MailServer, ServerInterface}, IbcMailMessage, Message, Recipient, Route, Sender, IBCMAIL_SERVER_ID, MessageHash, DeliveryStatus}; +use cosmwasm_std::{ensure_eq, Addr, CosmosMsg, Deps, DepsMut, Env, MessageInfo}; use ibcmail::client::state::STATUS; -use crate::{ - contract::{App, ClientResult}, - error::ClientError, - msg::ClientExecuteMsg, +use ibcmail::{ + client::{ + state::{RECEIVED, SENT}, + ClientApp, + }, + server::api::{MailServer, ServerInterface}, + DeliveryStatus, IbcMailMessage, Message, MessageHash, Recipient, Route, Sender, + IBCMAIL_SERVER_ID, }; // # ANCHOR: execute_handler @@ -29,7 +34,9 @@ pub fn execute_handler( send_msg(deps, env, info, message, route, app) } ClientExecuteMsg::ReceiveMessage(message) => receive_msg(deps, info, app, message), - ClientExecuteMsg::UpdateDeliveryStatus { id, status } => update_delivery_status(deps, info, app, id, status), + ClientExecuteMsg::UpdateDeliveryStatus { id, status } => { + update_delivery_status(deps, info, app, id, status) + } } } // # ANCHOR_END: execute_handler @@ -95,10 +102,14 @@ fn update_delivery_status( ensure_server_sender(deps.as_ref(), &app, info.sender)?; // ensure that the message exists - SENT.load(deps.storage, id.clone()).map_err(|_| ClientError::MessageNotFound(id.clone()))?; + SENT.load(deps.storage, id.clone()) + .map_err(|_| ClientError::MessageNotFound(id.clone()))?; STATUS.save(deps.storage, id.clone(), &status)?; - Ok(app.response("update_msg_status").add_attribute("message_id", &id).add_attribute("status", status.to_string())) + Ok(app + .response("update_msg_status") + .add_attribute("message_id", &id) + .add_attribute("status", status.to_string())) } fn ensure_server_sender(deps: Deps, app: &ClientApp, sender: Addr) -> Result<(), ClientError> { diff --git a/contracts/client/src/handlers/instantiate.rs b/contracts/client/src/handlers/instantiate.rs index 3c4d341..2a384bc 100644 --- a/contracts/client/src/handlers/instantiate.rs +++ b/contracts/client/src/handlers/instantiate.rs @@ -1,13 +1,25 @@ +use crate::{ + contract::{App, ClientResult}, + msg::AppMigrateMsg, + CLIENT_FEATURES, +}; use abstract_app::traits::AbstractResponse; use cosmwasm_std::{DepsMut, Env, MessageInfo}; use ibcmail::client::msg::ClientInstantiateMsg; use ibcmail::client::state::FEATURES; -use crate::{CLIENT_FEATURES, contract::{App, ClientResult}, msg::AppMigrateMsg}; -pub fn instantiate_handler(deps: DepsMut, _env: Env, info: MessageInfo, app: App, _msg: ClientInstantiateMsg) -> ClientResult { +pub fn instantiate_handler( + deps: DepsMut, + _env: Env, + info: MessageInfo, + app: App, + _msg: ClientInstantiateMsg, +) -> ClientResult { for feature in CLIENT_FEATURES { FEATURES.save(deps.storage, feature.to_string(), &true)?; } - Ok(app.response("instantiate").add_attribute("features", CLIENT_FEATURES.join(","))) + Ok(app + .response("instantiate") + .add_attribute("features", CLIENT_FEATURES.join(","))) } diff --git a/contracts/client/src/handlers/mod.rs b/contracts/client/src/handlers/mod.rs index 338860f..bd14bb0 100644 --- a/contracts/client/src/handlers/mod.rs +++ b/contracts/client/src/handlers/mod.rs @@ -1,8 +1,9 @@ pub mod execute; +pub mod instantiate; pub mod migrate; pub mod query; -pub mod instantiate; pub use crate::handlers::{ - execute::execute_handler, migrate::migrate_handler, query::query_handler, instantiate::instantiate_handler + execute::execute_handler, instantiate::instantiate_handler, migrate::migrate_handler, + query::query_handler, }; diff --git a/contracts/client/src/handlers/query.rs b/contracts/client/src/handlers/query.rs index 491c58d..ce3adec 100644 --- a/contracts/client/src/handlers/query.rs +++ b/contracts/client/src/handlers/query.rs @@ -1,11 +1,14 @@ use abstract_app::sdk::cw_helpers::load_many; use cosmwasm_std::{to_json_binary, Binary, Deps, Env}; use cw_storage_plus::Bound; -use ibcmail::{client::{ - error::ClientError, - msg::{MessageFilter, MessagesResponse}, - state::{RECEIVED, SENT}, -}, MessageHash, DeliveryStatus, MessageKind}; +use ibcmail::{ + client::{ + error::ClientError, + msg::{MessageFilter, MessagesResponse}, + state::{RECEIVED, SENT}, + }, + DeliveryStatus, MessageHash, MessageKind, +}; use crate::{ contract::{App, ClientResult}, diff --git a/contracts/server/src/contract.rs b/contracts/server/src/contract.rs index dadc329..e6c9297 100644 --- a/contracts/server/src/contract.rs +++ b/contracts/server/src/contract.rs @@ -3,10 +3,10 @@ pub use ibcmail::server::ServerAdapter as Adapter; use ibcmail::{server::error::ServerError, IBCMAIL_SERVER_ID}; use ibcmail::{server::msg::ServerInstantiateMsg, IBCMAIL_CLIENT_ID}; -use crate::{handlers, APP_VERSION, replies}; +use crate::{handlers, replies, APP_VERSION}; -use abstract_adapter::objects::dependency::StaticDependency; use crate::replies::DELIVER_MESSAGE_REPLY; +use abstract_adapter::objects::dependency::StaticDependency; pub const MAIL_CLIENT: StaticDependency = StaticDependency::new(IBCMAIL_CLIENT_ID, &[]); pub const IBC_CLIENT: StaticDependency = StaticDependency::new("abstract:ibc-client", &[]); @@ -19,9 +19,7 @@ const ADAPTER: Adapter = Adapter::new(IBCMAIL_SERVER_ID, APP_VERSION, None) .with_execute(handlers::execute_handler) .with_module_ibc(handlers::module_ibc_handler) .with_ibc_callback(handlers::ibc_callback_handler) - .with_replies(&[ - (DELIVER_MESSAGE_REPLY, replies::deliver_message_reply), - ]) + .with_replies(&[(DELIVER_MESSAGE_REPLY, replies::deliver_message_reply)]) .with_dependencies(&[MAIL_CLIENT, IBC_CLIENT]); // Export handlers diff --git a/contracts/server/src/handlers/execute.rs b/contracts/server/src/handlers/execute.rs index 35595cd..b60e355 100644 --- a/contracts/server/src/handlers/execute.rs +++ b/contracts/server/src/handlers/execute.rs @@ -1,30 +1,39 @@ use abstract_adapter::objects::TruncatedChainId; use abstract_adapter::sdk::{ - AccountVerification, features::ModuleIdentification, ModuleRegistryInterface, + features::ModuleIdentification, AccountVerification, ModuleRegistryInterface, }; +use abstract_adapter::std::ibc::Callback; +use abstract_adapter::std::version_control::AccountBase; use abstract_adapter::std::{ ibc_client, + objects::{account::AccountTrace, module::ModuleInfo}, IBC_CLIENT, - objects::{account::AccountTrace, module::ModuleInfo} - , }; -use abstract_adapter::std::ibc::Callback; -use abstract_adapter::std::version_control::AccountBase; use abstract_adapter::traits::{AbstractResponse, AccountIdentification}; -use cosmwasm_std::{Addr, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, StdResult, SubMsg, to_json_binary, wasm_execute}; +use cosmwasm_std::{ + to_json_binary, wasm_execute, Addr, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, + StdResult, SubMsg, +}; -use ibcmail::{client::api::ClientInterface, Header, IbcMailMessage, Recipient, Route, Sender, server::{ - msg::{ServerExecuteMsg, ServerIbcMessage}, - ServerAdapter, -}}; use ibcmail::client::api::MailClient; use ibcmail::client::state::FEATURES; use ibcmail::features::DELIVERY_STATUS_FEATURE; use ibcmail::server::msg::ServerMessage; use ibcmail::server::state::{AWAITING, AWAITING_DELIVERY}; +use ibcmail::{ + client::api::ClientInterface, + server::{ + msg::{ServerExecuteMsg, ServerIbcMessage}, + ServerAdapter, + }, + Header, IbcMailMessage, Recipient, Route, Sender, +}; -use crate::{contract::{Adapter, ServerResult}, error::ServerError}; use crate::replies::DELIVER_MESSAGE_REPLY; +use crate::{ + contract::{Adapter, ServerResult}, + error::ServerError, +}; // ANCHOR: execute_handler pub fn execute_handler( @@ -52,7 +61,9 @@ fn process_message( ) -> ServerResult { println!("processing message: {:?} with route {:?}", msg, route); - let sender_acc_id = app.account_id(deps.as_ref()).map_err(|_| ServerError::NoSenderAccount)?; + let sender_acc_id = app + .account_id(deps.as_ref()) + .map_err(|_| ServerError::NoSenderAccount)?; let current_chain = TruncatedChainId::new(&env); let sender = Sender::account(sender_acc_id, Some(current_chain.clone())); @@ -104,7 +115,6 @@ fn process_message( } }?; - let header = Header { current_hop: 0, route, @@ -148,7 +158,15 @@ pub(crate) fn route_msg( // Save that we're awaiting callbacks from dest chain onwards. AWAITING.save(deps.storage, &msg.id(), dest_chain)?; - let msg = remote_server_msg(deps, &app, &ServerIbcMessage::RouteMessage { msg, header: header.clone() }, dest_chain)?; + let msg = remote_server_msg( + deps, + &app, + &ServerIbcMessage::RouteMessage { + msg, + header: header.clone(), + }, + dest_chain, + )?; Ok::, ServerError>(vec![SubMsg::new(msg)]) } } @@ -171,27 +189,46 @@ fn route_to_local_account( })?; let mail_client = get_recipient_mail_client(deps.as_ref(), app, &header.recipient)?; - Ok(vec![SubMsg::reply_always(mail_client.receive_msg(message, header)?, DELIVER_MESSAGE_REPLY)]) + Ok(vec![SubMsg::reply_always( + mail_client.receive_msg(message, header)?, + DELIVER_MESSAGE_REPLY, + )]) } ServerMessage::DeliveryStatus { id, status } => { - println!("updating local delivery message status: recipient: {:?} status: {:?}", header.recipient, status); + println!( + "updating local delivery message status: recipient: {:?} status: {:?}", + header.recipient, status + ); let mail_client = get_recipient_mail_client(deps.as_ref(), app, &header.recipient)?; - let is_delivery_enabled = FEATURES.query(&deps.querier, mail_client.module_address()?, DELIVERY_STATUS_FEATURE.to_string()).is_ok_and(|f| f.is_some_and(|f| f)); + let is_delivery_enabled = FEATURES + .query( + &deps.querier, + mail_client.module_address()?, + DELIVERY_STATUS_FEATURE.to_string(), + ) + .is_ok_and(|f| f.is_some_and(|f| f)); if is_delivery_enabled { - Ok(vec![SubMsg::new(mail_client.update_msg_status(id, status)?)]) + Ok(vec![SubMsg::new( + mail_client.update_msg_status(id, status)?, + )]) } else { Ok(vec![]) } } - _ => Err(ServerError::NotImplemented("Unknown message type".to_string())) + _ => Err(ServerError::NotImplemented( + "Unknown message type".to_string(), + )), } } - /// Set the target account for the message and get the mail client for the recipient -fn get_recipient_mail_client<'a>(deps: Deps<'a>, app: &'a mut ServerAdapter, recipient: &Recipient) -> ServerResult> { +fn get_recipient_mail_client<'a>( + deps: Deps<'a>, + app: &'a mut ServerAdapter, + recipient: &Recipient, +) -> ServerResult> { let account_id = recipient.resolve_account_id(app.module_registry(deps)?)?; // ANCHOR: set_acc_and_send @@ -202,9 +239,13 @@ fn get_recipient_mail_client<'a>(deps: Deps<'a>, app: &'a mut ServerAdapter, rec // ANCHOR_END: set_acc_and_send } - /// Build a message to send to a server on the destination chain -fn remote_server_msg(deps: DepsMut, module: &ServerAdapter, msg: &ServerIbcMessage, dest_chain: &TruncatedChainId) -> ServerResult { +fn remote_server_msg( + deps: DepsMut, + module: &ServerAdapter, + msg: &ServerIbcMessage, + dest_chain: &TruncatedChainId, +) -> ServerResult { // ANCHOR: ibc_client // Call IBC client let current_module_info = ModuleInfo::from_id(module.module_id(), module.version().into())?; @@ -213,7 +254,7 @@ fn remote_server_msg(deps: DepsMut, module: &ServerAdapter, msg: &ServerIbcMessa host_chain: dest_chain.clone(), target_module: current_module_info, msg: to_json_binary(msg)?, - callback: Some(Callback::new(&Empty {})?) + callback: Some(Callback::new(&Empty {})?), }; let ibc_client_addr: Addr = module @@ -225,4 +266,4 @@ fn remote_server_msg(deps: DepsMut, module: &ServerAdapter, msg: &ServerIbcMessa let msg: CosmosMsg = wasm_execute(ibc_client_addr, &ibc_client_msg, vec![])?.into(); // ANCHOR_END: ibc_client Ok(msg) -} \ No newline at end of file +} diff --git a/contracts/server/src/handlers/ibc_callback.rs b/contracts/server/src/handlers/ibc_callback.rs index 014eb70..1e80b38 100644 --- a/contracts/server/src/handlers/ibc_callback.rs +++ b/contracts/server/src/handlers/ibc_callback.rs @@ -1,12 +1,15 @@ use abstract_adapter::objects::TruncatedChainId; use abstract_adapter::std::ibc::{Callback, IbcResult}; -use cosmwasm_std::{CosmosMsg, DepsMut, Env, from_json, Response, SubMsg}; +use cosmwasm_std::{from_json, CosmosMsg, DepsMut, Env, Response, SubMsg}; -use ibcmail::{Header, DeliveryStatus, Recipient, Route, Sender, server::{msg::ServerIbcMessage, ServerAdapter}, DeliveryFailure}; -use ibcmail::server::msg::ServerMessage; -use ibcmail::server::state::AWAITING; use crate::contract::ServerResult; use crate::handlers::execute; +use ibcmail::server::msg::ServerMessage; +use ibcmail::server::state::AWAITING; +use ibcmail::{ + server::{msg::ServerIbcMessage, ServerAdapter}, + DeliveryFailure, DeliveryStatus, Header, Recipient, Route, Sender, +}; // ANCHOR: ibc_callback_handler /// Handler for message callbacks. @@ -16,38 +19,55 @@ pub fn ibc_callback_handler( _env: Env, mut app: ServerAdapter, callback: Callback, - ibc_result: IbcResult + ibc_result: IbcResult, ) -> ServerResult { // panic!("ibc_callback_handler: {:?}", callback); - println!("ibc_callback_handler callback: {:?} result, env: {:?}", callback, _env); + println!( + "ibc_callback_handler callback: {:?} result, env: {:?}", + callback, _env + ); let msgs: Vec = match ibc_result { // The destination server successfully processed the message - IbcResult::Execute { result: Ok(_response), initiator_msg } => { + IbcResult::Execute { + result: Ok(_response), + initiator_msg, + } => { println!("ibc_callback_handler execute success"); let origin_msg: ServerIbcMessage = from_json(initiator_msg)?; match origin_msg { // We successfully routed a packet, and need to send an update to the sender ServerIbcMessage::RouteMessage { msg, header } => { - println!("ibc_callback_handler success route_msg id: {:?}, header: {:?}", msg.id(), header); + println!( + "ibc_callback_handler success route_msg id: {:?}, header: {:?}", + msg.id(), + header + ); vec![] // vec![execute::update_message_status(deps, &mut app, msg.id, header, MessageStatus::Received)?] - }, + } _ => { println!("Unknown message"); vec![] - }, + } } } // The destination server failed to process the message - IbcResult::Execute { result: Err(e), initiator_msg } => { + IbcResult::Execute { + result: Err(e), + initiator_msg, + } => { println!("ibc_callback_handler execute error"); // println!("ibc_callback_handler execute error: {:?}", e); let origin_msg: ServerIbcMessage = from_json(initiator_msg)?; match origin_msg { ServerIbcMessage::RouteMessage { msg, header } => { - println!("ibc_callback_handler execute error route_msg id: {:?}, header: {:?}", msg.id(), header); + println!( + "ibc_callback_handler execute error route_msg id: {:?}, header: {:?}", + msg.id(), + header + ); match msg { ServerMessage::Mail { ref message } => { // archway juno neutron @@ -62,35 +82,44 @@ pub fn ibc_callback_handler( chains.truncate(header.current_hop as usize + 1); chains.reverse(); Route::Remote(chains) - }, - _ => Route::Local + } + _ => Route::Local, }, recipient: message.sender.clone().try_into()?, sender: Sender::Server { chain: TruncatedChainId::new(&_env), address: _env.contract.address.to_string(), - } + }, }; - execute::route_msg(deps, &mut app, ServerMessage::delivery_status(msg.id(), DeliveryFailure::Unknown(e).into()), status_header)? - }, + execute::route_msg( + deps, + &mut app, + ServerMessage::delivery_status( + msg.id(), + DeliveryFailure::Unknown(e).into(), + ), + status_header, + )? + } _ => { - println!("ibc_callback_handler execute error route_msg unknown message"); + println!( + "ibc_callback_handler execute error route_msg unknown message" + ); vec![] - }, + } } // We failed to route a message, we send a failed status update to the sender - }, + } _ => { println!("unknown message"); vec![] - }, + } } - - }, + } IbcResult::FatalError(e) => { println!("ibc_callback_handler fatal error: {:?}", e); vec![] - }, + } _ => { println!("unexpected callback result"); vec![] @@ -100,4 +129,3 @@ pub fn ibc_callback_handler( Ok(Response::default().add_submessages(msgs)) } // ANCHOR_END: ibc_callback_handler - diff --git a/contracts/server/src/handlers/instantiate.rs b/contracts/server/src/handlers/instantiate.rs index 0a499f7..1c91530 100644 --- a/contracts/server/src/handlers/instantiate.rs +++ b/contracts/server/src/handlers/instantiate.rs @@ -2,13 +2,18 @@ use abstract_adapter::sdk::AbstractResponse; use cosmwasm_std::{DepsMut, Env, MessageInfo}; use ibcmail::server::msg::ServerInstantiateMsg; -use ibcmail::server::ServerAdapter; use ibcmail::server::state::AWAITING_DELIVERY; +use ibcmail::server::ServerAdapter; use crate::contract::ServerResult; -pub fn instantiate_handler(deps: DepsMut, _env: Env, info: MessageInfo, app: ServerAdapter, _msg: ServerInstantiateMsg) -> ServerResult { - +pub fn instantiate_handler( + deps: DepsMut, + _env: Env, + info: MessageInfo, + app: ServerAdapter, + _msg: ServerInstantiateMsg, +) -> ServerResult { AWAITING_DELIVERY.save(deps.storage, &vec![])?; Ok(app.response("instantiate")) } diff --git a/contracts/server/src/handlers/mod.rs b/contracts/server/src/handlers/mod.rs index 4ea4d41..16b92d6 100644 --- a/contracts/server/src/handlers/mod.rs +++ b/contracts/server/src/handlers/mod.rs @@ -1,6 +1,9 @@ pub mod execute; -pub mod module_ibc; pub mod ibc_callback; pub mod instantiate; +pub mod module_ibc; -pub use crate::handlers::{instantiate::instantiate_handler, execute::execute_handler, module_ibc::module_ibc_handler, ibc_callback::ibc_callback_handler}; +pub use crate::handlers::{ + execute::execute_handler, ibc_callback::ibc_callback_handler, instantiate::instantiate_handler, + module_ibc::module_ibc_handler, +}; diff --git a/contracts/server/src/handlers/module_ibc.rs b/contracts/server/src/handlers/module_ibc.rs index 16d02d0..e65b9ca 100644 --- a/contracts/server/src/handlers/module_ibc.rs +++ b/contracts/server/src/handlers/module_ibc.rs @@ -1,10 +1,10 @@ use abstract_adapter::sdk::AbstractResponse; use abstract_adapter::std::ibc::ModuleIbcInfo; -use cosmwasm_std::{Binary, DepsMut, Env, from_json}; +use cosmwasm_std::{from_json, Binary, DepsMut, Env}; use ibcmail::{ - IBCMAIL_SERVER_ID, server::{error::ServerError, msg::ServerIbcMessage, ServerAdapter}, + IBCMAIL_SERVER_ID, }; use crate::{contract::ServerResult, handlers::execute::route_msg}; @@ -30,7 +30,10 @@ pub fn module_ibc_handler( let msgs = route_msg(deps, &mut app, msg, header)?; - Ok(app.response("module_ibc").add_attribute("method", "route").add_submessages(msgs)) + Ok(app + .response("module_ibc") + .add_attribute("method", "route") + .add_submessages(msgs)) } _ => Err(ServerError::UnauthorizedIbcMessage {}), } diff --git a/contracts/server/src/replies/deliver_msg.rs b/contracts/server/src/replies/deliver_msg.rs index 8c54b36..e436b6d 100644 --- a/contracts/server/src/replies/deliver_msg.rs +++ b/contracts/server/src/replies/deliver_msg.rs @@ -2,22 +2,23 @@ use abstract_adapter::objects::TruncatedChainId; use abstract_adapter::sdk::AbstractResponse; use cosmwasm_std::{DepsMut, Env, Reply, SubMsgResult}; -use ibcmail::{Header, DeliveryStatus, Sender, DeliveryFailure}; use ibcmail::server::msg::ServerMessage; -use ibcmail::server::ServerAdapter; use ibcmail::server::state::AWAITING_DELIVERY; +use ibcmail::server::ServerAdapter; +use ibcmail::{DeliveryFailure, DeliveryStatus, Header, Sender}; use crate::contract::ServerResult; use crate::handlers::execute::route_msg; -pub fn deliver_message_reply(deps: DepsMut, env: Env, mut app: ServerAdapter, reply: Reply) -> ServerResult { +pub fn deliver_message_reply( + deps: DepsMut, + env: Env, + mut app: ServerAdapter, + reply: Reply, +) -> ServerResult { let delivery_status = match reply.result { - SubMsgResult::Ok(_) => { - DeliveryStatus::Delivered - } - SubMsgResult::Err(error) => { - DeliveryFailure::Unknown(error).into() - } + SubMsgResult::Ok(_) => DeliveryStatus::Delivered, + SubMsgResult::Err(error) => DeliveryFailure::Unknown(error).into(), }; // Load the awaiting message @@ -28,7 +29,7 @@ pub fn deliver_message_reply(deps: DepsMut, env: Env, mut app: ServerAdapter, re let delivery_msg = ServerMessage::delivery_status(message_id.clone(), delivery_status); let delivery_header = origin_header.reverse(Sender::Server { address: env.contract.address.to_string(), - chain: TruncatedChainId::new(&env) + chain: TruncatedChainId::new(&env), })?; let msg = route_msg(deps, &mut app, delivery_msg, delivery_header)?; diff --git a/contracts/server/src/replies/mod.rs b/contracts/server/src/replies/mod.rs index 1475331..3e3d582 100644 --- a/contracts/server/src/replies/mod.rs +++ b/contracts/server/src/replies/mod.rs @@ -1,6 +1,6 @@ mod deliver_msg; -pub use deliver_msg::{deliver_message_reply}; +pub use deliver_msg::deliver_message_reply; pub const DELIVER_MESSAGE_REPLY: u64 = 1u64; diff --git a/packages/ibcmail/Cargo.toml b/packages/ibcmail/Cargo.toml index 81ff821..4a9f63c 100644 --- a/packages/ibcmail/Cargo.toml +++ b/packages/ibcmail/Cargo.toml @@ -19,4 +19,4 @@ thiserror = { workspace = true } cw-asset = { workspace = true } cw-controllers = { workspace = true } cw-semver = { workspace = true } -const_format = { workspace = true } \ No newline at end of file +const_format = { workspace = true } diff --git a/packages/ibcmail/src/client/api.rs b/packages/ibcmail/src/client/api.rs index 261d75c..bf3afdc 100644 --- a/packages/ibcmail/src/client/api.rs +++ b/packages/ibcmail/src/client/api.rs @@ -4,7 +4,10 @@ use abstract_app::sdk::AppInterface; use cosmwasm_std::{Addr, CosmosMsg, Deps}; -use crate::{client::msg::ClientExecuteMsg, Header, IbcMailMessage, Message, Route, IBCMAIL_CLIENT_ID, MessageHash, DeliveryStatus}; +use crate::{ + client::msg::ClientExecuteMsg, DeliveryStatus, Header, IbcMailMessage, Message, MessageHash, + Route, IBCMAIL_CLIENT_ID, +}; // API for Abstract SDK users pub trait ClientInterface: AppInterface { @@ -34,7 +37,9 @@ impl<'a, T: ClientInterface> MailClient<'a, T> { } pub fn module_address(&self) -> AbstractSdkResult { - self.base.modules(self.deps).module_address(self.module_id()) + self.base + .modules(self.deps) + .module_address(self.module_id()) } // Execute a request on the ibc mail client diff --git a/packages/ibcmail/src/client/error.rs b/packages/ibcmail/src/client/error.rs index 6ea3ea2..f93795c 100644 --- a/packages/ibcmail/src/client/error.rs +++ b/packages/ibcmail/src/client/error.rs @@ -1,9 +1,9 @@ +use crate::MessageHash; use abstract_app::{sdk::AbstractSdkError, std::AbstractError, AppError as AbstractAppError}; use cosmwasm_std::StdError; use cw_asset::AssetError; use cw_controllers::AdminError; use thiserror::Error; -use crate::MessageHash; #[derive(Error, Debug, PartialEq)] pub enum ClientError { diff --git a/packages/ibcmail/src/client/msg.rs b/packages/ibcmail/src/client/msg.rs index 1c6816b..d52171c 100644 --- a/packages/ibcmail/src/client/msg.rs +++ b/packages/ibcmail/src/client/msg.rs @@ -1,6 +1,9 @@ use cosmwasm_schema::QueryResponses; -use crate::{client::ClientApp, IbcMailMessage, Message, MessageHash, DeliveryStatus, Route, Sender, MessageKind}; +use crate::{ + client::ClientApp, DeliveryStatus, IbcMailMessage, Message, MessageHash, MessageKind, Route, + Sender, +}; // This is used for type safety and re-exporting the contract endpoint structs. abstract_app::app_msg_types!(ClientApp, ClientExecuteMsg, ClientQueryMsg); diff --git a/packages/ibcmail/src/client/state.rs b/packages/ibcmail/src/client/state.rs index 6529ccc..a8f3259 100644 --- a/packages/ibcmail/src/client/state.rs +++ b/packages/ibcmail/src/client/state.rs @@ -1,6 +1,6 @@ use cw_storage_plus::Map; -use crate::{IbcMailMessage, MessageHash, DeliveryStatus}; +use crate::{DeliveryStatus, IbcMailMessage, MessageHash}; // TODO: use an indexed map in the future pub const RECEIVED: Map = Map::new("received"); @@ -8,4 +8,4 @@ pub const SENT: Map = Map::new("sent"); pub const STATUS: Map = Map::new("status"); /// Set of features supported by the client -pub const FEATURES: Map = Map::new("features"); \ No newline at end of file +pub const FEATURES: Map = Map::new("features"); diff --git a/packages/ibcmail/src/features.rs b/packages/ibcmail/src/features.rs index 01e642d..98c9cbe 100644 --- a/packages/ibcmail/src/features.rs +++ b/packages/ibcmail/src/features.rs @@ -1 +1 @@ -pub const DELIVERY_STATUS_FEATURE: &str = "delivery"; \ No newline at end of file +pub const DELIVERY_STATUS_FEATURE: &str = "delivery"; diff --git a/packages/ibcmail/src/lib.rs b/packages/ibcmail/src/lib.rs index cdc8f1d..ed5ec7e 100644 --- a/packages/ibcmail/src/lib.rs +++ b/packages/ibcmail/src/lib.rs @@ -1,9 +1,8 @@ pub mod client; -pub mod server; pub mod features; +pub mod server; -use std::fmt; -use std::fmt::{Display, Formatter}; +use crate::server::error::ServerError; use abstract_adapter::sdk::ModuleRegistryInterface; use abstract_adapter::std::version_control::NamespaceResponse; use abstract_app::objects::TruncatedChainId; @@ -12,8 +11,9 @@ use abstract_app::std::objects::AccountId; use abstract_app::std::objects::{account::AccountTrace, namespace::Namespace}; use const_format::concatcp; use cosmwasm_std::{Addr, StdError, StdResult, Timestamp}; +use std::fmt; +use std::fmt::{Display, Formatter}; use thiserror::Error; -use crate::server::error::ServerError; pub const IBCMAIL_NAMESPACE: &str = "ibcmail"; pub const IBCMAIL_CLIENT_ID: &str = concatcp!(IBCMAIL_NAMESPACE, ":", "client"); @@ -73,7 +73,7 @@ impl Header { current_hop: 0, route: reverse_route, recipient: self.sender.clone().try_into()?, - sender + sender, }) } } @@ -117,8 +117,11 @@ impl Recipient { Recipient::Namespace { namespace, chain } } - pub fn resolve_account_id(&self, module_registry: ModuleRegistry) -> Result { - Ok(match self { + pub fn resolve_account_id( + &self, + module_registry: ModuleRegistry, + ) -> Result { + Ok(match self { Recipient::Account { id: account_id, .. } => Ok(account_id.clone()), Recipient::Namespace { namespace, .. } => { // TODO: this only allows for addressing recipients via namespace of their email account directly. @@ -149,7 +152,7 @@ pub enum Sender { chain: TruncatedChainId, // String because it's a different chain address: String, - } + }, } impl Sender { @@ -179,7 +182,6 @@ pub enum MessageKind { Received, } - impl Display for MessageKind { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { @@ -199,7 +201,6 @@ pub enum DeliveryFailure { Unknown(String), } - #[non_exhaustive] #[cosmwasm_schema::cw_serde] pub enum DeliveryStatus { @@ -222,4 +223,4 @@ impl Display for DeliveryStatus { DeliveryStatus::Failure(failure) => write!(f, "Failed: {}", failure), } } -} \ No newline at end of file +} diff --git a/packages/ibcmail/src/server/error.rs b/packages/ibcmail/src/server/error.rs index d760afa..373bd2a 100644 --- a/packages/ibcmail/src/server/error.rs +++ b/packages/ibcmail/src/server/error.rs @@ -1,3 +1,4 @@ +use crate::MessageHash; use abstract_adapter::std::ibc::ModuleIbcInfo; use abstract_adapter::{ sdk::AbstractSdkError, std::AbstractError, AdapterError as AbstractAdapterError, @@ -7,7 +8,6 @@ use cosmwasm_std::StdError; use cw_asset::AssetError; use cw_controllers::AdminError; use thiserror::Error; -use crate::MessageHash; #[derive(Error, Debug, PartialEq)] pub enum ServerError { diff --git a/packages/ibcmail/src/server/msg.rs b/packages/ibcmail/src/server/msg.rs index 211d451..2e6ccfb 100644 --- a/packages/ibcmail/src/server/msg.rs +++ b/packages/ibcmail/src/server/msg.rs @@ -1,6 +1,6 @@ use cosmwasm_schema::QueryResponses; -use crate::{server::ServerAdapter, Header, IbcMailMessage, Route, MessageHash, DeliveryStatus}; +use crate::{server::ServerAdapter, DeliveryStatus, Header, IbcMailMessage, MessageHash, Route}; // This is used for type safety and re-exporting the contract endpoint structs. abstract_adapter::adapter_msg_types!(ServerAdapter, ServerExecuteMsg, ServerQueryMsg); @@ -28,7 +28,7 @@ pub enum ServerMessage { DeliveryStatus { id: MessageHash, status: DeliveryStatus, - } + }, } impl ServerMessage { @@ -61,7 +61,11 @@ pub enum ServerIbcMessage { #[cosmwasm_schema::cw_serde] pub enum ServerCallbackMessage { /// Update a message - UpdateMessage { id: MessageHash, header: Header, status: DeliveryStatus }, + UpdateMessage { + id: MessageHash, + header: Header, + status: DeliveryStatus, + }, } /// App query messages diff --git a/packages/ibcmail/src/server/state.rs b/packages/ibcmail/src/server/state.rs index b4ad5e5..d956dbc 100644 --- a/packages/ibcmail/src/server/state.rs +++ b/packages/ibcmail/src/server/state.rs @@ -1,6 +1,6 @@ +use crate::{Header, Message, MessageHash}; use abstract_app::objects::TruncatedChainId; use cw_storage_plus::{Item, Map}; -use crate::{Header, Message, MessageHash}; pub const AWAITING: Map<&MessageHash, TruncatedChainId> = Map::new("awaiting"); -pub const AWAITING_DELIVERY: Item> = Item::new("awaiting_delivery"); \ No newline at end of file +pub const AWAITING_DELIVERY: Item> = Item::new("awaiting_delivery"); diff --git a/tests/src/bin/approve.rs b/tests/src/bin/approve.rs index 1977c60..6baa0fd 100644 --- a/tests/src/bin/approve.rs +++ b/tests/src/bin/approve.rs @@ -14,7 +14,7 @@ use clap::Parser; use cw_orch::{ anyhow, environment::TxHandler, - prelude::{*, DaemonBuilder, networks::parse_network}, + prelude::{networks::parse_network, DaemonBuilder, *}, tokio::runtime::Runtime, }; @@ -32,7 +32,8 @@ fn publish(networks: Vec) -> anyhow::Result<()> { // Create an [`AbstractClient`] let abs = Abstract::new(chain.clone()); - abs.version_control.approve_all_modules_for_namespace(app_namespace)?; + abs.version_control + .approve_all_modules_for_namespace(app_namespace)?; } Ok(()) } diff --git a/tests/src/bin/full_demo.rs b/tests/src/bin/full_demo.rs index 141b06f..6e900dd 100644 --- a/tests/src/bin/full_demo.rs +++ b/tests/src/bin/full_demo.rs @@ -8,8 +8,8 @@ use abstract_app::{ }, std::{ ibc_client::QueryMsgFns as IbcQueryFns, - IBC_HOST, version_control::{ExecuteMsgFns, ModuleFilter, QueryMsgFns}, + IBC_HOST, }, }; use abstract_client::AbstractClient; @@ -21,7 +21,7 @@ use cw_orch_interchain::{ChannelCreationValidator, DaemonInterchainEnv, Intercha use networks::{HARPOON_4, PION_1}; use client::ClientInterface; -use ibcmail::{client::msg::ClientExecuteMsgFns, IBCMAIL_NAMESPACE, Message}; +use ibcmail::{client::msg::ClientExecuteMsgFns, Message, IBCMAIL_NAMESPACE}; use tests::TEST_NAMESPACE; const SRC: ChainInfo = HARPOON_4; diff --git a/tests/src/client.rs b/tests/src/client.rs index 25cee9d..8894505 100644 --- a/tests/src/client.rs +++ b/tests/src/client.rs @@ -1,13 +1,13 @@ -use abstract_app::objects::{AccountId, namespace::Namespace}; +use abstract_app::objects::{namespace::Namespace, AccountId}; use abstract_client::{AbstractClient, Application, Environment}; use cw_orch::{anyhow, prelude::*}; use speculoos::prelude::*; // Use prelude to get all the necessary imports -use client::{*, contract::interface::ClientInterface, msg::ClientInstantiateMsg}; +use client::{contract::interface::ClientInterface, msg::ClientInstantiateMsg, *}; use ibcmail::{ - IBCMAIL_NAMESPACE, IBCMAIL_SERVER_ID, IbcMailMessage, Message, Recipient, - Sender, server::msg::ServerInstantiateMsg, + server::msg::ServerInstantiateMsg, IbcMailMessage, Message, Recipient, Sender, + IBCMAIL_NAMESPACE, IBCMAIL_SERVER_ID, }; use server::ServerInterface; @@ -88,7 +88,7 @@ fn create_test_message(from: AccountId, to: AccountId) -> IbcMailMessage { mod receive_msg { use speculoos::assert_that; - use ibcmail::{IBCMAIL_SERVER_ID, MessageKind}; + use ibcmail::{MessageKind, IBCMAIL_SERVER_ID}; use super::*; @@ -151,13 +151,13 @@ mod receive_msg { mod send_msg { use std::str::FromStr; - use abstract_app::{objects::account::AccountTrace, std::version_control::ExecuteMsgFns}; use abstract_app::objects::TruncatedChainId; + use abstract_app::{objects::account::AccountTrace, std::version_control::ExecuteMsgFns}; use abstract_cw_orch_polytone::{Polytone, PolytoneConnection}; use abstract_interface::Abstract; use cw_orch_interchain::{InterchainEnv, MockBech32InterchainEnv}; - use ibcmail::{IBCMAIL_CLIENT_ID, Message, Route, server::error::ServerError, MessageKind}; + use ibcmail::{server::error::ServerError, Message, MessageKind, Route, IBCMAIL_CLIENT_ID}; use super::*; @@ -199,7 +199,9 @@ mod send_msg { let res = client1.send_message(msg, None); assert_that!(res).is_ok(); - let received_messages = client2.list_messages(MessageKind::Received, None, None, None)?.messages; + let received_messages = client2 + .list_messages(MessageKind::Received, None, None, None)? + .messages; assert_that!(received_messages).has_length(1); Ok(()) @@ -260,13 +262,8 @@ mod send_msg { #[test] fn can_send_remote_message() -> anyhow::Result<()> { // Create a sender and mock env - let interchain = MockBech32InterchainEnv::new(vec![ - ("juno-1", "juno"), - ( - "archway-1", - "archway", - ), - ]); + let interchain = + MockBech32InterchainEnv::new(vec![("juno-1", "juno"), ("archway-1", "archway")]); // /Users/adair/.cargo/registry/src/index.crates.io-6f17d22bba15001f/cw-orch-mock-0.22.0/src/queriers/env.rs:12:70: // index out of bounds: the len is 1 but the index is 1 (when initializing with "juno") @@ -340,13 +337,8 @@ mod send_msg { #[test] fn send_remote_message_1_hop_account_dne_updates_status_to_failed() -> anyhow::Result<()> { // Create a sender and mock env - let interchain = MockBech32InterchainEnv::new(vec![ - ("juno-1", "juno"), - ( - "archway-1", - "archway", - ), - ]); + let interchain = + MockBech32InterchainEnv::new(vec![("juno-1", "juno"), ("archway-1", "archway")]); // /Users/adair/.cargo/registry/src/index.crates.io-6f17d22bba15001f/cw-orch-mock-0.22.0/src/queriers/env.rs:12:70: // index out of bounds: the len is 1 but the index is 1 (when initializing with "juno") @@ -368,7 +360,12 @@ mod send_msg { "test-body", ); - let res = arch_client.send_message(arch_to_juno_msg, Some(Route::Remote(vec![TruncatedChainId::from_string("juno".into())?]))); + let res = arch_client.send_message( + arch_to_juno_msg, + Some(Route::Remote(vec![TruncatedChainId::from_string( + "juno".into(), + )?])), + ); assert_that!(res).is_ok(); @@ -376,16 +373,23 @@ mod send_msg { println!("server: {:?}", server.address()?); let abstr = Abstract::new(arch_env.env.clone()); println!("ibc_host: {:?}", abstr.ibc.host.address()?); - let poly = PolytoneConnection::load_from( - arch_env.env.clone(), - juno_env.env.clone(), - ); + let poly = PolytoneConnection::load_from(arch_env.env.clone(), juno_env.env.clone()); println!("poly_note: {:?}", poly.note.address()?); let packets = interchain.await_packets("archway-1", res?)?; - assert_that!(arch_client.list_messages(MessageKind::Received, None, None, None)?.messages).is_empty(); - assert_that!(juno_client.list_messages(MessageKind::Received, None, None, None)?.messages).is_empty(); + assert_that!( + arch_client + .list_messages(MessageKind::Received, None, None, None)? + .messages + ) + .is_empty(); + assert_that!( + juno_client + .list_messages(MessageKind::Received, None, None, None)? + .messages + ) + .is_empty(); // interchain.await_packets("archway-1", res?)?; // println!("packets: {:?}", packets); @@ -398,14 +402,8 @@ mod send_msg { // Create a sender and mock env let interchain = MockBech32InterchainEnv::new(vec![ ("juno-1", "juno"), - ( - "archway-1", - "archway", - ), - ( - "neutron-1", - "neutron", - ), + ("archway-1", "archway"), + ("neutron-1", "neutron"), ]); // /Users/adair/.cargo/registry/src/index.crates.io-6f17d22bba15001f/cw-orch-mock-0.22.0/src/queriers/env.rs:12:70: diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 3ebb49e..8fd0181 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -1,4 +1,4 @@ #[cfg(test)] mod client; -pub const TEST_NAMESPACE: &str = "ibcmail-demo"; \ No newline at end of file +pub const TEST_NAMESPACE: &str = "ibcmail-demo"; From ce5f5bce140351a2fd0e0f01c70879280b559c10 Mon Sep 17 00:00:00 2001 From: adairrr <32375605+adairrr@users.noreply.github.com> Date: Sun, 4 Aug 2024 20:55:39 +0200 Subject: [PATCH 06/12] Update the header to be more sensical without current hop --- Cargo.toml | 14 ++-- contracts/client/src/dependencies.rs | 2 +- contracts/client/src/handlers/execute.rs | 30 ++++---- contracts/server/src/handlers/execute.rs | 30 ++++---- contracts/server/src/handlers/ibc_callback.rs | 33 +++++---- contracts/server/src/handlers/module_ibc.rs | 7 +- contracts/server/src/replies/deliver_msg.rs | 3 +- packages/ibcmail/src/client/api.rs | 13 ++-- packages/ibcmail/src/client/msg.rs | 11 +-- packages/ibcmail/src/lib.rs | 30 ++++++-- tests/Cargo.toml | 7 +- tests/src/bin/demo.rs | 3 +- tests/src/bin/full_demo.rs | 4 +- tests/src/client.rs | 72 ++++++++++--------- 14 files changed, 147 insertions(+), 112 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0d564c3..8a7e76b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = ["contracts/*", "packages/ibcmail", "tests"] resolver = "2" [workspace.package] -version = "0.2.0" +version = "0.3.0" [workspace.dependencies] cosmwasm-std = "1.5.3" @@ -21,14 +21,16 @@ cw-orch = "0.24.1" ibcmail = { path = "packages/ibcmail", package = "ibcmail" } client = { path = "contracts/client", package = "ibcmail-client" } server = { path = "contracts/server", package = "ibcmail-server" } -abstract-client = "0.23.0" -abstract-app = "0.23.0" -abstract-adapter = "0.23.0" -abstract-interface = "0.23.0" + +abstract-client = "=0.23.0" +abstract-app = "=0.23.0" +abstract-adapter = "=0.23.0" +abstract-interface = "0.23.1" + speculoos = "0.11.0" semver = "1.0" dotenv = "0.15.0" -env_logger = "0.10.0" +env_logger = "0.11.3" clap = "4.3.7" const_format = "0.2.32" diff --git a/contracts/client/src/dependencies.rs b/contracts/client/src/dependencies.rs index 7efe75e..a3cc4d2 100644 --- a/contracts/client/src/dependencies.rs +++ b/contracts/client/src/dependencies.rs @@ -4,7 +4,7 @@ use abstract_app::{objects::module::ModuleInfo, std::manager::ModuleInstallConfi use ibcmail::IBCMAIL_SERVER_ID; pub const MAIL_SERVER_DEP: StaticDependency = - StaticDependency::new(IBCMAIL_SERVER_ID, &[">=0.0.1"]); + StaticDependency::new(IBCMAIL_SERVER_ID, &[">=0.3.0"]); #[cfg(feature = "interface")] impl abstract_app::abstract_interface::DependencyCreation diff --git a/contracts/client/src/handlers/execute.rs b/contracts/client/src/handlers/execute.rs index 6210f91..c3c8864 100644 --- a/contracts/client/src/handlers/execute.rs +++ b/contracts/client/src/handlers/execute.rs @@ -11,15 +11,10 @@ use abstract_app::{ use base64::prelude::*; use cosmwasm_std::{ensure_eq, Addr, CosmosMsg, Deps, DepsMut, Env, MessageInfo}; use ibcmail::client::state::STATUS; -use ibcmail::{ - client::{ - state::{RECEIVED, SENT}, - ClientApp, - }, - server::api::{MailServer, ServerInterface}, - DeliveryStatus, IbcMailMessage, Message, MessageHash, Recipient, Route, Sender, - IBCMAIL_SERVER_ID, -}; +use ibcmail::{client::{ + state::{RECEIVED, SENT}, + ClientApp, +}, server::api::{MailServer, ServerInterface}, DeliveryStatus, IbcMailMessage, Message, MessageHash, Recipient, Route, Sender, IBCMAIL_SERVER_ID, Header}; // # ANCHOR: execute_handler pub fn execute_handler( @@ -30,10 +25,10 @@ pub fn execute_handler( msg: ClientExecuteMsg, ) -> ClientResult { match msg { - ClientExecuteMsg::SendMessage { message, route } => { - send_msg(deps, env, info, message, route, app) + ClientExecuteMsg::SendMessage { message, recipient, route } => { + send_msg(deps, env, info, app, message, recipient, route) } - ClientExecuteMsg::ReceiveMessage(message) => receive_msg(deps, info, app, message), + ClientExecuteMsg::ReceiveMessage { message, header } => receive_msg(deps, info, app, message, header), ClientExecuteMsg::UpdateDeliveryStatus { id, status } => { update_delivery_status(deps, info, app, id, status) } @@ -46,12 +41,13 @@ fn send_msg( deps: DepsMut, env: Env, _info: MessageInfo, + app: ClientApp, msg: Message, + recipient: Recipient, route: Option, - app: ClientApp, ) -> ClientResult { // validate basic fields of message, construct message to send to server - let to_hash = format!("{:?}{:?}{:?}", env.block.time, msg.subject, msg.recipient); + let to_hash = format!("{:?}{:?}{:?}", env.block.time, msg.subject, recipient); let hash = ::digest(to_hash); let base_64_hash = BASE64_STANDARD.encode(hash); let to_send = IbcMailMessage { @@ -60,8 +56,8 @@ fn send_msg( app.account_id(deps.as_ref()).unwrap(), Some(TruncatedChainId::new(&env)), ), + recipient, message: Message { - recipient: msg.recipient, subject: msg.subject, body: msg.body, }, @@ -80,9 +76,9 @@ fn send_msg( /// Receive a message from the server // # ANCHOR: receive_msg -fn receive_msg(deps: DepsMut, info: MessageInfo, app: App, msg: IbcMailMessage) -> ClientResult { +fn receive_msg(deps: DepsMut, info: MessageInfo, app: App, msg: IbcMailMessage, header: Header) -> ClientResult { ensure_server_sender(deps.as_ref(), &app, info.sender)?; - ensure_correct_recipient(deps.as_ref(), &msg.message.recipient, &app)?; + ensure_correct_recipient(deps.as_ref(), &header.recipient, &app)?; RECEIVED.save(deps.storage, msg.id.clone(), &msg)?; diff --git a/contracts/server/src/handlers/execute.rs b/contracts/server/src/handlers/execute.rs index b60e355..a205c6d 100644 --- a/contracts/server/src/handlers/execute.rs +++ b/contracts/server/src/handlers/execute.rs @@ -81,20 +81,20 @@ fn process_message( Route::Remote(chains) } } else { - chains.insert(0, current_chain); + chains.insert(0, current_chain.clone()); Route::Remote(chains) } } }) } else { - println!("processing message recipient: {:?}", msg.message.recipient); - match msg.message.recipient.clone() { + println!("processing message recipient: {:?}", msg.recipient); + match msg.recipient.clone() { // TODO: add smarter routing Recipient::Account { id: _, chain } => Ok(chain.map_or(AccountTrace::Local, |chain| { if chain == current_chain { AccountTrace::Local } else { - AccountTrace::Remote(vec![current_chain, chain.clone()]) + AccountTrace::Remote(vec![current_chain.clone(), chain.clone()]) } })), Recipient::Namespace { @@ -104,7 +104,7 @@ fn process_message( if chain == current_chain { AccountTrace::Local } else { - AccountTrace::Remote(vec![current_chain, chain.clone()]) + AccountTrace::Remote(vec![current_chain.clone(), chain.clone()]) } })), _ => { @@ -116,31 +116,37 @@ fn process_message( }?; let header = Header { - current_hop: 0, + route, - recipient: msg.message.recipient.clone(), + recipient: msg.recipient.clone(), + id: msg.id.clone(), + version: msg.version.clone(), sender, + timestamp: msg.timestamp.clone() }; - let msgs = route_msg(deps, &mut app, ServerMessage::mail(msg), header)?; + let msgs = route_msg(deps, ¤t_chain, &mut app, header, ServerMessage::mail(msg))?; Ok(app.response("route").add_submessages(msgs)) } pub(crate) fn route_msg( deps: DepsMut, + current_chain: &TruncatedChainId, app: &mut ServerAdapter, - msg: ServerMessage, header: Header, + msg: ServerMessage, ) -> ServerResult> { println!("routing message: {:?}, metadata: {:?}", msg, header); + let current_hop = header.current_hop(current_chain)?; + match header.route { AccountTrace::Local => route_to_local_account(deps, app, msg, header), AccountTrace::Remote(ref chains) => { println!("routing to chains: {:?}", chains); // check index of hop. If we are on the final hop, route to local account - if header.current_hop == (chains.len() - 1) as u32 { + if current_hop == (chains.len() - 1) as u32 { println!("routing to local account: {:?}", chains.last().unwrap()); return route_to_local_account(deps, app, msg.clone(), header); } @@ -148,10 +154,10 @@ pub(crate) fn route_msg( let dest_chain = chains - .get(header.current_hop as usize + 1) + .get(current_hop as usize + 1) .ok_or(ServerError::InvalidRoute { route: header.route.clone(), - hop: header.current_hop, + hop: current_hop, })?; // Awaiting callback diff --git a/contracts/server/src/handlers/ibc_callback.rs b/contracts/server/src/handlers/ibc_callback.rs index 1e80b38..17b59bd 100644 --- a/contracts/server/src/handlers/ibc_callback.rs +++ b/contracts/server/src/handlers/ibc_callback.rs @@ -1,15 +1,15 @@ use abstract_adapter::objects::TruncatedChainId; use abstract_adapter::std::ibc::{Callback, IbcResult}; -use cosmwasm_std::{from_json, CosmosMsg, DepsMut, Env, Response, SubMsg}; +use cosmwasm_std::{DepsMut, Env, from_json, Response, SubMsg}; -use crate::contract::ServerResult; -use crate::handlers::execute; -use ibcmail::server::msg::ServerMessage; -use ibcmail::server::state::AWAITING; use ibcmail::{ - server::{msg::ServerIbcMessage, ServerAdapter}, - DeliveryFailure, DeliveryStatus, Header, Recipient, Route, Sender, + DeliveryFailure, + Header, Route, Sender, server::{msg::ServerIbcMessage, ServerAdapter}, }; +use ibcmail::server::msg::ServerMessage; + +use crate::contract::ServerResult; +use crate::handlers::execute; // ANCHOR: ibc_callback_handler /// Handler for message callbacks. @@ -68,37 +68,46 @@ pub fn ibc_callback_handler( msg.id(), header ); + let current_chain = TruncatedChainId::new(&_env); + let current_hop = header.current_hop(¤t_chain)?; match msg { + // We failed to deliver a message, we send a failed status update to the sender ServerMessage::Mail { ref message } => { // archway juno neutron // juno -> neutron failed current hop 1 // expected: juno archway // need to remove anything after the current hop let status_header = Header { - current_hop: 0, + route: match header.route { Route::Remote(mut chains) => { // keep the current hop but remove everything after it - chains.truncate(header.current_hop as usize + 1); + chains.truncate(current_hop as usize + 1); chains.reverse(); Route::Remote(chains) } _ => Route::Local, }, - recipient: message.sender.clone().try_into()?, sender: Sender::Server { - chain: TruncatedChainId::new(&_env), + chain: current_chain.clone(), address: _env.contract.address.to_string(), }, + recipient: message.sender.clone().try_into()?, + // TODO: new message id + id: message.id.clone(), + version: message.version.clone(), + timestamp: _env.block.time, }; + execute::route_msg( deps, + ¤t_chain, &mut app, + status_header, ServerMessage::delivery_status( msg.id(), DeliveryFailure::Unknown(e).into(), ), - status_header, )? } _ => { diff --git a/contracts/server/src/handlers/module_ibc.rs b/contracts/server/src/handlers/module_ibc.rs index e65b9ca..5caeccc 100644 --- a/contracts/server/src/handlers/module_ibc.rs +++ b/contracts/server/src/handlers/module_ibc.rs @@ -1,3 +1,4 @@ +use abstract_adapter::objects::TruncatedChainId; use abstract_adapter::sdk::AbstractResponse; use abstract_adapter::std::ibc::ModuleIbcInfo; use cosmwasm_std::{from_json, Binary, DepsMut, Env}; @@ -12,7 +13,7 @@ use crate::{contract::ServerResult, handlers::execute::route_msg}; // ANCHOR: module_ibc_handler pub fn module_ibc_handler( deps: DepsMut, - _env: Env, + env: Env, mut app: ServerAdapter, module_info: ModuleIbcInfo, msg: Binary, @@ -26,9 +27,7 @@ pub fn module_ibc_handler( match server_msg { ServerIbcMessage::RouteMessage { msg, mut header } => { - header.current_hop += 1; - - let msgs = route_msg(deps, &mut app, msg, header)?; + let msgs = route_msg(deps, &TruncatedChainId::new(&env), &mut app, header, msg)?; Ok(app .response("module_ibc") diff --git a/contracts/server/src/replies/deliver_msg.rs b/contracts/server/src/replies/deliver_msg.rs index e436b6d..39abe87 100644 --- a/contracts/server/src/replies/deliver_msg.rs +++ b/contracts/server/src/replies/deliver_msg.rs @@ -16,6 +16,7 @@ pub fn deliver_message_reply( mut app: ServerAdapter, reply: Reply, ) -> ServerResult { + let current_chain = TruncatedChainId::new(&env); let delivery_status = match reply.result { SubMsgResult::Ok(_) => DeliveryStatus::Delivered, SubMsgResult::Err(error) => DeliveryFailure::Unknown(error).into(), @@ -32,7 +33,7 @@ pub fn deliver_message_reply( chain: TruncatedChainId::new(&env), })?; - let msg = route_msg(deps, &mut app, delivery_msg, delivery_header)?; + let msg = route_msg(deps, ¤t_chain, &mut app, delivery_header, delivery_msg)?; Ok(app .response("deliver_message_reply") diff --git a/packages/ibcmail/src/client/api.rs b/packages/ibcmail/src/client/api.rs index bf3afdc..42754d0 100644 --- a/packages/ibcmail/src/client/api.rs +++ b/packages/ibcmail/src/client/api.rs @@ -4,10 +4,7 @@ use abstract_app::sdk::AppInterface; use cosmwasm_std::{Addr, CosmosMsg, Deps}; -use crate::{ - client::msg::ClientExecuteMsg, DeliveryStatus, Header, IbcMailMessage, Message, MessageHash, - Route, IBCMAIL_CLIENT_ID, -}; +use crate::{client::msg::ClientExecuteMsg, DeliveryStatus, Header, IbcMailMessage, Message, MessageHash, Route, IBCMAIL_CLIENT_ID, Recipient}; // API for Abstract SDK users pub trait ClientInterface: AppInterface { @@ -49,17 +46,17 @@ impl<'a, T: ClientInterface> MailClient<'a, T> { } /// Send message - pub fn send_msg(&self, message: Message, route: Option) -> AbstractSdkResult { - self.request(ClientExecuteMsg::SendMessage { message, route }) + pub fn send_msg(&self, recipient: Recipient, message: Message, route: Option) -> AbstractSdkResult { + self.request(ClientExecuteMsg::SendMessage { recipient, message, route }) } /// Receive message pub fn receive_msg( &self, message: IbcMailMessage, - _header: Header, + header: Header, ) -> AbstractSdkResult { - self.request(ClientExecuteMsg::ReceiveMessage(message)) + self.request(ClientExecuteMsg::ReceiveMessage { message, header }) } /// Receive message diff --git a/packages/ibcmail/src/client/msg.rs b/packages/ibcmail/src/client/msg.rs index d52171c..e468e1b 100644 --- a/packages/ibcmail/src/client/msg.rs +++ b/packages/ibcmail/src/client/msg.rs @@ -1,9 +1,6 @@ use cosmwasm_schema::QueryResponses; -use crate::{ - client::ClientApp, DeliveryStatus, IbcMailMessage, Message, MessageHash, MessageKind, Route, - Sender, -}; +use crate::{client::ClientApp, DeliveryStatus, Header, IbcMailMessage, Message, MessageHash, MessageKind, Recipient, Route, Sender}; // This is used for type safety and re-exporting the contract endpoint structs. abstract_app::app_msg_types!(ClientApp, ClientExecuteMsg, ClientQueryMsg); @@ -19,7 +16,10 @@ pub struct ClientInstantiateMsg {} #[cw_orch(impl_into(ExecuteMsg))] pub enum ClientExecuteMsg { /// Receive a message from the server. - ReceiveMessage(IbcMailMessage), + ReceiveMessage { + header: Header, + message: IbcMailMessage + }, /// Update the status of a message. only callable by the server UpdateDeliveryStatus { id: MessageHash, @@ -27,6 +27,7 @@ pub enum ClientExecuteMsg { }, /// Send a message SendMessage { + recipient: Recipient, message: Message, route: Option, }, diff --git a/packages/ibcmail/src/lib.rs b/packages/ibcmail/src/lib.rs index ed5ec7e..6b66349 100644 --- a/packages/ibcmail/src/lib.rs +++ b/packages/ibcmail/src/lib.rs @@ -27,16 +27,14 @@ pub type MessageHash = String; // # ANCHOR: message #[cosmwasm_schema::cw_serde] pub struct Message { - pub recipient: Recipient, pub subject: String, pub body: String, } // # ANCHOR_END: message impl Message { - pub fn new(recipient: Recipient, subject: impl Into, body: impl Into) -> Self { + pub fn new(subject: impl Into, body: impl Into) -> Self { Self { - recipient, subject: subject.into(), body: body.into(), } @@ -47,6 +45,7 @@ impl Message { pub struct IbcMailMessage { pub id: MessageHash, pub sender: Sender, + pub recipient: Recipient, pub version: String, pub timestamp: Timestamp, pub message: Message, @@ -54,10 +53,13 @@ pub struct IbcMailMessage { #[cosmwasm_schema::cw_serde] pub struct Header { - pub current_hop: u32, + // TODO: remove current hop pub route: Route, - pub recipient: Recipient, pub sender: Sender, + pub recipient: Recipient, + pub id: MessageHash, + pub version: String, + pub timestamp: Timestamp } impl Header { @@ -70,12 +72,28 @@ impl Header { Route::Local => Route::Local, }; Ok(Header { - current_hop: 0, + route: reverse_route, recipient: self.sender.clone().try_into()?, sender, + id: self.id, + version: self.version, + timestamp: self.timestamp, }) } + + pub fn current_hop(&self, current_chain: &TruncatedChainId) -> StdResult { + match self.route { + Route::Local => Ok(0), + Route::Remote(ref route) => { + let position = route.iter().position(|chain| chain == current_chain); + match position { + Some(position) => Ok(position as u32), + None => Err(StdError::generic_err("Current chain not in route")) + } + } + } + } } pub type Route = AccountTrace; diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 2bb32c9..744a24e 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -15,7 +15,7 @@ default = [] abstract-app = { workspace = true, features = ["test-utils"] } abstract-cw-orch-polytone = "4.0.1" abstract-interface = { workspace = true } -abstract-interchain-tests = { git = "https://github.com/AbstractSDK/abstract", version = "0.23.0", tag = "v0.23.0" } +#abstract-interchain-tests = { git = "https://github.com/AbstractSDK/abstract", version = "=0.23.0", tag = "v0.23.0" } #abstract-interchain-tests = { git = "https://github.com/AbstractSDK/abstract", version = "0.22.1", branch = "removemm" } #cw-orch = { workspace = true } cw-orch-interchain = { version = "0.3.1", features = ["daemon"] } @@ -30,7 +30,8 @@ client = { workspace = true, features = ["interface"] } speculoos = { workspace = true } server = { workspace = true, features = ["interface"] } abstract-client = { workspace = true, features = ["interchain"] } -clap.workspace = true -env_logger = "0.11.3" +clap = { workspace = true , features = ["derive"]} dotenv = { workspace = true } + +env_logger ={ workspace = true } anyhow = "1.0.86" diff --git a/tests/src/bin/demo.rs b/tests/src/bin/demo.rs index f2e6712..b28ae82 100644 --- a/tests/src/bin/demo.rs +++ b/tests/src/bin/demo.rs @@ -39,10 +39,11 @@ fn test() -> anyhow::Result<()> { .namespace(Namespace::new(TEST_NAMESPACE)?) .build()?; - let mail_msg = Message::new(dst_acc.id()?.into(), "test-subject", "test-body"); + let mail_msg = Message::new("test-subject", "test-body"); let send = src_client.send_message( mail_msg, + dst_acc.id()?.into(), Some(AccountTrace::Remote(vec![TruncatedChainId::from_chain_id( DST.chain_id, )])), diff --git a/tests/src/bin/full_demo.rs b/tests/src/bin/full_demo.rs index 6e900dd..0bc0182 100644 --- a/tests/src/bin/full_demo.rs +++ b/tests/src/bin/full_demo.rs @@ -100,7 +100,8 @@ fn test() -> anyhow::Result<()> { // )?; let send = dst_client.send_message( - Message::new(src_acc.id()?.into(), "test-subject", "test-body"), + Message::new("test-subject", "test-body"), + src_acc.id()?.into(), Some(AccountTrace::Remote(vec![TruncatedChainId::from_chain_id( SRC.chain_id, )])), @@ -158,6 +159,7 @@ pub fn approve_mail_modules(vc: &VersionControl) -> anyhow::Res Ok(()) } + #[derive(Parser, Default, Debug)] #[command(author, version, about, long_about = None)] struct Arguments {} diff --git a/tests/src/client.rs b/tests/src/client.rs index 8894505..f24b311 100644 --- a/tests/src/client.rs +++ b/tests/src/client.rs @@ -5,10 +5,7 @@ use speculoos::prelude::*; // Use prelude to get all the necessary imports use client::{contract::interface::ClientInterface, msg::ClientInstantiateMsg, *}; -use ibcmail::{ - server::msg::ServerInstantiateMsg, IbcMailMessage, Message, Recipient, Sender, - IBCMAIL_NAMESPACE, IBCMAIL_SERVER_ID, -}; +use ibcmail::{server::msg::ServerInstantiateMsg, IbcMailMessage, Message, Recipient, Sender, IBCMAIL_NAMESPACE, IBCMAIL_SERVER_ID, MessageKind, Header, Route}; use server::ServerInterface; struct TestEnv { @@ -71,12 +68,12 @@ impl TestEnv { } } -fn create_test_message(from: AccountId, to: AccountId) -> IbcMailMessage { +fn create_server_test_msg(from: AccountId, to: AccountId) -> IbcMailMessage { IbcMailMessage { id: "test-id".to_string(), sender: Sender::account(from.clone(), None), + recipient: Recipient::account(to.clone(), None), message: Message { - recipient: Recipient::account(to.clone(), None), subject: "test-subject".to_string(), body: "test-body".to_string(), }, @@ -85,6 +82,18 @@ fn create_test_message(from: AccountId, to: AccountId) -> IbcMailMessage { } } +fn temp_ibc_mail_msg_to_header(msg: IbcMailMessage, route: Route) -> Header { + Header { + + route, + recipient: msg.recipient.clone(), + id: msg.id.clone(), + version: msg.version.clone(), + sender: msg.sender.clone(), + timestamp: msg.timestamp.clone(), + } +} + mod receive_msg { use speculoos::assert_that; @@ -109,7 +118,7 @@ mod receive_msg { server_account_id, app_account_id ); - let msg = create_test_message(server_account_id.clone(), app_account_id.clone()); + let msg = create_server_test_msg(server_account_id.clone(), app_account_id.clone()); let server_addr = app .account() .module_addresses(vec![IBCMAIL_SERVER_ID.into()])? @@ -118,7 +127,7 @@ mod receive_msg { .clone(); println!("app_account_id: {:?}", app.account().id()); - let res = app.call_as(&server_addr).receive_message(msg); + let res = app.call_as(&server_addr).receive_message(temp_ibc_mail_msg_to_header(msg.clone(), Route::Local), msg.clone()); assert_that!(res).is_ok(); @@ -137,8 +146,8 @@ mod receive_msg { let app_account_id = app.account().id().unwrap(); - let msg = create_test_message(app_account_id.clone(), app_account_id.clone()); - let res = app.receive_message(msg); + let msg = create_server_test_msg(app_account_id.clone(), app_account_id.clone()); + let res = app.receive_message(temp_ibc_mail_msg_to_header(msg.clone(), Route::Local), msg); assert_that!(res) .is_err() @@ -169,13 +178,13 @@ mod send_msg { let client1 = env.client1; let client2 = env.client2; + let recipient = Recipient::account(client2.account().id()?, None); let msg = Message::new( - Recipient::account(client2.account().id()?, None), "test-subject", "test-body", ); - let res = client1.send_message(msg, None); + let res = client1.send_message(msg, recipient, None); assert_that!(res).is_ok(); @@ -190,13 +199,13 @@ mod send_msg { let client1 = env.client1; let client2 = env.client2; + let recipient = Recipient::account(client2.account().id()?, None); let msg = Message::new( - Recipient::account(client2.account().id()?, None), "test-subject", "test-body", ); - let res = client1.send_message(msg, None); + let res = client1.send_message(msg, recipient, None); assert_that!(res).is_ok(); let received_messages = client2 @@ -222,12 +231,11 @@ mod send_msg { .claim_namespace(client2.account().id()?, namespace.to_string())?; let msg = Message::new( - Recipient::namespace(namespace.try_into()?, None), "test-subject", "test-body", ); - let res = client1.send_message(msg, None); + let res = client1.send_message(msg, Recipient::namespace(namespace.try_into()?, None),None); assert_that!(res).is_ok(); Ok(()) @@ -243,12 +251,11 @@ mod send_msg { let bad_namespace: Namespace = "nope".try_into()?; let msg = Message::new( - Recipient::namespace(bad_namespace.clone(), None), "test-subject", "test-body", ); - let res = client1.send_message(msg, None); + let res = client1.send_message(msg, Recipient::namespace(bad_namespace.clone(), None), None); assert_that!(res).is_err().matches(|e| { e.root() @@ -265,8 +272,6 @@ mod send_msg { let interchain = MockBech32InterchainEnv::new(vec![("juno-1", "juno"), ("archway-1", "archway")]); - // /Users/adair/.cargo/registry/src/index.crates.io-6f17d22bba15001f/cw-orch-mock-0.22.0/src/queriers/env.rs:12:70: - // index out of bounds: the len is 1 but the index is 1 (when initializing with "juno") let arch_env = TestEnv::setup(interchain.get_chain("archway-1")?)?; let juno_env = TestEnv::setup(interchain.get_chain("juno-1")?)?; @@ -277,15 +282,14 @@ mod send_msg { // the trait `From<&str>` is not implemented for `abstract_app::objects::chain_name::TruncatedChainId` let arch_to_juno_msg = Message::new( - Recipient::account( - juno_client.account().id()?, - Some(TruncatedChainId::from_string("juno".into())?), - ), "test-subject", "test-body", ); - let res = arch_client.send_message(arch_to_juno_msg, None); + let res = arch_client.send_message(arch_to_juno_msg, Recipient::account( + juno_client.account().id()?, + Some(TruncatedChainId::from_string("juno".into())?), + ), None); assert_that!(res).is_ok(); @@ -340,8 +344,6 @@ mod send_msg { let interchain = MockBech32InterchainEnv::new(vec![("juno-1", "juno"), ("archway-1", "archway")]); - // /Users/adair/.cargo/registry/src/index.crates.io-6f17d22bba15001f/cw-orch-mock-0.22.0/src/queriers/env.rs:12:70: - // index out of bounds: the len is 1 but the index is 1 (when initializing with "juno") let arch_env = TestEnv::setup(interchain.get_chain("archway-1")?)?; let juno_env = TestEnv::setup(interchain.get_chain("juno-1")?)?; @@ -352,16 +354,16 @@ mod send_msg { // the trait `From<&str>` is not implemented for `abstract_app::objects::chain_name::TruncatedChainId` let arch_to_juno_msg = Message::new( - Recipient::account( - AccountId::local(420), - Some(TruncatedChainId::from_string("juno".into())?), - ), "test-subject", "test-body", ); let res = arch_client.send_message( arch_to_juno_msg, + Recipient::account( + AccountId::local(420), + Some(TruncatedChainId::from_string("juno".into())?), + ), Some(Route::Remote(vec![TruncatedChainId::from_string( "juno".into(), )?])), @@ -424,16 +426,16 @@ mod send_msg { // the trait `From<&str>` is not implemented for `abstract_app::objects::chain_name::TruncatedChainId` let arch_to_neutron_msg = Message::new( - Recipient::account( - neutron_client.account().id()?, - Some(TruncatedChainId::from_string("neutron".into())?), - ), "test-subject", "test-body", ); let res = arch_client.send_message( arch_to_neutron_msg, + Recipient::account( + neutron_client.account().id()?, + Some(TruncatedChainId::from_string("neutron".into())?), + ), Some(AccountTrace::Remote(vec![ "juno".parse()?, TruncatedChainId::from_str("neutron")?, From 051b412ddd66f648629e239853b5ead0feb23f04 Mon Sep 17 00:00:00 2001 From: adairrr <32375605+adairrr@users.noreply.github.com> Date: Sun, 4 Aug 2024 20:59:13 +0200 Subject: [PATCH 07/12] Format --- contracts/client/examples/publish.rs | 1 - contracts/client/src/handlers/execute.rs | 31 +++++--- contracts/client/src/handlers/instantiate.rs | 1 - contracts/client/src/handlers/query.rs | 2 +- contracts/server/src/handlers/execute.rs | 13 ++-- contracts/server/src/handlers/ibc_callback.rs | 9 ++- contracts/server/src/handlers/module_ibc.rs | 2 +- contracts/server/src/replies/deliver_msg.rs | 10 ++- packages/ibcmail/src/client/api.rs | 18 ++++- packages/ibcmail/src/client/msg.rs | 7 +- packages/ibcmail/src/lib.rs | 15 ++-- packages/ibcmail/src/server/state.rs | 2 +- tests/Cargo.toml | 4 +- tests/src/bin/approve.rs | 1 - tests/src/bin/full_demo.rs | 1 - tests/src/client.rs | 70 ++++++++----------- 16 files changed, 106 insertions(+), 81 deletions(-) diff --git a/contracts/client/examples/publish.rs b/contracts/client/examples/publish.rs index 31afd35..114912f 100644 --- a/contracts/client/examples/publish.rs +++ b/contracts/client/examples/publish.rs @@ -8,7 +8,6 @@ //! $ just publish uni-6 osmo-test-5 //! ``` -use abstract_app::objects::module::ModuleVersion; use abstract_app::objects::namespace::Namespace; use abstract_client::{AbstractClient, Publisher}; use clap::Parser; diff --git a/contracts/client/src/handlers/execute.rs b/contracts/client/src/handlers/execute.rs index c3c8864..b08dbe4 100644 --- a/contracts/client/src/handlers/execute.rs +++ b/contracts/client/src/handlers/execute.rs @@ -11,10 +11,15 @@ use abstract_app::{ use base64::prelude::*; use cosmwasm_std::{ensure_eq, Addr, CosmosMsg, Deps, DepsMut, Env, MessageInfo}; use ibcmail::client::state::STATUS; -use ibcmail::{client::{ - state::{RECEIVED, SENT}, - ClientApp, -}, server::api::{MailServer, ServerInterface}, DeliveryStatus, IbcMailMessage, Message, MessageHash, Recipient, Route, Sender, IBCMAIL_SERVER_ID, Header}; +use ibcmail::{ + client::{ + state::{RECEIVED, SENT}, + ClientApp, + }, + server::api::{MailServer, ServerInterface}, + DeliveryStatus, Header, IbcMailMessage, Message, MessageHash, Recipient, Route, Sender, + IBCMAIL_SERVER_ID, +}; // # ANCHOR: execute_handler pub fn execute_handler( @@ -25,10 +30,14 @@ pub fn execute_handler( msg: ClientExecuteMsg, ) -> ClientResult { match msg { - ClientExecuteMsg::SendMessage { message, recipient, route } => { - send_msg(deps, env, info, app, message, recipient, route) + ClientExecuteMsg::SendMessage { + message, + recipient, + route, + } => send_msg(deps, env, info, app, message, recipient, route), + ClientExecuteMsg::ReceiveMessage { message, header } => { + receive_msg(deps, info, app, message, header) } - ClientExecuteMsg::ReceiveMessage { message, header } => receive_msg(deps, info, app, message, header), ClientExecuteMsg::UpdateDeliveryStatus { id, status } => { update_delivery_status(deps, info, app, id, status) } @@ -76,7 +85,13 @@ fn send_msg( /// Receive a message from the server // # ANCHOR: receive_msg -fn receive_msg(deps: DepsMut, info: MessageInfo, app: App, msg: IbcMailMessage, header: Header) -> ClientResult { +fn receive_msg( + deps: DepsMut, + info: MessageInfo, + app: App, + msg: IbcMailMessage, + header: Header, +) -> ClientResult { ensure_server_sender(deps.as_ref(), &app, info.sender)?; ensure_correct_recipient(deps.as_ref(), &header.recipient, &app)?; diff --git a/contracts/client/src/handlers/instantiate.rs b/contracts/client/src/handlers/instantiate.rs index 2a384bc..f8fe31f 100644 --- a/contracts/client/src/handlers/instantiate.rs +++ b/contracts/client/src/handlers/instantiate.rs @@ -1,6 +1,5 @@ use crate::{ contract::{App, ClientResult}, - msg::AppMigrateMsg, CLIENT_FEATURES, }; use abstract_app::traits::AbstractResponse; diff --git a/contracts/client/src/handlers/query.rs b/contracts/client/src/handlers/query.rs index ce3adec..f10826f 100644 --- a/contracts/client/src/handlers/query.rs +++ b/contracts/client/src/handlers/query.rs @@ -7,7 +7,7 @@ use ibcmail::{ msg::{MessageFilter, MessagesResponse}, state::{RECEIVED, SENT}, }, - DeliveryStatus, MessageHash, MessageKind, + MessageHash, MessageKind, }; use crate::{ diff --git a/contracts/server/src/handlers/execute.rs b/contracts/server/src/handlers/execute.rs index a205c6d..a7dc2d2 100644 --- a/contracts/server/src/handlers/execute.rs +++ b/contracts/server/src/handlers/execute.rs @@ -116,16 +116,21 @@ fn process_message( }?; let header = Header { - route, recipient: msg.recipient.clone(), id: msg.id.clone(), version: msg.version.clone(), sender, - timestamp: msg.timestamp.clone() + timestamp: msg.timestamp, }; - let msgs = route_msg(deps, ¤t_chain, &mut app, header, ServerMessage::mail(msg))?; + let msgs = route_msg( + deps, + ¤t_chain, + &mut app, + header, + ServerMessage::mail(msg), + )?; Ok(app.response("route").add_submessages(msgs)) } @@ -166,7 +171,7 @@ pub(crate) fn route_msg( let msg = remote_server_msg( deps, - &app, + app, &ServerIbcMessage::RouteMessage { msg, header: header.clone(), diff --git a/contracts/server/src/handlers/ibc_callback.rs b/contracts/server/src/handlers/ibc_callback.rs index 17b59bd..8512deb 100644 --- a/contracts/server/src/handlers/ibc_callback.rs +++ b/contracts/server/src/handlers/ibc_callback.rs @@ -1,12 +1,12 @@ use abstract_adapter::objects::TruncatedChainId; use abstract_adapter::std::ibc::{Callback, IbcResult}; -use cosmwasm_std::{DepsMut, Env, from_json, Response, SubMsg}; +use cosmwasm_std::{from_json, DepsMut, Env, Response, SubMsg}; +use ibcmail::server::msg::ServerMessage; use ibcmail::{ - DeliveryFailure, - Header, Route, Sender, server::{msg::ServerIbcMessage, ServerAdapter}, + server::{msg::ServerIbcMessage, ServerAdapter}, + DeliveryFailure, Header, Route, Sender, }; -use ibcmail::server::msg::ServerMessage; use crate::contract::ServerResult; use crate::handlers::execute; @@ -78,7 +78,6 @@ pub fn ibc_callback_handler( // expected: juno archway // need to remove anything after the current hop let status_header = Header { - route: match header.route { Route::Remote(mut chains) => { // keep the current hop but remove everything after it diff --git a/contracts/server/src/handlers/module_ibc.rs b/contracts/server/src/handlers/module_ibc.rs index 5caeccc..2e25e1c 100644 --- a/contracts/server/src/handlers/module_ibc.rs +++ b/contracts/server/src/handlers/module_ibc.rs @@ -26,7 +26,7 @@ pub fn module_ibc_handler( let server_msg: ServerIbcMessage = from_json(msg)?; match server_msg { - ServerIbcMessage::RouteMessage { msg, mut header } => { + ServerIbcMessage::RouteMessage { msg, header } => { let msgs = route_msg(deps, &TruncatedChainId::new(&env), &mut app, header, msg)?; Ok(app diff --git a/contracts/server/src/replies/deliver_msg.rs b/contracts/server/src/replies/deliver_msg.rs index 39abe87..a589b57 100644 --- a/contracts/server/src/replies/deliver_msg.rs +++ b/contracts/server/src/replies/deliver_msg.rs @@ -5,7 +5,7 @@ use cosmwasm_std::{DepsMut, Env, Reply, SubMsgResult}; use ibcmail::server::msg::ServerMessage; use ibcmail::server::state::AWAITING_DELIVERY; use ibcmail::server::ServerAdapter; -use ibcmail::{DeliveryFailure, DeliveryStatus, Header, Sender}; +use ibcmail::{DeliveryFailure, DeliveryStatus, Sender}; use crate::contract::ServerResult; use crate::handlers::execute::route_msg; @@ -33,7 +33,13 @@ pub fn deliver_message_reply( chain: TruncatedChainId::new(&env), })?; - let msg = route_msg(deps, ¤t_chain, &mut app, delivery_header, delivery_msg)?; + let msg = route_msg( + deps, + ¤t_chain, + &mut app, + delivery_header, + delivery_msg, + )?; Ok(app .response("deliver_message_reply") diff --git a/packages/ibcmail/src/client/api.rs b/packages/ibcmail/src/client/api.rs index 42754d0..3f1fe98 100644 --- a/packages/ibcmail/src/client/api.rs +++ b/packages/ibcmail/src/client/api.rs @@ -4,7 +4,10 @@ use abstract_app::sdk::AppInterface; use cosmwasm_std::{Addr, CosmosMsg, Deps}; -use crate::{client::msg::ClientExecuteMsg, DeliveryStatus, Header, IbcMailMessage, Message, MessageHash, Route, IBCMAIL_CLIENT_ID, Recipient}; +use crate::{ + client::msg::ClientExecuteMsg, DeliveryStatus, Header, IbcMailMessage, Message, MessageHash, + Recipient, Route, IBCMAIL_CLIENT_ID, +}; // API for Abstract SDK users pub trait ClientInterface: AppInterface { @@ -46,8 +49,17 @@ impl<'a, T: ClientInterface> MailClient<'a, T> { } /// Send message - pub fn send_msg(&self, recipient: Recipient, message: Message, route: Option) -> AbstractSdkResult { - self.request(ClientExecuteMsg::SendMessage { recipient, message, route }) + pub fn send_msg( + &self, + recipient: Recipient, + message: Message, + route: Option, + ) -> AbstractSdkResult { + self.request(ClientExecuteMsg::SendMessage { + recipient, + message, + route, + }) } /// Receive message diff --git a/packages/ibcmail/src/client/msg.rs b/packages/ibcmail/src/client/msg.rs index e468e1b..332073b 100644 --- a/packages/ibcmail/src/client/msg.rs +++ b/packages/ibcmail/src/client/msg.rs @@ -1,6 +1,9 @@ use cosmwasm_schema::QueryResponses; -use crate::{client::ClientApp, DeliveryStatus, Header, IbcMailMessage, Message, MessageHash, MessageKind, Recipient, Route, Sender}; +use crate::{ + client::ClientApp, DeliveryStatus, Header, IbcMailMessage, Message, MessageHash, MessageKind, + Recipient, Route, Sender, +}; // This is used for type safety and re-exporting the contract endpoint structs. abstract_app::app_msg_types!(ClientApp, ClientExecuteMsg, ClientQueryMsg); @@ -18,7 +21,7 @@ pub enum ClientExecuteMsg { /// Receive a message from the server. ReceiveMessage { header: Header, - message: IbcMailMessage + message: IbcMailMessage, }, /// Update the status of a message. only callable by the server UpdateDeliveryStatus { diff --git a/packages/ibcmail/src/lib.rs b/packages/ibcmail/src/lib.rs index 6b66349..9069dea 100644 --- a/packages/ibcmail/src/lib.rs +++ b/packages/ibcmail/src/lib.rs @@ -10,7 +10,7 @@ use abstract_app::sdk::ModuleRegistry; use abstract_app::std::objects::AccountId; use abstract_app::std::objects::{account::AccountTrace, namespace::Namespace}; use const_format::concatcp; -use cosmwasm_std::{Addr, StdError, StdResult, Timestamp}; +use cosmwasm_std::{StdError, StdResult, Timestamp}; use std::fmt; use std::fmt::{Display, Formatter}; use thiserror::Error; @@ -59,7 +59,7 @@ pub struct Header { pub recipient: Recipient, pub id: MessageHash, pub version: String, - pub timestamp: Timestamp + pub timestamp: Timestamp, } impl Header { @@ -72,7 +72,6 @@ impl Header { Route::Local => Route::Local, }; Ok(Header { - route: reverse_route, recipient: self.sender.clone().try_into()?, sender, @@ -89,7 +88,7 @@ impl Header { let position = route.iter().position(|chain| chain == current_chain); match position { Some(position) => Ok(position as u32), - None => Err(StdError::generic_err("Current chain not in route")) + None => Err(StdError::generic_err("Current chain not in route")), } } } @@ -139,7 +138,7 @@ impl Recipient { &self, module_registry: ModuleRegistry, ) -> Result { - Ok(match self { + match self { Recipient::Account { id: account_id, .. } => Ok(account_id.clone()), Recipient::Namespace { namespace, .. } => { // TODO: this only allows for addressing recipients via namespace of their email account directly. @@ -148,14 +147,14 @@ impl Recipient { match namespace_status { NamespaceResponse::Claimed(info) => Ok(info.account_id), NamespaceResponse::Unclaimed {} => { - return Err(ServerError::UnclaimedNamespace(namespace.clone())); + Err(ServerError::UnclaimedNamespace(namespace.clone())) } } } _ => Err(ServerError::NotImplemented( "Non-account recipients not supported".to_string(), )), - }?) + } } } @@ -189,7 +188,7 @@ impl TryFrom for Recipient { match sender { Sender::Account { id, chain } => Ok(Recipient::Account { id, chain }), Sender::Server { chain, address } => Ok(Recipient::Server { chain, address }), - _ => Err(StdError::generic_err("Cannot convert Sender to Recipient").into()), + _ => Err(StdError::generic_err("Cannot convert Sender to Recipient")), } } } diff --git a/packages/ibcmail/src/server/state.rs b/packages/ibcmail/src/server/state.rs index d956dbc..d5c0fe9 100644 --- a/packages/ibcmail/src/server/state.rs +++ b/packages/ibcmail/src/server/state.rs @@ -1,4 +1,4 @@ -use crate::{Header, Message, MessageHash}; +use crate::{Header, MessageHash}; use abstract_app::objects::TruncatedChainId; use cw_storage_plus::{Item, Map}; diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 744a24e..7a967ab 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -30,8 +30,8 @@ client = { workspace = true, features = ["interface"] } speculoos = { workspace = true } server = { workspace = true, features = ["interface"] } abstract-client = { workspace = true, features = ["interchain"] } -clap = { workspace = true , features = ["derive"]} +clap = { workspace = true, features = ["derive"] } dotenv = { workspace = true } -env_logger ={ workspace = true } +env_logger = { workspace = true } anyhow = "1.0.86" diff --git a/tests/src/bin/approve.rs b/tests/src/bin/approve.rs index 6baa0fd..c667c8d 100644 --- a/tests/src/bin/approve.rs +++ b/tests/src/bin/approve.rs @@ -13,7 +13,6 @@ use abstract_interface::Abstract; use clap::Parser; use cw_orch::{ anyhow, - environment::TxHandler, prelude::{networks::parse_network, DaemonBuilder, *}, tokio::runtime::Runtime, }; diff --git a/tests/src/bin/full_demo.rs b/tests/src/bin/full_demo.rs index 0bc0182..924f1b4 100644 --- a/tests/src/bin/full_demo.rs +++ b/tests/src/bin/full_demo.rs @@ -159,7 +159,6 @@ pub fn approve_mail_modules(vc: &VersionControl) -> anyhow::Res Ok(()) } - #[derive(Parser, Default, Debug)] #[command(author, version, about, long_about = None)] struct Arguments {} diff --git a/tests/src/client.rs b/tests/src/client.rs index f24b311..f407fad 100644 --- a/tests/src/client.rs +++ b/tests/src/client.rs @@ -1,11 +1,14 @@ use abstract_app::objects::{namespace::Namespace, AccountId}; -use abstract_client::{AbstractClient, Application, Environment}; +use abstract_client::{AbstractClient, Application}; use cw_orch::{anyhow, prelude::*}; use speculoos::prelude::*; // Use prelude to get all the necessary imports use client::{contract::interface::ClientInterface, msg::ClientInstantiateMsg, *}; -use ibcmail::{server::msg::ServerInstantiateMsg, IbcMailMessage, Message, Recipient, Sender, IBCMAIL_NAMESPACE, IBCMAIL_SERVER_ID, MessageKind, Header, Route}; +use ibcmail::{ + server::msg::ServerInstantiateMsg, Header, IbcMailMessage, Message, Recipient, Route, Sender, + IBCMAIL_NAMESPACE, IBCMAIL_SERVER_ID, +}; use server::ServerInterface; struct TestEnv { @@ -84,13 +87,12 @@ fn create_server_test_msg(from: AccountId, to: AccountId) -> IbcMailMessage { fn temp_ibc_mail_msg_to_header(msg: IbcMailMessage, route: Route) -> Header { Header { - route, recipient: msg.recipient.clone(), id: msg.id.clone(), version: msg.version.clone(), sender: msg.sender.clone(), - timestamp: msg.timestamp.clone(), + timestamp: msg.timestamp, } } @@ -127,7 +129,10 @@ mod receive_msg { .clone(); println!("app_account_id: {:?}", app.account().id()); - let res = app.call_as(&server_addr).receive_message(temp_ibc_mail_msg_to_header(msg.clone(), Route::Local), msg.clone()); + let res = app.call_as(&server_addr).receive_message( + temp_ibc_mail_msg_to_header(msg.clone(), Route::Local), + msg.clone(), + ); assert_that!(res).is_ok(); @@ -162,7 +167,7 @@ mod send_msg { use abstract_app::objects::TruncatedChainId; use abstract_app::{objects::account::AccountTrace, std::version_control::ExecuteMsgFns}; - use abstract_cw_orch_polytone::{Polytone, PolytoneConnection}; + use abstract_cw_orch_polytone::PolytoneConnection; use abstract_interface::Abstract; use cw_orch_interchain::{InterchainEnv, MockBech32InterchainEnv}; @@ -179,10 +184,7 @@ mod send_msg { let client2 = env.client2; let recipient = Recipient::account(client2.account().id()?, None); - let msg = Message::new( - "test-subject", - "test-body", - ); + let msg = Message::new("test-subject", "test-body"); let res = client1.send_message(msg, recipient, None); @@ -200,10 +202,7 @@ mod send_msg { let client2 = env.client2; let recipient = Recipient::account(client2.account().id()?, None); - let msg = Message::new( - "test-subject", - "test-body", - ); + let msg = Message::new("test-subject", "test-body"); let res = client1.send_message(msg, recipient, None); assert_that!(res).is_ok(); @@ -230,12 +229,10 @@ mod send_msg { .version_control() .claim_namespace(client2.account().id()?, namespace.to_string())?; - let msg = Message::new( - "test-subject", - "test-body", - ); + let msg = Message::new("test-subject", "test-body"); - let res = client1.send_message(msg, Recipient::namespace(namespace.try_into()?, None),None); + let res = + client1.send_message(msg, Recipient::namespace(namespace.try_into()?, None), None); assert_that!(res).is_ok(); Ok(()) @@ -250,12 +247,10 @@ mod send_msg { let bad_namespace: Namespace = "nope".try_into()?; - let msg = Message::new( - "test-subject", - "test-body", - ); + let msg = Message::new("test-subject", "test-body"); - let res = client1.send_message(msg, Recipient::namespace(bad_namespace.clone(), None), None); + let res = + client1.send_message(msg, Recipient::namespace(bad_namespace.clone(), None), None); assert_that!(res).is_err().matches(|e| { e.root() @@ -281,15 +276,16 @@ mod send_msg { let juno_client = juno_env.client1; // the trait `From<&str>` is not implemented for `abstract_app::objects::chain_name::TruncatedChainId` - let arch_to_juno_msg = Message::new( - "test-subject", - "test-body", - ); + let arch_to_juno_msg = Message::new("test-subject", "test-body"); - let res = arch_client.send_message(arch_to_juno_msg, Recipient::account( - juno_client.account().id()?, - Some(TruncatedChainId::from_string("juno".into())?), - ), None); + let res = arch_client.send_message( + arch_to_juno_msg, + Recipient::account( + juno_client.account().id()?, + Some(TruncatedChainId::from_string("juno".into())?), + ), + None, + ); assert_that!(res).is_ok(); @@ -353,10 +349,7 @@ mod send_msg { let juno_client = juno_env.client1; // the trait `From<&str>` is not implemented for `abstract_app::objects::chain_name::TruncatedChainId` - let arch_to_juno_msg = Message::new( - "test-subject", - "test-body", - ); + let arch_to_juno_msg = Message::new("test-subject", "test-body"); let res = arch_client.send_message( arch_to_juno_msg, @@ -425,10 +418,7 @@ mod send_msg { let neutron_client = neutron_env.client1; // the trait `From<&str>` is not implemented for `abstract_app::objects::chain_name::TruncatedChainId` - let arch_to_neutron_msg = Message::new( - "test-subject", - "test-body", - ); + let arch_to_neutron_msg = Message::new("test-subject", "test-body"); let res = arch_client.send_message( arch_to_neutron_msg, From a16d733c64481e181826bd645c6786360d80e78e Mon Sep 17 00:00:00 2001 From: adairrr <32375605+adairrr@users.noreply.github.com> Date: Sun, 4 Aug 2024 22:06:51 +0200 Subject: [PATCH 08/12] Move route to metadata --- contracts/client/src/handlers/execute.rs | 40 +++-- contracts/server/src/handlers/execute.rs | 159 +++++++++++------- contracts/server/src/handlers/ibc_callback.rs | 62 ++++--- contracts/server/src/handlers/module_ibc.rs | 17 +- contracts/server/src/replies/deliver_msg.rs | 37 ++-- packages/ibcmail/src/client/api.rs | 10 +- packages/ibcmail/src/client/msg.rs | 6 +- packages/ibcmail/src/lib.rs | 45 +++-- packages/ibcmail/src/server/api.rs | 13 +- packages/ibcmail/src/server/error.rs | 7 + packages/ibcmail/src/server/msg.rs | 16 +- packages/ibcmail/src/server/state.rs | 5 +- tests/src/bin/demo.rs | 8 +- tests/src/bin/full_demo.rs | 8 +- tests/src/client.rs | 17 +- 15 files changed, 290 insertions(+), 160 deletions(-) diff --git a/contracts/client/src/handlers/execute.rs b/contracts/client/src/handlers/execute.rs index b08dbe4..bf6a298 100644 --- a/contracts/client/src/handlers/execute.rs +++ b/contracts/client/src/handlers/execute.rs @@ -17,8 +17,8 @@ use ibcmail::{ ClientApp, }, server::api::{MailServer, ServerInterface}, - DeliveryStatus, Header, IbcMailMessage, Message, MessageHash, Recipient, Route, Sender, - IBCMAIL_SERVER_ID, + ClientMetadata, DeliveryStatus, Header, IbcMailMessage, Message, MessageHash, Recipient, + Sender, IBCMAIL_SERVER_ID, }; // # ANCHOR: execute_handler @@ -33,8 +33,8 @@ pub fn execute_handler( ClientExecuteMsg::SendMessage { message, recipient, - route, - } => send_msg(deps, env, info, app, message, recipient, route), + metadata, + } => send_msg(deps, env, info, app, message, recipient, metadata), ClientExecuteMsg::ReceiveMessage { message, header } => { receive_msg(deps, info, app, message, header) } @@ -53,31 +53,45 @@ fn send_msg( app: ClientApp, msg: Message, recipient: Recipient, - route: Option, + metadata: Option, ) -> ClientResult { // validate basic fields of message, construct message to send to server let to_hash = format!("{:?}{:?}{:?}", env.block.time, msg.subject, recipient); let hash = ::digest(to_hash); let base_64_hash = BASE64_STANDARD.encode(hash); + + let sender = Sender::account( + app.account_id(deps.as_ref()).unwrap(), + Some(TruncatedChainId::new(&env)), + ); + let version = app.version().to_string(); + let to_send = IbcMailMessage { - id: base_64_hash, - sender: Sender::account( - app.account_id(deps.as_ref()).unwrap(), - Some(TruncatedChainId::new(&env)), - ), - recipient, + id: base_64_hash.clone(), + sender: sender.clone(), + recipient: recipient.clone(), message: Message { subject: msg.subject, body: msg.body, }, timestamp: env.block.time, - version: app.version().to_string(), + version: version.clone(), + reply_to: None, + }; + + let client_header = Header { + sender, + recipient, + id: base_64_hash, + version: version, + timestamp: env.block.time, + reply_to: None, }; SENT.save(deps.storage, to_send.id.clone(), &to_send)?; let server: MailServer<_> = app.mail_server(deps.as_ref()); - let route_msg: CosmosMsg = server.process_msg(to_send, route)?; + let route_msg: CosmosMsg = server.process_msg(to_send, client_header, metadata)?; Ok(app.response("send").add_message(route_msg)) } diff --git a/contracts/server/src/handlers/execute.rs b/contracts/server/src/handlers/execute.rs index a7dc2d2..5055c26 100644 --- a/contracts/server/src/handlers/execute.rs +++ b/contracts/server/src/handlers/execute.rs @@ -1,32 +1,29 @@ -use abstract_adapter::objects::TruncatedChainId; -use abstract_adapter::sdk::{ - features::ModuleIdentification, AccountVerification, ModuleRegistryInterface, -}; -use abstract_adapter::std::ibc::Callback; -use abstract_adapter::std::version_control::AccountBase; -use abstract_adapter::std::{ - ibc_client, - objects::{account::AccountTrace, module::ModuleInfo}, - IBC_CLIENT, +use abstract_adapter::{ + objects::TruncatedChainId, + sdk::{features::ModuleIdentification, AccountVerification, ModuleRegistryInterface}, + std::ibc::Callback, + std::version_control::AccountBase, + std::{ + ibc_client, + objects::{account::AccountTrace, module::ModuleInfo}, + IBC_CLIENT, + }, + traits::{AbstractResponse, AccountIdentification}, }; -use abstract_adapter::traits::{AbstractResponse, AccountIdentification}; use cosmwasm_std::{ - to_json_binary, wasm_execute, Addr, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, - StdResult, SubMsg, + ensure_eq, to_json_binary, wasm_execute, Addr, CosmosMsg, Deps, DepsMut, Empty, Env, + MessageInfo, StdResult, SubMsg, }; -use ibcmail::client::api::MailClient; -use ibcmail::client::state::FEATURES; -use ibcmail::features::DELIVERY_STATUS_FEATURE; -use ibcmail::server::msg::ServerMessage; -use ibcmail::server::state::{AWAITING, AWAITING_DELIVERY}; use ibcmail::{ - client::api::ClientInterface, + client::{api::ClientInterface, api::MailClient, state::FEATURES}, + features::DELIVERY_STATUS_FEATURE, server::{ - msg::{ServerExecuteMsg, ServerIbcMessage}, + msg::{ServerExecuteMsg, ServerIbcMessage, ServerMessage}, + state::{AWAITING, AWAITING_DELIVERY}, ServerAdapter, }, - Header, IbcMailMessage, Recipient, Route, Sender, + ClientMetadata, Header, IbcMailMessage, Recipient, Route, Sender, ServerMetadata, }; use crate::replies::DELIVER_MESSAGE_REPLY; @@ -44,31 +41,72 @@ pub fn execute_handler( msg: ServerExecuteMsg, ) -> ServerResult { match msg { - ServerExecuteMsg::ProcessMessage { msg, route } => { - process_message(deps, env, info, msg, route, app) - } + ServerExecuteMsg::ProcessMessage { + message, + header, + metadata, + } => process_message(deps, env, info, app, message, header, metadata), } } // ANCHOR_END: execute_handler +fn check_sender( + deps: Deps, + module: &Adapter, + current_chain: &TruncatedChainId, + sender_to_check: Sender, +) -> ServerResult { + let expected_sender = module + .account_id(deps) + .map_err(|_| ServerError::NoSenderAccount)?; + + match sender_to_check { + Sender::Account { id, chain } => { + ensure_eq!( + id, + expected_sender, + ServerError::MismatchedSender { + expected: expected_sender, + actual: id, + } + ); + + Ok(Sender::account(id, Some(current_chain.clone()))) + } + Sender::Server { address, chain } => { + panic!("Server sender not implemented"); + } + _ => Err(ServerError::NotImplemented( + "Non-account senders not supported".to_string(), + )), + } +} + fn process_message( deps: DepsMut, env: Env, _info: MessageInfo, - msg: IbcMailMessage, - route: Option, - mut app: Adapter, + mut module: Adapter, + message: IbcMailMessage, + header: Header, + metadata: Option, ) -> ServerResult { - println!("processing message: {:?} with route {:?}", msg, route); - - let sender_acc_id = app - .account_id(deps.as_ref()) - .map_err(|_| ServerError::NoSenderAccount)?; + println!( + "processing message: {:?} with route {:?}", + message, metadata + ); let current_chain = TruncatedChainId::new(&env); - let sender = Sender::account(sender_acc_id, Some(current_chain.clone())); + let checked_sender = check_sender( + deps.as_ref(), + &module, + ¤t_chain, + header.sender.clone(), + )?; + + let client_metadata = metadata.unwrap_or_default(); - let route: Route = if let Some(route) = route { + let route: Route = if let Some(route) = client_metadata.route { Ok::<_, ServerError>(match route { Route::Local => Route::Local, Route::Remote(mut chains) => { @@ -87,8 +125,9 @@ fn process_message( } }) } else { - println!("processing message recipient: {:?}", msg.recipient); - match msg.recipient.clone() { + // We weren't provided a route + println!("processing message recipient: {:?}", message.recipient); + match message.recipient.clone() { // TODO: add smarter routing Recipient::Account { id: _, chain } => Ok(chain.map_or(AccountTrace::Local, |chain| { if chain == current_chain { @@ -116,44 +155,46 @@ fn process_message( }?; let header = Header { - route, - recipient: msg.recipient.clone(), - id: msg.id.clone(), - version: msg.version.clone(), - sender, - timestamp: msg.timestamp, + recipient: header.recipient.clone(), + id: header.id.clone(), + version: header.version.clone(), + sender: checked_sender, + timestamp: header.timestamp, + reply_to: None, }; - let msgs = route_msg( + let msgs = route_message( deps, + &mut module, ¤t_chain, - &mut app, header, - ServerMessage::mail(msg), + ServerMetadata { route }, + ServerMessage::mail(message), )?; - Ok(app.response("route").add_submessages(msgs)) + Ok(module.response("route").add_submessages(msgs)) } -pub(crate) fn route_msg( +pub(crate) fn route_message( deps: DepsMut, - current_chain: &TruncatedChainId, app: &mut ServerAdapter, + current_chain: &TruncatedChainId, header: Header, - msg: ServerMessage, + metadata: ServerMetadata, + message: ServerMessage, ) -> ServerResult> { - println!("routing message: {:?}, metadata: {:?}", msg, header); + println!("routing message: {:?}, metadata: {:?}", message, header); - let current_hop = header.current_hop(current_chain)?; + let current_hop = metadata.current_hop(current_chain)?; - match header.route { - AccountTrace::Local => route_to_local_account(deps, app, msg, header), + match metadata.route { + AccountTrace::Local => route_to_local_account(deps, app, message, header, metadata), AccountTrace::Remote(ref chains) => { println!("routing to chains: {:?}", chains); // check index of hop. If we are on the final hop, route to local account if current_hop == (chains.len() - 1) as u32 { println!("routing to local account: {:?}", chains.last().unwrap()); - return route_to_local_account(deps, app, msg.clone(), header); + return route_to_local_account(deps, app, message.clone(), header, metadata); } // TODO verify that the chain is a valid chain @@ -161,20 +202,21 @@ pub(crate) fn route_msg( chains .get(current_hop as usize + 1) .ok_or(ServerError::InvalidRoute { - route: header.route.clone(), + route: metadata.route.clone(), hop: current_hop, })?; // Awaiting callback // Save that we're awaiting callbacks from dest chain onwards. - AWAITING.save(deps.storage, &msg.id(), dest_chain)?; + AWAITING.save(deps.storage, &message.id(), dest_chain)?; let msg = remote_server_msg( deps, app, &ServerIbcMessage::RouteMessage { - msg, + msg: message, header: header.clone(), + metadata: metadata.clone(), }, dest_chain, )?; @@ -189,13 +231,14 @@ fn route_to_local_account( app: &mut ServerAdapter, msg: ServerMessage, header: Header, + metadata: ServerMetadata, ) -> ServerResult> { println!("routing to local account: {:?}", header.recipient); // This is a local message match msg { ServerMessage::Mail { message } => { AWAITING_DELIVERY.update(deps.storage, |mut awaiting| -> StdResult> { - awaiting.push((message.id.clone(), header.clone())); + awaiting.push((message.id.clone(), header.clone(), metadata.clone())); Ok(awaiting) })?; diff --git a/contracts/server/src/handlers/ibc_callback.rs b/contracts/server/src/handlers/ibc_callback.rs index 8512deb..095e0ae 100644 --- a/contracts/server/src/handlers/ibc_callback.rs +++ b/contracts/server/src/handlers/ibc_callback.rs @@ -5,7 +5,7 @@ use cosmwasm_std::{from_json, DepsMut, Env, Response, SubMsg}; use ibcmail::server::msg::ServerMessage; use ibcmail::{ server::{msg::ServerIbcMessage, ServerAdapter}, - DeliveryFailure, Header, Route, Sender, + DeliveryFailure, Header, Route, Sender, ServerMetadata, }; use crate::contract::ServerResult; @@ -38,11 +38,16 @@ pub fn ibc_callback_handler( match origin_msg { // We successfully routed a packet, and need to send an update to the sender - ServerIbcMessage::RouteMessage { msg, header } => { + ServerIbcMessage::RouteMessage { + msg, + header, + metadata, + } => { println!( - "ibc_callback_handler success route_msg id: {:?}, header: {:?}", + "ibc_callback_handler success route_msg id: {:?}, header: {:?}, metadata: {:?}", msg.id(), - header + header, + metadata ); vec![] // vec![execute::update_message_status(deps, &mut app, msg.id, header, MessageStatus::Received)?] @@ -62,14 +67,19 @@ pub fn ibc_callback_handler( // println!("ibc_callback_handler execute error: {:?}", e); let origin_msg: ServerIbcMessage = from_json(initiator_msg)?; match origin_msg { - ServerIbcMessage::RouteMessage { msg, header } => { + ServerIbcMessage::RouteMessage { + msg, + header, + metadata, + } => { println!( - "ibc_callback_handler execute error route_msg id: {:?}, header: {:?}", + "ibc_callback_handler execute error route_msg id: {:?}, header: {:?}, metadata: {:?}", msg.id(), - header + header, + metadata ); let current_chain = TruncatedChainId::new(&_env); - let current_hop = header.current_hop(¤t_chain)?; + let current_hop = metadata.current_hop(¤t_chain)?; match msg { // We failed to deliver a message, we send a failed status update to the sender ServerMessage::Mail { ref message } => { @@ -78,15 +88,6 @@ pub fn ibc_callback_handler( // expected: juno archway // need to remove anything after the current hop let status_header = Header { - route: match header.route { - Route::Remote(mut chains) => { - // keep the current hop but remove everything after it - chains.truncate(current_hop as usize + 1); - chains.reverse(); - Route::Remote(chains) - } - _ => Route::Local, - }, sender: Sender::Server { chain: current_chain.clone(), address: _env.contract.address.to_string(), @@ -96,17 +97,32 @@ pub fn ibc_callback_handler( id: message.id.clone(), version: message.version.clone(), timestamp: _env.block.time, + reply_to: None, }; - execute::route_msg( + let status_metadata = ServerMetadata { + route: match metadata.route { + Route::Remote(mut chains) => { + // keep the current hop but remove everything after it + chains.truncate(current_hop as usize + 1); + chains.reverse(); + Route::Remote(chains) + } + _ => Route::Local, + }, + }; + + let status_message = ServerMessage::delivery_status( + msg.id(), + DeliveryFailure::Unknown(e).into(), + ); + execute::route_message( deps, - ¤t_chain, &mut app, + ¤t_chain, status_header, - ServerMessage::delivery_status( - msg.id(), - DeliveryFailure::Unknown(e).into(), - ), + status_metadata, + status_message, )? } _ => { diff --git a/contracts/server/src/handlers/module_ibc.rs b/contracts/server/src/handlers/module_ibc.rs index 2e25e1c..568de47 100644 --- a/contracts/server/src/handlers/module_ibc.rs +++ b/contracts/server/src/handlers/module_ibc.rs @@ -8,7 +8,7 @@ use ibcmail::{ IBCMAIL_SERVER_ID, }; -use crate::{contract::ServerResult, handlers::execute::route_msg}; +use crate::{contract::ServerResult, handlers::execute::route_message}; // ANCHOR: module_ibc_handler pub fn module_ibc_handler( @@ -26,8 +26,19 @@ pub fn module_ibc_handler( let server_msg: ServerIbcMessage = from_json(msg)?; match server_msg { - ServerIbcMessage::RouteMessage { msg, header } => { - let msgs = route_msg(deps, &TruncatedChainId::new(&env), &mut app, header, msg)?; + ServerIbcMessage::RouteMessage { + msg, + header, + metadata, + } => { + let msgs = route_message( + deps, + &mut app, + &TruncatedChainId::new(&env), + header, + metadata, + msg, + )?; Ok(app .response("module_ibc") diff --git a/contracts/server/src/replies/deliver_msg.rs b/contracts/server/src/replies/deliver_msg.rs index a589b57..90820f4 100644 --- a/contracts/server/src/replies/deliver_msg.rs +++ b/contracts/server/src/replies/deliver_msg.rs @@ -5,10 +5,10 @@ use cosmwasm_std::{DepsMut, Env, Reply, SubMsgResult}; use ibcmail::server::msg::ServerMessage; use ibcmail::server::state::AWAITING_DELIVERY; use ibcmail::server::ServerAdapter; -use ibcmail::{DeliveryFailure, DeliveryStatus, Sender}; +use ibcmail::{DeliveryFailure, DeliveryStatus, Header, Sender, ServerMetadata}; use crate::contract::ServerResult; -use crate::handlers::execute::route_msg; +use crate::handlers::execute::route_message; pub fn deliver_message_reply( deps: DepsMut, @@ -24,21 +24,36 @@ pub fn deliver_message_reply( // Load the awaiting message let mut awaiting_msgs = AWAITING_DELIVERY.load(deps.storage)?; - let (message_id, origin_header) = awaiting_msgs.remove(0); + let (message_id, origin_header, origin_metadata) = awaiting_msgs.remove(0); AWAITING_DELIVERY.save(deps.storage, &awaiting_msgs)?; - let delivery_msg = ServerMessage::delivery_status(message_id.clone(), delivery_status); - let delivery_header = origin_header.reverse(Sender::Server { - address: env.contract.address.to_string(), - chain: TruncatedChainId::new(&env), - })?; + let delivery_message = ServerMessage::delivery_status(message_id.clone(), delivery_status); - let msg = route_msg( + let delivery_header = Header { + sender: Sender::Server { + address: env.contract.address.to_string(), + chain: TruncatedChainId::new(&env), + }, + recipient: origin_header.sender.try_into()?, + // TODO: new ID? + id: message_id.clone(), + // TODO: version? + version: origin_header.version, + timestamp: env.block.time, + reply_to: None, + }; + + let delivery_metadata = ServerMetadata { + route: origin_metadata.reverse_route()?, + }; + + let msg = route_message( deps, - ¤t_chain, &mut app, + ¤t_chain, delivery_header, - delivery_msg, + delivery_metadata, + delivery_message, )?; Ok(app diff --git a/packages/ibcmail/src/client/api.rs b/packages/ibcmail/src/client/api.rs index 3f1fe98..306cf0f 100644 --- a/packages/ibcmail/src/client/api.rs +++ b/packages/ibcmail/src/client/api.rs @@ -1,12 +1,10 @@ use abstract_adapter::{sdk::AbstractSdkResult, std::objects::module::ModuleId}; - use abstract_app::sdk::AppInterface; - use cosmwasm_std::{Addr, CosmosMsg, Deps}; use crate::{ - client::msg::ClientExecuteMsg, DeliveryStatus, Header, IbcMailMessage, Message, MessageHash, - Recipient, Route, IBCMAIL_CLIENT_ID, + client::msg::ClientExecuteMsg, ClientMetadata, DeliveryStatus, Header, IbcMailMessage, Message, + MessageHash, Recipient, IBCMAIL_CLIENT_ID, }; // API for Abstract SDK users @@ -53,12 +51,12 @@ impl<'a, T: ClientInterface> MailClient<'a, T> { &self, recipient: Recipient, message: Message, - route: Option, + metadata: Option, ) -> AbstractSdkResult { self.request(ClientExecuteMsg::SendMessage { recipient, message, - route, + metadata, }) } diff --git a/packages/ibcmail/src/client/msg.rs b/packages/ibcmail/src/client/msg.rs index 332073b..03ce5ef 100644 --- a/packages/ibcmail/src/client/msg.rs +++ b/packages/ibcmail/src/client/msg.rs @@ -1,8 +1,8 @@ use cosmwasm_schema::QueryResponses; use crate::{ - client::ClientApp, DeliveryStatus, Header, IbcMailMessage, Message, MessageHash, MessageKind, - Recipient, Route, Sender, + client::ClientApp, ClientMetadata, DeliveryStatus, Header, IbcMailMessage, Message, + MessageHash, MessageKind, Recipient, Route, Sender, }; // This is used for type safety and re-exporting the contract endpoint structs. @@ -32,7 +32,7 @@ pub enum ClientExecuteMsg { SendMessage { recipient: Recipient, message: Message, - route: Option, + metadata: Option, }, } // # ANCHOR_END: execute_msg diff --git a/packages/ibcmail/src/lib.rs b/packages/ibcmail/src/lib.rs index 9069dea..713736e 100644 --- a/packages/ibcmail/src/lib.rs +++ b/packages/ibcmail/src/lib.rs @@ -49,36 +49,47 @@ pub struct IbcMailMessage { pub version: String, pub timestamp: Timestamp, pub message: Message, + pub reply_to: Option, } #[cosmwasm_schema::cw_serde] pub struct Header { - // TODO: remove current hop - pub route: Route, pub sender: Sender, pub recipient: Recipient, pub id: MessageHash, pub version: String, pub timestamp: Timestamp, + pub reply_to: Option, +} + +pub type Route = AccountTrace; + +#[derive(Default)] +#[cosmwasm_schema::cw_serde] +pub struct ClientMetadata { + pub route: Option, +} + +impl ClientMetadata { + pub fn new_with_route(route: Route) -> Self { + Self { route: Some(route) } + } +} + +#[cosmwasm_schema::cw_serde] +pub struct ServerMetadata { + pub route: Route, } -impl Header { - pub fn reverse(self, sender: Sender) -> StdResult
{ - let reverse_route = match self.route { +impl ServerMetadata { + pub fn reverse_route(&self) -> StdResult { + match self.route.clone() { Route::Remote(mut route) => { route.reverse(); - Route::Remote(route) + Ok(Route::Remote(route)) } - Route::Local => Route::Local, - }; - Ok(Header { - route: reverse_route, - recipient: self.sender.clone().try_into()?, - sender, - id: self.id, - version: self.version, - timestamp: self.timestamp, - }) + Route::Local => Ok(Route::Local), + } } pub fn current_hop(&self, current_chain: &TruncatedChainId) -> StdResult { @@ -95,8 +106,6 @@ impl Header { } } -pub type Route = AccountTrace; - #[non_exhaustive] #[cosmwasm_schema::cw_serde] pub enum Recipient { diff --git a/packages/ibcmail/src/server/api.rs b/packages/ibcmail/src/server/api.rs index 7342698..1776336 100644 --- a/packages/ibcmail/src/server/api.rs +++ b/packages/ibcmail/src/server/api.rs @@ -10,7 +10,7 @@ use cosmwasm_std::{CosmosMsg, Deps, Uint128}; use crate::{ server::msg::{ServerExecuteMsg, ServerQueryMsg}, - IbcMailMessage, Route, IBCMAIL_SERVER_ID, + ClientMetadata, Header, IbcMailMessage, Route, IBCMAIL_SERVER_ID, }; // API for Abstract SDK users @@ -49,10 +49,15 @@ impl<'a, T: ServerInterface> MailServer<'a, T> { pub fn process_msg( &self, - msg: IbcMailMessage, - route: Option, + message: IbcMailMessage, + header: Header, + metadata: Option, ) -> AbstractSdkResult { - self.request(ServerExecuteMsg::ProcessMessage { msg, route }) + self.request(ServerExecuteMsg::ProcessMessage { + message, + header, + metadata, + }) } } diff --git a/packages/ibcmail/src/server/error.rs b/packages/ibcmail/src/server/error.rs index 373bd2a..5bf94f9 100644 --- a/packages/ibcmail/src/server/error.rs +++ b/packages/ibcmail/src/server/error.rs @@ -1,4 +1,5 @@ use crate::MessageHash; +use abstract_adapter::objects::AccountId; use abstract_adapter::std::ibc::ModuleIbcInfo; use abstract_adapter::{ sdk::AbstractSdkError, std::AbstractError, AdapterError as AbstractAdapterError, @@ -49,4 +50,10 @@ pub enum ServerError { #[error("No sending account")] NoSenderAccount, + + #[error("Mismatched sender. Expected: {expected:?}, Actual: {actual:?}")] + MismatchedSender { + expected: AccountId, + actual: AccountId, + }, } diff --git a/packages/ibcmail/src/server/msg.rs b/packages/ibcmail/src/server/msg.rs index 2e6ccfb..4887d23 100644 --- a/packages/ibcmail/src/server/msg.rs +++ b/packages/ibcmail/src/server/msg.rs @@ -1,6 +1,9 @@ use cosmwasm_schema::QueryResponses; -use crate::{server::ServerAdapter, DeliveryStatus, Header, IbcMailMessage, MessageHash, Route}; +use crate::{ + server::ServerAdapter, ClientMetadata, DeliveryStatus, Header, IbcMailMessage, MessageHash, + Route, ServerMetadata, +}; // This is used for type safety and re-exporting the contract endpoint structs. abstract_adapter::adapter_msg_types!(ServerAdapter, ServerExecuteMsg, ServerQueryMsg); @@ -14,8 +17,9 @@ pub struct ServerInstantiateMsg {} pub enum ServerExecuteMsg { /// Process a message sent by the client ProcessMessage { - msg: IbcMailMessage, - route: Option, + message: IbcMailMessage, + header: Header, + metadata: Option, }, } @@ -53,7 +57,11 @@ impl ServerMessage { #[cosmwasm_schema::cw_serde] pub enum ServerIbcMessage { /// Route a message - RouteMessage { msg: ServerMessage, header: Header }, + RouteMessage { + msg: ServerMessage, + header: Header, + metadata: ServerMetadata, + }, } /// App execute messages diff --git a/packages/ibcmail/src/server/state.rs b/packages/ibcmail/src/server/state.rs index d5c0fe9..cef6262 100644 --- a/packages/ibcmail/src/server/state.rs +++ b/packages/ibcmail/src/server/state.rs @@ -1,6 +1,7 @@ -use crate::{Header, MessageHash}; +use crate::{Header, MessageHash, ServerMetadata}; use abstract_app::objects::TruncatedChainId; use cw_storage_plus::{Item, Map}; pub const AWAITING: Map<&MessageHash, TruncatedChainId> = Map::new("awaiting"); -pub const AWAITING_DELIVERY: Item> = Item::new("awaiting_delivery"); +pub const AWAITING_DELIVERY: Item> = + Item::new("awaiting_delivery"); diff --git a/tests/src/bin/demo.rs b/tests/src/bin/demo.rs index b28ae82..3021b6f 100644 --- a/tests/src/bin/demo.rs +++ b/tests/src/bin/demo.rs @@ -9,7 +9,7 @@ use cw_orch_interchain::{ChannelCreationValidator, DaemonInterchainEnv, Intercha use networks::{HARPOON_4, PION_1}; use client::ClientInterface; -use ibcmail::{client::msg::ClientExecuteMsgFns, Message}; +use ibcmail::{client::msg::ClientExecuteMsgFns, ClientMetadata, Message}; use tests::TEST_NAMESPACE; const SRC: ChainInfo = PION_1; @@ -44,9 +44,9 @@ fn test() -> anyhow::Result<()> { let send = src_client.send_message( mail_msg, dst_acc.id()?.into(), - Some(AccountTrace::Remote(vec![TruncatedChainId::from_chain_id( - DST.chain_id, - )])), + Some(ClientMetadata::new_with_route(AccountTrace::Remote(vec![ + TruncatedChainId::from_chain_id(DST.chain_id), + ]))), )?; interchain.await_and_check_packets(SRC.chain_id, send)?; diff --git a/tests/src/bin/full_demo.rs b/tests/src/bin/full_demo.rs index 924f1b4..d6be15b 100644 --- a/tests/src/bin/full_demo.rs +++ b/tests/src/bin/full_demo.rs @@ -21,7 +21,7 @@ use cw_orch_interchain::{ChannelCreationValidator, DaemonInterchainEnv, Intercha use networks::{HARPOON_4, PION_1}; use client::ClientInterface; -use ibcmail::{client::msg::ClientExecuteMsgFns, Message, IBCMAIL_NAMESPACE}; +use ibcmail::{client::msg::ClientExecuteMsgFns, ClientMetadata, Message, IBCMAIL_NAMESPACE}; use tests::TEST_NAMESPACE; const SRC: ChainInfo = HARPOON_4; @@ -102,9 +102,9 @@ fn test() -> anyhow::Result<()> { let send = dst_client.send_message( Message::new("test-subject", "test-body"), src_acc.id()?.into(), - Some(AccountTrace::Remote(vec![TruncatedChainId::from_chain_id( - SRC.chain_id, - )])), + Some(ClientMetadata::new_with_route(AccountTrace::Remote(vec![ + TruncatedChainId::from_chain_id(SRC.chain_id), + ]))), )?; interchain.await_and_check_packets(DST.chain_id, send)?; diff --git a/tests/src/client.rs b/tests/src/client.rs index f407fad..f5cd849 100644 --- a/tests/src/client.rs +++ b/tests/src/client.rs @@ -82,17 +82,18 @@ fn create_server_test_msg(from: AccountId, to: AccountId) -> IbcMailMessage { }, timestamp: Default::default(), version: "0.0.1".to_string(), + reply_to: None, } } fn temp_ibc_mail_msg_to_header(msg: IbcMailMessage, route: Route) -> Header { Header { - route, recipient: msg.recipient.clone(), id: msg.id.clone(), version: msg.version.clone(), sender: msg.sender.clone(), timestamp: msg.timestamp, + reply_to: msg.reply_to, } } @@ -171,7 +172,9 @@ mod send_msg { use abstract_interface::Abstract; use cw_orch_interchain::{InterchainEnv, MockBech32InterchainEnv}; - use ibcmail::{server::error::ServerError, Message, MessageKind, Route, IBCMAIL_CLIENT_ID}; + use ibcmail::{ + server::error::ServerError, ClientMetadata, Message, MessageKind, Route, IBCMAIL_CLIENT_ID, + }; use super::*; @@ -357,9 +360,9 @@ mod send_msg { AccountId::local(420), Some(TruncatedChainId::from_string("juno".into())?), ), - Some(Route::Remote(vec![TruncatedChainId::from_string( - "juno".into(), - )?])), + Some(ClientMetadata::new_with_route(Route::Remote(vec![ + TruncatedChainId::from_string("juno".into())?, + ]))), ); assert_that!(res).is_ok(); @@ -426,10 +429,10 @@ mod send_msg { neutron_client.account().id()?, Some(TruncatedChainId::from_string("neutron".into())?), ), - Some(AccountTrace::Remote(vec![ + Some(ClientMetadata::new_with_route(AccountTrace::Remote(vec![ "juno".parse()?, TruncatedChainId::from_str("neutron")?, - ])), + ]))), )?; interchain.await_and_check_packets("archway-1", res.clone())?; From ef84a625347ac698344fba7791eaf14c4b9ffa93 Mon Sep 17 00:00:00 2001 From: adairrr <32375605+adairrr@users.noreply.github.com> Date: Sun, 4 Aug 2024 22:31:20 +0200 Subject: [PATCH 09/12] Refactor away IbcMailMessage --- contracts/client/src/handlers/execute.rs | 45 ++++----- contracts/client/src/handlers/query.rs | 72 +++++++------- contracts/server/src/handlers/execute.rs | 18 ++-- contracts/server/src/handlers/ibc_callback.rs | 12 +-- packages/ibcmail/src/client/api.rs | 15 ++- packages/ibcmail/src/client/msg.rs | 36 +++---- packages/ibcmail/src/client/state.rs | 6 +- packages/ibcmail/src/lib.rs | 25 +++-- packages/ibcmail/src/server/api.rs | 4 +- packages/ibcmail/src/server/msg.rs | 17 +--- tests/src/bin/demo.rs | 4 +- tests/src/bin/full_demo.rs | 4 +- tests/src/client.rs | 94 +++++++++---------- 13 files changed, 170 insertions(+), 182 deletions(-) diff --git a/contracts/client/src/handlers/execute.rs b/contracts/client/src/handlers/execute.rs index bf6a298..5b2db44 100644 --- a/contracts/client/src/handlers/execute.rs +++ b/contracts/client/src/handlers/execute.rs @@ -17,8 +17,8 @@ use ibcmail::{ ClientApp, }, server::api::{MailServer, ServerInterface}, - ClientMetadata, DeliveryStatus, Header, IbcMailMessage, Message, MessageHash, Recipient, - Sender, IBCMAIL_SERVER_ID, + ClientMetadata, DeliveryStatus, Header, MailMessage, MessageHash, ReceivedMessage, Recipient, + Sender, ServerMetadata, IBCMAIL_SERVER_ID, }; // # ANCHOR: execute_handler @@ -35,9 +35,7 @@ pub fn execute_handler( recipient, metadata, } => send_msg(deps, env, info, app, message, recipient, metadata), - ClientExecuteMsg::ReceiveMessage { message, header } => { - receive_msg(deps, info, app, message, header) - } + ClientExecuteMsg::ReceiveMessage(message) => receive_msg(deps, info, app, message), ClientExecuteMsg::UpdateDeliveryStatus { id, status } => { update_delivery_status(deps, info, app, id, status) } @@ -51,12 +49,12 @@ fn send_msg( env: Env, _info: MessageInfo, app: ClientApp, - msg: Message, + message: MailMessage, recipient: Recipient, metadata: Option, ) -> ClientResult { // validate basic fields of message, construct message to send to server - let to_hash = format!("{:?}{:?}{:?}", env.block.time, msg.subject, recipient); + let to_hash = format!("{:?}{:?}{:?}", env.block.time, message.subject, recipient); let hash = ::digest(to_hash); let base_64_hash = BASE64_STANDARD.encode(hash); @@ -66,32 +64,23 @@ fn send_msg( ); let version = app.version().to_string(); - let to_send = IbcMailMessage { - id: base_64_hash.clone(), - sender: sender.clone(), - recipient: recipient.clone(), - message: Message { - subject: msg.subject, - body: msg.body, - }, - timestamp: env.block.time, - version: version.clone(), - reply_to: None, - }; - let client_header = Header { sender, recipient, id: base_64_hash, - version: version, + version, timestamp: env.block.time, reply_to: None, }; - SENT.save(deps.storage, to_send.id.clone(), &to_send)?; + SENT.save( + deps.storage, + client_header.id.clone(), + &(message.clone(), client_header.clone()), + )?; let server: MailServer<_> = app.mail_server(deps.as_ref()); - let route_msg: CosmosMsg = server.process_msg(to_send, client_header, metadata)?; + let route_msg: CosmosMsg = server.process_msg(message, client_header, metadata)?; Ok(app.response("send").add_message(route_msg)) } @@ -103,17 +92,17 @@ fn receive_msg( deps: DepsMut, info: MessageInfo, app: App, - msg: IbcMailMessage, - header: Header, + received: ReceivedMessage, ) -> ClientResult { ensure_server_sender(deps.as_ref(), &app, info.sender)?; - ensure_correct_recipient(deps.as_ref(), &header.recipient, &app)?; + ensure_correct_recipient(deps.as_ref(), &received.header.recipient, &app)?; - RECEIVED.save(deps.storage, msg.id.clone(), &msg)?; + let msg_id = received.header.id.clone(); + RECEIVED.save(deps.storage, msg_id.clone(), &received)?; Ok(app .response("received") - .add_attribute("message_id", &msg.id)) + .add_attribute("message_id", &msg_id)) } // # ANCHOR_END: receive_msg diff --git a/contracts/client/src/handlers/query.rs b/contracts/client/src/handlers/query.rs index f10826f..8aee7d5 100644 --- a/contracts/client/src/handlers/query.rs +++ b/contracts/client/src/handlers/query.rs @@ -1,20 +1,20 @@ +use crate::{ + contract::{App, ClientResult}, + msg::ClientQueryMsg, +}; use abstract_app::sdk::cw_helpers::load_many; use cosmwasm_std::{to_json_binary, Binary, Deps, Env}; use cw_storage_plus::Bound; +use ibcmail::client::msg::SentMessagesResponse; use ibcmail::{ client::{ error::ClientError, - msg::{MessageFilter, MessagesResponse}, + msg::{MessageFilter, ReceivedMessagesResponse}, state::{RECEIVED, SENT}, }, MessageHash, MessageKind, }; -use crate::{ - contract::{App, ClientResult}, - msg::ClientQueryMsg, -}; - pub fn query_handler( deps: Deps, _env: Env, @@ -22,17 +22,20 @@ pub fn query_handler( msg: ClientQueryMsg, ) -> ClientResult { match msg { - ClientQueryMsg::Messages { kind: status, ids } => { - to_json_binary(&query_messages(deps, status, ids)?) + ClientQueryMsg::ReceivedMessages { ids } => { + to_json_binary(&query_received_messages(deps, ids)?) } - ClientQueryMsg::ListMessages { - kind: status, + ClientQueryMsg::ListSentMessages { + filter, + start_after, + limit, + } => to_json_binary(&query_sent_messages_list(deps, filter, start_after, limit)?), + ClientQueryMsg::ListReceivedMessages { filter, start_after, limit, - } => to_json_binary(&query_messages_list( + } => to_json_binary(&query_received_messages_list( deps, - status, filter, start_after, limit, @@ -41,43 +44,46 @@ pub fn query_handler( .map_err(Into::into) } -fn query_messages( +fn query_received_messages( deps: Deps, - kind: MessageKind, ids: Vec, -) -> ClientResult { - let map = match kind { - MessageKind::Received => RECEIVED, - MessageKind::Sent => SENT, - _ => return Err(ClientError::NotImplemented("message type".to_string())), - }; - - let messages = load_many(map, deps.storage, ids)?; +) -> ClientResult { + let messages = load_many(RECEIVED, deps.storage, ids)?; let messages = messages.into_iter().map(|(_, m)| m).collect(); - Ok(MessagesResponse { messages }) + Ok(ReceivedMessagesResponse { messages }) } -fn query_messages_list( +fn query_sent_messages_list( deps: Deps, - status: MessageKind, _filter: Option, start: Option, limit: Option, -) -> ClientResult { - let map = match status { - MessageKind::Received => RECEIVED, - MessageKind::Sent => SENT, - _ => return Err(ClientError::NotImplemented("message type".to_string())), - }; +) -> ClientResult { + let messages = cw_paginate::paginate_map( + &SENT, + deps.storage, + start.as_ref().map(Bound::exclusive), + limit, + |_id, message| Ok::<_, ClientError>(message), + )?; + Ok(SentMessagesResponse { messages }) +} + +fn query_received_messages_list( + deps: Deps, + _filter: Option, + start: Option, + limit: Option, +) -> ClientResult { let messages = cw_paginate::paginate_map( - &map, + &RECEIVED, deps.storage, start.as_ref().map(Bound::exclusive), limit, |_id, message| Ok::<_, ClientError>(message), )?; - Ok(MessagesResponse { messages }) + Ok(ReceivedMessagesResponse { messages }) } diff --git a/contracts/server/src/handlers/execute.rs b/contracts/server/src/handlers/execute.rs index 5055c26..a253f54 100644 --- a/contracts/server/src/handlers/execute.rs +++ b/contracts/server/src/handlers/execute.rs @@ -23,7 +23,7 @@ use ibcmail::{ state::{AWAITING, AWAITING_DELIVERY}, ServerAdapter, }, - ClientMetadata, Header, IbcMailMessage, Recipient, Route, Sender, ServerMetadata, + ClientMetadata, Header, MailMessage, Recipient, Route, Sender, ServerMetadata, }; use crate::replies::DELIVER_MESSAGE_REPLY; @@ -87,13 +87,13 @@ fn process_message( env: Env, _info: MessageInfo, mut module: Adapter, - message: IbcMailMessage, + message: MailMessage, header: Header, metadata: Option, ) -> ServerResult { println!( - "processing message: {:?} with route {:?}", - message, metadata + "processing message: {:?} with header: {:?}, metadata {:?}", + message, header, metadata ); let current_chain = TruncatedChainId::new(&env); @@ -126,8 +126,8 @@ fn process_message( }) } else { // We weren't provided a route - println!("processing message recipient: {:?}", message.recipient); - match message.recipient.clone() { + println!("processing message recipient: {:?}", header.recipient); + match header.recipient.clone() { // TODO: add smarter routing Recipient::Account { id: _, chain } => Ok(chain.map_or(AccountTrace::Local, |chain| { if chain == current_chain { @@ -208,7 +208,7 @@ pub(crate) fn route_message( // Awaiting callback // Save that we're awaiting callbacks from dest chain onwards. - AWAITING.save(deps.storage, &message.id(), dest_chain)?; + AWAITING.save(deps.storage, &header.id, dest_chain)?; let msg = remote_server_msg( deps, @@ -238,13 +238,13 @@ fn route_to_local_account( match msg { ServerMessage::Mail { message } => { AWAITING_DELIVERY.update(deps.storage, |mut awaiting| -> StdResult> { - awaiting.push((message.id.clone(), header.clone(), metadata.clone())); + awaiting.push((header.id.clone(), header.clone(), metadata.clone())); Ok(awaiting) })?; let mail_client = get_recipient_mail_client(deps.as_ref(), app, &header.recipient)?; Ok(vec![SubMsg::reply_always( - mail_client.receive_msg(message, header)?, + mail_client.receive_msg(message, header, metadata)?, DELIVER_MESSAGE_REPLY, )]) } diff --git a/contracts/server/src/handlers/ibc_callback.rs b/contracts/server/src/handlers/ibc_callback.rs index 095e0ae..7ee491f 100644 --- a/contracts/server/src/handlers/ibc_callback.rs +++ b/contracts/server/src/handlers/ibc_callback.rs @@ -45,7 +45,7 @@ pub fn ibc_callback_handler( } => { println!( "ibc_callback_handler success route_msg id: {:?}, header: {:?}, metadata: {:?}", - msg.id(), + header.id, header, metadata ); @@ -74,7 +74,7 @@ pub fn ibc_callback_handler( } => { println!( "ibc_callback_handler execute error route_msg id: {:?}, header: {:?}, metadata: {:?}", - msg.id(), + header.id, header, metadata ); @@ -92,10 +92,10 @@ pub fn ibc_callback_handler( chain: current_chain.clone(), address: _env.contract.address.to_string(), }, - recipient: message.sender.clone().try_into()?, + recipient: header.sender.clone().try_into()?, // TODO: new message id - id: message.id.clone(), - version: message.version.clone(), + id: header.id.clone(), + version: header.version.clone(), timestamp: _env.block.time, reply_to: None, }; @@ -113,7 +113,7 @@ pub fn ibc_callback_handler( }; let status_message = ServerMessage::delivery_status( - msg.id(), + header.id, DeliveryFailure::Unknown(e).into(), ); execute::route_message( diff --git a/packages/ibcmail/src/client/api.rs b/packages/ibcmail/src/client/api.rs index 306cf0f..d6e1fdb 100644 --- a/packages/ibcmail/src/client/api.rs +++ b/packages/ibcmail/src/client/api.rs @@ -3,8 +3,8 @@ use abstract_app::sdk::AppInterface; use cosmwasm_std::{Addr, CosmosMsg, Deps}; use crate::{ - client::msg::ClientExecuteMsg, ClientMetadata, DeliveryStatus, Header, IbcMailMessage, Message, - MessageHash, Recipient, IBCMAIL_CLIENT_ID, + client::msg::ClientExecuteMsg, ClientMetadata, DeliveryStatus, Header, MailMessage, + MessageHash, ReceivedMessage, Recipient, ServerMetadata, IBCMAIL_CLIENT_ID, }; // API for Abstract SDK users @@ -50,7 +50,7 @@ impl<'a, T: ClientInterface> MailClient<'a, T> { pub fn send_msg( &self, recipient: Recipient, - message: Message, + message: MailMessage, metadata: Option, ) -> AbstractSdkResult { self.request(ClientExecuteMsg::SendMessage { @@ -63,10 +63,15 @@ impl<'a, T: ClientInterface> MailClient<'a, T> { /// Receive message pub fn receive_msg( &self, - message: IbcMailMessage, + message: MailMessage, header: Header, + metadata: ServerMetadata, ) -> AbstractSdkResult { - self.request(ClientExecuteMsg::ReceiveMessage { message, header }) + self.request(ClientExecuteMsg::ReceiveMessage(ReceivedMessage { + message, + header, + metadata, + })) } /// Receive message diff --git a/packages/ibcmail/src/client/msg.rs b/packages/ibcmail/src/client/msg.rs index 03ce5ef..90f18ed 100644 --- a/packages/ibcmail/src/client/msg.rs +++ b/packages/ibcmail/src/client/msg.rs @@ -1,8 +1,8 @@ use cosmwasm_schema::QueryResponses; use crate::{ - client::ClientApp, ClientMetadata, DeliveryStatus, Header, IbcMailMessage, Message, - MessageHash, MessageKind, Recipient, Route, Sender, + client::ClientApp, ClientMetadata, DeliveryStatus, Header, MailMessage, MessageHash, + MessageKind, ReceivedMessage, Recipient, Sender, ServerMetadata, }; // This is used for type safety and re-exporting the contract endpoint structs. @@ -19,10 +19,7 @@ pub struct ClientInstantiateMsg {} #[cw_orch(impl_into(ExecuteMsg))] pub enum ClientExecuteMsg { /// Receive a message from the server. - ReceiveMessage { - header: Header, - message: IbcMailMessage, - }, + ReceiveMessage(ReceivedMessage), /// Update the status of a message. only callable by the server UpdateDeliveryStatus { id: MessageHash, @@ -31,7 +28,7 @@ pub enum ClientExecuteMsg { /// Send a message SendMessage { recipient: Recipient, - message: Message, + message: MailMessage, metadata: Option, }, } @@ -43,18 +40,20 @@ pub enum ClientExecuteMsg { #[cw_orch(impl_into(QueryMsg))] #[derive(QueryResponses)] pub enum ClientQueryMsg { - #[returns(MessagesResponse)] - ListMessages { - kind: MessageKind, + #[returns(SentMessagesResponse)] + ListSentMessages { filter: Option, limit: Option, start_after: Option, }, - #[returns(MessagesResponse)] - Messages { - kind: MessageKind, - ids: Vec, + #[returns(ReceivedMessagesResponse)] + ListReceivedMessages { + filter: Option, + limit: Option, + start_after: Option, }, + #[returns(ReceivedMessagesResponse)] + ReceivedMessages { ids: Vec }, } #[cosmwasm_schema::cw_serde] @@ -69,6 +68,11 @@ pub struct AppMigrateMsg {} pub struct ConfigResponse {} #[cosmwasm_schema::cw_serde] -pub struct MessagesResponse { - pub messages: Vec, +pub struct SentMessagesResponse { + pub messages: Vec<(MailMessage, Header)>, +} + +#[cosmwasm_schema::cw_serde] +pub struct ReceivedMessagesResponse { + pub messages: Vec, } diff --git a/packages/ibcmail/src/client/state.rs b/packages/ibcmail/src/client/state.rs index a8f3259..5bbc31a 100644 --- a/packages/ibcmail/src/client/state.rs +++ b/packages/ibcmail/src/client/state.rs @@ -1,10 +1,10 @@ use cw_storage_plus::Map; -use crate::{DeliveryStatus, IbcMailMessage, MessageHash}; +use crate::{DeliveryStatus, Header, MailMessage, MessageHash, ReceivedMessage}; // TODO: use an indexed map in the future -pub const RECEIVED: Map = Map::new("received"); -pub const SENT: Map = Map::new("sent"); +pub const RECEIVED: Map = Map::new("received"); +pub const SENT: Map = Map::new("sent"); pub const STATUS: Map = Map::new("status"); /// Set of features supported by the client diff --git a/packages/ibcmail/src/lib.rs b/packages/ibcmail/src/lib.rs index 713736e..b2f589d 100644 --- a/packages/ibcmail/src/lib.rs +++ b/packages/ibcmail/src/lib.rs @@ -26,13 +26,20 @@ pub type MessageHash = String; /// Struct representing new message to send to another client // # ANCHOR: message #[cosmwasm_schema::cw_serde] -pub struct Message { +pub struct MailMessage { pub subject: String, pub body: String, } // # ANCHOR_END: message -impl Message { +#[cosmwasm_schema::cw_serde] +pub struct ReceivedMessage { + pub message: MailMessage, + pub header: Header, + pub metadata: ServerMetadata, +} + +impl MailMessage { pub fn new(subject: impl Into, body: impl Into) -> Self { Self { subject: subject.into(), @@ -40,18 +47,6 @@ impl Message { } } } - -#[cosmwasm_schema::cw_serde] -pub struct IbcMailMessage { - pub id: MessageHash, - pub sender: Sender, - pub recipient: Recipient, - pub version: String, - pub timestamp: Timestamp, - pub message: Message, - pub reply_to: Option, -} - #[cosmwasm_schema::cw_serde] pub struct Header { pub sender: Sender, @@ -64,6 +59,7 @@ pub struct Header { pub type Route = AccountTrace; +/// Metadata that can be set optionally by the client when they send a message #[derive(Default)] #[cosmwasm_schema::cw_serde] pub struct ClientMetadata { @@ -76,6 +72,7 @@ impl ClientMetadata { } } +/// Metadata used by the server for routing or other means #[cosmwasm_schema::cw_serde] pub struct ServerMetadata { pub route: Route, diff --git a/packages/ibcmail/src/server/api.rs b/packages/ibcmail/src/server/api.rs index 1776336..02c0906 100644 --- a/packages/ibcmail/src/server/api.rs +++ b/packages/ibcmail/src/server/api.rs @@ -10,7 +10,7 @@ use cosmwasm_std::{CosmosMsg, Deps, Uint128}; use crate::{ server::msg::{ServerExecuteMsg, ServerQueryMsg}, - ClientMetadata, Header, IbcMailMessage, Route, IBCMAIL_SERVER_ID, + ClientMetadata, Header, MailMessage, IBCMAIL_SERVER_ID, }; // API for Abstract SDK users @@ -49,7 +49,7 @@ impl<'a, T: ServerInterface> MailServer<'a, T> { pub fn process_msg( &self, - message: IbcMailMessage, + message: MailMessage, header: Header, metadata: Option, ) -> AbstractSdkResult { diff --git a/packages/ibcmail/src/server/msg.rs b/packages/ibcmail/src/server/msg.rs index 4887d23..1cb7dc7 100644 --- a/packages/ibcmail/src/server/msg.rs +++ b/packages/ibcmail/src/server/msg.rs @@ -1,8 +1,8 @@ use cosmwasm_schema::QueryResponses; use crate::{ - server::ServerAdapter, ClientMetadata, DeliveryStatus, Header, IbcMailMessage, MessageHash, - Route, ServerMetadata, + server::ServerAdapter, ClientMetadata, DeliveryStatus, Header, MailMessage, MessageHash, + ServerMetadata, }; // This is used for type safety and re-exporting the contract endpoint structs. @@ -17,7 +17,7 @@ pub struct ServerInstantiateMsg {} pub enum ServerExecuteMsg { /// Process a message sent by the client ProcessMessage { - message: IbcMailMessage, + message: MailMessage, header: Header, metadata: Option, }, @@ -27,7 +27,7 @@ pub enum ServerExecuteMsg { #[cosmwasm_schema::cw_serde] pub enum ServerMessage { Mail { - message: IbcMailMessage, + message: MailMessage, }, DeliveryStatus { id: MessageHash, @@ -36,14 +36,7 @@ pub enum ServerMessage { } impl ServerMessage { - pub fn id(&self) -> MessageHash { - match self { - ServerMessage::Mail { message } => message.id.clone(), - ServerMessage::DeliveryStatus { id, .. } => id.clone(), - } - } - - pub fn mail(message: IbcMailMessage) -> Self { + pub fn mail(message: MailMessage) -> Self { ServerMessage::Mail { message } } diff --git a/tests/src/bin/demo.rs b/tests/src/bin/demo.rs index 3021b6f..e4b9c3c 100644 --- a/tests/src/bin/demo.rs +++ b/tests/src/bin/demo.rs @@ -9,7 +9,7 @@ use cw_orch_interchain::{ChannelCreationValidator, DaemonInterchainEnv, Intercha use networks::{HARPOON_4, PION_1}; use client::ClientInterface; -use ibcmail::{client::msg::ClientExecuteMsgFns, ClientMetadata, Message}; +use ibcmail::{client::msg::ClientExecuteMsgFns, ClientMetadata, MailMessage}; use tests::TEST_NAMESPACE; const SRC: ChainInfo = PION_1; @@ -39,7 +39,7 @@ fn test() -> anyhow::Result<()> { .namespace(Namespace::new(TEST_NAMESPACE)?) .build()?; - let mail_msg = Message::new("test-subject", "test-body"); + let mail_msg = MailMessage::new("test-subject", "test-body"); let send = src_client.send_message( mail_msg, diff --git a/tests/src/bin/full_demo.rs b/tests/src/bin/full_demo.rs index d6be15b..2bd40be 100644 --- a/tests/src/bin/full_demo.rs +++ b/tests/src/bin/full_demo.rs @@ -21,7 +21,7 @@ use cw_orch_interchain::{ChannelCreationValidator, DaemonInterchainEnv, Intercha use networks::{HARPOON_4, PION_1}; use client::ClientInterface; -use ibcmail::{client::msg::ClientExecuteMsgFns, ClientMetadata, Message, IBCMAIL_NAMESPACE}; +use ibcmail::{client::msg::ClientExecuteMsgFns, ClientMetadata, MailMessage, IBCMAIL_NAMESPACE}; use tests::TEST_NAMESPACE; const SRC: ChainInfo = HARPOON_4; @@ -100,7 +100,7 @@ fn test() -> anyhow::Result<()> { // )?; let send = dst_client.send_message( - Message::new("test-subject", "test-body"), + MailMessage::new("test-subject", "test-body"), src_acc.id()?.into(), Some(ClientMetadata::new_with_route(AccountTrace::Remote(vec![ TruncatedChainId::from_chain_id(SRC.chain_id), diff --git a/tests/src/client.rs b/tests/src/client.rs index f5cd849..b44e0d3 100644 --- a/tests/src/client.rs +++ b/tests/src/client.rs @@ -1,13 +1,14 @@ use abstract_app::objects::{namespace::Namespace, AccountId}; use abstract_client::{AbstractClient, Application}; +use cosmwasm_schema::schemars::schema::Metadata; use cw_orch::{anyhow, prelude::*}; use speculoos::prelude::*; // Use prelude to get all the necessary imports use client::{contract::interface::ClientInterface, msg::ClientInstantiateMsg, *}; use ibcmail::{ - server::msg::ServerInstantiateMsg, Header, IbcMailMessage, Message, Recipient, Route, Sender, - IBCMAIL_NAMESPACE, IBCMAIL_SERVER_ID, + server::msg::ServerInstantiateMsg, Header, MailMessage, ReceivedMessage, Recipient, Route, + Sender, ServerMetadata, IBCMAIL_NAMESPACE, IBCMAIL_SERVER_ID, }; use server::ServerInterface; @@ -71,29 +72,21 @@ impl TestEnv { } } -fn create_server_test_msg(from: AccountId, to: AccountId) -> IbcMailMessage { - IbcMailMessage { - id: "test-id".to_string(), - sender: Sender::account(from.clone(), None), - recipient: Recipient::account(to.clone(), None), - message: Message { +fn create_received_message(from: AccountId, to: AccountId, route: Route) -> ReceivedMessage { + ReceivedMessage { + header: Header { + sender: Sender::account(from.clone(), None), + recipient: Recipient::account(to.clone(), None), + id: "test-id".to_string(), + version: "0.0.1".to_string(), + timestamp: Default::default(), + reply_to: None, + }, + message: MailMessage { subject: "test-subject".to_string(), body: "test-body".to_string(), }, - timestamp: Default::default(), - version: "0.0.1".to_string(), - reply_to: None, - } -} - -fn temp_ibc_mail_msg_to_header(msg: IbcMailMessage, route: Route) -> Header { - Header { - recipient: msg.recipient.clone(), - id: msg.id.clone(), - version: msg.version.clone(), - sender: msg.sender.clone(), - timestamp: msg.timestamp, - reply_to: msg.reply_to, + metadata: ServerMetadata { route }, } } @@ -121,7 +114,11 @@ mod receive_msg { server_account_id, app_account_id ); - let msg = create_server_test_msg(server_account_id.clone(), app_account_id.clone()); + let received = create_received_message( + server_account_id.clone(), + app_account_id.clone(), + Route::Local, + ); let server_addr = app .account() .module_addresses(vec![IBCMAIL_SERVER_ID.into()])? @@ -130,14 +127,11 @@ mod receive_msg { .clone(); println!("app_account_id: {:?}", app.account().id()); - let res = app.call_as(&server_addr).receive_message( - temp_ibc_mail_msg_to_header(msg.clone(), Route::Local), - msg.clone(), - ); + let res = app.call_as(&server_addr).receive_message(received.clone()); assert_that!(res).is_ok(); - let messages = app.list_messages(MessageKind::Received, None, None, None)?; + let messages = app.list_received_messages(None, None, None)?; assert_that!(messages.messages).has_length(1); Ok(()) @@ -152,8 +146,9 @@ mod receive_msg { let app_account_id = app.account().id().unwrap(); - let msg = create_server_test_msg(app_account_id.clone(), app_account_id.clone()); - let res = app.receive_message(temp_ibc_mail_msg_to_header(msg.clone(), Route::Local), msg); + let msg = + create_received_message(app_account_id.clone(), app_account_id.clone(), Route::Local); + let res = app.receive_message(msg); assert_that!(res) .is_err() @@ -173,7 +168,8 @@ mod send_msg { use cw_orch_interchain::{InterchainEnv, MockBech32InterchainEnv}; use ibcmail::{ - server::error::ServerError, ClientMetadata, Message, MessageKind, Route, IBCMAIL_CLIENT_ID, + server::error::ServerError, ClientMetadata, MailMessage, MessageKind, Route, + IBCMAIL_CLIENT_ID, }; use super::*; @@ -187,7 +183,7 @@ mod send_msg { let client2 = env.client2; let recipient = Recipient::account(client2.account().id()?, None); - let msg = Message::new("test-subject", "test-body"); + let msg = MailMessage::new("test-subject", "test-body"); let res = client1.send_message(msg, recipient, None); @@ -205,14 +201,12 @@ mod send_msg { let client2 = env.client2; let recipient = Recipient::account(client2.account().id()?, None); - let msg = Message::new("test-subject", "test-body"); + let msg = MailMessage::new("test-subject", "test-body"); let res = client1.send_message(msg, recipient, None); assert_that!(res).is_ok(); - let received_messages = client2 - .list_messages(MessageKind::Received, None, None, None)? - .messages; + let received_messages = client2.list_received_messages(None, None, None)?.messages; assert_that!(received_messages).has_length(1); Ok(()) @@ -232,7 +226,7 @@ mod send_msg { .version_control() .claim_namespace(client2.account().id()?, namespace.to_string())?; - let msg = Message::new("test-subject", "test-body"); + let msg = MailMessage::new("test-subject", "test-body"); let res = client1.send_message(msg, Recipient::namespace(namespace.try_into()?, None), None); @@ -250,7 +244,7 @@ mod send_msg { let bad_namespace: Namespace = "nope".try_into()?; - let msg = Message::new("test-subject", "test-body"); + let msg = MailMessage::new("test-subject", "test-body"); let res = client1.send_message(msg, Recipient::namespace(bad_namespace.clone(), None), None); @@ -279,7 +273,7 @@ mod send_msg { let juno_client = juno_env.client1; // the trait `From<&str>` is not implemented for `abstract_app::objects::chain_name::TruncatedChainId` - let arch_to_juno_msg = Message::new("test-subject", "test-body"); + let arch_to_juno_msg = MailMessage::new("test-subject", "test-body"); let res = arch_client.send_message( arch_to_juno_msg, @@ -294,7 +288,7 @@ mod send_msg { interchain.await_and_check_packets("archway-1", res?)?; - let arch_messages = arch_client.list_messages(MessageKind::Received, None, None, None)?; + let arch_messages = arch_client.list_received_messages(None, None, None)?; assert_that!(arch_messages.messages).is_empty(); let juno_client_1_module_addresses = juno_client @@ -323,15 +317,15 @@ mod send_msg { let juno_mail_client = ClientInterface::new(IBCMAIL_CLIENT_ID, juno_env.env.clone()); juno_mail_client.set_address(&juno_client_1_module_addresses.modules[0].1.clone()); let juno_mail_client_messages = - juno_mail_client.list_messages(MessageKind::Received, None, None, None)?; + juno_mail_client.list_received_messages(None, None, None)?; assert_that!(juno_mail_client_messages.messages).has_length(1); - let juno_messages = juno_client.list_messages(MessageKind::Received, None, None, None)?; + let juno_messages = juno_client.list_received_messages(None, None, None)?; assert_that!(juno_messages.messages).has_length(1); // Sanity check messages method - let juno_message_id = juno_messages.messages.first().cloned().unwrap().id; - let juno_message = juno_client.messages(vec![juno_message_id], MessageKind::Received)?; + let juno_message_id = juno_messages.messages.first().cloned().unwrap().header.id; + let juno_message = juno_client.received_messages(vec![juno_message_id])?; assert_that!(juno_message.messages).has_length(1); Ok(()) @@ -352,7 +346,7 @@ mod send_msg { let juno_client = juno_env.client1; // the trait `From<&str>` is not implemented for `abstract_app::objects::chain_name::TruncatedChainId` - let arch_to_juno_msg = Message::new("test-subject", "test-body"); + let arch_to_juno_msg = MailMessage::new("test-subject", "test-body"); let res = arch_client.send_message( arch_to_juno_msg, @@ -378,13 +372,13 @@ mod send_msg { assert_that!( arch_client - .list_messages(MessageKind::Received, None, None, None)? + .list_received_messages(None, None, None)? .messages ) .is_empty(); assert_that!( juno_client - .list_messages(MessageKind::Received, None, None, None)? + .list_received_messages(None, None, None)? .messages ) .is_empty(); @@ -421,7 +415,7 @@ mod send_msg { let neutron_client = neutron_env.client1; // the trait `From<&str>` is not implemented for `abstract_app::objects::chain_name::TruncatedChainId` - let arch_to_neutron_msg = Message::new("test-subject", "test-body"); + let arch_to_neutron_msg = MailMessage::new("test-subject", "test-body"); let res = arch_client.send_message( arch_to_neutron_msg, @@ -437,7 +431,7 @@ mod send_msg { interchain.await_and_check_packets("archway-1", res.clone())?; - let arch_messages = arch_client.list_messages(MessageKind::Received, None, None, None)?; + let arch_messages = arch_client.list_received_messages(None, None, None)?; assert_that!(arch_messages.messages).is_empty(); let neutron_client_1_module_addresses = neutron_client @@ -457,7 +451,7 @@ mod send_msg { let neutron_mail_client = ClientInterface::new(IBCMAIL_CLIENT_ID, neutron_env.env.clone()); neutron_mail_client.set_address(&neutron_client_1_module_addresses.modules[0].1.clone()); let neutron_mail_client_messages = - neutron_mail_client.list_messages(MessageKind::Received, None, None, None)?; + neutron_mail_client.list_received_messages(None, None, None)?; assert_that!(neutron_mail_client_messages.messages).has_length(1); // let juno_messages = neutron_client.list_messages(None, None, None)?; From 17b06494a34dda9b814bb0e0eb32899e5e08fabf Mon Sep 17 00:00:00 2001 From: adairrr <32375605+adairrr@users.noreply.github.com> Date: Sun, 4 Aug 2024 23:28:45 +0200 Subject: [PATCH 10/12] send cross-chain delivery status updates for account not found --- contracts/client/src/handlers/execute.rs | 4 +- contracts/client/src/handlers/query.rs | 15 +- contracts/server/src/handlers/execute.rs | 153 ++++++++++---- contracts/server/src/handlers/ibc_callback.rs | 1 + contracts/server/src/handlers/module_ibc.rs | 1 + contracts/server/src/replies/deliver_msg.rs | 39 +--- packages/ibcmail/src/client/msg.rs | 9 +- packages/ibcmail/src/client/state.rs | 2 +- packages/ibcmail/src/lib.rs | 7 + packages/ibcmail/src/server/error.rs | 5 +- packages/ibcmail/src/server/state.rs | 3 +- tests/src/client.rs | 196 ++++++++++++++---- 12 files changed, 316 insertions(+), 119 deletions(-) diff --git a/contracts/client/src/handlers/execute.rs b/contracts/client/src/handlers/execute.rs index 5b2db44..c27f85d 100644 --- a/contracts/client/src/handlers/execute.rs +++ b/contracts/client/src/handlers/execute.rs @@ -10,7 +10,7 @@ use abstract_app::{ }; use base64::prelude::*; use cosmwasm_std::{ensure_eq, Addr, CosmosMsg, Deps, DepsMut, Env, MessageInfo}; -use ibcmail::client::state::STATUS; +use ibcmail::client::state::SENT_STATUS; use ibcmail::{ client::{ state::{RECEIVED, SENT}, @@ -118,7 +118,7 @@ fn update_delivery_status( // ensure that the message exists SENT.load(deps.storage, id.clone()) .map_err(|_| ClientError::MessageNotFound(id.clone()))?; - STATUS.save(deps.storage, id.clone(), &status)?; + SENT_STATUS.save(deps.storage, id.clone(), &status)?; Ok(app .response("update_msg_status") diff --git a/contracts/client/src/handlers/query.rs b/contracts/client/src/handlers/query.rs index 8aee7d5..00ed951 100644 --- a/contracts/client/src/handlers/query.rs +++ b/contracts/client/src/handlers/query.rs @@ -6,13 +6,14 @@ use abstract_app::sdk::cw_helpers::load_many; use cosmwasm_std::{to_json_binary, Binary, Deps, Env}; use cw_storage_plus::Bound; use ibcmail::client::msg::SentMessagesResponse; +use ibcmail::client::state::SENT_STATUS; use ibcmail::{ client::{ error::ClientError, msg::{MessageFilter, ReceivedMessagesResponse}, state::{RECEIVED, SENT}, }, - MessageHash, MessageKind, + MessageHash, MessageKind, SentMessage, }; pub fn query_handler( @@ -68,7 +69,17 @@ fn query_sent_messages_list( |_id, message| Ok::<_, ClientError>(message), )?; - Ok(SentMessagesResponse { messages }) + let mut result = vec![]; + for (message, header) in messages { + let status = SENT_STATUS.load(deps.storage, header.id.clone())?; + result.push(SentMessage { + message, + header, + status, + }); + } + + Ok(SentMessagesResponse { messages: result }) } fn query_received_messages_list( diff --git a/contracts/server/src/handlers/execute.rs b/contracts/server/src/handlers/execute.rs index a253f54..a9a1aa6 100644 --- a/contracts/server/src/handlers/execute.rs +++ b/contracts/server/src/handlers/execute.rs @@ -23,7 +23,8 @@ use ibcmail::{ state::{AWAITING, AWAITING_DELIVERY}, ServerAdapter, }, - ClientMetadata, Header, MailMessage, Recipient, Route, Sender, ServerMetadata, + ClientMetadata, DeliveryFailure, DeliveryStatus, Header, MailMessage, MessageHash, Recipient, + Route, Sender, ServerMetadata, }; use crate::replies::DELIVER_MESSAGE_REPLY; @@ -34,7 +35,7 @@ use crate::{ // ANCHOR: execute_handler pub fn execute_handler( - deps: DepsMut, + mut deps: DepsMut, env: Env, info: MessageInfo, app: Adapter, @@ -83,7 +84,7 @@ fn check_sender( } fn process_message( - deps: DepsMut, + mut deps: DepsMut, env: Env, _info: MessageInfo, mut module: Adapter, @@ -163,12 +164,15 @@ fn process_message( reply_to: None, }; + let server_metadata = ServerMetadata { route }; + let msgs = route_message( - deps, + deps.branch(), + &env, &mut module, ¤t_chain, - header, - ServerMetadata { route }, + header.clone(), + server_metadata.clone(), ServerMessage::mail(message), )?; @@ -176,8 +180,9 @@ fn process_message( } pub(crate) fn route_message( - deps: DepsMut, - app: &mut ServerAdapter, + mut deps: DepsMut, + env: &Env, + module: &mut ServerAdapter, current_chain: &TruncatedChainId, header: Header, metadata: ServerMetadata, @@ -187,41 +192,72 @@ pub(crate) fn route_message( let current_hop = metadata.current_hop(current_chain)?; - match metadata.route { - AccountTrace::Local => route_to_local_account(deps, app, message, header, metadata), + let branched_deps = deps.branch(); + + let routing = match metadata.route { + AccountTrace::Local => route_to_local_account( + branched_deps, + module, + message, + header.clone(), + metadata.clone(), + ), AccountTrace::Remote(ref chains) => { println!("routing to chains: {:?}", chains); // check index of hop. If we are on the final hop, route to local account if current_hop == (chains.len() - 1) as u32 { println!("routing to local account: {:?}", chains.last().unwrap()); - return route_to_local_account(deps, app, message.clone(), header, metadata); - } - // TODO verify that the chain is a valid chain + route_to_local_account( + branched_deps, + module, + message.clone(), + header.clone(), + metadata.clone(), + ) + } else { + // TODO verify that the chain is a valid chain + let dest_chain = + chains + .get(current_hop as usize + 1) + .ok_or(ServerError::InvalidRoute { + route: metadata.route.clone(), + hop: current_hop, + })?; - let dest_chain = - chains - .get(current_hop as usize + 1) - .ok_or(ServerError::InvalidRoute { - route: metadata.route.clone(), - hop: current_hop, - })?; + // Awaiting callback + // Save that we're awaiting callbacks from dest chain onwards. + AWAITING.save(branched_deps.storage, &header.id, dest_chain)?; - // Awaiting callback - // Save that we're awaiting callbacks from dest chain onwards. - AWAITING.save(deps.storage, &header.id, dest_chain)?; + let msg = remote_server_msg( + branched_deps, + module, + &ServerIbcMessage::RouteMessage { + msg: message, + header: header.clone(), + metadata: metadata.clone(), + }, + dest_chain, + )?; + Ok::, ServerError>(vec![SubMsg::new(msg)]) + } + } + }; - let msg = remote_server_msg( + // ensure that the route is valid, otherwise send a status update + match routing { + Ok(msgs) => Ok(msgs), + Err(e) => match e { + ServerError::DeliveryFailure(delivery_failure) => send_delivery_status( deps, - app, - &ServerIbcMessage::RouteMessage { - msg: message, - header: header.clone(), - metadata: metadata.clone(), - }, - dest_chain, - )?; - Ok::, ServerError>(vec![SubMsg::new(msg)]) - } + &env, + module, + ¤t_chain, + header, + metadata, + delivery_failure.into(), + ), + _ => return Err(e), + }, } } @@ -238,11 +274,13 @@ fn route_to_local_account( match msg { ServerMessage::Mail { message } => { AWAITING_DELIVERY.update(deps.storage, |mut awaiting| -> StdResult> { - awaiting.push((header.id.clone(), header.clone(), metadata.clone())); + awaiting.push((header.clone(), metadata.clone())); Ok(awaiting) })?; - let mail_client = get_recipient_mail_client(deps.as_ref(), app, &header.recipient)?; + let mail_client = get_recipient_mail_client(deps.as_ref(), app, &header.recipient) + .map_err(|e| DeliveryFailure::RecipientNotFound)?; + Ok(vec![SubMsg::reply_always( mail_client.receive_msg(message, header, metadata)?, DELIVER_MESSAGE_REPLY, @@ -321,3 +359,46 @@ fn remote_server_msg( // ANCHOR_END: ibc_client Ok(msg) } + +/// Send a delivery status update to the +pub(crate) fn send_delivery_status( + deps: DepsMut, + env: &Env, + module: &mut ServerAdapter, + current_chain: &TruncatedChainId, + origin_header: Header, + origin_metadata: ServerMetadata, + delivery_status: DeliveryStatus, +) -> Result, ServerError> { + let message_id = origin_header.id.clone(); + let delivery_message = ServerMessage::delivery_status(message_id.clone(), delivery_status); + + let delivery_header = Header { + sender: Sender::Server { + address: env.contract.address.to_string(), + chain: TruncatedChainId::new(&env), + }, + recipient: origin_header.sender.try_into()?, + // TODO: new ID? + id: message_id.clone(), + // TODO: version? + version: origin_header.version, + timestamp: env.block.time, + reply_to: None, + }; + + let delivery_metadata = ServerMetadata { + route: origin_metadata.reverse_route()?, + }; + + let msg = route_message( + deps, + &env, + module, + ¤t_chain, + delivery_header, + delivery_metadata, + delivery_message, + )?; + Ok(msg) +} diff --git a/contracts/server/src/handlers/ibc_callback.rs b/contracts/server/src/handlers/ibc_callback.rs index 7ee491f..a796269 100644 --- a/contracts/server/src/handlers/ibc_callback.rs +++ b/contracts/server/src/handlers/ibc_callback.rs @@ -118,6 +118,7 @@ pub fn ibc_callback_handler( ); execute::route_message( deps, + &_env, &mut app, ¤t_chain, status_header, diff --git a/contracts/server/src/handlers/module_ibc.rs b/contracts/server/src/handlers/module_ibc.rs index 568de47..f98d1e5 100644 --- a/contracts/server/src/handlers/module_ibc.rs +++ b/contracts/server/src/handlers/module_ibc.rs @@ -33,6 +33,7 @@ pub fn module_ibc_handler( } => { let msgs = route_message( deps, + &env, &mut app, &TruncatedChainId::new(&env), header, diff --git a/contracts/server/src/replies/deliver_msg.rs b/contracts/server/src/replies/deliver_msg.rs index 90820f4..6ebd3c3 100644 --- a/contracts/server/src/replies/deliver_msg.rs +++ b/contracts/server/src/replies/deliver_msg.rs @@ -2,14 +2,12 @@ use abstract_adapter::objects::TruncatedChainId; use abstract_adapter::sdk::AbstractResponse; use cosmwasm_std::{DepsMut, Env, Reply, SubMsgResult}; -use ibcmail::server::msg::ServerMessage; use ibcmail::server::state::AWAITING_DELIVERY; use ibcmail::server::ServerAdapter; -use ibcmail::{DeliveryFailure, DeliveryStatus, Header, Sender, ServerMetadata}; +use ibcmail::{DeliveryFailure, DeliveryStatus}; use crate::contract::ServerResult; -use crate::handlers::execute::route_message; - +use crate::handlers::execute; pub fn deliver_message_reply( deps: DepsMut, env: Env, @@ -24,40 +22,23 @@ pub fn deliver_message_reply( // Load the awaiting message let mut awaiting_msgs = AWAITING_DELIVERY.load(deps.storage)?; - let (message_id, origin_header, origin_metadata) = awaiting_msgs.remove(0); + let (origin_header, origin_metadata) = awaiting_msgs.remove(0); AWAITING_DELIVERY.save(deps.storage, &awaiting_msgs)?; - let delivery_message = ServerMessage::delivery_status(message_id.clone(), delivery_status); - - let delivery_header = Header { - sender: Sender::Server { - address: env.contract.address.to_string(), - chain: TruncatedChainId::new(&env), - }, - recipient: origin_header.sender.try_into()?, - // TODO: new ID? - id: message_id.clone(), - // TODO: version? - version: origin_header.version, - timestamp: env.block.time, - reply_to: None, - }; - - let delivery_metadata = ServerMetadata { - route: origin_metadata.reverse_route()?, - }; + let message_id = origin_header.id.clone(); - let msg = route_message( + let msg = execute::send_delivery_status( deps, + &env, &mut app, ¤t_chain, - delivery_header, - delivery_metadata, - delivery_message, + origin_header, + origin_metadata, + delivery_status, )?; Ok(app .response("deliver_message_reply") - .add_attribute("message_id", message_id) + .add_attribute("message_id", &message_id) .add_submessages(msg)) } diff --git a/packages/ibcmail/src/client/msg.rs b/packages/ibcmail/src/client/msg.rs index 90f18ed..4db5fbc 100644 --- a/packages/ibcmail/src/client/msg.rs +++ b/packages/ibcmail/src/client/msg.rs @@ -2,7 +2,7 @@ use cosmwasm_schema::QueryResponses; use crate::{ client::ClientApp, ClientMetadata, DeliveryStatus, Header, MailMessage, MessageHash, - MessageKind, ReceivedMessage, Recipient, Sender, ServerMetadata, + MessageKind, ReceivedMessage, Recipient, Sender, SentMessage, ServerMetadata, }; // This is used for type safety and re-exporting the contract endpoint structs. @@ -69,10 +69,15 @@ pub struct ConfigResponse {} #[cosmwasm_schema::cw_serde] pub struct SentMessagesResponse { - pub messages: Vec<(MailMessage, Header)>, + pub messages: Vec, } #[cosmwasm_schema::cw_serde] pub struct ReceivedMessagesResponse { pub messages: Vec, } + +#[cosmwasm_schema::cw_serde] +pub struct MessageStatusesResponse { + pub statuses: Vec<(MessageHash, DeliveryStatus)>, +} diff --git a/packages/ibcmail/src/client/state.rs b/packages/ibcmail/src/client/state.rs index 5bbc31a..c6f5582 100644 --- a/packages/ibcmail/src/client/state.rs +++ b/packages/ibcmail/src/client/state.rs @@ -5,7 +5,7 @@ use crate::{DeliveryStatus, Header, MailMessage, MessageHash, ReceivedMessage}; // TODO: use an indexed map in the future pub const RECEIVED: Map = Map::new("received"); pub const SENT: Map = Map::new("sent"); -pub const STATUS: Map = Map::new("status"); +pub const SENT_STATUS: Map = Map::new("status"); /// Set of features supported by the client pub const FEATURES: Map = Map::new("features"); diff --git a/packages/ibcmail/src/lib.rs b/packages/ibcmail/src/lib.rs index b2f589d..cdc402c 100644 --- a/packages/ibcmail/src/lib.rs +++ b/packages/ibcmail/src/lib.rs @@ -32,6 +32,13 @@ pub struct MailMessage { } // # ANCHOR_END: message +#[cosmwasm_schema::cw_serde] +pub struct SentMessage { + pub message: MailMessage, + pub header: Header, + pub status: DeliveryStatus, +} + #[cosmwasm_schema::cw_serde] pub struct ReceivedMessage { pub message: MailMessage, diff --git a/packages/ibcmail/src/server/error.rs b/packages/ibcmail/src/server/error.rs index 5bf94f9..e25273d 100644 --- a/packages/ibcmail/src/server/error.rs +++ b/packages/ibcmail/src/server/error.rs @@ -1,4 +1,4 @@ -use crate::MessageHash; +use crate::{DeliveryFailure, MessageHash}; use abstract_adapter::objects::AccountId; use abstract_adapter::std::ibc::ModuleIbcInfo; use abstract_adapter::{ @@ -27,6 +27,9 @@ pub enum ServerError { #[error("{0}")] Admin(#[from] AdminError), + #[error("{0}")] + DeliveryFailure(#[from] DeliveryFailure), + #[error("{0}")] AdapterError(#[from] AbstractAdapterError), diff --git a/packages/ibcmail/src/server/state.rs b/packages/ibcmail/src/server/state.rs index cef6262..d51b166 100644 --- a/packages/ibcmail/src/server/state.rs +++ b/packages/ibcmail/src/server/state.rs @@ -3,5 +3,4 @@ use abstract_app::objects::TruncatedChainId; use cw_storage_plus::{Item, Map}; pub const AWAITING: Map<&MessageHash, TruncatedChainId> = Map::new("awaiting"); -pub const AWAITING_DELIVERY: Item> = - Item::new("awaiting_delivery"); +pub const AWAITING_DELIVERY: Item> = Item::new("awaiting_delivery"); diff --git a/tests/src/client.rs b/tests/src/client.rs index b44e0d3..287cea2 100644 --- a/tests/src/client.rs +++ b/tests/src/client.rs @@ -1,11 +1,18 @@ +use std::str::FromStr; + +use abstract_app::objects::TruncatedChainId; use abstract_app::objects::{namespace::Namespace, AccountId}; +use abstract_app::{objects::account::AccountTrace, std::version_control::ExecuteMsgFns}; use abstract_client::{AbstractClient, Application}; -use cosmwasm_schema::schemars::schema::Metadata; +use abstract_cw_orch_polytone::PolytoneConnection; +use abstract_interface::Abstract; use cw_orch::{anyhow, prelude::*}; +use cw_orch_interchain::{InterchainEnv, MockBech32InterchainEnv, MockInterchainEnv}; use speculoos::prelude::*; // Use prelude to get all the necessary imports use client::{contract::interface::ClientInterface, msg::ClientInstantiateMsg, *}; +use ibcmail::{server::error::ServerError, ClientMetadata, IBCMAIL_CLIENT_ID}; use ibcmail::{ server::msg::ServerInstantiateMsg, Header, MailMessage, ReceivedMessage, Recipient, Route, Sender, ServerMetadata, IBCMAIL_NAMESPACE, IBCMAIL_SERVER_ID, @@ -70,6 +77,33 @@ impl TestEnv { client2: app2, }) } + + pub fn assert_no_received_messages(&self) -> anyhow::Result<()> { + assert_that!( + self.client1 + .list_received_messages(None, None, None)? + .messages + ) + .is_empty(); + assert_that!( + self.client2 + .list_received_messages(None, None, None)? + .messages + ) + .is_empty(); + Ok(()) + } +} + +impl TestEnv { + pub fn connect_to( + &self, + other: &TestEnv, + interchain: &impl cw_orch_interchain::InterchainEnv, + ) -> anyhow::Result<()> { + self.abs.connect_to(&other.abs, interchain)?; + Ok(()) + } } fn create_received_message(from: AccountId, to: AccountId, route: Route) -> ReceivedMessage { @@ -267,7 +301,7 @@ mod send_msg { let arch_env = TestEnv::setup(interchain.get_chain("archway-1")?)?; let juno_env = TestEnv::setup(interchain.get_chain("juno-1")?)?; - arch_env.abs.connect_to(&juno_env.abs, &interchain)?; + arch_env.connect_to(&juno_env, &interchain)?; let arch_client = arch_env.client1; let juno_client = juno_env.client1; @@ -331,6 +365,84 @@ mod send_msg { Ok(()) } + #[test] + fn can_send_remote_message_2_hop() -> anyhow::Result<()> { + // Create a sender and mock env + let interchain = MockBech32InterchainEnv::new(vec![ + ("juno-1", "juno"), + ("archway-1", "archway"), + ("neutron-1", "neutron"), + ]); + + // /Users/adair/.cargo/registry/src/index.crates.io-6f17d22bba15001f/cw-orch-mock-0.22.0/src/queriers/env.rs:12:70: + // index out of bounds: the len is 1 but the index is 1 (when initializing with "juno") + let arch_env = TestEnv::setup(interchain.get_chain("archway-1")?)?; + let juno_env = TestEnv::setup(interchain.get_chain("juno-1")?)?; + let neutron_env = TestEnv::setup(interchain.get_chain("neutron-1")?)?; + + arch_env.connect_to(&juno_env, &interchain)?; + juno_env.connect_to(&neutron_env, &interchain)?; + + // ibc_abstract_setup(&interchain, "archway-1", "juno-1")?; + // ibc_abstract_setup(&interchain, "juno-1", "neutron-1")?; + + let arch_client = arch_env.client1; + let _juno_client = juno_env.client1; + let neutron_client = neutron_env.client1; + + // the trait `From<&str>` is not implemented for `abstract_app::objects::chain_name::TruncatedChainId` + let arch_to_neutron_msg = MailMessage::new("test-subject", "test-body"); + + let res = arch_client.send_message( + arch_to_neutron_msg, + Recipient::account( + neutron_client.account().id()?, + Some(TruncatedChainId::from_string("neutron".into())?), + ), + Some(ClientMetadata::new_with_route(AccountTrace::Remote(vec![ + "juno".parse()?, + TruncatedChainId::from_str("neutron")?, + ]))), + )?; + + interchain.await_and_check_packets("archway-1", res.clone())?; + + let arch_messages = arch_client.list_received_messages(None, None, None)?; + assert_that!(arch_messages.messages).is_empty(); + + let neutron_client_1_module_addresses = neutron_client + .account() + .module_addresses(vec![IBCMAIL_CLIENT_ID.into()])?; + // let acc_id = neutron_client.account().id()?; + // println!("neutron_client_1 addresses: {:?}, account_id: {:?}", neutron_client_1_module_addresses, acc_id); + // // TESTING: + // let addresses = juno_env.client2.account().module_addresses(vec![IBCMAIL_CLIENT_ID.into()])?; + // let acc_id = juno_env.client2.account().id()?; + // println!("neutron_client_2 addresses: {:?}, account_id: {:?}", addresses, acc_id); + // + // let test_address = neutron_client.address()?; + // let test_id = neutron_client.id(); + // println!("test_address: {:?}, test_id: {:?}", test_address, test_id); + + let neutron_mail_client = ClientInterface::new(IBCMAIL_CLIENT_ID, neutron_env.env.clone()); + neutron_mail_client.set_address(&neutron_client_1_module_addresses.modules[0].1.clone()); + let neutron_mail_client_messages = + neutron_mail_client.list_received_messages(None, None, None)?; + assert_that!(neutron_mail_client_messages.messages).has_length(1); + + // let juno_messages = neutron_client.list_messages(None, None, None)?; + // assert_that!(juno_messages.messages).has_length(1); + + Ok(()) + } +} + +mod update_status { + use super::*; + use ibcmail::DeliveryFailure; + use ibcmail::DeliveryStatus; + use speculoos::assert_that; + #[test] fn send_remote_message_1_hop_account_dne_updates_status_to_failed() -> anyhow::Result<()> { // Create a sender and mock env @@ -340,7 +452,7 @@ mod send_msg { let arch_env = TestEnv::setup(interchain.get_chain("archway-1")?)?; let juno_env = TestEnv::setup(interchain.get_chain("juno-1")?)?; - arch_env.abs.connect_to(&juno_env.abs, &interchain)?; + arch_env.connect_to(&juno_env, &interchain)?; let arch_client = arch_env.client1; let juno_client = juno_env.client1; @@ -390,7 +502,7 @@ mod send_msg { } #[test] - fn can_send_remote_message_2_hop() -> anyhow::Result<()> { + fn send_remote_message_2_hop_account_dne_updates_status_to_failed() -> anyhow::Result<()> { // Create a sender and mock env let interchain = MockBech32InterchainEnv::new(vec![ ("juno-1", "juno"), @@ -398,64 +510,60 @@ mod send_msg { ("neutron-1", "neutron"), ]); - // /Users/adair/.cargo/registry/src/index.crates.io-6f17d22bba15001f/cw-orch-mock-0.22.0/src/queriers/env.rs:12:70: - // index out of bounds: the len is 1 but the index is 1 (when initializing with "juno") let arch_env = TestEnv::setup(interchain.get_chain("archway-1")?)?; let juno_env = TestEnv::setup(interchain.get_chain("juno-1")?)?; let neutron_env = TestEnv::setup(interchain.get_chain("neutron-1")?)?; - arch_env.abs.connect_to(&juno_env.abs, &interchain)?; - juno_env.abs.connect_to(&neutron_env.abs, &interchain)?; + arch_env.connect_to(&juno_env, &interchain)?; + juno_env.connect_to(&neutron_env, &interchain)?; - // ibc_abstract_setup(&interchain, "archway-1", "juno-1")?; - // ibc_abstract_setup(&interchain, "juno-1", "neutron-1")?; - - let arch_client = arch_env.client1; - let _juno_client = juno_env.client1; - let neutron_client = neutron_env.client1; + let arch_client = arch_env.client1.clone(); + let juno_client = juno_env.client1.clone(); + let neutron_client = neutron_env.client1.clone(); // the trait `From<&str>` is not implemented for `abstract_app::objects::chain_name::TruncatedChainId` - let arch_to_neutron_msg = MailMessage::new("test-subject", "test-body"); + let mail_message = MailMessage::new("test-subject", "test-body"); let res = arch_client.send_message( - arch_to_neutron_msg, + mail_message, Recipient::account( - neutron_client.account().id()?, + AccountId::local(420), Some(TruncatedChainId::from_string("neutron".into())?), ), - Some(ClientMetadata::new_with_route(AccountTrace::Remote(vec![ - "juno".parse()?, - TruncatedChainId::from_str("neutron")?, + Some(ClientMetadata::new_with_route(Route::Remote(vec![ + TruncatedChainId::from_string("juno".into())?, + TruncatedChainId::from_string("neutron".into())?, ]))), - )?; + ); - interchain.await_and_check_packets("archway-1", res.clone())?; + assert_that!(res).is_ok(); - let arch_messages = arch_client.list_received_messages(None, None, None)?; - assert_that!(arch_messages.messages).is_empty(); + let server = ServerInterface::new(IBCMAIL_SERVER_ID, arch_env.env.clone()); + println!("server: {:?}", server.address()?); + let abstr = Abstract::new(arch_env.env.clone()); + println!("ibc_host: {:?}", abstr.ibc.host.address()?); + let poly = PolytoneConnection::load_from(arch_env.env.clone(), juno_env.env.clone()); + println!("poly_note: {:?}", poly.note.address()?); - let neutron_client_1_module_addresses = neutron_client - .account() - .module_addresses(vec![IBCMAIL_CLIENT_ID.into()])?; - // let acc_id = neutron_client.account().id()?; - // println!("neutron_client_1 addresses: {:?}, account_id: {:?}", neutron_client_1_module_addresses, acc_id); - // // TESTING: - // let addresses = juno_env.client2.account().module_addresses(vec![IBCMAIL_CLIENT_ID.into()])?; - // let acc_id = juno_env.client2.account().id()?; - // println!("neutron_client_2 addresses: {:?}, account_id: {:?}", addresses, acc_id); - // - // let test_address = neutron_client.address()?; - // let test_id = neutron_client.id(); - // println!("test_address: {:?}, test_id: {:?}", test_address, test_id); + let packets = interchain.await_packets("archway-1", res?)?; - let neutron_mail_client = ClientInterface::new(IBCMAIL_CLIENT_ID, neutron_env.env.clone()); - neutron_mail_client.set_address(&neutron_client_1_module_addresses.modules[0].1.clone()); - let neutron_mail_client_messages = - neutron_mail_client.list_received_messages(None, None, None)?; - assert_that!(neutron_mail_client_messages.messages).has_length(1); + arch_env.assert_no_received_messages()?; + juno_env.assert_no_received_messages()?; + neutron_env.assert_no_received_messages()?; - // let juno_messages = neutron_client.list_messages(None, None, None)?; - // assert_that!(juno_messages.messages).has_length(1); + assert_that!(arch_client.list_sent_messages(None, None, None)?.messages).has_length(1); + + let sent_message = arch_client + .list_sent_messages(None, None, None)? + .messages + .first() + .cloned() + .unwrap(); + assert_that!(sent_message.status) + .is_equal_to(DeliveryStatus::from(DeliveryFailure::RecipientNotFound)); + + // interchain.await_packets("archway-1", res?)?; + // println!("packets: {:?}", packets); Ok(()) } From 9a0aebe31b5cf7407a50cae27046f675dbfb2aa2 Mon Sep 17 00:00:00 2001 From: adairrr <32375605+adairrr@users.noreply.github.com> Date: Sun, 4 Aug 2024 23:29:20 +0200 Subject: [PATCH 11/12] Format --- contracts/client/src/handlers/execute.rs | 2 +- contracts/client/src/handlers/query.rs | 2 +- contracts/server/src/handlers/execute.rs | 18 +++++++++--------- packages/ibcmail/src/client/msg.rs | 4 ++-- tests/src/client.rs | 17 +++++------------ 5 files changed, 18 insertions(+), 25 deletions(-) diff --git a/contracts/client/src/handlers/execute.rs b/contracts/client/src/handlers/execute.rs index c27f85d..188d298 100644 --- a/contracts/client/src/handlers/execute.rs +++ b/contracts/client/src/handlers/execute.rs @@ -18,7 +18,7 @@ use ibcmail::{ }, server::api::{MailServer, ServerInterface}, ClientMetadata, DeliveryStatus, Header, MailMessage, MessageHash, ReceivedMessage, Recipient, - Sender, ServerMetadata, IBCMAIL_SERVER_ID, + Sender, IBCMAIL_SERVER_ID, }; // # ANCHOR: execute_handler diff --git a/contracts/client/src/handlers/query.rs b/contracts/client/src/handlers/query.rs index 00ed951..af7472c 100644 --- a/contracts/client/src/handlers/query.rs +++ b/contracts/client/src/handlers/query.rs @@ -13,7 +13,7 @@ use ibcmail::{ msg::{MessageFilter, ReceivedMessagesResponse}, state::{RECEIVED, SENT}, }, - MessageHash, MessageKind, SentMessage, + MessageHash, SentMessage, }; pub fn query_handler( diff --git a/contracts/server/src/handlers/execute.rs b/contracts/server/src/handlers/execute.rs index a9a1aa6..ca6b28c 100644 --- a/contracts/server/src/handlers/execute.rs +++ b/contracts/server/src/handlers/execute.rs @@ -23,8 +23,8 @@ use ibcmail::{ state::{AWAITING, AWAITING_DELIVERY}, ServerAdapter, }, - ClientMetadata, DeliveryFailure, DeliveryStatus, Header, MailMessage, MessageHash, Recipient, - Route, Sender, ServerMetadata, + ClientMetadata, DeliveryFailure, DeliveryStatus, Header, MailMessage, Recipient, Route, Sender, + ServerMetadata, }; use crate::replies::DELIVER_MESSAGE_REPLY; @@ -35,7 +35,7 @@ use crate::{ // ANCHOR: execute_handler pub fn execute_handler( - mut deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, app: Adapter, @@ -249,14 +249,14 @@ pub(crate) fn route_message( Err(e) => match e { ServerError::DeliveryFailure(delivery_failure) => send_delivery_status( deps, - &env, + env, module, - ¤t_chain, + current_chain, header, metadata, delivery_failure.into(), ), - _ => return Err(e), + _ => Err(e), }, } } @@ -376,7 +376,7 @@ pub(crate) fn send_delivery_status( let delivery_header = Header { sender: Sender::Server { address: env.contract.address.to_string(), - chain: TruncatedChainId::new(&env), + chain: TruncatedChainId::new(env), }, recipient: origin_header.sender.try_into()?, // TODO: new ID? @@ -393,9 +393,9 @@ pub(crate) fn send_delivery_status( let msg = route_message( deps, - &env, + env, module, - ¤t_chain, + current_chain, delivery_header, delivery_metadata, delivery_message, diff --git a/packages/ibcmail/src/client/msg.rs b/packages/ibcmail/src/client/msg.rs index 4db5fbc..f97f08d 100644 --- a/packages/ibcmail/src/client/msg.rs +++ b/packages/ibcmail/src/client/msg.rs @@ -1,8 +1,8 @@ use cosmwasm_schema::QueryResponses; use crate::{ - client::ClientApp, ClientMetadata, DeliveryStatus, Header, MailMessage, MessageHash, - MessageKind, ReceivedMessage, Recipient, Sender, SentMessage, ServerMetadata, + client::ClientApp, ClientMetadata, DeliveryStatus, MailMessage, MessageHash, ReceivedMessage, + Recipient, Sender, SentMessage, }; // This is used for type safety and re-exporting the contract endpoint structs. diff --git a/tests/src/client.rs b/tests/src/client.rs index 287cea2..e5446cd 100644 --- a/tests/src/client.rs +++ b/tests/src/client.rs @@ -1,18 +1,15 @@ -use std::str::FromStr; - use abstract_app::objects::TruncatedChainId; use abstract_app::objects::{namespace::Namespace, AccountId}; -use abstract_app::{objects::account::AccountTrace, std::version_control::ExecuteMsgFns}; use abstract_client::{AbstractClient, Application}; use abstract_cw_orch_polytone::PolytoneConnection; use abstract_interface::Abstract; use cw_orch::{anyhow, prelude::*}; -use cw_orch_interchain::{InterchainEnv, MockBech32InterchainEnv, MockInterchainEnv}; +use cw_orch_interchain::{InterchainEnv, MockBech32InterchainEnv}; use speculoos::prelude::*; // Use prelude to get all the necessary imports use client::{contract::interface::ClientInterface, msg::ClientInstantiateMsg, *}; -use ibcmail::{server::error::ServerError, ClientMetadata, IBCMAIL_CLIENT_ID}; +use ibcmail::ClientMetadata; use ibcmail::{ server::msg::ServerInstantiateMsg, Header, MailMessage, ReceivedMessage, Recipient, Route, Sender, ServerMetadata, IBCMAIL_NAMESPACE, IBCMAIL_SERVER_ID, @@ -127,7 +124,7 @@ fn create_received_message(from: AccountId, to: AccountId, route: Route) -> Rece mod receive_msg { use speculoos::assert_that; - use ibcmail::{MessageKind, IBCMAIL_SERVER_ID}; + use ibcmail::IBCMAIL_SERVER_ID; use super::*; @@ -197,14 +194,10 @@ mod send_msg { use abstract_app::objects::TruncatedChainId; use abstract_app::{objects::account::AccountTrace, std::version_control::ExecuteMsgFns}; - use abstract_cw_orch_polytone::PolytoneConnection; - use abstract_interface::Abstract; + use cw_orch_interchain::{InterchainEnv, MockBech32InterchainEnv}; - use ibcmail::{ - server::error::ServerError, ClientMetadata, MailMessage, MessageKind, Route, - IBCMAIL_CLIENT_ID, - }; + use ibcmail::{server::error::ServerError, ClientMetadata, MailMessage, IBCMAIL_CLIENT_ID}; use super::*; From e61e8b2c9db75151df5dc17cfde71480aeaa10c0 Mon Sep 17 00:00:00 2001 From: adairrr <32375605+adairrr@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:30:30 +0200 Subject: [PATCH 12/12] Update comment --- contracts/server/src/handlers/execute.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/server/src/handlers/execute.rs b/contracts/server/src/handlers/execute.rs index ca6b28c..d2bc33a 100644 --- a/contracts/server/src/handlers/execute.rs +++ b/contracts/server/src/handlers/execute.rs @@ -360,7 +360,7 @@ fn remote_server_msg( Ok(msg) } -/// Send a delivery status update to the +/// Send a delivery status update to the consumer pub(crate) fn send_delivery_status( deps: DepsMut, env: &Env,