ORMP

Oracle and Relayer based Message Protocol.

Deployments

See https://github.com/darwinia-network/contracts-deploy

Usage

To install with Foundry:

forge install msgport/ORMP

To install with Hardhat or Truffle:

npm install @darwinia/ormp

Install

To install dependencies and compile contracts:

git clone --recurse-submodules https://github.com/darwinia-network/ORMP.git && cd ORMP
make tools
make

Contents

Oracle

Git Source

Inherits: Verifier

State Variables

PROTOCOL

address public immutable PROTOCOL;

owner

address public owner;

feeOf

mapping(uint256 => uint256) public feeOf;

approvedOf

mapping(address => bool) public approvedOf;

Functions

onlyOwner

modifier onlyOwner();

onlyApproved

modifier onlyApproved();

constructor

constructor(address dao, address ormp);

receive

receive() external payable;

version

function version() public pure returns (string memory);

importMessageHash

Only could be called by owner.

function importMessageHash(uint256 chainId, address channel, uint256 msgIndex, bytes32 msgHash) external onlyOwner;

Parameters

NameTypeDescription
chainIduint256The source chain id.
channeladdressThe message channel.
msgIndexuint256The source chain message index.
msgHashbytes32The source chain message hash corresponding to the channel.

hashOf

function hashOf(uint256 chainId, address channel, uint256 msgIndex) public view override returns (bytes32);

changeOwner

function changeOwner(address newOwner) external onlyOwner;

setApproved

function setApproved(address operator, bool approve) external onlyOwner;

isApproved

function isApproved(address operator) public view returns (bool);

withdraw

function withdraw(address to, uint256 amount) external onlyApproved;

setFee

function setFee(uint256 chainId, uint256 fee_) external onlyApproved;

fee

function fee(uint256 toChainId, address) public view returns (uint256);

Events

SetFee

event SetFee(uint256 indexed chainId, uint256 fee);

SetApproved

event SetApproved(address operator, bool approve);

Withdrawal

event Withdrawal(address indexed to, uint256 amt);

OwnershipTransferred

event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

Relayer

Git Source

State Variables

PROTOCOL

address public immutable PROTOCOL;

owner

address public owner;

priceOf

mapping(uint256 => DstPrice) public priceOf;

configOf

mapping(uint256 => DstConfig) public configOf;

approvedOf

mapping(address => bool) public approvedOf;

Functions

onlyOwner

modifier onlyOwner();

onlyApproved

modifier onlyApproved();

constructor

constructor(address dao, address ormp);

version

function version() public pure returns (string memory);

receive

receive() external payable;

withdraw

function withdraw(address to, uint256 amount) external onlyApproved;

isApproved

function isApproved(address operator) public view returns (bool);

changeOwner

function changeOwner(address newOwner) external onlyOwner;

setApproved

function setApproved(address operator, bool approve) public onlyOwner;

setDstPrice

function setDstPrice(uint256 chainId, uint128 dstPriceRatio, uint128 dstGasPriceInWei) external onlyApproved;

setDstConfig

function setDstConfig(uint256 chainId, uint64 baseGas, uint64 gasPerByte) external onlyApproved;

fee

function fee(uint256 toChainId, address, uint256 gasLimit, bytes calldata encoded, bytes calldata)
    public
    view
    returns (uint256);

relay

function relay(Message calldata message) external onlyApproved;

Events

SetDstPrice

event SetDstPrice(uint256 indexed chainId, uint128 dstPriceRatio, uint128 dstGasPriceInWei);

SetDstConfig

event SetDstConfig(uint256 indexed chainId, uint64 baseGas, uint64 gasPerByte);

SetApproved

event SetApproved(address operator, bool approve);

OwnershipTransferred

event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

Structs

DstPrice

struct DstPrice {
    uint128 dstPriceRatio;
    uint128 dstGasPriceInWei;
}

DstConfig

struct DstConfig {
    uint64 baseGas;
    uint64 gasPerByte;
}

Contents

IORMP

Git Source

Functions

send

follow https://eips.ethereum.org/EIPS/eip-5750

Send a cross-chain message over the endpoint.

