Blockchain / Global / Address

Contract

0xCEd8153AdF62F31d940f230397b30622298a445d

Balance
0 SOMI
Transactions sent
1
Type
Contract · 13,240 bytes of code

Api3ServerV1 Verified

Compiler
solc 0.8.17+commit.8df45f5f
Language
Solidity
Optimization
Yes, 1000 runs
EVM version
—
License
—
Verified
2026-10-12

contracts/api3-server-v1/Api3ServerV1.sol

and 29 more files

Solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "./OevDapiServer.sol";
import "./BeaconUpdatesWithSignedData.sol";
import "./interfaces/IApi3ServerV1.sol";

/// @title First version of the contract that API3 uses to serve data feeds
/// @notice Api3ServerV1 serves data feeds in the form of Beacons, Beacon sets,
/// dAPIs, with optional OEV support for all of these.
/// The base Beacons are only updateable using signed data, and the Beacon sets
/// are updateable based on the Beacons, optionally using PSP. OEV proxy
/// Beacons and Beacon sets are updateable using OEV-signed data.
/// Api3ServerV1 does not support Beacons to be updated using RRP or PSP.
contract Api3ServerV1 is
    OevDapiServer,
    BeaconUpdatesWithSignedData,
    IApi3ServerV1
{
    /// @param _accessControlRegistry AccessControlRegistry contract address
    /// @param _adminRoleDescription Admin role description
    /// @param _manager Manager address
    constructor(
        address _accessControlRegistry,
        string memory _adminRoleDescription,
        address _manager
    ) OevDapiServer(_accessControlRegistry, _adminRoleDescription, _manager) {}

    /// @notice Reads the data feed with ID
    /// @param dataFeedId Data feed ID
    /// @return value Data feed value
    /// @return timestamp Data feed timestamp
    function readDataFeedWithId(
        bytes32 dataFeedId
    ) external view override returns (int224 value, uint32 timestamp) {
        return _readDataFeedWithId(dataFeedId);
    }

    /// @notice Reads the data feed with dAPI name hash
    /// @param dapiNameHash dAPI name hash
    /// @return value Data feed value
    /// @return timestamp Data feed timestamp
    function readDataFeedWithDapiNameHash(
        bytes32 dapiNameHash
    ) external view override returns (int224 value, uint32 timestamp) {
        return _readDataFeedWithDapiNameHash(dapiNameHash);
    }

    /// @notice Reads the data feed as the OEV proxy with ID
    /// @param dataFeedId Data feed ID
    /// @return value Data feed value
    /// @return timestamp Data feed timestamp
    function readDataFeedWithIdAsOevProxy(
        bytes32 dataFeedId
    ) external view override returns (int224 value, uint32 timestamp) {
        return _readDataFeedWithIdAsOevProxy(dataFeedId);
    }

    /// @notice Reads the data feed as the OEV proxy with dAPI name hash
    /// @param dapiNameHash dAPI name hash
    /// @return value Data feed value
    /// @return timestamp Data feed timestamp
    function readDataFeedWithDapiNameHashAsOevProxy(
        bytes32 dapiNameHash
    ) external view override returns (int224 value, uint32 timestamp) {
        return _readDataFeedWithDapiNameHashAsOevProxy(dapiNameHash);
    }

    function dataFeeds(
        bytes32 dataFeedId
    ) external view override returns (int224 value, uint32 timestamp) {
        DataFeed storage dataFeed = _dataFeeds[dataFeedId];
        (value, timestamp) = (dataFeed.value, dataFeed.timestamp);
    }

    function oevProxyToIdToDataFeed(
        address proxy,
        bytes32 dataFeedId
    ) external view override returns (int224 value, uint32 timestamp) {
        DataFeed storage dataFeed = _oevProxyToIdToDataFeed[proxy][dataFeedId];
        (value, timestamp) = (dataFeed.value, dataFeed.timestamp);
    }
}

