From f736c488005c29d2223d37b2c496377b5088cad6 Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Tue, 15 Oct 2024 14:41:24 -0400 Subject: [PATCH] refactor(minor-interchain-token-service): remove gateway token support (#658) --- .../interchain-token-service/src/contract.rs | 262 +----- .../src/contract/execute.rs | 776 +----------------- .../src/contract/query.rs | 5 - contracts/interchain-token-service/src/msg.rs | 12 - .../interchain-token-service/src/state.rs | 31 - 5 files changed, 6 insertions(+), 1080 deletions(-) diff --git a/contracts/interchain-token-service/src/contract.rs b/contracts/interchain-token-service/src/contract.rs index 1f5ed6b42..503ea1539 100644 --- a/contracts/interchain-token-service/src/contract.rs +++ b/contracts/interchain-token-service/src/contract.rs @@ -1,7 +1,6 @@ use std::fmt::Debug; use axelar_wasm_std::error::ContractError; -use axelar_wasm_std::token::GetToken; use axelar_wasm_std::{address, permission_control, FnExt, IntoContractError}; use axelarnet_gateway::AxelarExecutableMsg; #[cfg(not(feature = "library"))] @@ -30,16 +29,12 @@ pub enum Error { RegisterItsContract, #[error("failed to deregsiter an its edge contract")] DeregisterItsContract, - #[error("failed to register gateway token")] - RegisterGatewayToken, #[error("too many coins attached. Execute accepts zero or one coins")] TooManyCoins, #[error("failed to query its address")] QueryItsContract, #[error("failed to query all its addresses")] QueryAllItsContracts, - #[error("failed to query gateway tokens")] - QueryGatewayTokens, } #[cfg_attr(not(feature = "library"), entry_point)] @@ -94,11 +89,8 @@ pub fn execute( cc_id, source_address, payload, - }) => { - let coin = info.single_token()?; - execute::execute_message(deps, cc_id, source_address, payload, coin) - .change_context(Error::Execute) - } + }) => execute::execute_message(deps, cc_id, source_address, payload) + .change_context(Error::Execute), ExecuteMsg::RegisterItsContract { chain, address } => { execute::register_its_contract(deps, chain, address) .change_context(Error::RegisterItsContract) @@ -107,11 +99,6 @@ pub fn execute( execute::deregister_its_contract(deps, chain) .change_context(Error::DeregisterItsContract) } - ExecuteMsg::RegisterGatewayToken { - denom, - source_chain, - } => execute::register_gateway_token(deps, denom, source_chain) - .change_context(Error::RegisterGatewayToken), }? .then(Ok) } @@ -129,251 +116,6 @@ pub fn query(deps: Deps, _: Env, msg: QueryMsg) -> Result QueryMsg::AllItsContracts => { query::all_its_contracts(deps).change_context(Error::QueryAllItsContracts) } - QueryMsg::GatewayTokens => { - query::gateway_tokens(deps).change_context(Error::QueryGatewayTokens) - } }? .then(Ok) } - -#[cfg(test)] -mod tests { - use std::collections::HashMap; - use std::marker::PhantomData; - - use assert_ok::assert_ok; - use axelar_core_std::nexus; - use axelar_core_std::nexus::query::IsChainRegisteredResponse; - use axelar_core_std::query::AxelarQueryMsg; - use axelar_wasm_std::msg_id::HexTxHashAndEventIndex; - use axelar_wasm_std::nonempty; - use axelar_wasm_std::response::inspect_response_msg; - use axelarnet_gateway::AxelarExecutableMsg; - use cosmwasm_std::testing::{mock_env, mock_info, MockApi, MockQuerier, MockStorage}; - use cosmwasm_std::{ - from_json, to_json_binary, Coin, CosmosMsg, HexBinary, MemoryStorage, OwnedDeps, Uint128, - WasmMsg, WasmQuery, - }; - use router_api::{ChainName, ChainNameRaw, CrossChainId}; - - use super::{execute, instantiate}; - use crate::contract::execute::gateway_token_id; - use crate::contract::query; - use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; - use crate::{HubMessage, Message, TokenId}; - const GOVERNANCE_ADDRESS: &str = "governance"; - const ADMIN_ADDRESS: &str = "admin"; - const AXELARNET_GATEWAY_ADDRESS: &str = "axelarnet-gateway"; - const CORE_CHAIN: &str = "ethereum"; - const AMPLIFIER_CHAIN: &str = "solana"; - const AXELAR_CHAIN_NAME: &str = "axelar"; - - #[test] - fn register_gateway_token_should_register_denom_and_token_id() { - let mut deps = setup(); - let denom = "uaxl"; - let res = execute( - deps.as_mut(), - mock_env(), - mock_info(GOVERNANCE_ADDRESS, &[]), - ExecuteMsg::RegisterGatewayToken { - denom: denom.try_into().unwrap(), - source_chain: ChainNameRaw::try_from("axelar").unwrap(), - }, - ); - assert!(res.is_ok()); - - let tokens: HashMap = - from_json(query(deps.as_ref(), mock_env(), QueryMsg::GatewayTokens).unwrap()).unwrap(); - assert_eq!(tokens.len(), 1); - assert_eq!( - tokens, - HashMap::from([( - denom.try_into().unwrap(), - gateway_token_id(&deps.as_mut(), denom).unwrap() - )]) - ); - } - - /// Tests that a token can be attached to an ITS message, escrowed in the contract, and then subsequently - /// unlocked and sent back at a later time - #[test] - fn send_token_from_core_and_back() { - let mut deps = setup(); - let denom = "eth"; - let source_chain = ChainNameRaw::try_from(CORE_CHAIN).unwrap(); - let destination_chain = ChainNameRaw::try_from(AMPLIFIER_CHAIN).unwrap(); - - let its_address = "68d30f47F19c07bCCEf4Ac7FAE2Dc12FCa3e0dC9"; - let source_address = - HexBinary::from_hex("4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97").unwrap(); - - assert_ok!(execute( - deps.as_mut(), - mock_env(), - mock_info(GOVERNANCE_ADDRESS, &[]), - ExecuteMsg::RegisterGatewayToken { - denom: denom.try_into().unwrap(), - source_chain: source_chain.clone(), - }, - )); - - assert_ok!(execute( - deps.as_mut(), - mock_env(), - mock_info(GOVERNANCE_ADDRESS, &[]), - ExecuteMsg::RegisterItsContract { - chain: source_chain.clone(), - address: its_address.to_string().try_into().unwrap() - } - )); - - assert_ok!(execute( - deps.as_mut(), - mock_env(), - mock_info(GOVERNANCE_ADDRESS, &[]), - ExecuteMsg::RegisterItsContract { - chain: destination_chain.clone(), - address: its_address.to_string().try_into().unwrap() - } - )); - - let coin = Coin { - denom: denom.to_string(), - amount: Uint128::new(100u128), - }; - - let token_id = gateway_token_id(&deps.as_mut(), denom).unwrap(); - let msg = HubMessage::SendToHub { - destination_chain: destination_chain.clone(), - message: Message::InterchainTransfer { - token_id: token_id.clone(), - source_address: source_address.clone().try_into().unwrap(), - destination_address: HexBinary::from_hex(its_address) - .unwrap() - .try_into() - .unwrap(), - amount: coin.amount.try_into().unwrap(), - data: None, - }, - }; - - assert_ok!(execute( - deps.as_mut(), - mock_env(), - mock_info(AXELARNET_GATEWAY_ADDRESS, &[coin.clone()]), - ExecuteMsg::Execute(AxelarExecutableMsg { - cc_id: CrossChainId { - source_chain: source_chain.clone(), - message_id: HexTxHashAndEventIndex::new([1u8; 32], 0u32) - .to_string() - .try_into() - .unwrap(), - }, - source_address: its_address.to_string().try_into().unwrap(), - payload: msg.abi_encode(), - }) - )); - - let msg = HubMessage::SendToHub { - destination_chain: source_chain.clone(), - message: Message::InterchainTransfer { - token_id: token_id.clone(), - source_address: source_address.clone().try_into().unwrap(), - destination_address: HexBinary::from_hex(its_address) - .unwrap() - .try_into() - .unwrap(), - amount: coin.amount.try_into().unwrap(), - data: None, - }, - }; - - let res = assert_ok!(execute( - deps.as_mut(), - mock_env(), - mock_info(AXELARNET_GATEWAY_ADDRESS, &[]), - ExecuteMsg::Execute(AxelarExecutableMsg { - cc_id: CrossChainId { - source_chain: destination_chain.clone(), - message_id: HexTxHashAndEventIndex::new([1u8; 32], 0u32) - .to_string() - .try_into() - .unwrap(), - }, - source_address: its_address.to_string().try_into().unwrap(), - payload: msg.abi_encode(), - }) - )); - let _msg: axelarnet_gateway::msg::ExecuteMsg = - assert_ok!(inspect_response_msg(res.clone())); - - match &res.messages.first().unwrap().msg { - CosmosMsg::Wasm(WasmMsg::Execute { funds, .. }) => { - assert_eq!(funds.len(), 1); - assert_eq!(funds.first().unwrap(), &coin); - } - _ => panic!("incorrect msg type"), - }; - } - - fn make_deps() -> OwnedDeps> { - let mut deps = OwnedDeps { - storage: MockStorage::default(), - api: MockApi::default(), - querier: MockQuerier::::new(&[]), - custom_query_type: PhantomData, - }; - - let mut querier = MockQuerier::::new(&[]); - querier.update_wasm(move |msg| match msg { - WasmQuery::Smart { contract_addr, msg } - if contract_addr == AXELARNET_GATEWAY_ADDRESS => - { - let msg = from_json::(msg).unwrap(); - match msg { - axelarnet_gateway::msg::QueryMsg::ChainName {} => { - Ok(to_json_binary(&ChainName::try_from(AXELAR_CHAIN_NAME).unwrap()).into()) - .into() - } - _ => panic!("unsupported query"), - } - } - _ => panic!("unexpected query: {:?}", msg), - }); - querier = querier.with_custom_handler(|msg| match msg { - AxelarQueryMsg::Nexus(nexus::query::QueryMsg::IsChainRegistered { chain }) => { - Ok(to_json_binary( - &(IsChainRegisteredResponse { - is_registered: chain == CORE_CHAIN, - }), - ) - .into()) - .into() - } - _ => panic!("unsupported query"), - }); - - deps.querier = querier; - deps - } - - fn setup() -> OwnedDeps> { - let mut deps = make_deps(); - - instantiate( - deps.as_mut(), - mock_env(), - mock_info("instantiator", &[]), - InstantiateMsg { - governance_address: GOVERNANCE_ADDRESS.to_string(), - admin_address: ADMIN_ADDRESS.to_string(), - axelarnet_gateway_address: AXELARNET_GATEWAY_ADDRESS.to_string(), - its_contracts: HashMap::new(), - }, - ) - .unwrap(); - - deps - } -} diff --git a/contracts/interchain-token-service/src/contract/execute.rs b/contracts/interchain-token-service/src/contract/execute.rs index a97ec57eb..11f3e0558 100644 --- a/contracts/interchain-token-service/src/contract/execute.rs +++ b/contracts/interchain-token-service/src/contract/execute.rs @@ -1,20 +1,11 @@ -use axelar_core_std::nexus; -use axelar_wasm_std::{nonempty, FnExt, IntoContractError}; -use cosmwasm_std::{Coin, DepsMut, HexBinary, QuerierWrapper, Response, Storage, Uint128, Uint256}; +use axelar_wasm_std::IntoContractError; +use cosmwasm_std::{DepsMut, HexBinary, QuerierWrapper, Response, Storage}; use error_stack::{bail, ensure, report, Result, ResultExt}; use router_api::{Address, ChainName, ChainNameRaw, CrossChainId}; -use sha3::{Digest, Keccak256}; use crate::events::Event; use crate::primitives::HubMessage; use crate::state::{self, load_config, load_its_contract}; -use crate::{Message, TokenId}; - -// this is just keccak256("its-interchain-token-id-gateway") -const GATEWAY_TOKEN_PREFIX: [u8; 32] = [ - 106, 80, 188, 250, 12, 170, 167, 223, 94, 185, 52, 185, 146, 147, 21, 23, 145, 36, 97, 146, - 215, 72, 32, 167, 6, 16, 83, 155, 176, 213, 112, 44, -]; #[derive(thiserror::Error, Debug, IntoContractError)] pub enum Error { @@ -30,19 +21,8 @@ pub enum Error { FailedItsContractRegistration(ChainNameRaw), #[error("failed to deregister its contract for chain {0}")] FailedItsContractDeregistration(ChainNameRaw), - #[error("failed to register gateway token")] - FailedGatewayTokenRegistration, #[error("failed to execute message")] FailedExecuteMessage, - #[error("failed to generate token id")] - FailedTokenIdGeneration, - #[error("transfer amount exceeds Uint128 max")] - TransferAmountOverflow, - #[error("attached coin {attached:?} does not match expected coin {expected:?}")] - IncorrectAttachedCoin { - attached: Option, - expected: Option, - }, #[error("failed to query nexus")] NexusQueryError, #[error("storage error")] @@ -59,7 +39,6 @@ pub fn execute_message( cc_id: CrossChainId, source_address: Address, payload: HexBinary, - coin: Option, ) -> Result { ensure_its_source_address(deps.storage, &cc_id.source_chain, &source_address)?; @@ -77,15 +56,12 @@ pub fn execute_message( } .abi_encode(); - verify_coin(&deps, &coin, &message, &cc_id.source_chain)?; - Ok(send_to_destination( deps.storage, deps.querier, destination_chain.clone(), destination_address, destination_payload, - gateway_token_transfer(&deps, &destination_chain, &message)?, )? .add_event( Event::MessageReceived { @@ -121,72 +97,20 @@ fn ensure_its_source_address( Ok(()) } -fn verify_coin( - deps: &DepsMut, - coin: &Option, - message: &Message, - source_chain: &ChainNameRaw, -) -> Result<(), Error> { - let expected_coin = gateway_token_transfer(deps, source_chain, message)?; - ensure!( - &expected_coin == coin, - Error::IncorrectAttachedCoin { - attached: coin.clone(), - expected: expected_coin - } - ); - Ok(()) -} - -fn gateway_token_transfer( - deps: &DepsMut, - chain: &ChainNameRaw, - message: &Message, -) -> Result, Error> { - let client: nexus::Client = client::CosmosClient::new(deps.querier).into(); - let is_core_chain = client - .is_chain_registered(&normalize(chain)) - .change_context(Error::NexusQueryError)?; - - if !is_core_chain { - return Ok(None); - } - - let token_id = message.token_id(); - let gateway_denom = state::may_load_gateway_denom(deps.storage, token_id) - .change_context(Error::StorageError)?; - match (gateway_denom, message) { - (Some(denom), Message::InterchainTransfer { amount, .. }) => Ok(Some(Coin { - denom: denom.to_string(), - amount: Uint128::try_from(Uint256::from(*amount)) - .change_context(Error::TransferAmountOverflow)?, - })), - _ => Ok(None), - } -} - fn send_to_destination( storage: &dyn Storage, querier: QuerierWrapper, destination_chain: ChainNameRaw, destination_address: Address, payload: HexBinary, - coin: Option, ) -> Result { let config = load_config(storage); let gateway: axelarnet_gateway::Client = client::ContractClient::new(querier, &config.axelarnet_gateway).into(); - let call_contract_msg = match coin { - Some(coin) => gateway.call_contract_with_token( - normalize(&destination_chain), - destination_address, - payload, - coin, - ), - None => gateway.call_contract(normalize(&destination_chain), destination_address, payload), - }; + let call_contract_msg = + gateway.call_contract(normalize(&destination_chain), destination_address, payload); Ok(Response::new().add_message(call_contract_msg)) } @@ -208,695 +132,3 @@ pub fn deregister_its_contract(deps: DepsMut, chain: ChainNameRaw) -> Result Result { - let token_id = gateway_token_id(&deps, &denom)?; - state::save_gateway_token_denom(deps.storage, token_id, denom) - .change_context(Error::FailedGatewayTokenRegistration)?; - Ok(Response::new()) -} - -pub fn gateway_token_id(deps: &DepsMut, denom: &str) -> Result { - let config = state::load_config(deps.storage); - let gateway: axelarnet_gateway::Client = - client::ContractClient::new(deps.querier, &config.axelarnet_gateway).into(); - let chain_name = gateway - .chain_name() - .change_context(Error::FailedTokenIdGeneration)?; - let chain_name_hash: [u8; 32] = Keccak256::digest(chain_name.to_string().as_bytes()).into(); - - Keccak256::digest([&GATEWAY_TOKEN_PREFIX, &chain_name_hash, denom.as_bytes()].concat()) - .then(<[u8; 32]>::from) - .then(TokenId::new) - .then(Ok) -} - -#[cfg(test)] -mod tests { - use std::marker::PhantomData; - - use assert_ok::assert_ok; - use axelar_core_std::nexus; - use axelar_core_std::nexus::query::IsChainRegisteredResponse; - use axelar_core_std::query::AxelarQueryMsg; - use axelar_wasm_std::msg_id::HexTxHashAndEventIndex; - use axelar_wasm_std::{assert_err_contains, nonempty}; - use axelarnet_gateway::msg::QueryMsg; - use cosmwasm_std::testing::{MockApi, MockQuerier, MockStorage}; - use cosmwasm_std::{ - from_json, to_json_binary, Addr, Coin, CosmosMsg, HexBinary, MemoryStorage, OwnedDeps, - Uint128, Uint256, WasmMsg, WasmQuery, - }; - use router_api::{ChainName, ChainNameRaw, CrossChainId}; - - use super::{gateway_token_id, register_gateway_token, Error}; - use crate::contract::execute::{execute_message, register_its_contract}; - use crate::state::{self, Config}; - use crate::{HubMessage, Message}; - - const CORE_CHAIN: &str = "ethereum"; - const AMPLIFIER_CHAIN: &str = "solana"; - const GATEWAY_TOKEN_DENOM: &str = "eth"; - const ITS_ADDRESS: &str = "68d30f47F19c07bCCEf4Ac7FAE2Dc12FCa3e0dC9"; - - fn dummy_its_address() -> nonempty::HexBinary { - HexBinary::from_hex(ITS_ADDRESS) - .unwrap() - .try_into() - .unwrap() - } - - #[test] - fn gateway_token_id_should_be_idempotent() { - let mut deps = init(); - let denom = "uaxl"; - let token_id = assert_ok!(gateway_token_id(&deps.as_mut(), denom)); - let token_id_2 = assert_ok!(gateway_token_id(&deps.as_mut(), denom)); - assert_eq!(token_id, token_id_2); - } - - #[test] - fn gateway_token_id_should_differ_for_different_denoms() { - let mut deps = init(); - let axl_denom = "uaxl"; - let eth_denom = "eth"; - let token_id_axl = assert_ok!(gateway_token_id(&deps.as_mut(), axl_denom)); - let token_id_eth = assert_ok!(gateway_token_id(&deps.as_mut(), eth_denom)); - assert_ne!(token_id_axl, token_id_eth); - } - - #[test] - fn gateway_token_id_should_not_change() { - let mut deps = init(); - let denom = "uaxl"; - let token_id = assert_ok!(gateway_token_id(&deps.as_mut(), denom)); - goldie::assert_json!(token_id); - } - - #[test] - fn register_token_id_should_not_overwrite() { - let mut deps = init(); - let denom = "uaxl"; - let chain = ChainNameRaw::try_from("ethereum").unwrap(); - assert_ok!(register_gateway_token( - deps.as_mut(), - denom.try_into().unwrap(), - chain.clone() - )); - // calling again should fail - assert_err_contains!( - register_gateway_token(deps.as_mut(), denom.try_into().unwrap(), chain), - Error, - Error::FailedGatewayTokenRegistration - ); - } - - #[test] - fn should_lock_and_unlock_gateway_token() { - let mut deps = init(); - register_token_and_its_contracts(&mut deps); - - let destination_chain = ChainNameRaw::try_from(AMPLIFIER_CHAIN).unwrap(); - let source_chain = ChainNameRaw::try_from(CORE_CHAIN).unwrap(); - let source_address = - HexBinary::from_hex("4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97").unwrap(); - - let token_id = gateway_token_id(&deps.as_mut(), GATEWAY_TOKEN_DENOM).unwrap(); - - let coin = Coin { - denom: GATEWAY_TOKEN_DENOM.to_string(), - amount: Uint128::from(1500u128), - }; - - let msg = HubMessage::SendToHub { - destination_chain: destination_chain.clone(), - message: Message::InterchainTransfer { - token_id: token_id.clone(), - source_address: source_address.clone().try_into().unwrap(), - destination_address: dummy_its_address(), - amount: coin.amount.try_into().unwrap(), - data: None, - }, - }; - assert_ok!(execute_message( - deps.as_mut(), - CrossChainId { - source_chain: source_chain.clone(), - message_id: HexTxHashAndEventIndex::new([1u8; 32], 0u32) - .to_string() - .try_into() - .unwrap(), - }, - ITS_ADDRESS.to_string().try_into().unwrap(), - msg.abi_encode(), - Some(coin.clone()), - )); - - let msg = HubMessage::SendToHub { - destination_chain: source_chain.clone(), - message: Message::InterchainTransfer { - token_id, - source_address: source_address.try_into().unwrap(), - destination_address: dummy_its_address(), - amount: coin.amount.try_into().unwrap(), - data: None, - }, - }; - - let res = assert_ok!(execute_message( - deps.as_mut(), - CrossChainId { - source_chain: destination_chain.clone(), - message_id: HexTxHashAndEventIndex::new([1u8; 32], 0u32) - .to_string() - .try_into() - .unwrap(), - }, - ITS_ADDRESS.to_string().try_into().unwrap(), - msg.abi_encode(), - None, - )); - - match &res.messages[0].msg { - CosmosMsg::Wasm(WasmMsg::Execute { funds, .. }) => { - assert_eq!(funds.len(), 1); - assert_eq!(funds.first().unwrap(), &coin); - } - _ => panic!("incorrect msg type"), - }; - } - - #[test] - fn should_reject_transfer_if_token_id_does_not_match() { - let mut deps = init(); - register_token_and_its_contracts(&mut deps); - - let destination_chain = ChainNameRaw::try_from(AMPLIFIER_CHAIN).unwrap(); - let source_chain = ChainNameRaw::try_from(CORE_CHAIN).unwrap(); - let source_address = - HexBinary::from_hex("4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97").unwrap(); - - let coin = Coin { - denom: GATEWAY_TOKEN_DENOM.to_string(), - amount: Uint128::from(1500u128), - }; - - let msg = HubMessage::SendToHub { - destination_chain: destination_chain.clone(), - message: Message::InterchainTransfer { - token_id: [0u8; 32].into(), - source_address: source_address.try_into().unwrap(), - destination_address: dummy_its_address(), - amount: coin.amount.try_into().unwrap(), - data: None, - }, - }; - let res = execute_message( - deps.as_mut(), - CrossChainId { - source_chain: source_chain.clone(), - message_id: HexTxHashAndEventIndex::new([1u8; 32], 0u32) - .to_string() - .try_into() - .unwrap(), - }, - ITS_ADDRESS.to_string().try_into().unwrap(), - msg.abi_encode(), - Some(coin.clone()), - ); - assert!(res.is_err()); - assert_eq!( - res.unwrap_err().to_string(), - Error::IncorrectAttachedCoin { - attached: Some(coin), - expected: None - } - .to_string() - ); - } - - #[test] - fn should_reject_transfer_if_amount_does_not_match_attached_token() { - let mut deps = init(); - register_token_and_its_contracts(&mut deps); - - let destination_chain = ChainNameRaw::try_from(AMPLIFIER_CHAIN).unwrap(); - let source_chain = ChainNameRaw::try_from(CORE_CHAIN).unwrap(); - let source_address = - HexBinary::from_hex("4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97").unwrap(); - - let token_id = gateway_token_id(&deps.as_mut(), GATEWAY_TOKEN_DENOM).unwrap(); - - let coin = Coin { - denom: GATEWAY_TOKEN_DENOM.to_string(), - amount: Uint128::from(1500u128), - }; - - let amount_in_msg = coin.amount.strict_sub(Uint128::one()); - - let msg = HubMessage::SendToHub { - destination_chain: destination_chain.clone(), - message: Message::InterchainTransfer { - token_id: token_id.clone(), - source_address: source_address.try_into().unwrap(), - destination_address: dummy_its_address(), - amount: amount_in_msg.try_into().unwrap(), - data: None, - }, - }; - let res = execute_message( - deps.as_mut(), - CrossChainId { - source_chain: source_chain.clone(), - message_id: HexTxHashAndEventIndex::new([1u8; 32], 0u32) - .to_string() - .try_into() - .unwrap(), - }, - ITS_ADDRESS.to_string().try_into().unwrap(), - msg.abi_encode(), - Some(coin.clone()), - ); - assert!(res.is_err()); - assert_eq!( - res.unwrap_err().to_string(), - Error::IncorrectAttachedCoin { - attached: Some(coin.clone()), - expected: Some(Coin { - denom: coin.denom, - amount: amount_in_msg - }) - } - .to_string() - ); - } - - #[test] - fn should_reject_transfer_with_token_if_source_chain_is_not_core() { - let mut deps = init(); - register_token_and_its_contracts(&mut deps); - - let destination_chain = ChainNameRaw::try_from(CORE_CHAIN).unwrap(); - let source_chain = ChainNameRaw::try_from(AMPLIFIER_CHAIN).unwrap(); - let source_address = - HexBinary::from_hex("4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97").unwrap(); - - let token_id = gateway_token_id(&deps.as_mut(), GATEWAY_TOKEN_DENOM).unwrap(); - - let coin = Coin { - denom: GATEWAY_TOKEN_DENOM.to_string(), - amount: Uint128::from(1500u128), - }; - - let msg = HubMessage::SendToHub { - destination_chain: destination_chain.clone(), - message: Message::InterchainTransfer { - token_id: token_id.clone(), - source_address: source_address.try_into().unwrap(), - destination_address: dummy_its_address(), - amount: coin.amount.try_into().unwrap(), - data: None, - }, - }; - let res = execute_message( - deps.as_mut(), - CrossChainId { - source_chain: source_chain.clone(), - message_id: HexTxHashAndEventIndex::new([1u8; 32], 0u32) - .to_string() - .try_into() - .unwrap(), - }, - ITS_ADDRESS.to_string().try_into().unwrap(), - msg.abi_encode(), - Some(coin.clone()), - ); - assert!(res.is_err()); - assert_eq!( - res.unwrap_err().to_string(), - Error::IncorrectAttachedCoin { - attached: Some(coin), - expected: None - } - .to_string() - ); - } - - #[test] - fn should_reject_transfer_if_attached_token_is_not_registered() { - let mut deps = init(); - register_token_and_its_contracts(&mut deps); - - let destination_chain = ChainNameRaw::try_from(AMPLIFIER_CHAIN).unwrap(); - let source_chain = ChainNameRaw::try_from(CORE_CHAIN).unwrap(); - let source_address = - HexBinary::from_hex("4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97").unwrap(); - - let denom = "foobar"; - let token_id = gateway_token_id(&deps.as_mut(), denom).unwrap(); - - let coin = Coin { - denom: denom.to_string(), - amount: Uint128::from(1500u128), - }; - - let msg = HubMessage::SendToHub { - destination_chain: destination_chain.clone(), - message: Message::InterchainTransfer { - token_id: token_id.clone(), - source_address: source_address.try_into().unwrap(), - destination_address: dummy_its_address(), - amount: coin.amount.try_into().unwrap(), - data: None, - }, - }; - let res = execute_message( - deps.as_mut(), - CrossChainId { - source_chain: source_chain.clone(), - message_id: HexTxHashAndEventIndex::new([1u8; 32], 0u32) - .to_string() - .try_into() - .unwrap(), - }, - ITS_ADDRESS.to_string().try_into().unwrap(), - msg.abi_encode(), - Some(coin.clone()), - ); - assert!(res.is_err()); - assert_eq!( - res.unwrap_err().to_string(), - Error::IncorrectAttachedCoin { - attached: Some(coin), - expected: None - } - .to_string() - ); - } - - #[test] - fn should_not_attach_coin_if_destination_is_not_core() { - let mut deps = init(); - register_token_and_its_contracts(&mut deps); - - let destination_chain = ChainNameRaw::try_from(AMPLIFIER_CHAIN).unwrap(); - let source_chain = ChainNameRaw::try_from(CORE_CHAIN).unwrap(); - let source_address = - HexBinary::from_hex("4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97").unwrap(); - - let token_id = gateway_token_id(&deps.as_mut(), GATEWAY_TOKEN_DENOM).unwrap(); - - let coin = Coin { - denom: GATEWAY_TOKEN_DENOM.to_string(), - amount: Uint128::from(1500u128), - }; - - // send the token from core to an amplifier chain, should be escrowed - let msg = HubMessage::SendToHub { - destination_chain: destination_chain.clone(), - message: Message::InterchainTransfer { - token_id: token_id.clone(), - source_address: source_address.clone().try_into().unwrap(), - destination_address: dummy_its_address(), - amount: coin.amount.try_into().unwrap(), - data: None, - }, - }; - let res = assert_ok!(execute_message( - deps.as_mut(), - CrossChainId { - source_chain: source_chain.clone(), - message_id: HexTxHashAndEventIndex::new([1u8; 32], 0u32) - .to_string() - .try_into() - .unwrap(), - }, - ITS_ADDRESS.to_string().try_into().unwrap(), - msg.abi_encode(), - Some(coin.clone()), - )); - - // no tokens attached, token is encoded purely as GMP - assert_eq!(res.messages.len(), 1); - match &res.messages[0].msg { - CosmosMsg::Wasm(WasmMsg::Execute { funds, .. }) => assert_eq!(funds.len(), 0), - _ => panic!("incorrect msg type"), - }; - - // now send from amplifier chain to another amplifier chain - let second_destination_chain = ChainNameRaw::try_from("xrpl").unwrap(); - assert_ok!(register_its_contract( - deps.as_mut(), - second_destination_chain.clone(), - ITS_ADDRESS.to_string().try_into().unwrap(), - )); - - let msg = HubMessage::SendToHub { - destination_chain: second_destination_chain.clone(), - message: Message::InterchainTransfer { - token_id, - source_address: source_address.try_into().unwrap(), - destination_address: dummy_its_address(), - amount: coin.amount.try_into().unwrap(), - data: None, - }, - }; - - let res = assert_ok!(execute_message( - deps.as_mut(), - CrossChainId { - source_chain: destination_chain.clone(), - message_id: HexTxHashAndEventIndex::new([1u8; 32], 0u32) - .to_string() - .try_into() - .unwrap(), - }, - ITS_ADDRESS.to_string().try_into().unwrap(), - msg.abi_encode(), - None, - )); - - // no tokens should be attached - assert_eq!(res.messages.len(), 1); - match &res.messages[0].msg { - CosmosMsg::Wasm(WasmMsg::Execute { funds, .. }) => assert_eq!(funds.len(), 0), - _ => panic!("incorrect msg type"), - }; - } - - #[test] - fn can_send_pure_gmp_from_core() { - let mut deps = init(); - register_token_and_its_contracts(&mut deps); - - let destination_chain = ChainNameRaw::try_from(AMPLIFIER_CHAIN).unwrap(); - let source_chain = ChainNameRaw::try_from(CORE_CHAIN).unwrap(); - let source_address = - HexBinary::from_hex("4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97").unwrap(); - - let denom = "wBTC"; - - let token_id = gateway_token_id(&deps.as_mut(), denom).unwrap(); - - // send the token from core to an amplifier chain, should be escrowed - let msg = HubMessage::SendToHub { - destination_chain: destination_chain.clone(), - message: Message::InterchainTransfer { - token_id: token_id.clone(), - source_address: source_address.clone().try_into().unwrap(), - destination_address: dummy_its_address(), - amount: Uint256::one().try_into().unwrap(), - data: None, - }, - }; - - assert_ok!(execute_message( - deps.as_mut(), - CrossChainId { - source_chain: source_chain.clone(), - message_id: HexTxHashAndEventIndex::new([1u8; 32], 0u32) - .to_string() - .try_into() - .unwrap(), - }, - ITS_ADDRESS.to_string().try_into().unwrap(), - msg.abi_encode(), - None, - )); - } - - #[test] - fn should_reject_transfer_from_core_if_gateway_token_is_not_attached() { - let mut deps = init(); - register_token_and_its_contracts(&mut deps); - - let destination_chain = ChainNameRaw::try_from(AMPLIFIER_CHAIN).unwrap(); - let source_chain = ChainNameRaw::try_from(CORE_CHAIN).unwrap(); - let source_address = - HexBinary::from_hex("4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97").unwrap(); - - let token_id = gateway_token_id(&deps.as_mut(), GATEWAY_TOKEN_DENOM).unwrap(); - - let coin = Coin { - denom: GATEWAY_TOKEN_DENOM.to_string(), - amount: Uint128::from(1500u128), - }; - - let msg = HubMessage::SendToHub { - destination_chain: destination_chain.clone(), - message: Message::InterchainTransfer { - token_id: token_id.clone(), - source_address: source_address.clone().try_into().unwrap(), - destination_address: dummy_its_address(), - amount: coin.amount.try_into().unwrap(), - data: None, - }, - }; - let res = execute_message( - deps.as_mut(), - CrossChainId { - source_chain: source_chain.clone(), - message_id: HexTxHashAndEventIndex::new([1u8; 32], 0u32) - .to_string() - .try_into() - .unwrap(), - }, - ITS_ADDRESS.to_string().try_into().unwrap(), - msg.abi_encode(), - None, - ); - assert!(res.is_err()); - assert_eq!( - res.unwrap_err().to_string(), - Error::IncorrectAttachedCoin { - attached: None, - expected: Some(coin) - } - .to_string() - ); - } - - #[test] - fn should_reject_message_if_coin_attached_but_not_interchain_transfer() { - let mut deps = init(); - register_token_and_its_contracts(&mut deps); - - let destination_chain = ChainNameRaw::try_from(AMPLIFIER_CHAIN).unwrap(); - let source_chain = ChainNameRaw::try_from(CORE_CHAIN).unwrap(); - - let token_id = gateway_token_id(&deps.as_mut(), GATEWAY_TOKEN_DENOM).unwrap(); - - let coin = Coin { - denom: GATEWAY_TOKEN_DENOM.to_string(), - amount: Uint128::from(1500u128), - }; - - let msg = HubMessage::SendToHub { - destination_chain: destination_chain.clone(), - message: Message::DeployInterchainToken { - token_id: token_id.clone(), - name: "foobar".try_into().unwrap(), - symbol: "FOO".try_into().unwrap(), - decimals: 10u8, - minter: Some(HexBinary::from([0u8; 32]).try_into().unwrap()), - }, - }; - let res = execute_message( - deps.as_mut(), - CrossChainId { - source_chain: source_chain.clone(), - message_id: HexTxHashAndEventIndex::new([1u8; 32], 0u32) - .to_string() - .try_into() - .unwrap(), - }, - ITS_ADDRESS.to_string().try_into().unwrap(), - msg.abi_encode(), - Some(coin.clone()), - ); - assert!(res.is_err()); - assert_eq!( - res.unwrap_err().to_string(), - Error::IncorrectAttachedCoin { - expected: None, - attached: Some(coin) - } - .to_string() - ); - } - - fn register_token_and_its_contracts( - deps: &mut OwnedDeps>, - ) { - let amplifier_chain = ChainNameRaw::try_from(AMPLIFIER_CHAIN).unwrap(); - let core_chain = ChainNameRaw::try_from(CORE_CHAIN).unwrap(); - - assert_ok!(register_gateway_token( - deps.as_mut(), - GATEWAY_TOKEN_DENOM.try_into().unwrap(), - core_chain.clone() - )); - - assert_ok!(register_its_contract( - deps.as_mut(), - core_chain.clone(), - ITS_ADDRESS.to_string().try_into().unwrap(), - )); - - assert_ok!(register_its_contract( - deps.as_mut(), - amplifier_chain.clone(), - ITS_ADDRESS.to_string().try_into().unwrap(), - )); - } - - fn init() -> OwnedDeps> { - let addr = Addr::unchecked("axelar-gateway"); - let mut deps = OwnedDeps { - storage: MockStorage::default(), - api: MockApi::default(), - querier: MockQuerier::::new(&[]), - custom_query_type: PhantomData, - }; - state::save_config( - deps.as_mut().storage, - &Config { - axelarnet_gateway: addr.clone(), - }, - ) - .unwrap(); - - let mut querier = MockQuerier::::new(&[]); - querier.update_wasm(move |msg| match msg { - WasmQuery::Smart { contract_addr, msg } if contract_addr == &addr.to_string() => { - let msg = from_json::(msg).unwrap(); - match msg { - QueryMsg::ChainName {} => { - Ok(to_json_binary(&ChainName::try_from("axelar").unwrap()).into()).into() - } - _ => panic!("unsupported query"), - } - } - _ => panic!("unexpected query: {:?}", msg), - }); - querier = querier.with_custom_handler(|msg| match msg { - AxelarQueryMsg::Nexus(nexus::query::QueryMsg::IsChainRegistered { chain }) => { - Ok(to_json_binary( - &(IsChainRegisteredResponse { - is_registered: chain == CORE_CHAIN, - }), - ) - .into()) - .into() - } - _ => panic!("unsupported query"), - }); - - deps.querier = querier; - deps - } -} diff --git a/contracts/interchain-token-service/src/contract/query.rs b/contracts/interchain-token-service/src/contract/query.rs index 95c5c9a54..f9aeeea0e 100644 --- a/contracts/interchain-token-service/src/contract/query.rs +++ b/contracts/interchain-token-service/src/contract/query.rs @@ -12,8 +12,3 @@ pub fn all_its_contracts(deps: Deps) -> Result { let contract_addresses = state::load_all_its_contracts(deps.storage)?; Ok(to_json_binary(&contract_addresses)?) } - -pub fn gateway_tokens(deps: Deps) -> Result { - let tokens = state::load_all_gateway_tokens(deps.storage)?; - Ok(to_json_binary(&tokens)?) -} diff --git a/contracts/interchain-token-service/src/msg.rs b/contracts/interchain-token-service/src/msg.rs index 4a3ec107b..c9ff32b55 100644 --- a/contracts/interchain-token-service/src/msg.rs +++ b/contracts/interchain-token-service/src/msg.rs @@ -1,13 +1,10 @@ use std::collections::HashMap; -use axelar_wasm_std::nonempty; use axelarnet_gateway::AxelarExecutableMsg; use cosmwasm_schema::{cw_serde, QueryResponses}; use msgs_derive::EnsurePermissions; use router_api::{Address, ChainNameRaw}; -use crate::TokenId; - #[cw_serde] pub struct InstantiateMsg { pub governance_address: String, @@ -36,13 +33,6 @@ pub enum ExecuteMsg { /// The admin is allowed to remove the ITS address of a chain for emergencies. #[permission(Elevated)] DeregisterItsContract { chain: ChainNameRaw }, - - /// Register legacy gateway token with ITS - #[permission(Governance)] - RegisterGatewayToken { - denom: nonempty::String, - source_chain: ChainNameRaw, - }, } #[cw_serde] @@ -54,6 +44,4 @@ pub enum QueryMsg { /// Query all registererd ITS contract addresses #[returns(HashMap)] AllItsContracts, - #[returns(HashMap)] - GatewayTokens, } diff --git a/contracts/interchain-token-service/src/state.rs b/contracts/interchain-token-service/src/state.rs index 5928ab467..c977ad5fa 100644 --- a/contracts/interchain-token-service/src/state.rs +++ b/contracts/interchain-token-service/src/state.rs @@ -6,8 +6,6 @@ use cosmwasm_std::{ensure, Addr, StdError, Storage}; use cw_storage_plus::{Item, Map}; use router_api::{Address, ChainNameRaw}; -use crate::TokenId; - #[derive(thiserror::Error, Debug, IntoContractError)] pub enum Error { #[error(transparent)] @@ -29,7 +27,6 @@ pub struct Config { const CONFIG: Item = Item::new("config"); const ITS_CONTRACTS: Map<&ChainNameRaw, Address> = Map::new("its_contracts"); -const GATEWAY_TOKEN_DENOMS: Map = Map::new("gateway_token_denoms"); pub fn load_config(storage: &dyn Storage) -> Config { CONFIG @@ -84,34 +81,6 @@ pub fn load_all_its_contracts( .collect::, _>>()?) } -pub fn save_gateway_token_denom( - storage: &mut dyn Storage, - token_id: TokenId, - denom: nonempty::String, -) -> Result<(), Error> { - GATEWAY_TOKEN_DENOMS.update(storage, token_id, |stored_denom| match stored_denom { - None => Ok(denom), - _ => Err(Error::GatewayTokenAlreadyRegistered(denom)), - })?; - Ok(()) -} - -pub fn may_load_gateway_denom( - storage: &dyn Storage, - token_id: TokenId, -) -> Result, Error> { - Ok(GATEWAY_TOKEN_DENOMS.may_load(storage, token_id)?) -} - -pub fn load_all_gateway_tokens( - storage: &dyn Storage, -) -> Result, Error> { - Ok(GATEWAY_TOKEN_DENOMS - .range(storage, None, None, cosmwasm_std::Order::Ascending) - .map(|res| res.map(|(token_id, denom)| (denom, token_id))) - .collect::, _>>()?) -} - #[cfg(test)] mod tests { use assert_ok::assert_ok;