function send(
    uint256 toChainId,
    address to,
    uint256 gasLimit,
    bytes calldata encoded,
    address refund,
    bytes calldata params
) external payable returns (bytes32);

Parameters

NameTypeDescription
toChainIduint256The Message destination chain id.
toaddressUser application contract address which receive the message.
gasLimituint256Gas limit for destination user application used.
encodedbytesThe calldata which encoded by ABI Encoding.
refundaddressReturn extra fee to refund address.
paramsbytesGeneral extensibility for relayer to custom functionality.

Returns

NameTypeDescription
<none>bytes32Return the hash of the message as message id.

fee

Get a quote in source native gas, for the amount that send() requires to pay for message delivery.

function fee(uint256 toChainId, address ua, uint256 gasLimit, bytes calldata encoded, bytes calldata params)
    external
    view
    returns (uint256);

Parameters

NameTypeDescription
toChainIduint256The Message destination chain id.
uaaddress
gasLimituint256Gas limit for destination user application used.
encodedbytesThe calldata which encoded by ABI Encoding.
paramsbytesGeneral extensibility for relayer to custom functionality.

recv

Recv verified message and dispatch to destination user application address.

function recv(Message calldata message, bytes calldata proof) external payable returns (bool dispatchResult);

Parameters

NameTypeDescription
messageMessageVerified receive message info.
proofbytesMessage proof of this message.

Returns

NameTypeDescription
dispatchResultboolResult of the message dispatch.

getAppConfig

If user application has not configured, then the default config is used.

Fetch user application config.

function getAppConfig(address ua) external view returns (address oracle, address relayer);

Parameters

NameTypeDescription
uaaddressUser application contract address.

setAppConfig

Set user application config.

function setAppConfig(address oracle, address relayer) external;

Parameters

NameTypeDescription
oracleaddressOracle which user application choose.
relayeraddressRelayer which user application choose.

defaultUC

function defaultUC() external view returns (address oracle, address relayer);

dones

Check the msg if it is dispatched.

function dones(bytes32 msgHash) external view returns (bool);

Parameters

NameTypeDescription
msgHashbytes32Hash of the checked message.

Returns

NameTypeDescription
<none>boolReturn the dispatched result of the checked message.

importHash

Hash is an abstract of the proof system, it can be a block hash or a message root hash, specifically provided by oracles.

Import hash by any oracle address.

function importHash(uint256 chainId, address channel, uint256 msgIndex, bytes32 hash_) external;

Parameters

NameTypeDescription
chainIduint256The source chain id.
channeladdressThe message channel.
msgIndexuint256The source chain message index.
hash_bytes32The hash to import.

hashLookup

Fetch hash.

function hashLookup(address oracle, bytes32 lookupKey) external view returns (bytes32);

Parameters

NameTypeDescription
oracleaddressThe oracle address.
lookupKeybytes32The key for loop up hash.

Returns

NameTypeDescription
<none>bytes32Return the hash imported by the oracle.

IOracle

Git Source

Inherits: IVerifier

Functions

fee

Fetch oracle price to relay message root to the destination chain.

function fee(uint256 toChainId, address ua) external view returns (uint256);

Parameters

NameTypeDescription
toChainIduint256The destination chain id.
uaaddressThe user application which send the message.

Returns

NameTypeDescription
<none>uint256Oracle price in source native gas.

IRelayer

Git Source

Functions

fee

Fetch relayer price to relay message to the destination chain.

function fee(uint256 toChainId, address ua, uint256 gasLimit, bytes calldata encoded, bytes calldata params)
    external
    view
    returns (uint256);

Parameters

NameTypeDescription
toChainIduint256The destination chain id.
uaaddressThe user application which send the message.
gasLimituint256Gas limit for destination user application used.
encodedbytesThe calldata which encoded by ABI Encoding.
paramsbytesGeneral extensibility for relayer to custom functionality.

Returns

NameTypeDescription
<none>uint256Relayer price in source native gas.

IVerifier

Git Source

Functions

verifyMessageProof

Verify message proof

Message proof provided by relayer. Oracle should provide message root of source chain, and verify the merkle proof of the message hash.

function verifyMessageProof(Message calldata message, bytes calldata proof) external view returns (bool);

Parameters

NameTypeDescription
messageMessageThe message info.
proofbytesProof of the message

