Skip to content

Commit

Permalink
update golden files and fix merge conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
TanvirDeol committed Jan 18, 2025
2 parents 8d80826 + 1a5876d commit 512ddf4
Show file tree
Hide file tree
Showing 34 changed files with 830 additions and 533 deletions.
284 changes: 146 additions & 138 deletions contracts/interchain-token-service/src/contract.rs

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions contracts/interchain-token-service/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ pub enum ContractError {
InvalidUtf8 = 11,
InvalidMinter = 12,
InvalidDestinationAddress = 13,
InvalidHubChain = 14,
TokenAlreadyRegistered = 15,
NotHubChain = 14,
NotHubAddress = 15,
InvalidTokenMetaData = 16,
InvalidTokenId = 17,
TokenAlreadyDeployed = 18,
Expand All @@ -30,6 +30,10 @@ pub enum ContractError {
NotApproved = 22,
InvalidDestinationChain = 23,
InvalidData = 24,
InvalidTokenName = 25,
InvalidTokenSymbol = 26,
InvalidTokenDecimals = 27,
TokenAlreadyRegistered = 28,
}

impl_not_approved_error!(ContractError);
16 changes: 10 additions & 6 deletions contracts/interchain-token-service/src/flow_limit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,18 @@ pub fn set_flow_limit(
token_id: BytesN<32>,
flow_limit: Option<i128>,
) -> Result<(), ContractError> {
if let Some(limit) = flow_limit {
ensure!(limit >= 0, ContractError::InvalidFlowLimit);
if let Some(flow_limit) = flow_limit {
ensure!(flow_limit >= 0, ContractError::InvalidFlowLimit);

env.storage()
.persistent()
.set(&DataKey::FlowLimit(token_id.clone()), &flow_limit);
} else {
env.storage()
.persistent()
.remove(&DataKey::FlowLimit(token_id.clone()));
}

env.storage()
.persistent()
.set(&DataKey::FlowLimit(token_id.clone()), &flow_limit);

FlowLimitSetEvent {
token_id,
flow_limit,
Expand Down
27 changes: 16 additions & 11 deletions contracts/interchain-token-service/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,23 @@ use crate::types::TokenManagerType;
#[allow(dead_code)]
#[contractclient(name = "InterchainTokenServiceClient")]
pub trait InterchainTokenServiceInterface: AxelarExecutableInterface {
/// Returns the name of the current chain.
fn chain_name(env: &Env) -> String;

/// Returns the address of the Gas Service contract.
fn gas_service(env: &Env) -> Address;

/// Returns the WASM hash of the token contract used for deploying interchain tokens.
fn interchain_token_wasm_hash(env: &Env) -> BytesN<32>;
/// Returns the name of the current chain.
fn chain_name(env: &Env) -> String;

/// Returns the name of the chain on which the ITS Hub is deployed.
fn its_hub_chain_name(env: &Env) -> String;

/// Returns the address of the ITS Hub.
fn its_hub_address(env: &Env) -> String;

/// Returns the name of the chain on which the ITS Hub is deployed.
fn its_hub_chain_name(env: &Env) -> String;
/// Returns the address of the native token on the current chain.
fn native_token_address(env: &Env) -> Address;

/// Returns the WASM hash of the token contract used for deploying interchain tokens.
fn interchain_token_wasm_hash(env: &Env) -> BytesN<32>;

/// Returns whether the specified chain is trusted for cross-chain messaging.
fn is_trusted_chain(env: &Env, chain: String) -> bool;
Expand Down Expand Up @@ -129,7 +132,7 @@ pub trait InterchainTokenServiceInterface: AxelarExecutableInterface {
/// - `ContractError::InvalidMinter`: If the minter address is invalid.
///
/// # Authorization
/// - The caller must authenticate.
/// - The `deployer` must authenticate.
fn deploy_interchain_token(
env: &Env,
deployer: Address,
Expand All @@ -155,7 +158,7 @@ pub trait InterchainTokenServiceInterface: AxelarExecutableInterface {
/// - Any error propagated from `pay_gas_and_call_contract`.
///
/// # Authorization
/// - The caller must authenticate.
/// - The `caller` must authenticate.
fn deploy_remote_interchain_token(
env: &Env,
caller: Address,
Expand All @@ -182,6 +185,8 @@ pub trait InterchainTokenServiceInterface: AxelarExecutableInterface {
/// Deploys a remote canonical token on a specified destination chain.
///
/// Anyone can call this to deploy a trustless canonical representation of the token to any trusted destination chain.
/// If the token name is longer than 32 characters, the symbol will be used as the name.
/// Specifically, natively issued Stellar assets will be deployed with the symbol as the name.
///
/// # Arguments
/// * `token_address` - The address of the token to be deployed.
Expand All @@ -197,7 +202,7 @@ pub trait InterchainTokenServiceInterface: AxelarExecutableInterface {
/// - Any error propagated from `pay_gas_and_call_contract`.
///
/// # Authorization
/// - Gas Service requires authorization for spender.
/// - `spender` needs to authorize `pay_gas` call to the gas service.
fn deploy_remote_canonical_token(
env: &Env,
token_address: Address,
Expand Down Expand Up @@ -233,7 +238,7 @@ pub trait InterchainTokenServiceInterface: AxelarExecutableInterface {
/// - Any error propagated from `pay_gas_and_call_contract`.
///
/// # Authorization
/// - The caller must authenticate.
/// - The `caller` must authenticate.
fn interchain_transfer(
env: &Env,
caller: Address,
Expand Down
1 change: 1 addition & 0 deletions contracts/interchain-token-service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ cfg_if::cfg_if! {
mod abi;
pub mod event;
mod storage_types;
mod token_metadata;
mod token_handler;
mod contract;
mod flow_limit;
Expand Down
5 changes: 3 additions & 2 deletions contracts/interchain-token-service/src/storage_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ use crate::types::TokenManagerType;
#[contracttype]
#[derive(Clone, Debug)]
pub enum DataKey {
TrustedChain(String),
Gateway,
GasService,
ItsHubAddress,
ChainName,
ItsHubAddress,
NativeTokenAddress,
InterchainTokenWasmHash,
TrustedChain(String),
TokenIdConfigKey(BytesN<32>),
FlowLimit(BytesN<32>),
FlowOut(FlowKey),
Expand Down
74 changes: 74 additions & 0 deletions contracts/interchain-token-service/src/token_metadata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use soroban_sdk::{token, Address, Env, String};
use soroban_token_sdk::metadata::TokenMetadata;
use stellar_axelar_std::ensure;

use crate::error::ContractError;

const NATIVE_TOKEN_NAME: &str = "Stellar";
const NATIVE_TOKEN_SYMBOL: &str = "XLM";
const MAX_DECIMALS: u32 = u8::MAX as u32;
const MAX_NAME_LENGTH: u32 = 32;
const MAX_SYMBOL_LENGTH: u32 = 32;

pub trait TokenMetadataExt: Sized {
fn new(name: String, symbol: String, decimals: u32) -> Result<Self, ContractError>;

fn validate(&self) -> Result<(), ContractError>;
}

impl TokenMetadataExt for TokenMetadata {
fn new(name: String, symbol: String, decimals: u32) -> Result<Self, ContractError> {
let token_metadata = Self {
name,
symbol,
decimal: decimals,
};

token_metadata.validate()?;

Ok(token_metadata)
}

fn validate(&self) -> Result<(), ContractError> {
ensure!(
self.decimal <= MAX_DECIMALS,
ContractError::InvalidTokenDecimals
);
ensure!(
!self.name.is_empty() && self.name.len() <= MAX_NAME_LENGTH,
ContractError::InvalidTokenName
);
ensure!(
!self.symbol.is_empty() && self.symbol.len() <= MAX_SYMBOL_LENGTH,
ContractError::InvalidTokenSymbol
);

Ok(())
}
}

pub fn token_metadata(
env: &Env,
token_address: &Address,
native_token_address: &Address,
) -> Result<TokenMetadata, ContractError> {
let token = token::Client::new(env, token_address);
let decimals = token.decimals();
let name = token.name();
let symbol = token.symbol();

// Stellar's native token sets the name and symbol to 'native'. Override it to make it more readable
let (name, symbol) = if token_address == native_token_address {
(
String::from_str(env, NATIVE_TOKEN_NAME),
String::from_str(env, NATIVE_TOKEN_SYMBOL),
)
// If the name is longer than 32 characters, use the symbol as the name to avoid a deployment error on the destination chain
} else if name.len() > MAX_NAME_LENGTH {
(symbol.clone(), symbol)
} else {
(name, symbol)
};

TokenMetadata::new(name, symbol, decimals)
}
65 changes: 49 additions & 16 deletions contracts/interchain-token-service/tests/deploy_interchain_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn deploy_interchain_token_succeeds() {
let sender = Address::generate(&env);
let minter: Option<Address> = None;
let salt = BytesN::<32>::from_array(&env, &[1; 32]);
let token_metadata = TokenMetadata::new(&env, "name", "symbol", 6);
let token_metadata = TokenMetadata::new(&env, "Test", "TEST", 6);
let initial_supply = 100;

client.mock_all_auths().deploy_interchain_token(
Expand All @@ -41,7 +41,7 @@ fn deploy_interchain_token_with_initial_supply_no_minter() {
let sender = Address::generate(&env);
let minter: Option<Address> = None;
let salt = BytesN::<32>::from_array(&env, &[1; 32]);
let token_metadata = TokenMetadata::new(&env, "name", "symbol", 6);
let token_metadata = TokenMetadata::new(&env, "Test", "TEST", 6);
let initial_supply = 100;

let token_id = client.mock_all_auths().deploy_interchain_token(
Expand All @@ -68,7 +68,7 @@ fn deploy_interchain_token_with_initial_supply_valid_minter() {
let sender = Address::generate(&env);
let minter = Address::generate(&env);
let salt = BytesN::<32>::from_array(&env, &[1; 32]);
let token_metadata = TokenMetadata::new(&env, "name", "symbol", 6);
let token_metadata = TokenMetadata::new(&env, "Test", "TEST", 6);
let initial_supply = 100;

let token_id = client.deploy_interchain_token(
Expand Down Expand Up @@ -96,7 +96,7 @@ fn deploy_interchain_token_check_token_id_and_token_manager_type() {
let sender = Address::generate(&env);
let minter = Address::generate(&env);
let salt = BytesN::<32>::from_array(&env, &[1; 32]);
let token_metadata = TokenMetadata::new(&env, "name", "symbol", 6);
let token_metadata = TokenMetadata::new(&env, "Test", "TEST", 6);
let initial_supply = 100;

let deploy_salt = client.interchain_token_deploy_salt(&sender, &salt);
Expand Down Expand Up @@ -125,7 +125,7 @@ fn deploy_interchain_token_zero_initial_supply_and_valid_minter() {
let sender = Address::generate(&env);
let minter = Address::generate(&env);
let salt = BytesN::<32>::from_array(&env, &[1; 32]);
let token_metadata = TokenMetadata::new(&env, "name", "symbol", 6);
let token_metadata = TokenMetadata::new(&env, "Test", "TEST", 6);
let initial_supply = 0;

let token_id = client.deploy_interchain_token(
Expand Down Expand Up @@ -154,7 +154,7 @@ fn deploy_interchain_token_falis_zero_initial_supply_and_invalid_minter() {
let sender = Address::generate(&env);
let minter: Option<Address> = Some(client.address.clone());
let salt = BytesN::<32>::from_array(&env, &[1; 32]);
let token_metadata = TokenMetadata::new(&env, "name", "symbol", 6);
let token_metadata = TokenMetadata::new(&env, "Test", "TEST", 6);
let initial_supply = 0;

assert_contract_err!(
Expand All @@ -177,7 +177,7 @@ fn deploy_interchain_token_zero_initial_supply_no_minter() {
let sender = Address::generate(&env);
let minter: Option<Address> = None;
let salt = BytesN::<32>::from_array(&env, &[1; 32]);
let token_metadata = TokenMetadata::new(&env, "name", "symbol", 6);
let token_metadata = TokenMetadata::new(&env, "Test", "TEST", 6);
let initial_supply = 0;

let token_id =
Expand All @@ -193,36 +193,69 @@ fn deploy_interchain_token_zero_initial_supply_no_minter() {
}

#[test]
#[should_panic(expected = "HostError: Error(Context, InvalidAction)")]
fn deploy_interchain_token_fails_with_invalid_decimals() {
fn deploy_interchain_token_fails_with_invalid_token_metadata() {
let (env, client, _, _, _) = setup_env();
env.mock_all_auths();

let sender = Address::generate(&env);
let minter: Option<Address> = None;
let salt = BytesN::<32>::from_array(&env, &[1; 32]);
let invalid_decimals = (u8::MAX) as u32 + 1;
let token_metadata = TokenMetadata::new(&env, "name", "symbol", invalid_decimals);
let initial_supply = 0;

client.deploy_interchain_token(&sender, &salt, &token_metadata, &initial_supply, &minter);
let cases = [
(
TokenMetadata::new(&env, "", "symbol", 6),
ContractError::InvalidTokenName,
),
(
TokenMetadata::new(&env, "A".repeat(33).as_str(), "symbol", 6),
ContractError::InvalidTokenName,
),
(
TokenMetadata::new(&env, "name", "", 6),
ContractError::InvalidTokenSymbol,
),
(
TokenMetadata::new(&env, "name", "A".repeat(33).as_str(), 6),
ContractError::InvalidTokenSymbol,
),
(
TokenMetadata::new(&env, "name", "symbol", (u8::MAX) as u32 + 1),
ContractError::InvalidTokenDecimals,
),
(
TokenMetadata::new(&env, "name", "symbol", u32::MAX),
ContractError::InvalidTokenDecimals,
),
];

for (token_metadata, expected_error) in cases {
assert_contract_err!(
client.mock_all_auths().try_deploy_interchain_token(
&sender,
&salt,
&token_metadata,
&initial_supply,
&minter
),
expected_error
);
}
}

#[test]
fn deploy_interchain_token_fails_with_invalid_auth() {
let (env, client, _, _, _) = setup_env();
env.mock_all_auths();

let sender = Address::generate(&env);
let user = Address::generate(&env);
let minter: Option<Address> = None;
let salt = BytesN::<32>::from_array(&env, &[1; 32]);
let token_metadata = TokenMetadata::new(&env, "name", "symbol", 6);
let token_metadata = TokenMetadata::new(&env, "Test", "TEST", 6);

let initial_supply = 100;

assert_auth_err!(
user,
client.deploy_interchain_token(&sender, &salt, &token_metadata, &initial_supply, &minter,)
client.deploy_interchain_token(&sender, &salt, &token_metadata, &initial_supply, &minter)
);
}
Loading

0 comments on commit 512ddf4

Please sign in to comment.