diff --git a/contracts/interchain-token-service/src/contract/execute/interceptors.rs b/contracts/interchain-token-service/src/contract/execute/interceptors.rs index beb69a0fb..33f29235e 100644 --- a/contracts/interchain-token-service/src/contract/execute/interceptors.rs +++ b/contracts/interchain-token-service/src/contract/execute/interceptors.rs @@ -205,13 +205,15 @@ fn destination_token_decimals( state::load_chain_config(storage, destination_chain).change_context(Error::State)?; if source_chain_config + .truncation .max_uint - .le(&destination_chain_config.max_uint) + .le(&destination_chain_config.truncation.max_uint) { source_chain_decimals } else { - source_chain_config - .max_target_decimals + destination_chain_config + .truncation + .max_decimals_when_truncating .min(source_chain_decimals) } .then(Result::Ok) @@ -244,6 +246,7 @@ fn destination_amount( let destination_max_uint = state::load_chain_config(storage, destination_chain) .change_context(Error::State)? + .truncation .max_uint; // It's intentionally written in this way since the end result may still be fine even if @@ -311,6 +314,7 @@ mod test { use super::Error; use crate::contract::execute::interceptors; + use crate::msg::TruncationConfig; use crate::state::{self, TokenDeploymentType}; use crate::{msg, DeployInterchainToken, InterchainTransfer, TokenInstance}; @@ -347,8 +351,10 @@ mod test { msg::ChainConfig { chain: destination_chain.clone(), its_edge_contract: "itsedgecontract".to_string().try_into().unwrap(), - max_uint: Uint256::from(1_000_000_000u128).try_into().unwrap(), - max_target_decimals: 6, + truncation: TruncationConfig { + max_uint: Uint256::from(1_000_000_000u128).try_into().unwrap(), + max_decimals_when_truncating: 6, + }, }, ) .unwrap(); @@ -398,8 +404,10 @@ mod test { msg::ChainConfig { chain: destination_chain.clone(), its_edge_contract: "itsedgecontract".to_string().try_into().unwrap(), - max_uint: Uint256::from(1_000_000_000_000_000u128).try_into().unwrap(), - max_target_decimals: 6, + truncation: TruncationConfig { + max_uint: Uint256::from(1_000_000_000_000_000u128).try_into().unwrap(), + max_decimals_when_truncating: 6, + }, }, ) .unwrap(); @@ -449,8 +457,10 @@ mod test { msg::ChainConfig { chain: destination_chain.clone(), its_edge_contract: "itsedgecontract".to_string().try_into().unwrap(), - max_uint: Uint256::from(1_000_000_000_000_000u128).try_into().unwrap(), - max_target_decimals: 6, + truncation: TruncationConfig { + max_uint: Uint256::from(1_000_000_000_000_000u128).try_into().unwrap(), + max_decimals_when_truncating: 6, + }, }, ) .unwrap(); @@ -500,8 +510,10 @@ mod test { msg::ChainConfig { chain: destination_chain.clone(), its_edge_contract: "itsedgecontract".to_string().try_into().unwrap(), - max_uint: Uint256::from(100_000u128).try_into().unwrap(), - max_target_decimals: 6, + truncation: TruncationConfig { + max_uint: Uint256::from(100_000u128).try_into().unwrap(), + max_decimals_when_truncating: 6, + }, }, ) .unwrap(); @@ -551,8 +563,10 @@ mod test { msg::ChainConfig { chain: destination_chain.clone(), its_edge_contract: "itsedgecontract".to_string().try_into().unwrap(), - max_uint: Uint256::from(100_000u128).try_into().unwrap(), - max_target_decimals: 6, + truncation: TruncationConfig { + max_uint: Uint256::from(100_000u128).try_into().unwrap(), + max_decimals_when_truncating: 6, + }, }, ) .unwrap(); @@ -588,8 +602,10 @@ mod test { msg::ChainConfig { chain: source_chain.clone(), its_edge_contract: "itsedgecontract".to_string().try_into().unwrap(), - max_uint: Uint256::from(1_000_000_000_000_000u128).try_into().unwrap(), - max_target_decimals: 6, + truncation: TruncationConfig { + max_uint: Uint256::from(1_000_000_000_000_000u128).try_into().unwrap(), + max_decimals_when_truncating: 6, + }, }, ) .unwrap(); @@ -599,8 +615,10 @@ mod test { msg::ChainConfig { chain: destination_chain.clone(), its_edge_contract: "itsedgecontract".to_string().try_into().unwrap(), - max_uint: Uint256::from(1_000_000_000u128).try_into().unwrap(), - max_target_decimals: 6, + truncation: TruncationConfig { + max_uint: Uint256::from(1_000_000_000u128).try_into().unwrap(), + max_decimals_when_truncating: 6, + }, }, ) .unwrap(); @@ -648,8 +666,10 @@ mod test { msg::ChainConfig { chain: source_chain.clone(), its_edge_contract: "itsedgecontract".to_string().try_into().unwrap(), - max_uint: Uint256::from(1_000_000_000u128).try_into().unwrap(), - max_target_decimals: 6, + truncation: TruncationConfig { + max_uint: Uint256::from(1_000_000_000u128).try_into().unwrap(), + max_decimals_when_truncating: 6, + }, }, ) .unwrap(); @@ -659,8 +679,10 @@ mod test { msg::ChainConfig { chain: destination_chain.clone(), its_edge_contract: "itsedgecontract".to_string().try_into().unwrap(), - max_uint: Uint256::from(1_000_000_000_000_000u128).try_into().unwrap(), - max_target_decimals: 6, + truncation: TruncationConfig { + max_uint: Uint256::from(1_000_000_000_000_000u128).try_into().unwrap(), + max_decimals_when_truncating: 6, + }, }, ) .unwrap(); diff --git a/contracts/interchain-token-service/src/contract/execute/mod.rs b/contracts/interchain-token-service/src/contract/execute/mod.rs index ed862e331..3bbb4b925 100644 --- a/contracts/interchain-token-service/src/contract/execute/mod.rs +++ b/contracts/interchain-token-service/src/contract/execute/mod.rs @@ -300,6 +300,7 @@ mod tests { disable_execution, enable_execution, execute_message, freeze_chain, register_chain, register_chains, unfreeze_chain, update_chain, Error, }; + use crate::msg::TruncationConfig; use crate::state::{self, Config}; use crate::{msg, DeployInterchainToken, HubMessage, InterchainTransfer}; @@ -536,8 +537,10 @@ mod tests { msg::ChainConfig { chain: SOLANA.parse().unwrap(), its_edge_contract: ITS_ADDRESS.to_string().try_into().unwrap(), - max_uint: Uint256::one().try_into().unwrap(), - max_target_decimals: 16u8 + truncation: TruncationConfig { + max_uint: Uint256::one().try_into().unwrap(), + max_decimals_when_truncating: 16u8 + } } )); assert_err_contains!( @@ -546,8 +549,10 @@ mod tests { msg::ChainConfig { chain: SOLANA.parse().unwrap(), its_edge_contract: ITS_ADDRESS.to_string().try_into().unwrap(), - max_uint: Uint256::one().try_into().unwrap(), - max_target_decimals: 16u8 + truncation: TruncationConfig { + max_uint: Uint256::one().try_into().unwrap(), + max_decimals_when_truncating: 16u8 + } } ), Error, @@ -562,14 +567,18 @@ mod tests { msg::ChainConfig { chain: SOLANA.parse().unwrap(), its_edge_contract: ITS_ADDRESS.to_string().try_into().unwrap(), - max_uint: Uint256::MAX.try_into().unwrap(), - max_target_decimals: 16u8, + truncation: TruncationConfig { + max_uint: Uint256::MAX.try_into().unwrap(), + max_decimals_when_truncating: 16u8, + }, }, msg::ChainConfig { chain: XRPL.parse().unwrap(), its_edge_contract: ITS_ADDRESS.to_string().try_into().unwrap(), - max_uint: Uint256::MAX.try_into().unwrap(), - max_target_decimals: 16u8, + truncation: TruncationConfig { + max_uint: Uint256::MAX.try_into().unwrap(), + max_decimals_when_truncating: 16u8, + }, }, ]; assert_ok!(register_chains(deps.as_mut(), chains[0..1].to_vec())); @@ -623,8 +632,10 @@ mod tests { msg::ChainConfig { chain: chain.clone(), its_edge_contract: ITS_ADDRESS.to_string().try_into().unwrap(), - max_uint: Uint256::one().try_into().unwrap(), - max_target_decimals: 16u8 + truncation: TruncationConfig { + max_uint: Uint256::one().try_into().unwrap(), + max_decimals_when_truncating: 16u8 + } } )); } diff --git a/contracts/interchain-token-service/src/msg.rs b/contracts/interchain-token-service/src/msg.rs index a52e55029..e9364019a 100644 --- a/contracts/interchain-token-service/src/msg.rs +++ b/contracts/interchain-token-service/src/msg.rs @@ -57,8 +57,13 @@ pub enum ExecuteMsg { pub struct ChainConfig { pub chain: ChainNameRaw, pub its_edge_contract: Address, + pub truncation: TruncationConfig, +} + +#[cw_serde] +pub struct TruncationConfig { pub max_uint: nonempty::Uint256, // The maximum uint value that is supported by the chain's token standard - pub max_target_decimals: u8, // The maximum number of decimals that is preserved when deploying a token to another chain where smaller uint values are used + pub max_decimals_when_truncating: u8, // The maximum number of decimals that is preserved when deploying from a chain with a larger max_uint } #[cw_serde] diff --git a/contracts/interchain-token-service/src/state.rs b/contracts/interchain-token-service/src/state.rs index 692319850..f408ab4bf 100644 --- a/contracts/interchain-token-service/src/state.rs +++ b/contracts/interchain-token-service/src/state.rs @@ -34,17 +34,24 @@ pub struct Config { #[cw_serde] pub struct ChainConfig { - pub max_uint: nonempty::Uint256, - pub max_target_decimals: u8, + pub truncation: TruncationConfig, pub its_address: Address, frozen: bool, } +#[cw_serde] +pub struct TruncationConfig { + pub max_uint: nonempty::Uint256, + pub max_decimals_when_truncating: u8, +} + impl From for ChainConfig { fn from(value: msg::ChainConfig) -> Self { Self { - max_uint: value.max_uint, - max_target_decimals: value.max_target_decimals, + truncation: TruncationConfig { + max_uint: value.truncation.max_uint, + max_decimals_when_truncating: value.truncation.max_decimals_when_truncating, + }, its_address: value.its_edge_contract, frozen: false, } @@ -326,8 +333,10 @@ mod tests { msg::ChainConfig { chain: chain1.clone(), its_edge_contract: address1.clone(), - max_uint: Uint256::MAX.try_into().unwrap(), - max_target_decimals: 16u8 + truncation: msg::TruncationConfig { + max_uint: Uint256::MAX.try_into().unwrap(), + max_decimals_when_truncating: 16u8 + } } )); assert_ok!(save_chain_config( @@ -336,8 +345,10 @@ mod tests { msg::ChainConfig { chain: chain2.clone(), its_edge_contract: address2.clone(), - max_uint: Uint256::MAX.try_into().unwrap(), - max_target_decimals: 16u8 + truncation: msg::TruncationConfig { + max_uint: Uint256::MAX.try_into().unwrap(), + max_decimals_when_truncating: 16u8 + } } )); assert_eq!( diff --git a/contracts/interchain-token-service/tests/execute.rs b/contracts/interchain-token-service/tests/execute.rs index f1b9677d1..2ddec0568 100644 --- a/contracts/interchain-token-service/tests/execute.rs +++ b/contracts/interchain-token-service/tests/execute.rs @@ -8,7 +8,7 @@ use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; use cosmwasm_std::{HexBinary, Uint256}; use interchain_token_service::contract::{self, ExecuteError}; use interchain_token_service::events::Event; -use interchain_token_service::msg::{self, ExecuteMsg}; +use interchain_token_service::msg::{self, ExecuteMsg, TruncationConfig}; use interchain_token_service::{ DeployInterchainToken, HubMessage, InterchainTransfer, TokenId, TokenSupply, }; @@ -111,8 +111,10 @@ fn register_multiple_chains_succeeds() { .map(|i| msg::ChainConfig { chain: i.to_string().parse().unwrap(), its_edge_contract: i.to_string().parse().unwrap(), - max_target_decimals: 18u8, - max_uint: Uint256::MAX.try_into().unwrap(), + truncation: TruncationConfig { + max_decimals_when_truncating: 18u8, + max_uint: Uint256::MAX.try_into().unwrap(), + }, }) .collect(); assert_ok!(register_chains(deps.as_mut(), chains.clone())); @@ -134,8 +136,10 @@ fn register_multiple_chains_fails_if_one_invalid() { .map(|i| msg::ChainConfig { chain: i.to_string().parse().unwrap(), its_edge_contract: i.to_string().parse().unwrap(), - max_target_decimals: 18u8, - max_uint: Uint256::MAX.try_into().unwrap(), + truncation: TruncationConfig { + max_decimals_when_truncating: 18u8, + max_uint: Uint256::MAX.try_into().unwrap(), + }, }) .collect(); assert_ok!(register_chains(deps.as_mut(), chains[0..1].to_vec())); diff --git a/contracts/interchain-token-service/tests/utils/execute.rs b/contracts/interchain-token-service/tests/utils/execute.rs index 0c7c4ac97..7885341c6 100644 --- a/contracts/interchain-token-service/tests/utils/execute.rs +++ b/contracts/interchain-token-service/tests/utils/execute.rs @@ -10,7 +10,7 @@ use cosmwasm_std::{ from_json, to_json_binary, Addr, DepsMut, HexBinary, MemoryStorage, OwnedDeps, Response, Uint256, WasmQuery, }; -use interchain_token_service::msg::{self, ExecuteMsg}; +use interchain_token_service::msg::{self, ExecuteMsg, TruncationConfig}; use interchain_token_service::{contract, HubMessage}; use router_api::{Address, ChainName, ChainNameRaw, CrossChainId}; @@ -88,15 +88,17 @@ pub fn register_chain( chain: ChainNameRaw, its_edge_contract: Address, max_uint: nonempty::Uint256, - max_target_decimals: u8, + max_decimals_when_truncating: u8, ) -> Result { register_chains( deps, vec![msg::ChainConfig { chain, its_edge_contract, - max_uint, - max_target_decimals, + truncation: TruncationConfig { + max_uint, + max_decimals_when_truncating, + }, }], ) }