# Messages with tokens (https://docs.axelar.dev/gmp/integrations/evm/send-tokens-with-messages)



<Callout emoji="⚠️" title="Consensus chains only">
  `callContractWithToken` sends gateway tokens, such as axlUSDC, and exists only
  on the gateway of [consensus chains](https://docs.axelar.dev/llms.mdx/gmp/integrations/evm/intro/content.md#consensus-and-amplifier-chains).
  The gateway of Amplifier chains doesn't support it. To send tokens with a
  message to or from any chain, use the [Interchain Token
  Service](https://docs.axelar.dev/llms.mdx/its/integrations/evm/transfers-with-data/content.md).
</Callout>

`callContractWithToken` sends a message and an amount of a gateway token in one call. On the destination chain, the gateway sends the tokens to your contract before calling it. Gateway tokens are listed under [Assets](https://docs.axelar.dev/llms.mdx/infrastructure/network/chains-and-contracts/content.md#assets).

## Example [#example]

This contract takes tokens from the caller and sends them to its copy on another chain, which splits them between a list of recipients:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { AxelarExecutableWithToken } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutableWithToken.sol';
import { IAxelarGasService } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGasService.sol';
import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol';
import { SafeTokenTransfer, SafeTokenTransferFrom } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeTransfer.sol';

contract Distributor is AxelarExecutableWithToken {
    using SafeTokenTransfer for IERC20;
    using SafeTokenTransferFrom for IERC20;

    IAxelarGasService public immutable gasService;

    constructor(address gateway_, address gasService_) AxelarExecutableWithToken(gateway_) {
        gasService = IAxelarGasService(gasService_);
    }

    function sendToMany(
        string calldata destinationChain,
        string calldata destinationAddress,
        address[] calldata recipients,
        string calldata symbol,
        uint256 amount
    ) external payable {
        IERC20 token = IERC20(gatewayWithToken().tokenAddresses(symbol));

        // Take the tokens from the caller, who approved this contract first
        token.safeTransferFrom(msg.sender, address(this), amount);
        // Let the gateway take them from this contract
        token.approve(address(gateway()), amount);

        bytes memory payload = abi.encode(recipients);

        gasService.payNativeGasForContractCallWithToken{ value: msg.value }(
            address(this),
            destinationChain,
            destinationAddress,
            payload,
            symbol,
            amount,
            msg.sender // refund address
        );

        gatewayWithToken().callContractWithToken(destinationChain, destinationAddress, payload, symbol, amount);
    }

    function _execute(bytes32, string calldata, string calldata, bytes calldata) internal pure override {
        revert('Tokens required');
    }

    function _executeWithToken(
        bytes32 /* commandId */,
        string calldata /* sourceChain */,
        string calldata /* sourceAddress */,
        bytes calldata payload,
        string calldata tokenSymbol,
        uint256 amount
    ) internal override {
        // The gateway has already sent `amount` of the token to this contract
        address[] memory recipients = abi.decode(payload, (address[]));
        IERC20 token = IERC20(gatewayWithToken().tokenAddresses(tokenSymbol));

        uint256 share = amount / recipients.length;
        for (uint256 i = 0; i < recipients.length; i++) {
            token.safeTransfer(recipients[i], share);
        }
    }
}
```

## Send [#send]

Before calling the gateway, your contract must hold the tokens and approve the gateway to take them: the gateway burns or locks them from `msg.sender`. Then:

1. Pay gas with `payNativeGasForContractCallWithToken`, with the same values as the call. See [Estimate and pay](https://docs.axelar.dev/llms.mdx/gmp/gas/estimate-and-pay/content.md).
2. Call `callContractWithToken(destinationChain, destinationAddress, payload, symbol, amount)`.

`symbol` is the token's symbol on the source chain, and `tokenAddresses(symbol)` returns its address there. The call reverts if the symbol isn't a gateway token on that chain, if `amount` is 0, or if the gateway isn't approved for the amount.

## Receive [#receive]

Inherit `AxelarExecutableWithToken` and implement both `_executeWithToken` and `_execute`, which it also requires. A relayer calls `executeWithToken`, which validates the message and the token amount with the gateway. The gateway mints or releases the tokens to your contract, then your `_executeWithToken` runs with `tokenSymbol` (the symbol on this chain) and `amount`.

The same rules apply as for [plain messages](https://docs.axelar.dev/llms.mdx/gmp/integrations/evm/gmp-messages/content.md#receive-a-message): check the sender if your logic depends on it, and remember that a revert leaves the message approved for a retry. In the example, anyone may send tokens to be split, so it doesn't check the sender.

Each gateway token can have a limit on how much the gateway mints on a chain in each 6-hour window. If a message would go over it, execution reverts, and the message can be [executed again](https://docs.axelar.dev/llms.mdx/gmp/track-and-recover/recover-transactions/content.md#execute) in a later window.


---

All pages of these docs, as Markdown: https://docs.axelar.dev/llms.txt