General Message Passing

Quantum Portal’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 Quantum Portal chain itself are not yet supported. Quantum Portal only supports GMP call without token from Quantum Portal to chain X. Transactions sent to the Quantum Portal 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 Quantum Portal 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 Quantum Portal’s supported EVM chains. See chain names for a list of EVM chains that have an Quantum Portal Gateway deployed. The list is updated as new chains are added.

Flow architecture (in steps)

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 Quantum Portal Gateway contract to initiate a call. Once the call is initiated, the user can see its status at https://QPscan.io/gmp/[txHash] or programmatically track it via the QPJS SDK.
  2. You prepay the gas for the decentralized Quantum Portal consensus and the necessary transactions to approve and execute on the destination chain.
  3. The call enters the Quantum Portal Gateway from the source chain.

At the Quantum Portal network

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

At the destination chain

  1. The call is approved (Quantum Portal 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 Quantum Portal Gateway on the destination chain.
  2. The executor service relays and executes the approved call to the application’s Quantum Portal Executable interface.

Suppose the paid gas (step 2) is insufficient to approve or execute on the destination chain; Quantum Portal 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 QPExecutable.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 QPGateway.callContract() with the destination chain/address and payload, which emits the ContractCall event.

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

On Quantum Portal Network

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

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

  3. A relayer requests the Quantum Portal 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 Quantum Portal 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 IQPExecutable.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 Quantum Portal validators by calling validateContractCall() from the QPExecutable where it’s defined on its Quantum Portal 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 this page