diff --git a/contracts/interchain-token-service/src/contract.rs b/contracts/interchain-token-service/src/contract.rs index 9edd5ca9..5ecbaaa6 100644 --- a/contracts/interchain-token-service/src/contract.rs +++ b/contracts/interchain-token-service/src/contract.rs @@ -354,6 +354,15 @@ impl InterchainTokenServiceInterface for InterchainTokenService { ) -> Result<(), ContractError> { ensure!(amount > 0, ContractError::InvalidAmount); + ensure!( + !destination_address.is_empty(), + ContractError::InvalidDestinationAddress + ); + + if let Some(ref data) = data { + ensure!(!data.is_empty(), ContractError::InvalidData); + } + caller.require_auth(); token_handler::take_token( @@ -729,6 +738,11 @@ impl InterchainTokenService { destination_chain: String, gas_token: Token, ) -> Result, ContractError> { + ensure!( + destination_chain != Self::chain_name(env), + ContractError::InvalidDestinationChain + ); + let token_id = Self::interchain_token_id(env, Address::zero(env), deploy_salt); let token_address = Self::token_id_config(env, token_id.clone())?.token_address; let token = token::Client::new(env, &token_address); diff --git a/contracts/interchain-token-service/src/error.rs b/contracts/interchain-token-service/src/error.rs index fb6e0b01..ed82ffc2 100644 --- a/contracts/interchain-token-service/src/error.rs +++ b/contracts/interchain-token-service/src/error.rs @@ -28,6 +28,8 @@ pub enum ContractError { FlowLimitExceeded = 20, FlowAmountOverflow = 21, NotApproved = 22, + InvalidDestinationChain = 23, + InvalidData = 24, } impl_not_approved_error!(ContractError); diff --git a/contracts/interchain-token-service/tests/deploy_remote_interchain_token.rs b/contracts/interchain-token-service/tests/deploy_remote_interchain_token.rs index 42c7326d..a5e01b01 100644 --- a/contracts/interchain-token-service/tests/deploy_remote_interchain_token.rs +++ b/contracts/interchain-token-service/tests/deploy_remote_interchain_token.rs @@ -141,3 +141,23 @@ fn deploy_remote_interchain_token_fails_with_invalid_token_id() { ContractError::InvalidTokenId ); } + +#[test] +fn deploy_remote_token_fails_local_deployment() { + let (env, client, _, _, _) = setup_env(); + + let spender = Address::generate(&env); + let gas_token = setup_gas_token(&env, &spender); + let salt = BytesN::<32>::from_array(&env, &[1; 32]); + let destination_chain = client.chain_name(); + + assert_contract_err!( + client.mock_all_auths().try_deploy_remote_interchain_token( + &spender, + &salt, + &destination_chain, + &gas_token + ), + ContractError::InvalidDestinationChain + ); +} diff --git a/contracts/interchain-token-service/tests/interchain_transfer.rs b/contracts/interchain-token-service/tests/interchain_transfer.rs index 8663e6b3..6c14f988 100644 --- a/contracts/interchain-token-service/tests/interchain_transfer.rs +++ b/contracts/interchain-token-service/tests/interchain_transfer.rs @@ -2,8 +2,9 @@ mod utils; use soroban_sdk::testutils::Address as _; use soroban_sdk::{Address, Bytes, String}; -use stellar_axelar_std::events; use stellar_axelar_std::traits::BytesExt; +use stellar_axelar_std::{assert_contract_err, events}; +use stellar_interchain_token_service::error::ContractError; use stellar_interchain_token_service::event::InterchainTransferSentEvent; use utils::{register_chains, setup_env, setup_gas_token, setup_its_token}; @@ -64,3 +65,87 @@ fn interchain_transfer_send_fails_on_insufficient_balance() { &gas_token, ); } + +#[test] +fn interchain_transfer_fails_on_zero_amount() { + let (env, client, _, _, _) = setup_env(); + register_chains(&env, &client); + + let sender: Address = Address::generate(&env); + let gas_token = setup_gas_token(&env, &sender); + let amount = 0; + let token_id = setup_its_token(&env, &client, &sender, amount); + + let destination_chain = client.its_hub_chain_name(); + let destination_address = Bytes::from_hex(&env, "4F4495243837681061C4743b74B3eEdf548D56A5"); + let data = Some(Bytes::from_hex(&env, "abcd")); + + assert_contract_err!( + client.mock_all_auths().try_interchain_transfer( + &sender, + &token_id, + &destination_chain, + &destination_address, + &amount, + &data, + &gas_token + ), + ContractError::InvalidAmount + ); +} + +#[test] +fn interchain_transfer_fails_on_empty_destination_address() { + let (env, client, _, _, _) = setup_env(); + register_chains(&env, &client); + + let sender: Address = Address::generate(&env); + let gas_token = setup_gas_token(&env, &sender); + let amount = 1000; + let token_id = setup_its_token(&env, &client, &sender, amount); + + let destination_chain = client.its_hub_chain_name(); + let destination_address = Bytes::new(&env); + let data = Some(Bytes::from_hex(&env, "abcd")); + + assert_contract_err!( + client.mock_all_auths().try_interchain_transfer( + &sender, + &token_id, + &destination_chain, + &destination_address, + &amount, + &data, + &gas_token + ), + ContractError::InvalidDestinationAddress + ); +} + +#[test] +fn interchain_transfer_fails_on_empty_data() { + let (env, client, _, _, _) = setup_env(); + register_chains(&env, &client); + + let sender: Address = Address::generate(&env); + let gas_token = setup_gas_token(&env, &sender); + let amount = 1000; + let token_id = setup_its_token(&env, &client, &sender, amount); + + let destination_chain = client.its_hub_chain_name(); + let destination_address = Bytes::from_hex(&env, "4F4495243837681061C4743b74B3eEdf548D56A5"); + let empty_data = Some(Bytes::new(&env)); + + assert_contract_err!( + client.mock_all_auths().try_interchain_transfer( + &sender, + &token_id, + &destination_chain, + &destination_address, + &amount, + &empty_data, + &gas_token + ), + ContractError::InvalidData + ); +}