Returns

NameTypeDescription
<none>boolResult of the message verify.

Contents

ExcessivelySafeCall

Git Source

Functions

excessivelySafeCall

Use when you really really really don't trust the called contract. This prevents the called contract from causing reversion of the caller in as many ways as we can.

The main difference between this and a solidity low-level call is that we limit the number of bytes that the callee can cause to be copied to caller memory. This prevents stupid things like malicious contracts returning 10,000,000 bytes causing a local OOG when copying to memory.

function excessivelySafeCall(address _target, uint256 _gas, uint256 _value, uint16 _maxCopy, bytes memory _calldata)
    internal
    returns (bool, bytes memory);

Parameters

NameTypeDescription
_targetaddressThe address to call
_gasuint256The amount of gas to forward to the remote contract
_valueuint256Value in wei to send to the account
_maxCopyuint16The maximum number of bytes of returndata to copy to memory.
_calldatabytesThe data to send to the remote contract

Returns

NameTypeDescription
<none>boolsuccess and returndata, as .call(). Returndata is capped to _maxCopy bytes.
<none>bytes

excessivelySafeStaticCall

Use when you really really really don't trust the called contract. This prevents the called contract from causing reversion of the caller in as many ways as we can.

The main difference between this and a solidity low-level call is that we limit the number of bytes that the callee can cause to be copied to caller memory. This prevents stupid things like malicious contracts returning 10,000,000 bytes causing a local OOG when copying to memory.

function excessivelySafeStaticCall(address _target, uint256 _gas, uint16 _maxCopy, bytes memory _calldata)
    internal
    view
    returns (bool, bytes memory);

Parameters

NameTypeDescription
_targetaddressThe address to call
_gasuint256The amount of gas to forward to the remote contract
_maxCopyuint16The maximum number of bytes of returndata to copy to memory.
_calldatabytesThe data to send to the remote contract

Returns

NameTypeDescription
<none>boolsuccess and returndata, as .call(). Returndata is capped to _maxCopy bytes.
<none>bytes

ReentrancyGuard

Git Source

State Variables

_NOT_ENTERED

uint256 private constant _NOT_ENTERED = 1;

_ENTERED

uint256 private constant _ENTERED = 2;

_send_state

uint256 private _send_state = 1;

_receive_state

uint256 private _receive_state = 1;

Functions

sendNonReentrant

modifier sendNonReentrant();

recvNonReentrant

modifier recvNonReentrant();

Contents

AppBase

Git Source

Functions

onlyORMP

modifier onlyORMP() virtual;

_messageId

function _messageId() internal pure returns (bytes32 _msgDataMessageId);

_fromChainId

function _fromChainId() internal pure returns (uint256 _msgDataFromChainId);

_xmsgSender

function _xmsgSender() internal pure returns (address payable _from);

Application

Git Source

Inherits: AppBase

State Variables

ORMP

address public immutable ORMP;

Functions

onlyORMP

modifier onlyORMP() override;

constructor

constructor(address ormp);

_setAppConfig

function _setAppConfig(address oracle, address relayer) internal virtual;

Channel

Git Source

Inherits: UserConfig

A channel is a logical connection over cross-chain network. It used for cross-chain message transfer.

  • Accepts messages to be dispatched to destination chains, constructs a Merkle tree of the messages.
  • Dispatches verified messages from source chains.

State Variables

dones

msgHash => isDispathed.

mapping(bytes32 => bool) public dones;

count

message count.

uint256 public count;

__self

Self contract address cache.

address private immutable __self = address(this);

Functions

constructor

Init code.

constructor(address dao) UserConfig(dao);

LOCAL_CHAINID

Fetch local chain id.

function LOCAL_CHAINID() public view returns (uint256);

Returns

NameTypeDescription
<none>uint256chainId Local chain id.

_send

Send message.

function _send(address from, uint256 toChainId, address to, uint256 gasLimit, bytes calldata encoded)
    internal
    returns (bytes32);

Parameters

NameTypeDescription
fromaddressUser application contract address which send the message.
toChainIduint256The Message destination chain id.
toaddressUser application contract address which receive the message.
gasLimituint256Gas limit for destination user application used.
encodedbytesThe calldata which encoded by ABI Encoding.

