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
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
Name | Type | Description |
---|---|---|
chainId | uint256 | The source chain id. |
channel | address | The message channel. |
msgIndex | uint256 | The source chain message index. |
msgHash | bytes32 | The 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
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
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
Name | Type | Description |
---|---|---|
toChainId | uint256 | The Message destination chain id. |
to | address | User application contract address which receive the message. |
gasLimit | uint256 | Gas limit for destination user application used. |
encoded | bytes | The calldata which encoded by ABI Encoding. |
refund | address | Return extra fee to refund address. |
params | bytes | General extensibility for relayer to custom functionality. |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes32 | Return 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
Name | Type | Description |
---|---|---|
toChainId | uint256 | The Message destination chain id. |
ua | address | |
gasLimit | uint256 | Gas limit for destination user application used. |
encoded | bytes | The calldata which encoded by ABI Encoding. |
params | bytes | General 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
Name | Type | Description |
---|---|---|
message | Message | Verified receive message info. |
proof | bytes | Message proof of this message. |
Returns
Name | Type | Description |
---|---|---|
dispatchResult | bool | Result 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
Name | Type | Description |
---|---|---|
ua | address | User application contract address. |
setAppConfig
Set user application config.
function setAppConfig(address oracle, address relayer) external;
Parameters
Name | Type | Description |
---|---|---|
oracle | address | Oracle which user application choose. |
relayer | address | Relayer 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
Name | Type | Description |
---|---|---|
msgHash | bytes32 | Hash of the checked message. |
Returns
Name | Type | Description |
---|---|---|
<none> | bool | Return 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
Name | Type | Description |
---|---|---|
chainId | uint256 | The source chain id. |
channel | address | The message channel. |
msgIndex | uint256 | The source chain message index. |
hash_ | bytes32 | The hash to import. |
hashLookup
Fetch hash.
function hashLookup(address oracle, bytes32 lookupKey) external view returns (bytes32);
Parameters
Name | Type | Description |
---|---|---|
oracle | address | The oracle address. |
lookupKey | bytes32 | The key for loop up hash. |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes32 | Return the hash imported by the oracle. |
IOracle
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
Name | Type | Description |
---|---|---|
toChainId | uint256 | The destination chain id. |
ua | address | The user application which send the message. |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | Oracle price in source native gas. |
IRelayer
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
Name | Type | Description |
---|---|---|
toChainId | uint256 | The destination chain id. |
ua | address | The user application which send the message. |
gasLimit | uint256 | Gas limit for destination user application used. |
encoded | bytes | The calldata which encoded by ABI Encoding. |
params | bytes | General extensibility for relayer to custom functionality. |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | Relayer price in source native gas. |
IVerifier
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
Name | Type | Description |
---|---|---|
message | Message | The message info. |
proof | bytes | Proof of the message |
Returns
Name | Type | Description |
---|---|---|
<none> | bool | Result of the message verify. |
Contents
ExcessivelySafeCall
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
Name | Type | Description |
---|---|---|
_target | address | The address to call |
_gas | uint256 | The amount of gas to forward to the remote contract |
_value | uint256 | Value in wei to send to the account |
_maxCopy | uint16 | The maximum number of bytes of returndata to copy to memory. |
_calldata | bytes | The data to send to the remote contract |
Returns
Name | Type | Description |
---|---|---|
<none> | bool | success 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
Name | Type | Description |
---|---|---|
_target | address | The address to call |
_gas | uint256 | The amount of gas to forward to the remote contract |
_maxCopy | uint16 | The maximum number of bytes of returndata to copy to memory. |
_calldata | bytes | The data to send to the remote contract |
Returns
Name | Type | Description |
---|---|---|
<none> | bool | success and returndata, as .call() . Returndata is capped to _maxCopy bytes. |
<none> | bytes |
ReentrancyGuard
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
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
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
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
Name | Type | Description |
---|---|---|
<none> | uint256 | chainId Local chain id. |
_send
Send message.
function _send(address from, uint256 toChainId, address to, uint256 gasLimit, bytes calldata encoded)
internal
returns (bytes32);
Parameters
Name | Type | Description |
---|---|---|
from | address | User application contract address which send the message. |
toChainId | uint256 | The Message destination chain id. |
to | address | User application contract address which receive the message. |
gasLimit | uint256 | Gas limit for destination user application used. |
encoded | bytes | The 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
Name | Type | Description |
---|---|---|
message | Message | Received message info. |
proof | bytes | Message proof of this message. |
Events
MessageAccepted
Notifies an observer that the message has been accepted.
event MessageAccepted(bytes32 indexed msgHash, Message message);
Parameters
Name | Type | Description |
---|---|---|
msgHash | bytes32 | Hash of the message. |
message | Message | Accepted message info. |
MessageDispatched
Notifies an observer that the message has been dispatched.
event MessageDispatched(bytes32 indexed msgHash, bool dispatchResult);
Parameters
Name | Type | Description |
---|---|---|
msgHash | bytes32 | Hash of the message. |
dispatchResult | bool | The message dispatch result. |
Message
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
Name | Type | Description |
---|---|---|
channel | address | |
index | uint256 | The leaf index lives in channel's incremental mekle tree. |
fromChainId | uint256 | The message source chain id. |
from | address | User application contract address which send the message. |
toChainId | uint256 | The message destination chain id. |
to | address | User application contract address which receive the message. |
gasLimit | uint256 | Gas limit for destination UA used. |
encoded | bytes | The calldata which encoded by ABI Encoding. |
hash
Hash of the message.
function hash(Message memory message) pure returns (bytes32);
ORMP
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
Name | Type | Description |
---|---|---|
toChainId | uint256 | The Message destination chain id. |
to | address | User application contract address which receive the message. |
gasLimit | uint256 | Gas limit for destination user application used. |
encoded | bytes | The calldata which encoded by ABI Encoding. |
refund | address | Return extra fee to refund address. |
params | bytes | General 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
Name | Type | Description |
---|---|---|
chainId | uint256 | The source chain id. |
channel | address | The message channel. |
msgIndex | uint256 | The source chain message index. |
hash_ | bytes32 | The 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
Name | Type | Description |
---|---|---|
toChainId | uint256 | The Message destination chain id. |
ua | address | |
gasLimit | uint256 | Gas limit for destination user application used. |
encoded | bytes | The calldata which encoded by ABI Encoding. |
params | bytes | General 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
Name | Type | Description |
---|---|---|
message | Message | Verified receive message info. |
proof | bytes | Message proof of this message. |
Returns
Name | Type | Description |
---|---|---|
dispatchResult | bool | Result 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
User application custom configuration.
struct UC {
address oracle;
address relayer;
}
Properties
Name | Type | Description |
---|---|---|
oracle | address | Oracle contract address. |
relayer | address | Relayer contract address. |
UserConfig
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
Name | Type | Description |
---|---|---|
newSetter | address | New setter. |
setDefaultConfig
Only setter could call.
Set default user config for all user application.
function setDefaultConfig(address oracle, address relayer) external onlySetter;
Parameters
Name | Type | Description |
---|---|---|
oracle | address | Default oracle. |
relayer | address | Default relayer. |
setAppConfig
Set user application config.
function setAppConfig(address oracle, address relayer) external;
Parameters
Name | Type | Description |
---|---|---|
oracle | address | Oracle which user application. |
relayer | address | Relayer 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
Name | Type | Description |
---|---|---|
ua | address | User application contract address. |
Returns
Name | Type | Description |
---|---|---|
<none> | UC | user application config. |
Events
DefaultConfigUpdated
Notifies an observer that the default user config has updated.
event DefaultConfigUpdated(address oracle, address relayer);
Parameters
Name | Type | Description |
---|---|---|
oracle | address | Default oracle. |
relayer | address | Default relayer. |
AppConfigUpdated
Notifies an observer that the user application config has updated.
event AppConfigUpdated(address indexed ua, address oracle, address relayer);
Parameters
Name | Type | Description |
---|---|---|
ua | address | User application contract address. |
oracle | address | Oracle which the user application choose. |
relayer | address | Relayer which the user application choose. |
SetterChanged
Notifies an observer that the setter is changed.
event SetterChanged(address indexed oldSetter, address indexed newSetter);
Parameters
Name | Type | Description |
---|---|---|
oldSetter | address | Old setter address. |
newSetter | address | New setter address. |
Verifier
Inherits: IVerifier
Functions
hashOf
Fetch message hash.
function hashOf(uint256 chainId, address channel, uint256 msgIndex) public view virtual returns (bytes32);
Parameters
Name | Type | Description |
---|---|---|
chainId | uint256 | The source chain id. |
channel | address | The message channel. |
msgIndex | uint256 | The Message index. |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes32 | Message 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
Name | Type | Description |
---|---|---|
message | Message | The message info. |
<none> | bytes |
Returns
Name | Type | Description |
---|---|---|
<none> | bool | Result of the message verify. |