Docs
IntegrationsStellar

Contract reference

Stellar ITS: functions, events, errors and the interchain token executable.

Addresses are on the Stellar overview. The full API is in the crate documentation, and the source in stellar-interchain-token-service. Call ITS from your contract with InterchainTokenServiceClient.

gas_token is an optional Token { address, amount }, paid to the gas service by the address that authorizes the call; see Gas. Every function with a destination_chain fails with UntrustedChain if ITS doesn't trust that chain.

Deploy and register

// Deploys an interchain token on Stellar, and mints `initial_supply` to `caller`.
// The token ID comes from `caller` and `salt`. `minter` is an optional extra minter;
// with none, `initial_supply` must be more than 0. `caller` must authorize.
fn deploy_interchain_token(
    env: Env,
    caller: Address,
    salt: BytesN<32>,
    token_metadata: TokenMetadata, // { decimal, name, symbol }
    initial_supply: i128,
    minter: Option<Address>,
) -> Result<BytesN<32>, ContractError>;

// Deploys the interchain token of `caller` and `salt` on another chain, with no minter.
// `caller` must authorize.
fn deploy_remote_interchain_token(
    env: Env,
    caller: Address,
    salt: BytesN<32>,
    destination_chain: String,
    gas_token: Option<Token>,
) -> Result<BytesN<32>, ContractError>;

// Registers an existing Stellar token as a canonical token, with a LockUnlock token manager.
// Anyone can call it.
fn register_canonical_token(env: Env, token_address: Address) -> Result<BytesN<32>, ContractError>;

// Deploys a canonical token on another chain, with no minter. `spender` pays the gas.
fn deploy_remote_canonical_token(
    env: Env,
    token_address: Address,
    destination_chain: String,
    spender: Address,
    gas_token: Option<Token>,
) -> Result<BytesN<32>, ContractError>;

// Sends a token's address and decimals to the ITS Hub, before linking it. `spender` pays the gas.
fn register_token_metadata(
    env: Env,
    token_address: Address,
    spender: Address,
    gas_token: Option<Token>,
) -> Result<(), ContractError>;

// Registers a custom token on Stellar, with a token manager of the given type
// (not NativeInterchainToken). The token ID comes from `deployer` and `salt`.
// `deployer` must authorize.
fn register_custom_token(
    env: Env,
    deployer: Address,
    salt: BytesN<32>,
    token_address: Address,
    token_manager_type: TokenManagerType,
) -> Result<BytesN<32>, ContractError>;

// Links a token on another chain to the custom token of `deployer` and `salt`.
// `token_manager_type` and `link_params` are for the destination chain.
// `deployer` must authorize, and pays the gas.
fn link_token(
    env: Env,
    deployer: Address,
    salt: BytesN<32>,
    destination_chain: String,
    destination_token_address: Bytes,
    token_manager_type: TokenManagerType,
    link_params: Option<Bytes>,
    gas_token: Option<Token>,
) -> Result<BytesN<32>, ContractError>;

TokenMetadata is from soroban_token_sdk::metadata. The name and symbol must be 1 to 32 ASCII characters, and the decimals at most 255. TokenManagerType is in stellar_interchain_token_service::types; see Token managers.

Transfers

// Burns or locks `amount` of `caller`'s tokens and sends them to `destination_address`.
// With `data`, ITS on the destination chain then calls the recipient contract with it.
// `caller` must authorize, and pays the gas.
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>;

amount must be more than 0, and data, if set, not empty. For the format of destination_address, see Addresses in messages.

Queries

fn interchain_token_id(env: Env, deployer: Address, salt: BytesN<32>) -> BytesN<32>;
fn canonical_interchain_token_id(env: Env, token_address: Address) -> BytesN<32>;
fn linked_token_id(env: Env, deployer: Address, salt: BytesN<32>) -> BytesN<32>;

fn registered_token_address(env: Env, token_id: BytesN<32>) -> Address;
fn deployed_token_manager(env: Env, token_id: BytesN<32>) -> Address;
fn token_manager_type(env: Env, token_id: BytesN<32>) -> TokenManagerType;

fn is_trusted_chain(env: Env, chain: String) -> bool;
fn chain_name(env: Env) -> String;
fn native_token_address(env: Env) -> Address; // XLM
fn gas_service(env: Env) -> Address;

