General Message Passing

Axelar’s General Message Passing (GMP) enables a developer building on one chain to call any function on any other connected chain. (We use the word “function” to encompass both smart contracts at the application layer and functions built at the protocol layer, as in Cosmos, for example.) That means complete composability across Web3.

With GMP, you can:

  • Call a contract on chain B from chain A.
  • Call a contract on chain B from chain A and attach some tokens.

🚨

NOTE: The security of your contracts is limited to the security of the chains they integrate with. Since blockchains can have different security practices, we recommend doing due diligence on all chains your contract will be deployed to.

🚨

NOTE: GMP Transactions using callContractWithToken sent to the Axelar chain itself are not yet supported. Axelar only supports GMP call without token from Axelar to chain X. Transactions sent to the Axelar chain as the destination chain will be stuck until support is rolled out.

Prerequisites

  • For GMP to work, chains A and B must be EVM or Cosmos with a deployed Axelar Gateway contract. We’re adding new chains and chain technology stacks all of the time. This document primarily focuses on EVM chains and Solidity code, but you can learn about interacting with Cosmos GMP.
  • The application’s executable contract must be deployed on the destination contract.
  • The application must be on one of Axelar’s supported EVM chains. See chain names for a list of EVM chains that have an Axelar Gateway deployed. The list is updated as new chains are added.

Flow architecture (in steps)

Your browser does not support SVG

Gateway Interface

In your smart contract, you’ll be interacting with the callContract or callContractWithToken methods of the gateway contract.

function callContract(
string calldata destinationChain,
string calldata destinationContractAddress,
bytes calldata payload
) external {
emit ContractCall(msg.sender, destinationChain, destinationContractAddress, keccak256(payload), payload);
}
function callContractWithToken(
string calldata destinationChain,
string calldata destinationContractAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount
) external {
_burnTokenFrom(msg.sender, symbol, amount);
emit ContractCallWithToken(msg.sender, destinationChain, destinationContractAddress, keccak256(payload), payload, symbol, amount);
}
function _execute(string calldata sourceChain, string calldata sourceAddress, bytes calldata payload) internal virtual {}

Steps

At the source chain

  1. You call a callContract (or callContractWithToken) function on the Axelar Gateway contract to initiate a call. Once the call is initiated, the user can see its status at https://axelarscan.io/gmp/[txHash] or programmatically track it via the AxelarJS SDK.
  2. You prepay the gas for the decentralized Axelar consensus and the necessary transactions to approve and execute on the destination chain.
  3. The call enters the Axelar Gateway from the source chain.

At the Axelar network

  1. The Axelar network confirms the call and utilizes funds from the source chain’s native token reserves to cover the gas costs on both the Axelar blockchain and the destination chain.

At the destination chain

  1. The call is approved (Axelar validators come to a consensus by voting, and their votes and signatures are then available to pass to the destination chain), and the approval is relayed to the Axelar Gateway on the destination chain.
  2. The executor service relays and executes the approved call to the application’s Axelar Executable interface.

Suppose the paid gas (step 2) is insufficient to approve or execute on the destination chain; Axelar offers monitoring and recovery steps to help deal with such scenarios.

Real-World Breakdown of Cross-Chain Contract Calls

Setup

  1. The destination application contract implements the AxelarExecutable.sol to receive the cross-chain message.

  2. The destination application contract stores the address of the local Gateway contract.

On Source Chain

  1. A smart contract on the source chain calls AxelarGateway.callContract() with the destination chain/address and payload, which emits the ContractCall event.

  2. The smart contract can deposit tokens to the AxelarGasService contract in the same transaction to pay the Axelar relayers for submitting the intermediate transactions required for cross-chain execution.

On Axelar Network

  1. A relayer monitors the ContractCall event and submits a transaction to the Axelar network to request validation. The relayer also stores the payload in a database, keyed by hash(payload) for later retrieval.

  2. Axelar validators then vote on-chain to validate the ContractCall event content.

  3. A relayer requests the Axelar network to prepare a command batch, including the pending payload approval (potentially batched with other messages), and requests validator signatures.

  4. A signed batch of approved payloads is prepared on Axelar that anyone can view.

On Destination Chain

  1. A relayer submits the signed batch to the destination gateway contract, which records the approval of the payload hash and emits a ContractCallApproved event.

  2. A trustless relayer service (can be anyone) listens for this event and calls IAxelarExecutable.execute() on the destination contract with the payload and other data as params.

  3. The execute method on the destination contract verifies the call was indeed approved by Axelar validators by calling validateContractCall() from the AxelarExecutable where it’s defined on its Axelar gateway contract.

  4. The gateway records that the destination application contract validated the approval and did not allow validateContractCall to be called again (to prevent replay of execute).

  5. The destination application contract uses the payload to _execute its logic.

Edit on GitHub