Stellar Interchain Token Service (ITS)

The Interchain Token Service (ITS) is a protocol that allows tokens to move freely between different blockchains. Think of it as a universal bridge for tokens - it provides a standardized way to:

  1. Deploy a token onto multiple blockchains that are interlinked.
  2. Connect existing tokens from one blockchain to other blockchains.
  3. Transfer tokens securely between blockchains.

For Stellar developers, ITS opens up new possibilities to interact with tokens from Ethereum, Polygon, Avalanche, and many other blockchains without understanding the intricacies of each chain’s token standards.

Unlike on EVM chains (like Ethereum), where tokens follow the ERC-20 standard, Stellar assets work a bit differently.

Stellar has its classic assets (issued with G... address) as well as contract tokens. The classic assets are native assets that have been part of the Stellar network since its inception, including tokens like XLM, USDC, and EURC, they are issued by Stellar Account and have a built-in asset contract. Contract tokens were Introduced with Soroban, CAP-41, they allow for custom logic in token implementation through smart contracts. These are similar to ERC-20 tokens on other chains. ITS integration adapts to Stellar’s unique characteristics:

  1. Hub Mode Operation: Stellar ITS works exclusively in “Hub mode” - all cross-chain messages go through the ITS Hub on the Axelar network rather than directly between chains.

  2. Token Representation: When an external token (like an Ethereum ERC-20) comes to Stellar, it’s represented by a Stellar token that’s controlled by a special contract called the TokenManager.

  3. Trust System: Instead of trusting specific addresses (as in EVM implementations), Stellar ITS uses a system of trusted chains.

With the integration of Stellar into Axelar, Stellar smart contracts can now leverage ITS to interact with tokens from other blockchains connected to Axelar.

Before diving into implementation, let’s understand the key components:

  1. InterchainTokenService: The main contract that coordinates token-related operations. It’s the primary interface for cross-chain token functionality.

  2. TokenManager: A contract that handles tokens’ minting, burning, and locking on a specific blockchain. Each token has its own TokenManager.

  3. InterchainToken: The token contract implementing Stellar’s token interface.

  4. Gateway: A contract that facilitates the cross-chain message passing between Stellar and other blockchains.

  5. GasService: A contract that handles payments for cross-chain transactions. Without this, messages couldn’t be relayed between chains.

ITS enables several robust use cases on Stellar:

fn deploy_interchain_token(
env: &Env,
caller: Address,
salt: BytesN<32>,
token_metadata: TokenMetadata,
initial_supply: i128,
minter: Option<Address>,
) -> Result<BytesN<32>, ContractError> {
// Returns a token_id that uniquely identifies your token across all chains
}
fn deploy_remote_token(
env: &Env,
caller: Address,
salt: BytesN<32>,
destination_chain: String,
gas_token: Option<Token>,
) -> Result<BytesN<32>, ContractError> {
// Deploys your token to another blockchain like Ethereum, Avalanche, etc.
}

These functions let you link existing tokens to the ITS network, making them available across chains.

// Register an existing Stellar token
fn register_canonical_token(
env: &Env,
token_address: Address,
) -> Result<BytesN<32>, ContractError> {
// Registers an existing token with the ITS
}
// Deploy that token to other chains (Ethereum, Avalanche, etc.)
fn deploy_remote_canonical_token(
env: &Env,
token_address: Address,
destination_chain: String,
spender: Address,
gas_token: Option<Token>,
) -> Result<BytesN<32>, ContractError> {
// Makes your existing token available on other blockchains
}

Send tokens between Stellar and any supported blockchain:

fn interchain_transfer(
env: &Env,
caller: Address,
token_id: BytesN<32>,
destination_chain: String,
destination_address: Bytes,
amount: i128,
data: Option<Bytes>,
gas_token: Option<Token>,
) -> Result<(), ContractError> {
// Transfers tokens from Stellar to another blockchain
}

Before sending tokens cross-chain, you can check if the destination chain is valid or trusted:

fn is_trusted_chain(env: &Env, chain: String) -> bool {
storage::is_trusted_chain(env, chain)
}

To receive tokens from other blockchains, the contract must implement message handling:

fn execute(
env: &Env,
source_chain: String,
message_id: String,
source_address: String,
payload: Bytes,
) -> Result<(), ContractError> {
// This function:
// 1. Validates that the message is coming from the ITS Hub
// 2. Decodes the message to determine its type
// 3. Processes it appropriately - either as a token transfer or a token deployment
}

The ITS implementation includes a flow-limiting system to control how many tokens can move in a given period:

#[only_operator]
fn set_flow_limit(
env: &Env,
token_id: BytesN<32>,
flow_limit: Option<i128>,
) -> Result<(), ContractError> {}

This function allows the operator to limit how many tokens can flow in or out over time.

Flow limits are configured per token and can only be set by authorized operators:

// Set a flow limit for a token
client.set_flow_limit(&token_id, &Some(1000_000));
// Remove flow limit (disable flow limiting)
client.set_flow_limit(&token_id, &None);
// Freeze token transfers (set limit to 0)
client.set_flow_limit(&token_id, &Some(0));
  • Only Operators: Flow limits can only be set by addresses with operator privileges
  • Per-Token Configuration: Each token can have its own independent flow limit
  • Optional Feature: Tokens without configured flow limits have no transfer restrictions

The ITS contract provides several functions to query flow limit status:

// Get the configured flow limit for a token
fn flow_limit(token_id: BytesN<32>) -> Option<i128>
// Get current epoch's outflow amount
fn flow_out_amount(token_id: BytesN<32>) -> i128
// Get current epoch's inflow amount
fn flow_in_amount(token_id: BytesN<32>) -> i128

The system returns specific errors for different flow limit violations:

  • InvalidFlowLimit: Attempted to set a negative flow limit
  • FlowAmountExceededLimit: Single transfer exceeds the flow limit
  • FlowAmountOverflow: Cumulative flow would cause integer overflow
  • FlowLimitExceeded: Net flow would exceed the configured limit

Flow limit changes emit events for monitoring and auditing:

FlowLimitSetEvent {
token_id: BytesN<32>,
flow_limit: Option<i128>,
}

Learn More: Explore our tutorial on building a rust project from scratch with interchain token service implementation to deploy and transfer tokens from Steller to EVM. This tutorial will guide you through distributing tokens across multiple chains.

Edit on GitHub