Skip to content

Commit

Permalink
feat(interchain-token-service): add message type SetChainConfig
Browse files Browse the repository at this point in the history
  • Loading branch information
fish-sammy committed Oct 28, 2024
1 parent 340975d commit 78c3c8e
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 5 deletions.
8 changes: 8 additions & 0 deletions contracts/interchain-token-service/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pub enum Error {
RegisterItsContract,
#[error("failed to deregsiter an its edge contract")]
DeregisterItsContract,
#[error("failed to set chain config")]
SetChainConfig,
#[error("too many coins attached. Execute accepts zero or one coins")]
TooManyCoins,
#[error("failed to query its address")]
Expand Down Expand Up @@ -99,6 +101,12 @@ pub fn execute(
execute::deregister_its_contract(deps, chain)
.change_context(Error::DeregisterItsContract)
}
ExecuteMsg::SetChainConfig {
chain,
max_uint,
max_target_decimals,
} => execute::set_chain_config(deps, chain, max_uint, max_target_decimals)
.change_context(Error::DeregisterItsContract),
}?
.then(Ok)
}
Expand Down
32 changes: 29 additions & 3 deletions contracts/interchain-token-service/src/contract/execute.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use axelar_wasm_std::IntoContractError;
use cosmwasm_std::{DepsMut, HexBinary, QuerierWrapper, Response, Storage};
use error_stack::{bail, ensure, report, Result, ResultExt};
use axelar_wasm_std::{FnExt, IntoContractError};
use cosmwasm_std::{DepsMut, HexBinary, QuerierWrapper, Response, Storage, Uint256};
use error_stack::{bail, ensure, report, Report, Result, ResultExt};
use router_api::{Address, ChainName, ChainNameRaw, CrossChainId};

use crate::events::Event;
Expand All @@ -27,6 +27,10 @@ pub enum Error {
NexusQueryError,
#[error("storage error")]
StorageError,
#[error("chain config for {0} already set")]
ChainConfigAlreadySet(ChainNameRaw),
#[error("invalid chain max uint")]
InvalidChainMaxUint,
}

/// Executes an incoming ITS message.
Expand Down Expand Up @@ -132,3 +136,25 @@ pub fn deregister_its_contract(deps: DepsMut, chain: ChainNameRaw) -> Result<Res

Ok(Response::new().add_event(Event::ItsContractDeregistered { chain }.into()))
}

pub fn set_chain_config(
deps: DepsMut,
chain: ChainNameRaw,
max_uint: Uint256,
max_target_decimals: u8,
) -> Result<Response, Error> {
match state::load_chain_config(deps.storage, &chain).change_context(Error::StorageError)? {
Some(_) => bail!(Error::ChainConfigAlreadySet(chain)),
None => state::save_chain_config(
deps.storage,
&chain,
max_uint
.try_into()
.map_err(Report::new)
.change_context(Error::InvalidChainMaxUint)?,
max_target_decimals,
)
.change_context(Error::StorageError)?
.then(|_| Ok(Response::new())),
}
}
8 changes: 8 additions & 0 deletions contracts/interchain-token-service/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::collections::HashMap;

use axelarnet_gateway::AxelarExecutableMsg;
use cosmwasm_schema::{cw_serde, QueryResponses};
use cosmwasm_std::Uint256;
use msgs_derive::EnsurePermissions;
use router_api::{Address, ChainNameRaw};

Expand Down Expand Up @@ -33,6 +34,13 @@ pub enum ExecuteMsg {
/// The admin is allowed to remove the ITS address of a chain for emergencies.
#[permission(Elevated)]
DeregisterItsContract { chain: ChainNameRaw },

#[permission(Governance)]
SetChainConfig {
chain: ChainNameRaw,
max_uint: Uint256,
max_target_decimals: u8,
},
}

#[cw_serde]
Expand Down
33 changes: 32 additions & 1 deletion contracts/interchain-token-service/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::collections::HashMap;

use axelar_wasm_std::{nonempty, IntoContractError};
use axelar_wasm_std::nonempty::{self, Uint256};
use axelar_wasm_std::IntoContractError;
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{ensure, Addr, StdError, Storage};
use cw_storage_plus::{Item, Map};
Expand All @@ -25,8 +26,15 @@ pub struct Config {
pub axelarnet_gateway: Addr,
}

#[cw_serde]
pub struct ChainConfig {
max_uint: Uint256,
max_target_decimals: u8,
}

