Integrate Custom Token

Custom tokens are independently deployed tokens, as opposed to those 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.

Register your token metadata using the registerTokenMetadata function on the ITS contract. 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.

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.

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, // minter address
uint256 gasValue // gas value
) external payable returns (bytes32 tokenId) {}

This function links a remote token on destinationChain to a local token corresponding to the tokenId computed from the provided salt.

Note: A local token must be registered first using the registerCustomToken function.

Transfer the minter 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