_recv

Only message.to's config relayer could relay this message.

Receive messages.

function _recv(Message calldata message, bytes calldata proof) internal returns (bytes32);

Parameters

NameTypeDescription
messageMessageReceived message info.
proofbytesMessage proof of this message.

Events

MessageAccepted

Notifies an observer that the message has been accepted.

event MessageAccepted(bytes32 indexed msgHash, Message message);

Parameters

NameTypeDescription
msgHashbytes32Hash of the message.
messageMessageAccepted message info.

MessageDispatched

Notifies an observer that the message has been dispatched.

event MessageDispatched(bytes32 indexed msgHash, bool dispatchResult);

Parameters

NameTypeDescription
msgHashbytes32Hash of the message.
dispatchResultboolThe message dispatch result.

Message

Git Source

The block of control information and data for comminicate between user applications. Messages are the exchange medium used by channels to send and receive data through cross-chain networks. A message is sent from a source chain to a destination chain.

struct Message {
    address channel;
    uint256 index;
    uint256 fromChainId;
    address from;
    uint256 toChainId;
    address to;
    uint256 gasLimit;
    bytes encoded;
}

Properties

NameTypeDescription
channeladdress
indexuint256The leaf index lives in channel's incremental mekle tree.
fromChainIduint256The message source chain id.
fromaddressUser application contract address which send the message.
toChainIduint256The message destination chain id.
toaddressUser application contract address which receive the message.
gasLimituint256Gas limit for destination UA used.
encodedbytesThe calldata which encoded by ABI Encoding.

hash

Git Source

Hash of the message.

function hash(Message memory message) pure returns (bytes32);

ORMP

Git Source

Inherits: ReentrancyGuard, Channel

An endpoint is a type of network node for cross-chain communication. It is an interface exposed by a communication channel.

An endpoint is associated with an immutable channel and user configuration.

State Variables

hashLookup

oracle => lookupKey => hash

mapping(address => mapping(bytes32 => bytes32)) public hashLookup;

Functions

constructor

constructor(address dao) Channel(dao);

version

function version() public pure returns (string memory);

send

follow https://eips.ethereum.org/EIPS/eip-5750

Send a cross-chain message over the endpoint.

function send(
    uint256 toChainId,
    address to,
    uint256 gasLimit,
    bytes calldata encoded,
    address refund,
    bytes calldata params
) external payable sendNonReentrant returns (bytes32);

Parameters

NameTypeDescription
toChainIduint256The Message destination chain id.
toaddressUser application contract address which receive the message.
gasLimituint256Gas limit for destination user application used.
encodedbytesThe calldata which encoded by ABI Encoding.
refundaddressReturn extra fee to refund address.
paramsbytesGeneral extensibility for relayer to custom functionality.

importHash

Hash is an abstract of the proof system, it can be a block hash or a message root hash, specifically provided by oracles.

Import hash by any oracle address.

function importHash(uint256 chainId, address channel, uint256 msgIndex, bytes32 hash_) external;

Parameters

NameTypeDescription
chainIduint256The source chain id.
channeladdressThe message channel.
msgIndexuint256The source chain message index.
hash_bytes32The hash to import.

_handleFee

function _handleFee(
    address ua,
    address refund,
    bytes32 msgHash,
    uint256 toChainId,
    uint256 gasLimit,
    bytes calldata encoded,
    bytes calldata params
) internal;

fee

Get a quote in source native gas, for the amount that send() requires to pay for message delivery.

function fee(uint256 toChainId, address ua, uint256 gasLimit, bytes calldata encoded, bytes calldata params)
    external
    view
    returns (uint256);

Parameters

NameTypeDescription
toChainIduint256The Message destination chain id.
uaaddress
gasLimituint256Gas limit for destination user application used.
encodedbytesThe calldata which encoded by ABI Encoding.
paramsbytesGeneral extensibility for relayer to custom functionality.

_handleRelayer

function _handleRelayer(
    address relayer,
    uint256 toChainId,
    address ua,
    uint256 gasLimit,
    bytes calldata encoded,
    bytes calldata params
) internal returns (uint256);

_handleOracle