const CONFIG: Item<Config> = Item::new("config");
const ITS_CONTRACTS: Map<&ChainNameRaw, Address> = Map::new("its_contracts");
const CHAIN_CONFIGS: Map<&ChainNameRaw, ChainConfig> = Map::new("chain_configs");

pub fn load_config(storage: &dyn Storage) -> Config {
CONFIG
Expand All @@ -38,6 +46,29 @@ pub fn save_config(storage: &mut dyn Storage, config: &Config) -> Result<(), Err
Ok(CONFIG.save(storage, config)?)
}

pub fn load_chain_config(
storage: &dyn Storage,
chain: &ChainNameRaw,
) -> Result<Option<ChainConfig>, Error> {
Ok(CHAIN_CONFIGS.may_load(storage, chain)?)
}

pub fn save_chain_config(
storage: &mut dyn Storage,
chain: &ChainNameRaw,
max_uint: Uint256,
max_target_decimals: u8,
) -> Result<(), Error> {
Ok(CHAIN_CONFIGS.save(
storage,
chain,
&ChainConfig {
max_uint,
max_target_decimals,
},
)?)
}

pub fn may_load_its_contract(
storage: &dyn Storage,
chain: &ChainNameRaw,
Expand Down
55 changes: 55 additions & 0 deletions contracts/interchain-token-service/tests/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,3 +314,58 @@ fn execute_message_when_invalid_message_type_fails() {
);
assert_err_contains!(result, ExecuteError, ExecuteError::InvalidMessageType);
}

#[test]
fn set_chain_config_should_succeed() {
let chain = "ethereum".parse().unwrap();
let max_uint = "120000000000000000000000000".parse().unwrap();
let decimals = 18;

let mut deps = mock_dependencies();
utils::instantiate_contract(deps.as_mut()).unwrap();

assert_ok!(utils::set_chain_config(
deps.as_mut(),
chain,
max_uint,
decimals
));
}

#[test]
fn set_chain_config_should_fail_if_max_uint_is_zero() {
let chain: ChainNameRaw = "ethereum".parse().unwrap();
let max_uint = 0u64.into();
let decimals = 18;

let mut deps = mock_dependencies();
utils::instantiate_contract(deps.as_mut()).unwrap();

assert_err_contains!(
utils::set_chain_config(deps.as_mut(), chain, max_uint, decimals),
ExecuteError,
ExecuteError::InvalidChainMaxUint
)
}

#[test]
fn set_chain_config_should_fail_if_chain_config_is_already_set() {
let chain: ChainNameRaw = "ethereum".parse().unwrap();
let max_uint = "120000000000000000000000000".parse().unwrap();
let decimals = 18;

let mut deps = mock_dependencies();
utils::instantiate_contract(deps.as_mut()).unwrap();

assert_ok!(utils::set_chain_config(
deps.as_mut(),
chain.clone(),
max_uint,
decimals
));
assert_err_contains!(
utils::set_chain_config(deps.as_mut(), chain, max_uint, decimals),
ExecuteError,
ExecuteError::ChainConfigAlreadySet(_)
)
}
20 changes: 19 additions & 1 deletion contracts/interchain-token-service/tests/utils/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use axelar_wasm_std::error::ContractError;
use cosmwasm_std::testing::{mock_env, mock_info, MockApi, MockQuerier, MockStorage};
use cosmwasm_std::{
from_json, to_json_binary, Addr, DepsMut, HexBinary, MemoryStorage, OwnedDeps, Response,
WasmQuery,
Uint256, WasmQuery,
};
use interchain_token_service::contract;
use interchain_token_service::msg::ExecuteMsg;
Expand Down Expand Up @@ -58,6 +58,24 @@ pub fn deregister_its_contract(
)
}

pub fn set_chain_config(
deps: DepsMut,
chain: ChainNameRaw,
max_uint: Uint256,
max_target_decimals: u8,
) -> Result<Response, ContractError> {
contract::execute(
deps,
mock_env(),
mock_info(params::GOVERNANCE, &[]),
ExecuteMsg::SetChainConfig {
chain,
max_uint,
max_target_decimals,
},
)
}

pub fn make_deps() -> OwnedDeps<MemoryStorage, MockApi, MockQuerier<AxelarQueryMsg>> {
let addr = Addr::unchecked(params::GATEWAY);
let mut deps = OwnedDeps {
Expand Down

0 comments on commit 78c3c8e

Please sign in to comment.