Message Proxy

The MessageProxy contract sends messages to any contract. The IMA system uses MessageProxy to send Eth, ERC20, ERC721, and ERC1155 transfer messages to DepositBox and TokenManager contracts, and is expandable to support other messages and contracts.

Architecture

  • MessageProxy contracts are deployed on Mainnet and each SKALE Chain.

  • Contracts are registered to MessageProxy, allowing them to interact with the IMA Agent.

  • Messages sent via postOutgoingMessage are processed by the IMA Agent, a containerized nodejs script operating on each SKALE Node and listening for events on the SKALE Chain and Mainnet.

  • When the Agent receives an Outgoing Message on either blockchain, it sends the message onward via postIncomingMessage to another MessageProxy contract on the destination chain to which it’s sent.

  • You can view how postOutgoingMessage is used by DepositBox and TokenManager when a transfer is initiated to another chain (Mainnet or SKALE Chain).

Messages are limited to 1M gas by default. To change this limit, use the respective MessageProxy…​ contract. Below is shown for MessageProxyForSchain:

MessageProxyForSchain.grantRole(keccak256("CONSTANT_SETTER_ROLE"), YOUR_ADDRESS)
MessageProxyForSchain.setNewGasLimit(3M)

Implementation

First, your contracts must be registered to MessageProxy on Mainnet and on your SKALE Chain. This enables MessageProxy to interact with your specific contracts.

To send messages via MessageProxy, your sending contract(s) on the SKALE Chain or Mainnet need to call postOutgoingMessage on the MessageProxy to send messages through the Agent. You need to pass in the parameters for destinationChainID, destination contract address, and the data to be sent. If you send messages from Schain to Mainnet, you must call MessageProxyOnSchain’s postOutgoingMessage and include destinationChainID = "Mainnet" and the receiving contract address on Mainnet.

To receive messages via MessageProxy, your receiving contract(s) need to implement postMessage logic (see PostMessage section below).

When the IMA Agent receives a message from postOutgoingMessage, the agent calls postIncomingMessage on the destination chain’s MessageProxy contract, and this postIncomingMessage executes the postMessage function in your contract.

To register contracts to your SKALE Chain with MessageProxy on Mainnet:
msg.sender must be the SKALE Chain owner.
  • Add extra mainnet contract by calling registerExtraContract([SKALE_CHAIN_NAME], [CONTRACT_ADDRESS_ON_MAINNET])

  • Remove extra mainnet contract by calling removeExtraContract([SKALE_CHAIN_NAME], [CONTRACT_ADDRESS_ON_MAINNET]).

To register contracts to Mainnet with MessageProxy on your SKALE Chain:
msg.sender must be granted EXTRA_CONTRACT_REGISTRAR_ROLE.
  • Add extra SKALE Chain contract by calling registerExtraContract("Mainnet", [CONTRACT_ADDRESS_ON_SCHAIN]).

  • Remove extra SKALE Chain contract by calling removeExtraContract("Mainnet", [CONTRACT_ADDRESS_ON_SCHAIN]).

To send messages from SKALE Chain to Mainnet
  • Your SKALE Chain contract(s) must call postOutgoingMessage("Mainnet", [RECEIVING_CONTRACT_ADDRESS_ON_MAINNET], [DATA])

  • The receiving contract address on mainnet must implement a postMessage function.

To send messages from Mainnet to SKALE Chain:
  • Your Mainnet contract(s) must call postOutgoingMessage([SKALE_CHAIN_NAME], [RECEIVING_CONTRACT_ADDRESS_ON_SCHAIN], [DATA])

  • The receiving contract address on SKALE Chain must implement a postMessage function.

PostMessage

See below for instructions to implement postMessage in receiving contracts:

1. Add the interface

interface Proxy {
    function postOutgoingMessage(
        bytes32 targetChainHash,
        address targetContract,
        bytes calldata data
    ) external;
}

2. Add postMessage()

Add postMessage to allow processing of incoming messages from MessageProxy.

function postMessage(
    bytes32 schainHash,
    address sender,
    bytes calldata data
    )
    external
    returns (address)
{
    [add in your processing logic]
}

3. Add MessageProxyOnMainnet/MessageProxyOnSchain address

Methods

MessageProxyForMainnet

registerExtraContract

Adds extra contract to skale-chain - means that MessageProxyForMainnet will not revert messages from this contract to given schainName - otherwise revert

Calling from SchainOwner or EXTRA_CONTRACT_REGISTRAR_ROLE

removeExtraContract

removes extra contract to skale-chain - means that MessageProxyForMainnet will revert messages from this contract to given schainName

Calling from SchainOwner or EXTRA_CONTRACT_REGISTRAR_ROLE

registerExtraContractForAll

adds extra contract to all skale-chains(already connected or would be connected) - means that MessageProxyForMainnet will not revert messages from this contract to all schains

Calling only from EXTRA_CONTRACT_REGISTRAR_ROLE

removeExtraContractForAll

Removes extra contract from all skale-chains(already connected or would be connected) - means that MessageProxyForMainnet will revert messages from this contract to all schains

Calling only from EXTRA_CONTRACT_REGISTRAR_ROLE

MessageProxyForSchain

registerExtraContract

Adds extra contract to skale-chain or “Mainnet” - means that MessageProxyForSchain will not revert messages from this contract to given schainName or “Mainnet” - otherwise revert

Calling from SchainOwner or EXTRA_CONTRACT_REGISTRAR_ROLE

removeExtraContract

Removes extra contract to skale-chain or “Mainnet” - means that MessageProxyForSchain will revert messages from this contract to given schainName or “Mainnet”

Calling from SchainOwner or EXTRA_CONTRACT_REGISTRAR_ROLE

registerExtraContractForAll

Adds extra contract to all skale-chains and “Mainnet”(already connected or would be connected) - means that MessageProxyForSchain will not revert messages from this contract to all schains and “Mainnet”

Calling only from EXTRA_CONTRACT_REGISTRAR_ROLE

removeExtraContractForAll

Removes extra contract from all skale-chains and “Mainnet”(already connected or would be connected) - means that MessageProxyForSchain will revert messages from this contract to all schains and “Mainnet”

Calling only from EXTRA_CONTRACT_REGISTRAR_ROLE