Quantum Portal Executable

Overview

The Quantum Portal Executable Contract is a component of the Quantum Portal General Message Passing (GMP) flow, allowing the execution of custom logic in response to messages from different blockchains. By simply inheriting from the Quantum Portal Executable your contract can process and respond to incoming cross-chain GMP data.

Integration

  1. Import QPExecutable from the Quantum Portal GMP SDK to enable cross-chain capabilities.

    import "@QP-network/QP-gmp-sdk-solidity/contracts/executable/QPExecutable.sol";
    
  2. Inherit Quantum Portal Executable Functions:

contract MyContract is QPExecutable {}
  1. Implement the virtual functions defined in Quantum Portal Executable on your own contracts. The functions you implement on your own contract will be automatically triggered by an Quantum Portal relayer on the destination chain once the multichain transaction arrives on the destination chain

GMP Message vs. GMP Message With Token

There are two relevant functions that can be overriden from QPExecutable. The function you want to override depends on whether your sending a GMP message or a GMP message WITH a Gateway Token. These two functions are _execute() and _executeWithToken()

/*** For GMP Message ***/
/**
	@param sourceChain The chain where the GMP message is sent from
	@param sourceAddress The address on where the GMP msg is sent from
	@param payload The GMP message being sent
**/
function _execute(string calldata sourceChain, string calldata sourceAddress, bytes calldata payload) internal override {
    // Implement your logic on the destination chain
    string memory myGmpMessage = abi.decode(payload, (string));
    
}

/*** For GMP Message + Token ***/
/**
	@param sourceChain The chain where the GMP message is sent from
	@param sourceAddress The address on where the GMP msg is sent from
	@param payload The GMP message being sent 
	@param tokenSymbol The token being sent
	@param amount The amount of the token being sent
**/
function _executeWithToken(string calldata sourceChain, string calldata sourceAddress, bytes calldata payload, string calldata tokenSymbol, uint256 amount) internal override {
	address memory receiver = abi.decode(payload, (address));
	address tokenAddress = gateway.tokenAddresses(tokenSymbol);
	IERC20(tokenAddress).transfer(receiver, amount);
}

Incoming Message Validation

The QPExecutable contract allows developers to override the _execute and the _executeWithToken() function on your own contract. However, the function that is actually triggered by the Quantum Portal relayers are external execute() and executeWithToken() functions. Since these contracts are external with no relevant modifiers they can in theory be triggered by anyone. This can be a security vulnerability as your own contract’s implementation is dependent on the data being passed into the execute() function (which triggers in the internal _execute() function you’re overriding).

To solve this problem, QPExecutable triggers the Quantum Portal Gateway’s validateContractCall() function. This function will validate that the incoming message was approved by the Quantum Portal validators and return true if it was. It will then mark the message as a valid to ensure that it is not called more than once. Only once the message is marked as valid will your _execute() function be triggered.

By simply inheriting QPExecutable and overriding the _execute() function defined their you can be confident that the message you’re receiving is an authentic message from the Quantum Portal network.

Upgradeable Contracts

If your contract is upgradeable then you may be unable to inherit from QPExecutable as it implements a constructor . To get around this issue you can simply call the external execute() function (or executeWithToken()). By simply making the execute() function available the relayer will still trigger this function on your contract and it will run the same way the internal _execute() function would if you were overriding from QPExecutable. The catch is that the validateContractCall() function will not be automatically implemented the way it would be if you were inheriting from QPExecutable. To get around this problem simply make sure you implement the validateContractCall() functionality yourself in your execute() function to ensure the authenticity of the incoming message. Once implemented your execute() function should look like this


  function execute(
    bytes32 commandId,
    string calldata sourceChain,
    string calldata sourceAddress,
    bytes calldata payload
  ) external {
    bytes32 payloadHash = keccak256(payload);

    if (
      !gateway.validateContractCall(
        commandId,
        sourceChain,
        sourceAddress,
        payloadHash
      )
    ) revert NotApprovedByGateway();
    
    //The rest of your implementation
 }
Edit this page