Send Tokens Cross-Chain (Deprecated)

💡

Note: Transfering assets via sendToken() is deprecated. For gateway tokens it is recommended to use callContractWithToken() and for other tokens it is recommended to use the Interchain Token Service.

To send a token from an EVM source chain:

Locate the source chain’s Gateway contract address on either the mainnet or the testnet.

EVM chains use Axelar Gateway smart contracts to send tokens. These are application-layer smart contracts that send and receive payloads as well as monitor transaction state.

All Gateway contracts implement the IAxelarGateway interface, which has a public method called sendToken() that transfers tokens between chains:

function sendToken(
string memory destinationChain,
string memory destinationAddress,
string memory symbol,
uint256 amount
) external;

Transferring tokens through a Gateway is similar to doing a typical ERC-20 token transfer. You’ll need to call the source chain’s approve() method (inherited from the ERC-20 interface to allow the Gateway to transfer a specific token in a specific amount.

function approve(address spender, uint256 amount) external returns (bool);

spender is the source chain’s Gateway contract address on either the mainnet or the testnet.

Call sendToken() on the source chain’s Gateway contract to transfer the tokens. For example:

sendToken(
"avalanche", // destination chain name
"0xF16DfB26e1FEc993E085092563ECFAEaDa7eD7fD", // some destination wallet address (should be your own)
"axlUSDC", // asset symbol, can be differ by chain, see above
100000000 // amount (in atomic units)
)

Once you call sendToken(), watch for the tokens to appear at the address on the destination chain.

For Cosmos-based source chains, sendToken() is a simple IBC transfer of any asset supported on the Axelar network. The message is sent to the address axelar1dv4u5k73pzqrxlzujxg3qp8kvc3pje7jtdvu72npnt5zhq05ejcsn5qme5, which is the designated address on the Axelar network for receiving GMP messages, and includes a memo field with the following payload:

{
destination_chain,
destination_address,
payload: null,
type: 3, // corresponds to the `sendToken` command on Axelar
}

The AxelarJS SDK allows any frontend application to call sendToken() with one line of JS code.

import {
AxelarAssetTransfer,
CHAINS,
Environment,
SendTokenParams,
} from "@axelar-network/axelarjs-sdk";
import { ethers, Wallet } from "ethers";
const api = new AxelarAssetTransfer({ environment: Environment.TESTNET });
const getSigner = () => {
const privateKey = PRIVATE_KEY;
return new Wallet(privateKey);
};
async function test() {
const provider = new ethers.providers.JsonRpcProvider(
"https://api.avax-test.network/ext/bc/C/rpc",
);
const signer = getSigner().connect(provider);
const requestOptions: SendTokenParams = {
fromChain: CHAINS.TESTNET.AVALANCHE,
toChain: CHAINS.TESTNET.OSMOSIS,
destinationAddress: "osmo1x3z2vepjd7fhe30epncxjrk0lehq7xdqe8ltsn",
asset: { symbol: "aUSDC" },
amountInAtomicUnits: "5000000",
options: {
evmOptions: {
signer,
provider,
txOptions: null as any,
approveSendForMe: true,
},
},
};
return api.sendToken(requestOptions);
}
import {
AxelarAssetTransfer,
CHAINS,
Environment,
SendTokenParams,
} from "@axelar-network/axelarjs-sdk";
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
const api = new AxelarAssetTransfer({ environment: Environment.TESTNET });
const getSigner = async () => {
const mnemonic = MNEMONIC;
return DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { prefix: "osmo" });
};
async function test() {
const offlineSigner = await getSigner();
const requestOptions: SendTokenParams = {
fromChain: CHAINS.TESTNET.OSMOSIS,
toChain: CHAINS.TESTNET.AVALANCHE,
destinationAddress: "0xB8Cd93C83A974649D76B1c19f311f639e62272BC",
asset: {
denom:
"ibc/6F34E1BD664C36CE49ACC28E60D62559A5F96C4F9A6CCE4FC5A67B2852E24CFE",
}, //aUSDC
amountInAtomicUnits: "1000000",
options: {
cosmosOptions: {
cosmosDirectSigner: offlineSigner,
rpcUrl: "https://rpc.osmotest5.osmosis.zone",
fee: {
gas: "250000",
amount: [{ denom: "uosmo", amount: "30000" }],
},
},
},
};
return api.sendToken(requestOptions);
}

Edit on GitHub