From e5fbaadfe583223cbe2cca311473102c0e709317 Mon Sep 17 00:00:00 2001 From: Haiyi Zhong Date: Fri, 4 Oct 2024 13:03:28 +0800 Subject: [PATCH 1/6] feat(minor-axelarnet-gateway): call contract with token to nexus module --- .../axelarnet-gateway/src/clients/external.rs | 15 +- .../axelarnet-gateway/src/clients/gateway.rs | 2 +- contracts/axelarnet-gateway/src/contract.rs | 5 +- .../axelarnet-gateway/src/contract/execute.rs | 118 ++++++++++---- contracts/axelarnet-gateway/src/msg.rs | 4 +- contracts/axelarnet-gateway/src/state.rs | 2 +- contracts/axelarnet-gateway/tests/execute.rs | 144 +++++++++--------- .../axelarnet-gateway/tests/instantiate.rs | 6 +- contracts/axelarnet-gateway/tests/query.rs | 59 ++++--- ..._with_token_returns_correct_message.golden | 115 ++++++++++++-- .../axelarnet-gateway/tests/utils/execute.rs | 22 ++- .../tests/utils/instantiate.rs | 2 +- .../axelarnet-gateway/tests/utils/mod.rs | 61 ++++++++ .../axelarnet-gateway/tests/utils/params.rs | 2 +- packages/axelar-wasm-std/src/response.rs | 4 +- 15 files changed, 400 insertions(+), 161 deletions(-) diff --git a/contracts/axelarnet-gateway/src/clients/external.rs b/contracts/axelarnet-gateway/src/clients/external.rs index 5d6b4be78..b3eda0786 100644 --- a/contracts/axelarnet-gateway/src/clients/external.rs +++ b/contracts/axelarnet-gateway/src/clients/external.rs @@ -1,5 +1,5 @@ use cosmwasm_schema::cw_serde; -use cosmwasm_std::{Addr, CosmosMsg, HexBinary, QuerierWrapper}; +use cosmwasm_std::{Addr, CosmosMsg, Empty, HexBinary, QuerierWrapper}; use router_api::{Address, CrossChainId}; /// `AxelarExecutableMsg` is a struct containing the args used by the axelarnet gateway to execute a destination contract on Axelar. @@ -19,18 +19,18 @@ enum ExecuteMsg { Execute(AxelarExecutableMsg), } -pub struct Client<'a> { - client: client::ContractClient<'a, ExecuteMsg, ()>, +pub struct Client<'a, T = Empty> { + client: client::ContractClient<'a, ExecuteMsg, (), T>, } -impl<'a> Client<'a> { +impl<'a, T> Client<'a, T> { pub fn new(querier: QuerierWrapper<'a>, destination: &'a Addr) -> Self { Client { client: client::ContractClient::new(querier, destination), } } - pub fn execute(&self, msg: AxelarExecutableMsg) -> CosmosMsg { + pub fn execute(&self, msg: AxelarExecutableMsg) -> CosmosMsg { self.client.execute(&ExecuteMsg::Execute(msg)) } } @@ -38,7 +38,7 @@ impl<'a> Client<'a> { #[cfg(test)] mod test { use cosmwasm_std::testing::mock_dependencies; - use cosmwasm_std::{to_json_binary, Addr, HexBinary, WasmMsg}; + use cosmwasm_std::{to_json_binary, Addr, Empty, HexBinary, WasmMsg}; use router_api::CrossChainId; use crate::clients::external; @@ -55,7 +55,8 @@ mod test { cc_id: CrossChainId::new("source-chain", "message-id").unwrap(), }; - let client = external::Client::new(deps.as_ref().querier, &destination_addr); + let client: external::Client<'_, Empty> = + external::Client::new(deps.as_ref().querier, &destination_addr); assert_eq!( client.execute(executable_msg.clone()), diff --git a/contracts/axelarnet-gateway/src/clients/gateway.rs b/contracts/axelarnet-gateway/src/clients/gateway.rs index 3efe78794..1b6768e80 100644 --- a/contracts/axelarnet-gateway/src/clients/gateway.rs +++ b/contracts/axelarnet-gateway/src/clients/gateway.rs @@ -154,7 +154,7 @@ mod test { let msg = InstantiateMsg { chain_name: "source-chain".parse().unwrap(), router_address: "router".to_string(), - nexus_gateway: "nexus-gateway".to_string(), + nexus: "nexus".to_string(), }; instantiate(deps, env, info, msg.clone()).unwrap(); diff --git a/contracts/axelarnet-gateway/src/contract.rs b/contracts/axelarnet-gateway/src/contract.rs index 4ea9fc276..c85fbdbdd 100644 --- a/contracts/axelarnet-gateway/src/contract.rs +++ b/contracts/axelarnet-gateway/src/contract.rs @@ -1,3 +1,4 @@ +use axelar_core_std::nexus; use axelar_wasm_std::error::ContractError; use axelar_wasm_std::{address, FnExt, IntoContractError}; #[cfg(not(feature = "library"))] @@ -55,7 +56,7 @@ pub fn instantiate( let config = Config { chain_name: msg.chain_name, router: address::validate_cosmwasm_address(deps.api, &msg.router_address)?, - nexus_gateway: address::validate_cosmwasm_address(deps.api, &msg.nexus_gateway)?, + nexus: address::validate_cosmwasm_address(deps.api, &msg.nexus)?, }; state::save_config(deps.storage, &config)?; @@ -68,7 +69,7 @@ pub fn execute( _env: Env, info: MessageInfo, msg: ExecuteMsg, -) -> Result { +) -> Result, ContractError> { match msg.ensure_permissions(deps.storage, &info.sender)? { ExecuteMsg::CallContract { destination_chain, diff --git a/contracts/axelarnet-gateway/src/contract/execute.rs b/contracts/axelarnet-gateway/src/contract/execute.rs index 2fa189645..963702835 100644 --- a/contracts/axelarnet-gateway/src/contract/execute.rs +++ b/contracts/axelarnet-gateway/src/contract/execute.rs @@ -1,3 +1,4 @@ +use std::iter; use std::str::FromStr; use axelar_core_std::nexus; @@ -6,10 +7,9 @@ use axelar_wasm_std::token::GetToken; use axelar_wasm_std::{address, FnExt, IntoContractError}; use cosmwasm_schema::cw_serde; use cosmwasm_std::{ - to_json_binary, Addr, DepsMut, HexBinary, MessageInfo, QuerierWrapper, Response, Storage, - WasmMsg, + Addr, BankMsg, Coin, DepsMut, HexBinary, MessageInfo, QuerierWrapper, Response, Storage, }; -use error_stack::{bail, ensure, report, Result, ResultExt}; +use error_stack::{bail, ensure, report, ResultExt}; use itertools::Itertools; use router_api::client::Router; use router_api::{Address, ChainName, CrossChainId, Message}; @@ -53,6 +53,8 @@ pub enum Error { NonceOverflow, #[error("invalid token received")] InvalidToken, + #[error("invalid routing destination")] + RoutingDestination, } #[cw_serde] @@ -74,30 +76,28 @@ impl CallContractData { } } +enum RoutingDestination { + Nexus, + Router, +} + +type Result = error_stack::Result; + pub fn call_contract( storage: &mut dyn Storage, querier: QuerierWrapper, info: MessageInfo, call_contract: CallContractData, -) -> Result { +) -> Result> { let Config { router, chain_name, - nexus_gateway, + nexus, } = state::load_config(storage); let client: nexus::Client = client::CosmosClient::new(querier).into(); - let nexus::query::TxHashAndNonceResponse { tx_hash, nonce } = - client.tx_hash_and_nonce().change_context(Error::Nexus)?; - let id = CrossChainId::new( - chain_name, - HexTxHashAndEventIndex::new( - tx_hash, - u32::try_from(nonce).change_context(Error::NonceOverflow)?, - ), - ) - .change_context(Error::InvalidCrossChainId)?; + let id = unique_cross_chain_id(&client, chain_name.clone())?; let source_address = Address::from_str(info.sender.as_str()) .change_context(Error::InvalidSourceAddress(info.sender.clone()))?; let msg = call_contract.to_message(id, source_address); @@ -112,14 +112,13 @@ pub fn call_contract( payload: call_contract.payload, token: token.clone(), }; - let res = match token { - None => route_to_router(storage, &Router::new(router), vec![msg])?, - Some(token) => Response::new().add_message(WasmMsg::Execute { - contract_addr: nexus_gateway.to_string(), - msg: to_json_binary(&nexus_gateway::msg::ExecuteMsg::RouteMessageWithToken(msg)) - .expect("failed to serialize route message with token"), - funds: vec![token], - }), + + let res = match determine_routing_destination(&client, chain_name)? { + RoutingDestination::Nexus => route_to_nexus(&client, nexus, msg, token)?, + RoutingDestination::Router if token.is_none() => { + route_to_router(storage, &Router::new(router), vec![msg])? + } + _ => bail!(Error::RoutingDestination), } .add_event(event.into()); @@ -130,7 +129,7 @@ pub fn route_messages( storage: &mut dyn Storage, sender: Addr, msgs: Vec, -) -> Result { +) -> Result> { let Config { chain_name, router, .. } = state::load_config(storage); @@ -144,7 +143,11 @@ pub fn route_messages( } } -pub fn execute(deps: DepsMut, cc_id: CrossChainId, payload: HexBinary) -> Result { +pub fn execute( + deps: DepsMut, + cc_id: CrossChainId, + payload: HexBinary, +) -> Result> { let payload_hash: [u8; 32] = Keccak256::digest(payload.as_slice()).into(); let msg = state::mark_as_executed( deps.storage, @@ -163,6 +166,7 @@ pub fn execute(deps: DepsMut, cc_id: CrossChainId, payload: HexBinary) -> Result .change_context(Error::InvalidDestinationAddress( msg.destination_address.to_string(), ))?; + Response::new() .add_message(external::Client::new(deps.querier, &destination).execute(executable_msg)) .add_event(AxelarnetGatewayEvent::MessageExecuted { msg }.into()) @@ -195,7 +199,7 @@ fn prepare_msgs_for_execution( store: &mut dyn Storage, chain_name: ChainName, msgs: Vec, -) -> Result { +) -> Result> { for msg in msgs.iter() { ensure!( chain_name == msg.destination_chain, @@ -218,9 +222,9 @@ fn prepare_msgs_for_execution( /// Route messages to the router, ignore unknown messages. fn route_to_router( store: &mut dyn Storage, - router: &Router, + router: &Router, msgs: Vec, -) -> Result { +) -> Result> { let msgs: Vec<_> = msgs .into_iter() .unique() @@ -238,10 +242,7 @@ fn route_to_router( /// Verify that the message is stored and matches the one we're trying to route. Returns Ok(None) if /// the message is not stored. -fn try_load_executable_msg( - store: &mut dyn Storage, - msg: Message, -) -> Result, Error> { +fn try_load_executable_msg(store: &mut dyn Storage, msg: Message) -> Result> { let stored_msg = state::may_load_routable_msg(store, &msg.cc_id) .change_context(Error::ExecutableMessageAccess)?; @@ -253,3 +254,56 @@ fn try_load_executable_msg( None => Ok(None), } } + +/// Query Nexus module in core to generate an unique cross chain id. +fn unique_cross_chain_id(client: &nexus::Client, chain_name: ChainName) -> Result { + let nexus::query::TxHashAndNonceResponse { tx_hash, nonce } = + client.tx_hash_and_nonce().change_context(Error::Nexus)?; + + CrossChainId::new( + chain_name, + HexTxHashAndEventIndex::new( + tx_hash, + u32::try_from(nonce).change_context(Error::NonceOverflow)?, + ), + ) + .change_context(Error::InvalidCrossChainId) +} + +/// Query Nexus module in core to decide should route message to core +fn determine_routing_destination( + client: &nexus::Client, + name: ChainName, +) -> Result { + let dest = match client + .is_chain_registered(&name) + .change_context(Error::Nexus)? + { + true => RoutingDestination::Nexus, + false => RoutingDestination::Router, + }; + + Ok(dest) +} + +/// Route message to the Nexus module +fn route_to_nexus( + client: &nexus::Client, + nexus: Addr, + msg: Message, + token: Option, +) -> Result> { + let msg: nexus::execute::Message = (msg, token.clone()).into(); + + token + .map(|token| BankMsg::Send { + to_address: nexus.to_string(), + amount: vec![token], + }) + .map(Into::into) + .into_iter() + .chain(iter::once(client.route_message(msg))) + .collect::>() + .then(|msgs| Response::new().add_messages(msgs)) + .then(Ok) +} diff --git a/contracts/axelarnet-gateway/src/msg.rs b/contracts/axelarnet-gateway/src/msg.rs index 5bf54b128..9eea71a84 100644 --- a/contracts/axelarnet-gateway/src/msg.rs +++ b/contracts/axelarnet-gateway/src/msg.rs @@ -11,8 +11,8 @@ pub struct InstantiateMsg { pub chain_name: ChainName, /// Address of the router contract on axelar. pub router_address: String, - /// Address of the nexus gateway contract on axelar. - pub nexus_gateway: String, + /// Address of the nexus module on axelar. + pub nexus: String, } #[cw_serde] diff --git a/contracts/axelarnet-gateway/src/state.rs b/contracts/axelarnet-gateway/src/state.rs index aa3a7805e..7cec9c436 100644 --- a/contracts/axelarnet-gateway/src/state.rs +++ b/contracts/axelarnet-gateway/src/state.rs @@ -33,7 +33,7 @@ pub enum Error { pub struct Config { pub chain_name: ChainName, pub router: Addr, - pub nexus_gateway: Addr, + pub nexus: Addr, } #[cw_serde] diff --git a/contracts/axelarnet-gateway/tests/execute.rs b/contracts/axelarnet-gateway/tests/execute.rs index ec5f3ce96..7fa8bc091 100644 --- a/contracts/axelarnet-gateway/tests/execute.rs +++ b/contracts/axelarnet-gateway/tests/execute.rs @@ -1,21 +1,15 @@ use assert_ok::assert_ok; use axelar_wasm_std::assert_err_contains; -use axelar_wasm_std::error::ContractError; use axelar_wasm_std::response::inspect_response_msg; -use axelarnet_gateway::contract::{self, ExecuteError}; -use axelarnet_gateway::msg::ExecuteMsg; +use axelarnet_gateway::contract::ExecuteError; use axelarnet_gateway::StateError; -use cosmwasm_std::testing::{ - mock_dependencies, mock_env, mock_info, MockQuerierCustomHandlerResult, -}; -use cosmwasm_std::{Coin, ContractResult, DepsMut, HexBinary, Response, SystemResult}; +use cosmwasm_std::testing::{mock_dependencies, mock_info}; +use cosmwasm_std::{Coin, HexBinary}; use rand::RngCore; use router_api::msg::ExecuteMsg as RouterExecuteMsg; use router_api::{CrossChainId, Message}; -use serde::de::DeserializeOwned; -use serde_json::json; -use crate::utils::messages; +use crate::utils::{axelar_query_handler, emptying_deps_mut, messages, mock_axelar_dependencies}; mod utils; @@ -85,7 +79,7 @@ fn execute_approved_message_once_returns_correct_message() { utils::route_from_router(deps.as_mut(), vec![msg]).unwrap(); let response = assert_ok!(utils::execute_payload(deps.as_mut(), cc_id, payload)); - let msg = assert_ok!(inspect_response_msg::(response)); + let msg: utils::ExecuteMsg = assert_ok!(inspect_response_msg(response)); goldie::assert_json!(msg) } @@ -161,7 +155,7 @@ fn route_to_router_without_contract_call_ignores_message() { utils::instantiate_contract(deps.as_mut()).unwrap(); - let response = assert_ok!(route_to_router(deps.as_mut(), vec![msg])); + let response = assert_ok!(utils::route_to_router(deps.as_mut(), vec![msg])); assert_eq!(response.messages.len(), 0); } @@ -171,18 +165,18 @@ fn route_to_router_after_contract_call_with_tempered_data_fails() { rand::thread_rng().fill_bytes(&mut tx_hash); let nonce = rand::random(); - let mut deps = mock_dependencies(); + let mut deps = mock_axelar_dependencies(); deps.querier = deps .querier - .with_custom_handler(reply_with_tx_hash_and_nonce(tx_hash, nonce)); + .with_custom_handler(axelar_query_handler(tx_hash, nonce, false)); let destination_chain = "destination-chain".parse().unwrap(); let destination_address = "destination-address".parse().unwrap(); let payload = vec![1, 2, 3].into(); - utils::instantiate_contract(deps.as_mut()).unwrap(); + utils::instantiate_contract(emptying_deps_mut(&mut deps.as_mut())).unwrap(); let response = utils::call_contract( - deps.as_mut(), + emptying_deps_mut(&mut deps.as_mut()), mock_info("sender", &[]), destination_chain, destination_address, @@ -196,7 +190,7 @@ fn route_to_router_after_contract_call_with_tempered_data_fails() { msgs[0].destination_chain = "wrong-chain".parse().unwrap(); assert_err_contains!( - route_to_router(deps.as_mut(), msgs), + utils::route_to_router(emptying_deps_mut(&mut deps.as_mut()), msgs), ExecuteError, ExecuteError::MessageMismatch(..) ); @@ -211,18 +205,18 @@ fn route_to_router_after_contract_call_succeeds_multiple_times() { .unwrap(); let nonce = 210; - let mut deps = mock_dependencies(); + let mut deps = mock_axelar_dependencies(); deps.querier = deps .querier - .with_custom_handler(reply_with_tx_hash_and_nonce(tx_hash, nonce)); + .with_custom_handler(axelar_query_handler(tx_hash, nonce, false)); let destination_chain = "destination-chain".parse().unwrap(); let destination_address = "destination-address".parse().unwrap(); let payload = vec![1, 2, 3].into(); - utils::instantiate_contract(deps.as_mut()).unwrap(); + utils::instantiate_contract(emptying_deps_mut(&mut deps.as_mut())).unwrap(); let response = utils::call_contract( - deps.as_mut(), + emptying_deps_mut(&mut deps.as_mut()), mock_info("sender", &[]), destination_chain, destination_address, @@ -235,8 +229,11 @@ fn route_to_router_after_contract_call_succeeds_multiple_times() { }; for _ in 0..10 { - let response = assert_ok!(route_to_router(deps.as_mut(), msgs.clone())); - let msg = assert_ok!(inspect_response_msg::(response)); + let response = assert_ok!(utils::route_to_router( + emptying_deps_mut(&mut deps.as_mut()), + msgs.clone() + )); + let msg: RouterExecuteMsg = assert_ok!(inspect_response_msg(response)); goldie::assert_json!(msg); } } @@ -250,18 +247,18 @@ fn route_to_router_after_contract_call_ignores_duplicates() { .unwrap(); let nonce = 200; - let mut deps = mock_dependencies(); + let mut deps = mock_axelar_dependencies(); deps.querier = deps .querier - .with_custom_handler(reply_with_tx_hash_and_nonce(tx_hash, nonce)); + .with_custom_handler(axelar_query_handler(tx_hash, nonce, false)); let destination_chain = "destination-chain".parse().unwrap(); let destination_address = "destination-address".parse().unwrap(); let payload = vec![1, 2, 3].into(); - utils::instantiate_contract(deps.as_mut()).unwrap(); + utils::instantiate_contract(emptying_deps_mut(&mut deps.as_mut())).unwrap(); let response = utils::call_contract( - deps.as_mut(), + emptying_deps_mut(&mut deps.as_mut()), mock_info("sender", &[]), destination_chain, destination_address, @@ -277,8 +274,11 @@ fn route_to_router_after_contract_call_ignores_duplicates() { msgs.append(&mut msgs.clone()); assert_eq!(msgs.len(), 4); - let response = assert_ok!(route_to_router(deps.as_mut(), msgs)); - let msg = assert_ok!(inspect_response_msg::(response)); + let response = assert_ok!(utils::route_to_router( + emptying_deps_mut(&mut deps.as_mut()), + msgs + )); + let msg: RouterExecuteMsg = assert_ok!(inspect_response_msg(response)); goldie::assert_json!(msg); } @@ -291,25 +291,25 @@ fn contract_call_returns_correct_message() { .unwrap(); let nonce = 190; - let mut deps = mock_dependencies(); + let mut deps = mock_axelar_dependencies(); deps.querier = deps .querier - .with_custom_handler(reply_with_tx_hash_and_nonce(tx_hash, nonce)); + .with_custom_handler(axelar_query_handler(tx_hash, nonce, false)); let destination_chain = "destination-chain".parse().unwrap(); let destination_address = "destination-address".parse().unwrap(); let payload = vec![1, 2, 3].into(); - utils::instantiate_contract(deps.as_mut()).unwrap(); + utils::instantiate_contract(emptying_deps_mut(&mut deps.as_mut())).unwrap(); let response = assert_ok!(utils::call_contract( - deps.as_mut(), + emptying_deps_mut(&mut deps.as_mut()), mock_info("sender", &[]), destination_chain, destination_address, payload, )); - let msg = assert_ok!(inspect_response_msg::(response)); + let msg: RouterExecuteMsg = assert_ok!(inspect_response_msg(response)); goldie::assert_json!(msg) } @@ -319,28 +319,27 @@ fn contract_call_with_token_returns_correct_message() { let nonce = 99; let token = Coin::new(10, "axelar"); - let mut deps = mock_dependencies(); + let mut deps = mock_axelar_dependencies(); deps.querier = deps .querier - .with_custom_handler(reply_with_tx_hash_and_nonce(tx_hash, nonce)); + .with_custom_handler(axelar_query_handler(tx_hash, nonce, true)); let destination_chain = "destination-chain".parse().unwrap(); let destination_address = "destination-address".parse().unwrap(); let payload = vec![1, 2, 3].into(); - utils::instantiate_contract(deps.as_mut()).unwrap(); + utils::instantiate_contract(emptying_deps_mut(&mut deps.as_mut())).unwrap(); let response = assert_ok!(utils::call_contract( - deps.as_mut(), + emptying_deps_mut(&mut deps.as_mut()), mock_info("sender", &[token]), destination_chain, destination_address, payload, )); - let msg = assert_ok!(inspect_response_msg::( - response - )); - goldie::assert_json!(msg) + assert_eq!(response.messages.len(), 2); + + goldie::assert_json!(response.messages) } #[test] @@ -352,18 +351,18 @@ fn contract_call_returns_correct_events() { .unwrap(); let nonce = 160; - let mut deps = mock_dependencies(); + let mut deps = mock_axelar_dependencies(); deps.querier = deps .querier - .with_custom_handler(reply_with_tx_hash_and_nonce(tx_hash, nonce)); + .with_custom_handler(axelar_query_handler(tx_hash, nonce, false)); let destination_chain = "destination-chain".parse().unwrap(); let destination_address = "destination-address".parse().unwrap(); let payload = vec![1, 2, 3].into(); - utils::instantiate_contract(deps.as_mut()).unwrap(); + utils::instantiate_contract(emptying_deps_mut(&mut deps.as_mut())).unwrap(); let response = assert_ok!(utils::call_contract( - deps.as_mut(), + emptying_deps_mut(&mut deps.as_mut()), mock_info("sender", &[]), destination_chain, destination_address, @@ -372,31 +371,32 @@ fn contract_call_returns_correct_events() { goldie::assert_json!(response.events) } -fn route_to_router(deps: DepsMut, msgs: Vec) -> Result { - contract::execute( - deps, - mock_env(), - mock_info("sender", &[]), - ExecuteMsg::RouteMessages(msgs), - ) -} +#[test] +fn contract_call_with_token_to_amplifier_chains_fails() { + let tx_hash: [u8; 32] = [2; 32]; + let nonce = 99; + let token = Coin::new(10, "axelar"); -fn reply_with_tx_hash_and_nonce( - tx_hash: [u8; 32], - nonce: u32, -) -> impl Fn(&C) -> MockQuerierCustomHandlerResult -where - C: DeserializeOwned, -{ - move |_| { - SystemResult::Ok(ContractResult::Ok( - json!({ - "tx_hash": tx_hash, - "nonce": nonce, - }) - .to_string() - .as_bytes() - .into(), - )) - } + let mut deps = mock_axelar_dependencies(); + deps.querier = deps + .querier + .with_custom_handler(axelar_query_handler(tx_hash, nonce, false)); + + let destination_chain = "destination-chain".parse().unwrap(); + let destination_address = "destination-address".parse().unwrap(); + let payload = vec![1, 2, 3].into(); + + utils::instantiate_contract(emptying_deps_mut(&mut deps.as_mut())).unwrap(); + + assert_err_contains!( + utils::call_contract( + emptying_deps_mut(&mut deps.as_mut()), + mock_info("sender", &[token]), + destination_chain, + destination_address, + payload, + ), + ExecuteError, + ExecuteError::RoutingDestination, + ); } diff --git a/contracts/axelarnet-gateway/tests/instantiate.rs b/contracts/axelarnet-gateway/tests/instantiate.rs index 1c5a7f98f..bee376d77 100644 --- a/contracts/axelarnet-gateway/tests/instantiate.rs +++ b/contracts/axelarnet-gateway/tests/instantiate.rs @@ -21,7 +21,7 @@ fn invalid_router_address() { let msg = InstantiateMsg { chain_name: params::AXELARNET.parse().unwrap(), router_address: "".to_string(), - nexus_gateway: params::NEXUS_GATEWAY.parse().unwrap(), + nexus: params::NEXUS.parse().unwrap(), }; assert_err_contains!( @@ -32,13 +32,13 @@ fn invalid_router_address() { } #[test] -fn invalid_nexus_gateway_address() { +fn invalid_nexus_module_address() { let mut deps = mock_dependencies(); let msg = InstantiateMsg { chain_name: params::AXELARNET.parse().unwrap(), router_address: params::ROUTER.parse().unwrap(), - nexus_gateway: "".to_string(), + nexus: "".to_string(), }; assert_err_contains!( diff --git a/contracts/axelarnet-gateway/tests/query.rs b/contracts/axelarnet-gateway/tests/query.rs index b6307bf1a..40334f9ca 100644 --- a/contracts/axelarnet-gateway/tests/query.rs +++ b/contracts/axelarnet-gateway/tests/query.rs @@ -1,4 +1,5 @@ use assert_ok::assert_ok; +use axelar_core_std::query::AxelarQueryMsg; use axelar_wasm_std::response::inspect_response_msg; use axelarnet_gateway::msg::QueryMsg; use axelarnet_gateway::{contract, ExecutableMessage}; @@ -10,29 +11,31 @@ use cosmwasm_std::{from_json, ContractResult, Deps, OwnedDeps, SystemResult}; use rand::RngCore; use router_api::msg::ExecuteMsg as RouterExecuteMsg; use router_api::{ChainName, CrossChainId, Message}; -use serde::de::DeserializeOwned; use serde_json::json; use sha3::{Digest, Keccak256}; -use crate::utils::params; +use crate::utils::{emptying_deps, emptying_deps_mut, mock_axelar_dependencies, params}; mod utils; #[test] fn query_routable_messages_gets_expected_messages() { - let mut deps = mock_dependencies(); + let mut deps = mock_axelar_dependencies(); deps.querier = deps .querier .with_custom_handler(reply_rand_tx_hash_and_nonce); - utils::instantiate_contract(deps.as_mut()).unwrap(); + utils::instantiate_contract(emptying_deps_mut(&mut deps.as_mut())).unwrap(); let mut expected = populate_routable_messages(&mut deps); expected.remove(3); let cc_ids = expected.iter().map(|msg| &msg.cc_id).cloned().collect(); assert_eq!( - assert_ok!(query_routable_messages(deps.as_ref(), cc_ids)), + assert_ok!(query_routable_messages( + emptying_deps(&deps.as_ref()), + cc_ids + )), expected, ); } @@ -85,12 +88,12 @@ fn query_chain_name(deps: Deps) -> Result { } fn populate_routable_messages( - deps: &mut OwnedDeps, + deps: &mut OwnedDeps, AxelarQueryMsg>, ) -> Vec { (0..10) .map(|i| { let response = utils::call_contract( - deps.as_mut(), + emptying_deps_mut(&mut deps.as_mut()), mock_info("sender", &[]), format!("destination-chain-{}", i).parse().unwrap(), format!("destination-address-{}", i).parse().unwrap(), @@ -130,21 +133,29 @@ fn populate_executable_messages( msgs.into_iter().map(|msg| msg.cc_id).collect() } -fn reply_rand_tx_hash_and_nonce(_: &C) -> MockQuerierCustomHandlerResult -where - C: DeserializeOwned, -{ - let mut tx_hash = [0u8; 32]; - rand::thread_rng().fill_bytes(&mut tx_hash); - let nonce: u32 = rand::random(); - - SystemResult::Ok(ContractResult::Ok( - json!({ - "tx_hash": tx_hash, - "nonce": nonce, - }) - .to_string() - .as_bytes() - .into(), - )) +pub fn reply_rand_tx_hash_and_nonce(query: &AxelarQueryMsg) -> MockQuerierCustomHandlerResult { + let result = match query { + AxelarQueryMsg::Nexus(nexus_query) => match nexus_query { + axelar_core_std::nexus::query::QueryMsg::TxHashAndNonce {} => { + let mut tx_hash = [0u8; 32]; + rand::thread_rng().fill_bytes(&mut tx_hash); + let nonce: u32 = rand::random(); + + json!({ + "tx_hash": tx_hash, + "nonce": nonce, + }) + } + axelar_core_std::nexus::query::QueryMsg::IsChainRegistered { chain: _ } => json!({ + "is_registered": false + }), + _ => unreachable!("unexpected nexus query {:?}", nexus_query), + }, + _ => unreachable!("unexpected query request {:?}", query), + } + .to_string() + .as_bytes() + .into(); + + SystemResult::Ok(ContractResult::Ok(result)) } diff --git a/contracts/axelarnet-gateway/tests/testdata/contract_call_with_token_returns_correct_message.golden b/contracts/axelarnet-gateway/tests/testdata/contract_call_with_token_returns_correct_message.golden index 88aedff67..32ff5761b 100644 --- a/contracts/axelarnet-gateway/tests/testdata/contract_call_with_token_returns_correct_message.golden +++ b/contracts/axelarnet-gateway/tests/testdata/contract_call_with_token_returns_correct_message.golden @@ -1,12 +1,107 @@ -{ - "route_message_with_token": { - "cc_id": { - "source_chain": "axelarnet", - "message_id": "0x0202020202020202020202020202020202020202020202020202020202020202-99" +[ + { + "id": 0, + "msg": { + "bank": { + "send": { + "to_address": "nexus", + "amount": [ + { + "denom": "axelar", + "amount": "10" + } + ] + } + } }, - "source_address": "sender", - "destination_chain": "destination-chain", - "destination_address": "destination-address", - "payload_hash": "f1885eda54b7a053318cd41e2093220dab15d65381b1157a3633a83bfd5c9239" + "gas_limit": null, + "reply_on": "never" + }, + { + "id": 0, + "msg": { + "custom": { + "source_chain": "axelarnet", + "source_address": "sender", + "destination_chain": "destination-chain", + "destination_address": "destination-address", + "payload_hash": [ + 241, + 136, + 94, + 218, + 84, + 183, + 160, + 83, + 49, + 140, + 212, + 30, + 32, + 147, + 34, + 13, + 171, + 21, + 214, + 83, + 129, + 177, + 21, + 122, + 54, + 51, + 168, + 59, + 253, + 92, + 146, + 57 + ], + "source_tx_id": [ + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2 + ], + "source_tx_index": 99, + "id": "0x0202020202020202020202020202020202020202020202020202020202020202-99", + "token": { + "denom": "axelar", + "amount": "10" + } + } + }, + "gas_limit": null, + "reply_on": "never" } -} \ No newline at end of file +] \ No newline at end of file diff --git a/contracts/axelarnet-gateway/tests/utils/execute.rs b/contracts/axelarnet-gateway/tests/utils/execute.rs index de9cc34df..cb544c3c9 100644 --- a/contracts/axelarnet-gateway/tests/utils/execute.rs +++ b/contracts/axelarnet-gateway/tests/utils/execute.rs @@ -1,3 +1,4 @@ +use axelar_core_std::nexus; use axelar_wasm_std::error::ContractError; use axelarnet_gateway::msg::ExecuteMsg as GatewayExecuteMsg; use axelarnet_gateway::{contract, AxelarExecutableMsg}; @@ -20,7 +21,7 @@ pub fn call_contract( destination_chain: ChainName, destination_address: Address, payload: HexBinary, -) -> Result { +) -> Result, ContractError> { contract::execute( deps, mock_env(), @@ -33,7 +34,10 @@ pub fn call_contract( ) } -pub fn route_from_router(deps: DepsMut, msgs: Vec) -> Result { +pub fn route_from_router( + deps: DepsMut, + msgs: Vec, +) -> Result, ContractError> { contract::execute( deps, mock_env(), @@ -46,7 +50,7 @@ pub fn execute_payload( deps: DepsMut, cc_id: CrossChainId, payload: HexBinary, -) -> Result { +) -> Result, ContractError> { contract::execute( deps, mock_env(), @@ -54,3 +58,15 @@ pub fn execute_payload( GatewayExecuteMsg::Execute { cc_id, payload }.clone(), ) } + +pub fn route_to_router( + deps: DepsMut, + msgs: Vec, +) -> Result, ContractError> { + contract::execute( + deps, + mock_env(), + mock_info("sender", &[]), + GatewayExecuteMsg::RouteMessages(msgs), + ) +} diff --git a/contracts/axelarnet-gateway/tests/utils/instantiate.rs b/contracts/axelarnet-gateway/tests/utils/instantiate.rs index 0f2682629..3d7ab6bc3 100644 --- a/contracts/axelarnet-gateway/tests/utils/instantiate.rs +++ b/contracts/axelarnet-gateway/tests/utils/instantiate.rs @@ -14,7 +14,7 @@ pub fn instantiate_contract(deps: DepsMut) -> Result { InstantiateMsg { chain_name: params::AXELARNET.parse().unwrap(), router_address: params::ROUTER.parse().unwrap(), - nexus_gateway: params::NEXUS_GATEWAY.parse().unwrap(), + nexus: params::NEXUS.parse().unwrap(), }, ) } diff --git a/contracts/axelarnet-gateway/tests/utils/mod.rs b/contracts/axelarnet-gateway/tests/utils/mod.rs index e5c84b81f..71380fd69 100644 --- a/contracts/axelarnet-gateway/tests/utils/mod.rs +++ b/contracts/axelarnet-gateway/tests/utils/mod.rs @@ -2,11 +2,72 @@ // This circumvents that issue. #![allow(dead_code)] +use std::marker::PhantomData; +use std::ops::Deref; + +use axelar_core_std::nexus::query::QueryMsg; +use axelar_core_std::query::AxelarQueryMsg; +use cosmwasm_std::testing::{MockApi, MockQuerier, MockQuerierCustomHandlerResult, MockStorage}; +use cosmwasm_std::{ContractResult, Deps, DepsMut, Empty, OwnedDeps, QuerierWrapper, SystemResult}; #[allow(unused_imports)] pub use execute::*; pub use instantiate::*; +use serde_json::json; mod execute; mod instantiate; pub mod messages; pub mod params; + +pub fn mock_axelar_dependencies( +) -> OwnedDeps, AxelarQueryMsg> { + OwnedDeps { + storage: MockStorage::default(), + api: MockApi::default(), + querier: MockQuerier::::new(&[("contract", &[])]), + custom_query_type: PhantomData, + } +} + +pub fn axelar_query_handler( + tx_hash: [u8; 32], + nonce: u32, + is_chain_registered: bool, +) -> impl Fn(&AxelarQueryMsg) -> MockQuerierCustomHandlerResult { + move |query| { + let result = match query { + AxelarQueryMsg::Nexus(nexus_query) => match nexus_query { + QueryMsg::TxHashAndNonce {} => json!({ + "tx_hash": tx_hash, + "nonce": nonce, + }), + QueryMsg::IsChainRegistered { chain: _ } => json!({ + "is_registered": is_chain_registered + }), + _ => unreachable!("unexpected nexus query {:?}", nexus_query), + }, + _ => unreachable!("unexpected query request {:?}", query), + } + .to_string() + .as_bytes() + .into(); + + SystemResult::Ok(ContractResult::Ok(result)) + } +} + +pub fn emptying_deps_mut<'a>(deps: &'a mut DepsMut) -> DepsMut<'a, Empty> { + DepsMut { + storage: deps.storage, + api: deps.api, + querier: QuerierWrapper::new(deps.querier.deref()), + } +} + +pub fn emptying_deps<'a>(deps: &'a Deps) -> Deps<'a, Empty> { + Deps { + storage: deps.storage, + api: deps.api, + querier: QuerierWrapper::new(deps.querier.deref()), + } +} diff --git a/contracts/axelarnet-gateway/tests/utils/params.rs b/contracts/axelarnet-gateway/tests/utils/params.rs index 873dea560..5075e611c 100644 --- a/contracts/axelarnet-gateway/tests/utils/params.rs +++ b/contracts/axelarnet-gateway/tests/utils/params.rs @@ -1,3 +1,3 @@ pub const AXELARNET: &str = "axelarnet"; pub const ROUTER: &str = "router"; -pub const NEXUS_GATEWAY: &str = "nexus_gateway"; +pub const NEXUS: &str = "nexus"; diff --git a/packages/axelar-wasm-std/src/response.rs b/packages/axelar-wasm-std/src/response.rs index fd2e6ef92..7f74434df 100644 --- a/packages/axelar-wasm-std/src/response.rs +++ b/packages/axelar-wasm-std/src/response.rs @@ -13,9 +13,9 @@ pub enum Error { /// Get a msg wrapped inside a `WasmMsg::Execute` from a `Response`. /// If there are no wasm messages or more than one message in the response, this returns an error. -pub fn inspect_response_msg(response: Response) -> Result +pub fn inspect_response_msg(response: Response) -> Result where - T: DeserializeOwned, + D: DeserializeOwned, { let mut followup_messages = response.messages.into_iter(); From 2acf1dc6c1abc104b1c04b70d097a5cea0c6fb4b Mon Sep 17 00:00:00 2001 From: Haiyi Zhong Date: Wed, 9 Oct 2024 02:02:27 +0800 Subject: [PATCH 2/6] update --- contracts/axelarnet-gateway/src/contract/execute.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/axelarnet-gateway/src/contract/execute.rs b/contracts/axelarnet-gateway/src/contract/execute.rs index 963702835..e062e4263 100644 --- a/contracts/axelarnet-gateway/src/contract/execute.rs +++ b/contracts/axelarnet-gateway/src/contract/execute.rs @@ -97,7 +97,7 @@ pub fn call_contract( let client: nexus::Client = client::CosmosClient::new(querier).into(); - let id = unique_cross_chain_id(&client, chain_name.clone())?; + let id = unique_cross_chain_id(&client, chain_name)?; let source_address = Address::from_str(info.sender.as_str()) .change_context(Error::InvalidSourceAddress(info.sender.clone()))?; let msg = call_contract.to_message(id, source_address); @@ -113,7 +113,7 @@ pub fn call_contract( token: token.clone(), }; - let res = match determine_routing_destination(&client, chain_name)? { + let res = match determine_routing_destination(&client, &msg.destination_chain)? { RoutingDestination::Nexus => route_to_nexus(&client, nexus, msg, token)?, RoutingDestination::Router if token.is_none() => { route_to_router(storage, &Router::new(router), vec![msg])? @@ -273,10 +273,10 @@ fn unique_cross_chain_id(client: &nexus::Client, chain_name: ChainName) -> Resul /// Query Nexus module in core to decide should route message to core fn determine_routing_destination( client: &nexus::Client, - name: ChainName, + name: &ChainName, ) -> Result { let dest = match client - .is_chain_registered(&name) + .is_chain_registered(name) .change_context(Error::Nexus)? { true => RoutingDestination::Nexus, From be1a588534e81c430c49d5d3f13f036eac65be08 Mon Sep 17 00:00:00 2001 From: Haiyi Zhong Date: Thu, 10 Oct 2024 01:34:21 +0800 Subject: [PATCH 3/6] address comments --- .../axelarnet-gateway/src/contract/execute.rs | 4 +- contracts/axelarnet-gateway/src/msg.rs | 3 +- contracts/axelarnet-gateway/tests/execute.rs | 2 +- .../axelarnet-gateway/tests/utils/deps.rs | 61 ++++++++++++++++++ .../axelarnet-gateway/tests/utils/mod.rs | 63 +------------------ 5 files changed, 68 insertions(+), 65 deletions(-) create mode 100644 contracts/axelarnet-gateway/tests/utils/deps.rs diff --git a/contracts/axelarnet-gateway/src/contract/execute.rs b/contracts/axelarnet-gateway/src/contract/execute.rs index e062e4263..8047eff37 100644 --- a/contracts/axelarnet-gateway/src/contract/execute.rs +++ b/contracts/axelarnet-gateway/src/contract/execute.rs @@ -54,7 +54,7 @@ pub enum Error { #[error("invalid token received")] InvalidToken, #[error("invalid routing destination")] - RoutingDestination, + InvalidRoutingDestination, } #[cw_serde] @@ -118,7 +118,7 @@ pub fn call_contract( RoutingDestination::Router if token.is_none() => { route_to_router(storage, &Router::new(router), vec![msg])? } - _ => bail!(Error::RoutingDestination), + _ => bail!(Error::InvalidRoutingDestination), } .add_event(event.into()); diff --git a/contracts/axelarnet-gateway/src/msg.rs b/contracts/axelarnet-gateway/src/msg.rs index 9eea71a84..8e1617c02 100644 --- a/contracts/axelarnet-gateway/src/msg.rs +++ b/contracts/axelarnet-gateway/src/msg.rs @@ -33,7 +33,8 @@ pub enum ExecuteMsg { }, /// Initiate a cross-chain contract call from Axelarnet to another chain. - /// The message will be routed to the destination chain's gateway via the router. + /// If the destination chain is registered with core, the message will be routed to core with an optional token. + /// Otherwise, the message will be routed to the destination chain's gateway via the router. #[permission(Any)] CallContract { destination_chain: ChainName, diff --git a/contracts/axelarnet-gateway/tests/execute.rs b/contracts/axelarnet-gateway/tests/execute.rs index 7fa8bc091..3555709e8 100644 --- a/contracts/axelarnet-gateway/tests/execute.rs +++ b/contracts/axelarnet-gateway/tests/execute.rs @@ -397,6 +397,6 @@ fn contract_call_with_token_to_amplifier_chains_fails() { payload, ), ExecuteError, - ExecuteError::RoutingDestination, + ExecuteError::InvalidRoutingDestination, ); } diff --git a/contracts/axelarnet-gateway/tests/utils/deps.rs b/contracts/axelarnet-gateway/tests/utils/deps.rs new file mode 100644 index 000000000..10cbc6c4e --- /dev/null +++ b/contracts/axelarnet-gateway/tests/utils/deps.rs @@ -0,0 +1,61 @@ +use std::marker::PhantomData; +use std::ops::Deref; + +use axelar_core_std::nexus::query::QueryMsg; +use axelar_core_std::query::AxelarQueryMsg; +use cosmwasm_std::testing::{MockApi, MockQuerier, MockQuerierCustomHandlerResult, MockStorage}; +use cosmwasm_std::{ContractResult, Deps, DepsMut, Empty, OwnedDeps, QuerierWrapper, SystemResult}; +use serde_json::json; + +pub fn mock_axelar_dependencies( +) -> OwnedDeps, AxelarQueryMsg> { + OwnedDeps { + storage: MockStorage::default(), + api: MockApi::default(), + querier: MockQuerier::::new(&[("contract", &[])]), + custom_query_type: PhantomData, + } +} + +pub fn axelar_query_handler( + tx_hash: [u8; 32], + nonce: u32, + is_chain_registered: bool, +) -> impl Fn(&AxelarQueryMsg) -> MockQuerierCustomHandlerResult { + move |query| { + let result = match query { + AxelarQueryMsg::Nexus(nexus_query) => match nexus_query { + QueryMsg::TxHashAndNonce {} => json!({ + "tx_hash": tx_hash, + "nonce": nonce, + }), + QueryMsg::IsChainRegistered { chain: _ } => json!({ + "is_registered": is_chain_registered + }), + _ => unreachable!("unexpected nexus query {:?}", nexus_query), + }, + _ => unreachable!("unexpected query request {:?}", query), + } + .to_string() + .as_bytes() + .into(); + + SystemResult::Ok(ContractResult::Ok(result)) + } +} + +pub fn emptying_deps_mut<'a>(deps: &'a mut DepsMut) -> DepsMut<'a, Empty> { + DepsMut { + storage: deps.storage, + api: deps.api, + querier: QuerierWrapper::new(deps.querier.deref()), + } +} + +pub fn emptying_deps<'a>(deps: &'a Deps) -> Deps<'a, Empty> { + Deps { + storage: deps.storage, + api: deps.api, + querier: QuerierWrapper::new(deps.querier.deref()), + } +} diff --git a/contracts/axelarnet-gateway/tests/utils/mod.rs b/contracts/axelarnet-gateway/tests/utils/mod.rs index 71380fd69..1b0ebe14b 100644 --- a/contracts/axelarnet-gateway/tests/utils/mod.rs +++ b/contracts/axelarnet-gateway/tests/utils/mod.rs @@ -2,72 +2,13 @@ // This circumvents that issue. #![allow(dead_code)] -use std::marker::PhantomData; -use std::ops::Deref; - -use axelar_core_std::nexus::query::QueryMsg; -use axelar_core_std::query::AxelarQueryMsg; -use cosmwasm_std::testing::{MockApi, MockQuerier, MockQuerierCustomHandlerResult, MockStorage}; -use cosmwasm_std::{ContractResult, Deps, DepsMut, Empty, OwnedDeps, QuerierWrapper, SystemResult}; +pub use deps::*; #[allow(unused_imports)] pub use execute::*; pub use instantiate::*; -use serde_json::json; +mod deps; mod execute; mod instantiate; pub mod messages; pub mod params; - -pub fn mock_axelar_dependencies( -) -> OwnedDeps, AxelarQueryMsg> { - OwnedDeps { - storage: MockStorage::default(), - api: MockApi::default(), - querier: MockQuerier::::new(&[("contract", &[])]), - custom_query_type: PhantomData, - } -} - -pub fn axelar_query_handler( - tx_hash: [u8; 32], - nonce: u32, - is_chain_registered: bool, -) -> impl Fn(&AxelarQueryMsg) -> MockQuerierCustomHandlerResult { - move |query| { - let result = match query { - AxelarQueryMsg::Nexus(nexus_query) => match nexus_query { - QueryMsg::TxHashAndNonce {} => json!({ - "tx_hash": tx_hash, - "nonce": nonce, - }), - QueryMsg::IsChainRegistered { chain: _ } => json!({ - "is_registered": is_chain_registered - }), - _ => unreachable!("unexpected nexus query {:?}", nexus_query), - }, - _ => unreachable!("unexpected query request {:?}", query), - } - .to_string() - .as_bytes() - .into(); - - SystemResult::Ok(ContractResult::Ok(result)) - } -} - -pub fn emptying_deps_mut<'a>(deps: &'a mut DepsMut) -> DepsMut<'a, Empty> { - DepsMut { - storage: deps.storage, - api: deps.api, - querier: QuerierWrapper::new(deps.querier.deref()), - } -} - -pub fn emptying_deps<'a>(deps: &'a Deps) -> Deps<'a, Empty> { - Deps { - storage: deps.storage, - api: deps.api, - querier: QuerierWrapper::new(deps.querier.deref()), - } -} From 5635a89bbce3aa32f8909cfa407577d33ce222bd Mon Sep 17 00:00:00 2001 From: Haiyi Zhong Date: Thu, 10 Oct 2024 02:06:46 +0800 Subject: [PATCH 4/6] update --- contracts/axelarnet-gateway/src/msg.rs | 2 +- contracts/axelarnet-gateway/tests/utils/mod.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/axelarnet-gateway/src/msg.rs b/contracts/axelarnet-gateway/src/msg.rs index 8e1617c02..85d6f674f 100644 --- a/contracts/axelarnet-gateway/src/msg.rs +++ b/contracts/axelarnet-gateway/src/msg.rs @@ -11,7 +11,7 @@ pub struct InstantiateMsg { pub chain_name: ChainName, /// Address of the router contract on axelar. pub router_address: String, - /// Address of the nexus module on axelar. + /// Address of the nexus module account on axelar. pub nexus: String, } diff --git a/contracts/axelarnet-gateway/tests/utils/mod.rs b/contracts/axelarnet-gateway/tests/utils/mod.rs index 1b0ebe14b..f48991cd8 100644 --- a/contracts/axelarnet-gateway/tests/utils/mod.rs +++ b/contracts/axelarnet-gateway/tests/utils/mod.rs @@ -2,6 +2,7 @@ // This circumvents that issue. #![allow(dead_code)] +#[cfg_attr(test, allow(unused_imports))] pub use deps::*; #[allow(unused_imports)] pub use execute::*; From 6dbccc5ae4db0bd39bf7884f99386dfc5f0e4826 Mon Sep 17 00:00:00 2001 From: Haiyi Zhong Date: Thu, 10 Oct 2024 03:30:46 +0800 Subject: [PATCH 5/6] better test helper --- contracts/axelarnet-gateway/tests/execute.rs | 42 ++++++++----------- contracts/axelarnet-gateway/tests/query.rs | 11 ++--- .../axelarnet-gateway/tests/utils/deps.rs | 34 +++++++++------ 3 files changed, 44 insertions(+), 43 deletions(-) diff --git a/contracts/axelarnet-gateway/tests/execute.rs b/contracts/axelarnet-gateway/tests/execute.rs index 3555709e8..fe8cc957b 100644 --- a/contracts/axelarnet-gateway/tests/execute.rs +++ b/contracts/axelarnet-gateway/tests/execute.rs @@ -9,7 +9,7 @@ use rand::RngCore; use router_api::msg::ExecuteMsg as RouterExecuteMsg; use router_api::{CrossChainId, Message}; -use crate::utils::{axelar_query_handler, emptying_deps_mut, messages, mock_axelar_dependencies}; +use crate::utils::{axelar_query_handler, messages, mock_axelar_dependencies, OwnedDepsExt}; mod utils; @@ -174,9 +174,9 @@ fn route_to_router_after_contract_call_with_tempered_data_fails() { let destination_address = "destination-address".parse().unwrap(); let payload = vec![1, 2, 3].into(); - utils::instantiate_contract(emptying_deps_mut(&mut deps.as_mut())).unwrap(); + utils::instantiate_contract(deps.as_default_mut()).unwrap(); let response = utils::call_contract( - emptying_deps_mut(&mut deps.as_mut()), + deps.as_default_mut(), mock_info("sender", &[]), destination_chain, destination_address, @@ -190,7 +190,7 @@ fn route_to_router_after_contract_call_with_tempered_data_fails() { msgs[0].destination_chain = "wrong-chain".parse().unwrap(); assert_err_contains!( - utils::route_to_router(emptying_deps_mut(&mut deps.as_mut()), msgs), + utils::route_to_router(deps.as_default_mut(), msgs), ExecuteError, ExecuteError::MessageMismatch(..) ); @@ -214,9 +214,9 @@ fn route_to_router_after_contract_call_succeeds_multiple_times() { let destination_address = "destination-address".parse().unwrap(); let payload = vec![1, 2, 3].into(); - utils::instantiate_contract(emptying_deps_mut(&mut deps.as_mut())).unwrap(); + utils::instantiate_contract(deps.as_default_mut()).unwrap(); let response = utils::call_contract( - emptying_deps_mut(&mut deps.as_mut()), + deps.as_default_mut(), mock_info("sender", &[]), destination_chain, destination_address, @@ -229,10 +229,7 @@ fn route_to_router_after_contract_call_succeeds_multiple_times() { }; for _ in 0..10 { - let response = assert_ok!(utils::route_to_router( - emptying_deps_mut(&mut deps.as_mut()), - msgs.clone() - )); + let response = assert_ok!(utils::route_to_router(deps.as_default_mut(), msgs.clone())); let msg: RouterExecuteMsg = assert_ok!(inspect_response_msg(response)); goldie::assert_json!(msg); } @@ -256,9 +253,9 @@ fn route_to_router_after_contract_call_ignores_duplicates() { let destination_address = "destination-address".parse().unwrap(); let payload = vec![1, 2, 3].into(); - utils::instantiate_contract(emptying_deps_mut(&mut deps.as_mut())).unwrap(); + utils::instantiate_contract(deps.as_default_mut()).unwrap(); let response = utils::call_contract( - emptying_deps_mut(&mut deps.as_mut()), + deps.as_default_mut(), mock_info("sender", &[]), destination_chain, destination_address, @@ -274,10 +271,7 @@ fn route_to_router_after_contract_call_ignores_duplicates() { msgs.append(&mut msgs.clone()); assert_eq!(msgs.len(), 4); - let response = assert_ok!(utils::route_to_router( - emptying_deps_mut(&mut deps.as_mut()), - msgs - )); + let response = assert_ok!(utils::route_to_router(deps.as_default_mut(), msgs)); let msg: RouterExecuteMsg = assert_ok!(inspect_response_msg(response)); goldie::assert_json!(msg); } @@ -300,10 +294,10 @@ fn contract_call_returns_correct_message() { let destination_address = "destination-address".parse().unwrap(); let payload = vec![1, 2, 3].into(); - utils::instantiate_contract(emptying_deps_mut(&mut deps.as_mut())).unwrap(); + utils::instantiate_contract(deps.as_default_mut()).unwrap(); let response = assert_ok!(utils::call_contract( - emptying_deps_mut(&mut deps.as_mut()), + deps.as_default_mut(), mock_info("sender", &[]), destination_chain, destination_address, @@ -328,10 +322,10 @@ fn contract_call_with_token_returns_correct_message() { let destination_address = "destination-address".parse().unwrap(); let payload = vec![1, 2, 3].into(); - utils::instantiate_contract(emptying_deps_mut(&mut deps.as_mut())).unwrap(); + utils::instantiate_contract(deps.as_default_mut()).unwrap(); let response = assert_ok!(utils::call_contract( - emptying_deps_mut(&mut deps.as_mut()), + deps.as_default_mut(), mock_info("sender", &[token]), destination_chain, destination_address, @@ -360,9 +354,9 @@ fn contract_call_returns_correct_events() { let destination_address = "destination-address".parse().unwrap(); let payload = vec![1, 2, 3].into(); - utils::instantiate_contract(emptying_deps_mut(&mut deps.as_mut())).unwrap(); + utils::instantiate_contract(deps.as_default_mut()).unwrap(); let response = assert_ok!(utils::call_contract( - emptying_deps_mut(&mut deps.as_mut()), + deps.as_default_mut(), mock_info("sender", &[]), destination_chain, destination_address, @@ -386,11 +380,11 @@ fn contract_call_with_token_to_amplifier_chains_fails() { let destination_address = "destination-address".parse().unwrap(); let payload = vec![1, 2, 3].into(); - utils::instantiate_contract(emptying_deps_mut(&mut deps.as_mut())).unwrap(); + utils::instantiate_contract(deps.as_default_mut()).unwrap(); assert_err_contains!( utils::call_contract( - emptying_deps_mut(&mut deps.as_mut()), + deps.as_default_mut(), mock_info("sender", &[token]), destination_chain, destination_address, diff --git a/contracts/axelarnet-gateway/tests/query.rs b/contracts/axelarnet-gateway/tests/query.rs index 40334f9ca..283d9cc44 100644 --- a/contracts/axelarnet-gateway/tests/query.rs +++ b/contracts/axelarnet-gateway/tests/query.rs @@ -14,7 +14,7 @@ use router_api::{ChainName, CrossChainId, Message}; use serde_json::json; use sha3::{Digest, Keccak256}; -use crate::utils::{emptying_deps, emptying_deps_mut, mock_axelar_dependencies, params}; +use crate::utils::{mock_axelar_dependencies, params, OwnedDepsExt}; mod utils; @@ -25,17 +25,14 @@ fn query_routable_messages_gets_expected_messages() { .querier .with_custom_handler(reply_rand_tx_hash_and_nonce); - utils::instantiate_contract(emptying_deps_mut(&mut deps.as_mut())).unwrap(); + utils::instantiate_contract(deps.as_default_mut()).unwrap(); let mut expected = populate_routable_messages(&mut deps); expected.remove(3); let cc_ids = expected.iter().map(|msg| &msg.cc_id).cloned().collect(); assert_eq!( - assert_ok!(query_routable_messages( - emptying_deps(&deps.as_ref()), - cc_ids - )), + assert_ok!(query_routable_messages(deps.as_default_deps(), cc_ids)), expected, ); } @@ -93,7 +90,7 @@ fn populate_routable_messages( (0..10) .map(|i| { let response = utils::call_contract( - emptying_deps_mut(&mut deps.as_mut()), + deps.as_default_mut(), mock_info("sender", &[]), format!("destination-chain-{}", i).parse().unwrap(), format!("destination-address-{}", i).parse().unwrap(), diff --git a/contracts/axelarnet-gateway/tests/utils/deps.rs b/contracts/axelarnet-gateway/tests/utils/deps.rs index 10cbc6c4e..0cf03e2d0 100644 --- a/contracts/axelarnet-gateway/tests/utils/deps.rs +++ b/contracts/axelarnet-gateway/tests/utils/deps.rs @@ -4,7 +4,10 @@ use std::ops::Deref; use axelar_core_std::nexus::query::QueryMsg; use axelar_core_std::query::AxelarQueryMsg; use cosmwasm_std::testing::{MockApi, MockQuerier, MockQuerierCustomHandlerResult, MockStorage}; -use cosmwasm_std::{ContractResult, Deps, DepsMut, Empty, OwnedDeps, QuerierWrapper, SystemResult}; +use cosmwasm_std::{ + Api, ContractResult, CustomQuery, Deps, DepsMut, Empty, OwnedDeps, Querier, QuerierWrapper, + Storage, SystemResult, +}; use serde_json::json; pub fn mock_axelar_dependencies( @@ -44,18 +47,25 @@ pub fn axelar_query_handler( } } -pub fn emptying_deps_mut<'a>(deps: &'a mut DepsMut) -> DepsMut<'a, Empty> { - DepsMut { - storage: deps.storage, - api: deps.api, - querier: QuerierWrapper::new(deps.querier.deref()), - } +pub trait OwnedDepsExt { + fn as_default_mut(&mut self) -> DepsMut; + fn as_default_deps(&self) -> Deps; } -pub fn emptying_deps<'a>(deps: &'a Deps) -> Deps<'a, Empty> { - Deps { - storage: deps.storage, - api: deps.api, - querier: QuerierWrapper::new(deps.querier.deref()), +impl OwnedDepsExt for OwnedDeps { + fn as_default_mut(&'_ mut self) -> DepsMut<'_, Empty> { + DepsMut { + storage: &mut self.storage, + api: &self.api, + querier: QuerierWrapper::new(&self.querier), + } + } + + fn as_default_deps(&'_ self) -> Deps<'_, Empty> { + Deps { + storage: &self.storage, + api: &self.api, + querier: QuerierWrapper::new(&self.querier), + } } } From 662cf4c4bf84806426ab2b2ad0951dbb9644d229 Mon Sep 17 00:00:00 2001 From: Haiyi Zhong Date: Thu, 10 Oct 2024 03:39:12 +0800 Subject: [PATCH 6/6] fix lint --- contracts/axelarnet-gateway/tests/utils/deps.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/axelarnet-gateway/tests/utils/deps.rs b/contracts/axelarnet-gateway/tests/utils/deps.rs index 0cf03e2d0..188b135a8 100644 --- a/contracts/axelarnet-gateway/tests/utils/deps.rs +++ b/contracts/axelarnet-gateway/tests/utils/deps.rs @@ -1,5 +1,4 @@ use std::marker::PhantomData; -use std::ops::Deref; use axelar_core_std::nexus::query::QueryMsg; use axelar_core_std::query::AxelarQueryMsg;