function _handleOracle(address oracle, uint256 toChainId, address ua) internal returns (uint256);

recv

Only channel could call this function.

Recv verified message from Channel and dispatch to destination user application address.

function recv(Message calldata message, bytes calldata proof)
    external
    payable
    recvNonReentrant
    returns (bool dispatchResult);

Parameters

NameTypeDescription
messageMessageVerified receive message info.
proofbytesMessage proof of this message.

Returns

NameTypeDescription
dispatchResultboolResult of the message dispatch.

_dispatch

Dispatch the cross chain message.

function _dispatch(Message memory message, bytes32 msgHash) private returns (bool dispatchResult);

_sendValue

Replacement for Solidity's transfer: sends amount wei to recipient, forwarding all available gas and reverting on errors.

function _sendValue(address recipient, uint256 amount) internal;

Events

MessageAssigned

event MessageAssigned(
    bytes32 indexed msgHash,
    address indexed oracle,
    address indexed relayer,
    uint256 oracleFee,
    uint256 relayerFee,
    bytes params
);

HashImported

event HashImported(address indexed oracle, uint256 chainId, address channel, uint256 msgIndex, bytes32 hash);

UC

Git Source

User application custom configuration.

struct UC {
    address oracle;
    address relayer;
}

Properties

NameTypeDescription
oracleaddressOracle contract address.
relayeraddressRelayer contract address.

UserConfig

Git Source

User config could select their own relayer and oracle. The default configuration is used by default.

Only setter could set default user config.

State Variables

setter

Setter address.

address public setter;

defaultUC

Default user config.

UC public defaultUC;

ucOf

ua => uc.

mapping(address => UC) public ucOf;

Functions

onlySetter

modifier onlySetter();

constructor

constructor(address dao);

changeSetter

Only current setter could call.

Change setter.

function changeSetter(address newSetter) external onlySetter;

Parameters

NameTypeDescription
newSetteraddressNew setter.

setDefaultConfig

Only setter could call.

Set default user config for all user application.

function setDefaultConfig(address oracle, address relayer) external onlySetter;

Parameters

NameTypeDescription
oracleaddressDefault oracle.
relayeraddressDefault relayer.

setAppConfig

Set user application config.

function setAppConfig(address oracle, address relayer) external;

Parameters

NameTypeDescription
oracleaddressOracle which user application.
relayeraddressRelayer which user application choose.

getAppConfig

If user application has not configured, then the default user config is used.

Fetch user application config.

function getAppConfig(address ua) public view returns (UC memory);

Parameters

NameTypeDescription
uaaddressUser application contract address.

Returns

NameTypeDescription
<none>UCuser application config.

Events

DefaultConfigUpdated

Notifies an observer that the default user config has updated.

event DefaultConfigUpdated(address oracle, address relayer);

Parameters

NameTypeDescription
oracleaddressDefault oracle.
relayeraddressDefault relayer.

AppConfigUpdated

Notifies an observer that the user application config has updated.

event AppConfigUpdated(address indexed ua, address oracle, address relayer);

Parameters

NameTypeDescription
uaaddressUser application contract address.
oracleaddressOracle which the user application choose.
relayeraddressRelayer which the user application choose.

SetterChanged

Notifies an observer that the setter is changed.

event SetterChanged(address indexed oldSetter, address indexed newSetter);

Parameters

NameTypeDescription
oldSetteraddressOld setter address.
newSetteraddressNew setter address.

Verifier

Git Source

Inherits: IVerifier

Functions

hashOf

Fetch message hash.

function hashOf(uint256 chainId, address channel, uint256 msgIndex) public view virtual returns (bytes32);

Parameters

NameTypeDescription
chainIduint256The source chain id.
channeladdressThe message channel.
msgIndexuint256The Message index.

Returns

NameTypeDescription
<none>bytes32Message hash in source chain.

verifyMessageProof

Verify message proof

Message proof provided by relayer. Oracle should provide message root of source chain, and verify the merkle proof of the message hash.

function verifyMessageProof(Message calldata message, bytes calldata) external view returns (bool);

Parameters

NameTypeDescription
messageMessageThe message info.
<none>bytes

Returns

NameTypeDescription
<none>boolResult of the message verify.