Other files

  • contracts/access/AccessControlRegistryAdminned.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    import "../utils/SelfMulticall.sol";
    import "./RoleDeriver.sol";
    import "./interfaces/IAccessControlRegistryAdminned.sol";
    import "./interfaces/IAccessControlRegistry.sol";
    
    /// @title Contract to be inherited by contracts whose adminship functionality
    /// will be implemented using AccessControlRegistry
    contract AccessControlRegistryAdminned is
        SelfMulticall,
        RoleDeriver,
        IAccessControlRegistryAdminned
    {
        /// @notice AccessControlRegistry contract address
        address public immutable override accessControlRegistry;
    
        /// @notice Admin role description
        string public override adminRoleDescription;
    
        bytes32 internal immutable adminRoleDescriptionHash;
    
        /// @dev Contracts deployed with the same admin role descriptions will have
        /// the same roles, meaning that granting an account a role will authorize
        /// it in multiple contracts. Unless you want your deployed contract to
        /// share the role configuration of another contract, use a unique admin
        /// role description.
        /// @param _accessControlRegistry AccessControlRegistry contract address
        /// @param _adminRoleDescription Admin role description
        constructor(
            address _accessControlRegistry,
            string memory _adminRoleDescription
        ) {
            require(_accessControlRegistry != address(0), "ACR address zero");
            require(
                bytes(_adminRoleDescription).length > 0,
                "Admin role description empty"
            );
            accessControlRegistry = _accessControlRegistry;
            adminRoleDescription = _adminRoleDescription;
            adminRoleDescriptionHash = keccak256(
                abi.encodePacked(_adminRoleDescription)
            );
        }
    
        /// @notice Derives the admin role for the specific manager address
        /// @param manager Manager address
        /// @return adminRole Admin role
        function _deriveAdminRole(
            address manager
        ) internal view returns (bytes32 adminRole) {
            adminRole = _deriveRole(
                _deriveRootRole(manager),
                adminRoleDescriptionHash
            );
        }
    }
    
  • contracts/access/AccessControlRegistryAdminnedWithManager.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    import "./AccessControlRegistryAdminned.sol";
    import "./interfaces/IAccessControlRegistryAdminnedWithManager.sol";
    
    /// @title Contract to be inherited by contracts with manager whose adminship
    /// functionality will be implemented using AccessControlRegistry
    /// @notice The manager address here is expected to belong to an
    /// AccessControlRegistry user that is a multisig/DAO
    contract AccessControlRegistryAdminnedWithManager is
        AccessControlRegistryAdminned,
        IAccessControlRegistryAdminnedWithManager
    {
        /// @notice Address of the manager that manages the related
        /// AccessControlRegistry roles
        /// @dev The mutability of the manager role can be implemented by
        /// designating an OwnableCallForwarder contract as the manager. The
        /// ownership of this contract can then be transferred, effectively
        /// transferring managership.
        address public immutable override manager;
    
        /// @notice Admin role
        /// @dev Since `manager` is immutable, so is `adminRole`
        bytes32 public immutable override adminRole;
    
        /// @param _accessControlRegistry AccessControlRegistry contract address
        /// @param _adminRoleDescription Admin role description
        /// @param _manager Manager address
        constructor(
            address _accessControlRegistry,
            string memory _adminRoleDescription,
            address _manager
        )
            AccessControlRegistryAdminned(
                _accessControlRegistry,
                _adminRoleDescription
            )
        {
            require(_manager != address(0), "Manager address zero");
            manager = _manager;
            adminRole = _deriveAdminRole(_manager);
        }
    }
    
  • contracts/access/RoleDeriver.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    /// @title Contract to be inherited by contracts that will derive
    /// AccessControlRegistry roles
    /// @notice If a contract interfaces with AccessControlRegistry and needs to
    /// derive roles, it should inherit this contract instead of re-implementing
    /// the logic
    contract RoleDeriver {
        /// @notice Derives the root role of the manager
        /// @param manager Manager address
        /// @return rootRole Root role
        function _deriveRootRole(
            address manager
        ) internal pure returns (bytes32 rootRole) {
            rootRole = keccak256(abi.encodePacked(manager));
        }
    
        /// @notice Derives the role using its admin role and description
        /// @dev This implies that roles adminned by the same role cannot have the
        /// same description
        /// @param adminRole Admin role
        /// @param description Human-readable description of the role
        /// @return role Role
        function _deriveRole(
            bytes32 adminRole,
            string memory description
        ) internal pure returns (bytes32 role) {
            role = _deriveRole(adminRole, keccak256(abi.encodePacked(description)));
        }
    
        /// @notice Derives the role using its admin role and description hash
        /// @dev This implies that roles adminned by the same role cannot have the
        /// same description
        /// @param adminRole Admin role
        /// @param descriptionHash Hash of the human-readable description of the
        /// role
        /// @return role Role
        function _deriveRole(
            bytes32 adminRole,
            bytes32 descriptionHash
        ) internal pure returns (bytes32 role) {
            role = keccak256(abi.encodePacked(adminRole, descriptionHash));
        }
    }
    
  • contracts/access/interfaces/IAccessControlRegistry.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    import "../../vendor/@openzeppelin/contracts@4.8.2/access/IAccessControl.sol";
    import "../../utils/interfaces/ISelfMulticall.sol";
    
    interface IAccessControlRegistry is IAccessControl, ISelfMulticall {
        event InitializedManager(
            bytes32 indexed rootRole,
            address indexed manager,
            address sender
        );
    
        event InitializedRole(
            bytes32 indexed role,
            bytes32 indexed adminRole,
            string description,
            address sender
        );
    
        function initializeManager(address manager) external;
    
        function initializeRoleAndGrantToSender(
            bytes32 adminRole,
            string calldata description
        ) external returns (bytes32 role);
    }
    
  • contracts/access/interfaces/IAccessControlRegistryAdminned.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    import "../../utils/interfaces/ISelfMulticall.sol";
    
    interface IAccessControlRegistryAdminned is ISelfMulticall {
        function accessControlRegistry() external view returns (address);
    
        function adminRoleDescription() external view returns (string memory);
    }
    
  • contracts/access/interfaces/IAccessControlRegistryAdminnedWithManager.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    import "./IAccessControlRegistryAdminned.sol";
    
    interface IAccessControlRegistryAdminnedWithManager is
        IAccessControlRegistryAdminned
    {
        function manager() external view returns (address);
    
        function adminRole() external view returns (bytes32);
    }
    
  • contracts/api3-server-v1/BeaconUpdatesWithSignedData.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.17;
    
    import "./DataFeedServer.sol";
    import "./interfaces/IBeaconUpdatesWithSignedData.sol";
    import "../vendor/@openzeppelin/contracts@4.8.2/utils/cryptography/ECDSA.sol";
    
    /// @title Contract that updates Beacons using signed data
    contract BeaconUpdatesWithSignedData is
        DataFeedServer,
        IBeaconUpdatesWithSignedData
    {
        using ECDSA for bytes32;
    
        /// @notice Updates a Beacon using data signed by the Airnode
        /// @dev The signed data here is intentionally very general for practical
        /// reasons. It is less demanding on the signer to have data signed once
        /// and use that everywhere.
        /// @param airnode Airnode address
        /// @param templateId Template ID
        /// @param timestamp Signature timestamp
        /// @param data Update data (an `int256` encoded in contract ABI)
        /// @param signature Template ID, timestamp and the update data signed by
        /// the Airnode
        /// @return beaconId Updated Beacon ID
        function updateBeaconWithSignedData(
            address airnode,
            bytes32 templateId,
            uint256 timestamp,
            bytes calldata data,
            bytes calldata signature
        ) external override returns (bytes32 beaconId) {
            require(
                (
                    keccak256(abi.encodePacked(templateId, timestamp, data))
                        .toEthSignedMessageHash()
                ).recover(signature) == airnode,
                "Signature mismatch"
            );
            beaconId = deriveBeaconId(airnode, templateId);
            int224 updatedValue = processBeaconUpdate(beaconId, timestamp, data);
            emit UpdatedBeaconWithSignedData(
                beaconId,
                updatedValue,
                uint32(timestamp)
            );
        }
    }
    
  • contracts/api3-server-v1/DapiServer.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.17;
    
    import "../access/AccessControlRegistryAdminnedWithManager.sol";
    import "./DataFeedServer.sol";
    import "./interfaces/IDapiServer.sol";
    
    /// @title Contract that serves dAPIs mapped to Beacons and Beacon sets
    /// @notice Beacons and Beacon sets are addressed by immutable IDs. Although
    /// this is trust-minimized, it requires users to manage the ID of the data
    /// feed they are using. For when the user does not want to do this, dAPIs can
    /// be used as an abstraction layer. By using a dAPI, the user delegates this
    /// responsibility to dAPI management. It is important for dAPI management to
    /// be restricted by consensus rules (by using a multisig or a DAO) and similar
    /// trustless security mechanisms.
    contract DapiServer is
        AccessControlRegistryAdminnedWithManager,
        DataFeedServer,
        IDapiServer
    {
        /// @notice dAPI name setter role description
        string public constant override DAPI_NAME_SETTER_ROLE_DESCRIPTION =
            "dAPI name setter";
    
        /// @notice dAPI name setter role
        bytes32 public immutable override dapiNameSetterRole;
    
        /// @notice dAPI name hash mapped to the data feed ID
        mapping(bytes32 => bytes32) public override dapiNameHashToDataFeedId;
    
        /// @param _accessControlRegistry AccessControlRegistry contract address
        /// @param _adminRoleDescription Admin role description
        /// @param _manager Manager address
        constructor(
            address _accessControlRegistry,
            string memory _adminRoleDescription,
            address _manager
        )
            AccessControlRegistryAdminnedWithManager(
                _accessControlRegistry,
                _adminRoleDescription,
                _manager
            )
        {
            dapiNameSetterRole = _deriveRole(
                _deriveAdminRole(manager),
                DAPI_NAME_SETTER_ROLE_DESCRIPTION
            );
        }
    
        /// @notice Sets the data feed ID the dAPI name points to
        /// @dev While a data feed ID refers to a specific Beacon or Beacon set,
        /// dAPI names provide a more abstract interface for convenience. This
        /// means a dAPI name that was pointing to a Beacon can be pointed to a
        /// Beacon set, then another Beacon set, etc.
        /// @param dapiName Human-readable dAPI name
        /// @param dataFeedId Data feed ID the dAPI name will point to
        function setDapiName(
            bytes32 dapiName,
            bytes32 dataFeedId
        ) external override {
            require(dapiName != bytes32(0), "dAPI name zero");
            require(
                msg.sender == manager ||
                    IAccessControlRegistry(accessControlRegistry).hasRole(
                        dapiNameSetterRole,
                        msg.sender
                    ),
                "Sender cannot set dAPI name"
            );
            dapiNameHashToDataFeedId[
                keccak256(abi.encodePacked(dapiName))
            ] = dataFeedId;
            emit SetDapiName(dataFeedId, dapiName, msg.sender);
        }
    
        /// @notice Returns the data feed ID the dAPI name is set to
        /// @param dapiName dAPI name
        /// @return Data feed ID
        function dapiNameToDataFeedId(
            bytes32 dapiName
        ) external view override returns (bytes32) {
            return dapiNameHashToDataFeedId[keccak256(abi.encodePacked(dapiName))];
        }
    
        /// @notice Reads the data feed with dAPI name hash
        /// @param dapiNameHash dAPI name hash
        /// @return value Data feed value
        /// @return timestamp Data feed timestamp
        function _readDataFeedWithDapiNameHash(
            bytes32 dapiNameHash
        ) internal view returns (int224 value, uint32 timestamp) {
            bytes32 dataFeedId = dapiNameHashToDataFeedId[dapiNameHash];
            require(dataFeedId != bytes32(0), "dAPI name not set");
            DataFeed storage dataFeed = _dataFeeds[dataFeedId];
            (value, timestamp) = (dataFeed.value, dataFeed.timestamp);
            require(timestamp > 0, "Data feed not initialized");
        }
    }
    
  • contracts/api3-server-v1/DataFeedServer.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.17;
    
    import "../utils/ExtendedSelfMulticall.sol";
    import "./aggregation/Median.sol";
    import "./interfaces/IDataFeedServer.sol";
    import "../vendor/@openzeppelin/contracts@4.8.2/utils/cryptography/ECDSA.sol";
    
    /// @title Contract that serves Beacons and Beacon sets
    /// @notice A Beacon is a live data feed addressed by an ID, which is derived
    /// from an Airnode address and a template ID. This is suitable where the more
    /// recent data point is always more favorable, e.g., in the context of an
    /// asset price data feed. Beacons can also be seen as one-Airnode data feeds
    /// that can be used individually or combined to build Beacon sets.
    contract DataFeedServer is ExtendedSelfMulticall, Median, IDataFeedServer {
        using ECDSA for bytes32;
    
        // Airnodes serve their fulfillment data along with timestamps. This
        // contract casts the reported data to `int224` and the timestamp to
        // `uint32`, which works until year 2106.
        struct DataFeed {
            int224 value;
            uint32 timestamp;
        }
    
        /// @notice Data feed with ID
        mapping(bytes32 => DataFeed) internal _dataFeeds;
    
        /// @dev Reverts if the timestamp is from more than 1 hour in the future
        modifier onlyValidTimestamp(uint256 timestamp) virtual {
            unchecked {
                require(
                    timestamp < block.timestamp + 1 hours,
                    "Timestamp not valid"
                );
            }
            _;
        }
    
        /// @notice Updates the Beacon set using the current values of its Beacons
        /// @dev As an oddity, this function still works if some of the IDs in
        /// `beaconIds` belong to Beacon sets rather than Beacons. This can be used
        /// to implement hierarchical Beacon sets.
        /// @param beaconIds Beacon IDs
        /// @return beaconSetId Beacon set ID
        function updateBeaconSetWithBeacons(
            bytes32[] memory beaconIds
        ) public override returns (bytes32 beaconSetId) {
            (int224 updatedValue, uint32 updatedTimestamp) = aggregateBeacons(
                beaconIds
            );
            beaconSetId = deriveBeaconSetId(beaconIds);
            DataFeed storage beaconSet = _dataFeeds[beaconSetId];
            if (beaconSet.timestamp == updatedTimestamp) {
                require(
                    beaconSet.value != updatedValue,
                    "Does not update Beacon set"
                );
            }
            _dataFeeds[beaconSetId] = DataFeed({
                value: updatedValue,
                timestamp: updatedTimestamp
            });
            emit UpdatedBeaconSetWithBeacons(
                beaconSetId,
                updatedValue,
                updatedTimestamp
            );
        }
    
        /// @notice Reads the data feed with ID
        /// @param dataFeedId Data feed ID
        /// @return value Data feed value
        /// @return timestamp Data feed timestamp
        function _readDataFeedWithId(
            bytes32 dataFeedId
        ) internal view returns (int224 value, uint32 timestamp) {
            DataFeed storage dataFeed = _dataFeeds[dataFeedId];
            (value, timestamp) = (dataFeed.value, dataFeed.timestamp);
            require(timestamp > 0, "Data feed not initialized");
        }
    
        /// @notice Derives the Beacon ID from the Airnode address and template ID
        /// @param airnode Airnode address
        /// @param templateId Template ID
        /// @return beaconId Beacon ID
        function deriveBeaconId(
            address airnode,
            bytes32 templateId
        ) internal pure returns (bytes32 beaconId) {
            beaconId = keccak256(abi.encodePacked(airnode, templateId));
        }
    
        /// @notice Derives the Beacon set ID from the Beacon IDs
        /// @dev Notice that `abi.encode()` is used over `abi.encodePacked()`
        /// @param beaconIds Beacon IDs
        /// @return beaconSetId Beacon set ID
        function deriveBeaconSetId(
            bytes32[] memory beaconIds
        ) internal pure returns (bytes32 beaconSetId) {
            beaconSetId = keccak256(abi.encode(beaconIds));
        }
    
        /// @notice Called privately to process the Beacon update
        /// @param beaconId Beacon ID
        /// @param timestamp Timestamp used in the signature
        /// @param data Fulfillment data (an `int256` encoded in contract ABI)
        /// @return updatedBeaconValue Updated Beacon value
        function processBeaconUpdate(
            bytes32 beaconId,
            uint256 timestamp,
            bytes calldata data
        )
            internal
            onlyValidTimestamp(timestamp)
            returns (int224 updatedBeaconValue)
        {
            updatedBeaconValue = decodeFulfillmentData(data);
            require(
                timestamp > _dataFeeds[beaconId].timestamp,
                "Does not update timestamp"
            );
            _dataFeeds[beaconId] = DataFeed({
                value: updatedBeaconValue,
                timestamp: uint32(timestamp)
            });
        }
    
        /// @notice Called privately to decode the fulfillment data
        /// @param data Fulfillment data (an `int256` encoded in contract ABI)
        /// @return decodedData Decoded fulfillment data
        function decodeFulfillmentData(
            bytes memory data
        ) internal pure returns (int224) {
            require(data.length == 32, "Data length not correct");
            int256 decodedData = abi.decode(data, (int256));
            require(
                decodedData >= type(int224).min && decodedData <= type(int224).max,
                "Value typecasting error"
            );
            return int224(decodedData);
        }
    
        /// @notice Called privately to aggregate the Beacons and return the result
        /// @param beaconIds Beacon IDs
        /// @return value Aggregation value
        /// @return timestamp Aggregation timestamp
        function aggregateBeacons(
            bytes32[] memory beaconIds
        ) internal view returns (int224 value, uint32 timestamp) {
            uint256 beaconCount = beaconIds.length;
            require(beaconCount > 1, "Specified less than two Beacons");
            int256[] memory values = new int256[](beaconCount);
            int256[] memory timestamps = new int256[](beaconCount);
            for (uint256 ind = 0; ind < beaconCount; ) {
                DataFeed storage dataFeed = _dataFeeds[beaconIds[ind]];
                values[ind] = dataFeed.value;
                timestamps[ind] = int256(uint256(dataFeed.timestamp));
                unchecked {
                    ind++;
                }
            }
            value = int224(median(values));
            timestamp = uint32(uint256(median(timestamps)));
        }
    }
    
  • contracts/api3-server-v1/OevDapiServer.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.17;
    
    import "./OevDataFeedServer.sol";
    import "./DapiServer.sol";
    import "./interfaces/IOevDapiServer.sol";
    
    /// @title Contract that serves OEV dAPIs
    contract OevDapiServer is OevDataFeedServer, DapiServer, IOevDapiServer {
        /// @param _accessControlRegistry AccessControlRegistry contract address
        /// @param _adminRoleDescription Admin role description
        /// @param _manager Manager address
        constructor(
            address _accessControlRegistry,
            string memory _adminRoleDescription,
            address _manager
        ) DapiServer(_accessControlRegistry, _adminRoleDescription, _manager) {}
    
        /// @notice Reads the data feed as the OEV proxy with dAPI name hash
        /// @param dapiNameHash dAPI name hash
        /// @return value Data feed value
        /// @return timestamp Data feed timestamp
        function _readDataFeedWithDapiNameHashAsOevProxy(
            bytes32 dapiNameHash
        ) internal view returns (int224 value, uint32 timestamp) {
            bytes32 dataFeedId = dapiNameHashToDataFeedId[dapiNameHash];
            require(dataFeedId != bytes32(0), "dAPI name not set");
            DataFeed storage oevDataFeed = _oevProxyToIdToDataFeed[msg.sender][
                dataFeedId
            ];
            DataFeed storage dataFeed = _dataFeeds[dataFeedId];
            if (oevDataFeed.timestamp > dataFeed.timestamp) {
                (value, timestamp) = (oevDataFeed.value, oevDataFeed.timestamp);
            } else {
                (value, timestamp) = (dataFeed.value, dataFeed.timestamp);
            }
            require(timestamp > 0, "Data feed not initialized");
        }
    }
    
  • contracts/api3-server-v1/OevDataFeedServer.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.17;
    
    import "./DataFeedServer.sol";
    import "./interfaces/IOevDataFeedServer.sol";
    import "../vendor/@openzeppelin/contracts@4.8.2/utils/cryptography/ECDSA.sol";
    import "./proxies/interfaces/IOevProxy.sol";
    
    /// @title Contract that serves OEV Beacons and Beacon sets
    /// @notice OEV Beacons and Beacon sets can be updated by the winner of the
    /// respective OEV auctions. The beneficiary can withdraw the proceeds from
    /// this contract.
    contract OevDataFeedServer is DataFeedServer, IOevDataFeedServer {
        using ECDSA for bytes32;
    
        /// @notice Data feed with ID specific to the OEV proxy
        /// @dev This implies that an update as a result of an OEV auction only
        /// affects contracts that read through the respective proxy that the
        /// auction was being held for
        mapping(address => mapping(bytes32 => DataFeed))
            internal _oevProxyToIdToDataFeed;
    
        /// @notice Accumulated OEV auction proceeds for the specific proxy
        mapping(address => uint256) public override oevProxyToBalance;
    
        /// @notice Updates a data feed that the OEV proxy reads using the
        /// aggregation signed by the absolute majority of the respective Airnodes
        /// for the specific bid
        /// @dev For when the data feed being updated is a Beacon set, an absolute
        /// majority of the Airnodes that power the respective Beacons must sign
        /// the aggregated value and timestamp. While doing so, the Airnodes should
        /// refer to data signed to update an absolute majority of the respective
        /// Beacons. The Airnodes should require the data to be fresh enough (e.g.,
        /// at most 2 minutes-old), and tightly distributed around the resulting
        /// aggregation (e.g., within 1% deviation), and reject to provide an OEV
        /// proxy data feed update signature if these are not satisfied.
        /// @param oevProxy OEV proxy that reads the data feed
        /// @param dataFeedId Data feed ID
        /// @param updateId Update ID
        /// @param timestamp Signature timestamp
        /// @param data Update data (an `int256` encoded in contract ABI)
        /// @param packedOevUpdateSignatures Packed OEV update signatures, which
        /// include the Airnode address, template ID and these signed with the OEV
        /// update hash
        function updateOevProxyDataFeedWithSignedData(
            address oevProxy,
            bytes32 dataFeedId,
            bytes32 updateId,
            uint256 timestamp,
            bytes calldata data,
            bytes[] calldata packedOevUpdateSignatures
        ) external payable override onlyValidTimestamp(timestamp) {
            require(
                timestamp > _oevProxyToIdToDataFeed[oevProxy][dataFeedId].timestamp,
                "Does not update timestamp"
            );
            bytes32 oevUpdateHash = keccak256(
                abi.encodePacked(
                    block.chainid,
                    address(this),
                    oevProxy,
                    dataFeedId,
                    updateId,
                    timestamp,
                    data,
                    msg.sender,
                    msg.value
                )
            );
            int224 updatedValue = decodeFulfillmentData(data);
            uint32 updatedTimestamp = uint32(timestamp);
            uint256 beaconCount = packedOevUpdateSignatures.length;
            if (beaconCount > 1) {
                bytes32[] memory beaconIds = new bytes32[](beaconCount);
                uint256 validSignatureCount;
                for (uint256 ind = 0; ind < beaconCount; ) {
                    bool signatureIsNotOmitted;
                    (
                        signatureIsNotOmitted,
                        beaconIds[ind]
                    ) = unpackAndValidateOevUpdateSignature(
                        oevUpdateHash,
                        packedOevUpdateSignatures[ind]
                    );
                    if (signatureIsNotOmitted) {
                        unchecked {
                            validSignatureCount++;
                        }
                    }
                    unchecked {
                        ind++;
                    }
                }
                // "Greater than or equal to" is not enough because full control
                // of aggregation requires an absolute majority
                require(
                    validSignatureCount > beaconCount / 2,
                    "Not enough signatures"
                );
                require(
                    dataFeedId == deriveBeaconSetId(beaconIds),
                    "Beacon set ID mismatch"
                );
                emit UpdatedOevProxyBeaconSetWithSignedData(
                    dataFeedId,
                    oevProxy,
                    updateId,
                    updatedValue,
                    updatedTimestamp
                );
            } else if (beaconCount == 1) {
                {
                    (
                        bool signatureIsNotOmitted,
                        bytes32 beaconId
                    ) = unpackAndValidateOevUpdateSignature(
                            oevUpdateHash,
                            packedOevUpdateSignatures[0]
                        );
                    require(signatureIsNotOmitted, "Missing signature");
                    require(dataFeedId == beaconId, "Beacon ID mismatch");
                }
                emit UpdatedOevProxyBeaconWithSignedData(
                    dataFeedId,
                    oevProxy,
                    updateId,
                    updatedValue,
                    updatedTimestamp
                );
            } else {
                revert("Did not specify any Beacons");
            }
            _oevProxyToIdToDataFeed[oevProxy][dataFeedId] = DataFeed({
                value: updatedValue,
                timestamp: updatedTimestamp
            });
            oevProxyToBalance[oevProxy] += msg.value;
        }
    
        /// @notice Withdraws the balance of the OEV proxy to the respective
        /// beneficiary account
        /// @dev This does not require the caller to be the beneficiary because we
        /// expect that in most cases, the OEV beneficiary will be a contract that
        /// will not be able to make arbitrary calls. Our choice can be worked
        /// around by implementing a beneficiary proxy.
        /// @param oevProxy OEV proxy
        function withdraw(address oevProxy) external override {
            address oevBeneficiary = IOevProxy(oevProxy).oevBeneficiary();
            require(oevBeneficiary != address(0), "Beneficiary address zero");
            uint256 balance = oevProxyToBalance[oevProxy];
            require(balance != 0, "OEV proxy balance zero");
            oevProxyToBalance[oevProxy] = 0;
            emit Withdrew(oevProxy, oevBeneficiary, balance);
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, ) = oevBeneficiary.call{value: balance}("");
            require(success, "Withdrawal reverted");
        }
    
        /// @notice Reads the data feed as the OEV proxy with ID
        /// @param dataFeedId Data feed ID
        /// @return value Data feed value
        /// @return timestamp Data feed timestamp
        function _readDataFeedWithIdAsOevProxy(
            bytes32 dataFeedId
        ) internal view returns (int224 value, uint32 timestamp) {
            DataFeed storage oevDataFeed = _oevProxyToIdToDataFeed[msg.sender][
                dataFeedId
            ];
            DataFeed storage dataFeed = _dataFeeds[dataFeedId];
            if (oevDataFeed.timestamp > dataFeed.timestamp) {
                (value, timestamp) = (oevDataFeed.value, oevDataFeed.timestamp);
            } else {
                (value, timestamp) = (dataFeed.value, dataFeed.timestamp);
            }
            require(timestamp > 0, "Data feed not initialized");
        }
    
        /// @notice Called privately to unpack and validate the OEV update
        /// signature
        /// @param oevUpdateHash OEV update hash
        /// @param packedOevUpdateSignature Packed OEV update signature, which
        /// includes the Airnode address, template ID and these signed with the OEV
        /// update hash
        /// @return signatureIsNotOmitted If the signature is omitted in
        /// `packedOevUpdateSignature`
        /// @return beaconId Beacon ID
        function unpackAndValidateOevUpdateSignature(
            bytes32 oevUpdateHash,
            bytes calldata packedOevUpdateSignature
        ) private pure returns (bool signatureIsNotOmitted, bytes32 beaconId) {
            (address airnode, bytes32 templateId, bytes memory signature) = abi
                .decode(packedOevUpdateSignature, (address, bytes32, bytes));
            beaconId = deriveBeaconId(airnode, templateId);
            if (signature.length != 0) {
                require(
                    (
                        keccak256(abi.encodePacked(oevUpdateHash, templateId))
                            .toEthSignedMessageHash()
                    ).recover(signature) == airnode,
                    "Signature mismatch"
                );
                signatureIsNotOmitted = true;
            }
        }
    }
    
  • contracts/api3-server-v1/aggregation/Median.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    import "./Sort.sol";
    import "./QuickSelect.sol";
    
    /// @title Contract to be inherited by contracts that will calculate the median
    /// of an array
    /// @notice The operation will be in-place, i.e., the array provided as the
    /// argument will be modified.
    contract Median is Sort, Quickselect {
        /// @notice Returns the median of the array
        /// @dev Uses an unrolled sorting implementation for shorter arrays and
        /// quickselect for longer arrays for gas cost efficiency
        /// @param array Array whose median is to be calculated
        /// @return Median of the array
        function median(int256[] memory array) internal pure returns (int256) {
            uint256 arrayLength = array.length;
            if (arrayLength <= MAX_SORT_LENGTH) {
                sort(array);
                if (arrayLength % 2 == 1) {
                    return array[arrayLength / 2];
                } else {
                    assert(arrayLength != 0);
                    unchecked {
                        return
                            average(
                                array[arrayLength / 2 - 1],
                                array[arrayLength / 2]
                            );
                    }
                }
            } else {
                if (arrayLength % 2 == 1) {
                    return array[quickselectK(array, arrayLength / 2)];
                } else {
                    uint256 mid1;
                    uint256 mid2;
                    unchecked {
                        (mid1, mid2) = quickselectKPlusOne(
                            array,
                            arrayLength / 2 - 1
                        );
                    }
                    return average(array[mid1], array[mid2]);
                }
            }
        }
    
        /// @notice Averages two signed integers without overflowing
        /// @param x Integer x
        /// @param y Integer y
        /// @return Average of integers x and y
        function average(int256 x, int256 y) private pure returns (int256) {
            unchecked {
                int256 averageRoundedDownToNegativeInfinity = (x >> 1) +
                    (y >> 1) +
                    (x & y & 1);
                // If the average rounded down to negative infinity is negative
                // (i.e., its 256th sign bit is set), and one of (x, y) is even and
                // the other one is odd (i.e., the 1st bit of their xor is set),
                // add 1 to round the average down to zero instead.
                // We will typecast the signed integer to unsigned to logical-shift
                // int256(uint256(signedInt)) >> 255 ~= signedInt >>> 255
                return
                    averageRoundedDownToNegativeInfinity +
                    (int256(
                        (uint256(averageRoundedDownToNegativeInfinity) >> 255)
                    ) & (x ^ y));
            }
        }
    }
    
  • contracts/api3-server-v1/aggregation/QuickSelect.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    /// @title Contract to be inherited by contracts that will calculate the index
    /// of the k-th and optionally (k+1)-th largest elements in the array
    /// @notice Uses quickselect, which operates in-place, i.e., the array provided
    /// as the argument will be modified.
    contract Quickselect {
        /// @notice Returns the index of the k-th largest element in the array
        /// @param array Array in which k-th largest element will be searched
        /// @param k K
        /// @return indK Index of the k-th largest element
        function quickselectK(
            int256[] memory array,
            uint256 k
        ) internal pure returns (uint256 indK) {
            uint256 arrayLength = array.length;
            assert(arrayLength > 0);
            unchecked {
                (indK, ) = quickselect(array, 0, arrayLength - 1, k, false);
            }
        }
    
        /// @notice Returns the index of the k-th and (k+1)-th largest elements in
        /// the array
        /// @param array Array in which k-th and (k+1)-th largest elements will be
        /// searched
        /// @param k K
        /// @return indK Index of the k-th largest element
        /// @return indKPlusOne Index of the (k+1)-th largest element
        function quickselectKPlusOne(
            int256[] memory array,
            uint256 k
        ) internal pure returns (uint256 indK, uint256 indKPlusOne) {
            uint256 arrayLength = array.length;
            assert(arrayLength > 1);
            unchecked {
                (indK, indKPlusOne) = quickselect(
                    array,
                    0,
                    arrayLength - 1,
                    k,
                    true
                );
            }
        }
    
        /// @notice Returns the index of the k-th largest element in the specified
        /// section of the (potentially unsorted) array
        /// @param array Array in which K will be searched for
        /// @param lo Starting index of the section of the array that K will be
        /// searched in
        /// @param hi Last index of the section of the array that K will be
        /// searched in
        /// @param k K
        /// @param selectKPlusOne If the index of the (k+1)-th largest element is
        /// to be returned
        /// @return indK Index of the k-th largest element
        /// @return indKPlusOne Index of the (k+1)-th largest element (only set if
        /// `selectKPlusOne` is `true`)
        function quickselect(
            int256[] memory array,
            uint256 lo,
            uint256 hi,
            uint256 k,
            bool selectKPlusOne
        ) private pure returns (uint256 indK, uint256 indKPlusOne) {
            if (lo == hi) {
                return (k, 0);
            }
            uint256 indPivot = partition(array, lo, hi);
            if (k < indPivot) {
                unchecked {
                    (indK, ) = quickselect(array, lo, indPivot - 1, k, false);
                }
            } else if (k > indPivot) {
                unchecked {
                    (indK, ) = quickselect(array, indPivot + 1, hi, k, false);
                }
            } else {
                indK = indPivot;
            }
            // Since Quickselect ends in the array being partitioned around the
            // k-th largest element, we can continue searching towards right for
            // the (k+1)-th largest element, which is useful in calculating the
            // median of an array with even length
            if (selectKPlusOne) {
                unchecked {
                    indKPlusOne = indK + 1;
                }
                uint256 i;
                unchecked {
                    i = indKPlusOne + 1;
                }
                uint256 arrayLength = array.length;
                for (; i < arrayLength; ) {
                    if (array[i] < array[indKPlusOne]) {
                        indKPlusOne = i;
                    }
                    unchecked {
                        i++;
                    }
                }
            }
        }
    
        /// @notice Partitions the array into two around a pivot
        /// @param array Array that will be partitioned
        /// @param lo Starting index of the section of the array that will be
        /// partitioned
        /// @param hi Last index of the section of the array that will be
        /// partitioned
        /// @return pivotInd Pivot index
        function partition(
            int256[] memory array,
            uint256 lo,
            uint256 hi
        ) private pure returns (uint256 pivotInd) {
            if (lo == hi) {
                return lo;
            }
            int256 pivot = array[lo];
            uint256 i = lo;
            unchecked {
                pivotInd = hi + 1;
            }
            while (true) {
                do {
                    unchecked {
                        i++;
                    }
                } while (i < array.length && array[i] < pivot);
                do {
                    unchecked {
                        pivotInd--;
                    }
                } while (array[pivotInd] > pivot);
                if (i >= pivotInd) {
                    (array[lo], array[pivotInd]) = (array[pivotInd], array[lo]);
                    return pivotInd;
                }
                (array[i], array[pivotInd]) = (array[pivotInd], array[i]);
            }
        }
    }
    
  • contracts/api3-server-v1/aggregation/Sort.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    /// @title Contract to be inherited by contracts that will sort an array using
    /// an unrolled implementation
    /// @notice The operation will be in-place, i.e., the array provided as the
    /// argument will be modified.
    contract Sort {
        uint256 internal constant MAX_SORT_LENGTH = 9;
    
        /// @notice Sorts the array
        /// @param array Array to be sorted
        function sort(int256[] memory array) internal pure {
            uint256 arrayLength = array.length;
            require(arrayLength <= MAX_SORT_LENGTH, "Array too long to sort");
            // Do a binary search
            if (arrayLength < 6) {
                // Possible lengths: 1, 2, 3, 4, 5
                if (arrayLength < 4) {
                    // Possible lengths: 1, 2, 3
                    if (arrayLength == 3) {
                        // Length: 3
                        swapIfFirstIsLarger(array, 0, 1);
                        swapIfFirstIsLarger(array, 1, 2);
                        swapIfFirstIsLarger(array, 0, 1);
                    } else if (arrayLength == 2) {
                        // Length: 2
                        swapIfFirstIsLarger(array, 0, 1);
                    }
                    // Do nothing for Length: 1
                } else {
                    // Possible lengths: 4, 5
                    if (arrayLength == 5) {
                        // Length: 5
                        swapIfFirstIsLarger(array, 1, 2);
                        swapIfFirstIsLarger(array, 3, 4);
                        swapIfFirstIsLarger(array, 1, 3);
                        swapIfFirstIsLarger(array, 0, 2);
                        swapIfFirstIsLarger(array, 2, 4);
                        swapIfFirstIsLarger(array, 0, 3);
                        swapIfFirstIsLarger(array, 0, 1);
                        swapIfFirstIsLarger(array, 2, 3);
                        swapIfFirstIsLarger(array, 1, 2);
                    } else {
                        // Length: 4
                        swapIfFirstIsLarger(array, 0, 1);
                        swapIfFirstIsLarger(array, 2, 3);
                        swapIfFirstIsLarger(array, 1, 3);
                        swapIfFirstIsLarger(array, 0, 2);
                        swapIfFirstIsLarger(array, 1, 2);
                    }
                }
            } else {
                // Possible lengths: 6, 7, 8, 9
                if (arrayLength < 8) {
                    // Possible lengths: 6, 7
                    if (arrayLength == 7) {
                        // Length: 7
                        swapIfFirstIsLarger(array, 1, 2);
                        swapIfFirstIsLarger(array, 3, 4);
                        swapIfFirstIsLarger(array, 5, 6);
                        swapIfFirstIsLarger(array, 0, 2);
                        swapIfFirstIsLarger(array, 4, 6);
                        swapIfFirstIsLarger(array, 3, 5);
                        swapIfFirstIsLarger(array, 2, 6);
                        swapIfFirstIsLarger(array, 1, 5);
                        swapIfFirstIsLarger(array, 0, 4);
                        swapIfFirstIsLarger(array, 2, 5);
                        swapIfFirstIsLarger(array, 0, 3);
                        swapIfFirstIsLarger(array, 2, 4);
                        swapIfFirstIsLarger(array, 1, 3);
                        swapIfFirstIsLarger(array, 0, 1);
                        swapIfFirstIsLarger(array, 2, 3);
                        swapIfFirstIsLarger(array, 4, 5);
                    } else {
                        // Length: 6
                        swapIfFirstIsLarger(array, 0, 1);
                        swapIfFirstIsLarger(array, 2, 3);
                        swapIfFirstIsLarger(array, 4, 5);
                        swapIfFirstIsLarger(array, 1, 3);
                        swapIfFirstIsLarger(array, 3, 5);
                        swapIfFirstIsLarger(array, 1, 3);
                        swapIfFirstIsLarger(array, 2, 4);
                        swapIfFirstIsLarger(array, 0, 2);
                        swapIfFirstIsLarger(array, 2, 4);
                        swapIfFirstIsLarger(array, 3, 4);
                        swapIfFirstIsLarger(array, 1, 2);
                        swapIfFirstIsLarger(array, 2, 3);
                    }
                } else {
                    // Possible lengths: 8, 9
                    if (arrayLength == 9) {
                        // Length: 9
                        swapIfFirstIsLarger(array, 1, 8);
                        swapIfFirstIsLarger(array, 2, 7);
                        swapIfFirstIsLarger(array, 3, 6);
                        swapIfFirstIsLarger(array, 4, 5);
                        swapIfFirstIsLarger(array, 1, 4);
                        swapIfFirstIsLarger(array, 5, 8);
                        swapIfFirstIsLarger(array, 0, 2);
                        swapIfFirstIsLarger(array, 6, 7);
                        swapIfFirstIsLarger(array, 2, 6);
                        swapIfFirstIsLarger(array, 7, 8);
                        swapIfFirstIsLarger(array, 0, 3);
                        swapIfFirstIsLarger(array, 4, 5);
                        swapIfFirstIsLarger(array, 0, 1);
                        swapIfFirstIsLarger(array, 3, 5);
                        swapIfFirstIsLarger(array, 6, 7);
                        swapIfFirstIsLarger(array, 2, 4);
                        swapIfFirstIsLarger(array, 1, 3);
                        swapIfFirstIsLarger(array, 5, 7);
                        swapIfFirstIsLarger(array, 4, 6);
                        swapIfFirstIsLarger(array, 1, 2);
                        swapIfFirstIsLarger(array, 3, 4);
                        swapIfFirstIsLarger(array, 5, 6);
                        swapIfFirstIsLarger(array, 7, 8);
                        swapIfFirstIsLarger(array, 2, 3);
                        swapIfFirstIsLarger(array, 4, 5);
                    } else {
                        // Length: 8
                        swapIfFirstIsLarger(array, 0, 7);
                        swapIfFirstIsLarger(array, 1, 6);
                        swapIfFirstIsLarger(array, 2, 5);
                        swapIfFirstIsLarger(array, 3, 4);
                        swapIfFirstIsLarger(array, 0, 3);
                        swapIfFirstIsLarger(array, 4, 7);
                        swapIfFirstIsLarger(array, 1, 2);
                        swapIfFirstIsLarger(array, 5, 6);
                        swapIfFirstIsLarger(array, 0, 1);
                        swapIfFirstIsLarger(array, 2, 3);
                        swapIfFirstIsLarger(array, 4, 5);
                        swapIfFirstIsLarger(array, 6, 7);
                        swapIfFirstIsLarger(array, 3, 5);
                        swapIfFirstIsLarger(array, 2, 4);
                        swapIfFirstIsLarger(array, 1, 2);
                        swapIfFirstIsLarger(array, 3, 4);
                        swapIfFirstIsLarger(array, 5, 6);
                        swapIfFirstIsLarger(array, 2, 3);
                        swapIfFirstIsLarger(array, 4, 5);
                        swapIfFirstIsLarger(array, 3, 4);
                    }
                }
            }
        }
    
        /// @notice Swaps two elements of an array if the first element is greater
        /// than the second
        /// @param array Array whose elements are to be swapped
        /// @param ind1 Index of the first element
        /// @param ind2 Index of the second element
        function swapIfFirstIsLarger(
            int256[] memory array,
            uint256 ind1,
            uint256 ind2
        ) private pure {
            if (array[ind1] > array[ind2]) {
                (array[ind1], array[ind2]) = (array[ind2], array[ind1]);
            }
        }
    }
    
  • contracts/api3-server-v1/interfaces/IApi3ServerV1.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    import "./IOevDapiServer.sol";
    import "./IBeaconUpdatesWithSignedData.sol";
    
    interface IApi3ServerV1 is IOevDapiServer, IBeaconUpdatesWithSignedData {
        function readDataFeedWithId(
            bytes32 dataFeedId
        ) external view returns (int224 value, uint32 timestamp);
    
        function readDataFeedWithDapiNameHash(
            bytes32 dapiNameHash
        ) external view returns (int224 value, uint32 timestamp);
    
        function readDataFeedWithIdAsOevProxy(
            bytes32 dataFeedId
        ) external view returns (int224 value, uint32 timestamp);
    
        function readDataFeedWithDapiNameHashAsOevProxy(
            bytes32 dapiNameHash
        ) external view returns (int224 value, uint32 timestamp);
    
        function dataFeeds(
            bytes32 dataFeedId
        ) external view returns (int224 value, uint32 timestamp);
    
        function oevProxyToIdToDataFeed(
            address proxy,
            bytes32 dataFeedId
        ) external view returns (int224 value, uint32 timestamp);
    }
    
  • contracts/api3-server-v1/interfaces/IBeaconUpdatesWithSignedData.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    import "./IDataFeedServer.sol";
    
    interface IBeaconUpdatesWithSignedData is IDataFeedServer {
        function updateBeaconWithSignedData(
            address airnode,
            bytes32 templateId,
            uint256 timestamp,
            bytes calldata data,
            bytes calldata signature
        ) external returns (bytes32 beaconId);
    }
    
  • contracts/api3-server-v1/interfaces/IDapiServer.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    import "../../access/interfaces/IAccessControlRegistryAdminnedWithManager.sol";
    import "./IDataFeedServer.sol";
    
    interface IDapiServer is
        IAccessControlRegistryAdminnedWithManager,
        IDataFeedServer
    {
        event SetDapiName(
            bytes32 indexed dataFeedId,
            bytes32 indexed dapiName,
            address sender
        );
    
        function setDapiName(bytes32 dapiName, bytes32 dataFeedId) external;
    
        function dapiNameToDataFeedId(
            bytes32 dapiName
        ) external view returns (bytes32);
    
        // solhint-disable-next-line func-name-mixedcase
        function DAPI_NAME_SETTER_ROLE_DESCRIPTION()
            external
            view
            returns (string memory);
    
        function dapiNameSetterRole() external view returns (bytes32);
    
        function dapiNameHashToDataFeedId(
            bytes32 dapiNameHash
        ) external view returns (bytes32 dataFeedId);
    }
    
  • contracts/api3-server-v1/interfaces/IDataFeedServer.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    import "../../utils/interfaces/IExtendedSelfMulticall.sol";
    
    interface IDataFeedServer is IExtendedSelfMulticall {
        event UpdatedBeaconWithSignedData(
            bytes32 indexed beaconId,
            int224 value,
            uint32 timestamp
        );
    
        event UpdatedBeaconSetWithBeacons(
            bytes32 indexed beaconSetId,
            int224 value,
            uint32 timestamp
        );
    
        function updateBeaconSetWithBeacons(
            bytes32[] memory beaconIds
        ) external returns (bytes32 beaconSetId);
    }
    
  • contracts/api3-server-v1/interfaces/IOevDapiServer.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    import "./IOevDataFeedServer.sol";
    import "./IDapiServer.sol";
    
    interface IOevDapiServer is IOevDataFeedServer, IDapiServer {}
    
  • contracts/api3-server-v1/interfaces/IOevDataFeedServer.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    import "./IDataFeedServer.sol";
    
    interface IOevDataFeedServer is IDataFeedServer {
        event UpdatedOevProxyBeaconWithSignedData(
            bytes32 indexed beaconId,
            address indexed proxy,
            bytes32 indexed updateId,
            int224 value,
            uint32 timestamp
        );
    
        event UpdatedOevProxyBeaconSetWithSignedData(
            bytes32 indexed beaconSetId,
            address indexed proxy,
            bytes32 indexed updateId,
            int224 value,
            uint32 timestamp
        );
    
        event Withdrew(
            address indexed oevProxy,
            address oevBeneficiary,
            uint256 amount
        );
    
        function updateOevProxyDataFeedWithSignedData(
            address oevProxy,
            bytes32 dataFeedId,
            bytes32 updateId,
            uint256 timestamp,
            bytes calldata data,
            bytes[] calldata packedOevUpdateSignatures
        ) external payable;
    
        function withdraw(address oevProxy) external;
    
        function oevProxyToBalance(
            address oevProxy
        ) external view returns (uint256 balance);
    }
    
  • contracts/api3-server-v1/proxies/interfaces/IOevProxy.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    interface IOevProxy {
        function oevBeneficiary() external view returns (address);
    }
    
  • contracts/utils/ExtendedSelfMulticall.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    
    import "./SelfMulticall.sol";
    import "./interfaces/IExtendedSelfMulticall.sol";
    
    /// @title Contract that extends SelfMulticall to fetch some of the global
    /// variables
    /// @notice Available global variables are limited to the ones that Airnode
    /// tends to need
    contract ExtendedSelfMulticall is SelfMulticall, IExtendedSelfMulticall {
        /// @notice Returns the chain ID
        /// @return Chain ID
        function getChainId() external view override returns (uint256) {
            return block.chainid;
        }
    
        /// @notice Returns the account balance
        /// @param account Account address
        /// @return Account balance
        function getBalance(
            address account
        ) external view override returns (uint256) {
            return account.balance;
        }
    
        /// @notice Returns if the account contains bytecode
        /// @dev An account not containing any bytecode does not indicate that it
        /// is an EOA or it will not contain any bytecode in the future.
        /// Contract construction and `SELFDESTRUCT` updates the bytecode at the
        /// end of the transaction.
        /// @return If the account contains bytecode
        function containsBytecode(
            address account
        ) external view override returns (bool) {
            return account.code.length > 0;
        }
    
        /// @notice Returns the current block number
        /// @return Current block number
        function getBlockNumber() external view override returns (uint256) {
            return block.number;
        }
    
        /// @notice Returns the current block timestamp
        /// @return Current block timestamp
        function getBlockTimestamp() external view override returns (uint256) {
            return block.timestamp;
        }
    
        /// @notice Returns the current block basefee
        /// @return Current block basefee
        function getBlockBasefee() external view override returns (uint256) {
            return block.basefee;
        }
    }
    
  • contracts/utils/SelfMulticall.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    import "./interfaces/ISelfMulticall.sol";
    
    /// @title Contract that enables calls to the inheriting contract to be batched
    /// @notice Implements two ways of batching, one requires none of the calls to
    /// revert and the other tolerates individual calls reverting
    /// @dev This implementation uses delegatecall for individual function calls.
    /// Since delegatecall is a message call, it can only be made to functions that
    /// are externally visible. This means that a contract cannot multicall its own
    /// functions that use internal/private visibility modifiers.
    /// Refer to OpenZeppelin's Multicall.sol for a similar implementation.
    contract SelfMulticall is ISelfMulticall {
        /// @notice Batches calls to the inheriting contract and reverts as soon as
        /// one of the batched calls reverts
        /// @param data Array of calldata of batched calls
        /// @return returndata Array of returndata of batched calls
        function multicall(
            bytes[] calldata data
        ) external override returns (bytes[] memory returndata) {
            uint256 callCount = data.length;
            returndata = new bytes[](callCount);
            for (uint256 ind = 0; ind < callCount; ) {
                bool success;
                // solhint-disable-next-line avoid-low-level-calls
                (success, returndata[ind]) = address(this).delegatecall(data[ind]);
                if (!success) {
                    bytes memory returndataWithRevertData = returndata[ind];
                    if (returndataWithRevertData.length > 0) {
                        // Adapted from OpenZeppelin's Address.sol
                        // solhint-disable-next-line no-inline-assembly
                        assembly {
                            let returndata_size := mload(returndataWithRevertData)
                            revert(
                                add(32, returndataWithRevertData),
                                returndata_size
                            )
                        }
                    } else {
                        revert("Multicall: No revert string");
                    }
                }
                unchecked {
                    ind++;
                }
            }
        }
    
        /// @notice Batches calls to the inheriting contract but does not revert if
        /// any of the batched calls reverts
        /// @param data Array of calldata of batched calls
        /// @return successes Array of success conditions of batched calls
        /// @return returndata Array of returndata of batched calls
        function tryMulticall(
            bytes[] calldata data
        )
            external
            override
            returns (bool[] memory successes, bytes[] memory returndata)
        {
            uint256 callCount = data.length;
            successes = new bool[](callCount);
            returndata = new bytes[](callCount);
            for (uint256 ind = 0; ind < callCount; ) {
                // solhint-disable-next-line avoid-low-level-calls
                (successes[ind], returndata[ind]) = address(this).delegatecall(
                    data[ind]
                );
                unchecked {
                    ind++;
                }
            }
        }
    }
    
  • contracts/utils/interfaces/IExtendedSelfMulticall.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    import "./ISelfMulticall.sol";
    
    interface IExtendedSelfMulticall is ISelfMulticall {
        function getChainId() external view returns (uint256);
    
        function getBalance(address account) external view returns (uint256);
    
        function containsBytecode(address account) external view returns (bool);
    
        function getBlockNumber() external view returns (uint256);
    
        function getBlockTimestamp() external view returns (uint256);
    
        function getBlockBasefee() external view returns (uint256);
    }
    
  • contracts/utils/interfaces/ISelfMulticall.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    interface ISelfMulticall {
        function multicall(
            bytes[] calldata data
        ) external returns (bytes[] memory returndata);
    
        function tryMulticall(
            bytes[] calldata data
        ) external returns (bool[] memory successes, bytes[] memory returndata);
    }
    
  • contracts/vendor/@openzeppelin/contracts@4.8.2/access/IAccessControl.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
    
    pragma solidity ^0.8.0;
    
    /**
     * @dev External interface of AccessControl declared to support ERC165 detection.
     */
    interface IAccessControl {
        /**
         * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
         *
         * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
         * {RoleAdminChanged} not being emitted signaling this.
         *
         * _Available since v3.1._
         */
        event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
    
        /**
         * @dev Emitted when `account` is granted `role`.
         *
         * `sender` is the account that originated the contract call, an admin role
         * bearer except when using {AccessControl-_setupRole}.
         */
        event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
    
        /**
         * @dev Emitted when `account` is revoked `role`.
         *
         * `sender` is the account that originated the contract call:
         *   - if using `revokeRole`, it is the admin role bearer
         *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
         */
        event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
    
        /**
         * @dev Returns `true` if `account` has been granted `role`.
         */
        function hasRole(bytes32 role, address account) external view returns (bool);
    
        /**
         * @dev Returns the admin role that controls `role`. See {grantRole} and
         * {revokeRole}.
         *
         * To change a role's admin, use {AccessControl-_setRoleAdmin}.
         */
        function getRoleAdmin(bytes32 role) external view returns (bytes32);
    
        /**
         * @dev Grants `role` to `account`.
         *
         * If `account` had not been already granted `role`, emits a {RoleGranted}
         * event.
         *
         * Requirements:
         *
         * - the caller must have ``role``'s admin role.
         */
        function grantRole(bytes32 role, address account) external;
    
        /**
         * @dev Revokes `role` from `account`.
         *
         * If `account` had been granted `role`, emits a {RoleRevoked} event.
         *
         * Requirements:
         *
         * - the caller must have ``role``'s admin role.
         */
        function revokeRole(bytes32 role, address account) external;
    
        /**
         * @dev Revokes `role` from the calling account.
         *
         * Roles are often managed via {grantRole} and {revokeRole}: this function's
         * purpose is to provide a mechanism for accounts to lose their privileges
         * if they are compromised (such as when a trusted device is misplaced).
         *
         * If the calling account had been granted `role`, emits a {RoleRevoked}
         * event.
         *
         * Requirements:
         *
         * - the caller must be `account`.
         */
        function renounceRole(bytes32 role, address account) external;
    }
    
  • contracts/vendor/@openzeppelin/contracts@4.8.2/utils/Strings.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
    
    pragma solidity ^0.8.0;
    
    import "./math/Math.sol";
    
    /**
     * @dev String operations.
     */
    library Strings {
        bytes16 private constant _SYMBOLS = "0123456789abcdef";
        uint8 private constant _ADDRESS_LENGTH = 20;
    
        /**
         * @dev Converts a `uint256` to its ASCII `string` decimal representation.
         */
        function toString(uint256 value) internal pure returns (string memory) {
            unchecked {
                uint256 length = Math.log10(value) + 1;
                string memory buffer = new string(length);
                uint256 ptr;
                /// @solidity memory-safe-assembly
                assembly {
                    ptr := add(buffer, add(32, length))
                }
                while (true) {
                    ptr--;
                    /// @solidity memory-safe-assembly
                    assembly {
                        mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                    }
                    value /= 10;
                    if (value == 0) break;
                }
                return buffer;
            }
        }
    
        /**
         * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
         */
        function toHexString(uint256 value) internal pure returns (string memory) {
            unchecked {
                return toHexString(value, Math.log256(value) + 1);
            }
        }
    
        /**
         * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
         */
        function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
            bytes memory buffer = new bytes(2 * length + 2);
            buffer[0] = "0";
            buffer[1] = "x";
            for (uint256 i = 2 * length + 1; i > 1; --i) {
                buffer[i] = _SYMBOLS[value & 0xf];
                value >>= 4;
            }
            require(value == 0, "Strings: hex length insufficient");
            return string(buffer);
        }
    
        /**
         * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
         */
        function toHexString(address addr) internal pure returns (string memory) {
            return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
        }
    }
    
  • contracts/vendor/@openzeppelin/contracts@4.8.2/utils/cryptography/ECDSA.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)
    
    pragma solidity ^0.8.0;
    
    import "../Strings.sol";
    
    /**
     * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
     *
     * These functions can be used to verify that a message was signed by the holder
     * of the private keys of a given address.
     */
    library ECDSA {
        enum RecoverError {
            NoError,
            InvalidSignature,
            InvalidSignatureLength,
            InvalidSignatureS,
            InvalidSignatureV // Deprecated in v4.8
        }
    
        function _throwError(RecoverError error) private pure {
            if (error == RecoverError.NoError) {
                return; // no error: do nothing
            } else if (error == RecoverError.InvalidSignature) {
                revert("ECDSA: invalid signature");
            } else if (error == RecoverError.InvalidSignatureLength) {
                revert("ECDSA: invalid signature length");
            } else if (error == RecoverError.InvalidSignatureS) {
                revert("ECDSA: invalid signature 's' value");
            }
        }
    
        /**
         * @dev Returns the address that signed a hashed message (`hash`) with
         * `signature` or error string. This address can then be used for verification purposes.
         *
         * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
         * this function rejects them by requiring the `s` value to be in the lower
         * half order, and the `v` value to be either 27 or 28.
         *
         * IMPORTANT: `hash` _must_ be the result of a hash operation for the
         * verification to be secure: it is possible to craft signatures that
         * recover to arbitrary addresses for non-hashed data. A safe way to ensure
         * this is by receiving a hash of the original message (which may otherwise
         * be too long), and then calling {toEthSignedMessageHash} on it.
         *
         * Documentation for signature generation:
         * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
         * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
         *
         * _Available since v4.3._
         */
        function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
            if (signature.length == 65) {
                bytes32 r;
                bytes32 s;
                uint8 v;
                // ecrecover takes the signature parameters, and the only way to get them
                // currently is to use assembly.
                /// @solidity memory-safe-assembly
                assembly {
                    r := mload(add(signature, 0x20))
                    s := mload(add(signature, 0x40))
                    v := byte(0, mload(add(signature, 0x60)))
                }
                return tryRecover(hash, v, r, s);
            } else {
                return (address(0), RecoverError.InvalidSignatureLength);
            }
        }
    
        /**
         * @dev Returns the address that signed a hashed message (`hash`) with
         * `signature`. This address can then be used for verification purposes.
         *
         * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
         * this function rejects them by requiring the `s` value to be in the lower
         * half order, and the `v` value to be either 27 or 28.
         *
         * IMPORTANT: `hash` _must_ be the result of a hash operation for the
         * verification to be secure: it is possible to craft signatures that
         * recover to arbitrary addresses for non-hashed data. A safe way to ensure
         * this is by receiving a hash of the original message (which may otherwise
         * be too long), and then calling {toEthSignedMessageHash} on it.
         */
        function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
            (address recovered, RecoverError error) = tryRecover(hash, signature);
            _throwError(error);
            return recovered;
        }
    
        /**
         * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
         *
         * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
         *
         * _Available since v4.3._
         */
        function tryRecover(
            bytes32 hash,
            bytes32 r,
            bytes32 vs
        ) internal pure returns (address, RecoverError) {
            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
            uint8 v = uint8((uint256(vs) >> 255) + 27);
            return tryRecover(hash, v, r, s);
        }
    
        /**
         * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
         *
         * _Available since v4.2._
         */
        function recover(
            bytes32 hash,
            bytes32 r,
            bytes32 vs
        ) internal pure returns (address) {
            (address recovered, RecoverError error) = tryRecover(hash, r, vs);
            _throwError(error);
            return recovered;
        }
    
        /**
         * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
         * `r` and `s` signature fields separately.
         *
         * _Available since v4.3._
         */
        function tryRecover(
            bytes32 hash,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) internal pure returns (address, RecoverError) {
            // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
            // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
            // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
            // signatures from current libraries generate a unique signature with an s-value in the lower half order.
            //
            // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
            // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
            // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
            // these malleable signatures as well.
            if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
                return (address(0), RecoverError.InvalidSignatureS);
            }
    
            // If the signature is valid (and not malleable), return the signer address
            address signer = ecrecover(hash, v, r, s);
            if (signer == address(0)) {
                return (address(0), RecoverError.InvalidSignature);
            }
    
            return (signer, RecoverError.NoError);
        }
    
        /**
         * @dev Overload of {ECDSA-recover} that receives the `v`,
         * `r` and `s` signature fields separately.
         */
        function recover(
            bytes32 hash,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) internal pure returns (address) {
            (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
            _throwError(error);
            return recovered;
        }
    
        /**
         * @dev Returns an Ethereum Signed Message, created from a `hash`. This
         * produces hash corresponding to the one signed with the
         * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
         * JSON-RPC method as part of EIP-191.
         *
         * See {recover}.
         */
        function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
            // 32 is the length in bytes of hash,
            // enforced by the type signature above
            return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
        }
    
        /**
         * @dev Returns an Ethereum Signed Message, created from `s`. This
         * produces hash corresponding to the one signed with the
         * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
         * JSON-RPC method as part of EIP-191.
         *
         * See {recover}.
         */
        function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
            return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
        }
    
        /**
         * @dev Returns an Ethereum Signed Typed Data, created from a
         * `domainSeparator` and a `structHash`. This produces hash corresponding
         * to the one signed with the
         * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
         * JSON-RPC method as part of EIP-712.
         *
         * See {recover}.
         */
        function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
            return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
        }
    }
    
  • contracts/vendor/@openzeppelin/contracts@4.8.2/utils/math/Math.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
    
    pragma solidity ^0.8.0;
    
    /**
     * @dev Standard math utilities missing in the Solidity language.
     */
    library Math {
        enum Rounding {
            Down, // Toward negative infinity
            Up, // Toward infinity
            Zero // Toward zero
        }
    
        /**
         * @dev Returns the largest of two numbers.
         */
        function max(uint256 a, uint256 b) internal pure returns (uint256) {
            return a > b ? a : b;
        }
    
        /**
         * @dev Returns the smallest of two numbers.
         */
        function min(uint256 a, uint256 b) internal pure returns (uint256) {
            return a < b ? a : b;
        }
    
        /**
         * @dev Returns the average of two numbers. The result is rounded towards
         * zero.
         */
        function average(uint256 a, uint256 b) internal pure returns (uint256) {
            // (a + b) / 2 can overflow.
            return (a & b) + (a ^ b) / 2;
        }
    
        /**
         * @dev Returns the ceiling of the division of two numbers.
         *
         * This differs from standard division with `/` in that it rounds up instead
         * of rounding down.
         */
        function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
            // (a + b - 1) / b can overflow on addition, so we distribute.
            return a == 0 ? 0 : (a - 1) / b + 1;
        }
    
        /**
         * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
         * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
         * with further edits by Uniswap Labs also under MIT license.
         */
        function mulDiv(
            uint256 x,
            uint256 y,
            uint256 denominator
        ) internal pure returns (uint256 result) {
            unchecked {
                // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
                // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
                // variables such that product = prod1 * 2^256 + prod0.
                uint256 prod0; // Least significant 256 bits of the product
                uint256 prod1; // Most significant 256 bits of the product
                assembly {
                    let mm := mulmod(x, y, not(0))
                    prod0 := mul(x, y)
                    prod1 := sub(sub(mm, prod0), lt(mm, prod0))
                }
    
                // Handle non-overflow cases, 256 by 256 division.
                if (prod1 == 0) {
                    return prod0 / denominator;
                }
    
                // Make sure the result is less than 2^256. Also prevents denominator == 0.
                require(denominator > prod1);
    
                ///////////////////////////////////////////////
                // 512 by 256 division.
                ///////////////////////////////////////////////
    
                // Make division exact by subtracting the remainder from [prod1 prod0].
                uint256 remainder;
                assembly {
                    // Compute remainder using mulmod.
                    remainder := mulmod(x, y, denominator)
    
                    // Subtract 256 bit number from 512 bit number.
                    prod1 := sub(prod1, gt(remainder, prod0))
                    prod0 := sub(prod0, remainder)
                }
    
                // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
                // See https://cs.stackexchange.com/q/138556/92363.
    
                // Does not overflow because the denominator cannot be zero at this stage in the function.
                uint256 twos = denominator & (~denominator + 1);
                assembly {
                    // Divide denominator by twos.
                    denominator := div(denominator, twos)
    
                    // Divide [prod1 prod0] by twos.
                    prod0 := div(prod0, twos)
    
                    // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                    twos := add(div(sub(0, twos), twos), 1)
                }
    
                // Shift in bits from prod1 into prod0.
                prod0 |= prod1 * twos;
    
                // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
                // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
                // four bits. That is, denominator * inv = 1 mod 2^4.
                uint256 inverse = (3 * denominator) ^ 2;
    
                // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
                // in modular arithmetic, doubling the correct bits in each step.
                inverse *= 2 - denominator * inverse; // inverse mod 2^8
                inverse *= 2 - denominator * inverse; // inverse mod 2^16
                inverse *= 2 - denominator * inverse; // inverse mod 2^32
                inverse *= 2 - denominator * inverse; // inverse mod 2^64
                inverse *= 2 - denominator * inverse; // inverse mod 2^128
                inverse *= 2 - denominator * inverse; // inverse mod 2^256
    
                // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
                // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
                // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
                // is no longer required.
                result = prod0 * inverse;
                return result;
            }
        }
    
        /**
         * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
         */
        function mulDiv(
            uint256 x,
            uint256 y,
            uint256 denominator,
            Rounding rounding
        ) internal pure returns (uint256) {
            uint256 result = mulDiv(x, y, denominator);
            if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
                result += 1;
            }
            return result;
        }
    
        /**
         * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
         *
         * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
         */
        function sqrt(uint256 a) internal pure returns (uint256) {
            if (a == 0) {
                return 0;
            }
    
            // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
            //
            // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
            // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
            //
            // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
            // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
            // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
            //
            // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
            uint256 result = 1 << (log2(a) >> 1);
    
            // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
            // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
            // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
            // into the expected uint128 result.
            unchecked {
                result = (result + a / result) >> 1;
                result = (result + a / result) >> 1;
                result = (result + a / result) >> 1;
                result = (result + a / result) >> 1;
                result = (result + a / result) >> 1;
                result = (result + a / result) >> 1;
                result = (result + a / result) >> 1;
                return min(result, a / result);
            }
        }
    
        /**
         * @notice Calculates sqrt(a), following the selected rounding direction.
         */
        function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
            unchecked {
                uint256 result = sqrt(a);
                return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
            }
        }
    
        /**
         * @dev Return the log in base 2, rounded down, of a positive value.
         * Returns 0 if given 0.
         */
        function log2(uint256 value) internal pure returns (uint256) {
            uint256 result = 0;
            unchecked {
                if (value >> 128 > 0) {
                    value >>= 128;
                    result += 128;
                }
                if (value >> 64 > 0) {
                    value >>= 64;
                    result += 64;
                }
                if (value >> 32 > 0) {
                    value >>= 32;
                    result += 32;
                }
                if (value >> 16 > 0) {
                    value >>= 16;
                    result += 16;
                }
                if (value >> 8 > 0) {
                    value >>= 8;
                    result += 8;
                }
                if (value >> 4 > 0) {
                    value >>= 4;
                    result += 4;
                }
                if (value >> 2 > 0) {
                    value >>= 2;
                    result += 2;
                }
                if (value >> 1 > 0) {
                    result += 1;
                }
            }
            return result;
        }
    
        /**
         * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
         * Returns 0 if given 0.
         */
        function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
            unchecked {
                uint256 result = log2(value);
                return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
            }
        }
    
        /**
         * @dev Return the log in base 10, rounded down, of a positive value.
         * Returns 0 if given 0.
         */
        function log10(uint256 value) internal pure returns (uint256) {
            uint256 result = 0;
            unchecked {
                if (value >= 10**64) {
                    value /= 10**64;
                    result += 64;
                }
                if (value >= 10**32) {
                    value /= 10**32;
                    result += 32;
                }
                if (value >= 10**16) {
                    value /= 10**16;
                    result += 16;
                }
                if (value >= 10**8) {
                    value /= 10**8;
                    result += 8;
                }
                if (value >= 10**4) {
                    value /= 10**4;
                    result += 4;
                }
                if (value >= 10**2) {
                    value /= 10**2;
                    result += 2;
                }
                if (value >= 10**1) {
                    result += 1;
                }
            }
            return result;
        }
    
        /**
         * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
         * Returns 0 if given 0.
         */
        function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
            unchecked {
                uint256 result = log10(value);
                return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
            }
        }
    
        /**
         * @dev Return the log in base 256, rounded down, of a positive value.
         * Returns 0 if given 0.
         *
         * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
         */
        function log256(uint256 value) internal pure returns (uint256) {
            uint256 result = 0;
            unchecked {
                if (value >> 128 > 0) {
                    value >>= 128;
                    result += 16;
                }
                if (value >> 64 > 0) {
                    value >>= 64;
                    result += 8;
                }
                if (value >> 32 > 0) {
                    value >>= 32;
                    result += 4;
                }
                if (value >> 16 > 0) {
                    value >>= 16;
                    result += 2;
                }
                if (value >> 8 > 0) {
                    result += 1;
                }
            }
            return result;
        }
    
        /**
         * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
         * Returns 0 if given 0.
         */
        function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
            unchecked {
                uint256 result = log256(value);
                return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
            }
        }
    }
    