registered_token_address, deployed_token_manager and token_manager_type fail for a token ID that isn't registered on Stellar.

Flow limits

ITS keeps each token's flow limit: None for no limit, and Some(0) to block every transfer.

fn flow_limit(env: Env, token_id: BytesN<32>) -> Option<i128>;
fn flow_out_amount(env: Env, token_id: BytesN<32>) -> i128; // sent out in the current window
fn flow_in_amount(env: Env, token_id: BytesN<32>) -> i128; // received in the current window
fn is_flow_limiter(env: Env, token_id: BytesN<32>, flow_limiter: Address) -> bool;

// `caller` must be ITS's operator or an approved flow limiter of the token, and authorize.
fn set_flow_limit(
    env: Env,
    caller: Address,
    token_id: BytesN<32>,
    flow_limit: Option<i128>,
) -> Result<(), ContractError>;

ITS's operator approves flow limiters with add_flow_limiter(token_id, flow_limiter), remove_flow_limiter(token_id, flow_limiter) and transfer_flow_limiter(token_id, from, to).

Owner functions

transfer_token_admin(token_id, new_admin), callable only by ITS's owner, makes new_admin the admin of a MintBurn token in place of its token manager. See Link custom tokens.

Events

EventFields
interchain_token_deployedtoken_id, token_address, name, symbol, decimals, minter
token_manager_deployedtoken_id, token_address, token_manager, token_manager_type
token_deployment_startedtoken_id, token_address, destination_chain, name, symbol, decimals, minter
token_metadata_registeredtoken_address, decimals
link_token_startedtoken_id, destination_chain, source_token_address, destination_token_address, token_manager_type, params
link_token_receivedsource_chain, token_id, source_token_address, destination_token_address, token_manager_type, params
interchain_transfer_senttoken_id, source_address, destination_chain, destination_address, amount; data_hash in the data
interchain_transfer_receivedsource_chain, token_id, source_address, destination_address, amount; data_hash in the data
flow_limit_settoken_id, flow_limit
flow_limiter_addedtoken_id, flow_limiter
flow_limiter_removedtoken_id, flow_limiter

Errors

A failed call returns Error(Contract, #n). The ones you're most likely to see:

CodeErrorCause
7UntrustedChainThe destination chain isn't trusted, or its name doesn't match exactly
10InvalidAmountThe amount isn't more than 0
17InvalidTokenIdNo token is registered under the token ID
18TokenAlreadyRegisteredThe token ID is already registered, e.g. the salt was used before
20FlowLimitExceededThe transfer would take the net flow over the flow limit
23InvalidDestinationChainA deployment or link to Stellar itself
25InvalidTokenNameThe name is empty, longer than 32 characters or not ASCII
26InvalidTokenSymbolThe symbol is empty, longer than 32 characters or not ASCII
28ContractPausedITS is paused
32InvalidTokenConfiginitial_supply is 0 and there's no minter
34FlowAmountExceededLimitThe transfer alone is larger than the flow limit
35InvalidTokenManagerTypeNativeInterchainToken for a custom token or link
39NotApprovedFlowLimiterset_flow_limit from someone who isn't allowed to set it

The full list is in error.rs.

Interchain token executable

stellar_interchain_token_service::executable. To receive tokens with data, implement CustomInterchainTokenExecutable and derive InterchainTokenExecutable:

pub trait CustomInterchainTokenExecutable {
    type Error: Into<stellar_axelar_std::Error>;

    // Returns the ITS address
    fn __interchain_token_service(env: &Env) -> Address;

    // Your logic, called after ITS has given the tokens to your contract
    fn __authorized_execute_with_token(
        env: &Env,
        source_chain: String,
        message_id: String,
        source_address: Bytes,
        payload: Bytes,
        token_id: BytesN<32>,
        token_address: Address,
        amount: i128,
    ) -> Result<(), Self::Error>;
}

The derive generates the contract functions interchain_token_service() and execute_with_interchain_token(...), with the same arguments. execute_with_interchain_token requires ITS's authorization, then calls __authorized_execute_with_token. Check the sender in it; see Receive tokens.

On this page