Integrate Custom Token

Custom tokens are independently deployed tokens, as opposed to InterchainTokens deployed via the Interchain Token Service (ITS). These tokens are integrated with ITS across different chains by deploying a Token Manager for each.

Once a custom token has a Token Manager deployed on a given chain, it becomes bridgeable between blockchains that also have a token connected to a Token Manager sharing the same interchainTokenId.

Install the Axelar Interchain Token Service (ITS) package using npm or any other node package manager:

Terminal window
npm i @axelar-network/interchain-token-service

Build your ERC-20 token and deploy it on multiple chains. You can use a tool like the Create3 Deployer to ensure your token has the same address across chains.

Example token contract:

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
contract MyInterchainToken is ERC20, ERC20Burnable {
constructor(address initialOwner)
ERC20("My Interchain Token", "ITS")
{
// Initialization code here
}
function mint(address to, uint256 amount) public onlyMinter {
_mint(to, amount);
}
function burn(address from, uint256 amount) public onlyMinter {
_burn(from, amount);
}
}

This token is a simple implementation of an ERC-20 token that includes the critical functions needed to integrate with ITS: the ability to mint() and burn() tokens. ITS calls these functions when bridging tokens between chains.

Alternatively, you can inherit from the InterchainTokenStandard so that your token has cross-chain functionality built in, such as the interchainTransfer() function.

After deploying your custom tokens on your preferred chains, the next step is to integrate your token with ITS by following these steps:

  1. Register token metadata with the ITS Contract
  2. Register custom token with the Interchain Token Factory
  3. Link custom token with the Interchain Token Factory
  4. Assign the minter role to your token’s Token Manager

Register your token metadata using the registerTokenMetadata function on the ITS contract. This function registers metadata for a token on the ITS Hub. This metadata is used for scaling linked tokens. For example, if you are integrating your custom token on chains A, B, and C, you should register token metadata on each chain separately.

function registerTokenMetadata(
address tokenAddress, // your token address
uint256 gasValue // gas value
) external payable {};

This function registers metadata for a token on the ITS Hub. This metadata is used for scaling linked tokens.

Note: Token metadata must be registered before linkToken can be called for the corresponding token. This function links a remote token on destinationChain to a local token corresponding to the tokenId computed from the provided salt.

After registering token metadata for each of your custom tokens, call the registerCustomToken function on the Interchain Token Factory.

function registerCustomToken(
bytes32 salt, // your unique salt value
address tokenAddress, // your custom token address
TokenManagerType tokenManagerType, // token manager type
address operator // minter address
) external payable returns (bytes32 tokenId) {};

This function registers an existing ERC-20 token (your custom token) under a tokenId computed from the provided salt. A token metadata registration message will also be sent to the ITS Hub. Then, the token can be linked to remote tokens on different chains by submitting the linkToken function from the same msg.sender using the same salt.

Note: This function is called from the Interchain Token Factory rather than directly from ITS because the Factory provides additional utility functions and standardized tokenId computation logic. It simplifies the deployment process by managing the salt derivation and tracking of token deployments, making it easier for developers to work with custom tokens while maintaining consistency across chains.

To link a custom token, use the linkToken function to link your custom tokens on your respective chains.

function linkToken(
bytes32 salt, // your unique salt value previously used
string calldata destinationChain, // destination chain
bytes calldata destinationTokenAddress, // destination custom token address
TokenManagerType tokenManagerType, // token manager type
bytes calldata linkParams, // operator address
uint256 gasValue // gas value
) external payable returns (bytes32 tokenId) {}

This function does the following:

  1. It computes a tokenId using the same salt you used during token registration
  2. Creates a cross-chain message that instructs the destination chain to deploy a Token Manager for your token
  3. Establishes the connection between your tokens across chains by associating them with the same tokenId
  4. Sets up the appropriate Token Manager type that defines how tokens will be bridged (lock/unlock, mint/burn, etc.)

When this function executes, it:

  • Takes gas payment for the cross-chain message (this is why it’s payable)
  • Routes the message through the ITS Hub to the destination chain
  • Triggers the deployment of a Token Manager on the destination chain that’s linked to your token

You can see a real example of this function being used in this transaction on Axelarscan, which demonstrates linking a token between BNB chain and Avalanche.

Note: A local token must be registered first using the registerCustomToken function. The entire linking process might take a few minutes to complete as the cross-chain message propagates through the Axelar network.

Transfer the minter / burn role to the Token Manager using the transferMintership function on your token. To retrieve your token manager address, use the tokenManagerAddress function on the ITS contract by specifying your tokenId.

yourToken.transferMintership(tokenManagerAddress);

The transferMintership() function transfers the minter role to the Token Manager. This is necessary because when your token is bridged to a destination chain, the msg.sender of the mint() call will be the Token Manager.

An Interchain Token is an ERC-20 connected to ITS upon deployment and comes built in with the interchainTransfer() function, which allows users to bridge their token between any blockchain on which it is deployed. Refer to the diagram below to see how the interchainTransfer() function works.

💡

This diagram is interactive—click on the function names!

Your browser does not support SVG

Use the interchainTransfer function to send tokens across chains.

function interchainTransfer(
bytes32 tokenId, // token ID
string calldata destinationChain, // destination chain name
bytes calldata destinationAddress, // receiver address on destination chain
uint256 amount, // amount to transfer
bytes calldata metadata, // metadata (optional)
uint256 gasValue // gas value sent for the transfer
) external payable whenNotPaused {};

The interchainTransfer() function sends a cross-chain transfer via the Interchain Token Service.

🚨

Security Note: The key used to deploy custom tokens is critical for security. If that key is compromised, the token can be compromised across multiple chains. - Interchain native tokens can only be deployed to additional chains via the same deployer key, so that key must be securely retained. - Tokens registered on ITS should be cautious about granting mint/burn permissions to other contracts. For example, sharing mint permission with the Polygon native bridge is not supported (the Polygon native bridge only looks for burns, which ITS uses—potentially allowing duplicate sends).

For further examples utilizing the Interchain Token Service, check out the axelar-examples repository on GitHub. There, you can find implementations such as:

  • its-custom-token — Demonstrates how to use ITS with a custom token implementation.
  • its-executable — Demonstrates how to deploy an interchain token and send a cross-chain transfer along with a message.
  • its-mint-burn-from — Demonstrates how to deploy an interchain token that uses burnFrom() instead of burn() when bridging tokens.

For a step-by-step guide on integrating a custom token, check out the Link Custom Tokens Deployed Across Multiple Chains into Interchain Tokens tutorial.

Edit on GitHub