ABI · 35 entries
json
[
  {
    "type": "constructor",
    "inputs": [
      {
        "name": "_accessControlRegistry",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "_adminRoleDescription",
        "type": "string",
        "internalType": "string"
      },
      {
        "name": "_manager",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "name": "SetDapiName",
    "type": "event",
    "inputs": [
      {
        "name": "dataFeedId",
        "type": "bytes32",
        "indexed": true,
        "internalType": "bytes32"
      },
      {
        "name": "dapiName",
        "type": "bytes32",
        "indexed": true,
        "internalType": "bytes32"
      },
      {
        "name": "sender",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "name": "UpdatedBeaconSetWithBeacons",
    "type": "event",
    "inputs": [
      {
        "name": "beaconSetId",
        "type": "bytes32",
        "indexed": true,
        "internalType": "bytes32"
      },
      {
        "name": "value",
        "type": "int224",
        "indexed": false,
        "internalType": "int224"
      },
      {
        "name": "timestamp",
        "type": "uint32",
        "indexed": false,
        "internalType": "uint32"
      }
    ],
    "anonymous": false
  },
  {
    "name": "UpdatedBeaconWithSignedData",
    "type": "event",
    "inputs": [
      {
        "name": "beaconId",
        "type": "bytes32",
        "indexed": true,
        "internalType": "bytes32"
      },
      {
        "name": "value",
        "type": "int224",
        "indexed": false,
        "internalType": "int224"
      },
      {
        "name": "timestamp",
        "type": "uint32",
        "indexed": false,
        "internalType": "uint32"
      }
    ],
    "anonymous": false
  },
  {
    "name": "UpdatedOevProxyBeaconSetWithSignedData",
    "type": "event",
    "inputs": [
      {
        "name": "beaconSetId",
        "type": "bytes32",
        "indexed": true,
        "internalType": "bytes32"
      },
      {
        "name": "proxy",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "updateId",
        "type": "bytes32",
        "indexed": true,
        "internalType": "bytes32"
      },
      {
        "name": "value",
        "type": "int224",
        "indexed": false,
        "internalType": "int224"
      },
      {
        "name": "timestamp",
        "type": "uint32",
        "indexed": false,
        "internalType": "uint32"
      }
    ],
    "anonymous": false
  },
  {
    "name": "UpdatedOevProxyBeaconWithSignedData",
    "type": "event",
    "inputs": [
      {
        "name": "beaconId",
        "type": "bytes32",
        "indexed": true,
        "internalType": "bytes32"
      },
      {
        "name": "proxy",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "updateId",
        "type": "bytes32",
        "indexed": true,
        "internalType": "bytes32"
      },
      {
        "name": "value",
        "type": "int224",
        "indexed": false,
        "internalType": "int224"
      },
      {
        "name": "timestamp",
        "type": "uint32",
        "indexed": false,
        "internalType": "uint32"
      }
    ],
    "anonymous": false
  },
  {
    "name": "Withdrew",
    "type": "event",
    "inputs": [
      {
        "name": "oevProxy",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "oevBeneficiary",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "amount",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "name": "DAPI_NAME_SETTER_ROLE_DESCRIPTION",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "string",
        "internalType": "string"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "accessControlRegistry",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "adminRole",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "adminRoleDescription",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "string",
        "internalType": "string"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "containsBytecode",
    "type": "function",
    "inputs": [
      {
        "name": "account",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "dapiNameHashToDataFeedId",
    "type": "function",
    "inputs": [
      {
        "name": "",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "dapiNameSetterRole",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "dapiNameToDataFeedId",
    "type": "function",
    "inputs": [
      {
        "name": "dapiName",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "dataFeeds",
    "type": "function",
    "inputs": [
      {
        "name": "dataFeedId",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "outputs": [
      {
        "name": "value",
        "type": "int224",
        "internalType": "int224"
      },
      {
        "name": "timestamp",
        "type": "uint32",
        "internalType": "uint32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getBalance",
    "type": "function",
    "inputs": [
      {
        "name": "account",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getBlockBasefee",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getBlockNumber",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getBlockTimestamp",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getChainId",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "manager",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "multicall",
    "type": "function",
    "inputs": [
      {
        "name": "data",
        "type": "bytes[]",
        "internalType": "bytes[]"
      }
    ],
    "outputs": [
      {
        "name": "returndata",
        "type": "bytes[]",
        "internalType": "bytes[]"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "name": "oevProxyToBalance",
    "type": "function",
    "inputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "oevProxyToIdToDataFeed",
    "type": "function",
    "inputs": [
      {
        "name": "proxy",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "dataFeedId",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "outputs": [
      {
        "name": "value",
        "type": "int224",
        "internalType": "int224"
      },
      {
        "name": "timestamp",
        "type": "uint32",
        "internalType": "uint32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "readDataFeedWithDapiNameHash",
    "type": "function",
    "inputs": [
      {
        "name": "dapiNameHash",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "outputs": [
      {
        "name": "value",
        "type": "int224",
        "internalType": "int224"
      },
      {
        "name": "timestamp",
        "type": "uint32",
        "internalType": "uint32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "readDataFeedWithDapiNameHashAsOevProxy",
    "type": "function",
    "inputs": [
      {
        "name": "dapiNameHash",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "outputs": [
      {
        "name": "value",
        "type": "int224",
        "internalType": "int224"
      },
      {
        "name": "timestamp",
        "type": "uint32",
        "internalType": "uint32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "readDataFeedWithId",
    "type": "function",
    "inputs": [
      {
        "name": "dataFeedId",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "outputs": [
      {
        "name": "value",
        "type": "int224",
        "internalType": "int224"
      },
      {
        "name": "timestamp",
        "type": "uint32",
        "internalType": "uint32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "readDataFeedWithIdAsOevProxy",
    "type": "function",
    "inputs": [
      {
        "name": "dataFeedId",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "outputs": [
      {
        "name": "value",
        "type": "int224",
        "internalType": "int224"
      },
      {
        "name": "timestamp",
        "type": "uint32",
        "internalType": "uint32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "setDapiName",
    "type": "function",
    "inputs": [
      {
        "name": "dapiName",
        "type": "bytes32",
        "internalType": "bytes32"
      },
      {
        "name": "dataFeedId",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "tryMulticall",
    "type": "function",
    "inputs": [
      {
        "name": "data",
        "type": "bytes[]",
        "internalType": "bytes[]"
      }
    ],
    "outputs": [
      {
        "name": "successes",
        "type": "bool[]",
        "internalType": "bool[]"
      },
      {
        "name": "returndata",
        "type": "bytes[]",
        "internalType": "bytes[]"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "name": "updateBeaconSetWithBeacons",
    "type": "function",
    "inputs": [
      {
        "name": "beaconIds",
        "type": "bytes32[]",
        "internalType": "bytes32[]"
      }
    ],
    "outputs": [
      {
        "name": "beaconSetId",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "name": "updateBeaconWithSignedData",
    "type": "function",
    "inputs": [
      {
        "name": "airnode",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "templateId",
        "type": "bytes32",
        "internalType": "bytes32"
      },
      {
        "name": "timestamp",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "data",
        "type": "bytes",
        "internalType": "bytes"
      },
      {
        "name": "signature",
        "type": "bytes",
        "internalType": "bytes"
      }
    ],
    "outputs": [
      {
        "name": "beaconId",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "name": "updateOevProxyDataFeedWithSignedData",
    "type": "function",
    "inputs": [
      {
        "name": "oevProxy",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "dataFeedId",
        "type": "bytes32",
        "internalType": "bytes32"
      },
      {
        "name": "updateId",
        "type": "bytes32",
        "internalType": "bytes32"
      },
      {
        "name": "timestamp",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "data",
        "type": "bytes",
        "internalType": "bytes"
      },
      {
        "name": "packedOevUpdateSignatures",
        "type": "bytes[]",
        "internalType": "bytes[]"
      }
    ],
    "outputs": [],
    "stateMutability": "payable"
  },
  {
    "name": "withdraw",
    "type": "function",
    "inputs": [
      {
        "name": "oevProxy",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  }
]