From 65995d789554efa71c4d8c3daa81d4c2e9d1f5bc Mon Sep 17 00:00:00 2001 From: echo Date: Thu, 29 Feb 2024 15:30:18 +0800 Subject: [PATCH] Support Polygon (#122) * support polygon config * polygon network config * upgrade lib/create3-deploy * support polygon * transfer ownership to dao --- README.md | 1 + bin/dao.sh | 11 +++++++---- bin/deploy.sh | 9 +++++---- bin/fee.sh | 6 ++++-- bin/verify.sh | 11 +++++++---- foundry.toml | 2 ++ lib/create3-deploy | 2 +- script/deploy/Deploy.s.sol | 14 +++++++------- script/fee/Fee.s.sol | 2 +- script/input/137/deploy.c.json | 6 ++++++ script/input/137/fee.c.json | 15 +++++++++++++++ script/input/46/fee.c.json | 9 +++++++++ script/output/137/ORMP.v.json | 1 + script/output/137/ORMPOracle.v.json | 1 + script/output/137/Relayer.v.json | 1 + script/output/137/deploy.a-latest.json | 6 ++++++ 16 files changed, 74 insertions(+), 23 deletions(-) create mode 100644 script/input/137/deploy.c.json create mode 100644 script/input/137/fee.c.json create mode 100644 script/output/137/ORMP.v.json create mode 100644 script/output/137/ORMPOracle.v.json create mode 100644 script/output/137/Relayer.v.json create mode 100644 script/output/137/deploy.a-latest.json diff --git a/README.md b/README.md index 418c2a7..2a6baf2 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Oracle and Relayer based Message Protocol. - Crab - Darwinia - Ethereum +- Polygon ### Testnet - Arbitrum Sepolia diff --git a/bin/dao.sh b/bin/dao.sh index 95c5e27..6178c3d 100755 --- a/bin/dao.sh +++ b/bin/dao.sh @@ -29,7 +29,10 @@ set -x # seth send -F $deployer $oracle "changeOwner(address)" $subapi_multisig --chain sepolia # seth send -F $deployer $oracle "changeOwner(address)" $subapi_multisig --chain arbitrum-sepolia -seth send -F $deployer $oracle "changeOwner(address)" $subapi_multisig --chain crab -seth send -F $deployer $oracle "changeOwner(address)" $subapi_multisig --chain darwinia -seth send -F $deployer $oracle "changeOwner(address)" $subapi_multisig --chain ethereum -seth send -F $deployer $oracle "changeOwner(address)" $subapi_multisig --chain arbitrum +# seth send -F $deployer $oracle "changeOwner(address)" $subapi_multisig --chain crab +# seth send -F $deployer $oracle "changeOwner(address)" $subapi_multisig --chain darwinia +# seth send -F $deployer $oracle "changeOwner(address)" $subapi_multisig --chain ethereum +# seth send -F $deployer $oracle "changeOwner(address)" $subapi_multisig --chain arbitrum +# seth send -F $deployer $oracle "changeOwner(address)" $subapi_multisig --chain polygon +seth send -F $deployer $relayer "changeOwner(address)" $dao --chain polygon +seth send -F $deployer $ormp "changeSetter(address)" $dao --chain polygon diff --git a/bin/deploy.sh b/bin/deploy.sh index 139c659..ba2ddd8 100755 --- a/bin/deploy.sh +++ b/bin/deploy.sh @@ -2,10 +2,11 @@ set -eo pipefail -forge script script/deploy/Deploy.s.sol:Deploy --chain-id 1 --broadcast --verify --slow -forge script script/deploy/Deploy.s.sol:Deploy --chain-id 44 --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 --skip-simulation +# forge script script/deploy/Deploy.s.sol:Deploy --chain-id 1 --broadcast --verify --slow +# forge script script/deploy/Deploy.s.sol:Deploy --chain-id 44 --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 137 --broadcast --verify +# forge script script/deploy/Deploy.s.sol:Deploy --chain-id 42161 --broadcast --verify --slow --legacy --skip-simulation # forge script script/deploy/Deploy.s.sol:Deploy --chain-id 43 --broadcast --verify --skip-simulation # forge script script/deploy/Deploy.s.sol:Deploy --chain-id 421614 --broadcast --verify --skip-simulation --slow diff --git a/bin/fee.sh b/bin/fee.sh index b7f049e..7b87d75 100755 --- a/bin/fee.sh +++ b/bin/fee.sh @@ -6,11 +6,13 @@ set -x # forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 1 --broadcast --slow # forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 42161 --chain-id 1 --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)" 42161 --chain-id 46 --broadcast --slow -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)" 44 --chain-id 46 --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 44 --broadcast --slow --legacy +# forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 46 --chain-id 137 --broadcast +forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 137 --chain-id 46 --broadcast --slow --legacy # forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 11155111 --chain-id 43 --broadcast # forge script script/fee/Fee.s.sol:Fee --sig "run(uint256)" 421614 --chain-id 43 --broadcast diff --git a/bin/verify.sh b/bin/verify.sh index 1944666..c222d72 100755 --- a/bin/verify.sh +++ b/bin/verify.sh @@ -31,19 +31,22 @@ verify() { # 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/ORMPOracle.sol:ORMPOracle -verify $oracle 44 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/ORMPOracle.sol:ORMPOracle -verify $oracle 46 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/ORMPOracle.sol:ORMPOracle -verify $oracle 42161 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/ORMPOracle.sol:ORMPOracle +# verify $oracle 1 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/ORMPOracle.sol:ORMPOracle +# verify $oracle 44 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/ORMPOracle.sol:ORMPOracle +# verify $oracle 46 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/ORMPOracle.sol:ORMPOracle +verify $oracle 137 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/ORMPOracle.sol:ORMPOracle +# verify $oracle 42161 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/ORMPOracle.sol:ORMPOracle # verify $oracle 421614 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/ORMPOracle.sol:ORMPOracle # verify $oracle 11155111 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/ORMPOracle.sol:ORMPOracle # 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 +verify $ormp 137 $(cast abi-encode "constructor(address)" $deployer) src/ORMP.sol:ORMP # verify $oracle 42161 $(cast abi-encode "constructor(address,address,address)" $deployer $ormp $subapi) src/eco/Oracle.sol:Oracle # verify $oracle 46 $(cast abi-encode "constructor(address,address,address)" $deployer $ormp $subapi) src/eco/Oracle.sol:Oracle # verify $relayer 42161 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/Relayer.sol:Relayer # verify $relayer 46 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/Relayer.sol:Relayer +verify $relayer 137 $(cast abi-encode "constructor(address,address)" $deployer $ormp) src/eco/Relayer.sol:Relayer # verify $ormp 1 $(cast abi-encode "constructor(address)" $deployer) src/ORMP.sol:ORMP # verify $oracle 1 $(cast abi-encode "constructor(address,address,address)" $deployer $ormp $subapi) src/eco/Oracle.sol:Oracle diff --git a/foundry.toml b/foundry.toml index ceb9dc9..ef3e0f5 100644 --- a/foundry.toml +++ b/foundry.toml @@ -72,8 +72,10 @@ darwinia = "https://rpc.darwinia.network" arbitrum = "https://arb1.arbitrum.io/rpc" sepolia = "https://sepolia.infura.io/v3/${INFURA_KEY}" ethereum = "https://mainnet.infura.io/v3/${INFURA_KEY}" +polygon = "https://polygon-mainnet.infura.io/v3/${INFURA_KEY}" [etherscan] +polygon = { key = "${ETHERSCAN_POLYGON_KEY}" } arbitrum = { key = "${ETHERSCAN_ARBITRUM_KEY}" } arbitrum-goerli = { key = "${ETHERSCAN_ARBITRUM_KEY}" } arbitrum-sepolia = { key = "${ETHERSCAN_ARBITRUM_KEY}" } diff --git a/lib/create3-deploy b/lib/create3-deploy index c9b5e5e..c956de8 160000 --- a/lib/create3-deploy +++ b/lib/create3-deploy @@ -1 +1 @@ -Subproject commit c9b5e5e6a42ed318edb83b9e2c494ef16f496d9b +Subproject commit c956de81a1249f955dc5c759ae663430c3b990fa diff --git a/script/deploy/Deploy.s.sol b/script/deploy/Deploy.s.sol index 9556c27..1eff62c 100644 --- a/script/deploy/Deploy.s.sol +++ b/script/deploy/Deploy.s.sol @@ -77,7 +77,7 @@ contract Deploy is Common { require(deployer == msg.sender, "!deployer"); // deployProtocol(); - deployOralce(); + // deployOralce(); // deployRelayer(); setConfig(); @@ -127,15 +127,15 @@ 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"); - // III(RELAYER_ADDR).setApproved(relayerOperator, true); - // require(III(RELAYER_ADDR).isApproved(relayerOperator), "!r-operator"); + III(RELAYER_ADDR).setApproved(relayerOperator, true); + require(III(RELAYER_ADDR).isApproved(relayerOperator), "!r-operator"); // III(ORMP_ADDR).changeSetter(dao); // require(III(ORMP_ADDR).setter() == dao, "!dao"); diff --git a/script/fee/Fee.s.sol b/script/fee/Fee.s.sol index 69912be..1beabf3 100644 --- a/script/fee/Fee.s.sol +++ b/script/fee/Fee.s.sol @@ -42,7 +42,7 @@ contract Fee is Common { function run(uint256 chainId) public { require(dao == msg.sender, "!dao"); - // setOracleFee(chainId); + setOracleFee(chainId); setRelayerFee(chainId); } diff --git a/script/input/137/deploy.c.json b/script/input/137/deploy.c.json new file mode 100644 index 0000000..0324c37 --- /dev/null +++ b/script/input/137/deploy.c.json @@ -0,0 +1,6 @@ +{ + "DAO": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", + "DEPLOYER": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", + "ORACLE_OPERATOR": "0x912D7601569cBc2DF8A7f0aaE50BFd18e8C64d05", + "RELAYER_OPERATOR": "0x912D7601569cBc2DF8A7f0aaE50BFd18e8C64d05" +} diff --git a/script/input/137/fee.c.json b/script/input/137/fee.c.json new file mode 100644 index 0000000..b2665d7 --- /dev/null +++ b/script/input/137/fee.c.json @@ -0,0 +1,15 @@ +{ + "ORACLE": { + "46": { + "fee": 4000000000000000 + } + }, + "RELAYER": { + "46": { + "dstPriceRatio": 40000000, + "dstGasPriceInWei": 180000000000, + "baseGas": 200000, + "gasPerByte": 16 + } + } +} diff --git a/script/input/46/fee.c.json b/script/input/46/fee.c.json index 9e24c5b..16d9ade 100644 --- a/script/input/46/fee.c.json +++ b/script/input/46/fee.c.json @@ -6,6 +6,9 @@ "44": { "fee": 1000000000000000000 }, + "137": { + "fee": 2000000000000000000 + }, "42161": { "fee": 360000000000000000000 } @@ -23,6 +26,12 @@ "baseGas": 200000, "gasPerByte": 16 }, + "137": { + "dstPriceRatio": 2500000000000, + "dstGasPriceInWei": 70000000000, + "baseGas": 120000, + "gasPerByte": 16 + }, "42161": { "dstPriceRatio": 7000000000000000, "dstGasPriceInWei": 110000000, diff --git a/script/output/137/ORMP.v.json b/script/output/137/ORMP.v.json new file mode 100644 index 0000000..4aa8080 --- /dev/null +++ b/script/output/137/ORMP.v.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/ORMP.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./Channel.sol\";\nimport \"./interfaces/IOracle.sol\";\nimport \"./interfaces/IRelayer.sol\";\nimport \"./security/ReentrancyGuard.sol\";\nimport \"./security/ExcessivelySafeCall.sol\";\n\n/// @title ORMP\n/// @notice An endpoint is a type of network node for cross-chain communication.\n/// It is an interface exposed by a communication channel.\n/// @dev An endpoint is associated with an immutable channel and user configuration.\ncontract ORMP is ReentrancyGuard, Channel {\n using ExcessivelySafeCall for address;\n\n constructor(address dao) Channel(dao) {}\n\n /// @dev Send a cross-chain message over the endpoint.\n /// @notice follow https://eips.ethereum.org/EIPS/eip-5750\n /// @param toChainId The Message destination chain id.\n /// @param to User application contract address which receive the message.\n /// @param gasLimit Gas limit for destination user application used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param refund Return extra fee to refund address.\n /// @param params General extensibility for relayer to custom functionality.\n function send(\n uint256 toChainId,\n address to,\n uint256 gasLimit,\n bytes calldata encoded,\n address refund,\n bytes calldata params\n ) external payable sendNonReentrant returns (bytes32) {\n // user application address.\n address ua = msg.sender;\n // send message by channel, return the hash of the message as id.\n bytes32 msgHash = _send(ua, toChainId, to, gasLimit, encoded);\n\n // handle fee\n _handleFee(ua, refund, msgHash, toChainId, gasLimit, encoded, params);\n\n return msgHash;\n }\n\n function _handleFee(\n address ua,\n address refund,\n bytes32 msgHash,\n uint256 toChainId,\n uint256 gasLimit,\n bytes calldata encoded,\n bytes calldata params\n ) internal {\n // fetch user application's config.\n UC memory uc = getAppConfig(ua);\n // handle relayer fee\n uint256 relayerFee = _handleRelayer(uc.relayer, msgHash, toChainId, ua, gasLimit, encoded, params);\n // handle oracle fee\n uint256 oracleFee = _handleOracle(uc.oracle, msgHash, toChainId, ua);\n\n // refund\n if (msg.value > relayerFee + oracleFee) {\n uint256 refundFee = msg.value - (relayerFee + oracleFee);\n (bool success,) = refund.call{value: refundFee}(\"\");\n require(success, \"!refund\");\n }\n }\n\n /// @notice Get a quote in source native gas, for the amount that send() requires to pay for message delivery.\n /// @param toChainId The Message destination chain id.\n // @param ua User application contract address which send the message.\n /// @param gasLimit Gas limit for destination user application used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param params General extensibility for relayer to custom functionality.\n function fee(uint256 toChainId, address ua, uint256 gasLimit, bytes calldata encoded, bytes calldata params)\n external\n view\n returns (uint256)\n {\n UC memory uc = getAppConfig(ua);\n uint256 relayerFee = IRelayer(uc.relayer).fee(toChainId, ua, gasLimit, encoded, params);\n uint256 oracleFee = IOracle(uc.oracle).fee(toChainId, ua);\n return relayerFee + oracleFee;\n }\n\n function _handleRelayer(\n address relayer,\n bytes32 msgHash,\n uint256 toChainId,\n address ua,\n uint256 gasLimit,\n bytes calldata encoded,\n bytes calldata params\n ) internal returns (uint256) {\n uint256 relayerFee = IRelayer(relayer).fee(toChainId, ua, gasLimit, encoded, params);\n IRelayer(relayer).assign{value: relayerFee}(msgHash, params);\n return relayerFee;\n }\n\n function _handleOracle(address oracle, bytes32 msgHash, uint256 toChainId, address ua) internal returns (uint256) {\n uint256 oracleFee = IOracle(oracle).fee(toChainId, ua);\n IOracle(oracle).assign{value: oracleFee}(msgHash);\n return oracleFee;\n }\n\n /// @dev Recv verified message from Channel and dispatch to destination user application address.\n /// @notice Only channel could call this function.\n /// @param message Verified receive message info.\n /// @param proof Message proof of this message.\n /// @return dispatchResult Result of the message dispatch.\n function recv(Message calldata message, bytes calldata proof)\n external\n payable\n recvNonReentrant\n returns (bool dispatchResult)\n {\n bytes32 msgHash = _recv(message, proof);\n dispatchResult = _dispatch(message, msgHash);\n // emit dispatched message event.\n emit MessageDispatched(msgHash, dispatchResult);\n }\n\n /// @dev Dispatch the cross chain message.\n function _dispatch(Message memory message, bytes32 msgHash) private returns (bool dispatchResult) {\n // Deliver the message to user application contract address.\n (dispatchResult,) = message.to.excessivelySafeCall(\n message.gasLimit,\n msg.value,\n 0,\n abi.encodePacked(message.encoded, msgHash, message.fromChainId, message.from)\n );\n }\n}\n"},"src/Channel.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./UserConfig.sol\";\nimport \"./interfaces/IVerifier.sol\";\nimport \"./imt/IncrementalMerkleTree.sol\";\n\n/// @title Channel\n/// @notice A channel is a logical connection over cross-chain network.\n/// It used for cross-chain message transfer.\n/// - Accepts messages to be dispatched to destination chains,\n/// constructs a Merkle tree of the messages.\n/// - Dispatches verified messages from source chains.\n/// @dev Messages live in an incremental merkle tree (imt)\n/// > A Merkle tree is a binary and complete tree decorated with\n/// > the Merkle (hash) attribute.\ncontract Channel is UserConfig {\n using IncrementalMerkleTree for IncrementalMerkleTree.Tree;\n\n /// @dev Incremental merkle tree root which all message hashes live in leafs.\n bytes32 public root;\n /// @dev Incremental merkle tree.\n IncrementalMerkleTree.Tree private _imt;\n /// @dev msgHash => isDispathed.\n mapping(bytes32 => bool) public dones;\n\n /// @dev Self contract address cache.\n address private immutable __self = address(this);\n\n /// @dev Notifies an observer that the message has been accepted.\n /// @param msgHash Hash of the message.\n /// @param root New incremental merkle tree root after a new message inserted.\n /// @param message Accepted message info.\n event MessageAccepted(bytes32 indexed msgHash, bytes32 root, Message message);\n /// @dev Notifies an observer that the message has been dispatched.\n /// @param msgHash Hash of the message.\n /// @param dispatchResult The message dispatch result.\n event MessageDispatched(bytes32 indexed msgHash, bool dispatchResult);\n\n /// @dev Init code.\n constructor(address dao) UserConfig(dao) {\n // init with empty tree\n root = 0x27ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757;\n }\n\n /// @dev Fetch local chain id.\n /// @return chainId Local chain id.\n function LOCAL_CHAINID() public view returns (uint256 chainId) {\n assembly {\n chainId := chainid()\n }\n }\n\n /// @dev Send message.\n /// @param from User application contract address which send the message.\n /// @param toChainId The Message destination chain id.\n /// @param to User application contract address which receive the message.\n /// @param gasLimit Gas limit for destination user application used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n function _send(address from, uint256 toChainId, address to, uint256 gasLimit, bytes calldata encoded)\n internal\n returns (bytes32)\n {\n // only cross-chain message\n require(toChainId != LOCAL_CHAINID(), \"!cross-chain\");\n // get this message leaf index.\n uint256 index = messageCount();\n // constuct message object.\n Message memory message = Message({\n channel: __self,\n index: index,\n fromChainId: LOCAL_CHAINID(),\n from: from,\n toChainId: toChainId,\n to: to,\n gasLimit: gasLimit,\n encoded: encoded\n });\n // hash the message.\n bytes32 msgHash = hash(message);\n // insert msg hash to imt.\n _imt.insert(msgHash);\n // update new imt.root to root storage.\n root = _imt.root();\n\n // emit accepted message event.\n emit MessageAccepted(msgHash, root, message);\n\n // return this message hash.\n return msgHash;\n }\n\n /// @dev Receive messages.\n /// @notice Only message.to's config relayer could relay this message.\n /// @param message Received message info.\n /// @param proof Message proof of this message.\n function _recv(Message calldata message, bytes calldata proof) internal returns (bytes32) {\n // get message.to user config.\n UC memory uc = getAppConfig(message.to);\n // only the config relayer could relay this message.\n require(uc.relayer == msg.sender, \"!auth\");\n\n // hash the message.\n bytes32 msgHash = hash(message);\n // verify message by the config oracle.\n require(IVerifier(uc.oracle).verifyMessageProof(message.fromChainId, msgHash, proof), \"!proof\");\n\n // check destination chain id is correct.\n require(LOCAL_CHAINID() == message.toChainId, \"!toChainId\");\n // check the message is not dispatched.\n require(dones[msgHash] == false, \"done\");\n // set the message is dispatched.\n dones[msgHash] = true;\n\n return msgHash;\n }\n\n /// @dev Fetch the messages count of incremental merkle tree.\n function messageCount() public view returns (uint256) {\n return _imt.count;\n }\n\n /// @dev Fetch the branch of incremental merkle tree.\n function imtBranch() public view returns (bytes32[32] memory) {\n return _imt.branch;\n }\n\n /// @dev Fetch the latest message proof\n function prove() public view returns (bytes32[32] memory) {\n return _imt.prove();\n }\n}\n"},"src/interfaces/IOracle.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./IVerifier.sol\";\n\ninterface IOracle is IVerifier {\n /// @notice Fetch oracle price to relay message root to the destination chain.\n /// @param toChainId The destination chain id.\n /// @param ua The user application which send the message.\n /// @return Oracle price in source native gas.\n function fee(uint256 toChainId, address ua) external view returns (uint256);\n\n /// @notice Assign the relay message root task to oracle maintainer.\n /// @param msgHash Hash of the message.\n function assign(bytes32 msgHash) external payable;\n}\n"},"src/interfaces/IRelayer.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IRelayer {\n /// @notice Fetch relayer price to relay message to the destination chain.\n /// @param toChainId The destination chain id.\n /// @param ua The user application which send the message.\n /// @param gasLimit Gas limit for destination user application used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param params General extensibility for relayer to custom functionality.\n /// @return Relayer price in source native gas.\n function fee(uint256 toChainId, address ua, uint256 gasLimit, bytes calldata encoded, bytes calldata params)\n external\n view\n returns (uint256);\n\n /// @notice Assign the relay message task to relayer maintainer.\n /// @param msgHash Hash of the message.\n /// @param params General extensibility for relayer to custom functionality.\n function assign(bytes32 msgHash, bytes calldata params) external payable;\n}\n"},"src/security/ReentrancyGuard.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nabstract contract ReentrancyGuard {\n // send and receive nonreentrant lock\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n uint256 private _send_state = 1;\n uint256 private _receive_state = 1;\n\n modifier sendNonReentrant() {\n require(_send_state == _NOT_ENTERED, \"!send-reentrancy\");\n _send_state = _ENTERED;\n _;\n _send_state = _NOT_ENTERED;\n }\n\n modifier recvNonReentrant() {\n require(_receive_state == _NOT_ENTERED, \"!recv-reentrancy\");\n _receive_state = _ENTERED;\n _;\n _receive_state = _NOT_ENTERED;\n }\n}\n"},"src/security/ExcessivelySafeCall.sol":{"content":"// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity 0.8.17;\n\n// Inspired: https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/util/ExcessivelySafeCall.sol\n\nlibrary ExcessivelySafeCall {\n uint256 private constant LOW_28_MASK = 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff;\n\n /// @notice Use when you _really_ really _really_ don't trust the called\n /// contract. This prevents the called contract from causing reversion of\n /// the caller in as many ways as we can.\n /// @dev The main difference between this and a solidity low-level call is\n /// that we limit the number of bytes that the callee can cause to be\n /// copied to caller memory. This prevents stupid things like malicious\n /// contracts returning 10,000,000 bytes causing a local OOG when copying\n /// to memory.\n /// @param _target The address to call\n /// @param _gas The amount of gas to forward to the remote contract\n /// @param _value Value in wei to send to the account\n /// @param _maxCopy The maximum number of bytes of returndata to copy\n /// to memory.\n /// @param _calldata The data to send to the remote contract\n /// @return success and returndata, as `.call()`. Returndata is capped to\n /// `_maxCopy` bytes.\n function excessivelySafeCall(address _target, uint256 _gas, uint256 _value, uint16 _maxCopy, bytes memory _calldata)\n internal\n returns (bool, bytes memory)\n {\n // set up for assembly call\n uint256 _toCopy;\n bool _success;\n bytes memory _returnData = new bytes(_maxCopy);\n // dispatch message to recipient\n // by assembly calling \"handle\" function\n // we call via assembly to avoid memcopying a very large returndata\n // returned by a malicious contract\n assembly (\"memory-safe\") {\n _success :=\n call(\n _gas, // gas\n _target, // recipient\n _value, // ether value\n add(_calldata, 0x20), // inloc\n mload(_calldata), // inlen\n 0, // outloc\n 0 // outlen\n )\n // limit our copy to 256 bytes\n _toCopy := returndatasize()\n if gt(_toCopy, _maxCopy) { _toCopy := _maxCopy }\n // Store the length of the copied bytes\n mstore(_returnData, _toCopy)\n // copy the bytes from returndata[0:_toCopy]\n returndatacopy(add(_returnData, 0x20), 0, _toCopy)\n }\n return (_success, _returnData);\n }\n\n /// @notice Use when you _really_ really _really_ don't trust the called\n /// contract. This prevents the called contract from causing reversion of\n /// the caller in as many ways as we can.\n /// @dev The main difference between this and a solidity low-level call is\n /// that we limit the number of bytes that the callee can cause to be\n /// copied to caller memory. This prevents stupid things like malicious\n /// contracts returning 10,000,000 bytes causing a local OOG when copying\n /// to memory.\n /// @param _target The address to call\n /// @param _gas The amount of gas to forward to the remote contract\n /// @param _maxCopy The maximum number of bytes of returndata to copy\n /// to memory.\n /// @param _calldata The data to send to the remote contract\n /// @return success and returndata, as `.call()`. Returndata is capped to\n /// `_maxCopy` bytes.\n function excessivelySafeStaticCall(address _target, uint256 _gas, uint16 _maxCopy, bytes memory _calldata)\n internal\n view\n returns (bool, bytes memory)\n {\n // set up for assembly call\n uint256 _toCopy;\n bool _success;\n bytes memory _returnData = new bytes(_maxCopy);\n // dispatch message to recipient\n // by assembly calling \"handle\" function\n // we call via assembly to avoid memcopying a very large returndata\n // returned by a malicious contract\n assembly (\"memory-safe\") {\n _success :=\n staticcall(\n _gas, // gas\n _target, // recipient\n add(_calldata, 0x20), // inloc\n mload(_calldata), // inlen\n 0, // outloc\n 0 // outlen\n )\n // limit our copy to 256 bytes\n _toCopy := returndatasize()\n if gt(_toCopy, _maxCopy) { _toCopy := _maxCopy }\n // Store the length of the copied bytes\n mstore(_returnData, _toCopy)\n // copy the bytes from returndata[0:_toCopy]\n returndatacopy(add(_returnData, 0x20), 0, _toCopy)\n }\n return (_success, _returnData);\n }\n\n /// @notice Swaps function selectors in encoded contract calls\n /// @dev Allows reuse of encoded calldata for functions with identical\n /// argument types but different names. It simply swaps out the first 4 bytes\n /// for the new selector. This function modifies memory in place, and should\n /// only be used with caution.\n /// @param _newSelector The new 4-byte selector\n /// @param _buf The encoded contract args\n function swapSelector(bytes4 _newSelector, bytes memory _buf) internal pure {\n require(_buf.length >= 4);\n uint256 _mask = LOW_28_MASK;\n assembly (\"memory-safe\") {\n // load the first word of\n let _word := mload(add(_buf, 0x20))\n // mask out the top 4 bytes\n // /x\n _word := and(_word, _mask)\n _word := or(_newSelector, _word)\n mstore(add(_buf, 0x20), _word)\n }\n }\n}\n"},"src/UserConfig.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"./Common.sol\";\n\n/// @title UserConfig\n/// @notice User config could select their own relayer and oracle.\n/// The default configuration is used by default.\n/// @dev Only setter could set default user config.\ncontract UserConfig {\n /// @dev Setter address.\n address public setter;\n /// @dev Default user config.\n UC public defaultUC;\n /// @dev ua => uc.\n mapping(address => UC) public ucOf;\n\n /// @dev Notifies an observer that the default user config has updated.\n /// @param oracle Default oracle.\n /// @param relayer Default relayer.\n event DefaultConfigUpdated(address oracle, address relayer);\n /// @dev Notifies an observer that the user application config has updated.\n /// @param ua User application contract address.\n /// @param oracle Oracle which the user application choose.\n /// @param relayer Relayer which the user application choose.\n event AppConfigUpdated(address indexed ua, address oracle, address relayer);\n\n modifier onlySetter() {\n require(msg.sender == setter, \"!auth\");\n _;\n }\n\n constructor(address dao) {\n setter = dao;\n }\n\n /// @dev Change setter.\n /// @notice Only current setter could call.\n /// @param setter_ New setter.\n function changeSetter(address setter_) external onlySetter {\n setter = setter_;\n }\n\n /// @dev Set default user config for all user application.\n /// @notice Only setter could call.\n /// @param oracle Default oracle.\n /// @param relayer Default relayer.\n function setDefaultConfig(address oracle, address relayer) external onlySetter {\n defaultUC = UC(oracle, relayer);\n emit DefaultConfigUpdated(oracle, relayer);\n }\n\n /// @notice Set user application config.\n /// @param oracle Oracle which user application.\n /// @param relayer Relayer which user application choose.\n function setAppConfig(address oracle, address relayer) external {\n ucOf[msg.sender] = UC(oracle, relayer);\n emit AppConfigUpdated(msg.sender, oracle, relayer);\n }\n\n /// @dev Fetch user application config.\n /// @notice If user application has not configured, then the default user config is used.\n /// @param ua User application contract address.\n /// @return user application config.\n function getAppConfig(address ua) public view returns (UC memory) {\n UC memory c = ucOf[ua];\n\n if (c.relayer == address(0x0)) {\n c.relayer = defaultUC.relayer;\n }\n\n if (c.oracle == address(0x0)) {\n c.oracle = defaultUC.oracle;\n }\n\n return c;\n }\n}\n"},"src/interfaces/IVerifier.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IVerifier {\n /// @notice Fetch message root oracle.\n /// @param chainId The destination chain id.\n /// @param blockNumber The block number where the message root is located.\n /// @return Message root in destination chain.\n function merkleRoot(uint256 chainId, uint256 blockNumber) external view returns (bytes32);\n\n /// @notice Verify message proof\n /// @dev Message proof provided by relayer. Oracle should provide message root of\n /// source chain, and verify the merkle proof of the message hash.\n /// @param fromChainId Source chain id.\n /// @param msgHash Hash of the message.\n /// @param proof Merkle proof of the message\n /// @return Result of the message verify.\n function verifyMessageProof(uint256 fromChainId, bytes32 msgHash, bytes calldata proof)\n external\n view\n returns (bool);\n}\n"},"src/imt/IncrementalMerkleTree.sol":{"content":"// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity 0.8.17;\n\n// Inspired: https://github.com/nomad-xyz/monorepo/blob/main/packages/contracts-core/contracts/libs/Merkle.sol\n\n/// @title IncrementalMerkleTree\n/// @author Illusory Systems Inc.\n/// @notice An incremental merkle tree modeled on the eth2 deposit contract.\nlibrary IncrementalMerkleTree {\n uint256 private constant TREE_DEPTH = 32;\n uint256 private constant MAX_LEAVES = 2 ** TREE_DEPTH - 1;\n\n /// @notice Struct representing incremental merkle tree. Contains current\n /// branch and the number of inserted leaves in the tree.\n struct Tree {\n bytes32[TREE_DEPTH] branch;\n uint256 count;\n }\n\n /// @notice Inserts `_node` into merkle tree\n /// @dev Reverts if tree is full\n /// @param _node Element to insert into tree\n function insert(Tree storage _tree, bytes32 _node) internal {\n require(_tree.count < MAX_LEAVES, \"merkle tree full\");\n\n _tree.count += 1;\n uint256 size = _tree.count;\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n if ((size & 1) == 1) {\n _tree.branch[i] = _node;\n return;\n }\n _node = keccak256(abi.encodePacked(_tree.branch[i], _node));\n size /= 2;\n }\n // As the loop should always end prematurely with the `return` statement,\n // this code should be unreachable. We assert `false` just to be safe.\n assert(false);\n }\n\n /// @notice Calculates and returns`_tree`'s current root given array of zero\n /// hashes\n /// @param _zeroes Array of zero hashes\n /// @return _current Calculated root of `_tree`\n function rootWithCtx(Tree storage _tree, bytes32[TREE_DEPTH] memory _zeroes)\n internal\n view\n returns (bytes32 _current)\n {\n uint256 _index = _tree.count;\n\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ithBit = (_index >> i) & 0x01;\n bytes32 _next = _tree.branch[i];\n if (_ithBit == 1) {\n _current = keccak256(abi.encodePacked(_next, _current));\n } else {\n _current = keccak256(abi.encodePacked(_current, _zeroes[i]));\n }\n }\n }\n\n /// @notice Calculates and returns`_tree`'s current root\n function root(Tree storage _tree) internal view returns (bytes32) {\n return rootWithCtx(_tree, zeroHashes());\n }\n\n /// @notice Returns array of TREE_DEPTH zero hashes\n /// @return _zeroes Array of TREE_DEPTH zero hashes\n function zeroHashes() internal pure returns (bytes32[TREE_DEPTH] memory _zeroes) {\n _zeroes[0] = Z_0;\n _zeroes[1] = Z_1;\n _zeroes[2] = Z_2;\n _zeroes[3] = Z_3;\n _zeroes[4] = Z_4;\n _zeroes[5] = Z_5;\n _zeroes[6] = Z_6;\n _zeroes[7] = Z_7;\n _zeroes[8] = Z_8;\n _zeroes[9] = Z_9;\n _zeroes[10] = Z_10;\n _zeroes[11] = Z_11;\n _zeroes[12] = Z_12;\n _zeroes[13] = Z_13;\n _zeroes[14] = Z_14;\n _zeroes[15] = Z_15;\n _zeroes[16] = Z_16;\n _zeroes[17] = Z_17;\n _zeroes[18] = Z_18;\n _zeroes[19] = Z_19;\n _zeroes[20] = Z_20;\n _zeroes[21] = Z_21;\n _zeroes[22] = Z_22;\n _zeroes[23] = Z_23;\n _zeroes[24] = Z_24;\n _zeroes[25] = Z_25;\n _zeroes[26] = Z_26;\n _zeroes[27] = Z_27;\n _zeroes[28] = Z_28;\n _zeroes[29] = Z_29;\n _zeroes[30] = Z_30;\n _zeroes[31] = Z_31;\n }\n\n /// @notice Calculates and returns the merkle root for the given leaf\n /// `_item`, a merkle branch, and the index of `_item` in the tree.\n /// @param _item Merkle leaf\n /// @param _branch Merkle proof\n /// @param _index Index of `_item` in tree\n /// @return _current Calculated merkle root\n function branchRoot(bytes32 _item, bytes32[TREE_DEPTH] memory _branch, uint256 _index)\n internal\n pure\n returns (bytes32 _current)\n {\n _current = _item;\n\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ithBit = (_index >> i) & 0x01;\n bytes32 _next = _branch[i];\n if (_ithBit == 1) {\n _current = keccak256(abi.encodePacked(_next, _current));\n } else {\n _current = keccak256(abi.encodePacked(_current, _next));\n }\n }\n }\n\n function prove(Tree storage _tree) internal view returns (bytes32[TREE_DEPTH] memory proof) {\n uint256 _index = _tree.count - 1;\n bytes32[TREE_DEPTH] memory left = _tree.branch;\n bytes32[TREE_DEPTH] memory right = zeroHashes();\n for (uint256 i = 0; i < TREE_DEPTH; i++) {\n uint256 _ith_bit = (_index >> i) & 0x01;\n if (_ith_bit == 1) {\n proof[i] = left[i];\n } else {\n proof[i] = right[i];\n }\n }\n }\n\n // keccak256 zero hashes\n bytes32 private constant Z_0 = hex\"0000000000000000000000000000000000000000000000000000000000000000\";\n bytes32 private constant Z_1 = hex\"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5\";\n bytes32 private constant Z_2 = hex\"b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30\";\n bytes32 private constant Z_3 = hex\"21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85\";\n bytes32 private constant Z_4 = hex\"e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344\";\n bytes32 private constant Z_5 = hex\"0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d\";\n bytes32 private constant Z_6 = hex\"887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968\";\n bytes32 private constant Z_7 = hex\"ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83\";\n bytes32 private constant Z_8 = hex\"9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af\";\n bytes32 private constant Z_9 = hex\"cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0\";\n bytes32 private constant Z_10 = hex\"f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5\";\n bytes32 private constant Z_11 = hex\"f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892\";\n bytes32 private constant Z_12 = hex\"3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c\";\n bytes32 private constant Z_13 = hex\"c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb\";\n bytes32 private constant Z_14 = hex\"5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc\";\n bytes32 private constant Z_15 = hex\"da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2\";\n bytes32 private constant Z_16 = hex\"2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f\";\n bytes32 private constant Z_17 = hex\"e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a\";\n bytes32 private constant Z_18 = hex\"5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0\";\n bytes32 private constant Z_19 = hex\"b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0\";\n bytes32 private constant Z_20 = hex\"c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2\";\n bytes32 private constant Z_21 = hex\"f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9\";\n bytes32 private constant Z_22 = hex\"5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377\";\n bytes32 private constant Z_23 = hex\"4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652\";\n bytes32 private constant Z_24 = hex\"cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef\";\n bytes32 private constant Z_25 = hex\"0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d\";\n bytes32 private constant Z_26 = hex\"b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0\";\n bytes32 private constant Z_27 = hex\"838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e\";\n bytes32 private constant Z_28 = hex\"662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e\";\n bytes32 private constant Z_29 = hex\"388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322\";\n bytes32 private constant Z_30 = hex\"93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735\";\n bytes32 private constant Z_31 = hex\"8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9\";\n}\n"},"src/Common.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\n/// @dev The block of control information and data for comminicate\n/// between user applications. Messages are the exchange medium\n/// used by channels to send and receive data through cross-chain networks.\n/// A message is sent from a source chain to a destination chain.\n/// @param index The leaf index lives in channel's incremental mekle tree.\n/// @param fromChainId The message source chain id.\n/// @param from User application contract address which send the message.\n/// @param toChainId The message destination chain id.\n/// @param to User application contract address which receive the message.\n/// @param gasLimit Gas limit for destination UA used.\n/// @param encoded The calldata which encoded by ABI Encoding.\nstruct Message {\n address channel;\n uint256 index;\n uint256 fromChainId;\n address from;\n uint256 toChainId;\n address to;\n uint256 gasLimit;\n bytes encoded; /*(abi.encodePacked(SELECTOR, PARAMS))*/\n}\n\n/// @dev User application custom configuration.\n/// @param oracle Oracle contract address.\n/// @param relayer Relayer contract address.\nstruct UC {\n address oracle;\n address relayer;\n}\n\n/// @dev Hash of the message.\nfunction hash(Message memory message) pure returns (bytes32) {\n return keccak256(abi.encode(message));\n}\n"}},"settings":{"remappings":["forge-std/=lib/forge-std/src/","ds-test/=lib/forge-std/lib/ds-test/src/","create3-deploy/=lib/create3-deploy/"],"optimizer":{"enabled":true,"runs":999999},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs"},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata","storageLayout","devdoc","userdoc"]}},"evmVersion":"london","libraries":{}}} diff --git a/script/output/137/ORMPOracle.v.json b/script/output/137/ORMPOracle.v.json new file mode 100644 index 0000000..11c0b26 --- /dev/null +++ b/script/output/137/ORMPOracle.v.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/eco/ORMPOracle.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 ORMPOracle 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 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 /// @dev Only could be called by owner.\n /// @notice Each channel has a corresponding oracle, and the message root should match with it.\n /// @param chainId The source chain id.\n /// @param blockNumber The source chain block number.\n /// @param messageRoot The source chain message root corresponding to the channel.\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 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 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/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/137/Relayer.v.json b/script/output/137/Relayer.v.json new file mode 100644 index 0000000..9e64573 --- /dev/null +++ b/script/output/137/Relayer.v.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/eco/Relayer.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"../interfaces/IORMP.sol\";\n\ncontract Relayer {\n event Assigned(bytes32 indexed msgHash, uint256 fee, bytes params, bytes32[32] proof);\n event SetDstPrice(uint256 indexed chainId, uint128 dstPriceRatio, uint128 dstGasPriceInWei);\n event SetDstConfig(uint256 indexed chainId, uint64 baseGas, uint64 gasPerByte);\n event SetApproved(address operator, bool approve);\n\n struct DstPrice {\n uint128 dstPriceRatio; // dstPrice / localPrice * 10^10\n uint128 dstGasPriceInWei;\n }\n\n struct DstConfig {\n uint64 baseGas;\n uint64 gasPerByte;\n }\n\n address public immutable PROTOCOL;\n\n address public owner;\n // chainId => price\n mapping(uint256 => DstPrice) public priceOf;\n mapping(uint256 => DstConfig) public configOf;\n mapping(address => bool) public approvedOf;\n\n modifier onlyOwner() {\n require(msg.sender == owner, \"!owner\");\n _;\n }\n\n modifier onlyApproved() {\n require(isApproved(msg.sender), \"!approve\");\n _;\n }\n\n constructor(address dao, address ormp) {\n PROTOCOL = ormp;\n owner = dao;\n }\n\n receive() external payable {}\n\n function withdraw(address to, uint256 amount) external onlyApproved {\n (bool success,) = to.call{value: amount}(\"\");\n require(success, \"!withdraw\");\n }\n\n function isApproved(address operator) public view returns (bool) {\n return approvedOf[operator];\n }\n\n function changeOwner(address owner_) external onlyOwner {\n owner = owner_;\n }\n\n function setApproved(address operator, bool approve) public onlyOwner {\n approvedOf[operator] = approve;\n emit SetApproved(operator, approve);\n }\n\n function setDstPrice(uint256 chainId, uint128 dstPriceRatio, uint128 dstGasPriceInWei) external onlyApproved {\n priceOf[chainId] = DstPrice(dstPriceRatio, dstGasPriceInWei);\n emit SetDstPrice(chainId, dstPriceRatio, dstGasPriceInWei);\n }\n\n function setDstConfig(uint256 chainId, uint64 baseGas, uint64 gasPerByte) external onlyApproved {\n configOf[chainId] = DstConfig(baseGas, gasPerByte);\n emit SetDstConfig(chainId, baseGas, gasPerByte);\n }\n\n // extraGas = gasLimit\n function fee(\n uint256 toChainId,\n address, /*ua*/\n uint256 gasLimit,\n bytes calldata encoded,\n bytes calldata /*params*/\n ) public view returns (uint256) {\n uint256 size = encoded.length;\n uint256 extraGas = gasLimit;\n DstPrice memory p = priceOf[toChainId];\n DstConfig memory c = configOf[toChainId];\n\n require(c.baseGas != 0, \"!baseGas\");\n // remoteToken = dstGasPriceInWei * (baseGas + extraGas)\n uint256 remoteToken = p.dstGasPriceInWei * (c.baseGas + extraGas);\n // dstPriceRatio = dstPrice / localPrice * 10^10\n // sourceToken = RemoteToken * dstPriceRatio\n uint256 sourceToken = remoteToken * p.dstPriceRatio / (10 ** 10);\n uint256 payloadToken = c.gasPerByte * size * p.dstGasPriceInWei * p.dstPriceRatio / (10 ** 10);\n return sourceToken + payloadToken;\n }\n\n function assign(bytes32 msgHash, bytes calldata params) external payable {\n require(msg.sender == PROTOCOL, \"!ormp\");\n emit Assigned(msgHash, msg.value, params, IORMP(PROTOCOL).prove());\n }\n\n function relay(Message calldata message, bytes calldata proof) external onlyApproved {\n IORMP(PROTOCOL).recv(message, proof);\n }\n}\n"},"src/interfaces/IORMP.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\nimport \"../Common.sol\";\n\ninterface IORMP {\n /// @dev Send a cross-chain message over the endpoint.\n /// @notice follow https://eips.ethereum.org/EIPS/eip-5750\n /// @param toChainId The Message destination chain id.\n /// @param to User application contract address which receive the message.\n /// @param gasLimit Gas limit for destination user application used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param refund Return extra fee to refund address.\n /// @param params General extensibility for relayer to custom functionality.\n /// @return Return the hash of the message as message id.\n function send(\n uint256 toChainId,\n address to,\n uint256 gasLimit,\n bytes calldata encoded,\n address refund,\n bytes calldata params\n ) external payable returns (bytes32);\n\n /// @notice Get a quote in source native gas, for the amount that send() requires to pay for message delivery.\n /// @param toChainId The Message destination chain id.\n // @param ua User application contract address which send the message.\n /// @param gasLimit Gas limit for destination user application used.\n /// @param encoded The calldata which encoded by ABI Encoding.\n /// @param params General extensibility for relayer to custom functionality.\n function fee(uint256 toChainId, address ua, uint256 gasLimit, bytes calldata encoded, bytes calldata params)\n external\n view\n returns (uint256);\n\n /// @dev Recv verified message and dispatch to destination user application address.\n /// @param message Verified receive message info.\n /// @param proof Message proof of this message.\n /// @return dispatchResult Result of the message dispatch.\n function recv(Message calldata message, bytes calldata proof) external returns (bool dispatchResult);\n\n function prove() external view returns (bytes32[32] memory);\n\n /// @dev Fetch user application config.\n /// @notice If user application has not configured, then the default config is used.\n /// @param ua User application contract address.\n /// @return user application config.\n function getAppConfig(address ua) external view returns (UC memory);\n\n /// @notice Set user application config.\n /// @param oracle Oracle which user application choose.\n /// @param relayer Relayer which user application choose.\n function setAppConfig(address oracle, address relayer) external;\n\n function defaultUC() external view returns (UC memory);\n}\n"},"src/Common.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2023 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\n/// @dev The block of control information and data for comminicate\n/// between user applications. Messages are the exchange medium\n/// used by channels to send and receive data through cross-chain networks.\n/// A message is sent from a source chain to a destination chain.\n/// @param index The leaf index lives in channel's incremental mekle tree.\n/// @param fromChainId The message source chain id.\n/// @param from User application contract address which send the message.\n/// @param toChainId The message destination chain id.\n/// @param to User application contract address which receive the message.\n/// @param gasLimit Gas limit for destination UA used.\n/// @param encoded The calldata which encoded by ABI Encoding.\nstruct Message {\n address channel;\n uint256 index;\n uint256 fromChainId;\n address from;\n uint256 toChainId;\n address to;\n uint256 gasLimit;\n bytes encoded; /*(abi.encodePacked(SELECTOR, PARAMS))*/\n}\n\n/// @dev User application custom configuration.\n/// @param oracle Oracle contract address.\n/// @param relayer Relayer contract address.\nstruct UC {\n address oracle;\n address relayer;\n}\n\n/// @dev Hash of the message.\nfunction hash(Message memory message) pure returns (bytes32) {\n return keccak256(abi.encode(message));\n}\n"}},"settings":{"remappings":["forge-std/=lib/forge-std/src/","ds-test/=lib/forge-std/lib/ds-test/src/","create3-deploy/=lib/create3-deploy/"],"optimizer":{"enabled":true,"runs":999999},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs"},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata","storageLayout","devdoc","userdoc"]}},"evmVersion":"london","libraries":{}}} diff --git a/script/output/137/deploy.a-latest.json b/script/output/137/deploy.a-latest.json new file mode 100644 index 0000000..eeb9b0f --- /dev/null +++ b/script/output/137/deploy.a-latest.json @@ -0,0 +1,6 @@ +{ + "DAO": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", + "ORACLE": "0x0000000003ebeF32D8f0ED406a5CA8805c80AFba", + "ORMP": "0x00000000001523057a05d6293C1e5171eE33eE0A", + "RELAYER": "0x0000000000808fE9bDCc1d180EfbF5C53552a6b1" +} \ No newline at end of file