diff --git a/README.md b/README.md index 22665cc..cbfdc48 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ Oracle and Relayer based Message Protocol. ### Canonical Cross-chain Deployment Addresses | Contract | Canonical Cross-chain Deployment Address | |------------|--------------------------------------------| -| ORMP | 0x009D223Aad560e72282db9c0438Ef1ef2bf7703D | -| Oracle | 0x00BD655DDfA7aFeF4BB109FE1F938724527B49D8 | -| Relayer | 0x003605167cd4C36063a7B63e604497e623Bb8B10 | +| ORMP | 0x00000000001523057a05d6293C1e5171eE33eE0A | +| Oracle | 0x0000000000ba03146Cc235509E802873D418a6bc | +| Relayer | 0x0000000000808fE9bDCc1d180EfbF5C53552a6b1 | ## Usage To install with [**Foundry**](https://github.com/gakonst/foundry): diff --git a/bin/deploy.sh b/bin/deploy.sh index f3b54c7..f40a302 100755 --- a/bin/deploy.sh +++ b/bin/deploy.sh @@ -2,5 +2,5 @@ set -eo pipefail -forge script script/deploy/Deploy.s.sol:Deploy --chain-id 44 # --broadcast --verify -forge script script/deploy/Deploy.s.sol:Deploy --chain-id 421614 # --broadcast --verify # --skip-simulation +forge script script/deploy/Deploy.s.sol:Deploy --chain-id 44 --broadcast --verify +forge script script/deploy/Deploy.s.sol:Deploy --chain-id 421614 --broadcast --verify --skip-simulation diff --git a/bin/fee.sh b/bin/fee.sh index d45bbb9..27b959c 100755 --- a/bin/fee.sh +++ b/bin/fee.sh @@ -4,4 +4,4 @@ set -eo pipefail set -x forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 421614 --chain-id 44 --broadcast -forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 44 --chain-id 421614 --broadcast # --skip-simulation +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 44 --chain-id 421614 --broadcast --skip-simulation --slow diff --git a/script/deploy/Deploy.s.sol b/script/deploy/Deploy.s.sol index 8ed8734..f2fa30f 100644 --- a/script/deploy/Deploy.s.sol +++ b/script/deploy/Deploy.s.sol @@ -84,7 +84,7 @@ contract Deploy is Common { ScriptTools.exportContract(outputName, "DAO", dao); ScriptTools.exportContract(outputName, "ORMP", ORMP_ADDR); - ScriptTools.exportContract(outputName, "ORACLE", ORMP_ADDR); + ScriptTools.exportContract(outputName, "ORACLE", ORACLE_ADDR); ScriptTools.exportContract(outputName, "RELAYER", RELAYER_ADDR); } diff --git a/script/input/421614/oracle.c.json b/script/input/421614/oracle.c.json index 834982c..494caeb 100644 --- a/script/input/421614/oracle.c.json +++ b/script/input/421614/oracle.c.json @@ -1,3 +1,3 @@ { - "44": "0x00d917EC19A6b8837ADFcF8adE3D6faF62e0F587" + "44": "0x00000000007317c91F57D86A410934A490E62E1E" } diff --git a/script/input/44/oracle.c.json b/script/input/44/oracle.c.json index c028813..f7e844f 100644 --- a/script/input/44/oracle.c.json +++ b/script/input/44/oracle.c.json @@ -1,3 +1,3 @@ { - "421614": "0x00d917EC19A6b8837ADFcF8adE3D6faF62e0F587" + "421614": "0x00000000007317c91F57D86A410934A490E62E1E" } diff --git a/script/input/c3.json b/script/input/c3.json index 6e3186a..c59031f 100644 --- a/script/input/c3.json +++ b/script/input/c3.json @@ -5,5 +5,5 @@ "ORACLE_ADDR": "0x0000000000ba03146Cc235509E802873D418a6bc", "ORACLE_SALT": "0x7945140b3deab397a3ed2a87a716d03930e85e019b9bd2c21d28713feb5ab1de", "RELAYER_ADDR": "0x0000000000808fE9bDCc1d180EfbF5C53552a6b1", - "RELATER_SALT": "0x9d38bcb32422a45bc9c08605d4457bcd3dadddfee1573a352ace5f1defa45621" + "RELAYER_SALT": "0x9d38bcb32422a45bc9c08605d4457bcd3dadddfee1573a352ace5f1defa45621" } diff --git a/script/output/421614/ORMP.v.json b/script/output/421614/ORMP.v.json index fa6f54c..4aa8080 100644 --- a/script/output/421614/ORMP.v.json +++ b/script/output/421614/ORMP.v.json @@ -1 +1 @@ -{"language":"Solidity","sources":{"src/ORMP.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./Channel.sol\";\nimport \"./interfaces/IOracle.sol\";\nimport \"./interfaces/IRelayer.sol\";\nimport \"./security/ReentrancyGuard.sol\";\nimport \"./security/ExcessivelySafeCall.sol\";\n\n/// @title ORMP\n/// @notice An endpoint is a type of network node for cross-chain communication.\n/// It is an interface exposed by a communication channel.\n/// @dev An endpoint is associated with an immutable channel and user configuration.\ncontract ORMP is ReentrancyGuard, Channel {\n using ExcessivelySafeCall for address;\n\n constructor(address dao) Channel(dao) {}\n\n /// @dev Send a cross-chain message over the endpoint.\n /// @notice follow https://eips.ethereum.org/EIPS/eip-5750\n /// @param toChainId The Message destination chain id.\n /// @param to User application contract address which receive the message.\n /// @param gasLimit Gas limit for UA used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param refund Return extra fee to refund address.\n /// @param params General extensibility for relayer to custom functionality.\n function send(\n uint256 toChainId,\n address to,\n uint256 gasLimit,\n bytes calldata encoded,\n address refund,\n bytes calldata params\n ) external payable sendNonReentrant returns (bytes32) {\n // user application address.\n address ua = msg.sender;\n // send message by channel, return the hash of the message as id.\n bytes32 msgHash = _send(ua, toChainId, to, gasLimit, encoded);\n\n // handle fee\n _handleFee(ua, refund, msgHash, toChainId, gasLimit, encoded, params);\n\n return msgHash;\n }\n\n function _handleFee(\n address ua,\n address refund,\n bytes32 msgHash,\n uint256 toChainId,\n uint256 gasLimit,\n bytes calldata encoded,\n bytes calldata params\n ) internal {\n // fetch user application's config.\n Config memory uaConfig = getAppConfig(ua);\n // handle relayer fee\n uint256 relayerFee = _handleRelayer(uaConfig.relayer, msgHash, toChainId, ua, gasLimit, encoded, params);\n // handle oracle fee\n uint256 oracleFee = _handleOracle(uaConfig.oracle, msgHash, toChainId, ua);\n\n // refund\n if (msg.value > relayerFee + oracleFee) {\n uint256 refundFee = msg.value - (relayerFee + oracleFee);\n (bool success,) = refund.call{value: refundFee}(\"\");\n require(success, \"!refund\");\n }\n }\n\n /// @notice Get a quote in source native gas, for the amount that send() requires to pay for message delivery.\n /// @param toChainId The Message destination chain id.\n // @param ua User application contract address which send the message.\n /// @param gasLimit Gas limit for UA used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param params General extensibility for relayer to custom functionality.\n function fee(uint256 toChainId, address ua, uint256 gasLimit, bytes calldata encoded, bytes calldata params)\n external\n view\n returns (uint256)\n {\n Config memory uaConfig = getAppConfig(ua);\n uint256 relayerFee = IRelayer(uaConfig.relayer).fee(toChainId, ua, gasLimit, encoded, params);\n uint256 oracleFee = IOracle(uaConfig.oracle).fee(toChainId, ua);\n return relayerFee + oracleFee;\n }\n\n function _handleRelayer(\n address relayer,\n bytes32 msgHash,\n uint256 toChainId,\n address ua,\n uint256 gasLimit,\n bytes calldata encoded,\n bytes calldata params\n ) internal returns (uint256) {\n uint256 relayerFee = IRelayer(relayer).fee(toChainId, ua, gasLimit, encoded, params);\n IRelayer(relayer).assign{value: relayerFee}(msgHash, params);\n return relayerFee;\n }\n\n function _handleOracle(address oracle, bytes32 msgHash, uint256 toChainId, address ua) internal returns (uint256) {\n uint256 oracleFee = IOracle(oracle).fee(toChainId, ua);\n IOracle(oracle).assign{value: oracleFee}(msgHash);\n return oracleFee;\n }\n\n /// @dev Recv verified message from Channel and dispatch to destination user application address.\n /// @notice Only channel could call this function.\n /// @param message Verified receive message info.\n /// @param proof Message proof of this message.\n /// @return dispatchResult Result of the message dispatch.\n function recv(Message calldata message, bytes calldata proof)\n external\n payable\n recvNonReentrant\n returns (bool dispatchResult)\n {\n bytes32 msgHash = _recv(message, proof);\n dispatchResult = _dispatch(message, msgHash);\n // emit dispatched message event.\n emit MessageDispatched(msgHash, dispatchResult);\n }\n\n /// @dev Dispatch the cross chain message.\n function _dispatch(Message memory message, bytes32 msgHash) private returns (bool dispatchResult) {\n // Deliver the message to user application contract address.\n (dispatchResult,) = message.to.excessivelySafeCall(\n message.gasLimit,\n msg.value,\n 0,\n abi.encodePacked(message.encoded, msgHash, message.fromChainId, message.from)\n );\n }\n}\n"},"src/Channel.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./UserConfig.sol\";\nimport \"./interfaces/IVerifier.sol\";\nimport \"./imt/IncrementalMerkleTree.sol\";\n\n/// @title Channel\n/// @notice A channel is a logical connection over cross-chain network.\n/// It used for cross-chain message transfer.\n/// - Accepts messages to be dispatched to remote chains,\n/// constructs a Merkle tree of the messages.\n/// - Dispatches verified messages from source chains.\n/// @dev Messages live in an incremental merkle tree (imt)\n/// > A Merkle tree is a binary and complete tree decorated with\n/// > the Merkle (hash) attribute.\ncontract Channel is UserConfig {\n using IncrementalMerkleTree for IncrementalMerkleTree.Tree;\n\n /// @dev Incremental merkle tree root which all message hashes live in leafs.\n bytes32 public root;\n /// @dev Incremental merkle tree.\n IncrementalMerkleTree.Tree private imt;\n /// @dev msgHash => isDispathed.\n mapping(bytes32 => bool) public dones;\n /// @dev Self contract address cache.\n address private immutable _self = address(this);\n\n /// @dev Notifies an observer that the message has been accepted.\n /// @param msgHash Hash of the message.\n /// @param root New incremental merkle tree root after a new message inserted.\n /// @param message Accepted message info.\n event MessageAccepted(bytes32 indexed msgHash, bytes32 root, Message message);\n /// @dev Notifies an observer that the message has been dispatched.\n /// @param msgHash Hash of the message.\n /// @param dispatchResult The message dispatch result.\n event MessageDispatched(bytes32 indexed msgHash, bool dispatchResult);\n\n /// @dev Init code.\n constructor(address dao) UserConfig(dao) {\n // init with empty tree\n root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757;\n }\n\n /// @dev Fetch local chain id.\n /// @return chainId Local chain id.\n function LOCAL_CHAINID() public view returns (uint256 chainId) {\n assembly {\n chainId := chainid()\n }\n }\n\n /// @dev Send message.\n /// @param from User application contract address which send the message.\n /// @param toChainId The Message destination chain id.\n /// @param to User application contract address which receive the message.\n /// @param gasLimit Gas limit for UA used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n function _send(address from, uint256 toChainId, address to, uint256 gasLimit, bytes calldata encoded)\n internal\n returns (bytes32)\n {\n // only cross-chain message\n require(toChainId != LOCAL_CHAINID(), \"!cross-chain\");\n // get this message leaf index.\n uint256 index = messageCount();\n // constuct message object.\n Message memory message = Message({\n channel: _self,\n index: index,\n fromChainId: LOCAL_CHAINID(),\n from: from,\n toChainId: toChainId,\n to: to,\n gasLimit: gasLimit,\n encoded: encoded\n });\n // hash the message.\n bytes32 msgHash = hash(message);\n // insert msg hash to imt.\n imt.insert(msgHash);\n // update new imt.root to root storage.\n root = imt.root();\n\n // emit accepted message event.\n emit MessageAccepted(msgHash, root, message);\n\n // return this message hash.\n return msgHash;\n }\n\n /// @dev Receive messages.\n /// @notice Only message.to's config relayer could relayer this message.\n /// @param message Received message info.\n /// @param proof Message proof of this message.\n function _recv(Message calldata message, bytes calldata proof) internal returns (bytes32) {\n // get message.to user config.\n Config memory uaConfig = getAppConfig(message.to);\n // only the config relayer could relay this message.\n require(uaConfig.relayer == msg.sender, \"!auth\");\n\n // hash the message.\n bytes32 msgHash = hash(message);\n // verify message by the config oracle.\n require(IVerifier(uaConfig.oracle).verifyMessageProof(message.fromChainId, msgHash, proof), \"!proof\");\n\n // check destination chain id is correct.\n require(LOCAL_CHAINID() == message.toChainId, \"!toChainId\");\n // check the message is not dispatched.\n require(dones[msgHash] == false, \"done\");\n // set the message is dispatched.\n dones[msgHash] = true;\n\n return msgHash;\n }\n\n /// @dev Fetch the messages count of incremental merkle tree.\n function messageCount() public view returns (uint256) {\n return imt.count;\n }\n\n /// @dev Fetch the branch of incremental merkle tree.\n function imtBranch() public view returns (bytes32[32] memory) {\n return imt.branch;\n }\n\n /// @dev Fetch the latest message proof\n function prove() public view returns (bytes32[32] memory) {\n return imt.prove();\n }\n}\n"},"src/interfaces/IOracle.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./IVerifier.sol\";\n\ninterface IOracle is IVerifier {\n /// @notice Fetch oracle price to relay message root to the destination chain.\n /// @param toChainId The destination chain id.\n /// @param ua The user application which send the message.\n /// @return Oracle price in source native gas.\n function fee(uint256 toChainId, address ua) external view returns (uint256);\n\n /// @notice Assign the relay message root task to oracle maintainer.\n /// @param msgHash Hash of the message.\n function assign(bytes32 msgHash) external payable;\n}\n"},"src/interfaces/IRelayer.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IRelayer {\n /// @notice Fetch relayer price to relay message to the destination chain.\n /// @param toChainId The destination chain id.\n /// @param ua The user application which send the message.\n /// @param gasLimit Gas limit for UA used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param params General extensibility for relayer to custom functionality.\n /// @return Relayer price in source native gas.\n function fee(uint256 toChainId, address ua, uint256 gasLimit, bytes calldata encoded, bytes calldata params)\n external\n view\n returns (uint256);\n\n /// @notice Assign the relay message task to relayer maintainer.\n /// @param msgHash Hash of the message.\n /// @param params General extensibility for relayer to custom functionality.\n function assign(bytes32 msgHash, bytes calldata params) external payable;\n}\n"},"src/security/ReentrancyGuard.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nabstract contract ReentrancyGuard {\n // send and receive nonreentrant lock\n uint8 internal constant _NOT_ENTERED = 1;\n uint8 internal constant _ENTERED = 2;\n uint8 internal _send_state = 1;\n uint8 internal _receive_state = 1;\n\n modifier sendNonReentrant() {\n require(_send_state == _NOT_ENTERED, \"!send-reentrancy\");\n _send_state = _ENTERED;\n _;\n _send_state = _NOT_ENTERED;\n }\n\n modifier recvNonReentrant() {\n require(_receive_state == _NOT_ENTERED, \"!recv-reentrancy\");\n _receive_state = _ENTERED;\n _;\n _receive_state = _NOT_ENTERED;\n }\n}\n"},"src/security/ExcessivelySafeCall.sol":{"content":"// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity 0.8.17;\n\n// Inspired: https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/util/ExcessivelySafeCall.sol\n\nlibrary ExcessivelySafeCall {\n uint256 internal constant LOW_28_MASK = 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff;\n\n /// @notice Use when you _really_ really _really_ don't trust the called\n /// contract. This prevents the called contract from causing reversion of\n /// the caller in as many ways as we can.\n /// @dev The main difference between this and a solidity low-level call is\n /// that we limit the number of bytes that the callee can cause to be\n /// copied to caller memory. This prevents stupid things like malicious\n /// contracts returning 10,000,000 bytes causing a local OOG when copying\n /// to memory.\n /// @param _target The address to call\n /// @param _gas The amount of gas to forward to the remote contract\n /// @param _value Value in wei to send to the account\n /// @param _maxCopy The maximum number of bytes of returndata to copy\n /// to memory.\n /// @param _calldata The data to send to the remote contract\n /// @return success and returndata, as `.call()`. Returndata is capped to\n /// `_maxCopy` bytes.\n function excessivelySafeCall(address _target, uint256 _gas, uint256 _value, uint16 _maxCopy, bytes memory _calldata)\n internal\n returns (bool, bytes memory)\n {\n // set up for assembly call\n uint256 _toCopy;\n bool _success;\n bytes memory _returnData = new bytes(_maxCopy);\n // dispatch message to recipient\n // by assembly calling \"handle\" function\n // we call via assembly to avoid memcopying a very large returndata\n // returned by a malicious contract\n assembly (\"memory-safe\") {\n _success :=\n call(\n _gas, // gas\n _target, // recipient\n _value, // ether value\n add(_calldata, 0x20), // inloc\n mload(_calldata), // inlen\n 0, // outloc\n 0 // outlen\n )\n // limit our copy to 256 bytes\n _toCopy := returndatasize()\n if gt(_toCopy, _maxCopy) { _toCopy := _maxCopy }\n // Store the length of the copied bytes\n mstore(_returnData, _toCopy)\n // copy the bytes from returndata[0:_toCopy]\n returndatacopy(add(_returnData, 0x20), 0, _toCopy)\n }\n return (_success, _returnData);\n }\n\n /// @notice Use when you _really_ really _really_ don't trust the called\n /// contract. This prevents the called contract from causing reversion of\n /// the caller in as many ways as we can.\n /// @dev The main difference between this and a solidity low-level call is\n /// that we limit the number of bytes that the callee can cause to be\n /// copied to caller memory. This prevents stupid things like malicious\n /// contracts returning 10,000,000 bytes causing a local OOG when copying\n /// to memory.\n /// @param _target The address to call\n /// @param _gas The amount of gas to forward to the remote contract\n /// @param _maxCopy The maximum number of bytes of returndata to copy\n /// to memory.\n /// @param _calldata The data to send to the remote contract\n /// @return success and returndata, as `.call()`. Returndata is capped to\n /// `_maxCopy` bytes.\n function excessivelySafeStaticCall(address _target, uint256 _gas, uint16 _maxCopy, bytes memory _calldata)\n internal\n view\n returns (bool, bytes memory)\n {\n // set up for assembly call\n uint256 _toCopy;\n bool _success;\n bytes memory _returnData = new bytes(_maxCopy);\n // dispatch message to recipient\n // by assembly calling \"handle\" function\n // we call via assembly to avoid memcopying a very large returndata\n // returned by a malicious contract\n assembly (\"memory-safe\") {\n _success :=\n staticcall(\n _gas, // gas\n _target, // recipient\n add(_calldata, 0x20), // inloc\n mload(_calldata), // inlen\n 0, // outloc\n 0 // outlen\n )\n // limit our copy to 256 bytes\n _toCopy := returndatasize()\n if gt(_toCopy, _maxCopy) { _toCopy := _maxCopy }\n // Store the length of the copied bytes\n mstore(_returnData, _toCopy)\n // copy the bytes from returndata[0:_toCopy]\n returndatacopy(add(_returnData, 0x20), 0, _toCopy)\n }\n return (_success, _returnData);\n }\n\n /// @notice Swaps function selectors in encoded contract calls\n /// @dev Allows reuse of encoded calldata for functions with identical\n /// argument types but different names. It simply swaps out the first 4 bytes\n /// for the new selector. This function modifies memory in place, and should\n /// only be used with caution.\n /// @param _newSelector The new 4-byte selector\n /// @param _buf The encoded contract args\n function swapSelector(bytes4 _newSelector, bytes memory _buf) internal pure {\n require(_buf.length >= 4);\n uint256 _mask = LOW_28_MASK;\n assembly (\"memory-safe\") {\n // load the first word of\n let _word := mload(add(_buf, 0x20))\n // mask out the top 4 bytes\n // /x\n _word := and(_word, _mask)\n _word := or(_newSelector, _word)\n mstore(add(_buf, 0x20), _word)\n }\n }\n}\n"},"src/UserConfig.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./Common.sol\";\n\n/// @title UserConfig\n/// @notice User config could select their own relayer and oracle.\n/// The default configuration is used by default.\n/// @dev Only setter could set default config.\ncontract UserConfig {\n /// @dev Setter address.\n address public setter;\n /// @dev ua => config.\n mapping(address => Config) public appConfig;\n /// @dev Default config.\n Config public defaultConfig;\n\n /// @dev Notifies an observer that the default config has set.\n /// @param oracle Default oracle.\n /// @param relayer Default relayer.\n event SetDefaultConfig(address oracle, address relayer);\n /// @dev Notifies an observer that the user application config has updated.\n /// @param ua User application contract address.\n /// @param oracle Oracle which user application.\n /// @param relayer Relayer which user application choose.\n event AppConfigUpdated(address indexed ua, address oracle, address relayer);\n\n modifier onlySetter() {\n require(msg.sender == setter, \"!auth\");\n _;\n }\n\n constructor(address dao) {\n setter = dao;\n }\n\n /// @dev Change setter.\n /// @notice Only current setter could call.\n /// @param setter_ New setter.\n function changeSetter(address setter_) external onlySetter {\n setter = setter_;\n }\n\n /// @dev Set default config for all application.\n /// @notice Only setter could call.\n /// @param oracle Default oracle.\n /// @param relayer Default relayer.\n function setDefaultConfig(address oracle, address relayer) external onlySetter {\n defaultConfig = Config(oracle, relayer);\n emit SetDefaultConfig(oracle, relayer);\n }\n\n function getDefaultConfig() external view returns (Config memory) {\n return defaultConfig;\n }\n\n /// @dev Fetch user application config.\n /// @notice If user application has not configured, then the default config is used.\n /// @param ua User application contract address.\n /// @return user application config.\n function getAppConfig(address ua) public view returns (Config memory) {\n Config memory c = appConfig[ua];\n\n if (c.relayer == address(0x0)) {\n c.relayer = defaultConfig.relayer;\n }\n\n if (c.oracle == address(0x0)) {\n c.oracle = defaultConfig.oracle;\n }\n\n return c;\n }\n\n /// @notice Set user application config.\n /// @param oracle Oracle which user application.\n /// @param relayer Relayer which user application choose.\n function setAppConfig(address oracle, address relayer) external {\n appConfig[msg.sender] = Config(oracle, relayer);\n emit AppConfigUpdated(msg.sender, oracle, relayer);\n }\n}\n"},"src/interfaces/IVerifier.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IVerifier {\n /// @notice Fetch message root oracle.\n /// @param chainId The destination chain id.\n /// @param blockNumber The block number where the message root is located.\n /// @return Message root in destination chain.\n function merkleRoot(uint256 chainId, uint256 blockNumber) external view returns (bytes32);\n\n /// @notice Verify message proof\n /// @dev Message proof provided by relayer. Oracle should provide message root of\n /// source chain, and verify the merkle proof of the message hash.\n /// @param fromChainId Source chain id.\n /// @param msgHash Hash of the message.\n /// @param proof Merkle proof of the message\n /// @return Result of the message verify.\n function verifyMessageProof(uint256 fromChainId, bytes32 msgHash, bytes calldata proof)\n external\n view\n returns (bool);\n}\n"},"src/imt/IncrementalMerkleTree.sol":{"content":"// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity 0.8.17;\n\n// Inspired: https://github.com/nomad-xyz/monorepo/blob/main/packages/contracts-core/contracts/libs/Merkle.sol\n\n/// @title IncrementalMerkleTree\n/// @author Illusory Systems Inc.\n/// @notice An incremental merkle tree modeled on the eth2 deposit contract.\nlibrary IncrementalMerkleTree {\n uint256 internal constant TREE_DEPTH = 32;\n uint256 internal constant MAX_LEAVES = 2 ** TREE_DEPTH - 1;\n\n /// @notice Struct representing incremental merkle tree. Contains current\n /// branch and the number of inserted leaves in the tree.\n struct Tree {\n bytes32[TREE_DEPTH] branch;\n uint256 count;\n }\n\n /// @notice Inserts `_node` into merkle tree\n /// @dev Reverts if tree is full\n /// @param _node Element to insert into tree\n function insert(Tree storage _tree, bytes32 _node) internal {\n require(_tree.count < MAX_LEAVES, \"merkle tree full\");\n\n _tree.count += 1;\n uint256 size = _tree.count;\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n if ((size & 1) == 1) {\n _tree.branch[i] = _node;\n return;\n }\n _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n size /= 2;\n }\n // As the loop should always end prematurely with the `return` statement,\n // this code should be unreachable. We assert `false` just to be safe.\n assert(false);\n }\n\n /// @notice Calculates and returns`_tree`'s current root given array of zero\n /// hashes\n /// @param _zeroes Array of zero hashes\n /// @return _current Calculated root of `_tree`\n function rootWithCtx(Tree storage _tree, bytes32[TREE_DEPTH] memory _zeroes)\n internal\n view\n returns (bytes32 _current)\n {\n uint256 _index = _tree.count;\n\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ithBit = (_index >> i) & 0x01;\n bytes32 _next = _tree.branch[i];\n if (_ithBit == 1) {\n _current = keccak256(abi.encodePacked(_next, _current));\n } else {\n _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n }\n }\n }\n\n /// @notice Calculates and returns`_tree`'s current root\n function root(Tree storage _tree) internal view returns (bytes32) {\n return rootWithCtx(_tree, zeroHashes());\n }\n\n /// @notice Returns array of TREE_DEPTH zero hashes\n /// @return _zeroes Array of TREE_DEPTH zero hashes\n function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n _zeroes[0] = Z_0;\n _zeroes[1] = Z_1;\n _zeroes[2] = Z_2;\n _zeroes[3] = Z_3;\n _zeroes[4] = Z_4;\n _zeroes[5] = Z_5;\n _zeroes[6] = Z_6;\n _zeroes[7] = Z_7;\n _zeroes[8] = Z_8;\n _zeroes[9] = Z_9;\n _zeroes[10] = Z_10;\n _zeroes[11] = Z_11;\n _zeroes[12] = Z_12;\n _zeroes[13] = Z_13;\n _zeroes[14] = Z_14;\n _zeroes[15] = Z_15;\n _zeroes[16] = Z_16;\n _zeroes[17] = Z_17;\n _zeroes[18] = Z_18;\n _zeroes[19] = Z_19;\n _zeroes[20] = Z_20;\n _zeroes[21] = Z_21;\n _zeroes[22] = Z_22;\n _zeroes[23] = Z_23;\n _zeroes[24] = Z_24;\n _zeroes[25] = Z_25;\n _zeroes[26] = Z_26;\n _zeroes[27] = Z_27;\n _zeroes[28] = Z_28;\n _zeroes[29] = Z_29;\n _zeroes[30] = Z_30;\n _zeroes[31] = Z_31;\n }\n\n /// @notice Calculates and returns the merkle root for the given leaf\n /// `_item`, a merkle branch, and the index of `_item` in the tree.\n /// @param _item Merkle leaf\n /// @param _branch Merkle proof\n /// @param _index Index of `_item` in tree\n /// @return _current Calculated merkle root\n function branchRoot(bytes32 _item, bytes32[TREE_DEPTH] memory _branch, uint256 _index)\n internal\n pure\n returns (bytes32 _current)\n {\n _current = _item;\n\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ithBit = (_index >> i) & 0x01;\n bytes32 _next = _branch[i];\n if (_ithBit == 1) {\n _current = keccak256(abi.encodePacked(_next, _current));\n } else {\n _current = keccak256(abi.encodePacked(_current, _next));\n }\n }\n }\n\n function prove(Tree storage _tree) internal view returns (bytes32[TREE_DEPTH] memory proof) {\n uint256 _index = _tree.count - 1;\n bytes32[TREE_DEPTH] memory left = _tree.branch;\n bytes32[TREE_DEPTH] memory right = zeroHashes();\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ith_bit = (_index >> i) & 0x01;\n if (_ith_bit == 1) {\n proof[i] = left[i];\n } else {\n proof[i] = right[i];\n }\n }\n }\n\n // keccak256 zero hashes\n bytes32 internal constant Z_0 = hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n bytes32 internal constant Z_1 = hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n bytes32 internal constant Z_2 = hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n bytes32 internal constant Z_3 = hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n bytes32 internal constant Z_4 = hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n bytes32 internal constant Z_5 = hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n bytes32 internal constant Z_6 = hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n bytes32 internal constant Z_7 = hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n bytes32 internal constant Z_8 = hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n bytes32 internal constant Z_9 = hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n bytes32 internal constant Z_10 = hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n bytes32 internal constant Z_11 = hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n bytes32 internal constant Z_12 = hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n bytes32 internal constant Z_13 = hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n bytes32 internal constant Z_14 = hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n bytes32 internal constant Z_15 = hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n bytes32 internal constant Z_16 = hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n bytes32 internal constant Z_17 = hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n bytes32 internal constant Z_18 = hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n bytes32 internal constant Z_19 = hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n bytes32 internal constant Z_20 = hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n bytes32 internal constant Z_21 = hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n bytes32 internal constant Z_22 = hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n bytes32 internal constant Z_23 = hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n bytes32 internal constant Z_24 = hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n bytes32 internal constant Z_25 = hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n bytes32 internal constant Z_26 = hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n bytes32 internal constant Z_27 = hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n bytes32 internal constant Z_28 = hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n bytes32 internal constant Z_29 = hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n bytes32 internal constant Z_30 = hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n bytes32 internal constant Z_31 = hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n"},"src/Common.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\n/// @dev The block of control information and data for comminicate\n/// between user applications. Messages are the exchange medium\n/// used by channels to send and receive data through cross-chain networks.\n/// A message is sent from a source chain to a destination chain.\n/// @param index The leaf index lives in channel's incremental mekle tree.\n/// @param fromChainId The message source chain id.\n/// @param from User application contract address which send the message.\n/// @param toChainId The Message destination chain id.\n/// @param to User application contract address which receive the message.\n/// @param gasLimit Gas limit for UA used.\n/// @param encoded The calldata which encoded by ABI Encoding.\nstruct Message {\n address channel;\n uint256 index;\n uint256 fromChainId;\n address from;\n uint256 toChainId;\n address to;\n uint256 gasLimit;\n bytes encoded; /*(abi.encodePacked(SELECTOR, PARAMS))*/\n}\n\n/// @dev User application custom configuration.\n/// @param oracle Oracle contract address.\n/// @param relayer Relayer contract address.\nstruct Config {\n address oracle;\n address relayer;\n}\n\n/// @dev Hash of the message.\nfunction hash(Message memory message) pure returns (bytes32) {\n return keccak256(abi.encode(message));\n}\n"}},"settings":{"remappings":["forge-std/=lib/forge-std/src/","ds-test/=lib/forge-std/lib/ds-test/src/","create3-deploy/=lib/create3-deploy/"],"optimizer":{"enabled":true,"runs":999999},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs"},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata","storageLayout","devdoc","userdoc"]}},"evmVersion":"london","libraries":{}}} +{"language":"Solidity","sources":{"src/ORMP.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./Channel.sol\";\nimport \"./interfaces/IOracle.sol\";\nimport \"./interfaces/IRelayer.sol\";\nimport \"./security/ReentrancyGuard.sol\";\nimport \"./security/ExcessivelySafeCall.sol\";\n\n/// @title ORMP\n/// @notice An endpoint is a type of network node for cross-chain communication.\n/// It is an interface exposed by a communication channel.\n/// @dev An endpoint is associated with an immutable channel and user configuration.\ncontract ORMP is ReentrancyGuard, Channel {\n using ExcessivelySafeCall for address;\n\n constructor(address dao) Channel(dao) {}\n\n /// @dev Send a cross-chain message over the endpoint.\n /// @notice follow https://eips.ethereum.org/EIPS/eip-5750\n /// @param toChainId The Message destination chain id.\n /// @param to User application contract address which receive the message.\n /// @param gasLimit Gas limit for destination user application used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param refund Return extra fee to refund address.\n /// @param params General extensibility for relayer to custom functionality.\n function send(\n uint256 toChainId,\n address to,\n uint256 gasLimit,\n bytes calldata encoded,\n address refund,\n bytes calldata params\n ) external payable sendNonReentrant returns (bytes32) {\n // user application address.\n address ua = msg.sender;\n // send message by channel, return the hash of the message as id.\n bytes32 msgHash = _send(ua, toChainId, to, gasLimit, encoded);\n\n // handle fee\n _handleFee(ua, refund, msgHash, toChainId, gasLimit, encoded, params);\n\n return msgHash;\n }\n\n function _handleFee(\n address ua,\n address refund,\n bytes32 msgHash,\n uint256 toChainId,\n uint256 gasLimit,\n bytes calldata encoded,\n bytes calldata params\n ) internal {\n // fetch user application's config.\n UC memory uc = getAppConfig(ua);\n // handle relayer fee\n uint256 relayerFee = _handleRelayer(uc.relayer, msgHash, toChainId, ua, gasLimit, encoded, params);\n // handle oracle fee\n uint256 oracleFee = _handleOracle(uc.oracle, msgHash, toChainId, ua);\n\n // refund\n if (msg.value > relayerFee + oracleFee) {\n uint256 refundFee = msg.value - (relayerFee + oracleFee);\n (bool success,) = refund.call{value: refundFee}(\"\");\n require(success, \"!refund\");\n }\n }\n\n /// @notice Get a quote in source native gas, for the amount that send() requires to pay for message delivery.\n /// @param toChainId The Message destination chain id.\n // @param ua User application contract address which send the message.\n /// @param gasLimit Gas limit for destination user application used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param params General extensibility for relayer to custom functionality.\n function fee(uint256 toChainId, address ua, uint256 gasLimit, bytes calldata encoded, bytes calldata params)\n external\n view\n returns (uint256)\n {\n UC memory uc = getAppConfig(ua);\n uint256 relayerFee = IRelayer(uc.relayer).fee(toChainId, ua, gasLimit, encoded, params);\n uint256 oracleFee = IOracle(uc.oracle).fee(toChainId, ua);\n return relayerFee + oracleFee;\n }\n\n function _handleRelayer(\n address relayer,\n bytes32 msgHash,\n uint256 toChainId,\n address ua,\n uint256 gasLimit,\n bytes calldata encoded,\n bytes calldata params\n ) internal returns (uint256) {\n uint256 relayerFee = IRelayer(relayer).fee(toChainId, ua, gasLimit, encoded, params);\n IRelayer(relayer).assign{value: relayerFee}(msgHash, params);\n return relayerFee;\n }\n\n function _handleOracle(address oracle, bytes32 msgHash, uint256 toChainId, address ua) internal returns (uint256) {\n uint256 oracleFee = IOracle(oracle).fee(toChainId, ua);\n IOracle(oracle).assign{value: oracleFee}(msgHash);\n return oracleFee;\n }\n\n /// @dev Recv verified message from Channel and dispatch to destination user application address.\n /// @notice Only channel could call this function.\n /// @param message Verified receive message info.\n /// @param proof Message proof of this message.\n /// @return dispatchResult Result of the message dispatch.\n function recv(Message calldata message, bytes calldata proof)\n external\n payable\n recvNonReentrant\n returns (bool dispatchResult)\n {\n bytes32 msgHash = _recv(message, proof);\n dispatchResult = _dispatch(message, msgHash);\n // emit dispatched message event.\n emit MessageDispatched(msgHash, dispatchResult);\n }\n\n /// @dev Dispatch the cross chain message.\n function _dispatch(Message memory message, bytes32 msgHash) private returns (bool dispatchResult) {\n // Deliver the message to user application contract address.\n (dispatchResult,) = message.to.excessivelySafeCall(\n message.gasLimit,\n msg.value,\n 0,\n abi.encodePacked(message.encoded, msgHash, message.fromChainId, message.from)\n );\n }\n}\n"},"src/Channel.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./UserConfig.sol\";\nimport \"./interfaces/IVerifier.sol\";\nimport \"./imt/IncrementalMerkleTree.sol\";\n\n/// @title Channel\n/// @notice A channel is a logical connection over cross-chain network.\n/// It used for cross-chain message transfer.\n/// - Accepts messages to be dispatched to destination chains,\n/// constructs a Merkle tree of the messages.\n/// - Dispatches verified messages from source chains.\n/// @dev Messages live in an incremental merkle tree (imt)\n/// > A Merkle tree is a binary and complete tree decorated with\n/// > the Merkle (hash) attribute.\ncontract Channel is UserConfig {\n using IncrementalMerkleTree for IncrementalMerkleTree.Tree;\n\n /// @dev Incremental merkle tree root which all message hashes live in leafs.\n bytes32 public root;\n /// @dev Incremental merkle tree.\n IncrementalMerkleTree.Tree private _imt;\n /// @dev msgHash => isDispathed.\n mapping(bytes32 => bool) public dones;\n\n /// @dev Self contract address cache.\n address private immutable __self = address(this);\n\n /// @dev Notifies an observer that the message has been accepted.\n /// @param msgHash Hash of the message.\n /// @param root New incremental merkle tree root after a new message inserted.\n /// @param message Accepted message info.\n event MessageAccepted(bytes32 indexed msgHash, bytes32 root, Message message);\n /// @dev Notifies an observer that the message has been dispatched.\n /// @param msgHash Hash of the message.\n /// @param dispatchResult The message dispatch result.\n event MessageDispatched(bytes32 indexed msgHash, bool dispatchResult);\n\n /// @dev Init code.\n constructor(address dao) UserConfig(dao) {\n // init with empty tree\n root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757;\n }\n\n /// @dev Fetch local chain id.\n /// @return chainId Local chain id.\n function LOCAL_CHAINID() public view returns (uint256 chainId) {\n assembly {\n chainId := chainid()\n }\n }\n\n /// @dev Send message.\n /// @param from User application contract address which send the message.\n /// @param toChainId The Message destination chain id.\n /// @param to User application contract address which receive the message.\n /// @param gasLimit Gas limit for destination user application used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n function _send(address from, uint256 toChainId, address to, uint256 gasLimit, bytes calldata encoded)\n internal\n returns (bytes32)\n {\n // only cross-chain message\n require(toChainId != LOCAL_CHAINID(), \"!cross-chain\");\n // get this message leaf index.\n uint256 index = messageCount();\n // constuct message object.\n Message memory message = Message({\n channel: __self,\n index: index,\n fromChainId: LOCAL_CHAINID(),\n from: from,\n toChainId: toChainId,\n to: to,\n gasLimit: gasLimit,\n encoded: encoded\n });\n // hash the message.\n bytes32 msgHash = hash(message);\n // insert msg hash to imt.\n _imt.insert(msgHash);\n // update new imt.root to root storage.\n root = _imt.root();\n\n // emit accepted message event.\n emit MessageAccepted(msgHash, root, message);\n\n // return this message hash.\n return msgHash;\n }\n\n /// @dev Receive messages.\n /// @notice Only message.to's config relayer could relay this message.\n /// @param message Received message info.\n /// @param proof Message proof of this message.\n function _recv(Message calldata message, bytes calldata proof) internal returns (bytes32) {\n // get message.to user config.\n UC memory uc = getAppConfig(message.to);\n // only the config relayer could relay this message.\n require(uc.relayer == msg.sender, \"!auth\");\n\n // hash the message.\n bytes32 msgHash = hash(message);\n // verify message by the config oracle.\n require(IVerifier(uc.oracle).verifyMessageProof(message.fromChainId, msgHash, proof), \"!proof\");\n\n // check destination chain id is correct.\n require(LOCAL_CHAINID() == message.toChainId, \"!toChainId\");\n // check the message is not dispatched.\n require(dones[msgHash] == false, \"done\");\n // set the message is dispatched.\n dones[msgHash] = true;\n\n return msgHash;\n }\n\n /// @dev Fetch the messages count of incremental merkle tree.\n function messageCount() public view returns (uint256) {\n return _imt.count;\n }\n\n /// @dev Fetch the branch of incremental merkle tree.\n function imtBranch() public view returns (bytes32[32] memory) {\n return _imt.branch;\n }\n\n /// @dev Fetch the latest message proof\n function prove() public view returns (bytes32[32] memory) {\n return _imt.prove();\n }\n}\n"},"src/interfaces/IOracle.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./IVerifier.sol\";\n\ninterface IOracle is IVerifier {\n /// @notice Fetch oracle price to relay message root to the destination chain.\n /// @param toChainId The destination chain id.\n /// @param ua The user application which send the message.\n /// @return Oracle price in source native gas.\n function fee(uint256 toChainId, address ua) external view returns (uint256);\n\n /// @notice Assign the relay message root task to oracle maintainer.\n /// @param msgHash Hash of the message.\n function assign(bytes32 msgHash) external payable;\n}\n"},"src/interfaces/IRelayer.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IRelayer {\n /// @notice Fetch relayer price to relay message to the destination chain.\n /// @param toChainId The destination chain id.\n /// @param ua The user application which send the message.\n /// @param gasLimit Gas limit for destination user application used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param params General extensibility for relayer to custom functionality.\n /// @return Relayer price in source native gas.\n function fee(uint256 toChainId, address ua, uint256 gasLimit, bytes calldata encoded, bytes calldata params)\n external\n view\n returns (uint256);\n\n /// @notice Assign the relay message task to relayer maintainer.\n /// @param msgHash Hash of the message.\n /// @param params General extensibility for relayer to custom functionality.\n function assign(bytes32 msgHash, bytes calldata params) external payable;\n}\n"},"src/security/ReentrancyGuard.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nabstract contract ReentrancyGuard {\n // send and receive nonreentrant lock\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n uint256 private _send_state = 1;\n uint256 private _receive_state = 1;\n\n modifier sendNonReentrant() {\n require(_send_state == _NOT_ENTERED, \"!send-reentrancy\");\n _send_state = _ENTERED;\n _;\n _send_state = _NOT_ENTERED;\n }\n\n modifier recvNonReentrant() {\n require(_receive_state == _NOT_ENTERED, \"!recv-reentrancy\");\n _receive_state = _ENTERED;\n _;\n _receive_state = _NOT_ENTERED;\n }\n}\n"},"src/security/ExcessivelySafeCall.sol":{"content":"// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity 0.8.17;\n\n// Inspired: https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/util/ExcessivelySafeCall.sol\n\nlibrary ExcessivelySafeCall {\n uint256 private constant LOW_28_MASK = 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff;\n\n /// @notice Use when you _really_ really _really_ don't trust the called\n /// contract. This prevents the called contract from causing reversion of\n /// the caller in as many ways as we can.\n /// @dev The main difference between this and a solidity low-level call is\n /// that we limit the number of bytes that the callee can cause to be\n /// copied to caller memory. This prevents stupid things like malicious\n /// contracts returning 10,000,000 bytes causing a local OOG when copying\n /// to memory.\n /// @param _target The address to call\n /// @param _gas The amount of gas to forward to the remote contract\n /// @param _value Value in wei to send to the account\n /// @param _maxCopy The maximum number of bytes of returndata to copy\n /// to memory.\n /// @param _calldata The data to send to the remote contract\n /// @return success and returndata, as `.call()`. Returndata is capped to\n /// `_maxCopy` bytes.\n function excessivelySafeCall(address _target, uint256 _gas, uint256 _value, uint16 _maxCopy, bytes memory _calldata)\n internal\n returns (bool, bytes memory)\n {\n // set up for assembly call\n uint256 _toCopy;\n bool _success;\n bytes memory _returnData = new bytes(_maxCopy);\n // dispatch message to recipient\n // by assembly calling \"handle\" function\n // we call via assembly to avoid memcopying a very large returndata\n // returned by a malicious contract\n assembly (\"memory-safe\") {\n _success :=\n call(\n _gas, // gas\n _target, // recipient\n _value, // ether value\n add(_calldata, 0x20), // inloc\n mload(_calldata), // inlen\n 0, // outloc\n 0 // outlen\n )\n // limit our copy to 256 bytes\n _toCopy := returndatasize()\n if gt(_toCopy, _maxCopy) { _toCopy := _maxCopy }\n // Store the length of the copied bytes\n mstore(_returnData, _toCopy)\n // copy the bytes from returndata[0:_toCopy]\n returndatacopy(add(_returnData, 0x20), 0, _toCopy)\n }\n return (_success, _returnData);\n }\n\n /// @notice Use when you _really_ really _really_ don't trust the called\n /// contract. This prevents the called contract from causing reversion of\n /// the caller in as many ways as we can.\n /// @dev The main difference between this and a solidity low-level call is\n /// that we limit the number of bytes that the callee can cause to be\n /// copied to caller memory. This prevents stupid things like malicious\n /// contracts returning 10,000,000 bytes causing a local OOG when copying\n /// to memory.\n /// @param _target The address to call\n /// @param _gas The amount of gas to forward to the remote contract\n /// @param _maxCopy The maximum number of bytes of returndata to copy\n /// to memory.\n /// @param _calldata The data to send to the remote contract\n /// @return success and returndata, as `.call()`. Returndata is capped to\n /// `_maxCopy` bytes.\n function excessivelySafeStaticCall(address _target, uint256 _gas, uint16 _maxCopy, bytes memory _calldata)\n internal\n view\n returns (bool, bytes memory)\n {\n // set up for assembly call\n uint256 _toCopy;\n bool _success;\n bytes memory _returnData = new bytes(_maxCopy);\n // dispatch message to recipient\n // by assembly calling \"handle\" function\n // we call via assembly to avoid memcopying a very large returndata\n // returned by a malicious contract\n assembly (\"memory-safe\") {\n _success :=\n staticcall(\n _gas, // gas\n _target, // recipient\n add(_calldata, 0x20), // inloc\n mload(_calldata), // inlen\n 0, // outloc\n 0 // outlen\n )\n // limit our copy to 256 bytes\n _toCopy := returndatasize()\n if gt(_toCopy, _maxCopy) { _toCopy := _maxCopy }\n // Store the length of the copied bytes\n mstore(_returnData, _toCopy)\n // copy the bytes from returndata[0:_toCopy]\n returndatacopy(add(_returnData, 0x20), 0, _toCopy)\n }\n return (_success, _returnData);\n }\n\n /// @notice Swaps function selectors in encoded contract calls\n /// @dev Allows reuse of encoded calldata for functions with identical\n /// argument types but different names. It simply swaps out the first 4 bytes\n /// for the new selector. This function modifies memory in place, and should\n /// only be used with caution.\n /// @param _newSelector The new 4-byte selector\n /// @param _buf The encoded contract args\n function swapSelector(bytes4 _newSelector, bytes memory _buf) internal pure {\n require(_buf.length >= 4);\n uint256 _mask = LOW_28_MASK;\n assembly (\"memory-safe\") {\n // load the first word of\n let _word := mload(add(_buf, 0x20))\n // mask out the top 4 bytes\n // /x\n _word := and(_word, _mask)\n _word := or(_newSelector, _word)\n mstore(add(_buf, 0x20), _word)\n }\n }\n}\n"},"src/UserConfig.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./Common.sol\";\n\n/// @title UserConfig\n/// @notice User config could select their own relayer and oracle.\n/// The default configuration is used by default.\n/// @dev Only setter could set default user config.\ncontract UserConfig {\n /// @dev Setter address.\n address public setter;\n /// @dev Default user config.\n UC public defaultUC;\n /// @dev ua => uc.\n mapping(address => UC) public ucOf;\n\n /// @dev Notifies an observer that the default user config has updated.\n /// @param oracle Default oracle.\n /// @param relayer Default relayer.\n event DefaultConfigUpdated(address oracle, address relayer);\n /// @dev Notifies an observer that the user application config has updated.\n /// @param ua User application contract address.\n /// @param oracle Oracle which the user application choose.\n /// @param relayer Relayer which the user application choose.\n event AppConfigUpdated(address indexed ua, address oracle, address relayer);\n\n modifier onlySetter() {\n require(msg.sender == setter, \"!auth\");\n _;\n }\n\n constructor(address dao) {\n setter = dao;\n }\n\n /// @dev Change setter.\n /// @notice Only current setter could call.\n /// @param setter_ New setter.\n function changeSetter(address setter_) external onlySetter {\n setter = setter_;\n }\n\n /// @dev Set default user config for all user application.\n /// @notice Only setter could call.\n /// @param oracle Default oracle.\n /// @param relayer Default relayer.\n function setDefaultConfig(address oracle, address relayer) external onlySetter {\n defaultUC = UC(oracle, relayer);\n emit DefaultConfigUpdated(oracle, relayer);\n }\n\n /// @notice Set user application config.\n /// @param oracle Oracle which user application.\n /// @param relayer Relayer which user application choose.\n function setAppConfig(address oracle, address relayer) external {\n ucOf[msg.sender] = UC(oracle, relayer);\n emit AppConfigUpdated(msg.sender, oracle, relayer);\n }\n\n /// @dev Fetch user application config.\n /// @notice If user application has not configured, then the default user config is used.\n /// @param ua User application contract address.\n /// @return user application config.\n function getAppConfig(address ua) public view returns (UC memory) {\n UC memory c = ucOf[ua];\n\n if (c.relayer == address(0x0)) {\n c.relayer = defaultUC.relayer;\n }\n\n if (c.oracle == address(0x0)) {\n c.oracle = defaultUC.oracle;\n }\n\n return c;\n }\n}\n"},"src/interfaces/IVerifier.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IVerifier {\n /// @notice Fetch message root oracle.\n /// @param chainId The destination chain id.\n /// @param blockNumber The block number where the message root is located.\n /// @return Message root in destination chain.\n function merkleRoot(uint256 chainId, uint256 blockNumber) external view returns (bytes32);\n\n /// @notice Verify message proof\n /// @dev Message proof provided by relayer. Oracle should provide message root of\n /// source chain, and verify the merkle proof of the message hash.\n /// @param fromChainId Source chain id.\n /// @param msgHash Hash of the message.\n /// @param proof Merkle proof of the message\n /// @return Result of the message verify.\n function verifyMessageProof(uint256 fromChainId, bytes32 msgHash, bytes calldata proof)\n external\n view\n returns (bool);\n}\n"},"src/imt/IncrementalMerkleTree.sol":{"content":"// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity 0.8.17;\n\n// Inspired: https://github.com/nomad-xyz/monorepo/blob/main/packages/contracts-core/contracts/libs/Merkle.sol\n\n/// @title IncrementalMerkleTree\n/// @author Illusory Systems Inc.\n/// @notice An incremental merkle tree modeled on the eth2 deposit contract.\nlibrary IncrementalMerkleTree {\n uint256 private constant TREE_DEPTH = 32;\n uint256 private constant MAX_LEAVES = 2 ** TREE_DEPTH - 1;\n\n /// @notice Struct representing incremental merkle tree. Contains current\n /// branch and the number of inserted leaves in the tree.\n struct Tree {\n bytes32[TREE_DEPTH] branch;\n uint256 count;\n }\n\n /// @notice Inserts `_node` into merkle tree\n /// @dev Reverts if tree is full\n /// @param _node Element to insert into tree\n function insert(Tree storage _tree, bytes32 _node) internal {\n require(_tree.count < MAX_LEAVES, \"merkle tree full\");\n\n _tree.count += 1;\n uint256 size = _tree.count;\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n if ((size & 1) == 1) {\n _tree.branch[i] = _node;\n return;\n }\n _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n size /= 2;\n }\n // As the loop should always end prematurely with the `return` statement,\n // this code should be unreachable. We assert `false` just to be safe.\n assert(false);\n }\n\n /// @notice Calculates and returns`_tree`'s current root given array of zero\n /// hashes\n /// @param _zeroes Array of zero hashes\n /// @return _current Calculated root of `_tree`\n function rootWithCtx(Tree storage _tree, bytes32[TREE_DEPTH] memory _zeroes)\n internal\n view\n returns (bytes32 _current)\n {\n uint256 _index = _tree.count;\n\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ithBit = (_index >> i) & 0x01;\n bytes32 _next = _tree.branch[i];\n if (_ithBit == 1) {\n _current = keccak256(abi.encodePacked(_next, _current));\n } else {\n _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n }\n }\n }\n\n /// @notice Calculates and returns`_tree`'s current root\n function root(Tree storage _tree) internal view returns (bytes32) {\n return rootWithCtx(_tree, zeroHashes());\n }\n\n /// @notice Returns array of TREE_DEPTH zero hashes\n /// @return _zeroes Array of TREE_DEPTH zero hashes\n function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n _zeroes[0] = Z_0;\n _zeroes[1] = Z_1;\n _zeroes[2] = Z_2;\n _zeroes[3] = Z_3;\n _zeroes[4] = Z_4;\n _zeroes[5] = Z_5;\n _zeroes[6] = Z_6;\n _zeroes[7] = Z_7;\n _zeroes[8] = Z_8;\n _zeroes[9] = Z_9;\n _zeroes[10] = Z_10;\n _zeroes[11] = Z_11;\n _zeroes[12] = Z_12;\n _zeroes[13] = Z_13;\n _zeroes[14] = Z_14;\n _zeroes[15] = Z_15;\n _zeroes[16] = Z_16;\n _zeroes[17] = Z_17;\n _zeroes[18] = Z_18;\n _zeroes[19] = Z_19;\n _zeroes[20] = Z_20;\n _zeroes[21] = Z_21;\n _zeroes[22] = Z_22;\n _zeroes[23] = Z_23;\n _zeroes[24] = Z_24;\n _zeroes[25] = Z_25;\n _zeroes[26] = Z_26;\n _zeroes[27] = Z_27;\n _zeroes[28] = Z_28;\n _zeroes[29] = Z_29;\n _zeroes[30] = Z_30;\n _zeroes[31] = Z_31;\n }\n\n /// @notice Calculates and returns the merkle root for the given leaf\n /// `_item`, a merkle branch, and the index of `_item` in the tree.\n /// @param _item Merkle leaf\n /// @param _branch Merkle proof\n /// @param _index Index of `_item` in tree\n /// @return _current Calculated merkle root\n function branchRoot(bytes32 _item, bytes32[TREE_DEPTH] memory _branch, uint256 _index)\n internal\n pure\n returns (bytes32 _current)\n {\n _current = _item;\n\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ithBit = (_index >> i) & 0x01;\n bytes32 _next = _branch[i];\n if (_ithBit == 1) {\n _current = keccak256(abi.encodePacked(_next, _current));\n } else {\n _current = keccak256(abi.encodePacked(_current, _next));\n }\n }\n }\n\n function prove(Tree storage _tree) internal view returns (bytes32[TREE_DEPTH] memory proof) {\n uint256 _index = _tree.count - 1;\n bytes32[TREE_DEPTH] memory left = _tree.branch;\n bytes32[TREE_DEPTH] memory right = zeroHashes();\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ith_bit = (_index >> i) & 0x01;\n if (_ith_bit == 1) {\n proof[i] = left[i];\n } else {\n proof[i] = right[i];\n }\n }\n }\n\n // keccak256 zero hashes\n bytes32 private constant Z_0 = hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n bytes32 private constant Z_1 = hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n bytes32 private constant Z_2 = hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n bytes32 private constant Z_3 = hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n bytes32 private constant Z_4 = hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n bytes32 private constant Z_5 = hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n bytes32 private constant Z_6 = hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n bytes32 private constant Z_7 = hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n bytes32 private constant Z_8 = hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n bytes32 private constant Z_9 = hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n bytes32 private constant Z_10 = hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n bytes32 private constant Z_11 = hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n bytes32 private constant Z_12 = hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n bytes32 private constant Z_13 = hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n bytes32 private constant Z_14 = hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n bytes32 private constant Z_15 = hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n bytes32 private constant Z_16 = hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n bytes32 private constant Z_17 = hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n bytes32 private constant Z_18 = hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n bytes32 private constant Z_19 = hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n bytes32 private constant Z_20 = hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n bytes32 private constant Z_21 = hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n bytes32 private constant Z_22 = hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n bytes32 private constant Z_23 = hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n bytes32 private constant Z_24 = hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n bytes32 private constant Z_25 = hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n bytes32 private constant Z_26 = hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n bytes32 private constant Z_27 = hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n bytes32 private constant Z_28 = hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n bytes32 private constant Z_29 = hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n bytes32 private constant Z_30 = hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n bytes32 private constant Z_31 = hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n"},"src/Common.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\n/// @dev The block of control information and data for comminicate\n/// between user applications. Messages are the exchange medium\n/// used by channels to send and receive data through cross-chain networks.\n/// A message is sent from a source chain to a destination chain.\n/// @param index The leaf index lives in channel's incremental mekle tree.\n/// @param fromChainId The message source chain id.\n/// @param from User application contract address which send the message.\n/// @param toChainId The message destination chain id.\n/// @param to User application contract address which receive the message.\n/// @param gasLimit Gas limit for destination UA used.\n/// @param encoded The calldata which encoded by ABI Encoding.\nstruct Message {\n address channel;\n uint256 index;\n uint256 fromChainId;\n address from;\n uint256 toChainId;\n address to;\n uint256 gasLimit;\n bytes encoded; /*(abi.encodePacked(SELECTOR, PARAMS))*/\n}\n\n/// @dev User application custom configuration.\n/// @param oracle Oracle contract address.\n/// @param relayer Relayer contract address.\nstruct UC {\n address oracle;\n address relayer;\n}\n\n/// @dev Hash of the message.\nfunction hash(Message memory message) pure returns (bytes32) {\n return keccak256(abi.encode(message));\n}\n"}},"settings":{"remappings":["forge-std/=lib/forge-std/src/","ds-test/=lib/forge-std/lib/ds-test/src/","create3-deploy/=lib/create3-deploy/"],"optimizer":{"enabled":true,"runs":999999},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs"},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata","storageLayout","devdoc","userdoc"]}},"evmVersion":"london","libraries":{}}} diff --git a/script/output/421614/Oracle.v.json b/script/output/421614/Oracle.v.json index 0922c68..8666252 100644 --- a/script/output/421614/Oracle.v.json +++ b/script/output/421614/Oracle.v.json @@ -1 +1 @@ -{"language":"Solidity","sources":{"src/eco/Oracle.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"../Verifier.sol\";\nimport \"../interfaces/IFeedOracle.sol\";\n\ncontract Oracle is Verifier {\n event Assigned(bytes32 indexed msgHash, uint256 fee);\n event SetFee(uint256 indexed chainId, uint256 fee);\n event SetDapi(uint256 indexed chainId, address dapi);\n event SetApproved(address operator, bool approve);\n\n address public immutable PROTOCOL;\n address public owner;\n\n // chainId => price\n mapping(uint256 => uint256) public feeOf;\n // chainId => dapi\n mapping(uint256 => address) public dapiOf;\n mapping(address => bool) public approvedOf;\n\n modifier onlyOwner() {\n require(msg.sender == owner, \"!owner\");\n _;\n }\n\n modifier onlyApproved() {\n require(isApproved(msg.sender), \"!approve\");\n _;\n }\n\n constructor(address dao, address ormp) {\n PROTOCOL = ormp;\n owner = dao;\n }\n\n receive() external payable {}\n\n function changeOwner(address owner_) external onlyOwner {\n owner = owner_;\n }\n\n function isApproved(address operator) public view returns (bool) {\n return approvedOf[operator];\n }\n\n function setApproved(address operator, bool approve) public onlyOwner {\n approvedOf[operator] = approve;\n emit SetApproved(operator, approve);\n }\n\n function withdraw(address to, uint256 amount) external onlyApproved {\n (bool success,) = to.call{value: amount}(\"\");\n require(success, \"!withdraw\");\n }\n\n function setFee(uint256 chainId, uint256 fee_) external onlyApproved {\n feeOf[chainId] = fee_;\n emit SetFee(chainId, fee_);\n }\n\n function setDapi(uint256 chainId, address dapi) external onlyOwner {\n dapiOf[chainId] = dapi;\n emit SetDapi(chainId, dapi);\n }\n\n function fee(uint256 toChainId, address /*ua*/ ) public view returns (uint256) {\n return feeOf[toChainId];\n }\n\n function assign(bytes32 msgHash) external payable {\n require(msg.sender == PROTOCOL, \"!enpoint\");\n emit Assigned(msgHash, msg.value);\n }\n\n function merkleRoot(uint256 chainId, uint256 /*blockNumber*/ ) public view override returns (bytes32) {\n address dapi = dapiOf[chainId];\n return IFeedOracle(dapi).messageRoot();\n }\n}\n"},"src/Verifier.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./interfaces/IVerifier.sol\";\nimport \"./imt/IncrementalMerkleTree.sol\";\n\nabstract contract Verifier is IVerifier {\n /// @notice Message proof.\n /// @param messageIndex Leaf index of the message hash in incremental merkle tree.\n /// @param messageProof Merkle proof of the message hash.\n struct Proof {\n uint256 blockNumber;\n uint256 messageIndex;\n bytes32[32] messageProof;\n }\n\n /// @inheritdoc IVerifier\n function merkleRoot(uint256 chainId, uint256 blockNumber) public view virtual returns (bytes32);\n\n /// @inheritdoc IVerifier\n function verifyMessageProof(uint256 fromChainId, bytes32 msgHash, bytes calldata proof)\n external\n view\n returns (bool)\n {\n // decode proof\n Proof memory p = abi.decode(proof, (Proof));\n\n // fetch message root in block number from chain\n bytes32 imtRootOracle = merkleRoot(fromChainId, p.blockNumber);\n // calculate the expected root based on the proof\n bytes32 imtRootProof = IncrementalMerkleTree.branchRoot(msgHash, p.messageProof, p.messageIndex);\n\n // check oracle's merkle root equal relayer's merkle root\n return imtRootOracle == imtRootProof;\n }\n}\n"},"src/interfaces/IFeedOracle.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IFeedOracle {\n function messageRoot() external view returns (bytes32);\n}\n"},"src/interfaces/IVerifier.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IVerifier {\n /// @notice Fetch message root oracle.\n /// @param chainId The destination chain id.\n /// @param blockNumber The block number where the message root is located.\n /// @return Message root in destination chain.\n function merkleRoot(uint256 chainId, uint256 blockNumber) external view returns (bytes32);\n\n /// @notice Verify message proof\n /// @dev Message proof provided by relayer. Oracle should provide message root of\n /// source chain, and verify the merkle proof of the message hash.\n /// @param fromChainId Source chain id.\n /// @param msgHash Hash of the message.\n /// @param proof Merkle proof of the message\n /// @return Result of the message verify.\n function verifyMessageProof(uint256 fromChainId, bytes32 msgHash, bytes calldata proof)\n external\n view\n returns (bool);\n}\n"},"src/imt/IncrementalMerkleTree.sol":{"content":"// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity 0.8.17;\n\n// Inspired: https://github.com/nomad-xyz/monorepo/blob/main/packages/contracts-core/contracts/libs/Merkle.sol\n\n/// @title IncrementalMerkleTree\n/// @author Illusory Systems Inc.\n/// @notice An incremental merkle tree modeled on the eth2 deposit contract.\nlibrary IncrementalMerkleTree {\n uint256 internal constant TREE_DEPTH = 32;\n uint256 internal constant MAX_LEAVES = 2 ** TREE_DEPTH - 1;\n\n /// @notice Struct representing incremental merkle tree. Contains current\n /// branch and the number of inserted leaves in the tree.\n struct Tree {\n bytes32[TREE_DEPTH] branch;\n uint256 count;\n }\n\n /// @notice Inserts `_node` into merkle tree\n /// @dev Reverts if tree is full\n /// @param _node Element to insert into tree\n function insert(Tree storage _tree, bytes32 _node) internal {\n require(_tree.count < MAX_LEAVES, \"merkle tree full\");\n\n _tree.count += 1;\n uint256 size = _tree.count;\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n if ((size & 1) == 1) {\n _tree.branch[i] = _node;\n return;\n }\n _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n size /= 2;\n }\n // As the loop should always end prematurely with the `return` statement,\n // this code should be unreachable. We assert `false` just to be safe.\n assert(false);\n }\n\n /// @notice Calculates and returns`_tree`'s current root given array of zero\n /// hashes\n /// @param _zeroes Array of zero hashes\n /// @return _current Calculated root of `_tree`\n function rootWithCtx(Tree storage _tree, bytes32[TREE_DEPTH] memory _zeroes)\n internal\n view\n returns (bytes32 _current)\n {\n uint256 _index = _tree.count;\n\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ithBit = (_index >> i) & 0x01;\n bytes32 _next = _tree.branch[i];\n if (_ithBit == 1) {\n _current = keccak256(abi.encodePacked(_next, _current));\n } else {\n _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n }\n }\n }\n\n /// @notice Calculates and returns`_tree`'s current root\n function root(Tree storage _tree) internal view returns (bytes32) {\n return rootWithCtx(_tree, zeroHashes());\n }\n\n /// @notice Returns array of TREE_DEPTH zero hashes\n /// @return _zeroes Array of TREE_DEPTH zero hashes\n function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n _zeroes[0] = Z_0;\n _zeroes[1] = Z_1;\n _zeroes[2] = Z_2;\n _zeroes[3] = Z_3;\n _zeroes[4] = Z_4;\n _zeroes[5] = Z_5;\n _zeroes[6] = Z_6;\n _zeroes[7] = Z_7;\n _zeroes[8] = Z_8;\n _zeroes[9] = Z_9;\n _zeroes[10] = Z_10;\n _zeroes[11] = Z_11;\n _zeroes[12] = Z_12;\n _zeroes[13] = Z_13;\n _zeroes[14] = Z_14;\n _zeroes[15] = Z_15;\n _zeroes[16] = Z_16;\n _zeroes[17] = Z_17;\n _zeroes[18] = Z_18;\n _zeroes[19] = Z_19;\n _zeroes[20] = Z_20;\n _zeroes[21] = Z_21;\n _zeroes[22] = Z_22;\n _zeroes[23] = Z_23;\n _zeroes[24] = Z_24;\n _zeroes[25] = Z_25;\n _zeroes[26] = Z_26;\n _zeroes[27] = Z_27;\n _zeroes[28] = Z_28;\n _zeroes[29] = Z_29;\n _zeroes[30] = Z_30;\n _zeroes[31] = Z_31;\n }\n\n /// @notice Calculates and returns the merkle root for the given leaf\n /// `_item`, a merkle branch, and the index of `_item` in the tree.\n /// @param _item Merkle leaf\n /// @param _branch Merkle proof\n /// @param _index Index of `_item` in tree\n /// @return _current Calculated merkle root\n function branchRoot(bytes32 _item, bytes32[TREE_DEPTH] memory _branch, uint256 _index)\n internal\n pure\n returns (bytes32 _current)\n {\n _current = _item;\n\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ithBit = (_index >> i) & 0x01;\n bytes32 _next = _branch[i];\n if (_ithBit == 1) {\n _current = keccak256(abi.encodePacked(_next, _current));\n } else {\n _current = keccak256(abi.encodePacked(_current, _next));\n }\n }\n }\n\n function prove(Tree storage _tree) internal view returns (bytes32[TREE_DEPTH] memory proof) {\n uint256 _index = _tree.count - 1;\n bytes32[TREE_DEPTH] memory left = _tree.branch;\n bytes32[TREE_DEPTH] memory right = zeroHashes();\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ith_bit = (_index >> i) & 0x01;\n if (_ith_bit == 1) {\n proof[i] = left[i];\n } else {\n proof[i] = right[i];\n }\n }\n }\n\n // keccak256 zero hashes\n bytes32 internal constant Z_0 = hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n bytes32 internal constant Z_1 = hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n bytes32 internal constant Z_2 = hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n bytes32 internal constant Z_3 = hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n bytes32 internal constant Z_4 = hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n bytes32 internal constant Z_5 = hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n bytes32 internal constant Z_6 = hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n bytes32 internal constant Z_7 = hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n bytes32 internal constant Z_8 = hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n bytes32 internal constant Z_9 = hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n bytes32 internal constant Z_10 = hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n bytes32 internal constant Z_11 = hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n bytes32 internal constant Z_12 = hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n bytes32 internal constant Z_13 = hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n bytes32 internal constant Z_14 = hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n bytes32 internal constant Z_15 = hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n bytes32 internal constant Z_16 = hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n bytes32 internal constant Z_17 = hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n bytes32 internal constant Z_18 = hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n bytes32 internal constant Z_19 = hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n bytes32 internal constant Z_20 = hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n bytes32 internal constant Z_21 = hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n bytes32 internal constant Z_22 = hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n bytes32 internal constant Z_23 = hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n bytes32 internal constant Z_24 = hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n bytes32 internal constant Z_25 = hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n bytes32 internal constant Z_26 = hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n bytes32 internal constant Z_27 = hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n bytes32 internal constant Z_28 = hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n bytes32 internal constant Z_29 = hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n bytes32 internal constant Z_30 = hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n bytes32 internal constant Z_31 = hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n"}},"settings":{"remappings":["forge-std/=lib/forge-std/src/","ds-test/=lib/forge-std/lib/ds-test/src/","create3-deploy/=lib/create3-deploy/"],"optimizer":{"enabled":true,"runs":999999},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs"},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata","storageLayout","devdoc","userdoc"]}},"evmVersion":"london","libraries":{}}} +{"language":"Solidity","sources":{"src/eco/Oracle.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"../Verifier.sol\";\nimport \"../interfaces/IFeedOracle.sol\";\n\ncontract Oracle is Verifier {\n event Assigned(bytes32 indexed msgHash, uint256 fee);\n event SetFee(uint256 indexed chainId, uint256 fee);\n event SetDapi(uint256 indexed chainId, address dapi);\n event SetApproved(address operator, bool approve);\n\n address public immutable PROTOCOL;\n\n address public owner;\n // chainId => price\n mapping(uint256 => uint256) public feeOf;\n // chainId => dapi\n mapping(uint256 => address) public dapiOf;\n mapping(address => bool) public approvedOf;\n\n modifier onlyOwner() {\n require(msg.sender == owner, \"!owner\");\n _;\n }\n\n modifier onlyApproved() {\n require(isApproved(msg.sender), \"!approve\");\n _;\n }\n\n constructor(address dao, address ormp) {\n PROTOCOL = ormp;\n owner = dao;\n }\n\n receive() external payable {}\n\n function withdraw(address to, uint256 amount) external onlyApproved {\n (bool success,) = to.call{value: amount}(\"\");\n require(success, \"!withdraw\");\n }\n\n function isApproved(address operator) public view returns (bool) {\n return approvedOf[operator];\n }\n\n function changeOwner(address owner_) external onlyOwner {\n owner = owner_;\n }\n\n function setApproved(address operator, bool approve) external onlyOwner {\n approvedOf[operator] = approve;\n emit SetApproved(operator, approve);\n }\n\n function setFee(uint256 chainId, uint256 fee_) external onlyApproved {\n feeOf[chainId] = fee_;\n emit SetFee(chainId, fee_);\n }\n\n function setDapi(uint256 chainId, address dapi) external onlyOwner {\n dapiOf[chainId] = dapi;\n emit SetDapi(chainId, dapi);\n }\n\n function fee(uint256 toChainId, address /*ua*/ ) public view returns (uint256) {\n return feeOf[toChainId];\n }\n\n function assign(bytes32 msgHash) external payable {\n require(msg.sender == PROTOCOL, \"!auth\");\n emit Assigned(msgHash, msg.value);\n }\n\n function merkleRoot(uint256 chainId, uint256 /*blockNumber*/ ) public view override returns (bytes32) {\n address dapi = dapiOf[chainId];\n return IFeedOracle(dapi).messageRoot();\n }\n}\n"},"src/Verifier.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./interfaces/IVerifier.sol\";\nimport \"./imt/IncrementalMerkleTree.sol\";\n\nabstract contract Verifier is IVerifier {\n /// @notice Message proof.\n /// @param blockNumber The block number corresponding to the proof.\n /// @param messageIndex Leaf index of the message hash in incremental merkle tree.\n /// @param messageProof Merkle proof of the message hash.\n struct Proof {\n uint256 blockNumber;\n uint256 messageIndex;\n bytes32[32] messageProof;\n }\n\n /// @inheritdoc IVerifier\n function merkleRoot(uint256 chainId, uint256 blockNumber) public view virtual returns (bytes32);\n\n /// @inheritdoc IVerifier\n function verifyMessageProof(uint256 fromChainId, bytes32 msgHash, bytes calldata proof)\n external\n view\n returns (bool)\n {\n // decode proof\n Proof memory p = abi.decode(proof, (Proof));\n\n // fetch message root in block number from chain\n bytes32 imtRootOracle = merkleRoot(fromChainId, p.blockNumber);\n // calculate the expected root based on the proof\n bytes32 imtRootProof = IncrementalMerkleTree.branchRoot(msgHash, p.messageProof, p.messageIndex);\n\n // check oracle's merkle root equal relayer's merkle root\n return imtRootOracle == imtRootProof;\n }\n}\n"},"src/interfaces/IFeedOracle.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IFeedOracle {\n function messageRoot() external view returns (bytes32);\n}\n"},"src/interfaces/IVerifier.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IVerifier {\n /// @notice Fetch message root oracle.\n /// @param chainId The destination chain id.\n /// @param blockNumber The block number where the message root is located.\n /// @return Message root in destination chain.\n function merkleRoot(uint256 chainId, uint256 blockNumber) external view returns (bytes32);\n\n /// @notice Verify message proof\n /// @dev Message proof provided by relayer. Oracle should provide message root of\n /// source chain, and verify the merkle proof of the message hash.\n /// @param fromChainId Source chain id.\n /// @param msgHash Hash of the message.\n /// @param proof Merkle proof of the message\n /// @return Result of the message verify.\n function verifyMessageProof(uint256 fromChainId, bytes32 msgHash, bytes calldata proof)\n external\n view\n returns (bool);\n}\n"},"src/imt/IncrementalMerkleTree.sol":{"content":"// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity 0.8.17;\n\n// Inspired: https://github.com/nomad-xyz/monorepo/blob/main/packages/contracts-core/contracts/libs/Merkle.sol\n\n/// @title IncrementalMerkleTree\n/// @author Illusory Systems Inc.\n/// @notice An incremental merkle tree modeled on the eth2 deposit contract.\nlibrary IncrementalMerkleTree {\n uint256 private constant TREE_DEPTH = 32;\n uint256 private constant MAX_LEAVES = 2 ** TREE_DEPTH - 1;\n\n /// @notice Struct representing incremental merkle tree. Contains current\n /// branch and the number of inserted leaves in the tree.\n struct Tree {\n bytes32[TREE_DEPTH] branch;\n uint256 count;\n }\n\n /// @notice Inserts `_node` into merkle tree\n /// @dev Reverts if tree is full\n /// @param _node Element to insert into tree\n function insert(Tree storage _tree, bytes32 _node) internal {\n require(_tree.count < MAX_LEAVES, \"merkle tree full\");\n\n _tree.count += 1;\n uint256 size = _tree.count;\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n if ((size & 1) == 1) {\n _tree.branch[i] = _node;\n return;\n }\n _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n size /= 2;\n }\n // As the loop should always end prematurely with the `return` statement,\n // this code should be unreachable. We assert `false` just to be safe.\n assert(false);\n }\n\n /// @notice Calculates and returns`_tree`'s current root given array of zero\n /// hashes\n /// @param _zeroes Array of zero hashes\n /// @return _current Calculated root of `_tree`\n function rootWithCtx(Tree storage _tree, bytes32[TREE_DEPTH] memory _zeroes)\n internal\n view\n returns (bytes32 _current)\n {\n uint256 _index = _tree.count;\n\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ithBit = (_index >> i) & 0x01;\n bytes32 _next = _tree.branch[i];\n if (_ithBit == 1) {\n _current = keccak256(abi.encodePacked(_next, _current));\n } else {\n _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n }\n }\n }\n\n /// @notice Calculates and returns`_tree`'s current root\n function root(Tree storage _tree) internal view returns (bytes32) {\n return rootWithCtx(_tree, zeroHashes());\n }\n\n /// @notice Returns array of TREE_DEPTH zero hashes\n /// @return _zeroes Array of TREE_DEPTH zero hashes\n function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n _zeroes[0] = Z_0;\n _zeroes[1] = Z_1;\n _zeroes[2] = Z_2;\n _zeroes[3] = Z_3;\n _zeroes[4] = Z_4;\n _zeroes[5] = Z_5;\n _zeroes[6] = Z_6;\n _zeroes[7] = Z_7;\n _zeroes[8] = Z_8;\n _zeroes[9] = Z_9;\n _zeroes[10] = Z_10;\n _zeroes[11] = Z_11;\n _zeroes[12] = Z_12;\n _zeroes[13] = Z_13;\n _zeroes[14] = Z_14;\n _zeroes[15] = Z_15;\n _zeroes[16] = Z_16;\n _zeroes[17] = Z_17;\n _zeroes[18] = Z_18;\n _zeroes[19] = Z_19;\n _zeroes[20] = Z_20;\n _zeroes[21] = Z_21;\n _zeroes[22] = Z_22;\n _zeroes[23] = Z_23;\n _zeroes[24] = Z_24;\n _zeroes[25] = Z_25;\n _zeroes[26] = Z_26;\n _zeroes[27] = Z_27;\n _zeroes[28] = Z_28;\n _zeroes[29] = Z_29;\n _zeroes[30] = Z_30;\n _zeroes[31] = Z_31;\n }\n\n /// @notice Calculates and returns the merkle root for the given leaf\n /// `_item`, a merkle branch, and the index of `_item` in the tree.\n /// @param _item Merkle leaf\n /// @param _branch Merkle proof\n /// @param _index Index of `_item` in tree\n /// @return _current Calculated merkle root\n function branchRoot(bytes32 _item, bytes32[TREE_DEPTH] memory _branch, uint256 _index)\n internal\n pure\n returns (bytes32 _current)\n {\n _current = _item;\n\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ithBit = (_index >> i) & 0x01;\n bytes32 _next = _branch[i];\n if (_ithBit == 1) {\n _current = keccak256(abi.encodePacked(_next, _current));\n } else {\n _current = keccak256(abi.encodePacked(_current, _next));\n }\n }\n }\n\n function prove(Tree storage _tree) internal view returns (bytes32[TREE_DEPTH] memory proof) {\n uint256 _index = _tree.count - 1;\n bytes32[TREE_DEPTH] memory left = _tree.branch;\n bytes32[TREE_DEPTH] memory right = zeroHashes();\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ith_bit = (_index >> i) & 0x01;\n if (_ith_bit == 1) {\n proof[i] = left[i];\n } else {\n proof[i] = right[i];\n }\n }\n }\n\n // keccak256 zero hashes\n bytes32 private constant Z_0 = hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n bytes32 private constant Z_1 = hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n bytes32 private constant Z_2 = hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n bytes32 private constant Z_3 = hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n bytes32 private constant Z_4 = hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n bytes32 private constant Z_5 = hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n bytes32 private constant Z_6 = hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n bytes32 private constant Z_7 = hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n bytes32 private constant Z_8 = hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n bytes32 private constant Z_9 = hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n bytes32 private constant Z_10 = hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n bytes32 private constant Z_11 = hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n bytes32 private constant Z_12 = hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n bytes32 private constant Z_13 = hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n bytes32 private constant Z_14 = hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n bytes32 private constant Z_15 = hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n bytes32 private constant Z_16 = hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n bytes32 private constant Z_17 = hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n bytes32 private constant Z_18 = hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n bytes32 private constant Z_19 = hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n bytes32 private constant Z_20 = hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n bytes32 private constant Z_21 = hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n bytes32 private constant Z_22 = hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n bytes32 private constant Z_23 = hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n bytes32 private constant Z_24 = hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n bytes32 private constant Z_25 = hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n bytes32 private constant Z_26 = hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n bytes32 private constant Z_27 = hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n bytes32 private constant Z_28 = hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n bytes32 private constant Z_29 = hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n bytes32 private constant Z_30 = hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n bytes32 private constant Z_31 = hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n"}},"settings":{"remappings":["forge-std/=lib/forge-std/src/","ds-test/=lib/forge-std/lib/ds-test/src/","create3-deploy/=lib/create3-deploy/"],"optimizer":{"enabled":true,"runs":999999},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs"},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata","storageLayout","devdoc","userdoc"]}},"evmVersion":"london","libraries":{}}} diff --git a/script/output/421614/Relayer.v.json b/script/output/421614/Relayer.v.json index 3276703..9e64573 100644 --- a/script/output/421614/Relayer.v.json +++ b/script/output/421614/Relayer.v.json @@ -1 +1 @@ -{"language":"Solidity","sources":{"src/eco/Relayer.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"../interfaces/IORMP.sol\";\n\ncontract Relayer {\n event Assigned(bytes32 indexed msgHash, uint256 fee, bytes params, bytes32[32] proof);\n event SetDstPrice(uint256 indexed chainId, uint128 dstPriceRatio, uint128 dstGasPriceInWei);\n event SetDstConfig(uint256 indexed chainId, uint64 baseGas, uint64 gasPerByte);\n event SetApproved(address operator, bool approve);\n\n struct DstPrice {\n uint128 dstPriceRatio; // dstPrice / localPrice * 10^10\n uint128 dstGasPriceInWei;\n }\n\n struct DstConfig {\n uint64 baseGas;\n uint64 gasPerByte;\n }\n\n address public immutable PROTOCOL;\n address public owner;\n\n // chainId => price\n mapping(uint256 => DstPrice) public priceOf;\n mapping(uint256 => DstConfig) public configOf;\n mapping(address => bool) public approvedOf;\n\n modifier onlyOwner() {\n require(msg.sender == owner, \"!owner\");\n _;\n }\n\n modifier onlyApproved() {\n require(isApproved(msg.sender), \"!approve\");\n _;\n }\n\n constructor(address dao, address ormp) {\n PROTOCOL = ormp;\n owner = dao;\n }\n\n receive() external payable {}\n\n function changeOwner(address owner_) external onlyOwner {\n owner = owner_;\n }\n\n function isApproved(address operator) public view returns (bool) {\n return approvedOf[operator];\n }\n\n function setApproved(address operator, bool approve) public onlyOwner {\n approvedOf[operator] = approve;\n emit SetApproved(operator, approve);\n }\n\n function setDstPrice(uint256 chainId, uint128 dstPriceRatio, uint128 dstGasPriceInWei) external onlyApproved {\n priceOf[chainId] = DstPrice(dstPriceRatio, dstGasPriceInWei);\n emit SetDstPrice(chainId, dstPriceRatio, dstGasPriceInWei);\n }\n\n function setDstConfig(uint256 chainId, uint64 baseGas, uint64 gasPerByte) external onlyApproved {\n configOf[chainId] = DstConfig(baseGas, gasPerByte);\n emit SetDstConfig(chainId, baseGas, gasPerByte);\n }\n\n function withdraw(address to, uint256 amount) external onlyApproved {\n (bool success,) = to.call{value: amount}(\"\");\n require(success, \"!withdraw\");\n }\n\n // extraGas = gasLimit\n function fee(\n uint256 toChainId,\n address, /*ua*/\n uint256 gasLimit,\n bytes calldata encoded,\n bytes calldata /*params*/\n ) public view returns (uint256) {\n uint256 size = encoded.length;\n uint256 extraGas = gasLimit;\n DstPrice memory p = priceOf[toChainId];\n DstConfig memory c = configOf[toChainId];\n\n require(c.baseGas != 0, \"!baseGas\");\n // remoteToken = dstGasPriceInWei * (baseGas + extraGas)\n uint256 remoteToken = p.dstGasPriceInWei * (c.baseGas + extraGas);\n // dstPriceRatio = dstPrice / localPrice * 10^10\n // sourceToken = RemoteToken * dstPriceRatio\n uint256 sourceToken = remoteToken * p.dstPriceRatio / (10 ** 10);\n uint256 payloadToken = c.gasPerByte * size * p.dstGasPriceInWei * p.dstPriceRatio / (10 ** 10);\n return sourceToken + payloadToken;\n }\n\n function assign(bytes32 msgHash, bytes calldata params) external payable {\n require(msg.sender == PROTOCOL, \"!ormp\");\n emit Assigned(msgHash, msg.value, params, IORMP(PROTOCOL).prove());\n }\n\n function relay(Message calldata message, bytes calldata proof) external onlyApproved {\n IORMP(PROTOCOL).recv(message, proof);\n }\n}\n"},"src/interfaces/IORMP.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"../Common.sol\";\n\ninterface IORMP {\n /// @dev Send a cross-chain message over the endpoint.\n /// @notice follow https://eips.ethereum.org/EIPS/eip-5750\n /// @param toChainId The Message destination chain id.\n /// @param to User application contract address which receive the message.\n /// @param gasLimit Gas limit for UA used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param refund Return extra fee to refund address.\n /// @param params General extensibility for relayer to custom functionality.\n /// @return Return the hash of the message as message id.\n function send(\n uint256 toChainId,\n address to,\n uint256 gasLimit,\n bytes calldata encoded,\n address refund,\n bytes calldata params\n ) external payable returns (bytes32);\n\n /// @notice Get a quote in source native gas, for the amount that send() requires to pay for message delivery.\n /// @param toChainId The Message destination chain id.\n // @param ua User application contract address which send the message.\n /// @param gasLimit Gas limit for UA used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param params General extensibility for relayer to custom functionality.\n function fee(uint256 toChainId, address ua, uint256 gasLimit, bytes calldata encoded, bytes calldata params)\n external\n view\n returns (uint256);\n\n /// @dev Recv verified message and dispatch to destination user application address.\n /// @param message Verified receive message info.\n /// @param proof Message proof of this message.\n /// @return dispatchResult Result of the message dispatch.\n function recv(Message calldata message, bytes calldata proof) external returns (bool dispatchResult);\n\n function prove() external view returns (bytes32[32] memory);\n\n /// @dev Fetch user application config.\n /// @notice If user application has not configured, then the default config is used.\n /// @param ua User application contract address.\n /// @return user application config.\n function getAppConfig(address ua) external view returns (Config memory);\n\n /// @notice Set user application config.\n /// @param oracle Oracle which user application choose.\n /// @param relayer Relayer which user application choose.\n function setAppConfig(address oracle, address relayer) external;\n\n function setDefaultConfig(address oracle, address relayer) external;\n function defaultConfig() external view returns (Config memory);\n function changeSetter(address setter_) external;\n}\n"},"src/Common.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\n/// @dev The block of control information and data for comminicate\n/// between user applications. Messages are the exchange medium\n/// used by channels to send and receive data through cross-chain networks.\n/// A message is sent from a source chain to a destination chain.\n/// @param index The leaf index lives in channel's incremental mekle tree.\n/// @param fromChainId The message source chain id.\n/// @param from User application contract address which send the message.\n/// @param toChainId The Message destination chain id.\n/// @param to User application contract address which receive the message.\n/// @param gasLimit Gas limit for UA used.\n/// @param encoded The calldata which encoded by ABI Encoding.\nstruct Message {\n address channel;\n uint256 index;\n uint256 fromChainId;\n address from;\n uint256 toChainId;\n address to;\n uint256 gasLimit;\n bytes encoded; /*(abi.encodePacked(SELECTOR, PARAMS))*/\n}\n\n/// @dev User application custom configuration.\n/// @param oracle Oracle contract address.\n/// @param relayer Relayer contract address.\nstruct Config {\n address oracle;\n address relayer;\n}\n\n/// @dev Hash of the message.\nfunction hash(Message memory message) pure returns (bytes32) {\n return keccak256(abi.encode(message));\n}\n"}},"settings":{"remappings":["forge-std/=lib/forge-std/src/","ds-test/=lib/forge-std/lib/ds-test/src/","create3-deploy/=lib/create3-deploy/"],"optimizer":{"enabled":true,"runs":999999},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs"},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata","storageLayout","devdoc","userdoc"]}},"evmVersion":"london","libraries":{}}} +{"language":"Solidity","sources":{"src/eco/Relayer.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"../interfaces/IORMP.sol\";\n\ncontract Relayer {\n event Assigned(bytes32 indexed msgHash, uint256 fee, bytes params, bytes32[32] proof);\n event SetDstPrice(uint256 indexed chainId, uint128 dstPriceRatio, uint128 dstGasPriceInWei);\n event SetDstConfig(uint256 indexed chainId, uint64 baseGas, uint64 gasPerByte);\n event SetApproved(address operator, bool approve);\n\n struct DstPrice {\n uint128 dstPriceRatio; // dstPrice / localPrice * 10^10\n uint128 dstGasPriceInWei;\n }\n\n struct DstConfig {\n uint64 baseGas;\n uint64 gasPerByte;\n }\n\n address public immutable PROTOCOL;\n\n address public owner;\n // chainId => price\n mapping(uint256 => DstPrice) public priceOf;\n mapping(uint256 => DstConfig) public configOf;\n mapping(address => bool) public approvedOf;\n\n modifier onlyOwner() {\n require(msg.sender == owner, \"!owner\");\n _;\n }\n\n modifier onlyApproved() {\n require(isApproved(msg.sender), \"!approve\");\n _;\n }\n\n constructor(address dao, address ormp) {\n PROTOCOL = ormp;\n owner = dao;\n }\n\n receive() external payable {}\n\n function withdraw(address to, uint256 amount) external onlyApproved {\n (bool success,) = to.call{value: amount}(\"\");\n require(success, \"!withdraw\");\n }\n\n function isApproved(address operator) public view returns (bool) {\n return approvedOf[operator];\n }\n\n function changeOwner(address owner_) external onlyOwner {\n owner = owner_;\n }\n\n function setApproved(address operator, bool approve) public onlyOwner {\n approvedOf[operator] = approve;\n emit SetApproved(operator, approve);\n }\n\n function setDstPrice(uint256 chainId, uint128 dstPriceRatio, uint128 dstGasPriceInWei) external onlyApproved {\n priceOf[chainId] = DstPrice(dstPriceRatio, dstGasPriceInWei);\n emit SetDstPrice(chainId, dstPriceRatio, dstGasPriceInWei);\n }\n\n function setDstConfig(uint256 chainId, uint64 baseGas, uint64 gasPerByte) external onlyApproved {\n configOf[chainId] = DstConfig(baseGas, gasPerByte);\n emit SetDstConfig(chainId, baseGas, gasPerByte);\n }\n\n // extraGas = gasLimit\n function fee(\n uint256 toChainId,\n address, /*ua*/\n uint256 gasLimit,\n bytes calldata encoded,\n bytes calldata /*params*/\n ) public view returns (uint256) {\n uint256 size = encoded.length;\n uint256 extraGas = gasLimit;\n DstPrice memory p = priceOf[toChainId];\n DstConfig memory c = configOf[toChainId];\n\n require(c.baseGas != 0, \"!baseGas\");\n // remoteToken = dstGasPriceInWei * (baseGas + extraGas)\n uint256 remoteToken = p.dstGasPriceInWei * (c.baseGas + extraGas);\n // dstPriceRatio = dstPrice / localPrice * 10^10\n // sourceToken = RemoteToken * dstPriceRatio\n uint256 sourceToken = remoteToken * p.dstPriceRatio / (10 ** 10);\n uint256 payloadToken = c.gasPerByte * size * p.dstGasPriceInWei * p.dstPriceRatio / (10 ** 10);\n return sourceToken + payloadToken;\n }\n\n function assign(bytes32 msgHash, bytes calldata params) external payable {\n require(msg.sender == PROTOCOL, \"!ormp\");\n emit Assigned(msgHash, msg.value, params, IORMP(PROTOCOL).prove());\n }\n\n function relay(Message calldata message, bytes calldata proof) external onlyApproved {\n IORMP(PROTOCOL).recv(message, proof);\n }\n}\n"},"src/interfaces/IORMP.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"../Common.sol\";\n\ninterface IORMP {\n /// @dev Send a cross-chain message over the endpoint.\n /// @notice follow https://eips.ethereum.org/EIPS/eip-5750\n /// @param toChainId The Message destination chain id.\n /// @param to User application contract address which receive the message.\n /// @param gasLimit Gas limit for destination user application used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param refund Return extra fee to refund address.\n /// @param params General extensibility for relayer to custom functionality.\n /// @return Return the hash of the message as message id.\n function send(\n uint256 toChainId,\n address to,\n uint256 gasLimit,\n bytes calldata encoded,\n address refund,\n bytes calldata params\n ) external payable returns (bytes32);\n\n /// @notice Get a quote in source native gas, for the amount that send() requires to pay for message delivery.\n /// @param toChainId The Message destination chain id.\n // @param ua User application contract address which send the message.\n /// @param gasLimit Gas limit for destination user application used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param params General extensibility for relayer to custom functionality.\n function fee(uint256 toChainId, address ua, uint256 gasLimit, bytes calldata encoded, bytes calldata params)\n external\n view\n returns (uint256);\n\n /// @dev Recv verified message and dispatch to destination user application address.\n /// @param message Verified receive message info.\n /// @param proof Message proof of this message.\n /// @return dispatchResult Result of the message dispatch.\n function recv(Message calldata message, bytes calldata proof) external returns (bool dispatchResult);\n\n function prove() external view returns (bytes32[32] memory);\n\n /// @dev Fetch user application config.\n /// @notice If user application has not configured, then the default config is used.\n /// @param ua User application contract address.\n /// @return user application config.\n function getAppConfig(address ua) external view returns (UC memory);\n\n /// @notice Set user application config.\n /// @param oracle Oracle which user application choose.\n /// @param relayer Relayer which user application choose.\n function setAppConfig(address oracle, address relayer) external;\n\n function defaultUC() external view returns (UC memory);\n}\n"},"src/Common.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\n/// @dev The block of control information and data for comminicate\n/// between user applications. Messages are the exchange medium\n/// used by channels to send and receive data through cross-chain networks.\n/// A message is sent from a source chain to a destination chain.\n/// @param index The leaf index lives in channel's incremental mekle tree.\n/// @param fromChainId The message source chain id.\n/// @param from User application contract address which send the message.\n/// @param toChainId The message destination chain id.\n/// @param to User application contract address which receive the message.\n/// @param gasLimit Gas limit for destination UA used.\n/// @param encoded The calldata which encoded by ABI Encoding.\nstruct Message {\n address channel;\n uint256 index;\n uint256 fromChainId;\n address from;\n uint256 toChainId;\n address to;\n uint256 gasLimit;\n bytes encoded; /*(abi.encodePacked(SELECTOR, PARAMS))*/\n}\n\n/// @dev User application custom configuration.\n/// @param oracle Oracle contract address.\n/// @param relayer Relayer contract address.\nstruct UC {\n address oracle;\n address relayer;\n}\n\n/// @dev Hash of the message.\nfunction hash(Message memory message) pure returns (bytes32) {\n return keccak256(abi.encode(message));\n}\n"}},"settings":{"remappings":["forge-std/=lib/forge-std/src/","ds-test/=lib/forge-std/lib/ds-test/src/","create3-deploy/=lib/create3-deploy/"],"optimizer":{"enabled":true,"runs":999999},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs"},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata","storageLayout","devdoc","userdoc"]}},"evmVersion":"london","libraries":{}}} diff --git a/script/output/421614/deploy.a-latest.json b/script/output/421614/deploy.a-latest.json index 1be82e2..b03fd23 100644 --- a/script/output/421614/deploy.a-latest.json +++ b/script/output/421614/deploy.a-latest.json @@ -1,6 +1,6 @@ { "DAO": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", - "ORACLE": "0x00BD655DDfA7aFeF4BB109FE1F938724527B49D8", - "ORMP": "0x009D223Aad560e72282db9c0438Ef1ef2bf7703D", - "RELAYER": "0x003605167cd4C36063a7B63e604497e623Bb8B10" + "ORACLE": "0x0000000000ba03146Cc235509E802873D418a6bc", + "ORMP": "0x00000000001523057a05d6293C1e5171eE33eE0A", + "RELAYER": "0x0000000000808fE9bDCc1d180EfbF5C53552a6b1" } diff --git a/script/output/44/ORMP.v.json b/script/output/44/ORMP.v.json index 002aa97..7de0eb2 100644 --- a/script/output/44/ORMP.v.json +++ b/script/output/44/ORMP.v.json @@ -1 +1 @@ -{"language": "Solidity", "sources": {"src/ORMP.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./Channel.sol\";\nimport \"./interfaces/IOracle.sol\";\nimport \"./interfaces/IRelayer.sol\";\nimport \"./security/ReentrancyGuard.sol\";\nimport \"./security/ExcessivelySafeCall.sol\";\n\n/// @title ORMP\n/// @notice An endpoint is a type of network node for cross-chain communication.\n/// It is an interface exposed by a communication channel.\n/// @dev An endpoint is associated with an immutable channel and user configuration.\ncontract ORMP is ReentrancyGuard, Channel {\n using ExcessivelySafeCall for address;\n\n constructor(address dao) Channel(dao) {}\n\n /// @dev Send a cross-chain message over the endpoint.\n /// @notice follow https://eips.ethereum.org/EIPS/eip-5750\n /// @param toChainId The Message destination chain id.\n /// @param to User application contract address which receive the message.\n /// @param gasLimit Gas limit for UA used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param refund Return extra fee to refund address.\n /// @param params General extensibility for relayer to custom functionality.\n function send(\n uint256 toChainId,\n address to,\n uint256 gasLimit,\n bytes calldata encoded,\n address refund,\n bytes calldata params\n ) external payable sendNonReentrant returns (bytes32) {\n // user application address.\n address ua = msg.sender;\n // send message by channel, return the hash of the message as id.\n bytes32 msgHash = _send(ua, toChainId, to, gasLimit, encoded);\n\n // handle fee\n _handleFee(ua, refund, msgHash, toChainId, gasLimit, encoded, params);\n\n return msgHash;\n }\n\n function _handleFee(\n address ua,\n address refund,\n bytes32 msgHash,\n uint256 toChainId,\n uint256 gasLimit,\n bytes calldata encoded,\n bytes calldata params\n ) internal {\n // fetch user application's config.\n Config memory uaConfig = getAppConfig(ua);\n // handle relayer fee\n uint256 relayerFee = _handleRelayer(uaConfig.relayer, msgHash, toChainId, ua, gasLimit, encoded, params);\n // handle oracle fee\n uint256 oracleFee = _handleOracle(uaConfig.oracle, msgHash, toChainId, ua);\n\n // refund\n if (msg.value > relayerFee + oracleFee) {\n uint256 refundFee = msg.value - (relayerFee + oracleFee);\n (bool success,) = refund.call{value: refundFee}(\"\");\n require(success, \"!refund\");\n }\n }\n\n /// @notice Get a quote in source native gas, for the amount that send() requires to pay for message delivery.\n /// @param toChainId The Message destination chain id.\n // @param ua User application contract address which send the message.\n /// @param gasLimit Gas limit for UA used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param params General extensibility for relayer to custom functionality.\n function fee(uint256 toChainId, address ua, uint256 gasLimit, bytes calldata encoded, bytes calldata params)\n external\n view\n returns (uint256)\n {\n Config memory uaConfig = getAppConfig(ua);\n uint256 relayerFee = IRelayer(uaConfig.relayer).fee(toChainId, ua, gasLimit, encoded, params);\n uint256 oracleFee = IOracle(uaConfig.oracle).fee(toChainId, ua);\n return relayerFee + oracleFee;\n }\n\n function _handleRelayer(\n address relayer,\n bytes32 msgHash,\n uint256 toChainId,\n address ua,\n uint256 gasLimit,\n bytes calldata encoded,\n bytes calldata params\n ) internal returns (uint256) {\n uint256 relayerFee = IRelayer(relayer).fee(toChainId, ua, gasLimit, encoded, params);\n IRelayer(relayer).assign{value: relayerFee}(msgHash, params);\n return relayerFee;\n }\n\n function _handleOracle(address oracle, bytes32 msgHash, uint256 toChainId, address ua) internal returns (uint256) {\n uint256 oracleFee = IOracle(oracle).fee(toChainId, ua);\n IOracle(oracle).assign{value: oracleFee}(msgHash);\n return oracleFee;\n }\n\n /// @dev Recv verified message from Channel and dispatch to destination user application address.\n /// @notice Only channel could call this function.\n /// @param message Verified receive message info.\n /// @param proof Message proof of this message.\n /// @return dispatchResult Result of the message dispatch.\n function recv(Message calldata message, bytes calldata proof)\n external\n payable\n recvNonReentrant\n returns (bool dispatchResult)\n {\n bytes32 msgHash = _recv(message, proof);\n dispatchResult = _dispatch(message, msgHash);\n // emit dispatched message event.\n emit MessageDispatched(msgHash, dispatchResult);\n }\n\n /// @dev Dispatch the cross chain message.\n function _dispatch(Message memory message, bytes32 msgHash) private returns (bool dispatchResult) {\n // Deliver the message to user application contract address.\n (dispatchResult,) = message.to.excessivelySafeCall(\n message.gasLimit,\n msg.value,\n 0,\n abi.encodePacked(message.encoded, msgHash, message.fromChainId, message.from)\n );\n }\n}\n", "keccak256": "0x5046e9a2ae66dabaca7f94bc2a032378f49f3eac0141f379e48f650769a36541"}, "src/Channel.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./UserConfig.sol\";\nimport \"./interfaces/IVerifier.sol\";\nimport \"./imt/IncrementalMerkleTree.sol\";\n\n/// @title Channel\n/// @notice A channel is a logical connection over cross-chain network.\n/// It used for cross-chain message transfer.\n/// - Accepts messages to be dispatched to remote chains,\n/// constructs a Merkle tree of the messages.\n/// - Dispatches verified messages from source chains.\n/// @dev Messages live in an incremental merkle tree (imt)\n/// > A Merkle tree is a binary and complete tree decorated with\n/// > the Merkle (hash) attribute.\ncontract Channel is UserConfig {\n using IncrementalMerkleTree for IncrementalMerkleTree.Tree;\n\n /// @dev Incremental merkle tree root which all message hashes live in leafs.\n bytes32 public root;\n /// @dev Incremental merkle tree.\n IncrementalMerkleTree.Tree private imt;\n /// @dev msgHash => isDispathed.\n mapping(bytes32 => bool) public dones;\n /// @dev Self contract address cache.\n address private immutable _self = address(this);\n\n /// @dev Notifies an observer that the message has been accepted.\n /// @param msgHash Hash of the message.\n /// @param root New incremental merkle tree root after a new message inserted.\n /// @param message Accepted message info.\n event MessageAccepted(bytes32 indexed msgHash, bytes32 root, Message message);\n /// @dev Notifies an observer that the message has been dispatched.\n /// @param msgHash Hash of the message.\n /// @param dispatchResult The message dispatch result.\n event MessageDispatched(bytes32 indexed msgHash, bool dispatchResult);\n\n /// @dev Init code.\n constructor(address dao) UserConfig(dao) {\n // init with empty tree\n root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757;\n }\n\n /// @dev Fetch local chain id.\n /// @return chainId Local chain id.\n function LOCAL_CHAINID() public view returns (uint256 chainId) {\n assembly {\n chainId := chainid()\n }\n }\n\n /// @dev Send message.\n /// @param from User application contract address which send the message.\n /// @param toChainId The Message destination chain id.\n /// @param to User application contract address which receive the message.\n /// @param gasLimit Gas limit for UA used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n function _send(address from, uint256 toChainId, address to, uint256 gasLimit, bytes calldata encoded)\n internal\n returns (bytes32)\n {\n // only cross-chain message\n require(toChainId != LOCAL_CHAINID(), \"!cross-chain\");\n // get this message leaf index.\n uint256 index = messageCount();\n // constuct message object.\n Message memory message = Message({\n channel: _self,\n index: index,\n fromChainId: LOCAL_CHAINID(),\n from: from,\n toChainId: toChainId,\n to: to,\n gasLimit: gasLimit,\n encoded: encoded\n });\n // hash the message.\n bytes32 msgHash = hash(message);\n // insert msg hash to imt.\n imt.insert(msgHash);\n // update new imt.root to root storage.\n root = imt.root();\n\n // emit accepted message event.\n emit MessageAccepted(msgHash, root, message);\n\n // return this message hash.\n return msgHash;\n }\n\n /// @dev Receive messages.\n /// @notice Only message.to's config relayer could relayer this message.\n /// @param message Received message info.\n /// @param proof Message proof of this message.\n function _recv(Message calldata message, bytes calldata proof) internal returns (bytes32) {\n // get message.to user config.\n Config memory uaConfig = getAppConfig(message.to);\n // only the config relayer could relay this message.\n require(uaConfig.relayer == msg.sender, \"!auth\");\n\n // hash the message.\n bytes32 msgHash = hash(message);\n // verify message by the config oracle.\n require(IVerifier(uaConfig.oracle).verifyMessageProof(message.fromChainId, msgHash, proof), \"!proof\");\n\n // check destination chain id is correct.\n require(LOCAL_CHAINID() == message.toChainId, \"!toChainId\");\n // check the message is not dispatched.\n require(dones[msgHash] == false, \"done\");\n // set the message is dispatched.\n dones[msgHash] = true;\n\n return msgHash;\n }\n\n /// @dev Fetch the messages count of incremental merkle tree.\n function messageCount() public view returns (uint256) {\n return imt.count;\n }\n\n /// @dev Fetch the branch of incremental merkle tree.\n function imtBranch() public view returns (bytes32[32] memory) {\n return imt.branch;\n }\n\n /// @dev Fetch the latest message proof\n function prove() public view returns (bytes32[32] memory) {\n return imt.prove();\n }\n}\n", "keccak256": "0x319891d55eb24333ed77383a97301a793674201cf128557716dd10b721b42e3c"}, "src/interfaces/IOracle.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./IVerifier.sol\";\n\ninterface IOracle is IVerifier {\n /// @notice Fetch oracle price to relay message root to the destination chain.\n /// @param toChainId The destination chain id.\n /// @param ua The user application which send the message.\n /// @return Oracle price in source native gas.\n function fee(uint256 toChainId, address ua) external view returns (uint256);\n\n /// @notice Assign the relay message root task to oracle maintainer.\n /// @param msgHash Hash of the message.\n function assign(bytes32 msgHash) external payable;\n}\n", "keccak256": "0xfcadb8a3763f6d9536768653701f4dd76457d8f26fac4b8e3e74d57644e2578b"}, "src/interfaces/IRelayer.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IRelayer {\n /// @notice Fetch relayer price to relay message to the destination chain.\n /// @param toChainId The destination chain id.\n /// @param ua The user application which send the message.\n /// @param gasLimit Gas limit for UA used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param params General extensibility for relayer to custom functionality.\n /// @return Relayer price in source native gas.\n function fee(uint256 toChainId, address ua, uint256 gasLimit, bytes calldata encoded, bytes calldata params)\n external\n view\n returns (uint256);\n\n /// @notice Assign the relay message task to relayer maintainer.\n /// @param msgHash Hash of the message.\n /// @param params General extensibility for relayer to custom functionality.\n function assign(bytes32 msgHash, bytes calldata params) external payable;\n}\n", "keccak256": "0x927e3fe9b7ddc12b86193ba7baf9fad37ec6b36bdc76882cf3e21a4882feef59"}, "src/security/ReentrancyGuard.sol": {"content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nabstract contract ReentrancyGuard {\n // send and receive nonreentrant lock\n uint8 internal constant _NOT_ENTERED = 1;\n uint8 internal constant _ENTERED = 2;\n uint8 internal _send_state = 1;\n uint8 internal _receive_state = 1;\n\n modifier sendNonReentrant() {\n require(_send_state == _NOT_ENTERED, \"!send-reentrancy\");\n _send_state = _ENTERED;\n _;\n _send_state = _NOT_ENTERED;\n }\n\n modifier recvNonReentrant() {\n require(_receive_state == _NOT_ENTERED, \"!recv-reentrancy\");\n _receive_state = _ENTERED;\n _;\n _receive_state = _NOT_ENTERED;\n }\n}\n", "keccak256": "0x81c70ef950e72c47a438e15ed2afd753faf6fabe38378d57af355e5f20dd7044"}, "src/security/ExcessivelySafeCall.sol": {"content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity 0.8.17;\n\n// Inspired: https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/util/ExcessivelySafeCall.sol\n\nlibrary ExcessivelySafeCall {\n uint256 internal constant LOW_28_MASK = 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff;\n\n /// @notice Use when you _really_ really _really_ don't trust the called\n /// contract. This prevents the called contract from causing reversion of\n /// the caller in as many ways as we can.\n /// @dev The main difference between this and a solidity low-level call is\n /// that we limit the number of bytes that the callee can cause to be\n /// copied to caller memory. This prevents stupid things like malicious\n /// contracts returning 10,000,000 bytes causing a local OOG when copying\n /// to memory.\n /// @param _target The address to call\n /// @param _gas The amount of gas to forward to the remote contract\n /// @param _value Value in wei to send to the account\n /// @param _maxCopy The maximum number of bytes of returndata to copy\n /// to memory.\n /// @param _calldata The data to send to the remote contract\n /// @return success and returndata, as `.call()`. Returndata is capped to\n /// `_maxCopy` bytes.\n function excessivelySafeCall(address _target, uint256 _gas, uint256 _value, uint16 _maxCopy, bytes memory _calldata)\n internal\n returns (bool, bytes memory)\n {\n // set up for assembly call\n uint256 _toCopy;\n bool _success;\n bytes memory _returnData = new bytes(_maxCopy);\n // dispatch message to recipient\n // by assembly calling \"handle\" function\n // we call via assembly to avoid memcopying a very large returndata\n // returned by a malicious contract\n assembly (\"memory-safe\") {\n _success :=\n call(\n _gas, // gas\n _target, // recipient\n _value, // ether value\n add(_calldata, 0x20), // inloc\n mload(_calldata), // inlen\n 0, // outloc\n 0 // outlen\n )\n // limit our copy to 256 bytes\n _toCopy := returndatasize()\n if gt(_toCopy, _maxCopy) { _toCopy := _maxCopy }\n // Store the length of the copied bytes\n mstore(_returnData, _toCopy)\n // copy the bytes from returndata[0:_toCopy]\n returndatacopy(add(_returnData, 0x20), 0, _toCopy)\n }\n return (_success, _returnData);\n }\n\n /// @notice Use when you _really_ really _really_ don't trust the called\n /// contract. This prevents the called contract from causing reversion of\n /// the caller in as many ways as we can.\n /// @dev The main difference between this and a solidity low-level call is\n /// that we limit the number of bytes that the callee can cause to be\n /// copied to caller memory. This prevents stupid things like malicious\n /// contracts returning 10,000,000 bytes causing a local OOG when copying\n /// to memory.\n /// @param _target The address to call\n /// @param _gas The amount of gas to forward to the remote contract\n /// @param _maxCopy The maximum number of bytes of returndata to copy\n /// to memory.\n /// @param _calldata The data to send to the remote contract\n /// @return success and returndata, as `.call()`. Returndata is capped to\n /// `_maxCopy` bytes.\n function excessivelySafeStaticCall(address _target, uint256 _gas, uint16 _maxCopy, bytes memory _calldata)\n internal\n view\n returns (bool, bytes memory)\n {\n // set up for assembly call\n uint256 _toCopy;\n bool _success;\n bytes memory _returnData = new bytes(_maxCopy);\n // dispatch message to recipient\n // by assembly calling \"handle\" function\n // we call via assembly to avoid memcopying a very large returndata\n // returned by a malicious contract\n assembly (\"memory-safe\") {\n _success :=\n staticcall(\n _gas, // gas\n _target, // recipient\n add(_calldata, 0x20), // inloc\n mload(_calldata), // inlen\n 0, // outloc\n 0 // outlen\n )\n // limit our copy to 256 bytes\n _toCopy := returndatasize()\n if gt(_toCopy, _maxCopy) { _toCopy := _maxCopy }\n // Store the length of the copied bytes\n mstore(_returnData, _toCopy)\n // copy the bytes from returndata[0:_toCopy]\n returndatacopy(add(_returnData, 0x20), 0, _toCopy)\n }\n return (_success, _returnData);\n }\n\n /// @notice Swaps function selectors in encoded contract calls\n /// @dev Allows reuse of encoded calldata for functions with identical\n /// argument types but different names. It simply swaps out the first 4 bytes\n /// for the new selector. This function modifies memory in place, and should\n /// only be used with caution.\n /// @param _newSelector The new 4-byte selector\n /// @param _buf The encoded contract args\n function swapSelector(bytes4 _newSelector, bytes memory _buf) internal pure {\n require(_buf.length >= 4);\n uint256 _mask = LOW_28_MASK;\n assembly (\"memory-safe\") {\n // load the first word of\n let _word := mload(add(_buf, 0x20))\n // mask out the top 4 bytes\n // /x\n _word := and(_word, _mask)\n _word := or(_newSelector, _word)\n mstore(add(_buf, 0x20), _word)\n }\n }\n}\n", "keccak256": "0xf1af8846cb689d3305698b0577d7f5a65bea60412e5b3c27c1e26a995e88abda"}, "src/UserConfig.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./Common.sol\";\n\n/// @title UserConfig\n/// @notice User config could select their own relayer and oracle.\n/// The default configuration is used by default.\n/// @dev Only setter could set default config.\ncontract UserConfig {\n /// @dev Setter address.\n address public setter;\n /// @dev ua => config.\n mapping(address => Config) public appConfig;\n /// @dev Default config.\n Config public defaultConfig;\n\n /// @dev Notifies an observer that the default config has set.\n /// @param oracle Default oracle.\n /// @param relayer Default relayer.\n event SetDefaultConfig(address oracle, address relayer);\n /// @dev Notifies an observer that the user application config has updated.\n /// @param ua User application contract address.\n /// @param oracle Oracle which user application.\n /// @param relayer Relayer which user application choose.\n event AppConfigUpdated(address indexed ua, address oracle, address relayer);\n\n modifier onlySetter() {\n require(msg.sender == setter, \"!auth\");\n _;\n }\n\n constructor(address dao) {\n setter = dao;\n }\n\n /// @dev Change setter.\n /// @notice Only current setter could call.\n /// @param setter_ New setter.\n function changeSetter(address setter_) external onlySetter {\n setter = setter_;\n }\n\n /// @dev Set default config for all application.\n /// @notice Only setter could call.\n /// @param oracle Default oracle.\n /// @param relayer Default relayer.\n function setDefaultConfig(address oracle, address relayer) external onlySetter {\n defaultConfig = Config(oracle, relayer);\n emit SetDefaultConfig(oracle, relayer);\n }\n\n function getDefaultConfig() external view returns (Config memory) {\n return defaultConfig;\n }\n\n /// @dev Fetch user application config.\n /// @notice If user application has not configured, then the default config is used.\n /// @param ua User application contract address.\n /// @return user application config.\n function getAppConfig(address ua) public view returns (Config memory) {\n Config memory c = appConfig[ua];\n\n if (c.relayer == address(0x0)) {\n c.relayer = defaultConfig.relayer;\n }\n\n if (c.oracle == address(0x0)) {\n c.oracle = defaultConfig.oracle;\n }\n\n return c;\n }\n\n /// @notice Set user application config.\n /// @param oracle Oracle which user application.\n /// @param relayer Relayer which user application choose.\n function setAppConfig(address oracle, address relayer) external {\n appConfig[msg.sender] = Config(oracle, relayer);\n emit AppConfigUpdated(msg.sender, oracle, relayer);\n }\n}\n", "keccak256": "0xe0c99d30f46bec575bdc3075ed7973e468b03fff252e31a412611342d39312be"}, "src/interfaces/IVerifier.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IVerifier {\n /// @notice Fetch message root oracle.\n /// @param chainId The destination chain id.\n /// @param blockNumber The block number where the message root is located.\n /// @return Message root in destination chain.\n function merkleRoot(uint256 chainId, uint256 blockNumber) external view returns (bytes32);\n\n /// @notice Verify message proof\n /// @dev Message proof provided by relayer. Oracle should provide message root of\n /// source chain, and verify the merkle proof of the message hash.\n /// @param fromChainId Source chain id.\n /// @param msgHash Hash of the message.\n /// @param proof Merkle proof of the message\n /// @return Result of the message verify.\n function verifyMessageProof(uint256 fromChainId, bytes32 msgHash, bytes calldata proof)\n external\n view\n returns (bool);\n}\n", "keccak256": "0x60ad4dbeb54c04aa1c389a2dab7c9bca361eb2df245b3a29f0851be697876099"}, "src/imt/IncrementalMerkleTree.sol": {"content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity 0.8.17;\n\n// Inspired: https://github.com/nomad-xyz/monorepo/blob/main/packages/contracts-core/contracts/libs/Merkle.sol\n\n/// @title IncrementalMerkleTree\n/// @author Illusory Systems Inc.\n/// @notice An incremental merkle tree modeled on the eth2 deposit contract.\nlibrary IncrementalMerkleTree {\n uint256 internal constant TREE_DEPTH = 32;\n uint256 internal constant MAX_LEAVES = 2 ** TREE_DEPTH - 1;\n\n /// @notice Struct representing incremental merkle tree. Contains current\n /// branch and the number of inserted leaves in the tree.\n struct Tree {\n bytes32[TREE_DEPTH] branch;\n uint256 count;\n }\n\n /// @notice Inserts `_node` into merkle tree\n /// @dev Reverts if tree is full\n /// @param _node Element to insert into tree\n function insert(Tree storage _tree, bytes32 _node) internal {\n require(_tree.count < MAX_LEAVES, \"merkle tree full\");\n\n _tree.count += 1;\n uint256 size = _tree.count;\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n if ((size & 1) == 1) {\n _tree.branch[i] = _node;\n return;\n }\n _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n size /= 2;\n }\n // As the loop should always end prematurely with the `return` statement,\n // this code should be unreachable. We assert `false` just to be safe.\n assert(false);\n }\n\n /// @notice Calculates and returns`_tree`'s current root given array of zero\n /// hashes\n /// @param _zeroes Array of zero hashes\n /// @return _current Calculated root of `_tree`\n function rootWithCtx(Tree storage _tree, bytes32[TREE_DEPTH] memory _zeroes)\n internal\n view\n returns (bytes32 _current)\n {\n uint256 _index = _tree.count;\n\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ithBit = (_index >> i) & 0x01;\n bytes32 _next = _tree.branch[i];\n if (_ithBit == 1) {\n _current = keccak256(abi.encodePacked(_next, _current));\n } else {\n _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n }\n }\n }\n\n /// @notice Calculates and returns`_tree`'s current root\n function root(Tree storage _tree) internal view returns (bytes32) {\n return rootWithCtx(_tree, zeroHashes());\n }\n\n /// @notice Returns array of TREE_DEPTH zero hashes\n /// @return _zeroes Array of TREE_DEPTH zero hashes\n function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n _zeroes[0] = Z_0;\n _zeroes[1] = Z_1;\n _zeroes[2] = Z_2;\n _zeroes[3] = Z_3;\n _zeroes[4] = Z_4;\n _zeroes[5] = Z_5;\n _zeroes[6] = Z_6;\n _zeroes[7] = Z_7;\n _zeroes[8] = Z_8;\n _zeroes[9] = Z_9;\n _zeroes[10] = Z_10;\n _zeroes[11] = Z_11;\n _zeroes[12] = Z_12;\n _zeroes[13] = Z_13;\n _zeroes[14] = Z_14;\n _zeroes[15] = Z_15;\n _zeroes[16] = Z_16;\n _zeroes[17] = Z_17;\n _zeroes[18] = Z_18;\n _zeroes[19] = Z_19;\n _zeroes[20] = Z_20;\n _zeroes[21] = Z_21;\n _zeroes[22] = Z_22;\n _zeroes[23] = Z_23;\n _zeroes[24] = Z_24;\n _zeroes[25] = Z_25;\n _zeroes[26] = Z_26;\n _zeroes[27] = Z_27;\n _zeroes[28] = Z_28;\n _zeroes[29] = Z_29;\n _zeroes[30] = Z_30;\n _zeroes[31] = Z_31;\n }\n\n /// @notice Calculates and returns the merkle root for the given leaf\n /// `_item`, a merkle branch, and the index of `_item` in the tree.\n /// @param _item Merkle leaf\n /// @param _branch Merkle proof\n /// @param _index Index of `_item` in tree\n /// @return _current Calculated merkle root\n function branchRoot(bytes32 _item, bytes32[TREE_DEPTH] memory _branch, uint256 _index)\n internal\n pure\n returns (bytes32 _current)\n {\n _current = _item;\n\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ithBit = (_index >> i) & 0x01;\n bytes32 _next = _branch[i];\n if (_ithBit == 1) {\n _current = keccak256(abi.encodePacked(_next, _current));\n } else {\n _current = keccak256(abi.encodePacked(_current, _next));\n }\n }\n }\n\n function prove(Tree storage _tree) internal view returns (bytes32[TREE_DEPTH] memory proof) {\n uint256 _index = _tree.count - 1;\n bytes32[TREE_DEPTH] memory left = _tree.branch;\n bytes32[TREE_DEPTH] memory right = zeroHashes();\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ith_bit = (_index >> i) & 0x01;\n if (_ith_bit == 1) {\n proof[i] = left[i];\n } else {\n proof[i] = right[i];\n }\n }\n }\n\n // keccak256 zero hashes\n bytes32 internal constant Z_0 = hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n bytes32 internal constant Z_1 = hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n bytes32 internal constant Z_2 = hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n bytes32 internal constant Z_3 = hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n bytes32 internal constant Z_4 = hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n bytes32 internal constant Z_5 = hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n bytes32 internal constant Z_6 = hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n bytes32 internal constant Z_7 = hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n bytes32 internal constant Z_8 = hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n bytes32 internal constant Z_9 = hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n bytes32 internal constant Z_10 = hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n bytes32 internal constant Z_11 = hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n bytes32 internal constant Z_12 = hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n bytes32 internal constant Z_13 = hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n bytes32 internal constant Z_14 = hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n bytes32 internal constant Z_15 = hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n bytes32 internal constant Z_16 = hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n bytes32 internal constant Z_17 = hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n bytes32 internal constant Z_18 = hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n bytes32 internal constant Z_19 = hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n bytes32 internal constant Z_20 = hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n bytes32 internal constant Z_21 = hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n bytes32 internal constant Z_22 = hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n bytes32 internal constant Z_23 = hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n bytes32 internal constant Z_24 = hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n bytes32 internal constant Z_25 = hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n bytes32 internal constant Z_26 = hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n bytes32 internal constant Z_27 = hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n bytes32 internal constant Z_28 = hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n bytes32 internal constant Z_29 = hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n bytes32 internal constant Z_30 = hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n bytes32 internal constant Z_31 = hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n", "keccak256": "0x079b8761adbccaac42778a823b6b034acdee9a81eae7db2e1d5894c179871c14"}, "src/Common.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\n/// @dev The block of control information and data for comminicate\n/// between user applications. Messages are the exchange medium\n/// used by channels to send and receive data through cross-chain networks.\n/// A message is sent from a source chain to a destination chain.\n/// @param index The leaf index lives in channel's incremental mekle tree.\n/// @param fromChainId The message source chain id.\n/// @param from User application contract address which send the message.\n/// @param toChainId The Message destination chain id.\n/// @param to User application contract address which receive the message.\n/// @param gasLimit Gas limit for UA used.\n/// @param encoded The calldata which encoded by ABI Encoding.\nstruct Message {\n address channel;\n uint256 index;\n uint256 fromChainId;\n address from;\n uint256 toChainId;\n address to;\n uint256 gasLimit;\n bytes encoded; /*(abi.encodePacked(SELECTOR, PARAMS))*/\n}\n\n/// @dev User application custom configuration.\n/// @param oracle Oracle contract address.\n/// @param relayer Relayer contract address.\nstruct Config {\n address oracle;\n address relayer;\n}\n\n/// @dev Hash of the message.\nfunction hash(Message memory message) pure returns (bytes32) {\n return keccak256(abi.encode(message));\n}\n", "keccak256": "0x6f25340fed3b96d25c88449820225d9cc475ddf337fa058daa968cea41f93631"}}, "settings": {"remappings": ["forge-std/=lib/forge-std/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "create3-deploy/=lib/create3-deploy/"], "optimizer": {"enabled": true, "runs": 999999}, "metadata": {"useLiteralContent": false, "bytecodeHash": "ipfs"}, "outputSelection": {"*": {"": ["ast"], "*": ["abi", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers", "metadata", "storageLayout", "devdoc", "userdoc"]}}, "evmVersion": "london", "libraries": {}, "compilationTarget": {"src/ORMP.sol": "ORMP"}}} \ No newline at end of file +{"language": "Solidity", "sources": {"src/ORMP.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./Channel.sol\";\nimport \"./interfaces/IOracle.sol\";\nimport \"./interfaces/IRelayer.sol\";\nimport \"./security/ReentrancyGuard.sol\";\nimport \"./security/ExcessivelySafeCall.sol\";\n\n/// @title ORMP\n/// @notice An endpoint is a type of network node for cross-chain communication.\n/// It is an interface exposed by a communication channel.\n/// @dev An endpoint is associated with an immutable channel and user configuration.\ncontract ORMP is ReentrancyGuard, Channel {\n using ExcessivelySafeCall for address;\n\n constructor(address dao) Channel(dao) {}\n\n /// @dev Send a cross-chain message over the endpoint.\n /// @notice follow https://eips.ethereum.org/EIPS/eip-5750\n /// @param toChainId The Message destination chain id.\n /// @param to User application contract address which receive the message.\n /// @param gasLimit Gas limit for destination user application used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param refund Return extra fee to refund address.\n /// @param params General extensibility for relayer to custom functionality.\n function send(\n uint256 toChainId,\n address to,\n uint256 gasLimit,\n bytes calldata encoded,\n address refund,\n bytes calldata params\n ) external payable sendNonReentrant returns (bytes32) {\n // user application address.\n address ua = msg.sender;\n // send message by channel, return the hash of the message as id.\n bytes32 msgHash = _send(ua, toChainId, to, gasLimit, encoded);\n\n // handle fee\n _handleFee(ua, refund, msgHash, toChainId, gasLimit, encoded, params);\n\n return msgHash;\n }\n\n function _handleFee(\n address ua,\n address refund,\n bytes32 msgHash,\n uint256 toChainId,\n uint256 gasLimit,\n bytes calldata encoded,\n bytes calldata params\n ) internal {\n // fetch user application's config.\n UC memory uc = getAppConfig(ua);\n // handle relayer fee\n uint256 relayerFee = _handleRelayer(uc.relayer, msgHash, toChainId, ua, gasLimit, encoded, params);\n // handle oracle fee\n uint256 oracleFee = _handleOracle(uc.oracle, msgHash, toChainId, ua);\n\n // refund\n if (msg.value > relayerFee + oracleFee) {\n uint256 refundFee = msg.value - (relayerFee + oracleFee);\n (bool success,) = refund.call{value: refundFee}(\"\");\n require(success, \"!refund\");\n }\n }\n\n /// @notice Get a quote in source native gas, for the amount that send() requires to pay for message delivery.\n /// @param toChainId The Message destination chain id.\n // @param ua User application contract address which send the message.\n /// @param gasLimit Gas limit for destination user application used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param params General extensibility for relayer to custom functionality.\n function fee(uint256 toChainId, address ua, uint256 gasLimit, bytes calldata encoded, bytes calldata params)\n external\n view\n returns (uint256)\n {\n UC memory uc = getAppConfig(ua);\n uint256 relayerFee = IRelayer(uc.relayer).fee(toChainId, ua, gasLimit, encoded, params);\n uint256 oracleFee = IOracle(uc.oracle).fee(toChainId, ua);\n return relayerFee + oracleFee;\n }\n\n function _handleRelayer(\n address relayer,\n bytes32 msgHash,\n uint256 toChainId,\n address ua,\n uint256 gasLimit,\n bytes calldata encoded,\n bytes calldata params\n ) internal returns (uint256) {\n uint256 relayerFee = IRelayer(relayer).fee(toChainId, ua, gasLimit, encoded, params);\n IRelayer(relayer).assign{value: relayerFee}(msgHash, params);\n return relayerFee;\n }\n\n function _handleOracle(address oracle, bytes32 msgHash, uint256 toChainId, address ua) internal returns (uint256) {\n uint256 oracleFee = IOracle(oracle).fee(toChainId, ua);\n IOracle(oracle).assign{value: oracleFee}(msgHash);\n return oracleFee;\n }\n\n /// @dev Recv verified message from Channel and dispatch to destination user application address.\n /// @notice Only channel could call this function.\n /// @param message Verified receive message info.\n /// @param proof Message proof of this message.\n /// @return dispatchResult Result of the message dispatch.\n function recv(Message calldata message, bytes calldata proof)\n external\n payable\n recvNonReentrant\n returns (bool dispatchResult)\n {\n bytes32 msgHash = _recv(message, proof);\n dispatchResult = _dispatch(message, msgHash);\n // emit dispatched message event.\n emit MessageDispatched(msgHash, dispatchResult);\n }\n\n /// @dev Dispatch the cross chain message.\n function _dispatch(Message memory message, bytes32 msgHash) private returns (bool dispatchResult) {\n // Deliver the message to user application contract address.\n (dispatchResult,) = message.to.excessivelySafeCall(\n message.gasLimit,\n msg.value,\n 0,\n abi.encodePacked(message.encoded, msgHash, message.fromChainId, message.from)\n );\n }\n}\n", "keccak256": "0x080ccdf6bc319fb7784c529f2da2881a458ddb0d01fe67d5fe368e29aa48e5ef"}, "src/Channel.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./UserConfig.sol\";\nimport \"./interfaces/IVerifier.sol\";\nimport \"./imt/IncrementalMerkleTree.sol\";\n\n/// @title Channel\n/// @notice A channel is a logical connection over cross-chain network.\n/// It used for cross-chain message transfer.\n/// - Accepts messages to be dispatched to destination chains,\n/// constructs a Merkle tree of the messages.\n/// - Dispatches verified messages from source chains.\n/// @dev Messages live in an incremental merkle tree (imt)\n/// > A Merkle tree is a binary and complete tree decorated with\n/// > the Merkle (hash) attribute.\ncontract Channel is UserConfig {\n using IncrementalMerkleTree for IncrementalMerkleTree.Tree;\n\n /// @dev Incremental merkle tree root which all message hashes live in leafs.\n bytes32 public root;\n /// @dev Incremental merkle tree.\n IncrementalMerkleTree.Tree private _imt;\n /// @dev msgHash => isDispathed.\n mapping(bytes32 => bool) public dones;\n\n /// @dev Self contract address cache.\n address private immutable __self = address(this);\n\n /// @dev Notifies an observer that the message has been accepted.\n /// @param msgHash Hash of the message.\n /// @param root New incremental merkle tree root after a new message inserted.\n /// @param message Accepted message info.\n event MessageAccepted(bytes32 indexed msgHash, bytes32 root, Message message);\n /// @dev Notifies an observer that the message has been dispatched.\n /// @param msgHash Hash of the message.\n /// @param dispatchResult The message dispatch result.\n event MessageDispatched(bytes32 indexed msgHash, bool dispatchResult);\n\n /// @dev Init code.\n constructor(address dao) UserConfig(dao) {\n // init with empty tree\n root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757;\n }\n\n /// @dev Fetch local chain id.\n /// @return chainId Local chain id.\n function LOCAL_CHAINID() public view returns (uint256 chainId) {\n assembly {\n chainId := chainid()\n }\n }\n\n /// @dev Send message.\n /// @param from User application contract address which send the message.\n /// @param toChainId The Message destination chain id.\n /// @param to User application contract address which receive the message.\n /// @param gasLimit Gas limit for destination user application used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n function _send(address from, uint256 toChainId, address to, uint256 gasLimit, bytes calldata encoded)\n internal\n returns (bytes32)\n {\n // only cross-chain message\n require(toChainId != LOCAL_CHAINID(), \"!cross-chain\");\n // get this message leaf index.\n uint256 index = messageCount();\n // constuct message object.\n Message memory message = Message({\n channel: __self,\n index: index,\n fromChainId: LOCAL_CHAINID(),\n from: from,\n toChainId: toChainId,\n to: to,\n gasLimit: gasLimit,\n encoded: encoded\n });\n // hash the message.\n bytes32 msgHash = hash(message);\n // insert msg hash to imt.\n _imt.insert(msgHash);\n // update new imt.root to root storage.\n root = _imt.root();\n\n // emit accepted message event.\n emit MessageAccepted(msgHash, root, message);\n\n // return this message hash.\n return msgHash;\n }\n\n /// @dev Receive messages.\n /// @notice Only message.to's config relayer could relay this message.\n /// @param message Received message info.\n /// @param proof Message proof of this message.\n function _recv(Message calldata message, bytes calldata proof) internal returns (bytes32) {\n // get message.to user config.\n UC memory uc = getAppConfig(message.to);\n // only the config relayer could relay this message.\n require(uc.relayer == msg.sender, \"!auth\");\n\n // hash the message.\n bytes32 msgHash = hash(message);\n // verify message by the config oracle.\n require(IVerifier(uc.oracle).verifyMessageProof(message.fromChainId, msgHash, proof), \"!proof\");\n\n // check destination chain id is correct.\n require(LOCAL_CHAINID() == message.toChainId, \"!toChainId\");\n // check the message is not dispatched.\n require(dones[msgHash] == false, \"done\");\n // set the message is dispatched.\n dones[msgHash] = true;\n\n return msgHash;\n }\n\n /// @dev Fetch the messages count of incremental merkle tree.\n function messageCount() public view returns (uint256) {\n return _imt.count;\n }\n\n /// @dev Fetch the branch of incremental merkle tree.\n function imtBranch() public view returns (bytes32[32] memory) {\n return _imt.branch;\n }\n\n /// @dev Fetch the latest message proof\n function prove() public view returns (bytes32[32] memory) {\n return _imt.prove();\n }\n}\n", "keccak256": "0x286a6af99428230c2f67181181d52d63a647ee2d896c5855300eda37c52b2dbf"}, "src/interfaces/IOracle.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./IVerifier.sol\";\n\ninterface IOracle is IVerifier {\n /// @notice Fetch oracle price to relay message root to the destination chain.\n /// @param toChainId The destination chain id.\n /// @param ua The user application which send the message.\n /// @return Oracle price in source native gas.\n function fee(uint256 toChainId, address ua) external view returns (uint256);\n\n /// @notice Assign the relay message root task to oracle maintainer.\n /// @param msgHash Hash of the message.\n function assign(bytes32 msgHash) external payable;\n}\n", "keccak256": "0xfcadb8a3763f6d9536768653701f4dd76457d8f26fac4b8e3e74d57644e2578b"}, "src/interfaces/IRelayer.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IRelayer {\n /// @notice Fetch relayer price to relay message to the destination chain.\n /// @param toChainId The destination chain id.\n /// @param ua The user application which send the message.\n /// @param gasLimit Gas limit for destination user application used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param params General extensibility for relayer to custom functionality.\n /// @return Relayer price in source native gas.\n function fee(uint256 toChainId, address ua, uint256 gasLimit, bytes calldata encoded, bytes calldata params)\n external\n view\n returns (uint256);\n\n /// @notice Assign the relay message task to relayer maintainer.\n /// @param msgHash Hash of the message.\n /// @param params General extensibility for relayer to custom functionality.\n function assign(bytes32 msgHash, bytes calldata params) external payable;\n}\n", "keccak256": "0x1b271d78cbc79c1f0290cf1d7233071162fe84dff13ac5ca06d708440c7a9c31"}, "src/security/ReentrancyGuard.sol": {"content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nabstract contract ReentrancyGuard {\n // send and receive nonreentrant lock\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n uint256 private _send_state = 1;\n uint256 private _receive_state = 1;\n\n modifier sendNonReentrant() {\n require(_send_state == _NOT_ENTERED, \"!send-reentrancy\");\n _send_state = _ENTERED;\n _;\n _send_state = _NOT_ENTERED;\n }\n\n modifier recvNonReentrant() {\n require(_receive_state == _NOT_ENTERED, \"!recv-reentrancy\");\n _receive_state = _ENTERED;\n _;\n _receive_state = _NOT_ENTERED;\n }\n}\n", "keccak256": "0xbb376a44d276cf677debb795e823759f563a26bd3805e413f7b12ee38e3e13be"}, "src/security/ExcessivelySafeCall.sol": {"content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity 0.8.17;\n\n// Inspired: https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/util/ExcessivelySafeCall.sol\n\nlibrary ExcessivelySafeCall {\n uint256 private constant LOW_28_MASK = 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff;\n\n /// @notice Use when you _really_ really _really_ don't trust the called\n /// contract. This prevents the called contract from causing reversion of\n /// the caller in as many ways as we can.\n /// @dev The main difference between this and a solidity low-level call is\n /// that we limit the number of bytes that the callee can cause to be\n /// copied to caller memory. This prevents stupid things like malicious\n /// contracts returning 10,000,000 bytes causing a local OOG when copying\n /// to memory.\n /// @param _target The address to call\n /// @param _gas The amount of gas to forward to the remote contract\n /// @param _value Value in wei to send to the account\n /// @param _maxCopy The maximum number of bytes of returndata to copy\n /// to memory.\n /// @param _calldata The data to send to the remote contract\n /// @return success and returndata, as `.call()`. Returndata is capped to\n /// `_maxCopy` bytes.\n function excessivelySafeCall(address _target, uint256 _gas, uint256 _value, uint16 _maxCopy, bytes memory _calldata)\n internal\n returns (bool, bytes memory)\n {\n // set up for assembly call\n uint256 _toCopy;\n bool _success;\n bytes memory _returnData = new bytes(_maxCopy);\n // dispatch message to recipient\n // by assembly calling \"handle\" function\n // we call via assembly to avoid memcopying a very large returndata\n // returned by a malicious contract\n assembly (\"memory-safe\") {\n _success :=\n call(\n _gas, // gas\n _target, // recipient\n _value, // ether value\n add(_calldata, 0x20), // inloc\n mload(_calldata), // inlen\n 0, // outloc\n 0 // outlen\n )\n // limit our copy to 256 bytes\n _toCopy := returndatasize()\n if gt(_toCopy, _maxCopy) { _toCopy := _maxCopy }\n // Store the length of the copied bytes\n mstore(_returnData, _toCopy)\n // copy the bytes from returndata[0:_toCopy]\n returndatacopy(add(_returnData, 0x20), 0, _toCopy)\n }\n return (_success, _returnData);\n }\n\n /// @notice Use when you _really_ really _really_ don't trust the called\n /// contract. This prevents the called contract from causing reversion of\n /// the caller in as many ways as we can.\n /// @dev The main difference between this and a solidity low-level call is\n /// that we limit the number of bytes that the callee can cause to be\n /// copied to caller memory. This prevents stupid things like malicious\n /// contracts returning 10,000,000 bytes causing a local OOG when copying\n /// to memory.\n /// @param _target The address to call\n /// @param _gas The amount of gas to forward to the remote contract\n /// @param _maxCopy The maximum number of bytes of returndata to copy\n /// to memory.\n /// @param _calldata The data to send to the remote contract\n /// @return success and returndata, as `.call()`. Returndata is capped to\n /// `_maxCopy` bytes.\n function excessivelySafeStaticCall(address _target, uint256 _gas, uint16 _maxCopy, bytes memory _calldata)\n internal\n view\n returns (bool, bytes memory)\n {\n // set up for assembly call\n uint256 _toCopy;\n bool _success;\n bytes memory _returnData = new bytes(_maxCopy);\n // dispatch message to recipient\n // by assembly calling \"handle\" function\n // we call via assembly to avoid memcopying a very large returndata\n // returned by a malicious contract\n assembly (\"memory-safe\") {\n _success :=\n staticcall(\n _gas, // gas\n _target, // recipient\n add(_calldata, 0x20), // inloc\n mload(_calldata), // inlen\n 0, // outloc\n 0 // outlen\n )\n // limit our copy to 256 bytes\n _toCopy := returndatasize()\n if gt(_toCopy, _maxCopy) { _toCopy := _maxCopy }\n // Store the length of the copied bytes\n mstore(_returnData, _toCopy)\n // copy the bytes from returndata[0:_toCopy]\n returndatacopy(add(_returnData, 0x20), 0, _toCopy)\n }\n return (_success, _returnData);\n }\n\n /// @notice Swaps function selectors in encoded contract calls\n /// @dev Allows reuse of encoded calldata for functions with identical\n /// argument types but different names. It simply swaps out the first 4 bytes\n /// for the new selector. This function modifies memory in place, and should\n /// only be used with caution.\n /// @param _newSelector The new 4-byte selector\n /// @param _buf The encoded contract args\n function swapSelector(bytes4 _newSelector, bytes memory _buf) internal pure {\n require(_buf.length >= 4);\n uint256 _mask = LOW_28_MASK;\n assembly (\"memory-safe\") {\n // load the first word of\n let _word := mload(add(_buf, 0x20))\n // mask out the top 4 bytes\n // /x\n _word := and(_word, _mask)\n _word := or(_newSelector, _word)\n mstore(add(_buf, 0x20), _word)\n }\n }\n}\n", "keccak256": "0x586361e0b312522e1b4dfbbd7a4965fd0b36642660c16cba3a733ee66f388508"}, "src/UserConfig.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./Common.sol\";\n\n/// @title UserConfig\n/// @notice User config could select their own relayer and oracle.\n/// The default configuration is used by default.\n/// @dev Only setter could set default user config.\ncontract UserConfig {\n /// @dev Setter address.\n address public setter;\n /// @dev Default user config.\n UC public defaultUC;\n /// @dev ua => uc.\n mapping(address => UC) public ucOf;\n\n /// @dev Notifies an observer that the default user config has updated.\n /// @param oracle Default oracle.\n /// @param relayer Default relayer.\n event DefaultConfigUpdated(address oracle, address relayer);\n /// @dev Notifies an observer that the user application config has updated.\n /// @param ua User application contract address.\n /// @param oracle Oracle which the user application choose.\n /// @param relayer Relayer which the user application choose.\n event AppConfigUpdated(address indexed ua, address oracle, address relayer);\n\n modifier onlySetter() {\n require(msg.sender == setter, \"!auth\");\n _;\n }\n\n constructor(address dao) {\n setter = dao;\n }\n\n /// @dev Change setter.\n /// @notice Only current setter could call.\n /// @param setter_ New setter.\n function changeSetter(address setter_) external onlySetter {\n setter = setter_;\n }\n\n /// @dev Set default user config for all user application.\n /// @notice Only setter could call.\n /// @param oracle Default oracle.\n /// @param relayer Default relayer.\n function setDefaultConfig(address oracle, address relayer) external onlySetter {\n defaultUC = UC(oracle, relayer);\n emit DefaultConfigUpdated(oracle, relayer);\n }\n\n /// @notice Set user application config.\n /// @param oracle Oracle which user application.\n /// @param relayer Relayer which user application choose.\n function setAppConfig(address oracle, address relayer) external {\n ucOf[msg.sender] = UC(oracle, relayer);\n emit AppConfigUpdated(msg.sender, oracle, relayer);\n }\n\n /// @dev Fetch user application config.\n /// @notice If user application has not configured, then the default user config is used.\n /// @param ua User application contract address.\n /// @return user application config.\n function getAppConfig(address ua) public view returns (UC memory) {\n UC memory c = ucOf[ua];\n\n if (c.relayer == address(0x0)) {\n c.relayer = defaultUC.relayer;\n }\n\n if (c.oracle == address(0x0)) {\n c.oracle = defaultUC.oracle;\n }\n\n return c;\n }\n}\n", "keccak256": "0x654239923d341ccb1c73c3a65ad88f10067d3d7608dde3d0716e55effaf183b4"}, "src/interfaces/IVerifier.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IVerifier {\n /// @notice Fetch message root oracle.\n /// @param chainId The destination chain id.\n /// @param blockNumber The block number where the message root is located.\n /// @return Message root in destination chain.\n function merkleRoot(uint256 chainId, uint256 blockNumber) external view returns (bytes32);\n\n /// @notice Verify message proof\n /// @dev Message proof provided by relayer. Oracle should provide message root of\n /// source chain, and verify the merkle proof of the message hash.\n /// @param fromChainId Source chain id.\n /// @param msgHash Hash of the message.\n /// @param proof Merkle proof of the message\n /// @return Result of the message verify.\n function verifyMessageProof(uint256 fromChainId, bytes32 msgHash, bytes calldata proof)\n external\n view\n returns (bool);\n}\n", "keccak256": "0x60ad4dbeb54c04aa1c389a2dab7c9bca361eb2df245b3a29f0851be697876099"}, "src/imt/IncrementalMerkleTree.sol": {"content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity 0.8.17;\n\n// Inspired: https://github.com/nomad-xyz/monorepo/blob/main/packages/contracts-core/contracts/libs/Merkle.sol\n\n/// @title IncrementalMerkleTree\n/// @author Illusory Systems Inc.\n/// @notice An incremental merkle tree modeled on the eth2 deposit contract.\nlibrary IncrementalMerkleTree {\n uint256 private constant TREE_DEPTH = 32;\n uint256 private constant MAX_LEAVES = 2 ** TREE_DEPTH - 1;\n\n /// @notice Struct representing incremental merkle tree. Contains current\n /// branch and the number of inserted leaves in the tree.\n struct Tree {\n bytes32[TREE_DEPTH] branch;\n uint256 count;\n }\n\n /// @notice Inserts `_node` into merkle tree\n /// @dev Reverts if tree is full\n /// @param _node Element to insert into tree\n function insert(Tree storage _tree, bytes32 _node) internal {\n require(_tree.count < MAX_LEAVES, \"merkle tree full\");\n\n _tree.count += 1;\n uint256 size = _tree.count;\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n if ((size & 1) == 1) {\n _tree.branch[i] = _node;\n return;\n }\n _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n size /= 2;\n }\n // As the loop should always end prematurely with the `return` statement,\n // this code should be unreachable. We assert `false` just to be safe.\n assert(false);\n }\n\n /// @notice Calculates and returns`_tree`'s current root given array of zero\n /// hashes\n /// @param _zeroes Array of zero hashes\n /// @return _current Calculated root of `_tree`\n function rootWithCtx(Tree storage _tree, bytes32[TREE_DEPTH] memory _zeroes)\n internal\n view\n returns (bytes32 _current)\n {\n uint256 _index = _tree.count;\n\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ithBit = (_index >> i) & 0x01;\n bytes32 _next = _tree.branch[i];\n if (_ithBit == 1) {\n _current = keccak256(abi.encodePacked(_next, _current));\n } else {\n _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n }\n }\n }\n\n /// @notice Calculates and returns`_tree`'s current root\n function root(Tree storage _tree) internal view returns (bytes32) {\n return rootWithCtx(_tree, zeroHashes());\n }\n\n /// @notice Returns array of TREE_DEPTH zero hashes\n /// @return _zeroes Array of TREE_DEPTH zero hashes\n function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n _zeroes[0] = Z_0;\n _zeroes[1] = Z_1;\n _zeroes[2] = Z_2;\n _zeroes[3] = Z_3;\n _zeroes[4] = Z_4;\n _zeroes[5] = Z_5;\n _zeroes[6] = Z_6;\n _zeroes[7] = Z_7;\n _zeroes[8] = Z_8;\n _zeroes[9] = Z_9;\n _zeroes[10] = Z_10;\n _zeroes[11] = Z_11;\n _zeroes[12] = Z_12;\n _zeroes[13] = Z_13;\n _zeroes[14] = Z_14;\n _zeroes[15] = Z_15;\n _zeroes[16] = Z_16;\n _zeroes[17] = Z_17;\n _zeroes[18] = Z_18;\n _zeroes[19] = Z_19;\n _zeroes[20] = Z_20;\n _zeroes[21] = Z_21;\n _zeroes[22] = Z_22;\n _zeroes[23] = Z_23;\n _zeroes[24] = Z_24;\n _zeroes[25] = Z_25;\n _zeroes[26] = Z_26;\n _zeroes[27] = Z_27;\n _zeroes[28] = Z_28;\n _zeroes[29] = Z_29;\n _zeroes[30] = Z_30;\n _zeroes[31] = Z_31;\n }\n\n /// @notice Calculates and returns the merkle root for the given leaf\n /// `_item`, a merkle branch, and the index of `_item` in the tree.\n /// @param _item Merkle leaf\n /// @param _branch Merkle proof\n /// @param _index Index of `_item` in tree\n /// @return _current Calculated merkle root\n function branchRoot(bytes32 _item, bytes32[TREE_DEPTH] memory _branch, uint256 _index)\n internal\n pure\n returns (bytes32 _current)\n {\n _current = _item;\n\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ithBit = (_index >> i) & 0x01;\n bytes32 _next = _branch[i];\n if (_ithBit == 1) {\n _current = keccak256(abi.encodePacked(_next, _current));\n } else {\n _current = keccak256(abi.encodePacked(_current, _next));\n }\n }\n }\n\n function prove(Tree storage _tree) internal view returns (bytes32[TREE_DEPTH] memory proof) {\n uint256 _index = _tree.count - 1;\n bytes32[TREE_DEPTH] memory left = _tree.branch;\n bytes32[TREE_DEPTH] memory right = zeroHashes();\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ith_bit = (_index >> i) & 0x01;\n if (_ith_bit == 1) {\n proof[i] = left[i];\n } else {\n proof[i] = right[i];\n }\n }\n }\n\n // keccak256 zero hashes\n bytes32 private constant Z_0 = hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n bytes32 private constant Z_1 = hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n bytes32 private constant Z_2 = hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n bytes32 private constant Z_3 = hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n bytes32 private constant Z_4 = hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n bytes32 private constant Z_5 = hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n bytes32 private constant Z_6 = hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n bytes32 private constant Z_7 = hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n bytes32 private constant Z_8 = hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n bytes32 private constant Z_9 = hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n bytes32 private constant Z_10 = hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n bytes32 private constant Z_11 = hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n bytes32 private constant Z_12 = hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n bytes32 private constant Z_13 = hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n bytes32 private constant Z_14 = hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n bytes32 private constant Z_15 = hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n bytes32 private constant Z_16 = hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n bytes32 private constant Z_17 = hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n bytes32 private constant Z_18 = hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n bytes32 private constant Z_19 = hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n bytes32 private constant Z_20 = hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n bytes32 private constant Z_21 = hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n bytes32 private constant Z_22 = hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n bytes32 private constant Z_23 = hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n bytes32 private constant Z_24 = hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n bytes32 private constant Z_25 = hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n bytes32 private constant Z_26 = hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n bytes32 private constant Z_27 = hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n bytes32 private constant Z_28 = hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n bytes32 private constant Z_29 = hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n bytes32 private constant Z_30 = hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n bytes32 private constant Z_31 = hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n", "keccak256": "0x535228355f8bd4339f42aa3dfe3cebcbdaad7a92704c4e3eeb0982dce8acf246"}, "src/Common.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\n/// @dev The block of control information and data for comminicate\n/// between user applications. Messages are the exchange medium\n/// used by channels to send and receive data through cross-chain networks.\n/// A message is sent from a source chain to a destination chain.\n/// @param index The leaf index lives in channel's incremental mekle tree.\n/// @param fromChainId The message source chain id.\n/// @param from User application contract address which send the message.\n/// @param toChainId The message destination chain id.\n/// @param to User application contract address which receive the message.\n/// @param gasLimit Gas limit for destination UA used.\n/// @param encoded The calldata which encoded by ABI Encoding.\nstruct Message {\n address channel;\n uint256 index;\n uint256 fromChainId;\n address from;\n uint256 toChainId;\n address to;\n uint256 gasLimit;\n bytes encoded; /*(abi.encodePacked(SELECTOR, PARAMS))*/\n}\n\n/// @dev User application custom configuration.\n/// @param oracle Oracle contract address.\n/// @param relayer Relayer contract address.\nstruct UC {\n address oracle;\n address relayer;\n}\n\n/// @dev Hash of the message.\nfunction hash(Message memory message) pure returns (bytes32) {\n return keccak256(abi.encode(message));\n}\n", "keccak256": "0x832de8c9469de78d3133d42716444007d3fa2aa2fe88a6fcbb81d119d8ffbd1d"}}, "settings": {"remappings": ["forge-std/=lib/forge-std/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "create3-deploy/=lib/create3-deploy/"], "optimizer": {"enabled": true, "runs": 999999}, "metadata": {"useLiteralContent": false, "bytecodeHash": "ipfs"}, "outputSelection": {"*": {"": ["ast"], "*": ["abi", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers", "metadata", "storageLayout", "devdoc", "userdoc"]}}, "evmVersion": "london", "libraries": {}, "compilationTarget": {"src/ORMP.sol": "ORMP"}}} \ No newline at end of file diff --git a/script/output/44/Oracle.v.json b/script/output/44/Oracle.v.json index 91a9e19..d711576 100644 --- a/script/output/44/Oracle.v.json +++ b/script/output/44/Oracle.v.json @@ -1 +1 @@ -{"language": "Solidity", "sources": {"src/eco/Oracle.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"../Verifier.sol\";\nimport \"../interfaces/IFeedOracle.sol\";\n\ncontract Oracle is Verifier {\n event Assigned(bytes32 indexed msgHash, uint256 fee);\n event SetFee(uint256 indexed chainId, uint256 fee);\n event SetDapi(uint256 indexed chainId, address dapi);\n event SetApproved(address operator, bool approve);\n\n address public immutable PROTOCOL;\n address public owner;\n\n // chainId => price\n mapping(uint256 => uint256) public feeOf;\n // chainId => dapi\n mapping(uint256 => address) public dapiOf;\n mapping(address => bool) public approvedOf;\n\n modifier onlyOwner() {\n require(msg.sender == owner, \"!owner\");\n _;\n }\n\n modifier onlyApproved() {\n require(isApproved(msg.sender), \"!approve\");\n _;\n }\n\n constructor(address dao, address ormp) {\n PROTOCOL = ormp;\n owner = dao;\n }\n\n receive() external payable {}\n\n function changeOwner(address owner_) external onlyOwner {\n owner = owner_;\n }\n\n function isApproved(address operator) public view returns (bool) {\n return approvedOf[operator];\n }\n\n function setApproved(address operator, bool approve) public onlyOwner {\n approvedOf[operator] = approve;\n emit SetApproved(operator, approve);\n }\n\n function withdraw(address to, uint256 amount) external onlyApproved {\n (bool success,) = to.call{value: amount}(\"\");\n require(success, \"!withdraw\");\n }\n\n function setFee(uint256 chainId, uint256 fee_) external onlyApproved {\n feeOf[chainId] = fee_;\n emit SetFee(chainId, fee_);\n }\n\n function setDapi(uint256 chainId, address dapi) external onlyOwner {\n dapiOf[chainId] = dapi;\n emit SetDapi(chainId, dapi);\n }\n\n function fee(uint256 toChainId, address /*ua*/ ) public view returns (uint256) {\n return feeOf[toChainId];\n }\n\n function assign(bytes32 msgHash) external payable {\n require(msg.sender == PROTOCOL, \"!enpoint\");\n emit Assigned(msgHash, msg.value);\n }\n\n function merkleRoot(uint256 chainId, uint256 /*blockNumber*/ ) public view override returns (bytes32) {\n address dapi = dapiOf[chainId];\n return IFeedOracle(dapi).messageRoot();\n }\n}\n", "keccak256": "0xe8a8a1362c26697e8a8daed5c1a1b1ec9defaaae661d18a74548fde51a2626f2"}, "src/Verifier.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./interfaces/IVerifier.sol\";\nimport \"./imt/IncrementalMerkleTree.sol\";\n\nabstract contract Verifier is IVerifier {\n /// @notice Message proof.\n /// @param messageIndex Leaf index of the message hash in incremental merkle tree.\n /// @param messageProof Merkle proof of the message hash.\n struct Proof {\n uint256 blockNumber;\n uint256 messageIndex;\n bytes32[32] messageProof;\n }\n\n /// @inheritdoc IVerifier\n function merkleRoot(uint256 chainId, uint256 blockNumber) public view virtual returns (bytes32);\n\n /// @inheritdoc IVerifier\n function verifyMessageProof(uint256 fromChainId, bytes32 msgHash, bytes calldata proof)\n external\n view\n returns (bool)\n {\n // decode proof\n Proof memory p = abi.decode(proof, (Proof));\n\n // fetch message root in block number from chain\n bytes32 imtRootOracle = merkleRoot(fromChainId, p.blockNumber);\n // calculate the expected root based on the proof\n bytes32 imtRootProof = IncrementalMerkleTree.branchRoot(msgHash, p.messageProof, p.messageIndex);\n\n // check oracle's merkle root equal relayer's merkle root\n return imtRootOracle == imtRootProof;\n }\n}\n", "keccak256": "0x88004d62714ea3a40be4c14f73a63e07a956c46e9ce77e57805c95e7d2c8d65c"}, "src/interfaces/IFeedOracle.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IFeedOracle {\n function messageRoot() external view returns (bytes32);\n}\n", "keccak256": "0x5b308eb151ccd8038a597169173b96f05223d9a85d6437d9bdcf56248482b499"}, "src/interfaces/IVerifier.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IVerifier {\n /// @notice Fetch message root oracle.\n /// @param chainId The destination chain id.\n /// @param blockNumber The block number where the message root is located.\n /// @return Message root in destination chain.\n function merkleRoot(uint256 chainId, uint256 blockNumber) external view returns (bytes32);\n\n /// @notice Verify message proof\n /// @dev Message proof provided by relayer. Oracle should provide message root of\n /// source chain, and verify the merkle proof of the message hash.\n /// @param fromChainId Source chain id.\n /// @param msgHash Hash of the message.\n /// @param proof Merkle proof of the message\n /// @return Result of the message verify.\n function verifyMessageProof(uint256 fromChainId, bytes32 msgHash, bytes calldata proof)\n external\n view\n returns (bool);\n}\n", "keccak256": "0x60ad4dbeb54c04aa1c389a2dab7c9bca361eb2df245b3a29f0851be697876099"}, "src/imt/IncrementalMerkleTree.sol": {"content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity 0.8.17;\n\n// Inspired: https://github.com/nomad-xyz/monorepo/blob/main/packages/contracts-core/contracts/libs/Merkle.sol\n\n/// @title IncrementalMerkleTree\n/// @author Illusory Systems Inc.\n/// @notice An incremental merkle tree modeled on the eth2 deposit contract.\nlibrary IncrementalMerkleTree {\n uint256 internal constant TREE_DEPTH = 32;\n uint256 internal constant MAX_LEAVES = 2 ** TREE_DEPTH - 1;\n\n /// @notice Struct representing incremental merkle tree. Contains current\n /// branch and the number of inserted leaves in the tree.\n struct Tree {\n bytes32[TREE_DEPTH] branch;\n uint256 count;\n }\n\n /// @notice Inserts `_node` into merkle tree\n /// @dev Reverts if tree is full\n /// @param _node Element to insert into tree\n function insert(Tree storage _tree, bytes32 _node) internal {\n require(_tree.count < MAX_LEAVES, \"merkle tree full\");\n\n _tree.count += 1;\n uint256 size = _tree.count;\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n if ((size & 1) == 1) {\n _tree.branch[i] = _node;\n return;\n }\n _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n size /= 2;\n }\n // As the loop should always end prematurely with the `return` statement,\n // this code should be unreachable. We assert `false` just to be safe.\n assert(false);\n }\n\n /// @notice Calculates and returns`_tree`'s current root given array of zero\n /// hashes\n /// @param _zeroes Array of zero hashes\n /// @return _current Calculated root of `_tree`\n function rootWithCtx(Tree storage _tree, bytes32[TREE_DEPTH] memory _zeroes)\n internal\n view\n returns (bytes32 _current)\n {\n uint256 _index = _tree.count;\n\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ithBit = (_index >> i) & 0x01;\n bytes32 _next = _tree.branch[i];\n if (_ithBit == 1) {\n _current = keccak256(abi.encodePacked(_next, _current));\n } else {\n _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n }\n }\n }\n\n /// @notice Calculates and returns`_tree`'s current root\n function root(Tree storage _tree) internal view returns (bytes32) {\n return rootWithCtx(_tree, zeroHashes());\n }\n\n /// @notice Returns array of TREE_DEPTH zero hashes\n /// @return _zeroes Array of TREE_DEPTH zero hashes\n function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n _zeroes[0] = Z_0;\n _zeroes[1] = Z_1;\n _zeroes[2] = Z_2;\n _zeroes[3] = Z_3;\n _zeroes[4] = Z_4;\n _zeroes[5] = Z_5;\n _zeroes[6] = Z_6;\n _zeroes[7] = Z_7;\n _zeroes[8] = Z_8;\n _zeroes[9] = Z_9;\n _zeroes[10] = Z_10;\n _zeroes[11] = Z_11;\n _zeroes[12] = Z_12;\n _zeroes[13] = Z_13;\n _zeroes[14] = Z_14;\n _zeroes[15] = Z_15;\n _zeroes[16] = Z_16;\n _zeroes[17] = Z_17;\n _zeroes[18] = Z_18;\n _zeroes[19] = Z_19;\n _zeroes[20] = Z_20;\n _zeroes[21] = Z_21;\n _zeroes[22] = Z_22;\n _zeroes[23] = Z_23;\n _zeroes[24] = Z_24;\n _zeroes[25] = Z_25;\n _zeroes[26] = Z_26;\n _zeroes[27] = Z_27;\n _zeroes[28] = Z_28;\n _zeroes[29] = Z_29;\n _zeroes[30] = Z_30;\n _zeroes[31] = Z_31;\n }\n\n /// @notice Calculates and returns the merkle root for the given leaf\n /// `_item`, a merkle branch, and the index of `_item` in the tree.\n /// @param _item Merkle leaf\n /// @param _branch Merkle proof\n /// @param _index Index of `_item` in tree\n /// @return _current Calculated merkle root\n function branchRoot(bytes32 _item, bytes32[TREE_DEPTH] memory _branch, uint256 _index)\n internal\n pure\n returns (bytes32 _current)\n {\n _current = _item;\n\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ithBit = (_index >> i) & 0x01;\n bytes32 _next = _branch[i];\n if (_ithBit == 1) {\n _current = keccak256(abi.encodePacked(_next, _current));\n } else {\n _current = keccak256(abi.encodePacked(_current, _next));\n }\n }\n }\n\n function prove(Tree storage _tree) internal view returns (bytes32[TREE_DEPTH] memory proof) {\n uint256 _index = _tree.count - 1;\n bytes32[TREE_DEPTH] memory left = _tree.branch;\n bytes32[TREE_DEPTH] memory right = zeroHashes();\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ith_bit = (_index >> i) & 0x01;\n if (_ith_bit == 1) {\n proof[i] = left[i];\n } else {\n proof[i] = right[i];\n }\n }\n }\n\n // keccak256 zero hashes\n bytes32 internal constant Z_0 = hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n bytes32 internal constant Z_1 = hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n bytes32 internal constant Z_2 = hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n bytes32 internal constant Z_3 = hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n bytes32 internal constant Z_4 = hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n bytes32 internal constant Z_5 = hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n bytes32 internal constant Z_6 = hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n bytes32 internal constant Z_7 = hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n bytes32 internal constant Z_8 = hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n bytes32 internal constant Z_9 = hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n bytes32 internal constant Z_10 = hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n bytes32 internal constant Z_11 = hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n bytes32 internal constant Z_12 = hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n bytes32 internal constant Z_13 = hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n bytes32 internal constant Z_14 = hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n bytes32 internal constant Z_15 = hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n bytes32 internal constant Z_16 = hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n bytes32 internal constant Z_17 = hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n bytes32 internal constant Z_18 = hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n bytes32 internal constant Z_19 = hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n bytes32 internal constant Z_20 = hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n bytes32 internal constant Z_21 = hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n bytes32 internal constant Z_22 = hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n bytes32 internal constant Z_23 = hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n bytes32 internal constant Z_24 = hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n bytes32 internal constant Z_25 = hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n bytes32 internal constant Z_26 = hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n bytes32 internal constant Z_27 = hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n bytes32 internal constant Z_28 = hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n bytes32 internal constant Z_29 = hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n bytes32 internal constant Z_30 = hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n bytes32 internal constant Z_31 = hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n", "keccak256": "0x079b8761adbccaac42778a823b6b034acdee9a81eae7db2e1d5894c179871c14"}}, "settings": {"remappings": ["forge-std/=lib/forge-std/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "create3-deploy/=lib/create3-deploy/"], "optimizer": {"enabled": true, "runs": 999999}, "metadata": {"useLiteralContent": false, "bytecodeHash": "ipfs"}, "outputSelection": {"*": {"": ["ast"], "*": ["abi", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers", "metadata", "storageLayout", "devdoc", "userdoc"]}}, "evmVersion": "london", "libraries": {}, "compilationTarget": {"src/eco/Oracle.sol": "Oracle"}}} \ No newline at end of file +{"language": "Solidity", "sources": {"src/eco/Oracle.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"../Verifier.sol\";\nimport \"../interfaces/IFeedOracle.sol\";\n\ncontract Oracle is Verifier {\n event Assigned(bytes32 indexed msgHash, uint256 fee);\n event SetFee(uint256 indexed chainId, uint256 fee);\n event SetDapi(uint256 indexed chainId, address dapi);\n event SetApproved(address operator, bool approve);\n\n address public immutable PROTOCOL;\n\n address public owner;\n // chainId => price\n mapping(uint256 => uint256) public feeOf;\n // chainId => dapi\n mapping(uint256 => address) public dapiOf;\n mapping(address => bool) public approvedOf;\n\n modifier onlyOwner() {\n require(msg.sender == owner, \"!owner\");\n _;\n }\n\n modifier onlyApproved() {\n require(isApproved(msg.sender), \"!approve\");\n _;\n }\n\n constructor(address dao, address ormp) {\n PROTOCOL = ormp;\n owner = dao;\n }\n\n receive() external payable {}\n\n function withdraw(address to, uint256 amount) external onlyApproved {\n (bool success,) = to.call{value: amount}(\"\");\n require(success, \"!withdraw\");\n }\n\n function isApproved(address operator) public view returns (bool) {\n return approvedOf[operator];\n }\n\n function changeOwner(address owner_) external onlyOwner {\n owner = owner_;\n }\n\n function setApproved(address operator, bool approve) external onlyOwner {\n approvedOf[operator] = approve;\n emit SetApproved(operator, approve);\n }\n\n function setFee(uint256 chainId, uint256 fee_) external onlyApproved {\n feeOf[chainId] = fee_;\n emit SetFee(chainId, fee_);\n }\n\n function setDapi(uint256 chainId, address dapi) external onlyOwner {\n dapiOf[chainId] = dapi;\n emit SetDapi(chainId, dapi);\n }\n\n function fee(uint256 toChainId, address /*ua*/ ) public view returns (uint256) {\n return feeOf[toChainId];\n }\n\n function assign(bytes32 msgHash) external payable {\n require(msg.sender == PROTOCOL, \"!auth\");\n emit Assigned(msgHash, msg.value);\n }\n\n function merkleRoot(uint256 chainId, uint256 /*blockNumber*/ ) public view override returns (bytes32) {\n address dapi = dapiOf[chainId];\n return IFeedOracle(dapi).messageRoot();\n }\n}\n", "keccak256": "0x4965e1059e65e5c3790e7c28f458cf964d3822af0dd2b8ddfa4da59a71b9c7ac"}, "src/Verifier.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./interfaces/IVerifier.sol\";\nimport \"./imt/IncrementalMerkleTree.sol\";\n\nabstract contract Verifier is IVerifier {\n /// @notice Message proof.\n /// @param blockNumber The block number corresponding to the proof.\n /// @param messageIndex Leaf index of the message hash in incremental merkle tree.\n /// @param messageProof Merkle proof of the message hash.\n struct Proof {\n uint256 blockNumber;\n uint256 messageIndex;\n bytes32[32] messageProof;\n }\n\n /// @inheritdoc IVerifier\n function merkleRoot(uint256 chainId, uint256 blockNumber) public view virtual returns (bytes32);\n\n /// @inheritdoc IVerifier\n function verifyMessageProof(uint256 fromChainId, bytes32 msgHash, bytes calldata proof)\n external\n view\n returns (bool)\n {\n // decode proof\n Proof memory p = abi.decode(proof, (Proof));\n\n // fetch message root in block number from chain\n bytes32 imtRootOracle = merkleRoot(fromChainId, p.blockNumber);\n // calculate the expected root based on the proof\n bytes32 imtRootProof = IncrementalMerkleTree.branchRoot(msgHash, p.messageProof, p.messageIndex);\n\n // check oracle's merkle root equal relayer's merkle root\n return imtRootOracle == imtRootProof;\n }\n}\n", "keccak256": "0x3d61b8b81941f72eca88bc91c727de428e79bb512269bb56acab874b6832730e"}, "src/interfaces/IFeedOracle.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IFeedOracle {\n function messageRoot() external view returns (bytes32);\n}\n", "keccak256": "0x5b308eb151ccd8038a597169173b96f05223d9a85d6437d9bdcf56248482b499"}, "src/interfaces/IVerifier.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IVerifier {\n /// @notice Fetch message root oracle.\n /// @param chainId The destination chain id.\n /// @param blockNumber The block number where the message root is located.\n /// @return Message root in destination chain.\n function merkleRoot(uint256 chainId, uint256 blockNumber) external view returns (bytes32);\n\n /// @notice Verify message proof\n /// @dev Message proof provided by relayer. Oracle should provide message root of\n /// source chain, and verify the merkle proof of the message hash.\n /// @param fromChainId Source chain id.\n /// @param msgHash Hash of the message.\n /// @param proof Merkle proof of the message\n /// @return Result of the message verify.\n function verifyMessageProof(uint256 fromChainId, bytes32 msgHash, bytes calldata proof)\n external\n view\n returns (bool);\n}\n", "keccak256": "0x60ad4dbeb54c04aa1c389a2dab7c9bca361eb2df245b3a29f0851be697876099"}, "src/imt/IncrementalMerkleTree.sol": {"content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity 0.8.17;\n\n// Inspired: https://github.com/nomad-xyz/monorepo/blob/main/packages/contracts-core/contracts/libs/Merkle.sol\n\n/// @title IncrementalMerkleTree\n/// @author Illusory Systems Inc.\n/// @notice An incremental merkle tree modeled on the eth2 deposit contract.\nlibrary IncrementalMerkleTree {\n uint256 private constant TREE_DEPTH = 32;\n uint256 private constant MAX_LEAVES = 2 ** TREE_DEPTH - 1;\n\n /// @notice Struct representing incremental merkle tree. Contains current\n /// branch and the number of inserted leaves in the tree.\n struct Tree {\n bytes32[TREE_DEPTH] branch;\n uint256 count;\n }\n\n /// @notice Inserts `_node` into merkle tree\n /// @dev Reverts if tree is full\n /// @param _node Element to insert into tree\n function insert(Tree storage _tree, bytes32 _node) internal {\n require(_tree.count < MAX_LEAVES, \"merkle tree full\");\n\n _tree.count += 1;\n uint256 size = _tree.count;\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n if ((size & 1) == 1) {\n _tree.branch[i] = _node;\n return;\n }\n _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n size /= 2;\n }\n // As the loop should always end prematurely with the `return` statement,\n // this code should be unreachable. We assert `false` just to be safe.\n assert(false);\n }\n\n /// @notice Calculates and returns`_tree`'s current root given array of zero\n /// hashes\n /// @param _zeroes Array of zero hashes\n /// @return _current Calculated root of `_tree`\n function rootWithCtx(Tree storage _tree, bytes32[TREE_DEPTH] memory _zeroes)\n internal\n view\n returns (bytes32 _current)\n {\n uint256 _index = _tree.count;\n\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ithBit = (_index >> i) & 0x01;\n bytes32 _next = _tree.branch[i];\n if (_ithBit == 1) {\n _current = keccak256(abi.encodePacked(_next, _current));\n } else {\n _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n }\n }\n }\n\n /// @notice Calculates and returns`_tree`'s current root\n function root(Tree storage _tree) internal view returns (bytes32) {\n return rootWithCtx(_tree, zeroHashes());\n }\n\n /// @notice Returns array of TREE_DEPTH zero hashes\n /// @return _zeroes Array of TREE_DEPTH zero hashes\n function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n _zeroes[0] = Z_0;\n _zeroes[1] = Z_1;\n _zeroes[2] = Z_2;\n _zeroes[3] = Z_3;\n _zeroes[4] = Z_4;\n _zeroes[5] = Z_5;\n _zeroes[6] = Z_6;\n _zeroes[7] = Z_7;\n _zeroes[8] = Z_8;\n _zeroes[9] = Z_9;\n _zeroes[10] = Z_10;\n _zeroes[11] = Z_11;\n _zeroes[12] = Z_12;\n _zeroes[13] = Z_13;\n _zeroes[14] = Z_14;\n _zeroes[15] = Z_15;\n _zeroes[16] = Z_16;\n _zeroes[17] = Z_17;\n _zeroes[18] = Z_18;\n _zeroes[19] = Z_19;\n _zeroes[20] = Z_20;\n _zeroes[21] = Z_21;\n _zeroes[22] = Z_22;\n _zeroes[23] = Z_23;\n _zeroes[24] = Z_24;\n _zeroes[25] = Z_25;\n _zeroes[26] = Z_26;\n _zeroes[27] = Z_27;\n _zeroes[28] = Z_28;\n _zeroes[29] = Z_29;\n _zeroes[30] = Z_30;\n _zeroes[31] = Z_31;\n }\n\n /// @notice Calculates and returns the merkle root for the given leaf\n /// `_item`, a merkle branch, and the index of `_item` in the tree.\n /// @param _item Merkle leaf\n /// @param _branch Merkle proof\n /// @param _index Index of `_item` in tree\n /// @return _current Calculated merkle root\n function branchRoot(bytes32 _item, bytes32[TREE_DEPTH] memory _branch, uint256 _index)\n internal\n pure\n returns (bytes32 _current)\n {\n _current = _item;\n\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ithBit = (_index >> i) & 0x01;\n bytes32 _next = _branch[i];\n if (_ithBit == 1) {\n _current = keccak256(abi.encodePacked(_next, _current));\n } else {\n _current = keccak256(abi.encodePacked(_current, _next));\n }\n }\n }\n\n function prove(Tree storage _tree) internal view returns (bytes32[TREE_DEPTH] memory proof) {\n uint256 _index = _tree.count - 1;\n bytes32[TREE_DEPTH] memory left = _tree.branch;\n bytes32[TREE_DEPTH] memory right = zeroHashes();\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ith_bit = (_index >> i) & 0x01;\n if (_ith_bit == 1) {\n proof[i] = left[i];\n } else {\n proof[i] = right[i];\n }\n }\n }\n\n // keccak256 zero hashes\n bytes32 private constant Z_0 = hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n bytes32 private constant Z_1 = hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n bytes32 private constant Z_2 = hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n bytes32 private constant Z_3 = hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n bytes32 private constant Z_4 = hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n bytes32 private constant Z_5 = hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n bytes32 private constant Z_6 = hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n bytes32 private constant Z_7 = hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n bytes32 private constant Z_8 = hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n bytes32 private constant Z_9 = hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n bytes32 private constant Z_10 = hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n bytes32 private constant Z_11 = hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n bytes32 private constant Z_12 = hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n bytes32 private constant Z_13 = hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n bytes32 private constant Z_14 = hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n bytes32 private constant Z_15 = hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n bytes32 private constant Z_16 = hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n bytes32 private constant Z_17 = hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n bytes32 private constant Z_18 = hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n bytes32 private constant Z_19 = hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n bytes32 private constant Z_20 = hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n bytes32 private constant Z_21 = hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n bytes32 private constant Z_22 = hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n bytes32 private constant Z_23 = hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n bytes32 private constant Z_24 = hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n bytes32 private constant Z_25 = hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n bytes32 private constant Z_26 = hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n bytes32 private constant Z_27 = hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n bytes32 private constant Z_28 = hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n bytes32 private constant Z_29 = hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n bytes32 private constant Z_30 = hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n bytes32 private constant Z_31 = hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n", "keccak256": "0x535228355f8bd4339f42aa3dfe3cebcbdaad7a92704c4e3eeb0982dce8acf246"}}, "settings": {"remappings": ["forge-std/=lib/forge-std/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "create3-deploy/=lib/create3-deploy/"], "optimizer": {"enabled": true, "runs": 999999}, "metadata": {"useLiteralContent": false, "bytecodeHash": "ipfs"}, "outputSelection": {"*": {"": ["ast"], "*": ["abi", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers", "metadata", "storageLayout", "devdoc", "userdoc"]}}, "evmVersion": "london", "libraries": {}, "compilationTarget": {"src/eco/Oracle.sol": "Oracle"}}} \ No newline at end of file diff --git a/script/output/44/Relayer.v.json b/script/output/44/Relayer.v.json index ad9f4c8..76519d4 100644 --- a/script/output/44/Relayer.v.json +++ b/script/output/44/Relayer.v.json @@ -1 +1 @@ -{"language": "Solidity", "sources": {"src/eco/Relayer.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"../interfaces/IORMP.sol\";\n\ncontract Relayer {\n event Assigned(bytes32 indexed msgHash, uint256 fee, bytes params, bytes32[32] proof);\n event SetDstPrice(uint256 indexed chainId, uint128 dstPriceRatio, uint128 dstGasPriceInWei);\n event SetDstConfig(uint256 indexed chainId, uint64 baseGas, uint64 gasPerByte);\n event SetApproved(address operator, bool approve);\n\n struct DstPrice {\n uint128 dstPriceRatio; // dstPrice / localPrice * 10^10\n uint128 dstGasPriceInWei;\n }\n\n struct DstConfig {\n uint64 baseGas;\n uint64 gasPerByte;\n }\n\n address public immutable PROTOCOL;\n address public owner;\n\n // chainId => price\n mapping(uint256 => DstPrice) public priceOf;\n mapping(uint256 => DstConfig) public configOf;\n mapping(address => bool) public approvedOf;\n\n modifier onlyOwner() {\n require(msg.sender == owner, \"!owner\");\n _;\n }\n\n modifier onlyApproved() {\n require(isApproved(msg.sender), \"!approve\");\n _;\n }\n\n constructor(address dao, address ormp) {\n PROTOCOL = ormp;\n owner = dao;\n }\n\n receive() external payable {}\n\n function changeOwner(address owner_) external onlyOwner {\n owner = owner_;\n }\n\n function isApproved(address operator) public view returns (bool) {\n return approvedOf[operator];\n }\n\n function setApproved(address operator, bool approve) public onlyOwner {\n approvedOf[operator] = approve;\n emit SetApproved(operator, approve);\n }\n\n function setDstPrice(uint256 chainId, uint128 dstPriceRatio, uint128 dstGasPriceInWei) external onlyApproved {\n priceOf[chainId] = DstPrice(dstPriceRatio, dstGasPriceInWei);\n emit SetDstPrice(chainId, dstPriceRatio, dstGasPriceInWei);\n }\n\n function setDstConfig(uint256 chainId, uint64 baseGas, uint64 gasPerByte) external onlyApproved {\n configOf[chainId] = DstConfig(baseGas, gasPerByte);\n emit SetDstConfig(chainId, baseGas, gasPerByte);\n }\n\n function withdraw(address to, uint256 amount) external onlyApproved {\n (bool success,) = to.call{value: amount}(\"\");\n require(success, \"!withdraw\");\n }\n\n // extraGas = gasLimit\n function fee(\n uint256 toChainId,\n address, /*ua*/\n uint256 gasLimit,\n bytes calldata encoded,\n bytes calldata /*params*/\n ) public view returns (uint256) {\n uint256 size = encoded.length;\n uint256 extraGas = gasLimit;\n DstPrice memory p = priceOf[toChainId];\n DstConfig memory c = configOf[toChainId];\n\n require(c.baseGas != 0, \"!baseGas\");\n // remoteToken = dstGasPriceInWei * (baseGas + extraGas)\n uint256 remoteToken = p.dstGasPriceInWei * (c.baseGas + extraGas);\n // dstPriceRatio = dstPrice / localPrice * 10^10\n // sourceToken = RemoteToken * dstPriceRatio\n uint256 sourceToken = remoteToken * p.dstPriceRatio / (10 ** 10);\n uint256 payloadToken = c.gasPerByte * size * p.dstGasPriceInWei * p.dstPriceRatio / (10 ** 10);\n return sourceToken + payloadToken;\n }\n\n function assign(bytes32 msgHash, bytes calldata params) external payable {\n require(msg.sender == PROTOCOL, \"!ormp\");\n emit Assigned(msgHash, msg.value, params, IORMP(PROTOCOL).prove());\n }\n\n function relay(Message calldata message, bytes calldata proof) external onlyApproved {\n IORMP(PROTOCOL).recv(message, proof);\n }\n}\n", "keccak256": "0xdbbd98d174fd0e7042e77568ccd0ec3e320b5347f32cea11b2683dc4c5efd282"}, "src/interfaces/IORMP.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"../Common.sol\";\n\ninterface IORMP {\n /// @dev Send a cross-chain message over the endpoint.\n /// @notice follow https://eips.ethereum.org/EIPS/eip-5750\n /// @param toChainId The Message destination chain id.\n /// @param to User application contract address which receive the message.\n /// @param gasLimit Gas limit for UA used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param refund Return extra fee to refund address.\n /// @param params General extensibility for relayer to custom functionality.\n /// @return Return the hash of the message as message id.\n function send(\n uint256 toChainId,\n address to,\n uint256 gasLimit,\n bytes calldata encoded,\n address refund,\n bytes calldata params\n ) external payable returns (bytes32);\n\n /// @notice Get a quote in source native gas, for the amount that send() requires to pay for message delivery.\n /// @param toChainId The Message destination chain id.\n // @param ua User application contract address which send the message.\n /// @param gasLimit Gas limit for UA used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param params General extensibility for relayer to custom functionality.\n function fee(uint256 toChainId, address ua, uint256 gasLimit, bytes calldata encoded, bytes calldata params)\n external\n view\n returns (uint256);\n\n /// @dev Recv verified message and dispatch to destination user application address.\n /// @param message Verified receive message info.\n /// @param proof Message proof of this message.\n /// @return dispatchResult Result of the message dispatch.\n function recv(Message calldata message, bytes calldata proof) external returns (bool dispatchResult);\n\n function prove() external view returns (bytes32[32] memory);\n\n /// @dev Fetch user application config.\n /// @notice If user application has not configured, then the default config is used.\n /// @param ua User application contract address.\n /// @return user application config.\n function getAppConfig(address ua) external view returns (Config memory);\n\n /// @notice Set user application config.\n /// @param oracle Oracle which user application choose.\n /// @param relayer Relayer which user application choose.\n function setAppConfig(address oracle, address relayer) external;\n\n function setDefaultConfig(address oracle, address relayer) external;\n function defaultConfig() external view returns (Config memory);\n function changeSetter(address setter_) external;\n}\n", "keccak256": "0xafdb65bcc3162062fb07b6d81a4b51891b0f53bd09dbb6e49a5151daa4cd5538"}, "src/Common.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\n/// @dev The block of control information and data for comminicate\n/// between user applications. Messages are the exchange medium\n/// used by channels to send and receive data through cross-chain networks.\n/// A message is sent from a source chain to a destination chain.\n/// @param index The leaf index lives in channel's incremental mekle tree.\n/// @param fromChainId The message source chain id.\n/// @param from User application contract address which send the message.\n/// @param toChainId The Message destination chain id.\n/// @param to User application contract address which receive the message.\n/// @param gasLimit Gas limit for UA used.\n/// @param encoded The calldata which encoded by ABI Encoding.\nstruct Message {\n address channel;\n uint256 index;\n uint256 fromChainId;\n address from;\n uint256 toChainId;\n address to;\n uint256 gasLimit;\n bytes encoded; /*(abi.encodePacked(SELECTOR, PARAMS))*/\n}\n\n/// @dev User application custom configuration.\n/// @param oracle Oracle contract address.\n/// @param relayer Relayer contract address.\nstruct Config {\n address oracle;\n address relayer;\n}\n\n/// @dev Hash of the message.\nfunction hash(Message memory message) pure returns (bytes32) {\n return keccak256(abi.encode(message));\n}\n", "keccak256": "0x6f25340fed3b96d25c88449820225d9cc475ddf337fa058daa968cea41f93631"}}, "settings": {"remappings": ["forge-std/=lib/forge-std/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "create3-deploy/=lib/create3-deploy/"], "optimizer": {"enabled": true, "runs": 999999}, "metadata": {"useLiteralContent": false, "bytecodeHash": "ipfs"}, "outputSelection": {"*": {"": ["ast"], "*": ["abi", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers", "metadata", "storageLayout", "devdoc", "userdoc"]}}, "evmVersion": "london", "libraries": {}, "compilationTarget": {"src/eco/Relayer.sol": "Relayer"}}} \ No newline at end of file +{"language": "Solidity", "sources": {"src/eco/Relayer.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"../interfaces/IORMP.sol\";\n\ncontract Relayer {\n event Assigned(bytes32 indexed msgHash, uint256 fee, bytes params, bytes32[32] proof);\n event SetDstPrice(uint256 indexed chainId, uint128 dstPriceRatio, uint128 dstGasPriceInWei);\n event SetDstConfig(uint256 indexed chainId, uint64 baseGas, uint64 gasPerByte);\n event SetApproved(address operator, bool approve);\n\n struct DstPrice {\n uint128 dstPriceRatio; // dstPrice / localPrice * 10^10\n uint128 dstGasPriceInWei;\n }\n\n struct DstConfig {\n uint64 baseGas;\n uint64 gasPerByte;\n }\n\n address public immutable PROTOCOL;\n\n address public owner;\n // chainId => price\n mapping(uint256 => DstPrice) public priceOf;\n mapping(uint256 => DstConfig) public configOf;\n mapping(address => bool) public approvedOf;\n\n modifier onlyOwner() {\n require(msg.sender == owner, \"!owner\");\n _;\n }\n\n modifier onlyApproved() {\n require(isApproved(msg.sender), \"!approve\");\n _;\n }\n\n constructor(address dao, address ormp) {\n PROTOCOL = ormp;\n owner = dao;\n }\n\n receive() external payable {}\n\n function withdraw(address to, uint256 amount) external onlyApproved {\n (bool success,) = to.call{value: amount}(\"\");\n require(success, \"!withdraw\");\n }\n\n function isApproved(address operator) public view returns (bool) {\n return approvedOf[operator];\n }\n\n function changeOwner(address owner_) external onlyOwner {\n owner = owner_;\n }\n\n function setApproved(address operator, bool approve) public onlyOwner {\n approvedOf[operator] = approve;\n emit SetApproved(operator, approve);\n }\n\n function setDstPrice(uint256 chainId, uint128 dstPriceRatio, uint128 dstGasPriceInWei) external onlyApproved {\n priceOf[chainId] = DstPrice(dstPriceRatio, dstGasPriceInWei);\n emit SetDstPrice(chainId, dstPriceRatio, dstGasPriceInWei);\n }\n\n function setDstConfig(uint256 chainId, uint64 baseGas, uint64 gasPerByte) external onlyApproved {\n configOf[chainId] = DstConfig(baseGas, gasPerByte);\n emit SetDstConfig(chainId, baseGas, gasPerByte);\n }\n\n // extraGas = gasLimit\n function fee(\n uint256 toChainId,\n address, /*ua*/\n uint256 gasLimit,\n bytes calldata encoded,\n bytes calldata /*params*/\n ) public view returns (uint256) {\n uint256 size = encoded.length;\n uint256 extraGas = gasLimit;\n DstPrice memory p = priceOf[toChainId];\n DstConfig memory c = configOf[toChainId];\n\n require(c.baseGas != 0, \"!baseGas\");\n // remoteToken = dstGasPriceInWei * (baseGas + extraGas)\n uint256 remoteToken = p.dstGasPriceInWei * (c.baseGas + extraGas);\n // dstPriceRatio = dstPrice / localPrice * 10^10\n // sourceToken = RemoteToken * dstPriceRatio\n uint256 sourceToken = remoteToken * p.dstPriceRatio / (10 ** 10);\n uint256 payloadToken = c.gasPerByte * size * p.dstGasPriceInWei * p.dstPriceRatio / (10 ** 10);\n return sourceToken + payloadToken;\n }\n\n function assign(bytes32 msgHash, bytes calldata params) external payable {\n require(msg.sender == PROTOCOL, \"!ormp\");\n emit Assigned(msgHash, msg.value, params, IORMP(PROTOCOL).prove());\n }\n\n function relay(Message calldata message, bytes calldata proof) external onlyApproved {\n IORMP(PROTOCOL).recv(message, proof);\n }\n}\n", "keccak256": "0xc49d978c3f8677f9cdd4f2f2ca5c129711f56a4668ab3102637fe679c7b70df4"}, "src/interfaces/IORMP.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"../Common.sol\";\n\ninterface IORMP {\n /// @dev Send a cross-chain message over the endpoint.\n /// @notice follow https://eips.ethereum.org/EIPS/eip-5750\n /// @param toChainId The Message destination chain id.\n /// @param to User application contract address which receive the message.\n /// @param gasLimit Gas limit for destination user application used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param refund Return extra fee to refund address.\n /// @param params General extensibility for relayer to custom functionality.\n /// @return Return the hash of the message as message id.\n function send(\n uint256 toChainId,\n address to,\n uint256 gasLimit,\n bytes calldata encoded,\n address refund,\n bytes calldata params\n ) external payable returns (bytes32);\n\n /// @notice Get a quote in source native gas, for the amount that send() requires to pay for message delivery.\n /// @param toChainId The Message destination chain id.\n // @param ua User application contract address which send the message.\n /// @param gasLimit Gas limit for destination user application used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param params General extensibility for relayer to custom functionality.\n function fee(uint256 toChainId, address ua, uint256 gasLimit, bytes calldata encoded, bytes calldata params)\n external\n view\n returns (uint256);\n\n /// @dev Recv verified message and dispatch to destination user application address.\n /// @param message Verified receive message info.\n /// @param proof Message proof of this message.\n /// @return dispatchResult Result of the message dispatch.\n function recv(Message calldata message, bytes calldata proof) external returns (bool dispatchResult);\n\n function prove() external view returns (bytes32[32] memory);\n\n /// @dev Fetch user application config.\n /// @notice If user application has not configured, then the default config is used.\n /// @param ua User application contract address.\n /// @return user application config.\n function getAppConfig(address ua) external view returns (UC memory);\n\n /// @notice Set user application config.\n /// @param oracle Oracle which user application choose.\n /// @param relayer Relayer which user application choose.\n function setAppConfig(address oracle, address relayer) external;\n\n function defaultUC() external view returns (UC memory);\n}\n", "keccak256": "0xc78b6e5e140bf7972aa17bef9f4104df9d6841171a3be7424e4472f31e346cfd"}, "src/Common.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\n/// @dev The block of control information and data for comminicate\n/// between user applications. Messages are the exchange medium\n/// used by channels to send and receive data through cross-chain networks.\n/// A message is sent from a source chain to a destination chain.\n/// @param index The leaf index lives in channel's incremental mekle tree.\n/// @param fromChainId The message source chain id.\n/// @param from User application contract address which send the message.\n/// @param toChainId The message destination chain id.\n/// @param to User application contract address which receive the message.\n/// @param gasLimit Gas limit for destination UA used.\n/// @param encoded The calldata which encoded by ABI Encoding.\nstruct Message {\n address channel;\n uint256 index;\n uint256 fromChainId;\n address from;\n uint256 toChainId;\n address to;\n uint256 gasLimit;\n bytes encoded; /*(abi.encodePacked(SELECTOR, PARAMS))*/\n}\n\n/// @dev User application custom configuration.\n/// @param oracle Oracle contract address.\n/// @param relayer Relayer contract address.\nstruct UC {\n address oracle;\n address relayer;\n}\n\n/// @dev Hash of the message.\nfunction hash(Message memory message) pure returns (bytes32) {\n return keccak256(abi.encode(message));\n}\n", "keccak256": "0x832de8c9469de78d3133d42716444007d3fa2aa2fe88a6fcbb81d119d8ffbd1d"}}, "settings": {"remappings": ["forge-std/=lib/forge-std/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "create3-deploy/=lib/create3-deploy/"], "optimizer": {"enabled": true, "runs": 999999}, "metadata": {"useLiteralContent": false, "bytecodeHash": "ipfs"}, "outputSelection": {"*": {"": ["ast"], "*": ["abi", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers", "metadata", "storageLayout", "devdoc", "userdoc"]}}, "evmVersion": "london", "libraries": {}, "compilationTarget": {"src/eco/Relayer.sol": "Relayer"}}} \ No newline at end of file diff --git a/script/output/44/deploy.a-latest.json b/script/output/44/deploy.a-latest.json index 9189ef7..b03fd23 100644 --- a/script/output/44/deploy.a-latest.json +++ b/script/output/44/deploy.a-latest.json @@ -1,6 +1,6 @@ { "DAO": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", - "ORACLE": "0x00BD655DDfA7aFeF4BB109FE1F938724527B49D8", - "RELAYER": "0x003605167cd4C36063a7B63e604497e623Bb8B10", - "ORMP": "0x009D223Aad560e72282db9c0438Ef1ef2bf7703D" + "ORACLE": "0x0000000000ba03146Cc235509E802873D418a6bc", + "ORMP": "0x00000000001523057a05d6293C1e5171eE33eE0A", + "RELAYER": "0x0000000000808fE9bDCc1d180EfbF5C53552a6b1" }