From 9a1f25228ee6d2c1b473ee036a3b40ef319aca18 Mon Sep 17 00:00:00 2001 From: echo Date: Mon, 25 Mar 2024 15:58:33 +0800 Subject: [PATCH 1/4] fmt --- README.md | 2 +- script/deploy/Deploy.s.sol | 4 +- src/ORMP.sol | 4 ++ src/eco/ORMPOracle.sol | 101 ------------------------------------- src/eco/Oracle.sol | 51 +++++++++++++------ src/eco/Relayer.sol | 4 ++ test/bench/ORMP.b.sol | 4 +- test/eco/Oracle.t.sol | 4 +- 8 files changed, 51 insertions(+), 123 deletions(-) delete mode 100644 src/eco/ORMPOracle.sol diff --git a/README.md b/README.md index c5d3603..d94f453 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # ORMP Oracle and Relayer based Message Protocol. -## Deployments +## V1 Deployments ### Canonical Cross-chain Deployment Addresses | Contract | Canonical Cross-chain Deployment Address | |------------|--------------------------------------------| diff --git a/script/deploy/Deploy.s.sol b/script/deploy/Deploy.s.sol index 8f809df..ecad37b 100644 --- a/script/deploy/Deploy.s.sol +++ b/script/deploy/Deploy.s.sol @@ -9,7 +9,7 @@ import {ScriptTools} from "create3-deploy/script/ScriptTools.sol"; import {ORMP} from "../../src/ORMP.sol"; import {Relayer} from "../../src/eco/Relayer.sol"; -import {ORMPOracle} from "../../src/eco/ORMPOracle.sol"; +import {Oracle} from "../../src/eco/Oracle.sol"; interface III { function PROTOCOL() external view returns (address); @@ -101,7 +101,7 @@ contract Deploy is Common { /// @notice Deploy the Oracle function deployOralce() public broadcast returns (address) { - bytes memory byteCode = type(ORMPOracle).creationCode; + bytes memory byteCode = type(Oracle).creationCode; bytes memory initCode = bytes.concat(byteCode, abi.encode(deployer, ORMP_ADDR)); address oracle = _deploy3(ORACLE_SALT, initCode); require(oracle == ORACLE_ADDR, "!oracle"); diff --git a/src/ORMP.sol b/src/ORMP.sol index 0acd3c5..6b01f63 100644 --- a/src/ORMP.sol +++ b/src/ORMP.sol @@ -36,6 +36,10 @@ contract ORMP is ReentrancyGuard, Channel { constructor(address dao) Channel(dao) {} + function version() public pure returns (string memory) { + return "2.0.0"; + } + /// @dev Send a cross-chain message over the endpoint. /// @notice follow https://eips.ethereum.org/EIPS/eip-5750 /// @param toChainId The Message destination chain id. diff --git a/src/eco/ORMPOracle.sol b/src/eco/ORMPOracle.sol deleted file mode 100644 index 47e35cd..0000000 --- a/src/eco/ORMPOracle.sol +++ /dev/null @@ -1,101 +0,0 @@ -// This file is part of Darwinia. -// Copyright (C) 2018-2023 Darwinia Network -// SPDX-License-Identifier: GPL-3.0 -// -// Darwinia is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Darwinia is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Darwinia. If not, see . - -pragma solidity 0.8.17; - -import "../Verifier.sol"; - -contract ORMPOracle is Verifier { - event SetFee(uint256 indexed chainId, uint256 fee); - event SetApproved(address operator, bool approve); - event Withdrawal(address indexed to, uint256 amt); - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); - event ImportedMessageRoot(uint256 indexed chainId, uint256 indexed blockHeight, bytes32 messageRoot); - - address public immutable PROTOCOL; - - address public owner; - // chainId => price - mapping(uint256 => uint256) public feeOf; - // chainId => blockNumber => messageRoot - mapping(uint256 => mapping(uint256 => bytes32)) rootOf; - // operator => isApproved - mapping(address => bool) public approvedOf; - - modifier onlyOwner() { - require(msg.sender == owner, "!owner"); - _; - } - - modifier onlyApproved() { - require(isApproved(msg.sender), "!approve"); - _; - } - - constructor(address dao, address ormp) { - PROTOCOL = ormp; - owner = dao; - } - - receive() external payable {} - - /// @dev Only could be called by owner. - /// @notice Each channel has a corresponding oracle, and the message root should match with it. - /// @param chainId The source chain id. - /// @param blockNumber The source chain block number. - /// @param messageRoot The source chain message root corresponding to the channel. - function importMessageRoot(uint256 chainId, uint256 blockNumber, bytes32 messageRoot) external onlyOwner { - rootOf[chainId][blockNumber] = messageRoot; - emit ImportedMessageRoot(chainId, blockNumber, messageRoot); - } - - function changeOwner(address newOwner) external onlyOwner { - address oldOwner = owner; - owner = newOwner; - emit OwnershipTransferred(oldOwner, newOwner); - } - - function setApproved(address operator, bool approve) external onlyOwner { - approvedOf[operator] = approve; - emit SetApproved(operator, approve); - } - - function isApproved(address operator) public view returns (bool) { - return approvedOf[operator]; - } - - function withdraw(address to, uint256 amount) external onlyApproved { - (bool success,) = to.call{value: amount}(""); - require(success, "!withdraw"); - emit Withdrawal(to, amount); - } - - function setFee(uint256 chainId, uint256 fee_) external onlyApproved { - feeOf[chainId] = fee_; - emit SetFee(chainId, fee_); - } - - function fee(uint256 toChainId, address /*ua*/ ) public view returns (uint256) { - uint256 f = feeOf[toChainId]; - require(f != 0, "!fee"); - return f; - } - - function merkleRoot(uint256 chainId, uint256 blockNumber) public view override returns (bytes32) { - return rootOf[chainId][blockNumber]; - } -} diff --git a/src/eco/Oracle.sol b/src/eco/Oracle.sol index e8d37ca..30deb79 100644 --- a/src/eco/Oracle.sol +++ b/src/eco/Oracle.sol @@ -18,19 +18,22 @@ pragma solidity 0.8.17; import "../Verifier.sol"; -import "../interfaces/IFeedOracle.sol"; contract Oracle is Verifier { event SetFee(uint256 indexed chainId, uint256 fee); event SetApproved(address operator, bool approve); + event Withdrawal(address indexed to, uint256 amt); + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event ImportedMessageRoot(uint256 indexed chainId, uint256 indexed blockHeight, bytes32 messageRoot); address public immutable PROTOCOL; - address public immutable SUBAPI; address public owner; // chainId => price mapping(uint256 => uint256) public feeOf; - // chainId => dapi + // chainId => blockNumber => messageRoot + mapping(uint256 => mapping(uint256 => bytes32)) rootOf; + // operator => isApproved mapping(address => bool) public approvedOf; modifier onlyOwner() { @@ -43,25 +46,31 @@ contract Oracle is Verifier { _; } - constructor(address dao, address ormp, address subapi) { - SUBAPI = subapi; + constructor(address dao, address ormp) { PROTOCOL = ormp; owner = dao; } receive() external payable {} - function withdraw(address to, uint256 amount) external onlyApproved { - (bool success,) = to.call{value: amount}(""); - require(success, "!withdraw"); + function version() public pure returns (string memory) { + return "2.0.0"; } - function isApproved(address operator) public view returns (bool) { - return approvedOf[operator]; + /// @dev Only could be called by owner. + /// @notice Each channel has a corresponding oracle, and the message root should match with it. + /// @param chainId The source chain id. + /// @param blockNumber The source chain block number. + /// @param messageRoot The source chain message root corresponding to the channel. + function importMessageRoot(uint256 chainId, uint256 blockNumber, bytes32 messageRoot) external onlyOwner { + rootOf[chainId][blockNumber] = messageRoot; + emit ImportedMessageRoot(chainId, blockNumber, messageRoot); } - function changeOwner(address owner_) external onlyOwner { - owner = owner_; + function changeOwner(address newOwner) external onlyOwner { + address oldOwner = owner; + owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); } function setApproved(address operator, bool approve) external onlyOwner { @@ -69,16 +78,28 @@ contract Oracle is Verifier { emit SetApproved(operator, approve); } + function isApproved(address operator) public view returns (bool) { + return approvedOf[operator]; + } + + function withdraw(address to, uint256 amount) external onlyApproved { + (bool success,) = to.call{value: amount}(""); + require(success, "!withdraw"); + emit Withdrawal(to, amount); + } + function setFee(uint256 chainId, uint256 fee_) external onlyApproved { feeOf[chainId] = fee_; emit SetFee(chainId, fee_); } function fee(uint256 toChainId, address /*ua*/ ) public view returns (uint256) { - return feeOf[toChainId]; + uint256 f = feeOf[toChainId]; + require(f != 0, "!fee"); + return f; } - function merkleRoot(uint256 chainId, uint256 /*blockNumber*/ ) public view override returns (bytes32) { - return IFeedOracle(SUBAPI).messageRootOf(chainId); + function merkleRoot(uint256 chainId, uint256 blockNumber) public view override returns (bytes32) { + return rootOf[chainId][blockNumber]; } } diff --git a/src/eco/Relayer.sol b/src/eco/Relayer.sol index e81fe0f..56fa2a5 100644 --- a/src/eco/Relayer.sol +++ b/src/eco/Relayer.sol @@ -58,6 +58,10 @@ contract Relayer { owner = dao; } + function version() public pure returns (string memory) { + return "2.0.0"; + } + receive() external payable {} function withdraw(address to, uint256 amount) external onlyApproved { diff --git a/test/bench/ORMP.b.sol b/test/bench/ORMP.b.sol index 70fb446..db7c91e 100644 --- a/test/bench/ORMP.b.sol +++ b/test/bench/ORMP.b.sol @@ -21,14 +21,14 @@ import "forge-std/Test.sol"; import {Chains} from "create3-deploy/script/Chains.sol"; import "../../src/Verifier.sol"; import "../../src/ORMP.sol"; -import "../../src/eco/ORMPOracle.sol"; +import "../../src/eco/Oracle.sol"; import "../../src/eco/Relayer.sol"; contract ORMPBenchmarkTest is Test { using Chains for uint256; ORMP ormp = ORMP(0x00000000001523057a05d6293C1e5171eE33eE0A); - ORMPOracle oracle = ORMPOracle(payable(0x0000000003ebeF32D8f0ED406a5CA8805c80AFba)); + Oracle oracle = Oracle(payable(0x0000000003ebeF32D8f0ED406a5CA8805c80AFba)); Relayer relayer = Relayer(payable(0x0000000000808fE9bDCc1d180EfbF5C53552a6b1)); address immutable self = address(this); diff --git a/test/eco/Oracle.t.sol b/test/eco/Oracle.t.sol index bb52e79..3037021 100644 --- a/test/eco/Oracle.t.sol +++ b/test/eco/Oracle.t.sol @@ -27,7 +27,7 @@ contract OracleTest is Test { receive() external payable {} function setUp() public { - oracle = new Oracle(self, self, self); + oracle = new Oracle(self, self); oracle.setApproved(self, true); } @@ -71,7 +71,7 @@ contract OracleTest is Test { assertEq(r, bytes32(uint256(1))); } - function messageRootOf(uint256) external pure returns (bytes32) { + function merkleRoot(uint256, uint256) external pure returns (bytes32) { return bytes32(uint256(1)); } } From 19e313765425cb550ba2bdbc3d9efc2147472443 Mon Sep 17 00:00:00 2001 From: echo Date: Wed, 27 Mar 2024 23:11:22 +0800 Subject: [PATCH 2/4] clean --- src/eco/Oracle.sol | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/eco/Oracle.sol b/src/eco/Oracle.sol index 30deb79..aee841e 100644 --- a/src/eco/Oracle.sol +++ b/src/eco/Oracle.sol @@ -26,8 +26,6 @@ contract Oracle is Verifier { event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); event ImportedMessageRoot(uint256 indexed chainId, uint256 indexed blockHeight, bytes32 messageRoot); - address public immutable PROTOCOL; - address public owner; // chainId => price mapping(uint256 => uint256) public feeOf; @@ -46,8 +44,7 @@ contract Oracle is Verifier { _; } - constructor(address dao, address ormp) { - PROTOCOL = ormp; + constructor(address dao) { owner = dao; } From 2659f0d32eefc4060e9bbdd2f28f284d19b3e93d Mon Sep 17 00:00:00 2001 From: echo Date: Sun, 7 Apr 2024 15:52:16 +0800 Subject: [PATCH 3/4] move --- src/ORMP.sol | 15 +++++++++++++++ src/eco/Oracle.sol | 14 +++++++------- src/interfaces/IORMP.sol | 15 +++++++++++++++ 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/ORMP.sol b/src/ORMP.sol index 6b01f63..979d8e4 100644 --- a/src/ORMP.sol +++ b/src/ORMP.sol @@ -33,6 +33,10 @@ contract ORMP is ReentrancyGuard, Channel { event MessageAssigned( bytes32 indexed msgHash, address indexed oracle, address indexed relayer, uint256 oracleFee, uint256 relayerFee ); + event HashImported(uint256 indexed srcChainId, address indexed oracle, bytes32 indexed lookupKey, bytes32 hash); + + /// oracle => srcChainId => lookupKey => hash + mapping(address => mapping(uint256 => mapping(bytes32 => bytes32))) public hashLookup; constructor(address dao) Channel(dao) {} @@ -66,6 +70,17 @@ contract ORMP is ReentrancyGuard, Channel { return msgHash; } + /// @dev Import hash by any oracle address. + /// @notice Hash is an abstract of the proof system, it can be a block hash or a message root hash, + /// specifically provided by oracles. + /// @param srcChainId The source chain Id. + /// @param lookupKey The key for loop up hash. + /// @param hash_ The hash to import. + function importHash(uint256 srcChainId, bytes32 lookupKey, bytes32 hash_) external { + hashLookup[msg.sender][srcChainId][lookupKey] = hash_; + emit HashImported(srcChainId, msg.sender, lookupKey, hash_); + } + function _handleFee( address ua, address refund, diff --git a/src/eco/Oracle.sol b/src/eco/Oracle.sol index aee841e..d80becd 100644 --- a/src/eco/Oracle.sol +++ b/src/eco/Oracle.sol @@ -18,19 +18,19 @@ pragma solidity 0.8.17; import "../Verifier.sol"; +import "../interfaces/IORMP.sol"; contract Oracle is Verifier { event SetFee(uint256 indexed chainId, uint256 fee); event SetApproved(address operator, bool approve); event Withdrawal(address indexed to, uint256 amt); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); - event ImportedMessageRoot(uint256 indexed chainId, uint256 indexed blockHeight, bytes32 messageRoot); + + address public immutable PROTOCOL; address public owner; // chainId => price mapping(uint256 => uint256) public feeOf; - // chainId => blockNumber => messageRoot - mapping(uint256 => mapping(uint256 => bytes32)) rootOf; // operator => isApproved mapping(address => bool) public approvedOf; @@ -44,7 +44,8 @@ contract Oracle is Verifier { _; } - constructor(address dao) { + constructor(address dao, address ormp) { + PROTOCOL = ormp; owner = dao; } @@ -60,8 +61,7 @@ contract Oracle is Verifier { /// @param blockNumber The source chain block number. /// @param messageRoot The source chain message root corresponding to the channel. function importMessageRoot(uint256 chainId, uint256 blockNumber, bytes32 messageRoot) external onlyOwner { - rootOf[chainId][blockNumber] = messageRoot; - emit ImportedMessageRoot(chainId, blockNumber, messageRoot); + IORMP(PROTOCOL).importHash(chainId, bytes32(blockNumber), messageRoot); } function changeOwner(address newOwner) external onlyOwner { @@ -97,6 +97,6 @@ contract Oracle is Verifier { } function merkleRoot(uint256 chainId, uint256 blockNumber) public view override returns (bytes32) { - return rootOf[chainId][blockNumber]; + return IORMP(PROTOCOL).hashLookup(address(this), chainId, bytes32(blockNumber)); } } diff --git a/src/interfaces/IORMP.sol b/src/interfaces/IORMP.sol index 8dbd16a..ae694c4 100644 --- a/src/interfaces/IORMP.sol +++ b/src/interfaces/IORMP.sol @@ -74,4 +74,19 @@ interface IORMP { /// @param msgHash Hash of the checked message. /// @return Return the dispatched result of the checked message. function dones(bytes32 msgHash) external view returns (bool); + + /// @dev Import hash by any oracle address. + /// @notice Hash is an abstract of the proof system, it can be a block hash or a message root hash, + /// specifically provided by oracles. + /// @param srcChainId The source chain Id. + /// @param lookupKey The key for loop up hash. + /// @param hash_ The hash to import. + function importHash(uint256 srcChainId, bytes32 lookupKey, bytes32 hash_) external; + + /// @dev Fetch hash. + /// @param oracle The oracle address. + /// @param srcChainId The source chain Id. + /// @param lookupKey The key for loop up hash. + /// @return Return the hash imported by the oracle. + function hashLookup(address oracle, uint256 srcChainId, bytes32 lookupKey) external view returns (bytes32); } From 9ed249038a586fdc3e9fa8985501b30f773bd700 Mon Sep 17 00:00:00 2001 From: echo Date: Sun, 7 Apr 2024 17:26:14 +0800 Subject: [PATCH 4/4] fix test --- test/eco/Oracle.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/eco/Oracle.t.sol b/test/eco/Oracle.t.sol index 3037021..3ca0c32 100644 --- a/test/eco/Oracle.t.sol +++ b/test/eco/Oracle.t.sol @@ -71,7 +71,7 @@ contract OracleTest is Test { assertEq(r, bytes32(uint256(1))); } - function merkleRoot(uint256, uint256) external pure returns (bytes32) { + function hashLookup(address, uint256, bytes32) external pure returns (bytes32) { return bytes32(uint256(1)); } }