From c87d425240daec9d426c4cad6ab9b0dba29905d0 Mon Sep 17 00:00:00 2001 From: echo Date: Tue, 23 Jan 2024 15:47:04 +0800 Subject: [PATCH 1/9] Deploy OracleV2 on mainnet --- bin/dao.sh | 7 ++++--- bin/deploy.sh | 12 ++++++------ bin/fee.sh | 20 ++++++++++---------- bin/upgrade.sh | 16 ++++++++++++++++ bin/verify.sh | 6 +++--- script/deploy/Deploy.s.sol | 8 ++++---- script/input/1/fee.c.json | 2 +- script/input/42161/fee.c.json | 2 +- script/input/46/fee.c.json | 4 ++-- script/input/c3.json | 1 + script/output/1/OracleV2.v.json | 1 + script/output/1/deploy.a-latest.json | 2 +- script/output/42161/OracleV2.v.json | 1 + script/output/42161/deploy.a-latest.json | 2 +- script/output/46/OracleV2.v.json | 1 + script/output/46/deploy.a-latest.json | 2 +- 16 files changed, 54 insertions(+), 33 deletions(-) create mode 100755 bin/upgrade.sh create mode 100644 script/output/1/OracleV2.v.json create mode 100644 script/output/42161/OracleV2.v.json create mode 100644 script/output/46/OracleV2.v.json diff --git a/bin/dao.sh b/bin/dao.sh index ee55848..981dfdb 100755 --- a/bin/dao.sh +++ b/bin/dao.sh @@ -6,7 +6,7 @@ c3=$PWD/script/input/c3.json deployer=$(jq -r ".DEPLOYER" $c3) dao=$(jq -r ".MSGDAO" $c3) -subapi_dao=$(jq -r ".SUBAPIDAO_ADDR" $c3) +subapi_exe=$(jq -r ".SUBAPIEXECDAO_ADDR" $c3) ormp=$(jq -r ".ORMP_ADDR" $c3) oracle=$(jq -r ".ORACLEV2_ADDR" $c3) relayer=$(jq -r ".RELAYER_ADDR" $c3) @@ -25,5 +25,6 @@ set -x # seth send -F $deployer $relayer "changeOwner(address)" $dao --chain arbitrum # seth send -F $deployer $relayer "changeOwner(address)" $dao --chain ethereum -seth send -F $deployer $oracle "changeOwner(address)" $subapi_dao --chain crab -seth send -F $deployer $oracle "changeOwner(address)" $subapi_dao --chain sepolia +seth send -F $deployer $oracle "changeOwner(address)" $subapi_exe --chain crab +seth send -F $deployer $oracle "changeOwner(address)" $subapi_exe --chain sepolia +seth send -F $deployer $oracle "changeOwner(address)" $subapi_exe --chain arbitrum-sepolia diff --git a/bin/deploy.sh b/bin/deploy.sh index 4c579aa..316bb20 100755 --- a/bin/deploy.sh +++ b/bin/deploy.sh @@ -2,10 +2,10 @@ set -eo pipefail -# forge script script/deploy/Deploy.s.sol:Deploy --chain-id 1 --legacy --broadcast --verify --slow -# forge script script/deploy/Deploy.s.sol:Deploy --chain-id 46 --broadcast --verify --slow -# forge script script/deploy/Deploy.s.sol:Deploy --chain-id 42161 --broadcast --verify --slow --legacy +forge script script/deploy/Deploy.s.sol:Deploy --chain-id 1 --broadcast --verify --slow --legacy +forge script script/deploy/Deploy.s.sol:Deploy --chain-id 46 --broadcast --verify --slow +forge script script/deploy/Deploy.s.sol:Deploy --chain-id 42161 --broadcast --verify --slow --legacy -forge script script/deploy/Deploy.s.sol:Deploy --chain-id 44 --broadcast --verify --skip-simulation --slow -forge script script/deploy/Deploy.s.sol:Deploy --chain-id 421614 --broadcast --verify --skip-simulation --slow -forge script script/deploy/Deploy.s.sol:Deploy --chain-id 11155111 --broadcast --verify --skip-simulation --slow +# forge script script/deploy/Deploy.s.sol:Deploy --chain-id 44 --broadcast --verify --skip-simulation --slow +# forge script script/deploy/Deploy.s.sol:Deploy --chain-id 421614 --broadcast --verify --skip-simulation --slow +# forge script script/deploy/Deploy.s.sol:Deploy --chain-id 11155111 --broadcast --verify --skip-simulation --slow diff --git a/bin/fee.sh b/bin/fee.sh index d470821..8ca4933 100755 --- a/bin/fee.sh +++ b/bin/fee.sh @@ -3,18 +3,18 @@ set -eo pipefail set -x -# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 42161 --chain-id 46 --broadcast --slow -# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 1 --chain-id 46 --broadcast --slow -# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 42161 --broadcast --slow --legacy -# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 1 --chain-id 42161 --broadcast --slow --legacy -# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 1 --broadcast --slow --legacy -# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 42161 --chain-id 1 --broadcast --slow --legacy -# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 44 --broadcast --slow --legacy -# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 44 --chain-id 46 --broadcast --slow --legacy +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 42161 --chain-id 46 --broadcast --slow +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 1 --chain-id 46 --broadcast --slow +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 42161 --broadcast --slow --legacy +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 1 --chain-id 42161 --broadcast --slow --legacy +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 1 --broadcast --slow --legacy +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 42161 --chain-id 1 --broadcast --slow --legacy +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 44 --broadcast --slow --legacy +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 44 --chain-id 46 --broadcast --slow --legacy # forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 11155111 --chain-id 44 --broadcast # 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)" 421614 --chain-id 11155111 --broadcast # forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 44 --chain-id 11155111 --broadcast -forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 44 --chain-id 421614 --broadcast --skip-simulation --legacy -forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 11155111 --chain-id 421614 --broadcast --skip-simulation --legacy +# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 44 --chain-id 421614 --broadcast --skip-simulation --legacy +# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 11155111 --chain-id 421614 --broadcast --skip-simulation --legacy diff --git a/bin/upgrade.sh b/bin/upgrade.sh new file mode 100755 index 0000000..0e550f4 --- /dev/null +++ b/bin/upgrade.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -eo pipefail + +c3=$PWD/script/input/c3.json + +deployer=$(jq -r ".DEPLOYER" $c3) +ormp=$(jq -r ".ORMP_ADDR" $c3) +oracle=$(jq -r ".ORACLEV2_ADDR" $c3) +relayer=$(jq -r ".RELAYER_ADDR" $c3) + +set -x + +seth send -F $deployer $ormp "setDefaultConfig(address,address)" $oracle $relayer --chain crab +seth send -F $deployer $ormp "setDefaultConfig(address,address)" $oracle $relayer --chain sepolia +seth send -F $deployer $ormp "setDefaultConfig(address,address)" $oracle $relayer --chain arbitrum-sepolia diff --git a/bin/verify.sh b/bin/verify.sh index f2d1165..f91673c 100755 --- a/bin/verify.sh +++ b/bin/verify.sh @@ -27,9 +27,9 @@ verify() { $path > script/output/$chain_id/$name.v.json) } -verify $oracle 44 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/OracleV2.sol:OracleV2 -verify $oracle 11155111 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/OracleV2.sol:OracleV2 -verify $oracle 421614 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/OracleV2.sol:OracleV2 +verify $oracle 1 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/OracleV2.sol:OracleV2 +verify $oracle 46 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/OracleV2.sol:OracleV2 +verify $oracle 42161 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/OracleV2.sol:OracleV2 # verify $ormp 42161 $(cast abi-encode "constructor(address)" $deployer) src/ORMP.sol:ORMP # verify $ormp 46 $(cast abi-encode "constructor(address)" $deployer) src/ORMP.sol:ORMP diff --git a/script/deploy/Deploy.s.sol b/script/deploy/Deploy.s.sol index e90e14a..284a551 100644 --- a/script/deploy/Deploy.s.sol +++ b/script/deploy/Deploy.s.sol @@ -127,10 +127,10 @@ contract Deploy is Common { /// @notice Set the protocol config function setConfig() public broadcast { - ORMP(ORMP_ADDR).setDefaultConfig(ORACLE_ADDR, RELAYER_ADDR); - (address o, address r) = ORMP(ORMP_ADDR).defaultUC(); - require(o == ORACLE_ADDR, "!oracle"); - require(r == RELAYER_ADDR, "!relayer"); + // ORMP(ORMP_ADDR).setDefaultConfig(ORACLE_ADDR, RELAYER_ADDR); + // (address o, address r) = ORMP(ORMP_ADDR).defaultUC(); + // require(o == ORACLE_ADDR, "!oracle"); + // require(r == RELAYER_ADDR, "!relayer"); III(ORACLE_ADDR).setApproved(oracleOperator, true); require(III(ORACLE_ADDR).isApproved(oracleOperator), "!o-operator"); diff --git a/script/input/1/fee.c.json b/script/input/1/fee.c.json index 6845efe..80e2400 100644 --- a/script/input/1/fee.c.json +++ b/script/input/1/fee.c.json @@ -4,7 +4,7 @@ "fee": 20000000000000 }, "42161": { - "fee": 5000000000000000 + "fee": 400000000000000 } }, "RELAYER": { diff --git a/script/input/42161/fee.c.json b/script/input/42161/fee.c.json index 8cb88cf..b997932 100644 --- a/script/input/42161/fee.c.json +++ b/script/input/42161/fee.c.json @@ -4,7 +4,7 @@ "fee": 20000000000000 }, "1": { - "fee": 100000000000000000 + "fee": 4000000000000000 } }, "RELAYER": { diff --git a/script/input/46/fee.c.json b/script/input/46/fee.c.json index 0d90c45..4474d91 100644 --- a/script/input/46/fee.c.json +++ b/script/input/46/fee.c.json @@ -1,13 +1,13 @@ { "ORACLE": { "1": { - "fee": 55000000000000000000000 + "fee": 4000000000000000000000 }, "44": { "fee": 1000000000000000000 }, "42161": { - "fee": 2500000000000000000000 + "fee": 400000000000000000000 } }, "RELAYER": { diff --git a/script/input/c3.json b/script/input/c3.json index 0accfc0..e0cfab9 100644 --- a/script/input/c3.json +++ b/script/input/c3.json @@ -2,6 +2,7 @@ "DEPLOYER": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", "MSGDAO": "0x000000000879926D12aF396788C0785B7e581e53", "SUBAPIDAO_ADDR": "0x000000000a0D8ac9cc6CbD817fA77090322FF29d", + "SUBAPIEXECDAO_ADDR": "0x00000000079b20FEd6365B38f299D40236A90119", "ORMP_ADDR": "0x00000000001523057a05d6293C1e5171eE33eE0A", "ORMP_SALT": "0x4d629bbdb40d29206f12a51aa81faf14553b218f96845742a89e02e55ecfcef6", "ORACLEV2_ADDR": "0x0000000005Be70A35b6534bFBd21eC0c98B27b1f", diff --git a/script/output/1/OracleV2.v.json b/script/output/1/OracleV2.v.json new file mode 100644 index 0000000..e1db888 --- /dev/null +++ b/script/output/1/OracleV2.v.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/eco/OracleV2.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 OracleV2 is Verifier {\n event Assigned(bytes32 indexed msgHash, uint256 fee);\n event SetFee(uint256 indexed chainId, uint256 fee);\n event SetApproved(address operator, bool approve);\n event ImportedMessageRoot(uint256 indexed chainId, uint256 indexed blockHeight, bytes32 messageRoot);\n\n address public immutable PROTOCOL;\n\n address public owner;\n // chainId => price\n mapping(uint256 => uint256) public feeOf;\n // chainId => blockNumber => messageRoot\n mapping(uint256 => mapping(uint256 => bytes32)) rootOf;\n // operator => isApproved\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 importMessageRoot(uint256 chainId, uint256 blockNumber, bytes32 messageRoot) external onlyOwner {\n rootOf[chainId][blockNumber] = messageRoot;\n emit ImportedMessageRoot(chainId, blockNumber, messageRoot);\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 isApproved(address operator) public view returns (bool) {\n return approvedOf[operator];\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 fee(uint256 toChainId, address /*ua*/ ) public view returns (uint256) {\n uint256 f = feeOf[toChainId];\n require(f != 0, \"!fee\");\n return f;\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 return rootOf[chainId][blockNumber];\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 messageRootOf(uint256 chainid) 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/1/deploy.a-latest.json b/script/output/1/deploy.a-latest.json index 4bf9fcd..b06e3d2 100644 --- a/script/output/1/deploy.a-latest.json +++ b/script/output/1/deploy.a-latest.json @@ -1,6 +1,6 @@ { "DAO": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", - "ORACLE": "0x00000000046bc530804d66B6b64f7aF69B4E4E81", + "ORACLE": "0x0000000005Be70A35b6534bFBd21eC0c98B27b1f", "ORMP": "0x00000000001523057a05d6293C1e5171eE33eE0A", "RELAYER": "0x0000000000808fE9bDCc1d180EfbF5C53552a6b1" } \ No newline at end of file diff --git a/script/output/42161/OracleV2.v.json b/script/output/42161/OracleV2.v.json new file mode 100644 index 0000000..e1db888 --- /dev/null +++ b/script/output/42161/OracleV2.v.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/eco/OracleV2.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 OracleV2 is Verifier {\n event Assigned(bytes32 indexed msgHash, uint256 fee);\n event SetFee(uint256 indexed chainId, uint256 fee);\n event SetApproved(address operator, bool approve);\n event ImportedMessageRoot(uint256 indexed chainId, uint256 indexed blockHeight, bytes32 messageRoot);\n\n address public immutable PROTOCOL;\n\n address public owner;\n // chainId => price\n mapping(uint256 => uint256) public feeOf;\n // chainId => blockNumber => messageRoot\n mapping(uint256 => mapping(uint256 => bytes32)) rootOf;\n // operator => isApproved\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 importMessageRoot(uint256 chainId, uint256 blockNumber, bytes32 messageRoot) external onlyOwner {\n rootOf[chainId][blockNumber] = messageRoot;\n emit ImportedMessageRoot(chainId, blockNumber, messageRoot);\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 isApproved(address operator) public view returns (bool) {\n return approvedOf[operator];\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 fee(uint256 toChainId, address /*ua*/ ) public view returns (uint256) {\n uint256 f = feeOf[toChainId];\n require(f != 0, \"!fee\");\n return f;\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 return rootOf[chainId][blockNumber];\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 messageRootOf(uint256 chainid) 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/42161/deploy.a-latest.json b/script/output/42161/deploy.a-latest.json index 4bf9fcd..b06e3d2 100644 --- a/script/output/42161/deploy.a-latest.json +++ b/script/output/42161/deploy.a-latest.json @@ -1,6 +1,6 @@ { "DAO": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", - "ORACLE": "0x00000000046bc530804d66B6b64f7aF69B4E4E81", + "ORACLE": "0x0000000005Be70A35b6534bFBd21eC0c98B27b1f", "ORMP": "0x00000000001523057a05d6293C1e5171eE33eE0A", "RELAYER": "0x0000000000808fE9bDCc1d180EfbF5C53552a6b1" } \ No newline at end of file diff --git a/script/output/46/OracleV2.v.json b/script/output/46/OracleV2.v.json new file mode 100644 index 0000000..55faf1b --- /dev/null +++ b/script/output/46/OracleV2.v.json @@ -0,0 +1 @@ +{"language": "Solidity", "sources": {"src/eco/OracleV2.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 OracleV2 is Verifier {\n event Assigned(bytes32 indexed msgHash, uint256 fee);\n event SetFee(uint256 indexed chainId, uint256 fee);\n event SetApproved(address operator, bool approve);\n event ImportedMessageRoot(uint256 indexed chainId, uint256 indexed blockHeight, bytes32 messageRoot);\n\n address public immutable PROTOCOL;\n\n address public owner;\n // chainId => price\n mapping(uint256 => uint256) public feeOf;\n // chainId => blockNumber => messageRoot\n mapping(uint256 => mapping(uint256 => bytes32)) rootOf;\n // operator => isApproved\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 importMessageRoot(uint256 chainId, uint256 blockNumber, bytes32 messageRoot) external onlyOwner {\n rootOf[chainId][blockNumber] = messageRoot;\n emit ImportedMessageRoot(chainId, blockNumber, messageRoot);\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 isApproved(address operator) public view returns (bool) {\n return approvedOf[operator];\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 fee(uint256 toChainId, address /*ua*/ ) public view returns (uint256) {\n uint256 f = feeOf[toChainId];\n require(f != 0, \"!fee\");\n return f;\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 return rootOf[chainId][blockNumber];\n }\n}\n", "keccak256": "0x804d86bdc6ca5e0862ffb5ae237889fd313b27b286ad6876274980bc38a4a748"}, "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 messageRootOf(uint256 chainid) external view returns (bytes32);\n}\n", "keccak256": "0x573bea2faeba8db09c2cdf8524f6e56107b22274e024e8297f7ba31141e959e2"}, "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/OracleV2.sol": "OracleV2"}}} \ No newline at end of file diff --git a/script/output/46/deploy.a-latest.json b/script/output/46/deploy.a-latest.json index 4bf9fcd..b06e3d2 100644 --- a/script/output/46/deploy.a-latest.json +++ b/script/output/46/deploy.a-latest.json @@ -1,6 +1,6 @@ { "DAO": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", - "ORACLE": "0x00000000046bc530804d66B6b64f7aF69B4E4E81", + "ORACLE": "0x0000000005Be70A35b6534bFBd21eC0c98B27b1f", "ORMP": "0x00000000001523057a05d6293C1e5171eE33eE0A", "RELAYER": "0x0000000000808fE9bDCc1d180EfbF5C53552a6b1" } \ No newline at end of file From 81a975b589c9f7efc3ff87062653f19753b7c396 Mon Sep 17 00:00:00 2001 From: echo Date: Fri, 26 Jan 2024 14:07:25 +0800 Subject: [PATCH 2/9] set fee --- bin/fee.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/fee.sh b/bin/fee.sh index 8ca4933..bebe31d 100755 --- a/bin/fee.sh +++ b/bin/fee.sh @@ -5,10 +5,10 @@ set -eo pipefail set -x forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 42161 --chain-id 46 --broadcast --slow forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 1 --chain-id 46 --broadcast --slow -forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 42161 --broadcast --slow --legacy -forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 1 --chain-id 42161 --broadcast --slow --legacy -forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 1 --broadcast --slow --legacy -forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 42161 --chain-id 1 --broadcast --slow --legacy +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 42161 --broadcast --slow --legacy --skip-simulation +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 1 --chain-id 42161 --broadcast --slow --legacy --skip-simulation +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 1 --broadcast --slow --legacy +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 42161 --chain-id 1 --broadcast --slow --legacy forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 44 --broadcast --slow --legacy forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 44 --chain-id 46 --broadcast --slow --legacy From 0d4c3a6d2d336b6a7e55ed25eb2baf50d54ed861 Mon Sep 17 00:00:00 2001 From: echo Date: Wed, 31 Jan 2024 15:14:39 +0800 Subject: [PATCH 3/9] clean --- script/input/421613/deploy.c.json | 6 ------ script/input/421613/fee.c.json | 15 --------------- script/input/421613/oracle.c.json | 3 --- script/input/43/deploy.c.json | 6 ------ script/input/43/fee.c.json | 15 --------------- script/input/43/oracle.c.json | 3 --- 6 files changed, 48 deletions(-) delete mode 100644 script/input/421613/deploy.c.json delete mode 100644 script/input/421613/fee.c.json delete mode 100644 script/input/421613/oracle.c.json delete mode 100644 script/input/43/deploy.c.json delete mode 100644 script/input/43/fee.c.json delete mode 100644 script/input/43/oracle.c.json diff --git a/script/input/421613/deploy.c.json b/script/input/421613/deploy.c.json deleted file mode 100644 index 164a43d..0000000 --- a/script/input/421613/deploy.c.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "DAO": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", - "DEPLOYER": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", - "ORACLE_OPERATOR": "0x0b001c95E86D64C1Ad6e43944C568A6C31b53887", - "RELAYER_OPERATOR": "0x0b001c95E86D64C1Ad6e43944C568A6C31b53887" -} diff --git a/script/input/421613/fee.c.json b/script/input/421613/fee.c.json deleted file mode 100644 index 757a495..0000000 --- a/script/input/421613/fee.c.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "ORACLE": { - "43": { - "fee": 1000000000000000 - } - }, - "RELAYER": { - "43": { - "dstPriceRatio": 12000, - "dstGasPriceInWei": 180000000000, - "baseGas": 85000, - "gasPerByte": 16 - } - } -} diff --git a/script/input/421613/oracle.c.json b/script/input/421613/oracle.c.json deleted file mode 100644 index ff9af0b..0000000 --- a/script/input/421613/oracle.c.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "43": "0xa681492DBAd5a3999cFCE2d72196d5784dd08D0c" -} diff --git a/script/input/43/deploy.c.json b/script/input/43/deploy.c.json deleted file mode 100644 index 164a43d..0000000 --- a/script/input/43/deploy.c.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "DAO": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", - "DEPLOYER": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", - "ORACLE_OPERATOR": "0x0b001c95E86D64C1Ad6e43944C568A6C31b53887", - "RELAYER_OPERATOR": "0x0b001c95E86D64C1Ad6e43944C568A6C31b53887" -} diff --git a/script/input/43/fee.c.json b/script/input/43/fee.c.json deleted file mode 100644 index d09d3ef..0000000 --- a/script/input/43/fee.c.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "ORACLE": { - "421613": { - "fee": 100000000000000000000 - } - }, - "RELAYER": { - "421613": { - "dstPriceRatio": 9000000000000000, - "dstGasPriceInWei": 110000000, - "baseGas": 140000, - "gasPerByte": 16 - } - } -} diff --git a/script/input/43/oracle.c.json b/script/input/43/oracle.c.json deleted file mode 100644 index 1a5a4b8..0000000 --- a/script/input/43/oracle.c.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "421613": "0x770713580e5c618A4D29D7E8c0d7604276B63832" -} From 75b272410f71372966152984a2db1ade58acf4a3 Mon Sep 17 00:00:00 2001 From: echo Date: Wed, 31 Jan 2024 15:16:55 +0800 Subject: [PATCH 4/9] change base gas on ethereum --- bin/fee.sh | 18 +++++++++--------- script/fee/Fee.s.sol | 4 ++-- script/input/44/fee.c.json | 2 +- script/input/46/fee.c.json | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bin/fee.sh b/bin/fee.sh index bebe31d..4d41a17 100755 --- a/bin/fee.sh +++ b/bin/fee.sh @@ -3,16 +3,16 @@ set -eo pipefail set -x -forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 42161 --chain-id 46 --broadcast --slow -forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 1 --chain-id 46 --broadcast --slow -forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 42161 --broadcast --slow --legacy --skip-simulation -forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 1 --chain-id 42161 --broadcast --slow --legacy --skip-simulation -forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 1 --broadcast --slow --legacy -forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 42161 --chain-id 1 --broadcast --slow --legacy -forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 44 --broadcast --slow --legacy -forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 44 --chain-id 46 --broadcast --slow --legacy +# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 42161 --chain-id 46 --broadcast --slow +# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 1 --chain-id 46 --broadcast --slow +# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 42161 --broadcast --slow --legacy --skip-simulation +# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 1 --chain-id 42161 --broadcast --slow --legacy --skip-simulation +# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 1 --broadcast --slow --legacy +# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 42161 --chain-id 1 --broadcast --slow --legacy +# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 44 --broadcast --slow --legacy +# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 44 --chain-id 46 --broadcast --slow --legacy -# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 11155111 --chain-id 44 --broadcast +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 11155111 --chain-id 44 --broadcast # 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)" 421614 --chain-id 11155111 --broadcast # forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 44 --chain-id 11155111 --broadcast diff --git a/script/fee/Fee.s.sol b/script/fee/Fee.s.sol index 2022068..69912be 100644 --- a/script/fee/Fee.s.sol +++ b/script/fee/Fee.s.sol @@ -42,8 +42,8 @@ contract Fee is Common { function run(uint256 chainId) public { require(dao == msg.sender, "!dao"); - setOracleFee(chainId); - // setRelayerFee(chainId); + // setOracleFee(chainId); + setRelayerFee(chainId); } function setOracleFee(uint256 chainId) public broadcast { diff --git a/script/input/44/fee.c.json b/script/input/44/fee.c.json index 8374300..ce8e4f0 100644 --- a/script/input/44/fee.c.json +++ b/script/input/44/fee.c.json @@ -26,7 +26,7 @@ "11155111": { "dstPriceRatio": 9000000000000000, "dstGasPriceInWei": 1000000, - "baseGas": 200000, + "baseGas": 100000, "gasPerByte": 16 } } diff --git a/script/input/46/fee.c.json b/script/input/46/fee.c.json index 4474d91..7fede66 100644 --- a/script/input/46/fee.c.json +++ b/script/input/46/fee.c.json @@ -14,7 +14,7 @@ "1": { "dstPriceRatio": 9000000000000000, "dstGasPriceInWei": 50000000000, - "baseGas": 200000, + "baseGas": 100000, "gasPerByte": 16 }, "44": { From 3c17a30544c32ffd5571b40000e9856605172520 Mon Sep 17 00:00:00 2001 From: echo Date: Wed, 31 Jan 2024 15:18:39 +0800 Subject: [PATCH 5/9] change gas price on ethereum --- script/input/46/fee.c.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/input/46/fee.c.json b/script/input/46/fee.c.json index 7fede66..259c8c5 100644 --- a/script/input/46/fee.c.json +++ b/script/input/46/fee.c.json @@ -13,7 +13,7 @@ "RELAYER": { "1": { "dstPriceRatio": 9000000000000000, - "dstGasPriceInWei": 50000000000, + "dstGasPriceInWei": 40000000000, "baseGas": 100000, "gasPerByte": 16 }, From f17ca2d9452383d3c0907f91da56c2f5ef62b19b Mon Sep 17 00:00:00 2001 From: echo Date: Thu, 1 Feb 2024 14:58:35 +0800 Subject: [PATCH 6/9] fix #108 --- src/Verifier.sol | 6 ++---- src/eco/OracleV2.sol | 14 +++++++------- src/interfaces/IVerifier.sol | 4 ++-- test/Channel.t.sol | 4 ++-- test/ORMP.t.sol | 2 +- test/Verifier.t.sol | 2 +- test/bench/ORMP.b.sol | 3 +-- 7 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/Verifier.sol b/src/Verifier.sol index 2ca6f46..0ede474 100644 --- a/src/Verifier.sol +++ b/src/Verifier.sol @@ -22,17 +22,15 @@ import "./imt/IncrementalMerkleTree.sol"; abstract contract Verifier is IVerifier { /// @notice Message proof. - /// @param blockNumber The block number corresponding to the proof. /// @param messageIndex Leaf index of the message hash in incremental merkle tree. /// @param messageProof Merkle proof of the message hash. struct Proof { - uint256 blockNumber; uint256 messageIndex; bytes32[32] messageProof; } /// @inheritdoc IVerifier - function merkleRoot(uint256 chainId, uint256 blockNumber) public view virtual returns (bytes32); + function merkleRoot(uint256 chainId, uint256 messageIndex) public view virtual returns (bytes32); /// @inheritdoc IVerifier function verifyMessageProof(uint256 fromChainId, bytes32 msgHash, bytes calldata proof) @@ -44,7 +42,7 @@ abstract contract Verifier is IVerifier { Proof memory p = abi.decode(proof, (Proof)); // fetch message root in block number from chain - bytes32 imtRootOracle = merkleRoot(fromChainId, p.blockNumber); + bytes32 imtRootOracle = merkleRoot(fromChainId, p.messageIndex); // calculate the expected root based on the proof bytes32 imtRootProof = IncrementalMerkleTree.branchRoot(msgHash, p.messageProof, p.messageIndex); diff --git a/src/eco/OracleV2.sol b/src/eco/OracleV2.sol index 41aacb3..487ddc8 100644 --- a/src/eco/OracleV2.sol +++ b/src/eco/OracleV2.sol @@ -24,14 +24,14 @@ contract OracleV2 is Verifier { event Assigned(bytes32 indexed msgHash, uint256 fee); event SetFee(uint256 indexed chainId, uint256 fee); event SetApproved(address operator, bool approve); - event ImportedMessageRoot(uint256 indexed chainId, uint256 indexed blockHeight, bytes32 messageRoot); + event ImportedMessageRoot(uint256 indexed chainId, uint256 indexed messageIndex, bytes32 messageRoot); address public immutable PROTOCOL; address public owner; // chainId => price mapping(uint256 => uint256) public feeOf; - // chainId => blockNumber => messageRoot + // chainId => messageIndex => messageRoot mapping(uint256 => mapping(uint256 => bytes32)) rootOf; // operator => isApproved mapping(address => bool) public approvedOf; @@ -53,9 +53,9 @@ contract OracleV2 is Verifier { receive() external payable {} - function importMessageRoot(uint256 chainId, uint256 blockNumber, bytes32 messageRoot) external onlyOwner { - rootOf[chainId][blockNumber] = messageRoot; - emit ImportedMessageRoot(chainId, blockNumber, messageRoot); + function importMessageRoot(uint256 chainId, uint256 messageIndex, bytes32 messageRoot) external onlyOwner { + rootOf[chainId][messageIndex] = messageRoot; + emit ImportedMessageRoot(chainId, messageIndex, messageRoot); } function changeOwner(address owner_) external onlyOwner { @@ -92,7 +92,7 @@ contract OracleV2 is Verifier { emit Assigned(msgHash, msg.value); } - function merkleRoot(uint256 chainId, uint256 blockNumber) public view override returns (bytes32) { - return rootOf[chainId][blockNumber]; + function merkleRoot(uint256 chainId, uint256 messageIndex) public view override returns (bytes32) { + return rootOf[chainId][messageIndex]; } } diff --git a/src/interfaces/IVerifier.sol b/src/interfaces/IVerifier.sol index 5b25f7b..6c670d1 100644 --- a/src/interfaces/IVerifier.sol +++ b/src/interfaces/IVerifier.sol @@ -20,9 +20,9 @@ pragma solidity 0.8.17; interface IVerifier { /// @notice Fetch message root oracle. /// @param chainId The destination chain id. - /// @param blockNumber The block number where the message root is located. + /// @param messageIndex Leaf index of the message hash in incremental merkle tree. /// @return Message root in destination chain. - function merkleRoot(uint256 chainId, uint256 blockNumber) external view returns (bytes32); + function merkleRoot(uint256 chainId, uint256 messageIndex) external view returns (bytes32); /// @notice Verify message proof /// @dev Message proof provided by relayer. Oracle should provide message root of diff --git a/test/Channel.t.sol b/test/Channel.t.sol index d21ac3a..80fbb42 100644 --- a/test/Channel.t.sol +++ b/test/Channel.t.sol @@ -68,7 +68,7 @@ contract ChannelTest is Test, Verifier { encoded: "" }); assertEq(msgHash, hash(message)); - Proof memory proof = Proof({blockNumber: block.number, messageIndex: 0, messageProof: channel.prove()}); + Proof memory proof = Proof({messageIndex: 0, messageProof: channel.prove()}); vm.chainId(2); channel.recvMessage(message, abi.encode(proof)); } @@ -89,7 +89,7 @@ contract ChannelTest is Test, Verifier { encoded: "" }); assertEq(msgHash, hash(message)); - Proof memory proof = Proof({blockNumber: block.number, messageIndex: index, messageProof: channel.prove()}); + Proof memory proof = Proof({messageIndex: index, messageProof: channel.prove()}); vm.chainId(2); channel.recvMessage(message, abi.encode(proof)); } diff --git a/test/ORMP.t.sol b/test/ORMP.t.sol index 63edee3..da3d8e3 100644 --- a/test/ORMP.t.sol +++ b/test/ORMP.t.sol @@ -50,7 +50,7 @@ contract ORMPTest is Test, Verifier { function perform_send() public { uint256 f = ormp.fee(2, self, 0, "", ""); ormp.send{value: f}(2, self, 0, "", self, ""); - proof = Proof({blockNumber: block.number, messageIndex: ormp.messageCount() - 1, messageProof: ormp.prove()}); + proof = Proof({messageIndex: ormp.messageCount() - 1, messageProof: ormp.prove()}); vm.chainId(2); } diff --git a/test/Verifier.t.sol b/test/Verifier.t.sol index caff3e9..af4c27c 100644 --- a/test/Verifier.t.sol +++ b/test/Verifier.t.sol @@ -36,7 +36,7 @@ contract VerifierTest is Test, Verifier { function test_verifyMessageProof() public { bytes32 msgHash = bytes32(uint256(1)); imt.insert(msgHash); - Proof memory proof = Proof({blockNumber: block.number, messageIndex: 0, messageProof: zeroHashes}); + Proof memory proof = Proof({messageIndex: 0, messageProof: zeroHashes}); bool r = this.verifyMessageProof(1, msgHash, abi.encode(proof)); assertEq(r, true); } diff --git a/test/bench/ORMP.b.sol b/test/bench/ORMP.b.sol index fad756e..ba6d1f6 100644 --- a/test/bench/ORMP.b.sol +++ b/test/bench/ORMP.b.sol @@ -70,8 +70,7 @@ contract ORMPBenchmarkTest is Test { function perform_recv(Message memory message) public { root = ormp.root(); - Verifier.Proof memory proof = - Verifier.Proof({blockNumber: block.number, messageIndex: message.index, messageProof: ormp.prove()}); + Verifier.Proof memory proof = Verifier.Proof({messageIndex: message.index, messageProof: ormp.prove()}); vm.createSelectFork(message.toChainId.toChainName()); // TODO: setDefaltOracle From 2d601f4a3bd98da91b6d060f8ac2bb17f61f7040 Mon Sep 17 00:00:00 2001 From: echo Date: Thu, 1 Feb 2024 15:11:14 +0800 Subject: [PATCH 7/9] events --- bin/deploy.sh | 12 ++++++------ src/eco/OracleV2.sol | 9 +++++++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/bin/deploy.sh b/bin/deploy.sh index 316bb20..8f1406f 100755 --- a/bin/deploy.sh +++ b/bin/deploy.sh @@ -2,10 +2,10 @@ set -eo pipefail -forge script script/deploy/Deploy.s.sol:Deploy --chain-id 1 --broadcast --verify --slow --legacy -forge script script/deploy/Deploy.s.sol:Deploy --chain-id 46 --broadcast --verify --slow -forge script script/deploy/Deploy.s.sol:Deploy --chain-id 42161 --broadcast --verify --slow --legacy +# forge script script/deploy/Deploy.s.sol:Deploy --chain-id 1 --broadcast --verify --slow --legacy +# forge script script/deploy/Deploy.s.sol:Deploy --chain-id 46 --broadcast --verify --slow +# forge script script/deploy/Deploy.s.sol:Deploy --chain-id 42161 --broadcast --verify --slow --legacy -# forge script script/deploy/Deploy.s.sol:Deploy --chain-id 44 --broadcast --verify --skip-simulation --slow -# forge script script/deploy/Deploy.s.sol:Deploy --chain-id 421614 --broadcast --verify --skip-simulation --slow -# forge script script/deploy/Deploy.s.sol:Deploy --chain-id 11155111 --broadcast --verify --skip-simulation --slow +forge script script/deploy/Deploy.s.sol:Deploy --chain-id 44 --broadcast --verify --skip-simulation --slow +forge script script/deploy/Deploy.s.sol:Deploy --chain-id 421614 --broadcast --verify --skip-simulation --slow +forge script script/deploy/Deploy.s.sol:Deploy --chain-id 11155111 --broadcast --verify --skip-simulation --slow diff --git a/src/eco/OracleV2.sol b/src/eco/OracleV2.sol index 487ddc8..2792a95 100644 --- a/src/eco/OracleV2.sol +++ b/src/eco/OracleV2.sol @@ -24,6 +24,8 @@ contract OracleV2 is Verifier { event Assigned(bytes32 indexed msgHash, uint256 fee); 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 messageIndex, bytes32 messageRoot); address public immutable PROTOCOL; @@ -58,8 +60,10 @@ contract OracleV2 is Verifier { emit ImportedMessageRoot(chainId, messageIndex, 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 { @@ -74,6 +78,7 @@ contract OracleV2 is Verifier { 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 { From c50834532cf64632533d9b083f7d9af9c8c3121d Mon Sep 17 00:00:00 2001 From: echo Date: Thu, 1 Feb 2024 15:39:18 +0800 Subject: [PATCH 8/9] clean --- src/eco/OracleV2.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/src/eco/OracleV2.sol b/src/eco/OracleV2.sol index 2792a95..476ccdb 100644 --- a/src/eco/OracleV2.sol +++ b/src/eco/OracleV2.sol @@ -18,7 +18,6 @@ pragma solidity 0.8.17; import "../Verifier.sol"; -import "../interfaces/IFeedOracle.sol"; contract OracleV2 is Verifier { event Assigned(bytes32 indexed msgHash, uint256 fee); From d7497174d99ebe249ee38a3c9297f4d86da522d8 Mon Sep 17 00:00:00 2001 From: echo Date: Thu, 1 Feb 2024 15:57:51 +0800 Subject: [PATCH 9/9] redeploy --- README.md | 2 +- bin/dao.sh | 8 ++++---- bin/deploy.sh | 1 + bin/fee.sh | 12 ++++++------ bin/verify.sh | 10 +++++++--- script/fee/Fee.s.sol | 4 ++-- script/input/c3.json | 7 +++---- script/output/11155111/OracleV2.v.json | 2 +- script/output/11155111/deploy.a-latest.json | 2 +- script/output/421614/OracleV2.v.json | 2 +- script/output/421614/deploy.a-latest.json | 2 +- script/output/44/OracleV2.v.json | 2 +- script/output/44/deploy.a-latest.json | 2 +- 13 files changed, 30 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index f2a96df..c58de4b 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Oracle and Relayer based Message Protocol. |------------|--------------------------------------------| | ORMP | 0x00000000001523057a05d6293C1e5171eE33eE0A | | Oracle | 0x00000000046bc530804d66B6b64f7aF69B4E4E81 | -| OracleV2 | 0x0000000005Be70A35b6534bFBd21eC0c98B27b1f | +| OracleV2 | 0x0000000004A34ac73374b65a55C93CF9D4Bc3d17 | | Relayer | 0x0000000000808fE9bDCc1d180EfbF5C53552a6b1 | | MsgDAO | 0x000000000879926D12aF396788C0785B7e581e53 | diff --git a/bin/dao.sh b/bin/dao.sh index 981dfdb..4634b1f 100755 --- a/bin/dao.sh +++ b/bin/dao.sh @@ -6,7 +6,7 @@ c3=$PWD/script/input/c3.json deployer=$(jq -r ".DEPLOYER" $c3) dao=$(jq -r ".MSGDAO" $c3) -subapi_exe=$(jq -r ".SUBAPIEXECDAO_ADDR" $c3) +subapi_multisig=$(jq -r ".SUBAPIMULTISIG" $c3) ormp=$(jq -r ".ORMP_ADDR" $c3) oracle=$(jq -r ".ORACLEV2_ADDR" $c3) relayer=$(jq -r ".RELAYER_ADDR" $c3) @@ -25,6 +25,6 @@ set -x # seth send -F $deployer $relayer "changeOwner(address)" $dao --chain arbitrum # seth send -F $deployer $relayer "changeOwner(address)" $dao --chain ethereum -seth send -F $deployer $oracle "changeOwner(address)" $subapi_exe --chain crab -seth send -F $deployer $oracle "changeOwner(address)" $subapi_exe --chain sepolia -seth send -F $deployer $oracle "changeOwner(address)" $subapi_exe --chain arbitrum-sepolia +seth send -F $deployer $oracle "changeOwner(address)" $subapi_multisig --chain crab +seth send -F $deployer $oracle "changeOwner(address)" $subapi_multisig --chain sepolia +seth send -F $deployer $oracle "changeOwner(address)" $subapi_multisig --chain arbitrum-sepolia diff --git a/bin/deploy.sh b/bin/deploy.sh index 8f1406f..e94b2b7 100755 --- a/bin/deploy.sh +++ b/bin/deploy.sh @@ -6,6 +6,7 @@ set -eo pipefail # forge script script/deploy/Deploy.s.sol:Deploy --chain-id 46 --broadcast --verify --slow # forge script script/deploy/Deploy.s.sol:Deploy --chain-id 42161 --broadcast --verify --slow --legacy +# forge script script/deploy/Deploy.s.sol:Deploy --chain-id 43 --broadcast --verify --skip-simulation --slow forge script script/deploy/Deploy.s.sol:Deploy --chain-id 44 --broadcast --verify --skip-simulation --slow forge script script/deploy/Deploy.s.sol:Deploy --chain-id 421614 --broadcast --verify --skip-simulation --slow forge script script/deploy/Deploy.s.sol:Deploy --chain-id 11155111 --broadcast --verify --skip-simulation --slow diff --git a/bin/fee.sh b/bin/fee.sh index 4d41a17..2c4828d 100755 --- a/bin/fee.sh +++ b/bin/fee.sh @@ -12,9 +12,9 @@ set -x # forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 44 --broadcast --slow --legacy # forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 44 --chain-id 46 --broadcast --slow --legacy -forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 11155111 --chain-id 44 --broadcast -# 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)" 421614 --chain-id 11155111 --broadcast -# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 44 --chain-id 11155111 --broadcast -# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 44 --chain-id 421614 --broadcast --skip-simulation --legacy -# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 11155111 --chain-id 421614 --broadcast --skip-simulation --legacy +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 11155111 --chain-id 44 --broadcast --slow +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 421614 --chain-id 44 --broadcast --slow +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 421614 --chain-id 11155111 --broadcast --slow +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 44 --chain-id 11155111 --broadcast --slow +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 44 --chain-id 421614 --broadcast --skip-simulation --legacy --slow +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 11155111 --chain-id 421614 --broadcast --skip-simulation --legacy --slow diff --git a/bin/verify.sh b/bin/verify.sh index f91673c..1b505af 100755 --- a/bin/verify.sh +++ b/bin/verify.sh @@ -27,9 +27,13 @@ verify() { $path > script/output/$chain_id/$name.v.json) } -verify $oracle 1 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/OracleV2.sol:OracleV2 -verify $oracle 46 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/OracleV2.sol:OracleV2 -verify $oracle 42161 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/OracleV2.sol:OracleV2 +# verify $oracle 1 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/OracleV2.sol:OracleV2 +# verify $oracle 46 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/OracleV2.sol:OracleV2 +# verify $oracle 42161 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/OracleV2.sol:OracleV2 + +verify $oracle 44 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/OracleV2.sol:OracleV2 +verify $oracle 421614 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/OracleV2.sol:OracleV2 +verify $oracle 11155111 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/OracleV2.sol:OracleV2 # verify $ormp 42161 $(cast abi-encode "constructor(address)" $deployer) src/ORMP.sol:ORMP # verify $ormp 46 $(cast abi-encode "constructor(address)" $deployer) src/ORMP.sol:ORMP diff --git a/script/fee/Fee.s.sol b/script/fee/Fee.s.sol index 69912be..2022068 100644 --- a/script/fee/Fee.s.sol +++ b/script/fee/Fee.s.sol @@ -42,8 +42,8 @@ contract Fee is Common { function run(uint256 chainId) public { require(dao == msg.sender, "!dao"); - // setOracleFee(chainId); - setRelayerFee(chainId); + setOracleFee(chainId); + // setRelayerFee(chainId); } function setOracleFee(uint256 chainId) public broadcast { diff --git a/script/input/c3.json b/script/input/c3.json index e0cfab9..d3114d4 100644 --- a/script/input/c3.json +++ b/script/input/c3.json @@ -1,12 +1,11 @@ { "DEPLOYER": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", "MSGDAO": "0x000000000879926D12aF396788C0785B7e581e53", - "SUBAPIDAO_ADDR": "0x000000000a0D8ac9cc6CbD817fA77090322FF29d", - "SUBAPIEXECDAO_ADDR": "0x00000000079b20FEd6365B38f299D40236A90119", + "SUBAPIMULTISIG": "0x0000000004127035e3559B9E3376e9DF07822B1E", "ORMP_ADDR": "0x00000000001523057a05d6293C1e5171eE33eE0A", "ORMP_SALT": "0x4d629bbdb40d29206f12a51aa81faf14553b218f96845742a89e02e55ecfcef6", - "ORACLEV2_ADDR": "0x0000000005Be70A35b6534bFBd21eC0c98B27b1f", - "ORACLEV2_SALT": "0x7c4504befd2e385553429cae4be5837dbcd7532285439afb4aca7808356cc12d", + "ORACLEV2_ADDR": "0x0000000004A34ac73374b65a55C93CF9D4Bc3d17", + "ORACLEV2_SALT": "0xdd9400fe0ca3f3183153937a7a1209e1b21fbf038eb74b835dd874301323965e", "RELAYER_ADDR": "0x0000000000808fE9bDCc1d180EfbF5C53552a6b1", "RELAYER_SALT": "0x9d38bcb32422a45bc9c08605d4457bcd3dadddfee1573a352ace5f1defa45621" } diff --git a/script/output/11155111/OracleV2.v.json b/script/output/11155111/OracleV2.v.json index e1db888..7303d0d 100644 --- a/script/output/11155111/OracleV2.v.json +++ b/script/output/11155111/OracleV2.v.json @@ -1 +1 @@ -{"language":"Solidity","sources":{"src/eco/OracleV2.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 OracleV2 is Verifier {\n event Assigned(bytes32 indexed msgHash, uint256 fee);\n event SetFee(uint256 indexed chainId, uint256 fee);\n event SetApproved(address operator, bool approve);\n event ImportedMessageRoot(uint256 indexed chainId, uint256 indexed blockHeight, bytes32 messageRoot);\n\n address public immutable PROTOCOL;\n\n address public owner;\n // chainId => price\n mapping(uint256 => uint256) public feeOf;\n // chainId => blockNumber => messageRoot\n mapping(uint256 => mapping(uint256 => bytes32)) rootOf;\n // operator => isApproved\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 importMessageRoot(uint256 chainId, uint256 blockNumber, bytes32 messageRoot) external onlyOwner {\n rootOf[chainId][blockNumber] = messageRoot;\n emit ImportedMessageRoot(chainId, blockNumber, messageRoot);\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 isApproved(address operator) public view returns (bool) {\n return approvedOf[operator];\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 fee(uint256 toChainId, address /*ua*/ ) public view returns (uint256) {\n uint256 f = feeOf[toChainId];\n require(f != 0, \"!fee\");\n return f;\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 return rootOf[chainId][blockNumber];\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 messageRootOf(uint256 chainid) 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":{}}} +{"language":"Solidity","sources":{"src/eco/OracleV2.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\";\n\ncontract OracleV2 is Verifier {\n event Assigned(bytes32 indexed msgHash, uint256 fee);\n event SetFee(uint256 indexed chainId, uint256 fee);\n event SetApproved(address operator, bool approve);\n event Withdrawal(address indexed to, uint256 amt);\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n event ImportedMessageRoot(uint256 indexed chainId, uint256 indexed messageIndex, bytes32 messageRoot);\n\n address public immutable PROTOCOL;\n\n address public owner;\n // chainId => price\n mapping(uint256 => uint256) public feeOf;\n // chainId => messageIndex => messageRoot\n mapping(uint256 => mapping(uint256 => bytes32)) rootOf;\n // operator => isApproved\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 importMessageRoot(uint256 chainId, uint256 messageIndex, bytes32 messageRoot) external onlyOwner {\n rootOf[chainId][messageIndex] = messageRoot;\n emit ImportedMessageRoot(chainId, messageIndex, messageRoot);\n }\n\n function changeOwner(address newOwner) external onlyOwner {\n address oldOwner = owner;\n owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n\n function setApproved(address operator, bool approve) external onlyOwner {\n approvedOf[operator] = approve;\n emit SetApproved(operator, approve);\n }\n\n function isApproved(address operator) public view returns (bool) {\n return approvedOf[operator];\n }\n\n function withdraw(address to, uint256 amount) external onlyApproved {\n (bool success,) = to.call{value: amount}(\"\");\n require(success, \"!withdraw\");\n emit Withdrawal(to, amount);\n }\n\n function setFee(uint256 chainId, uint256 fee_) external onlyApproved {\n feeOf[chainId] = fee_;\n emit SetFee(chainId, fee_);\n }\n\n function fee(uint256 toChainId, address /*ua*/ ) public view returns (uint256) {\n uint256 f = feeOf[toChainId];\n require(f != 0, \"!fee\");\n return f;\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 messageIndex) public view override returns (bytes32) {\n return rootOf[chainId][messageIndex];\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 messageIndex;\n bytes32[32] messageProof;\n }\n\n /// @inheritdoc IVerifier\n function merkleRoot(uint256 chainId, uint256 messageIndex) 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.messageIndex);\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/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 messageIndex Leaf index of the message hash in incremental merkle tree.\n /// @return Message root in destination chain.\n function merkleRoot(uint256 chainId, uint256 messageIndex) 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/11155111/deploy.a-latest.json b/script/output/11155111/deploy.a-latest.json index b06e3d2..7e30eed 100644 --- a/script/output/11155111/deploy.a-latest.json +++ b/script/output/11155111/deploy.a-latest.json @@ -1,6 +1,6 @@ { "DAO": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", - "ORACLE": "0x0000000005Be70A35b6534bFBd21eC0c98B27b1f", + "ORACLE": "0x0000000004A34ac73374b65a55C93CF9D4Bc3d17", "ORMP": "0x00000000001523057a05d6293C1e5171eE33eE0A", "RELAYER": "0x0000000000808fE9bDCc1d180EfbF5C53552a6b1" } \ No newline at end of file diff --git a/script/output/421614/OracleV2.v.json b/script/output/421614/OracleV2.v.json index e1db888..7303d0d 100644 --- a/script/output/421614/OracleV2.v.json +++ b/script/output/421614/OracleV2.v.json @@ -1 +1 @@ -{"language":"Solidity","sources":{"src/eco/OracleV2.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 OracleV2 is Verifier {\n event Assigned(bytes32 indexed msgHash, uint256 fee);\n event SetFee(uint256 indexed chainId, uint256 fee);\n event SetApproved(address operator, bool approve);\n event ImportedMessageRoot(uint256 indexed chainId, uint256 indexed blockHeight, bytes32 messageRoot);\n\n address public immutable PROTOCOL;\n\n address public owner;\n // chainId => price\n mapping(uint256 => uint256) public feeOf;\n // chainId => blockNumber => messageRoot\n mapping(uint256 => mapping(uint256 => bytes32)) rootOf;\n // operator => isApproved\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 importMessageRoot(uint256 chainId, uint256 blockNumber, bytes32 messageRoot) external onlyOwner {\n rootOf[chainId][blockNumber] = messageRoot;\n emit ImportedMessageRoot(chainId, blockNumber, messageRoot);\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 isApproved(address operator) public view returns (bool) {\n return approvedOf[operator];\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 fee(uint256 toChainId, address /*ua*/ ) public view returns (uint256) {\n uint256 f = feeOf[toChainId];\n require(f != 0, \"!fee\");\n return f;\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 return rootOf[chainId][blockNumber];\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 messageRootOf(uint256 chainid) 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":{}}} +{"language":"Solidity","sources":{"src/eco/OracleV2.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\";\n\ncontract OracleV2 is Verifier {\n event Assigned(bytes32 indexed msgHash, uint256 fee);\n event SetFee(uint256 indexed chainId, uint256 fee);\n event SetApproved(address operator, bool approve);\n event Withdrawal(address indexed to, uint256 amt);\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n event ImportedMessageRoot(uint256 indexed chainId, uint256 indexed messageIndex, bytes32 messageRoot);\n\n address public immutable PROTOCOL;\n\n address public owner;\n // chainId => price\n mapping(uint256 => uint256) public feeOf;\n // chainId => messageIndex => messageRoot\n mapping(uint256 => mapping(uint256 => bytes32)) rootOf;\n // operator => isApproved\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 importMessageRoot(uint256 chainId, uint256 messageIndex, bytes32 messageRoot) external onlyOwner {\n rootOf[chainId][messageIndex] = messageRoot;\n emit ImportedMessageRoot(chainId, messageIndex, messageRoot);\n }\n\n function changeOwner(address newOwner) external onlyOwner {\n address oldOwner = owner;\n owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n\n function setApproved(address operator, bool approve) external onlyOwner {\n approvedOf[operator] = approve;\n emit SetApproved(operator, approve);\n }\n\n function isApproved(address operator) public view returns (bool) {\n return approvedOf[operator];\n }\n\n function withdraw(address to, uint256 amount) external onlyApproved {\n (bool success,) = to.call{value: amount}(\"\");\n require(success, \"!withdraw\");\n emit Withdrawal(to, amount);\n }\n\n function setFee(uint256 chainId, uint256 fee_) external onlyApproved {\n feeOf[chainId] = fee_;\n emit SetFee(chainId, fee_);\n }\n\n function fee(uint256 toChainId, address /*ua*/ ) public view returns (uint256) {\n uint256 f = feeOf[toChainId];\n require(f != 0, \"!fee\");\n return f;\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 messageIndex) public view override returns (bytes32) {\n return rootOf[chainId][messageIndex];\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 messageIndex;\n bytes32[32] messageProof;\n }\n\n /// @inheritdoc IVerifier\n function merkleRoot(uint256 chainId, uint256 messageIndex) 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.messageIndex);\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/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 messageIndex Leaf index of the message hash in incremental merkle tree.\n /// @return Message root in destination chain.\n function merkleRoot(uint256 chainId, uint256 messageIndex) 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/deploy.a-latest.json b/script/output/421614/deploy.a-latest.json index b06e3d2..7e30eed 100644 --- a/script/output/421614/deploy.a-latest.json +++ b/script/output/421614/deploy.a-latest.json @@ -1,6 +1,6 @@ { "DAO": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", - "ORACLE": "0x0000000005Be70A35b6534bFBd21eC0c98B27b1f", + "ORACLE": "0x0000000004A34ac73374b65a55C93CF9D4Bc3d17", "ORMP": "0x00000000001523057a05d6293C1e5171eE33eE0A", "RELAYER": "0x0000000000808fE9bDCc1d180EfbF5C53552a6b1" } \ No newline at end of file diff --git a/script/output/44/OracleV2.v.json b/script/output/44/OracleV2.v.json index 55faf1b..72af88c 100644 --- a/script/output/44/OracleV2.v.json +++ b/script/output/44/OracleV2.v.json @@ -1 +1 @@ -{"language": "Solidity", "sources": {"src/eco/OracleV2.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 OracleV2 is Verifier {\n event Assigned(bytes32 indexed msgHash, uint256 fee);\n event SetFee(uint256 indexed chainId, uint256 fee);\n event SetApproved(address operator, bool approve);\n event ImportedMessageRoot(uint256 indexed chainId, uint256 indexed blockHeight, bytes32 messageRoot);\n\n address public immutable PROTOCOL;\n\n address public owner;\n // chainId => price\n mapping(uint256 => uint256) public feeOf;\n // chainId => blockNumber => messageRoot\n mapping(uint256 => mapping(uint256 => bytes32)) rootOf;\n // operator => isApproved\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 importMessageRoot(uint256 chainId, uint256 blockNumber, bytes32 messageRoot) external onlyOwner {\n rootOf[chainId][blockNumber] = messageRoot;\n emit ImportedMessageRoot(chainId, blockNumber, messageRoot);\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 isApproved(address operator) public view returns (bool) {\n return approvedOf[operator];\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 fee(uint256 toChainId, address /*ua*/ ) public view returns (uint256) {\n uint256 f = feeOf[toChainId];\n require(f != 0, \"!fee\");\n return f;\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 return rootOf[chainId][blockNumber];\n }\n}\n", "keccak256": "0x804d86bdc6ca5e0862ffb5ae237889fd313b27b286ad6876274980bc38a4a748"}, "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 messageRootOf(uint256 chainid) external view returns (bytes32);\n}\n", "keccak256": "0x573bea2faeba8db09c2cdf8524f6e56107b22274e024e8297f7ba31141e959e2"}, "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/OracleV2.sol": "OracleV2"}}} \ No newline at end of file +{"language": "Solidity", "sources": {"src/eco/OracleV2.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\";\n\ncontract OracleV2 is Verifier {\n event Assigned(bytes32 indexed msgHash, uint256 fee);\n event SetFee(uint256 indexed chainId, uint256 fee);\n event SetApproved(address operator, bool approve);\n event Withdrawal(address indexed to, uint256 amt);\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n event ImportedMessageRoot(uint256 indexed chainId, uint256 indexed messageIndex, bytes32 messageRoot);\n\n address public immutable PROTOCOL;\n\n address public owner;\n // chainId => price\n mapping(uint256 => uint256) public feeOf;\n // chainId => messageIndex => messageRoot\n mapping(uint256 => mapping(uint256 => bytes32)) rootOf;\n // operator => isApproved\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 importMessageRoot(uint256 chainId, uint256 messageIndex, bytes32 messageRoot) external onlyOwner {\n rootOf[chainId][messageIndex] = messageRoot;\n emit ImportedMessageRoot(chainId, messageIndex, messageRoot);\n }\n\n function changeOwner(address newOwner) external onlyOwner {\n address oldOwner = owner;\n owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n\n function setApproved(address operator, bool approve) external onlyOwner {\n approvedOf[operator] = approve;\n emit SetApproved(operator, approve);\n }\n\n function isApproved(address operator) public view returns (bool) {\n return approvedOf[operator];\n }\n\n function withdraw(address to, uint256 amount) external onlyApproved {\n (bool success,) = to.call{value: amount}(\"\");\n require(success, \"!withdraw\");\n emit Withdrawal(to, amount);\n }\n\n function setFee(uint256 chainId, uint256 fee_) external onlyApproved {\n feeOf[chainId] = fee_;\n emit SetFee(chainId, fee_);\n }\n\n function fee(uint256 toChainId, address /*ua*/ ) public view returns (uint256) {\n uint256 f = feeOf[toChainId];\n require(f != 0, \"!fee\");\n return f;\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 messageIndex) public view override returns (bytes32) {\n return rootOf[chainId][messageIndex];\n }\n}\n", "keccak256": "0xf699f727d13c4d506dc15b9dad2f16668b6750e049d7cc44c2079e67700e9027"}, "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 messageIndex;\n bytes32[32] messageProof;\n }\n\n /// @inheritdoc IVerifier\n function merkleRoot(uint256 chainId, uint256 messageIndex) 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.messageIndex);\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": "0x08f06c2b65b57e30c57fb088e1adf9236480a936414a16f3694feff19ca3e970"}, "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 messageIndex Leaf index of the message hash in incremental merkle tree.\n /// @return Message root in destination chain.\n function merkleRoot(uint256 chainId, uint256 messageIndex) 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": "0x4b7161a706bb8aa2fad647c374317eeea786113e0cb63db04176eed693f43c43"}, "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/OracleV2.sol": "OracleV2"}}} \ 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 b06e3d2..7e30eed 100644 --- a/script/output/44/deploy.a-latest.json +++ b/script/output/44/deploy.a-latest.json @@ -1,6 +1,6 @@ { "DAO": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", - "ORACLE": "0x0000000005Be70A35b6534bFBd21eC0c98B27b1f", + "ORACLE": "0x0000000004A34ac73374b65a55C93CF9D4Bc3d17", "ORMP": "0x00000000001523057a05d6293C1e5171eE33eE0A", "RELAYER": "0x0000000000808fE9bDCc1d180EfbF5C53552a6b1" } \ No newline at end of file