diff --git a/.gitignore b/.gitignore index 94f38db..4f707f3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.DS_Store .env /docs /out diff --git a/bin/beacon/add-all.sh b/bin/beacon/add-all.sh index de624e0..e741196 100755 --- a/bin/beacon/add-all.sh +++ b/bin/beacon/add-all.sh @@ -2,7 +2,7 @@ set -eo pipefail -# . $(dirname $0)/add-beacon-guantong.sh +. $(dirname $0)/add-beacon-guantong.sh . $(dirname $0)/add-beacon-aki.sh . $(dirname $0)/add-beacon-yalin.sh . $(dirname $0)/add-beacon-echo.sh diff --git a/bin/beacon/add-beacon.sh b/bin/beacon/add-beacon.sh index b8763f2..c20923a 100755 --- a/bin/beacon/add-beacon.sh +++ b/bin/beacon/add-beacon.sh @@ -9,23 +9,43 @@ sponsorWallet=${3:?} c3=$PWD/script/input/c3.json subapi=$(jq -r ".SUBAPI_ADDR" $c3) +sig=$(cast sig "addBeacon(uint256,(uint256,address,bytes32,address,address))") + +add_beacon() { + local chain; chain=${1:?} + local endpointId; endpointId=${2:?} + local fromChain; fromChain=${3:?} + local chainId; chainId=$(seth --to-uint256 $(seth chain-id --chain $fromChain)) + local data; + data=$(set -x; ethabi encode params \ + -v "(uint256,uint256,address,bytes32,address,address)" \ + "(${chainId:2},${chainId:2},${airnode:2},${endpointId:2},${sponsor:2},${sponsorWallet:2})") + # (set -x; seth send $subapi $sig$data --chain $chain) +} + +# chain=darwinia +# fromChain=arbitrum +# endpointId=0x18905d41e909c79069d74843dc474d0809df62b5bc555ea272b0cc49ff3fa924 +# add_beacon $chain $endpointId $fromChain + +# fromChain=ethereum +# endpointId=0xd3b815c7ac0ba9242a379bdc8a2f94d609e64239c6c85ac27e244828d6f48815 +# add_beacon $chain $endpointId $fromChain chain=arbitrum +fromChain=darwinia endpointId=0x45189e2288f2d2e384c9e3be7c3c6cef65a553341ca8580e1ed3516725112bb4 +add_beacon $chain $endpointId $fromChain -data=$(set -x; ethabi encode params \ - -v "(address,bytes32,address,address)" \ - "(${airnode:2},${endpointId:2},${sponsor:2},${sponsorWallet:2})") +fromChain=ethereum +endpointId=0xd3b815c7ac0ba9242a379bdc8a2f94d609e64239c6c85ac27e244828d6f48815 +add_beacon $chain $endpointId $fromChain -sig=$(cast sig "addBeacon((address,bytes32,address,address))") -(set -x; seth send $subapi $sig$data --chain $chain) +# chain=ethereum +# fromChain=darwinia +# endpointId=0x45189e2288f2d2e384c9e3be7c3c6cef65a553341ca8580e1ed3516725112bb4 +# add_beacon $chain $endpointId $fromChain - -chain=darwinia -endpointId=0x18905d41e909c79069d74843dc474d0809df62b5bc555ea272b0cc49ff3fa924 - -data=$(set -x; ethabi encode params \ - -v "(address,bytes32,address,address)" \ - "(${airnode:2},${endpointId:2},${sponsor:2},${sponsorWallet:2})") - -(set -x; seth send $subapi $sig$data --chain $chain) +# fromChain=arbitrum +# endpointId=0x18905d41e909c79069d74843dc474d0809df62b5bc555ea272b0cc49ff3fa924 +# add_beacon $chain $endpointId $fromChain diff --git a/bin/config.sh b/bin/config.sh index 6e6fe18..a6b4796 100755 --- a/bin/config.sh +++ b/bin/config.sh @@ -4,7 +4,8 @@ set -eo pipefail # forge script script/Config.s.sol:Config --chain-id 46 --broadcast --slow # forge script script/Config.s.sol:Config --chain-id 42161 --broadcast --slow --legacy +# forge script script/Config.s.sol:Config --chain-id 1 --broadcast --slow --legacy --resume -forge script script/Config.s.sol:Config --chain-id 44 --broadcast -forge script script/Config.s.sol:Config --chain-id 421614 --broadcast -forge script script/Config.s.sol:Config --chain-id 11155111 --broadcast +# forge script script/Config.s.sol:Config --chain-id 44 --broadcast +# forge script script/Config.s.sol:Config --chain-id 421614 --broadcast +# forge script script/Config.s.sol:Config --chain-id 11155111 --broadcast diff --git a/bin/dao.sh b/bin/dao.sh index 54d8438..09798fd 100755 --- a/bin/dao.sh +++ b/bin/dao.sh @@ -10,3 +10,4 @@ dao=$(jq -r ".SUBAPIDAO" $c3) seth send -F $deployer $subapi "transferOwnership(address)" $dao --chain darwinia seth send -F $deployer $subapi "transferOwnership(address)" $dao --chain arbitrum +seth send -F $deployer $subapi "transferOwnership(address)" $dao --chain ethereum diff --git a/bin/deploy.sh b/bin/deploy.sh index df2e9ce..6bef824 100755 --- a/bin/deploy.sh +++ b/bin/deploy.sh @@ -4,7 +4,8 @@ set -eo pipefail # forge script script/Deploy.s.sol:Deploy --chain-id 46 --broadcast --verify --slow # forge script script/Deploy.s.sol:Deploy --chain-id 42161 --broadcast --verify --slow --legacy +# forge script script/Deploy.s.sol:Deploy --chain-id 1 --broadcast --verify --slow --legacy -forge script script/Deploy.s.sol:Deploy --chain-id 44 --broadcast --verify -forge script script/Deploy.s.sol:Deploy --chain-id 421614 --broadcast --verify -forge script script/Deploy.s.sol:Deploy --chain-id 11155111 --broadcast --verify +# forge script script/Deploy.s.sol:Deploy --chain-id 44 --broadcast --verify +# forge script script/Deploy.s.sol:Deploy --chain-id 421614 --broadcast --verify +# forge script script/Deploy.s.sol:Deploy --chain-id 11155111 --broadcast --verify diff --git a/bin/verify.sh b/bin/verify.sh index e32b817..4b6d45d 100755 --- a/bin/verify.sh +++ b/bin/verify.sh @@ -27,4 +27,4 @@ verify() { $path > script/output/$chain_id/$name.v.json) } -verify $subapi 421614 $(cast abi-encode "constructor(address,address,address)" $deployer $rrp $ormp) src/SubAPI.sol:SubAPI +verify $subapi 1 $(cast abi-encode "constructor(address,address,address)" $deployer $rrp $ormp) src/SubAPI.sol:SubAPI diff --git a/foundry.toml b/foundry.toml index 52c7540..0e23841 100644 --- a/foundry.toml +++ b/foundry.toml @@ -28,6 +28,7 @@ crab = "https://crab-rpc.darwinia.network" 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}" [etherscan] arbitrum = { key = "${ETHERSCAN_ARBITRUM_KEY}" } diff --git a/script/input/1/config.c.json b/script/input/1/config.c.json new file mode 100644 index 0000000..8f90498 --- /dev/null +++ b/script/input/1/config.c.json @@ -0,0 +1,3 @@ +{ + "fee": 12000000000000000 +} diff --git a/script/input/1/deploy.c.json b/script/input/1/deploy.c.json new file mode 100644 index 0000000..506b6ae --- /dev/null +++ b/script/input/1/deploy.c.json @@ -0,0 +1,5 @@ +{ + "DAO": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", + "DEPLOYER": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", + "AIRNODE_RRP": "0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd" +} diff --git a/script/input/42161/config.c.json b/script/input/42161/config.c.json index f297994..d037315 100644 --- a/script/input/42161/config.c.json +++ b/script/input/42161/config.c.json @@ -1,4 +1,3 @@ { - "name": "Darwinia ORMP msgroot SubAPI", "fee": 500000000000000 } diff --git a/script/input/46/config.c.json b/script/input/46/config.c.json index d7a5896..c39c192 100644 --- a/script/input/46/config.c.json +++ b/script/input/46/config.c.json @@ -1,4 +1,3 @@ { - "name": "Arbitrum ORMP msgroot SubAPI", - "fee": 100000000000000000 + "fee": 1000000000000000000 } diff --git a/script/output/1/SubAPI.v.json b/script/output/1/SubAPI.v.json new file mode 100644 index 0000000..9369219 --- /dev/null +++ b/script/output/1/SubAPI.v.json @@ -0,0 +1,64 @@ +{ + "language": "Solidity", + "sources": { + "src/SubAPI.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nimport \"@openzeppelin/contracts@4.9.2/utils/structs/EnumerableSet.sol\";\nimport \"@openzeppelin/contracts@4.9.2/access/Ownable2Step.sol\";\nimport \"./interfaces/IFeedOracle.sol\";\nimport \"./RrpRequesterV0.sol\";\nimport \"./ORMPWrapper.sol\";\nimport \"./SubAPIFeed.sol\";\n\n/// @title SubAPI\n/// @dev The contract uses to serve data feeds of source chain finalized header\n/// dAPI security model is the same as edcsa pallet.\n/// @notice SubAPI serves data feeds in the form of BeaconSet.\n/// The BeaconSet are only updateable using RRPv0.\ncontract SubAPI is IFeedOracle, RrpRequesterV0, SubAPIFeed, ORMPWrapper, Ownable2Step {\n using EnumerableSet for EnumerableSet.Bytes32Set;\n\n event SetFee(uint256 indexed fee);\n event AddBeacon(uint256 indexed chainId, bytes32 indexed beaconId, Beacon beacon);\n event RemoveBeacon(uint256 indexed chainId, bytes32 indexed beaconId);\n event AirnodeRrpRequested(uint256 indexed chainId, bytes32 indexed beaconId, bytes32 indexed requestId);\n event AirnodeRrpCompleted(bytes32 indexed beaconId, bytes32 indexed requestId, bytes data);\n event AggregatedORMPData(uint256 indexed chainId, ORMPData ormpData);\n\n /// @notice Beacon metadata\n /// @dev beaconId must be different on multi chain\n /// @param chainId Chain ID\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param sponsor Sponsor address\n /// @param sponsorWallet Sponsor wallet address\n struct Beacon {\n uint256 chainId;\n address airnode;\n bytes32 endpointId;\n address sponsor;\n address payable sponsorWallet;\n }\n\n uint256 public fee;\n // requestId => beaconId\n mapping(bytes32 => bytes32) private _requestIdToBeaconId;\n // beaconId => requestId\n mapping(bytes32 => bytes32) private _beaconIdToRequestId;\n // chainId => beaconIdSet\n mapping(uint256 => EnumerableSet.Bytes32Set) private _beaconIds;\n\n /// @param dao SubAPIDao\n /// @param rrp Airnode RRP contract address\n /// @param ormp ORMP RRP address\n constructor(address dao, address rrp, address ormp) RrpRequesterV0(rrp) ORMPWrapper(ormp) {\n _transferOwnership(dao);\n }\n\n /// @notice Add a beacon to BeaconSet\n function addBeacon(uint256 chainId, Beacon calldata beacon) external onlyOwner {\n bytes32 beaconId = deriveBeaconId(beacon);\n require(chainId == beacon.chainId, \"!chainId\");\n require(_beaconIds[chainId].add(beaconId), \"!add\");\n emit AddBeacon(chainId, beaconId, beacon);\n }\n\n /// @notice Remove the beacon from BeaconSet\n function removeBeacon(uint256 chainId, bytes32 beaconId) external onlyOwner {\n require(_beaconIds[chainId].remove(beaconId), \"!rm\");\n emit RemoveBeacon(chainId, beaconId);\n }\n\n /// @notice change the beacon fee\n function setFee(uint256 fee_) external onlyOwner {\n fee = fee_;\n emit SetFee(fee_);\n }\n\n function remoteCommitmentOf(uint256 chainId) external view returns (uint256 count, bytes32 root) {\n ORMPData memory data = _aggregatedDataOf[chainId];\n count = data.count;\n root = data.root;\n }\n\n function messageRootOf(uint256 chainId) external view returns (bytes32) {\n return _aggregatedDataOf[chainId].root;\n }\n\n /// @notice Fetch request fee\n /// return tokenAddress if tokenAddress is Address(0x0), pay the native token\n /// fee the request fee\n function getRequestFeeOf(uint256 chainId) external view returns (address, uint256) {\n return (address(0), fee * beaconsLengthOf(chainId));\n }\n\n /// @notice Fetch beaconId by requestId\n function getBeaconIdByRequestId(bytes32 requestId) external view returns (bytes32) {\n return _requestIdToBeaconId[requestId];\n }\n\n /// @notice Fetch requestId by beaconId\n function getRequestIdByBeaconId(bytes32 beaconId) external view returns (bytes32) {\n return _beaconIdToRequestId[beaconId];\n }\n\n /// @notice BeaconSet length\n function beaconsLengthOf(uint256 chainId) public view returns (uint256) {\n return _beaconIds[chainId].length();\n }\n\n /// @notice Check if the beacon exist by Id\n function isBeaconExist(uint256 chainId, bytes32 beaconId) public view returns (bool) {\n return _beaconIds[chainId].contains(beaconId);\n }\n\n /// @notice Derives the Beacon ID from the Airnode address and endpoint ID\n /// @param beacon Beacon\n function deriveBeaconId(Beacon calldata beacon) public pure returns (bytes32 beaconId) {\n beaconId = keccak256(abi.encode(beacon));\n }\n\n function _request(Beacon calldata beacon, bytes32 beaconId) internal {\n uint256 chainId = beacon.chainId;\n beacon.sponsorWallet.transfer(fee);\n bytes32 requestId = airnodeRrp.makeFullRequest(\n beacon.airnode,\n beacon.endpointId,\n beacon.sponsor,\n beacon.sponsorWallet,\n address(this),\n this.fulfill.selector,\n \"\"\n );\n _requestIdToBeaconId[requestId] = beaconId;\n _beaconIdToRequestId[beaconId] = requestId;\n emit AirnodeRrpRequested(chainId, beaconId, requestId);\n }\n\n /// @notice Create a request for arbitrum finalized header\n /// Send reqeust to all beacon in BeaconSet\n function requestFinalizedHash(uint256 chainId, Beacon[] calldata beacons) external payable {\n uint256 beaconCount = beacons.length;\n require(beaconCount == beaconsLengthOf(chainId), \"!all\");\n require(msg.value == fee * beaconCount, \"!fee\");\n for (uint256 i = 0; i < beaconCount; i++) {\n bytes32 beaconId = deriveBeaconId(beacons[i]);\n require(isBeaconExist(chainId, beaconId), \"!exist\");\n require(chainId == beacons[i].chainId, \"!chainId\");\n _request(beacons[i], beaconId);\n }\n }\n\n /// @notice Called by the ArinodeRRP to fulfill the request\n /// @param requestId Request ID\n /// @param data Fulfillment data (`BlockData` encoded in contract ABI)\n function fulfill(bytes32 requestId, bytes calldata data) external onlyAirnodeRrp {\n bytes32 beaconId = _requestIdToBeaconId[requestId];\n require(beaconId != bytes32(0), \"!requestId\");\n if (_beaconIdToRequestId[beaconId] == requestId) {\n delete _requestIdToBeaconId[requestId];\n delete _beaconIdToRequestId[beaconId];\n _processBeaconUpdate(beaconId, data);\n emit AirnodeRrpCompleted(beaconId, requestId, data);\n } else {\n delete _requestIdToBeaconId[requestId];\n }\n }\n\n /// @notice Called to aggregate the BeaconSet and save the result.\n /// beaconIds should be a supermajor(>2/3) subset of all beacons in contract.\n /// @param beaconIds Beacon IDs should be sorted in ascending order\n function aggregateBeacons(uint256 chainId, bytes32[] calldata beaconIds) external {\n uint256 beaconCount = beaconIds.length;\n bytes32[] memory allBeaconIds = _beaconIds[chainId].values();\n require(beaconCount * 3 > allBeaconIds.length * 2, \"!supermajor\");\n ORMPData[] memory datas = _checkAndGetDatasFromBeacons(chainId, beaconIds);\n ORMPData memory data = datas[0];\n for (uint256 i = 1; i < beaconCount; i++) {\n require(eq(data, datas[i]), \"!agg\");\n }\n require(neq(_aggregatedDataOf[chainId], data), \"same\");\n _aggregatedDataOf[chainId] = data;\n emit AggregatedORMPData(chainId, data);\n }\n\n function _checkAndGetDatasFromBeacons(uint256 chainId, bytes32[] calldata beaconIds)\n internal\n view\n returns (ORMPData[] memory)\n {\n uint256 beaconCount = beaconIds.length;\n ORMPData[] memory datas = new ORMPData[](beaconCount);\n bytes32 last = bytes32(0);\n bytes32 current;\n for (uint256 i = 0; i < beaconCount; i++) {\n current = beaconIds[i];\n require(current > last && isBeaconExist(chainId, current), \"!beacon\");\n datas[i] = _dataFeeds[current];\n last = current;\n }\n return datas;\n }\n}\n" + }, + "lib/zeppelin-solidity/contracts/utils/structs/EnumerableSet.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(bytes32 => uint256) _indexes;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._indexes[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We read and store the value's index to prevent multiple reads from the same storage slot\n uint256 valueIndex = set._indexes[value];\n\n if (valueIndex != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 toDeleteIndex = valueIndex - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (lastIndex != toDeleteIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the last value to the index where the value to delete is\n set._values[toDeleteIndex] = lastValue;\n // Update the index for the moved value\n set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the index for the deleted slot\n delete set._indexes[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._indexes[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n" + }, + "lib/zeppelin-solidity/contracts/access/Ownable2Step.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./Ownable.sol\";\n\n/**\n * @dev Contract module which provides access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2Step is Ownable {\n address private _pendingOwner;\n\n event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Returns the address of the pending owner.\n */\n function pendingOwner() public view virtual returns (address) {\n return _pendingOwner;\n }\n\n /**\n * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual override onlyOwner {\n _pendingOwner = newOwner;\n emit OwnershipTransferStarted(owner(), newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual override {\n delete _pendingOwner;\n super._transferOwnership(newOwner);\n }\n\n /**\n * @dev The new owner accepts the ownership transfer.\n */\n function acceptOwnership() public virtual {\n address sender = _msgSender();\n require(pendingOwner() == sender, \"Ownable2Step: caller is not the new owner\");\n _transferOwnership(sender);\n }\n}\n" + }, + "src/interfaces/IFeedOracle.sol": { + "content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2022 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/RrpRequesterV0.sol": { + "content": "// SPDX-License-Identifier: MIT\n//\n// Inspired: https://github.com/api3dao/airnode/blob/master/packages/airnode-protocol/contracts/rrp/requesters/RrpRequesterV0.sol\n\npragma solidity 0.8.17;\n\nimport \"./interfaces/IAirnodeRrpV0.sol\";\n\n/// @title The contract to be inherited to make Airnode RRP requests\ncontract RrpRequesterV0 {\n IAirnodeRrpV0 public immutable airnodeRrp;\n\n /// @dev Reverts if the caller is not the Airnode RRP contract.\n /// Use it as a modifier for fulfill and error callback methods, but also\n /// check `requestId`.\n modifier onlyAirnodeRrp() {\n require(msg.sender == address(airnodeRrp), \"Caller not Airnode RRP\");\n _;\n }\n\n /// @dev Airnode RRP address is set at deployment and is immutable.\n /// RrpRequester is made its own sponsor by default. RrpRequester can also\n /// be sponsored by others and use these sponsorships while making\n /// requests, i.e., using this default sponsorship is optional.\n /// @param _airnodeRrp Airnode RRP contract address\n constructor(address _airnodeRrp) {\n airnodeRrp = IAirnodeRrpV0(_airnodeRrp);\n IAirnodeRrpV0(_airnodeRrp).setSponsorshipStatus(address(this), true);\n }\n}\n" + }, + "src/ORMPWrapper.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\ninterface IORMP {\n function root() external view returns (bytes32);\n function messageCount() external view returns (uint256);\n}\n\ncontract ORMPWrapper {\n address public immutable ORMP;\n\n constructor(address ormp) {\n ORMP = ormp;\n }\n\n function localCommitment() external view returns (uint256 count, bytes32 root) {\n count = IORMP(ORMP).messageCount();\n root = IORMP(ORMP).root();\n }\n}\n" + }, + "src/SubAPIFeed.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\ncontract SubAPIFeed {\n event SubAPIFeedUpdated(bytes32 indexed beaconId, ORMPData msgRoot);\n\n struct ORMPData {\n // ormp message count\n uint256 count;\n // ormp message root\n bytes32 root;\n }\n\n // chainId => ORMPData\n mapping(uint256 => ORMPData) internal _aggregatedDataOf;\n // beaconId => ORMPData\n mapping(bytes32 => ORMPData) internal _dataFeeds;\n\n function _processBeaconUpdate(bytes32 beaconId, bytes calldata data) internal {\n bytes memory decodeData = abi.decode(data, (bytes));\n ORMPData memory ormpData = abi.decode(decodeData, (ORMPData));\n _dataFeeds[beaconId] = ormpData;\n emit SubAPIFeedUpdated(beaconId, ormpData);\n }\n\n function getDataFeedWithId(bytes32 beaconId) public view returns (ORMPData memory msgRoot) {\n return _dataFeeds[beaconId];\n }\n\n function eq(ORMPData memory a, ORMPData memory b) public pure returns (bool) {\n return (a.count == b.count && a.root == b.root);\n }\n\n function neq(ORMPData memory a, ORMPData memory b) public pure returns (bool) {\n return (a.count != b.count || a.root != b.root);\n }\n}\n" + }, + "lib/zeppelin-solidity/contracts/access/Ownable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby disabling any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" + }, + "src/interfaces/IAirnodeRrpV0.sol": { + "content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2022 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 IAirnodeRrpV0 {\n function setSponsorshipStatus(address requester, bool sponsorshipStatus) external;\n function makeFullRequest(\n address airnode,\n bytes32 endpointId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata parameters\n ) external returns (bytes32 requestId);\n}\n" + }, + "lib/zeppelin-solidity/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" + } + }, + "settings": { + "remappings": [ + "@openzeppelin/contracts@4.9.2/=lib/zeppelin-solidity/contracts/" + ], + "optimizer": { + "enabled": true, + "runs": 999999 + }, + "metadata": { + "useLiteralContent": true, + "bytecodeHash": "ipfs" + }, + "outputSelection": { + "*": { + "": [ + "ast" + ], + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ] + } + }, + "evmVersion": "london", + "libraries": {} + } +} diff --git a/script/output/1/deploy.a-latest.json b/script/output/1/deploy.a-latest.json new file mode 100644 index 0000000..4a50601 --- /dev/null +++ b/script/output/1/deploy.a-latest.json @@ -0,0 +1,4 @@ +{ + "DAO": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", + "SUBAPI": "0x00000000096c285629Fe3EAb3dd042c27b9dcBa6" +} \ No newline at end of file diff --git a/script/output/42161/SubAPI.v.json b/script/output/42161/SubAPI.v.json index 9c899f6..a6b1561 100644 --- a/script/output/42161/SubAPI.v.json +++ b/script/output/42161/SubAPI.v.json @@ -1 +1 @@ -{"language":"Solidity","sources":{"src/SubAPI.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nimport \"@openzeppelin/contracts@4.9.2/utils/structs/EnumerableSet.sol\";\nimport \"@openzeppelin/contracts@4.9.2/access/Ownable2Step.sol\";\nimport \"./interfaces/IFeedOracle.sol\";\nimport \"./RrpRequesterV0.sol\";\nimport \"./ORMPWrapper.sol\";\nimport \"./SubAPIFeed.sol\";\n\n/// @title SubAPI\n/// @dev The contract uses to serve data feeds of source chain finalized header\n/// dAPI security model is the same as edcsa pallet.\n/// @notice SubAPI serves data feeds in the form of BeaconSet.\n/// The BeaconSet are only updateable using RRPv0.\ncontract SubAPI is IFeedOracle, RrpRequesterV0, SubAPIFeed, ORMPWrapper, Ownable2Step {\n using EnumerableSet for EnumerableSet.Bytes32Set;\n\n event SetFee(uint256 indexed fee);\n event AddBeacon(bytes32 indexed beaconId, Beacon beacon);\n event RemoveBeacon(bytes32 indexed beaconId);\n event AirnodeRrpRequested(bytes32 indexed beaconId, bytes32 indexed requestId);\n event AirnodeRrpCompleted(bytes32 indexed beaconId, bytes32 indexed requestId, bytes data);\n event AggregatedORMPData(ORMPData ormpData);\n\n /// @notice Beacon metadata\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param sponsor Sponsor address\n /// @param sponsorWallet Sponsor wallet address\n struct Beacon {\n address airnode;\n bytes32 endpointId;\n address sponsor;\n address payable sponsorWallet;\n }\n\n // name for subAPI\n string public name;\n // fee pay to beacon sponsor wallet address for gas\n uint256 public fee;\n // requestId => beaconId\n mapping(bytes32 => bytes32) private _requestIdToBeaconId;\n // beaconId => requestId\n mapping(bytes32 => bytes32) private _beaconIdToRequestId;\n // beaconIdSet\n EnumerableSet.Bytes32Set private _beaconIds;\n\n /// @param dao SubAPIDao\n /// @param rrp Airnode RRP contract address\n /// @param ormp ORMP RRP address\n constructor(address dao, address rrp, address ormp) RrpRequesterV0(rrp) ORMPWrapper(ormp) {\n _transferOwnership(dao);\n }\n\n function setName(string memory name_) external onlyOwner {\n name = name_;\n }\n\n /// @notice Add a beacon to BeaconSet\n function addBeacon(Beacon calldata beacon) external onlyOwner {\n bytes32 beaconId = deriveBeaconId(beacon);\n require(_beaconIds.add(beaconId), \"!add\");\n emit AddBeacon(beaconId, beacon);\n }\n\n /// @notice Remove the beacon from BeaconSet\n function removeBeacon(bytes32 beaconId) external onlyOwner {\n require(_beaconIds.remove(beaconId), \"!rm\");\n emit RemoveBeacon(beaconId);\n }\n\n /// @notice change the beacon fee\n function setFee(uint256 fee_) external onlyOwner {\n fee = fee_;\n emit SetFee(fee_);\n }\n\n function remoteCommitment() external view returns (uint256 count, bytes32 root) {\n count = _aggregatedData.count;\n root = _aggregatedData.root;\n }\n\n function messageRoot() external view returns (bytes32) {\n return _aggregatedData.root;\n }\n\n /// @notice Fetch request fee\n /// return tokenAddress if tokenAddress is Address(0x0), pay the native token\n /// fee the request fee\n function getRequestFee() external view returns (address, uint256) {\n return (address(0), fee * beaconsLength());\n }\n\n /// @notice Fetch beaconId by requestId\n function getBeaconIdByRequestId(bytes32 requestId) external view returns (bytes32) {\n return _requestIdToBeaconId[requestId];\n }\n\n /// @notice Fetch requestId by beaconId\n function getRequestIdByBeaconId(bytes32 beaconId) external view returns (bytes32) {\n return _beaconIdToRequestId[beaconId];\n }\n\n /// @notice BeaconSet length\n function beaconsLength() public view returns (uint256) {\n return _beaconIds.length();\n }\n\n /// @notice Check if the beacon exist by Id\n function isBeaconExist(bytes32 beaconId) public view returns (bool) {\n return _beaconIds.contains(beaconId);\n }\n\n /// @notice Derives the Beacon ID from the Airnode address and endpoint ID\n /// @param beacon Beacon\n function deriveBeaconId(Beacon calldata beacon) public pure returns (bytes32 beaconId) {\n beaconId = keccak256(abi.encode(beacon));\n }\n\n function _request(Beacon calldata beacon, bytes32 beaconId) internal {\n beacon.sponsorWallet.transfer(fee);\n bytes32 requestId = airnodeRrp.makeFullRequest(\n beacon.airnode,\n beacon.endpointId,\n beacon.sponsor,\n beacon.sponsorWallet,\n address(this),\n this.fulfill.selector,\n \"\"\n );\n _requestIdToBeaconId[requestId] = beaconId;\n _beaconIdToRequestId[beaconId] = requestId;\n emit AirnodeRrpRequested(beaconId, requestId);\n }\n\n /// @notice Create a request for arbitrum finalized header\n /// Send reqeust to all beacon in BeaconSet\n function requestFinalizedHash(Beacon[] calldata beacons) external payable {\n uint256 beaconCount = beacons.length;\n require(beaconCount == beaconsLength(), \"!all\");\n require(msg.value == fee * beaconCount, \"!fee\");\n for (uint256 i = 0; i < beaconCount; i++) {\n bytes32 beaconId = deriveBeaconId(beacons[i]);\n require(isBeaconExist(beaconId), \"!exist\");\n _request(beacons[i], beaconId);\n }\n }\n\n /// @notice Called by the ArinodeRRP to fulfill the request\n /// @param requestId Request ID\n /// @param data Fulfillment data (`BlockData` encoded in contract ABI)\n function fulfill(bytes32 requestId, bytes calldata data) external onlyAirnodeRrp {\n bytes32 beaconId = _requestIdToBeaconId[requestId];\n require(beaconId != bytes32(0), \"!requestId\");\n if (_beaconIdToRequestId[beaconId] == requestId) {\n delete _requestIdToBeaconId[requestId];\n delete _beaconIdToRequestId[beaconId];\n _processBeaconUpdate(beaconId, data);\n emit AirnodeRrpCompleted(beaconId, requestId, data);\n } else {\n delete _requestIdToBeaconId[requestId];\n }\n }\n\n /// @notice Called to aggregate the BeaconSet and save the result.\n /// beaconIds should be a supermajor(>2/3) subset of all beacons in contract.\n /// @param beaconIds Beacon IDs should be sorted in ascending order\n function aggregateBeacons(bytes32[] calldata beaconIds) external {\n uint256 beaconCount = beaconIds.length;\n bytes32[] memory allBeaconIds = _beaconIds.values();\n require(beaconCount * 3 > allBeaconIds.length * 2, \"!supermajor\");\n ORMPData[] memory datas = _checkAndGetDatasFromBeacons(beaconIds);\n ORMPData memory data = datas[0];\n for (uint256 i = 1; i < beaconCount; i++) {\n require(eq(data, datas[i]), \"!agg\");\n }\n require(neq(_aggregatedData, data), \"same\");\n _aggregatedData = data;\n emit AggregatedORMPData(data);\n }\n\n function _checkAndGetDatasFromBeacons(bytes32[] calldata beaconIds) internal view returns (ORMPData[] memory) {\n uint256 beaconCount = beaconIds.length;\n ORMPData[] memory datas = new ORMPData[](beaconCount);\n bytes32 last = bytes32(0);\n bytes32 current;\n for (uint256 i = 0; i < beaconCount; i++) {\n current = beaconIds[i];\n require(current > last && isBeaconExist(current), \"!beacon\");\n datas[i] = _dataFeeds[current];\n last = current;\n }\n return datas;\n }\n}\n"},"lib/zeppelin-solidity/contracts/utils/structs/EnumerableSet.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(bytes32 => uint256) _indexes;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._indexes[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We read and store the value's index to prevent multiple reads from the same storage slot\n uint256 valueIndex = set._indexes[value];\n\n if (valueIndex != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 toDeleteIndex = valueIndex - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (lastIndex != toDeleteIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the last value to the index where the value to delete is\n set._values[toDeleteIndex] = lastValue;\n // Update the index for the moved value\n set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the index for the deleted slot\n delete set._indexes[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._indexes[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n"},"lib/zeppelin-solidity/contracts/access/Ownable2Step.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./Ownable.sol\";\n\n/**\n * @dev Contract module which provides access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2Step is Ownable {\n address private _pendingOwner;\n\n event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Returns the address of the pending owner.\n */\n function pendingOwner() public view virtual returns (address) {\n return _pendingOwner;\n }\n\n /**\n * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual override onlyOwner {\n _pendingOwner = newOwner;\n emit OwnershipTransferStarted(owner(), newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual override {\n delete _pendingOwner;\n super._transferOwnership(newOwner);\n }\n\n /**\n * @dev The new owner accepts the ownership transfer.\n */\n function acceptOwnership() public virtual {\n address sender = _msgSender();\n require(pendingOwner() == sender, \"Ownable2Step: caller is not the new owner\");\n _transferOwnership(sender);\n }\n}\n"},"src/interfaces/IFeedOracle.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2022 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IFeedOracle {\n function messageRoot() external view returns (bytes32);\n}\n"},"src/RrpRequesterV0.sol":{"content":"// SPDX-License-Identifier: MIT\n//\n// Inspired: https://github.com/api3dao/airnode/blob/master/packages/airnode-protocol/contracts/rrp/requesters/RrpRequesterV0.sol\n\npragma solidity 0.8.17;\n\nimport \"./interfaces/IAirnodeRrpV0.sol\";\n\n/// @title The contract to be inherited to make Airnode RRP requests\ncontract RrpRequesterV0 {\n IAirnodeRrpV0 public immutable airnodeRrp;\n\n /// @dev Reverts if the caller is not the Airnode RRP contract.\n /// Use it as a modifier for fulfill and error callback methods, but also\n /// check `requestId`.\n modifier onlyAirnodeRrp() {\n require(msg.sender == address(airnodeRrp), \"Caller not Airnode RRP\");\n _;\n }\n\n /// @dev Airnode RRP address is set at deployment and is immutable.\n /// RrpRequester is made its own sponsor by default. RrpRequester can also\n /// be sponsored by others and use these sponsorships while making\n /// requests, i.e., using this default sponsorship is optional.\n /// @param _airnodeRrp Airnode RRP contract address\n constructor(address _airnodeRrp) {\n airnodeRrp = IAirnodeRrpV0(_airnodeRrp);\n IAirnodeRrpV0(_airnodeRrp).setSponsorshipStatus(address(this), true);\n }\n}\n"},"src/ORMPWrapper.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\ninterface IORMP {\n function root() external view returns (bytes32);\n function messageCount() external view returns (uint256);\n}\n\ncontract ORMPWrapper {\n address public immutable ORMP;\n\n constructor(address ormp) {\n ORMP = ormp;\n }\n\n function localCommitment() external view returns (uint256 count, bytes32 root) {\n count = IORMP(ORMP).messageCount();\n root = IORMP(ORMP).root();\n }\n}\n"},"src/SubAPIFeed.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\ncontract SubAPIFeed {\n event SubAPIFeedUpdated(bytes32 indexed beaconId, ORMPData msgRoot);\n\n struct ORMPData {\n // ormp message count\n uint256 count;\n // ormp message root\n bytes32 root;\n }\n\n ORMPData internal _aggregatedData;\n // beaconId => ORMPData\n mapping(bytes32 => ORMPData) internal _dataFeeds;\n\n function _processBeaconUpdate(bytes32 beaconId, bytes calldata data) internal {\n bytes memory decodeData = abi.decode(data, (bytes));\n ORMPData memory ormpData = abi.decode(decodeData, (ORMPData));\n _dataFeeds[beaconId] = ormpData;\n emit SubAPIFeedUpdated(beaconId, ormpData);\n }\n\n function getDataFeedWithId(bytes32 beaconId) public view returns (ORMPData memory msgRoot) {\n return _dataFeeds[beaconId];\n }\n\n function eq(ORMPData memory a, ORMPData memory b) public pure returns (bool) {\n return (a.count == b.count && a.root == b.root);\n }\n\n function neq(ORMPData memory a, ORMPData memory b) public pure returns (bool) {\n return (a.count != b.count || a.root != b.root);\n }\n}\n"},"lib/zeppelin-solidity/contracts/access/Ownable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby disabling any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n"},"src/interfaces/IAirnodeRrpV0.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2022 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 IAirnodeRrpV0 {\n function setSponsorshipStatus(address requester, bool sponsorshipStatus) external;\n function makeFullRequest(\n address airnode,\n bytes32 endpointId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata parameters\n ) external returns (bytes32 requestId);\n}\n"},"lib/zeppelin-solidity/contracts/utils/Context.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n"}},"settings":{"remappings":["@openzeppelin/contracts@4.9.2/=lib/zeppelin-solidity/contracts/","ds-test/=lib/forge-std/lib/ds-test/src/","create3-deploy/=lib/create3-deploy/","forge-std/=lib/forge-std/src/","erc4626-tests/=lib/zeppelin-solidity/lib/erc4626-tests/","openzeppelin/=lib/zeppelin-solidity/contracts/","solmate/=lib/create3-deploy/lib/solmate/src/","zeppelin-solidity/=lib/zeppelin-solidity/"],"optimizer":{"enabled":true,"runs":999999},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs"},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"london","libraries":{}}} +{"language":"Solidity","sources":{"src/SubAPI.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nimport \"@openzeppelin/contracts@4.9.2/utils/structs/EnumerableSet.sol\";\nimport \"@openzeppelin/contracts@4.9.2/access/Ownable2Step.sol\";\nimport \"./interfaces/IFeedOracle.sol\";\nimport \"./RrpRequesterV0.sol\";\nimport \"./ORMPWrapper.sol\";\nimport \"./SubAPIFeed.sol\";\n\n/// @title SubAPI\n/// @dev The contract uses to serve data feeds of source chain finalized header\n/// dAPI security model is the same as edcsa pallet.\n/// @notice SubAPI serves data feeds in the form of BeaconSet.\n/// The BeaconSet are only updateable using RRPv0.\ncontract SubAPI is IFeedOracle, RrpRequesterV0, SubAPIFeed, ORMPWrapper, Ownable2Step {\n using EnumerableSet for EnumerableSet.Bytes32Set;\n\n event SetFee(uint256 indexed fee);\n event AddBeacon(uint256 indexed chainId, bytes32 indexed beaconId, Beacon beacon);\n event RemoveBeacon(uint256 indexed chainId, bytes32 indexed beaconId);\n event AirnodeRrpRequested(uint256 indexed chainId, bytes32 indexed beaconId, bytes32 indexed requestId);\n event AirnodeRrpCompleted(bytes32 indexed beaconId, bytes32 indexed requestId, bytes data);\n event AggregatedORMPData(uint256 indexed chainId, ORMPData ormpData);\n\n /// @notice Beacon metadata\n /// @dev beaconId must be different on multi chain\n /// @param chainId Chain ID\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param sponsor Sponsor address\n /// @param sponsorWallet Sponsor wallet address\n struct Beacon {\n uint256 chainId;\n address airnode;\n bytes32 endpointId;\n address sponsor;\n address payable sponsorWallet;\n }\n\n uint256 public fee;\n // requestId => beaconId\n mapping(bytes32 => bytes32) private _requestIdToBeaconId;\n // beaconId => requestId\n mapping(bytes32 => bytes32) private _beaconIdToRequestId;\n // chainId => beaconIdSet\n mapping(uint256 => EnumerableSet.Bytes32Set) private _beaconIds;\n\n /// @param dao SubAPIDao\n /// @param rrp Airnode RRP contract address\n /// @param ormp ORMP RRP address\n constructor(address dao, address rrp, address ormp) RrpRequesterV0(rrp) ORMPWrapper(ormp) {\n _transferOwnership(dao);\n }\n\n /// @notice Add a beacon to BeaconSet\n function addBeacon(uint256 chainId, Beacon calldata beacon) external onlyOwner {\n bytes32 beaconId = deriveBeaconId(beacon);\n require(chainId == beacon.chainId, \"!chainId\");\n require(_beaconIds[chainId].add(beaconId), \"!add\");\n emit AddBeacon(chainId, beaconId, beacon);\n }\n\n /// @notice Remove the beacon from BeaconSet\n function removeBeacon(uint256 chainId, bytes32 beaconId) external onlyOwner {\n require(_beaconIds[chainId].remove(beaconId), \"!rm\");\n emit RemoveBeacon(chainId, beaconId);\n }\n\n /// @notice change the beacon fee\n function setFee(uint256 fee_) external onlyOwner {\n fee = fee_;\n emit SetFee(fee_);\n }\n\n function remoteCommitmentOf(uint256 chainId) external view returns (uint256 count, bytes32 root) {\n ORMPData memory data = _aggregatedDataOf[chainId];\n count = data.count;\n root = data.root;\n }\n\n function messageRootOf(uint256 chainId) external view returns (bytes32) {\n return _aggregatedDataOf[chainId].root;\n }\n\n /// @notice Fetch request fee\n /// return tokenAddress if tokenAddress is Address(0x0), pay the native token\n /// fee the request fee\n function getRequestFeeOf(uint256 chainId) external view returns (address, uint256) {\n return (address(0), fee * beaconsLengthOf(chainId));\n }\n\n /// @notice Fetch beaconId by requestId\n function getBeaconIdByRequestId(bytes32 requestId) external view returns (bytes32) {\n return _requestIdToBeaconId[requestId];\n }\n\n /// @notice Fetch requestId by beaconId\n function getRequestIdByBeaconId(bytes32 beaconId) external view returns (bytes32) {\n return _beaconIdToRequestId[beaconId];\n }\n\n /// @notice BeaconSet length\n function beaconsLengthOf(uint256 chainId) public view returns (uint256) {\n return _beaconIds[chainId].length();\n }\n\n /// @notice Check if the beacon exist by Id\n function isBeaconExist(uint256 chainId, bytes32 beaconId) public view returns (bool) {\n return _beaconIds[chainId].contains(beaconId);\n }\n\n /// @notice Derives the Beacon ID from the Airnode address and endpoint ID\n /// @param beacon Beacon\n function deriveBeaconId(Beacon calldata beacon) public pure returns (bytes32 beaconId) {\n beaconId = keccak256(abi.encode(beacon));\n }\n\n function _request(Beacon calldata beacon, bytes32 beaconId) internal {\n uint256 chainId = beacon.chainId;\n beacon.sponsorWallet.transfer(fee);\n bytes32 requestId = airnodeRrp.makeFullRequest(\n beacon.airnode,\n beacon.endpointId,\n beacon.sponsor,\n beacon.sponsorWallet,\n address(this),\n this.fulfill.selector,\n \"\"\n );\n _requestIdToBeaconId[requestId] = beaconId;\n _beaconIdToRequestId[beaconId] = requestId;\n emit AirnodeRrpRequested(chainId, beaconId, requestId);\n }\n\n /// @notice Create a request for arbitrum finalized header\n /// Send reqeust to all beacon in BeaconSet\n function requestFinalizedHash(uint256 chainId, Beacon[] calldata beacons) external payable {\n uint256 beaconCount = beacons.length;\n require(beaconCount == beaconsLengthOf(chainId), \"!all\");\n require(msg.value == fee * beaconCount, \"!fee\");\n for (uint256 i = 0; i < beaconCount; i++) {\n bytes32 beaconId = deriveBeaconId(beacons[i]);\n require(isBeaconExist(chainId, beaconId), \"!exist\");\n require(chainId == beacons[i].chainId, \"!chainId\");\n _request(beacons[i], beaconId);\n }\n }\n\n /// @notice Called by the ArinodeRRP to fulfill the request\n /// @param requestId Request ID\n /// @param data Fulfillment data (`BlockData` encoded in contract ABI)\n function fulfill(bytes32 requestId, bytes calldata data) external onlyAirnodeRrp {\n bytes32 beaconId = _requestIdToBeaconId[requestId];\n require(beaconId != bytes32(0), \"!requestId\");\n if (_beaconIdToRequestId[beaconId] == requestId) {\n delete _requestIdToBeaconId[requestId];\n delete _beaconIdToRequestId[beaconId];\n _processBeaconUpdate(beaconId, data);\n emit AirnodeRrpCompleted(beaconId, requestId, data);\n } else {\n delete _requestIdToBeaconId[requestId];\n }\n }\n\n /// @notice Called to aggregate the BeaconSet and save the result.\n /// beaconIds should be a supermajor(>2/3) subset of all beacons in contract.\n /// @param beaconIds Beacon IDs should be sorted in ascending order\n function aggregateBeacons(uint256 chainId, bytes32[] calldata beaconIds) external {\n uint256 beaconCount = beaconIds.length;\n bytes32[] memory allBeaconIds = _beaconIds[chainId].values();\n require(beaconCount * 3 > allBeaconIds.length * 2, \"!supermajor\");\n ORMPData[] memory datas = _checkAndGetDatasFromBeacons(chainId, beaconIds);\n ORMPData memory data = datas[0];\n for (uint256 i = 1; i < beaconCount; i++) {\n require(eq(data, datas[i]), \"!agg\");\n }\n require(neq(_aggregatedDataOf[chainId], data), \"same\");\n _aggregatedDataOf[chainId] = data;\n emit AggregatedORMPData(chainId, data);\n }\n\n function _checkAndGetDatasFromBeacons(uint256 chainId, bytes32[] calldata beaconIds)\n internal\n view\n returns (ORMPData[] memory)\n {\n uint256 beaconCount = beaconIds.length;\n ORMPData[] memory datas = new ORMPData[](beaconCount);\n bytes32 last = bytes32(0);\n bytes32 current;\n for (uint256 i = 0; i < beaconCount; i++) {\n current = beaconIds[i];\n require(current > last && isBeaconExist(chainId, current), \"!beacon\");\n datas[i] = _dataFeeds[current];\n last = current;\n }\n return datas;\n }\n}\n"},"lib/zeppelin-solidity/contracts/utils/structs/EnumerableSet.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(bytes32 => uint256) _indexes;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._indexes[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We read and store the value's index to prevent multiple reads from the same storage slot\n uint256 valueIndex = set._indexes[value];\n\n if (valueIndex != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 toDeleteIndex = valueIndex - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (lastIndex != toDeleteIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the last value to the index where the value to delete is\n set._values[toDeleteIndex] = lastValue;\n // Update the index for the moved value\n set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the index for the deleted slot\n delete set._indexes[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._indexes[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n"},"lib/zeppelin-solidity/contracts/access/Ownable2Step.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./Ownable.sol\";\n\n/**\n * @dev Contract module which provides access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2Step is Ownable {\n address private _pendingOwner;\n\n event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Returns the address of the pending owner.\n */\n function pendingOwner() public view virtual returns (address) {\n return _pendingOwner;\n }\n\n /**\n * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual override onlyOwner {\n _pendingOwner = newOwner;\n emit OwnershipTransferStarted(owner(), newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual override {\n delete _pendingOwner;\n super._transferOwnership(newOwner);\n }\n\n /**\n * @dev The new owner accepts the ownership transfer.\n */\n function acceptOwnership() public virtual {\n address sender = _msgSender();\n require(pendingOwner() == sender, \"Ownable2Step: caller is not the new owner\");\n _transferOwnership(sender);\n }\n}\n"},"src/interfaces/IFeedOracle.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2022 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/RrpRequesterV0.sol":{"content":"// SPDX-License-Identifier: MIT\n//\n// Inspired: https://github.com/api3dao/airnode/blob/master/packages/airnode-protocol/contracts/rrp/requesters/RrpRequesterV0.sol\n\npragma solidity 0.8.17;\n\nimport \"./interfaces/IAirnodeRrpV0.sol\";\n\n/// @title The contract to be inherited to make Airnode RRP requests\ncontract RrpRequesterV0 {\n IAirnodeRrpV0 public immutable airnodeRrp;\n\n /// @dev Reverts if the caller is not the Airnode RRP contract.\n /// Use it as a modifier for fulfill and error callback methods, but also\n /// check `requestId`.\n modifier onlyAirnodeRrp() {\n require(msg.sender == address(airnodeRrp), \"Caller not Airnode RRP\");\n _;\n }\n\n /// @dev Airnode RRP address is set at deployment and is immutable.\n /// RrpRequester is made its own sponsor by default. RrpRequester can also\n /// be sponsored by others and use these sponsorships while making\n /// requests, i.e., using this default sponsorship is optional.\n /// @param _airnodeRrp Airnode RRP contract address\n constructor(address _airnodeRrp) {\n airnodeRrp = IAirnodeRrpV0(_airnodeRrp);\n IAirnodeRrpV0(_airnodeRrp).setSponsorshipStatus(address(this), true);\n }\n}\n"},"src/ORMPWrapper.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\ninterface IORMP {\n function root() external view returns (bytes32);\n function messageCount() external view returns (uint256);\n}\n\ncontract ORMPWrapper {\n address public immutable ORMP;\n\n constructor(address ormp) {\n ORMP = ormp;\n }\n\n function localCommitment() external view returns (uint256 count, bytes32 root) {\n count = IORMP(ORMP).messageCount();\n root = IORMP(ORMP).root();\n }\n}\n"},"src/SubAPIFeed.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\ncontract SubAPIFeed {\n event SubAPIFeedUpdated(bytes32 indexed beaconId, ORMPData msgRoot);\n\n struct ORMPData {\n // ormp message count\n uint256 count;\n // ormp message root\n bytes32 root;\n }\n\n // chainId => ORMPData\n mapping(uint256 => ORMPData) internal _aggregatedDataOf;\n // beaconId => ORMPData\n mapping(bytes32 => ORMPData) internal _dataFeeds;\n\n function _processBeaconUpdate(bytes32 beaconId, bytes calldata data) internal {\n bytes memory decodeData = abi.decode(data, (bytes));\n ORMPData memory ormpData = abi.decode(decodeData, (ORMPData));\n _dataFeeds[beaconId] = ormpData;\n emit SubAPIFeedUpdated(beaconId, ormpData);\n }\n\n function getDataFeedWithId(bytes32 beaconId) public view returns (ORMPData memory msgRoot) {\n return _dataFeeds[beaconId];\n }\n\n function eq(ORMPData memory a, ORMPData memory b) public pure returns (bool) {\n return (a.count == b.count && a.root == b.root);\n }\n\n function neq(ORMPData memory a, ORMPData memory b) public pure returns (bool) {\n return (a.count != b.count || a.root != b.root);\n }\n}\n"},"lib/zeppelin-solidity/contracts/access/Ownable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby disabling any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n"},"src/interfaces/IAirnodeRrpV0.sol":{"content":"// This file is part of Darwinia.\n// Copyright (C) 2018-2022 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 IAirnodeRrpV0 {\n function setSponsorshipStatus(address requester, bool sponsorshipStatus) external;\n function makeFullRequest(\n address airnode,\n bytes32 endpointId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata parameters\n ) external returns (bytes32 requestId);\n}\n"},"lib/zeppelin-solidity/contracts/utils/Context.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n"}},"settings":{"remappings":["@openzeppelin/contracts@4.9.2/=lib/zeppelin-solidity/contracts/","ds-test/=lib/forge-std/lib/ds-test/src/","create3-deploy/=lib/create3-deploy/","forge-std/=lib/forge-std/src/","ORMP/=lib/ORMP/","erc4626-tests/=lib/zeppelin-solidity/lib/erc4626-tests/","openzeppelin/=lib/zeppelin-solidity/contracts/","solmate/=lib/create3-deploy/lib/solmate/src/","zeppelin-solidity/=lib/zeppelin-solidity/"],"optimizer":{"enabled":true,"runs":999999},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs"},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"london","libraries":{}}} diff --git a/script/output/42161/deploy.a-latest.json b/script/output/42161/deploy.a-latest.json index d60bcfd..4a50601 100644 --- a/script/output/42161/deploy.a-latest.json +++ b/script/output/42161/deploy.a-latest.json @@ -1,4 +1,4 @@ { "DAO": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", - "SUBAPI": "0x00000000007317c91F57D86A410934A490E62E1E" + "SUBAPI": "0x00000000096c285629Fe3EAb3dd042c27b9dcBa6" } \ No newline at end of file diff --git a/script/output/46/SubAPI.v.json b/script/output/46/SubAPI.v.json index 587db37..ad99c73 100644 --- a/script/output/46/SubAPI.v.json +++ b/script/output/46/SubAPI.v.json @@ -1 +1 @@ -{"language": "Solidity", "sources": {"src/SubAPI.sol": {"content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nimport \"@openzeppelin/contracts@4.9.2/utils/structs/EnumerableSet.sol\";\nimport \"@openzeppelin/contracts@4.9.2/access/Ownable2Step.sol\";\nimport \"./interfaces/IFeedOracle.sol\";\nimport \"./RrpRequesterV0.sol\";\nimport \"./ORMPWrapper.sol\";\nimport \"./SubAPIFeed.sol\";\n\n/// @title SubAPI\n/// @dev The contract uses to serve data feeds of source chain finalized header\n/// dAPI security model is the same as edcsa pallet.\n/// @notice SubAPI serves data feeds in the form of BeaconSet.\n/// The BeaconSet are only updateable using RRPv0.\ncontract SubAPI is IFeedOracle, RrpRequesterV0, SubAPIFeed, ORMPWrapper, Ownable2Step {\n using EnumerableSet for EnumerableSet.Bytes32Set;\n\n event SetFee(uint256 indexed fee);\n event AddBeacon(bytes32 indexed beaconId, Beacon beacon);\n event RemoveBeacon(bytes32 indexed beaconId);\n event AirnodeRrpRequested(bytes32 indexed beaconId, bytes32 indexed requestId);\n event AirnodeRrpCompleted(bytes32 indexed beaconId, bytes32 indexed requestId, bytes data);\n event AggregatedORMPData(ORMPData ormpData);\n\n /// @notice Beacon metadata\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param sponsor Sponsor address\n /// @param sponsorWallet Sponsor wallet address\n struct Beacon {\n address airnode;\n bytes32 endpointId;\n address sponsor;\n address payable sponsorWallet;\n }\n\n // name for subAPI\n string public name;\n // fee pay to beacon sponsor wallet address for gas\n uint256 public fee;\n // requestId => beaconId\n mapping(bytes32 => bytes32) private _requestIdToBeaconId;\n // beaconId => requestId\n mapping(bytes32 => bytes32) private _beaconIdToRequestId;\n // beaconIdSet\n EnumerableSet.Bytes32Set private _beaconIds;\n\n /// @param dao SubAPIDao\n /// @param rrp Airnode RRP contract address\n /// @param ormp ORMP RRP address\n constructor(address dao, address rrp, address ormp) RrpRequesterV0(rrp) ORMPWrapper(ormp) {\n _transferOwnership(dao);\n }\n\n function setName(string memory name_) external onlyOwner {\n name = name_;\n }\n\n /// @notice Add a beacon to BeaconSet\n function addBeacon(Beacon calldata beacon) external onlyOwner {\n bytes32 beaconId = deriveBeaconId(beacon);\n require(_beaconIds.add(beaconId), \"!add\");\n emit AddBeacon(beaconId, beacon);\n }\n\n /// @notice Remove the beacon from BeaconSet\n function removeBeacon(bytes32 beaconId) external onlyOwner {\n require(_beaconIds.remove(beaconId), \"!rm\");\n emit RemoveBeacon(beaconId);\n }\n\n /// @notice change the beacon fee\n function setFee(uint256 fee_) external onlyOwner {\n fee = fee_;\n emit SetFee(fee_);\n }\n\n function remoteCommitment() external view returns (uint256 count, bytes32 root) {\n count = _aggregatedData.count;\n root = _aggregatedData.root;\n }\n\n function messageRoot() external view returns (bytes32) {\n return _aggregatedData.root;\n }\n\n /// @notice Fetch request fee\n /// return tokenAddress if tokenAddress is Address(0x0), pay the native token\n /// fee the request fee\n function getRequestFee() external view returns (address, uint256) {\n return (address(0), fee * beaconsLength());\n }\n\n /// @notice Fetch beaconId by requestId\n function getBeaconIdByRequestId(bytes32 requestId) external view returns (bytes32) {\n return _requestIdToBeaconId[requestId];\n }\n\n /// @notice Fetch requestId by beaconId\n function getRequestIdByBeaconId(bytes32 beaconId) external view returns (bytes32) {\n return _beaconIdToRequestId[beaconId];\n }\n\n /// @notice BeaconSet length\n function beaconsLength() public view returns (uint256) {\n return _beaconIds.length();\n }\n\n /// @notice Check if the beacon exist by Id\n function isBeaconExist(bytes32 beaconId) public view returns (bool) {\n return _beaconIds.contains(beaconId);\n }\n\n /// @notice Derives the Beacon ID from the Airnode address and endpoint ID\n /// @param beacon Beacon\n function deriveBeaconId(Beacon calldata beacon) public pure returns (bytes32 beaconId) {\n beaconId = keccak256(abi.encode(beacon));\n }\n\n function _request(Beacon calldata beacon, bytes32 beaconId) internal {\n beacon.sponsorWallet.transfer(fee);\n bytes32 requestId = airnodeRrp.makeFullRequest(\n beacon.airnode,\n beacon.endpointId,\n beacon.sponsor,\n beacon.sponsorWallet,\n address(this),\n this.fulfill.selector,\n \"\"\n );\n _requestIdToBeaconId[requestId] = beaconId;\n _beaconIdToRequestId[beaconId] = requestId;\n emit AirnodeRrpRequested(beaconId, requestId);\n }\n\n /// @notice Create a request for arbitrum finalized header\n /// Send reqeust to all beacon in BeaconSet\n function requestFinalizedHash(Beacon[] calldata beacons) external payable {\n uint256 beaconCount = beacons.length;\n require(beaconCount == beaconsLength(), \"!all\");\n require(msg.value == fee * beaconCount, \"!fee\");\n for (uint256 i = 0; i < beaconCount; i++) {\n bytes32 beaconId = deriveBeaconId(beacons[i]);\n require(isBeaconExist(beaconId), \"!exist\");\n _request(beacons[i], beaconId);\n }\n }\n\n /// @notice Called by the ArinodeRRP to fulfill the request\n /// @param requestId Request ID\n /// @param data Fulfillment data (`BlockData` encoded in contract ABI)\n function fulfill(bytes32 requestId, bytes calldata data) external onlyAirnodeRrp {\n bytes32 beaconId = _requestIdToBeaconId[requestId];\n require(beaconId != bytes32(0), \"!requestId\");\n if (_beaconIdToRequestId[beaconId] == requestId) {\n delete _requestIdToBeaconId[requestId];\n delete _beaconIdToRequestId[beaconId];\n _processBeaconUpdate(beaconId, data);\n emit AirnodeRrpCompleted(beaconId, requestId, data);\n } else {\n delete _requestIdToBeaconId[requestId];\n }\n }\n\n /// @notice Called to aggregate the BeaconSet and save the result.\n /// beaconIds should be a supermajor(>2/3) subset of all beacons in contract.\n /// @param beaconIds Beacon IDs should be sorted in ascending order\n function aggregateBeacons(bytes32[] calldata beaconIds) external {\n uint256 beaconCount = beaconIds.length;\n bytes32[] memory allBeaconIds = _beaconIds.values();\n require(beaconCount * 3 > allBeaconIds.length * 2, \"!supermajor\");\n ORMPData[] memory datas = _checkAndGetDatasFromBeacons(beaconIds);\n ORMPData memory data = datas[0];\n for (uint256 i = 1; i < beaconCount; i++) {\n require(eq(data, datas[i]), \"!agg\");\n }\n require(neq(_aggregatedData, data), \"same\");\n _aggregatedData = data;\n emit AggregatedORMPData(data);\n }\n\n function _checkAndGetDatasFromBeacons(bytes32[] calldata beaconIds) internal view returns (ORMPData[] memory) {\n uint256 beaconCount = beaconIds.length;\n ORMPData[] memory datas = new ORMPData[](beaconCount);\n bytes32 last = bytes32(0);\n bytes32 current;\n for (uint256 i = 0; i < beaconCount; i++) {\n current = beaconIds[i];\n require(current > last && isBeaconExist(current), \"!beacon\");\n datas[i] = _dataFeeds[current];\n last = current;\n }\n return datas;\n }\n}\n", "keccak256": "0x47f44cd04d6f650a46becb288cb01e8ee9f6c9cf1f4b4640ea854ebea003d714"}, "lib/zeppelin-solidity/contracts/utils/structs/EnumerableSet.sol": {"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(bytes32 => uint256) _indexes;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._indexes[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We read and store the value's index to prevent multiple reads from the same storage slot\n uint256 valueIndex = set._indexes[value];\n\n if (valueIndex != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 toDeleteIndex = valueIndex - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (lastIndex != toDeleteIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the last value to the index where the value to delete is\n set._values[toDeleteIndex] = lastValue;\n // Update the index for the moved value\n set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the index for the deleted slot\n delete set._indexes[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._indexes[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n", "keccak256": "0x9f4357008a8f7d8c8bf5d48902e789637538d8c016be5766610901b4bba81514"}, "lib/zeppelin-solidity/contracts/access/Ownable2Step.sol": {"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./Ownable.sol\";\n\n/**\n * @dev Contract module which provides access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2Step is Ownable {\n address private _pendingOwner;\n\n event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Returns the address of the pending owner.\n */\n function pendingOwner() public view virtual returns (address) {\n return _pendingOwner;\n }\n\n /**\n * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual override onlyOwner {\n _pendingOwner = newOwner;\n emit OwnershipTransferStarted(owner(), newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual override {\n delete _pendingOwner;\n super._transferOwnership(newOwner);\n }\n\n /**\n * @dev The new owner accepts the ownership transfer.\n */\n function acceptOwnership() public virtual {\n address sender = _msgSender();\n require(pendingOwner() == sender, \"Ownable2Step: caller is not the new owner\");\n _transferOwnership(sender);\n }\n}\n", "keccak256": "0xde231558366826d7cb61725af8147965a61c53b77a352cc8c9af38fc5a92ac3c"}, "src/interfaces/IFeedOracle.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2022 Darwinia Network\n// SPDX-License-Identifier: GPL-3.0\n//\n// Darwinia is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Darwinia is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Darwinia. If not, see .\n\npragma solidity 0.8.17;\n\ninterface IFeedOracle {\n function messageRoot() external view returns (bytes32);\n}\n", "keccak256": "0xa6385ad8507c0dd520794df275bddbdd3363435c160a842702ed5ab01e5d3aec"}, "src/RrpRequesterV0.sol": {"content": "// SPDX-License-Identifier: MIT\n//\n// Inspired: https://github.com/api3dao/airnode/blob/master/packages/airnode-protocol/contracts/rrp/requesters/RrpRequesterV0.sol\n\npragma solidity 0.8.17;\n\nimport \"./interfaces/IAirnodeRrpV0.sol\";\n\n/// @title The contract to be inherited to make Airnode RRP requests\ncontract RrpRequesterV0 {\n IAirnodeRrpV0 public immutable airnodeRrp;\n\n /// @dev Reverts if the caller is not the Airnode RRP contract.\n /// Use it as a modifier for fulfill and error callback methods, but also\n /// check `requestId`.\n modifier onlyAirnodeRrp() {\n require(msg.sender == address(airnodeRrp), \"Caller not Airnode RRP\");\n _;\n }\n\n /// @dev Airnode RRP address is set at deployment and is immutable.\n /// RrpRequester is made its own sponsor by default. RrpRequester can also\n /// be sponsored by others and use these sponsorships while making\n /// requests, i.e., using this default sponsorship is optional.\n /// @param _airnodeRrp Airnode RRP contract address\n constructor(address _airnodeRrp) {\n airnodeRrp = IAirnodeRrpV0(_airnodeRrp);\n IAirnodeRrpV0(_airnodeRrp).setSponsorshipStatus(address(this), true);\n }\n}\n", "keccak256": "0x5e37ae6d9ed044de23c8ffb7354a406b1a17da082466a25cb4f01954b717c7f1"}, "src/ORMPWrapper.sol": {"content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\ninterface IORMP {\n function root() external view returns (bytes32);\n function messageCount() external view returns (uint256);\n}\n\ncontract ORMPWrapper {\n address public immutable ORMP;\n\n constructor(address ormp) {\n ORMP = ormp;\n }\n\n function localCommitment() external view returns (uint256 count, bytes32 root) {\n count = IORMP(ORMP).messageCount();\n root = IORMP(ORMP).root();\n }\n}\n", "keccak256": "0xa48cfe7c88184f7930e496f2f3c5fbdd3ed06e407920c8326d048d5160cab1cb"}, "src/SubAPIFeed.sol": {"content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\ncontract SubAPIFeed {\n event SubAPIFeedUpdated(bytes32 indexed beaconId, ORMPData msgRoot);\n\n struct ORMPData {\n // ormp message count\n uint256 count;\n // ormp message root\n bytes32 root;\n }\n\n ORMPData internal _aggregatedData;\n // beaconId => ORMPData\n mapping(bytes32 => ORMPData) internal _dataFeeds;\n\n function _processBeaconUpdate(bytes32 beaconId, bytes calldata data) internal {\n bytes memory decodeData = abi.decode(data, (bytes));\n ORMPData memory ormpData = abi.decode(decodeData, (ORMPData));\n _dataFeeds[beaconId] = ormpData;\n emit SubAPIFeedUpdated(beaconId, ormpData);\n }\n\n function getDataFeedWithId(bytes32 beaconId) public view returns (ORMPData memory msgRoot) {\n return _dataFeeds[beaconId];\n }\n\n function eq(ORMPData memory a, ORMPData memory b) public pure returns (bool) {\n return (a.count == b.count && a.root == b.root);\n }\n\n function neq(ORMPData memory a, ORMPData memory b) public pure returns (bool) {\n return (a.count != b.count || a.root != b.root);\n }\n}\n", "keccak256": "0xff2b606626bcf0aa47b1298145ca040f747edf879e713a6db752606d09a1cc19"}, "lib/zeppelin-solidity/contracts/access/Ownable.sol": {"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby disabling any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n", "keccak256": "0xba43b97fba0d32eb4254f6a5a297b39a19a247082a02d6e69349e071e2946218"}, "src/interfaces/IAirnodeRrpV0.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2022 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 IAirnodeRrpV0 {\n function setSponsorshipStatus(address requester, bool sponsorshipStatus) external;\n function makeFullRequest(\n address airnode,\n bytes32 endpointId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata parameters\n ) external returns (bytes32 requestId);\n}\n", "keccak256": "0x3abcef14f6e9dcf76838d324266f6ab40721e88b1575e414cd517b38e4b3ed3a"}, "lib/zeppelin-solidity/contracts/utils/Context.sol": {"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n", "keccak256": "0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7"}}, "settings": {"remappings": ["@openzeppelin/contracts@4.9.2/=lib/zeppelin-solidity/contracts/", "ds-test/=lib/forge-std/lib/ds-test/src/", "create3-deploy/=lib/create3-deploy/", "forge-std/=lib/forge-std/src/", "erc4626-tests/=lib/zeppelin-solidity/lib/erc4626-tests/", "openzeppelin/=lib/zeppelin-solidity/contracts/", "solmate/=lib/create3-deploy/lib/solmate/src/", "zeppelin-solidity/=lib/zeppelin-solidity/"], "optimizer": {"enabled": true, "runs": 999999}, "metadata": {"useLiteralContent": false, "bytecodeHash": "ipfs"}, "outputSelection": {"*": {"": ["ast"], "*": ["abi", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers", "metadata"]}}, "evmVersion": "london", "libraries": {}, "compilationTarget": {"src/SubAPI.sol": "SubAPI"}}} \ No newline at end of file +{"language": "Solidity", "sources": {"src/SubAPI.sol": {"content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\nimport \"@openzeppelin/contracts@4.9.2/utils/structs/EnumerableSet.sol\";\nimport \"@openzeppelin/contracts@4.9.2/access/Ownable2Step.sol\";\nimport \"./interfaces/IFeedOracle.sol\";\nimport \"./RrpRequesterV0.sol\";\nimport \"./ORMPWrapper.sol\";\nimport \"./SubAPIFeed.sol\";\n\n/// @title SubAPI\n/// @dev The contract uses to serve data feeds of source chain finalized header\n/// dAPI security model is the same as edcsa pallet.\n/// @notice SubAPI serves data feeds in the form of BeaconSet.\n/// The BeaconSet are only updateable using RRPv0.\ncontract SubAPI is IFeedOracle, RrpRequesterV0, SubAPIFeed, ORMPWrapper, Ownable2Step {\n using EnumerableSet for EnumerableSet.Bytes32Set;\n\n event SetFee(uint256 indexed fee);\n event AddBeacon(uint256 indexed chainId, bytes32 indexed beaconId, Beacon beacon);\n event RemoveBeacon(uint256 indexed chainId, bytes32 indexed beaconId);\n event AirnodeRrpRequested(uint256 indexed chainId, bytes32 indexed beaconId, bytes32 indexed requestId);\n event AirnodeRrpCompleted(bytes32 indexed beaconId, bytes32 indexed requestId, bytes data);\n event AggregatedORMPData(uint256 indexed chainId, ORMPData ormpData);\n\n /// @notice Beacon metadata\n /// @dev beaconId must be different on multi chain\n /// @param chainId Chain ID\n /// @param airnode Airnode address\n /// @param endpointId Endpoint ID\n /// @param sponsor Sponsor address\n /// @param sponsorWallet Sponsor wallet address\n struct Beacon {\n uint256 chainId;\n address airnode;\n bytes32 endpointId;\n address sponsor;\n address payable sponsorWallet;\n }\n\n uint256 public fee;\n // requestId => beaconId\n mapping(bytes32 => bytes32) private _requestIdToBeaconId;\n // beaconId => requestId\n mapping(bytes32 => bytes32) private _beaconIdToRequestId;\n // chainId => beaconIdSet\n mapping(uint256 => EnumerableSet.Bytes32Set) private _beaconIds;\n\n /// @param dao SubAPIDao\n /// @param rrp Airnode RRP contract address\n /// @param ormp ORMP RRP address\n constructor(address dao, address rrp, address ormp) RrpRequesterV0(rrp) ORMPWrapper(ormp) {\n _transferOwnership(dao);\n }\n\n /// @notice Add a beacon to BeaconSet\n function addBeacon(uint256 chainId, Beacon calldata beacon) external onlyOwner {\n bytes32 beaconId = deriveBeaconId(beacon);\n require(chainId == beacon.chainId, \"!chainId\");\n require(_beaconIds[chainId].add(beaconId), \"!add\");\n emit AddBeacon(chainId, beaconId, beacon);\n }\n\n /// @notice Remove the beacon from BeaconSet\n function removeBeacon(uint256 chainId, bytes32 beaconId) external onlyOwner {\n require(_beaconIds[chainId].remove(beaconId), \"!rm\");\n emit RemoveBeacon(chainId, beaconId);\n }\n\n /// @notice change the beacon fee\n function setFee(uint256 fee_) external onlyOwner {\n fee = fee_;\n emit SetFee(fee_);\n }\n\n function remoteCommitmentOf(uint256 chainId) external view returns (uint256 count, bytes32 root) {\n ORMPData memory data = _aggregatedDataOf[chainId];\n count = data.count;\n root = data.root;\n }\n\n function messageRootOf(uint256 chainId) external view returns (bytes32) {\n return _aggregatedDataOf[chainId].root;\n }\n\n /// @notice Fetch request fee\n /// return tokenAddress if tokenAddress is Address(0x0), pay the native token\n /// fee the request fee\n function getRequestFeeOf(uint256 chainId) external view returns (address, uint256) {\n return (address(0), fee * beaconsLengthOf(chainId));\n }\n\n /// @notice Fetch beaconId by requestId\n function getBeaconIdByRequestId(bytes32 requestId) external view returns (bytes32) {\n return _requestIdToBeaconId[requestId];\n }\n\n /// @notice Fetch requestId by beaconId\n function getRequestIdByBeaconId(bytes32 beaconId) external view returns (bytes32) {\n return _beaconIdToRequestId[beaconId];\n }\n\n /// @notice BeaconSet length\n function beaconsLengthOf(uint256 chainId) public view returns (uint256) {\n return _beaconIds[chainId].length();\n }\n\n /// @notice Check if the beacon exist by Id\n function isBeaconExist(uint256 chainId, bytes32 beaconId) public view returns (bool) {\n return _beaconIds[chainId].contains(beaconId);\n }\n\n /// @notice Derives the Beacon ID from the Airnode address and endpoint ID\n /// @param beacon Beacon\n function deriveBeaconId(Beacon calldata beacon) public pure returns (bytes32 beaconId) {\n beaconId = keccak256(abi.encode(beacon));\n }\n\n function _request(Beacon calldata beacon, bytes32 beaconId) internal {\n uint256 chainId = beacon.chainId;\n beacon.sponsorWallet.transfer(fee);\n bytes32 requestId = airnodeRrp.makeFullRequest(\n beacon.airnode,\n beacon.endpointId,\n beacon.sponsor,\n beacon.sponsorWallet,\n address(this),\n this.fulfill.selector,\n \"\"\n );\n _requestIdToBeaconId[requestId] = beaconId;\n _beaconIdToRequestId[beaconId] = requestId;\n emit AirnodeRrpRequested(chainId, beaconId, requestId);\n }\n\n /// @notice Create a request for arbitrum finalized header\n /// Send reqeust to all beacon in BeaconSet\n function requestFinalizedHash(uint256 chainId, Beacon[] calldata beacons) external payable {\n uint256 beaconCount = beacons.length;\n require(beaconCount == beaconsLengthOf(chainId), \"!all\");\n require(msg.value == fee * beaconCount, \"!fee\");\n for (uint256 i = 0; i < beaconCount; i++) {\n bytes32 beaconId = deriveBeaconId(beacons[i]);\n require(isBeaconExist(chainId, beaconId), \"!exist\");\n require(chainId == beacons[i].chainId, \"!chainId\");\n _request(beacons[i], beaconId);\n }\n }\n\n /// @notice Called by the ArinodeRRP to fulfill the request\n /// @param requestId Request ID\n /// @param data Fulfillment data (`BlockData` encoded in contract ABI)\n function fulfill(bytes32 requestId, bytes calldata data) external onlyAirnodeRrp {\n bytes32 beaconId = _requestIdToBeaconId[requestId];\n require(beaconId != bytes32(0), \"!requestId\");\n if (_beaconIdToRequestId[beaconId] == requestId) {\n delete _requestIdToBeaconId[requestId];\n delete _beaconIdToRequestId[beaconId];\n _processBeaconUpdate(beaconId, data);\n emit AirnodeRrpCompleted(beaconId, requestId, data);\n } else {\n delete _requestIdToBeaconId[requestId];\n }\n }\n\n /// @notice Called to aggregate the BeaconSet and save the result.\n /// beaconIds should be a supermajor(>2/3) subset of all beacons in contract.\n /// @param beaconIds Beacon IDs should be sorted in ascending order\n function aggregateBeacons(uint256 chainId, bytes32[] calldata beaconIds) external {\n uint256 beaconCount = beaconIds.length;\n bytes32[] memory allBeaconIds = _beaconIds[chainId].values();\n require(beaconCount * 3 > allBeaconIds.length * 2, \"!supermajor\");\n ORMPData[] memory datas = _checkAndGetDatasFromBeacons(chainId, beaconIds);\n ORMPData memory data = datas[0];\n for (uint256 i = 1; i < beaconCount; i++) {\n require(eq(data, datas[i]), \"!agg\");\n }\n require(neq(_aggregatedDataOf[chainId], data), \"same\");\n _aggregatedDataOf[chainId] = data;\n emit AggregatedORMPData(chainId, data);\n }\n\n function _checkAndGetDatasFromBeacons(uint256 chainId, bytes32[] calldata beaconIds)\n internal\n view\n returns (ORMPData[] memory)\n {\n uint256 beaconCount = beaconIds.length;\n ORMPData[] memory datas = new ORMPData[](beaconCount);\n bytes32 last = bytes32(0);\n bytes32 current;\n for (uint256 i = 0; i < beaconCount; i++) {\n current = beaconIds[i];\n require(current > last && isBeaconExist(chainId, current), \"!beacon\");\n datas[i] = _dataFeeds[current];\n last = current;\n }\n return datas;\n }\n}\n", "keccak256": "0xd98645b995afb6d8527a97ae903cb9a439b44060c9fd1c6bfcb0c0bf0fadaaf1"}, "lib/zeppelin-solidity/contracts/utils/structs/EnumerableSet.sol": {"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(bytes32 => uint256) _indexes;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._indexes[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We read and store the value's index to prevent multiple reads from the same storage slot\n uint256 valueIndex = set._indexes[value];\n\n if (valueIndex != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 toDeleteIndex = valueIndex - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (lastIndex != toDeleteIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the last value to the index where the value to delete is\n set._values[toDeleteIndex] = lastValue;\n // Update the index for the moved value\n set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the index for the deleted slot\n delete set._indexes[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._indexes[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n", "keccak256": "0x9f4357008a8f7d8c8bf5d48902e789637538d8c016be5766610901b4bba81514"}, "lib/zeppelin-solidity/contracts/access/Ownable2Step.sol": {"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./Ownable.sol\";\n\n/**\n * @dev Contract module which provides access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2Step is Ownable {\n address private _pendingOwner;\n\n event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Returns the address of the pending owner.\n */\n function pendingOwner() public view virtual returns (address) {\n return _pendingOwner;\n }\n\n /**\n * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual override onlyOwner {\n _pendingOwner = newOwner;\n emit OwnershipTransferStarted(owner(), newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual override {\n delete _pendingOwner;\n super._transferOwnership(newOwner);\n }\n\n /**\n * @dev The new owner accepts the ownership transfer.\n */\n function acceptOwnership() public virtual {\n address sender = _msgSender();\n require(pendingOwner() == sender, \"Ownable2Step: caller is not the new owner\");\n _transferOwnership(sender);\n }\n}\n", "keccak256": "0xde231558366826d7cb61725af8147965a61c53b77a352cc8c9af38fc5a92ac3c"}, "src/interfaces/IFeedOracle.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2022 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": "0x47023709834d611d3e739215661b2fb5045268c883cf5e8b66f4e41ae63b551b"}, "src/RrpRequesterV0.sol": {"content": "// SPDX-License-Identifier: MIT\n//\n// Inspired: https://github.com/api3dao/airnode/blob/master/packages/airnode-protocol/contracts/rrp/requesters/RrpRequesterV0.sol\n\npragma solidity 0.8.17;\n\nimport \"./interfaces/IAirnodeRrpV0.sol\";\n\n/// @title The contract to be inherited to make Airnode RRP requests\ncontract RrpRequesterV0 {\n IAirnodeRrpV0 public immutable airnodeRrp;\n\n /// @dev Reverts if the caller is not the Airnode RRP contract.\n /// Use it as a modifier for fulfill and error callback methods, but also\n /// check `requestId`.\n modifier onlyAirnodeRrp() {\n require(msg.sender == address(airnodeRrp), \"Caller not Airnode RRP\");\n _;\n }\n\n /// @dev Airnode RRP address is set at deployment and is immutable.\n /// RrpRequester is made its own sponsor by default. RrpRequester can also\n /// be sponsored by others and use these sponsorships while making\n /// requests, i.e., using this default sponsorship is optional.\n /// @param _airnodeRrp Airnode RRP contract address\n constructor(address _airnodeRrp) {\n airnodeRrp = IAirnodeRrpV0(_airnodeRrp);\n IAirnodeRrpV0(_airnodeRrp).setSponsorshipStatus(address(this), true);\n }\n}\n", "keccak256": "0x5e37ae6d9ed044de23c8ffb7354a406b1a17da082466a25cb4f01954b717c7f1"}, "src/ORMPWrapper.sol": {"content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\ninterface IORMP {\n function root() external view returns (bytes32);\n function messageCount() external view returns (uint256);\n}\n\ncontract ORMPWrapper {\n address public immutable ORMP;\n\n constructor(address ormp) {\n ORMP = ormp;\n }\n\n function localCommitment() external view returns (uint256 count, bytes32 root) {\n count = IORMP(ORMP).messageCount();\n root = IORMP(ORMP).root();\n }\n}\n", "keccak256": "0xa48cfe7c88184f7930e496f2f3c5fbdd3ed06e407920c8326d048d5160cab1cb"}, "src/SubAPIFeed.sol": {"content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.17;\n\ncontract SubAPIFeed {\n event SubAPIFeedUpdated(bytes32 indexed beaconId, ORMPData msgRoot);\n\n struct ORMPData {\n // ormp message count\n uint256 count;\n // ormp message root\n bytes32 root;\n }\n\n // chainId => ORMPData\n mapping(uint256 => ORMPData) internal _aggregatedDataOf;\n // beaconId => ORMPData\n mapping(bytes32 => ORMPData) internal _dataFeeds;\n\n function _processBeaconUpdate(bytes32 beaconId, bytes calldata data) internal {\n bytes memory decodeData = abi.decode(data, (bytes));\n ORMPData memory ormpData = abi.decode(decodeData, (ORMPData));\n _dataFeeds[beaconId] = ormpData;\n emit SubAPIFeedUpdated(beaconId, ormpData);\n }\n\n function getDataFeedWithId(bytes32 beaconId) public view returns (ORMPData memory msgRoot) {\n return _dataFeeds[beaconId];\n }\n\n function eq(ORMPData memory a, ORMPData memory b) public pure returns (bool) {\n return (a.count == b.count && a.root == b.root);\n }\n\n function neq(ORMPData memory a, ORMPData memory b) public pure returns (bool) {\n return (a.count != b.count || a.root != b.root);\n }\n}\n", "keccak256": "0xff7cb3b52623f7ec84f5844ca8ae21fd637aed15dbd1cd6e48cb12f6f3f6b585"}, "lib/zeppelin-solidity/contracts/access/Ownable.sol": {"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby disabling any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n", "keccak256": "0xba43b97fba0d32eb4254f6a5a297b39a19a247082a02d6e69349e071e2946218"}, "src/interfaces/IAirnodeRrpV0.sol": {"content": "// This file is part of Darwinia.\n// Copyright (C) 2018-2022 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 IAirnodeRrpV0 {\n function setSponsorshipStatus(address requester, bool sponsorshipStatus) external;\n function makeFullRequest(\n address airnode,\n bytes32 endpointId,\n address sponsor,\n address sponsorWallet,\n address fulfillAddress,\n bytes4 fulfillFunctionId,\n bytes calldata parameters\n ) external returns (bytes32 requestId);\n}\n", "keccak256": "0x3abcef14f6e9dcf76838d324266f6ab40721e88b1575e414cd517b38e4b3ed3a"}, "lib/zeppelin-solidity/contracts/utils/Context.sol": {"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n", "keccak256": "0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7"}}, "settings": {"remappings": ["@openzeppelin/contracts@4.9.2/=lib/zeppelin-solidity/contracts/", "ds-test/=lib/forge-std/lib/ds-test/src/", "create3-deploy/=lib/create3-deploy/", "forge-std/=lib/forge-std/src/", "ORMP/=lib/ORMP/", "erc4626-tests/=lib/zeppelin-solidity/lib/erc4626-tests/", "openzeppelin/=lib/zeppelin-solidity/contracts/", "solmate/=lib/create3-deploy/lib/solmate/src/", "zeppelin-solidity/=lib/zeppelin-solidity/"], "optimizer": {"enabled": true, "runs": 999999}, "metadata": {"useLiteralContent": false, "bytecodeHash": "ipfs"}, "outputSelection": {"*": {"": ["ast"], "*": ["abi", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers", "metadata"]}}, "evmVersion": "london", "libraries": {}, "compilationTarget": {"src/SubAPI.sol": "SubAPI"}}} \ 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 d60bcfd..4a50601 100644 --- a/script/output/46/deploy.a-latest.json +++ b/script/output/46/deploy.a-latest.json @@ -1,4 +1,4 @@ { "DAO": "0x0f14341A7f464320319025540E8Fe48Ad0fe5aec", - "SUBAPI": "0x00000000007317c91F57D86A410934A490E62E1E" + "SUBAPI": "0x00000000096c285629Fe3EAb3dd042c27b9dcBa6" } \ No newline at end of file