ETH Price: $2,126.65 (+4.32%)

Transaction Decoder

Block:
23549877 at Oct-10-2025 09:01:35 PM +UTC
Transaction Fee:
0.00060514964784584 ETH $1.29
Gas Used:
53,660 Gas / 11.277481324 Gwei

Account State Difference:

  Address   Before After State Difference Code
0xb976d012...9264466D0
8.620147151290502284 Eth
Nonce: 154333
8.619542001642656444 Eth
Nonce: 154334
0.00060514964784584
(BuilderNet)
140.791324803514929243 Eth140.791807743514929243 Eth0.00048294

Execution Trace

AuthorizedForwarder.forward( to=0xc240796f93C5659708C5d14D90563e297314C532, data=0xB1DC65A40001599F75291A0EECFC0179A819A63A6ADE264BF7D82F02B9F10C6368DC1D6B000000000000000000000000000000000000000000000000000000000168AF064BCF3BFA32F61121DF0FD28B6CD29EFEEC00B8CB7F35197B081C3C85F8C33FFB00000000000000000000000000000000000000000000000000000000000000E000000000000000000000000000000000000000000000000000000000000003A00000000000000000000000000000000000000000000000000000000000000480010000010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002A00000000000000000000000000000000000000000000000000000000068E973D002040F0C0506010D08070A0B0903000E00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000A82EEEBB26BA410230000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000380F64A00000000000000000000000000000000000000000000000000000000038308580000000000000000000000000000000000000000000000000000000003837E5F000000000000000000000000000000000000000000000000000000000383C3D800000000000000000000000000000000000000000000000000000000038406E100000000000000000000000000000000000000000000000000000000038406E100000000000000000000000000000000000000000000000000000000038419C80000000000000000000000000000000000000000000000000000000003841AD50000000000000000000000000000000000000000000000000000000003841AD50000000000000000000000000000000000000000000000000000000003847210000000000000000000000000000000000000000000000000000000000384721000000000000000000000000000000000000000000000000000000000038472D700000000000000000000000000000000000000000000000000000000038472D700000000000000000000000000000000000000000000000000000000038472D700000000000000000000000000000000000000000000000000000000038472D700000000000000000000000000000000000000000000000000000000038B97C000000000000000000000000000000000000000000000000000000000000000061E4A29AC227CFC4DD22693A316B34EAD10A129D2823489ACAE62313753382F373205C04D8A65DD7339B0186E52747AD2CFE0F6487D585332320CB8B161CF3B14B7FC86BB8399DD4EE0A6E916E167C1CA15CAFC7D3E9F4088A86FB4885B08D110BCF0DF9B0835CCD4BFB459A22266ED903F9DD6C09657B253C4E2535717EC0D5F178D977601298B17AB99921D8BAE60F3BCCC1585841BDFD60F1D7C47F120377025BA9553F47BCDAC2D9161BA1925CD5062C0427711B585CB099BB1D1DE65B89A00000000000000000000000000000000000000000000000000000000000000066AC7ED2DAB9B20145BDA382F6215EC0416FDFDE3FC8200FB5FB75C193AE57C1D75B56D198C767002D32C19BF1B05BBE470D07677258E162A09EC0EF04F65C69D5BBC7108795F2D8E1826E24F81380C0ECF646B2661E6D6A4F904CB459DE039A67FACAB92B5597766AEA0BD142EBE217089D8347BE75C284F1264FCD3241BE68605CF1B10403BC60E32A3A2A0F8F7BE48E6BBF11B98DF66A3E803DDF94587E8397F7C0AF063084937A72B899CE4AFD35B18DBE679A4A110157A6E500F09E4611C )
  • AccessControlledOCR2Aggregator.transmit( )
    File 1 of 2: AuthorizedForwarder
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
    pragma solidity ^0.8.1;
    /**
     * @dev Collection of functions related to the address type
     */
    library Address {
        /**
         * @dev Returns true if `account` is a contract.
         *
         * [IMPORTANT]
         * ====
         * It is unsafe to assume that an address for which this function returns
         * false is an externally-owned account (EOA) and not a contract.
         *
         * Among others, `isContract` will return false for the following
         * types of addresses:
         *
         *  - an externally-owned account
         *  - a contract in construction
         *  - an address where a contract will be created
         *  - an address where a contract lived, but was destroyed
         *
         * Furthermore, `isContract` will also return true if the target contract within
         * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
         * which only has an effect at the end of a transaction.
         * ====
         *
         * [IMPORTANT]
         * ====
         * You shouldn't rely on `isContract` to protect against flash loan attacks!
         *
         * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
         * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
         * constructor.
         * ====
         */
        function isContract(address account) internal view returns (bool) {
            // This method relies on extcodesize/address.code.length, which returns 0
            // for contracts in construction, since the code is only stored at the end
            // of the constructor execution.
            return account.code.length > 0;
        }
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, "Address: insufficient balance");
            (bool success, ) = recipient.call{value: amount}("");
            require(success, "Address: unable to send value, recipient may have reverted");
        }
        /**
         * @dev Performs a Solidity function call using a low level `call`. A
         * plain `call` is an unsafe replacement for a function call: use this
         * function instead.
         *
         * If `target` reverts with a revert reason, it is bubbled up by this
         * function (like regular Solidity function calls).
         *
         * Returns the raw returned data. To convert to the expected return value,
         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
         *
         * Requirements:
         *
         * - `target` must be a contract.
         * - calling `target` with `data` must not revert.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
            return functionCallWithValue(target, data, 0, "Address: low-level call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
         * `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal returns (bytes memory) {
            return functionCallWithValue(target, data, 0, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but also transferring `value` wei to `target`.
         *
         * Requirements:
         *
         * - the calling contract must have an ETH balance of at least `value`.
         * - the called Solidity function must be `payable`.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
        }
        /**
         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
         * with `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(
            address target,
            bytes memory data,
            uint256 value,
            string memory errorMessage
        ) internal returns (bytes memory) {
            require(address(this).balance >= value, "Address: insufficient balance for call");
            (bool success, bytes memory returndata) = target.call{value: value}(data);
            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
            return functionStaticCall(target, data, "Address: low-level static call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal view returns (bytes memory) {
            (bool success, bytes memory returndata) = target.staticcall(data);
            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a delegate call.
         *
         * _Available since v3.4._
         */
        function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
            return functionDelegateCall(target, data, "Address: low-level delegate call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a delegate call.
         *
         * _Available since v3.4._
         */
        function functionDelegateCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal returns (bytes memory) {
            (bool success, bytes memory returndata) = target.delegatecall(data);
            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
        }
        /**
         * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
         * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
         *
         * _Available since v4.8._
         */
        function verifyCallResultFromTarget(
            address target,
            bool success,
            bytes memory returndata,
            string memory errorMessage
        ) internal view returns (bytes memory) {
            if (success) {
                if (returndata.length == 0) {
                    // only check isContract if the call was successful and the return data is empty
                    // otherwise we already know that it was a contract
                    require(isContract(target), "Address: call to non-contract");
                }
                return returndata;
            } else {
                _revert(returndata, errorMessage);
            }
        }
        /**
         * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
         * revert reason or using the provided one.
         *
         * _Available since v4.3._
         */
        function verifyCallResult(
            bool success,
            bytes memory returndata,
            string memory errorMessage
        ) internal pure returns (bytes memory) {
            if (success) {
                return returndata;
            } else {
                _revert(returndata, errorMessage);
            }
        }
        function _revert(bytes memory returndata, string memory errorMessage) private pure {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.19;
    import {ConfirmedOwnerWithProposal} from "../shared/access/ConfirmedOwnerWithProposal.sol";
    import {AuthorizedReceiver} from "./AuthorizedReceiver.sol";
    import {Address} from "@openzeppelin/contracts/utils/Address.sol";
    // solhint-disable gas-custom-errors
    contract AuthorizedForwarder is ConfirmedOwnerWithProposal, AuthorizedReceiver {
      using Address for address;
      // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i
      address public immutable linkToken;
      event OwnershipTransferRequestedWithMessage(address indexed from, address indexed to, bytes message);
      constructor(
        address link,
        address owner,
        address recipient,
        bytes memory message
      ) ConfirmedOwnerWithProposal(owner, recipient) {
        require(link != address(0), "Link token cannot be a zero address");
        linkToken = link;
        if (recipient != address(0)) {
          emit OwnershipTransferRequestedWithMessage(owner, recipient, message);
        }
      }
      string public constant typeAndVersion = "AuthorizedForwarder 1.1.0";
      // @notice Forward a call to another contract
      // @dev Only callable by an authorized sender
      // @param to address
      // @param data to forward
      function forward(address to, bytes calldata data) external validateAuthorizedSender {
        require(to != linkToken, "Cannot forward to Link token");
        _forward(to, data);
      }
      //  @notice Forward multiple calls to other contracts in a multicall style
      //  @dev Only callable by an authorized sender
      //  @param tos An array of addresses to forward the calls to
      //  @param datas An array of data to forward to each corresponding address
      function multiForward(address[] calldata tos, bytes[] calldata datas) external validateAuthorizedSender {
        require(tos.length == datas.length, "Arrays must have the same length");
        for (uint256 i = 0; i < tos.length; ++i) {
          address to = tos[i];
          require(to != linkToken, "Cannot forward to Link token");
          // Perform the forward operation
          _forward(to, datas[i]);
        }
      }
      // @notice Forward a call to another contract
      // @dev Only callable by the owner
      // @param to address
      // @param data to forward
      function ownerForward(address to, bytes calldata data) external onlyOwner {
        _forward(to, data);
      }
      // @notice Transfer ownership with instructions for recipient
      // @param to address proposed recipient of ownership
      // @param message instructions for recipient upon accepting ownership
      function transferOwnershipWithMessage(address to, bytes calldata message) external {
        transferOwnership(to);
        emit OwnershipTransferRequestedWithMessage(msg.sender, to, message);
      }
      // @notice concrete implementation of AuthorizedReceiver
      // @return bool of whether sender is authorized
      function _canSetAuthorizedSenders() internal view override returns (bool) {
        return owner() == msg.sender;
      }
      // @notice common forwarding functionality and validation
      function _forward(address to, bytes calldata data) private {
        require(to.isContract(), "Must forward to a contract");
        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory result) = to.call(data);
        if (!success) {
          if (result.length == 0) revert("Forwarded call reverted without reason");
          assembly {
            revert(add(32, result), mload(result))
          }
        }
      }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.19;
    import {IAuthorizedReceiver} from "./interfaces/IAuthorizedReceiver.sol";
    // solhint-disable gas-custom-errors
    abstract contract AuthorizedReceiver is IAuthorizedReceiver {
      mapping(address sender => bool authorized) private s_authorizedSenders;
      address[] private s_authorizedSenderList;
      event AuthorizedSendersChanged(address[] senders, address changedBy);
      // @notice Sets the fulfillment permission for a given node. Use `true` to allow, `false` to disallow.
      // @param senders The addresses of the authorized Chainlink node
      function setAuthorizedSenders(address[] calldata senders) external override validateAuthorizedSenderSetter {
        require(senders.length > 0, "Must have at least 1 sender");
        // Set previous authorized senders to false
        uint256 authorizedSendersLength = s_authorizedSenderList.length;
        for (uint256 i = 0; i < authorizedSendersLength; ++i) {
          s_authorizedSenders[s_authorizedSenderList[i]] = false;
        }
        // Set new to true
        for (uint256 i = 0; i < senders.length; ++i) {
          require(s_authorizedSenders[senders[i]] == false, "Must not have duplicate senders");
          s_authorizedSenders[senders[i]] = true;
        }
        // Replace list
        s_authorizedSenderList = senders;
        emit AuthorizedSendersChanged(senders, msg.sender);
      }
      // @notice Retrieve a list of authorized senders
      // @return array of addresses
      function getAuthorizedSenders() external view override returns (address[] memory) {
        return s_authorizedSenderList;
      }
      // @notice Use this to check if a node is authorized for fulfilling requests
      // @param sender The address of the Chainlink node
      // @return The authorization status of the node
      function isAuthorizedSender(address sender) public view override returns (bool) {
        return s_authorizedSenders[sender];
      }
      // @notice customizable guard of who can update the authorized sender list
      // @return bool whether sender can update authorized sender list
      function _canSetAuthorizedSenders() internal virtual returns (bool);
      // @notice validates the sender is an authorized sender
      function _validateIsAuthorizedSender() internal view {
        require(isAuthorizedSender(msg.sender), "Not authorized sender");
      }
      // @notice prevents non-authorized addresses from calling this method
      modifier validateAuthorizedSender() {
        _validateIsAuthorizedSender();
        _;
      }
      // @notice prevents non-authorized addresses from calling this method
      modifier validateAuthorizedSenderSetter() {
        require(_canSetAuthorizedSenders(), "Cannot set authorized senders");
        _;
      }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    interface IAuthorizedReceiver {
      function isAuthorizedSender(address sender) external view returns (bool);
      function getAuthorizedSenders() external returns (address[] memory);
      function setAuthorizedSenders(address[] calldata senders) external;
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import {IOwnable} from "../interfaces/IOwnable.sol";
    /// @title The ConfirmedOwner contract
    /// @notice A contract with helpers for basic contract ownership.
    contract ConfirmedOwnerWithProposal is IOwnable {
      address private s_owner;
      address private s_pendingOwner;
      event OwnershipTransferRequested(address indexed from, address indexed to);
      event OwnershipTransferred(address indexed from, address indexed to);
      constructor(address newOwner, address pendingOwner) {
        // solhint-disable-next-line gas-custom-errors
        require(newOwner != address(0), "Cannot set owner to zero");
        s_owner = newOwner;
        if (pendingOwner != address(0)) {
          _transferOwnership(pendingOwner);
        }
      }
      /// @notice Allows an owner to begin transferring ownership to a new address.
      function transferOwnership(address to) public override onlyOwner {
        _transferOwnership(to);
      }
      /// @notice Allows an ownership transfer to be completed by the recipient.
      function acceptOwnership() external override {
        // solhint-disable-next-line gas-custom-errors
        require(msg.sender == s_pendingOwner, "Must be proposed owner");
        address oldOwner = s_owner;
        s_owner = msg.sender;
        s_pendingOwner = address(0);
        emit OwnershipTransferred(oldOwner, msg.sender);
      }
      /// @notice Get the current owner
      function owner() public view override returns (address) {
        return s_owner;
      }
      /// @notice validate, transfer ownership, and emit relevant events
      function _transferOwnership(address to) private {
        // solhint-disable-next-line gas-custom-errors
        require(to != msg.sender, "Cannot transfer to self");
        s_pendingOwner = to;
        emit OwnershipTransferRequested(s_owner, to);
      }
      /// @notice validate access
      function _validateOwnership() internal view {
        // solhint-disable-next-line gas-custom-errors
        require(msg.sender == s_owner, "Only callable by owner");
      }
      /// @notice Reverts if called by anyone other than the contract owner.
      modifier onlyOwner() {
        _validateOwnership();
        _;
      }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    interface IOwnable {
      function owner() external returns (address);
      function transferOwnership(address recipient) external;
      function acceptOwnership() external;
    }
    

    File 2 of 2: AccessControlledOCR2Aggregator
    // SPDX-License-Identifier: MIT
    pragma solidity =0.8.19;
    import "./OCR2Aggregator.sol";
    import "./SimpleReadAccessController.sol";
    /**
     * @notice Wrapper of OCR2Aggregator which checks read access on Aggregator-interface methods
     */
    contract AccessControlledOCR2Aggregator is OCR2Aggregator, SimpleReadAccessController {
      constructor(
        LinkTokenInterface _link,
        int192 _minAnswer,
        int192 _maxAnswer,
        AccessControllerInterface _billingAccessController,
        AccessControllerInterface _requesterAccessController,
        uint8 _decimals,
        string memory description
      )
        OCR2Aggregator(
          _link,
          _minAnswer,
          _maxAnswer,
          _billingAccessController,
          _requesterAccessController,
          _decimals,
          description
        ) {
        }
      /*
       * Versioning
       */
      function typeAndVersion()
        external
        override
        pure
        virtual
        returns (string memory)
      {
        return "AccessControlledOCR2Aggregator 1.0.0";
      }
      /*
       * v2 Aggregator interface
       */
      /// @inheritdoc OCR2Aggregator
      function latestAnswer()
        public
        override
        view
        checkAccess()
        returns (int256)
      {
        return super.latestAnswer();
      }
      /// @inheritdoc OCR2Aggregator
      function latestTimestamp()
        public
        override
        view
        checkAccess()
        returns (uint256)
      {
        return super.latestTimestamp();
      }
      /// @inheritdoc OCR2Aggregator
      function latestRound()
        public
        override
        view
        checkAccess()
        returns (uint256)
      {
        return super.latestRound();
      }
      /// @inheritdoc OCR2Aggregator
      function getAnswer(uint256 _roundId)
        public
        override
        view
        checkAccess()
        returns (int256)
      {
        return super.getAnswer(_roundId);
      }
      /// @inheritdoc OCR2Aggregator
      function getTimestamp(uint256 _roundId)
        public
        override
        view
        checkAccess()
        returns (uint256)
      {
        return super.getTimestamp(_roundId);
      }
      /*
       * v3 Aggregator interface
       */
      /// @inheritdoc OCR2Aggregator
      function description()
        public
        override
        view
        checkAccess()
        returns (string memory)
      {
        return super.description();
      }
      /// @inheritdoc OCR2Aggregator
      function getRoundData(uint80 _roundId)
        public
        override
        view
        checkAccess()
        returns (
          uint80 roundId,
          int256 answer,
          uint256 startedAt,
          uint256 updatedAt,
          uint80 answeredInRound
        )
      {
        return super.getRoundData(_roundId);
      }
      /// @inheritdoc OCR2Aggregator
      function latestRoundData()
        public
        override
        view
        checkAccess()
        returns (
          uint80 roundId,
          int256 answer,
          uint256 startedAt,
          uint256 updatedAt,
          uint80 answeredInRound
        )
      {
        return super.latestRoundData();
      }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "./ConfirmedOwnerWithProposal.sol";
    /**
     * @title The ConfirmedOwner contract
     * @notice A contract with helpers for basic contract ownership.
     */
    contract ConfirmedOwner is ConfirmedOwnerWithProposal {
      constructor(
        address newOwner
      )
        ConfirmedOwnerWithProposal(
          newOwner,
          address(0)
        )
      {
      }
    }// SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "./interfaces/OwnableInterface.sol";
    /**
     * @title The ConfirmedOwner contract
     * @notice A contract with helpers for basic contract ownership.
     */
    contract ConfirmedOwnerWithProposal is OwnableInterface {
      address private s_owner;
      address private s_pendingOwner;
      event OwnershipTransferRequested(
        address indexed from,
        address indexed to
      );
      event OwnershipTransferred(
        address indexed from,
        address indexed to
      );
      constructor(
        address newOwner,
        address pendingOwner
      ) {
        require(newOwner != address(0), "Cannot set owner to zero");
        s_owner = newOwner;
        if (pendingOwner != address(0)) {
          _transferOwnership(pendingOwner);
        }
      }
      /**
       * @notice Allows an owner to begin transferring ownership to a new address,
       * pending.
       */
      function transferOwnership(
        address to
      )
        public
        override
        onlyOwner()
      {
        _transferOwnership(to);
      }
      /**
       * @notice Allows an ownership transfer to be completed by the recipient.
       */
      function acceptOwnership()
        external
        override
      {
        require(msg.sender == s_pendingOwner, "Must be proposed owner");
        address oldOwner = s_owner;
        s_owner = msg.sender;
        s_pendingOwner = address(0);
        emit OwnershipTransferred(oldOwner, msg.sender);
      }
      /**
       * @notice Get the current owner
       */
      function owner()
        public
        view
        override
        returns (
          address
        )
      {
        return s_owner;
      }
      /**
       * @notice validate, transfer ownership, and emit relevant events
       */
      function _transferOwnership(
        address to
      )
        private
      {
        require(to != msg.sender, "Cannot transfer to self");
        s_pendingOwner = to;
        emit OwnershipTransferRequested(s_owner, to);
      }
      /**
       * @notice validate access
       */
      function _validateOwnership()
        internal
        view
      {
        require(msg.sender == s_owner, "Only callable by owner");
      }
      /**
       * @notice Reverts if called by anyone other than the contract owner.
       */
      modifier onlyOwner() {
        _validateOwnership();
        _;
      }
    }// SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "./interfaces/TypeAndVersionInterface.sol";
    abstract contract OCR2Abstract is TypeAndVersionInterface {
      // Maximum number of oracles the offchain reporting protocol is designed for
      uint256 constant internal maxNumOracles = 31;
      /**
       * @notice triggers a new run of the offchain reporting protocol
       * @param previousConfigBlockNumber block in which the previous config was set, to simplify historic analysis
       * @param configDigest configDigest of this configuration
       * @param configCount ordinal number of this config setting among all config settings over the life of this contract
       * @param signers ith element is address ith oracle uses to sign a report
       * @param transmitters ith element is address ith oracle uses to transmit a report via the transmit method
       * @param f maximum number of faulty/dishonest oracles the protocol can tolerate while still working correctly
       * @param onchainConfig serialized configuration used by the contract (and possibly oracles)
       * @param offchainConfigVersion version of the serialization format used for "offchainConfig" parameter
       * @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract
       */
      event ConfigSet(
        uint32 previousConfigBlockNumber,
        bytes32 configDigest,
        uint64 configCount,
        address[] signers,
        address[] transmitters,
        uint8 f,
        bytes onchainConfig,
        uint64 offchainConfigVersion,
        bytes offchainConfig
      );
      /**
       * @notice sets offchain reporting protocol configuration incl. participating oracles
       * @param signers addresses with which oracles sign the reports
       * @param transmitters addresses oracles use to transmit the reports
       * @param f number of faulty oracles the system can tolerate
       * @param onchainConfig serialized configuration used by the contract (and possibly oracles)
       * @param offchainConfigVersion version number for offchainEncoding schema
       * @param offchainConfig serialized configuration used by the oracles exclusively and only passed through the contract
       */
      function setConfig(
        address[] memory signers,
        address[] memory transmitters,
        uint8 f,
        bytes memory onchainConfig,
        uint64 offchainConfigVersion,
        bytes memory offchainConfig
      )
        external
        virtual;
      /**
       * @notice information about current offchain reporting protocol configuration
       * @return configCount ordinal number of current config, out of all configs applied to this contract so far
       * @return blockNumber block at which this config was set
       * @return configDigest domain-separation tag for current config (see _configDigestFromConfigData)
       */
      function latestConfigDetails()
        external
        view
        virtual
        returns (
          uint32 configCount,
          uint32 blockNumber,
          bytes32 configDigest
        );
      function _configDigestFromConfigData(
        uint256 chainId,
        address contractAddress,
        uint64 configCount,
        address[] memory signers,
        address[] memory transmitters,
        uint8 f,
        bytes memory onchainConfig,
        uint64 offchainConfigVersion,
        bytes memory offchainConfig
      )
        internal
        pure
        returns (bytes32)
      {
        uint256 h = uint256(keccak256(abi.encode(chainId, contractAddress, configCount,
          signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig
        )));
        uint256 prefixMask = type(uint256).max << (256-16); // 0xFFFF00..00
        uint256 prefix = 0x0001 << (256-16); // 0x000100..00
        return bytes32((prefix & prefixMask) | (h & ~prefixMask));
      }
      /**
      * @notice optionally emitted to indicate the latest configDigest and epoch for
         which a report was successfully transmitted. Alternatively, the contract may
         use latestConfigDigestAndEpoch with scanLogs set to false.
      */
      event Transmitted(
        bytes32 configDigest,
        uint32 epoch
      );
      /**
       * @notice optionally returns the latest configDigest and epoch for which a
         report was successfully transmitted. Alternatively, the contract may return
         scanLogs set to true and use Transmitted events to provide this information
         to offchain watchers.
       * @return scanLogs indicates whether to rely on the configDigest and epoch
         returned or whether to scan logs for the Transmitted event instead.
       * @return configDigest
       * @return epoch
       */
      function latestConfigDigestAndEpoch()
        external
        view
        virtual
        returns(
          bool scanLogs,
          bytes32 configDigest,
          uint32 epoch
        );
      /**
       * @notice transmit is called to post a new report to the contract
       * @param reportContext serialized report context containing configDigest, epoch, round, extraHash
       * @param report serialized report, which the signatures are signing
       * @param rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries
       * @param ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries
       * @param rawVs ith element is the the V component of the ith signature
       */
      function transmit(
        // NOTE: If these parameters are changed, expectedMsgDataLength and/or
        // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly
        bytes32[3] calldata reportContext,
        bytes calldata report,
        bytes32[] calldata rs, bytes32[] calldata ss, bytes32 rawVs // signatures
      )
        external
        virtual;
    }
    // SPDX-License-Identifier: MIT
    pragma solidity =0.8.19;
    import "./interfaces/AccessControllerInterface.sol";
    import "./interfaces/AggregatorV2V3Interface.sol";
    import "./interfaces/AggregatorValidatorInterface.sol";
    import "./interfaces/LinkTokenInterface.sol";
    import "./interfaces/TypeAndVersionInterface.sol";
    import "./OCR2Abstract.sol";
    import "./OwnerIsCreator.sol";
    /**
     * @notice OCR2Aggregator for numerical data with billing support.
     * @dev
     * If you read or change this, be sure to read or adjust the comments. They
     * track the units of the values under consideration, and are crucial to
     * the readability of the operations it specifies.
     * @notice
     * Billing Trust Model:
     * Nothing in this contract prevents a billing admin from setting insane
     * values for the billing parameters in setBilling. Oracles
     * participating in this contract should regularly check that the
     * parameters make sense. Similarly, the outstanding obligations of this
     * contract to the oracles can exceed the funds held by the contract.
     * Oracles participating in this contract should regularly check that it
     * holds sufficient funds and stop interacting with it if funding runs
     * out.
     * This still leaves oracles with some risk due to TOCTOU issues.
     * However, since the sums involved are pretty small (Ethereum
     * transactions aren't that expensive in the end) and an oracle would
     * likely stop participating in a contract it repeatedly lost money on,
     * this risk is deemed acceptable. Oracles should also regularly
     * withdraw any funds in the contract to prevent issues where the
     * contract becomes underfunded at a later time, and different oracles
     * are competing for the left-over funds.
     * Finally, note that any change to the set of oracles or to the billing
     * parameters will trigger payout of all oracles first (using the old
     * parameters), a billing admin cannot take away funds that are already
     * marked for payment.
     */
    contract OCR2Aggregator is OCR2Abstract, OwnerIsCreator, AggregatorV2V3Interface {
      // This contract is divided into sections. Each section defines a set of
      // variables, events, and functions that belong together.
      /***************************************************************************
       * Section: Variables used in multiple other sections
       **************************************************************************/
      struct Transmitter {
        bool active;
        // Index of oracle in s_signersList/s_transmittersList
        uint8 index;
        // juels-denominated payment for transmitters, covering gas costs incurred
        // by the transmitter plus additional rewards. The entire LINK supply (1e9
        // LINK = 1e27 Juels) will always fit into a uint96.
        uint96 paymentJuels;
      }
      mapping (address /* transmitter address */ => Transmitter) internal s_transmitters;
      struct Signer {
        bool active;
        // Index of oracle in s_signersList/s_transmittersList
        uint8 index;
      }
      mapping (address /* signer address */ => Signer) internal s_signers;
      // s_signersList contains the signing address of each oracle
      address[] internal s_signersList;
      // s_transmittersList contains the transmission address of each oracle,
      // i.e. the address the oracle actually sends transactions to the contract from
      address[] internal s_transmittersList;
      // We assume that all oracles contribute observations to all rounds. this
      // variable tracks (per-oracle) from what round an oracle should be rewarded,
      // i.e. the oracle gets (latestAggregatorRoundId -
      // rewardFromAggregatorRoundId) * reward
      uint32[maxNumOracles] internal s_rewardFromAggregatorRoundId;
      bytes32 s_latestConfigDigest;
      // Storing these fields used on the hot path in a HotVars variable reduces the
      // retrieval of all of them to a single SLOAD.
      struct HotVars {
        // maximum number of faulty oracles
        uint8 f;
        // epoch and round from OCR protocol.
        // 32 most sig bits for epoch, 8 least sig bits for round
        uint40 latestEpochAndRound;
        // Chainlink Aggregators expose a roundId to consumers. The offchain reporting
        // protocol does not use this id anywhere. We increment it whenever a new
        // transmission is made to provide callers with contiguous ids for successive
        // reports.
        uint32 latestAggregatorRoundId;
        // Highest compensated gas price, in gwei uints
        uint32 maximumGasPriceGwei;
        // If gas price is less (in gwei units), transmitter gets half the savings
        uint32 reasonableGasPriceGwei;
        // Fixed LINK reward for each observer
        uint32 observationPaymentGjuels;
        // Fixed reward for transmitter
        uint32 transmissionPaymentGjuels;
        // Overhead incurred by accounting logic
        uint24 accountingGas;
      }
      HotVars internal s_hotVars;
      // Transmission records the median answer from the transmit transaction at
      // time timestamp
      struct Transmission {
        int192 answer; // 192 bits ought to be enough for anyone
        uint32 observationsTimestamp; // when were observations made offchain
        uint32 transmissionTimestamp; // when was report received onchain
      }
      mapping(uint32 /* aggregator round ID */ => Transmission) internal s_transmissions;
      // Lowest answer the system is allowed to report in response to transmissions
      int192 immutable public minAnswer;
      // Highest answer the system is allowed to report in response to transmissions
      int192 immutable public maxAnswer;
      /***************************************************************************
       * Section: Constructor
       **************************************************************************/
      /**
       * @param link address of the LINK contract
       * @param minAnswer_ lowest answer the median of a report is allowed to be
       * @param maxAnswer_ highest answer the median of a report is allowed to be
       * @param requesterAccessController access controller for requesting new rounds
       * @param decimals_ answers are stored in fixed-point format, with this many digits of precision
       * @param description_ short human-readable description of observable this contract's answers pertain to
       */
      constructor(
        LinkTokenInterface link,
        int192 minAnswer_,
        int192 maxAnswer_,
        AccessControllerInterface billingAccessController,
        AccessControllerInterface requesterAccessController,
        uint8 decimals_,
        string memory description_
      ) {
        s_linkToken = link;
        emit LinkTokenSet(LinkTokenInterface(address(0)), link);
        _setBillingAccessController(billingAccessController);
        decimals = decimals_;
        s_description = description_;
        setRequesterAccessController(requesterAccessController);
        setValidatorConfig(AggregatorValidatorInterface(address(0x0)), 0);
        minAnswer = minAnswer_;
        maxAnswer = maxAnswer_;
      }
      /***************************************************************************
       * Section: OCR2Abstract Configuration
       **************************************************************************/
      // incremented each time a new config is posted. This count is incorporated
      // into the config digest to prevent replay attacks.
      uint32 internal s_configCount;
      // makes it easier for offchain systems to extract config from logs
      uint32 internal s_latestConfigBlockNumber;
      // left as a function so this check can be disabled in derived contracts
      function _requirePositiveF (
        uint256 f
      )
        internal
        pure
        virtual
      {
        require(0 < f, "f must be positive");
      }
      struct SetConfigArgs {
        address[] signers;
        address[] transmitters;
        uint8 f;
        bytes onchainConfig;
        uint64 offchainConfigVersion;
        bytes offchainConfig;
      }
      /// @inheritdoc OCR2Abstract
      function setConfig(
        address[] memory signers,
        address[] memory transmitters,
        uint8 f,
        bytes memory onchainConfig,
        uint64 offchainConfigVersion,
        bytes memory offchainConfig
      )
        external
        override
        onlyOwner()
      {
        require(signers.length <= maxNumOracles, "too many oracles");
        require(signers.length == transmitters.length, "oracle length mismatch");
        require(3*f < signers.length, "faulty-oracle f too high");
        _requirePositiveF(f);
        require(keccak256(onchainConfig) == keccak256(abi.encodePacked(uint8(1) /*version*/, minAnswer, maxAnswer)), "invalid onchainConfig");
        SetConfigArgs memory args = SetConfigArgs({
          signers: signers,
          transmitters: transmitters,
          f: f,
          onchainConfig: onchainConfig,
          offchainConfigVersion: offchainConfigVersion,
          offchainConfig: offchainConfig
        });
        s_hotVars.latestEpochAndRound = 0;
        _payOracles();
        // remove any old signer/transmitter addresses
        uint256 oldLength = s_signersList.length;
        for (uint256 i = 0; i < oldLength; i++) {
          address signer = s_signersList[i];
          address transmitter = s_transmittersList[i];
          delete s_signers[signer];
          delete s_transmitters[transmitter];
        }
        delete s_signersList;
        delete s_transmittersList;
        // add new signer/transmitter addresses
        for (uint i = 0; i < args.signers.length; i++) {
          require(
            !s_signers[args.signers[i]].active,
            "repeated signer address"
          );
          s_signers[args.signers[i]] = Signer({
            active: true,
            index: uint8(i)
          });
          require(
            !s_transmitters[args.transmitters[i]].active,
            "repeated transmitter address"
          );
          s_transmitters[args.transmitters[i]] = Transmitter({
            active: true,
            index: uint8(i),
            paymentJuels: 0
          });
        }
        s_signersList = args.signers;
        s_transmittersList = args.transmitters;
        s_hotVars.f = args.f;
        uint32 previousConfigBlockNumber = s_latestConfigBlockNumber;
        s_latestConfigBlockNumber = uint32(block.number);
        s_configCount += 1;
        s_latestConfigDigest = _configDigestFromConfigData(
          block.chainid,
          address(this),
          s_configCount,
          args.signers,
          args.transmitters,
          args.f,
          args.onchainConfig,
          args.offchainConfigVersion,
          args.offchainConfig
        );
        emit ConfigSet(
          previousConfigBlockNumber,
          s_latestConfigDigest,
          s_configCount,
          args.signers,
          args.transmitters,
          args.f,
          args.onchainConfig,
          args.offchainConfigVersion,
          args.offchainConfig
        );
        uint32 latestAggregatorRoundId = s_hotVars.latestAggregatorRoundId;
        for (uint256 i = 0; i < args.signers.length; i++) {
          s_rewardFromAggregatorRoundId[i] = latestAggregatorRoundId;
        }
      }
      /// @inheritdoc OCR2Abstract
      function latestConfigDetails()
        external
        override
        view
        returns (
          uint32 configCount,
          uint32 blockNumber,
          bytes32 configDigest
        )
      {
        return (s_configCount, s_latestConfigBlockNumber, s_latestConfigDigest);
      }
      /**
       * @return list of addresses permitted to transmit reports to this contract
       * @dev The list will match the order used to specify the transmitter during setConfig
       */
      function getTransmitters()
        external
        view
        returns(address[] memory)
      {
        return s_transmittersList;
      }
      /***************************************************************************
       * Section: Onchain Validation
       **************************************************************************/
      // Configuration for validator
      struct ValidatorConfig {
        AggregatorValidatorInterface validator;
        uint32 gasLimit;
      }
      ValidatorConfig private s_validatorConfig;
      /**
       * @notice indicates that the validator configuration has been set
       * @param previousValidator previous validator contract
       * @param previousGasLimit previous gas limit for validate calls
       * @param currentValidator current validator contract
       * @param currentGasLimit current gas limit for validate calls
       */
      event ValidatorConfigSet(
        AggregatorValidatorInterface indexed previousValidator,
        uint32 previousGasLimit,
        AggregatorValidatorInterface indexed currentValidator,
        uint32 currentGasLimit
      );
      /**
       * @notice validator configuration
       * @return validator validator contract
       * @return gasLimit gas limit for validate calls
       */
      function getValidatorConfig()
        external
        view
        returns (AggregatorValidatorInterface validator, uint32 gasLimit)
      {
        ValidatorConfig memory vc = s_validatorConfig;
        return (vc.validator, vc.gasLimit);
      }
      /**
       * @notice sets validator configuration
       * @dev set newValidator to 0x0 to disable validate calls
       * @param newValidator address of the new validator contract
       * @param newGasLimit new gas limit for validate calls
       */
      function setValidatorConfig(
        AggregatorValidatorInterface newValidator,
        uint32 newGasLimit
      )
        public
        onlyOwner()
      {
        ValidatorConfig memory previous = s_validatorConfig;
        if (previous.validator != newValidator || previous.gasLimit != newGasLimit) {
          s_validatorConfig = ValidatorConfig({
            validator: newValidator,
            gasLimit: newGasLimit
          });
          emit ValidatorConfigSet(previous.validator, previous.gasLimit, newValidator, newGasLimit);
        }
      }
      function _validateAnswer(
        uint32 aggregatorRoundId,
        int256 answer
      )
        private
      {
        ValidatorConfig memory vc = s_validatorConfig;
        if (address(vc.validator) == address(0)) {
          return;
        }
        uint32 prevAggregatorRoundId = aggregatorRoundId - 1;
        int256 prevAggregatorRoundAnswer = s_transmissions[prevAggregatorRoundId].answer;
        require(
          _callWithExactGasEvenIfTargetIsNoContract(
            vc.gasLimit,
            address(vc.validator),
            abi.encodeWithSignature(
              "validate(uint256,int256,uint256,int256)",
              uint256(prevAggregatorRoundId),
              prevAggregatorRoundAnswer,
              uint256(aggregatorRoundId),
              answer
            )
          ),
          "insufficient gas"
        );
      }
      uint256 private constant CALL_WITH_EXACT_GAS_CUSHION = 5_000;
      /**
       * @dev calls target address with exactly gasAmount gas and data as calldata
       * or reverts if at least gasAmount gas is not available.
       */
      function _callWithExactGasEvenIfTargetIsNoContract(
        uint256 gasAmount,
        address target,
        bytes memory data
      )
        private
        returns (bool sufficientGas)
      {
        // solhint-disable-next-line no-inline-assembly
        assembly {
          let g := gas()
          // Compute g -= CALL_WITH_EXACT_GAS_CUSHION and check for underflow. We
          // need the cushion since the logic following the above call to gas also
          // costs gas which we cannot account for exactly. So cushion is a
          // conservative upper bound for the cost of this logic.
          if iszero(lt(g, CALL_WITH_EXACT_GAS_CUSHION)) {
            g := sub(g, CALL_WITH_EXACT_GAS_CUSHION)
            // If g - g//64 <= gasAmount, we don't have enough gas. (We subtract g//64
            // because of EIP-150.)
            if gt(sub(g, div(g, 64)), gasAmount) {
              // Call and ignore success/return data. Note that we did not check
              // whether a contract actually exists at the target address.
              pop(call(gasAmount, target, 0, add(data, 0x20), mload(data), 0, 0))
              sufficientGas := true
            }
          }
        }
      }
      /***************************************************************************
       * Section: RequestNewRound
       **************************************************************************/
      AccessControllerInterface internal s_requesterAccessController;
      /**
       * @notice emitted when a new requester access controller contract is set
       * @param old the address prior to the current setting
       * @param current the address of the new access controller contract
       */
      event RequesterAccessControllerSet(AccessControllerInterface old, AccessControllerInterface current);
      /**
       * @notice emitted to immediately request a new round
       * @param requester the address of the requester
       * @param configDigest the latest transmission's configDigest
       * @param epoch the latest transmission's epoch
       * @param round the latest transmission's round
       */
      event RoundRequested(address indexed requester, bytes32 configDigest, uint32 epoch, uint8 round);
      /**
       * @notice address of the requester access controller contract
       * @return requester access controller address
       */
      function getRequesterAccessController()
        external
        view
        returns (AccessControllerInterface)
      {
        return s_requesterAccessController;
      }
      /**
       * @notice sets the requester access controller
       * @param requesterAccessController designates the address of the new requester access controller
       */
      function setRequesterAccessController(AccessControllerInterface requesterAccessController)
        public
        onlyOwner()
      {
        AccessControllerInterface oldController = s_requesterAccessController;
        if (requesterAccessController != oldController) {
          s_requesterAccessController = AccessControllerInterface(requesterAccessController);
          emit RequesterAccessControllerSet(oldController, requesterAccessController);
        }
      }
      /**
       * @notice immediately requests a new round
       * @return the aggregatorRoundId of the next round. Note: The report for this round may have been
       * transmitted (but not yet mined) *before* requestNewRound() was even called. There is *no*
       * guarantee of causality between the request and the report at aggregatorRoundId.
       */
      function requestNewRound() external returns (uint80) {
        require(msg.sender == owner() || s_requesterAccessController.hasAccess(msg.sender, msg.data),
          "Only owner&requester can call");
        uint40 latestEpochAndRound = s_hotVars.latestEpochAndRound;
        uint32 latestAggregatorRoundId = s_hotVars.latestAggregatorRoundId;
        emit RoundRequested(
          msg.sender,
          s_latestConfigDigest,
          uint32(latestEpochAndRound >> 8),
          uint8(latestEpochAndRound)
        );
        return latestAggregatorRoundId + 1;
      }
      /***************************************************************************
       * Section: Transmission
       **************************************************************************/
      /**
       * @notice indicates that a new report was transmitted
       * @param aggregatorRoundId the round to which this report was assigned
       * @param answer median of the observations attached to this report
       * @param transmitter address from which the report was transmitted
       * @param observationsTimestamp when were observations made offchain
       * @param observations observations transmitted with this report
       * @param observers i-th element is the oracle id of the oracle that made the i-th observation
       * @param juelsPerFeeCoin exchange rate between feeCoin (e.g. ETH on Ethereum) and LINK, denominated in juels
       * @param configDigest configDigest of transmission
       * @param epochAndRound least-significant byte is the OCR protocol round number, the other bytes give the big-endian OCR protocol epoch number
       */
      event NewTransmission(
        uint32 indexed aggregatorRoundId,
        int192 answer,
        address transmitter,
        uint32 observationsTimestamp,
        int192[] observations,
        bytes observers,
        int192 juelsPerFeeCoin,
        bytes32 configDigest,
        uint40 epochAndRound
      );
      // Used to relieve stack pressure in transmit
      struct Report {
        uint32 observationsTimestamp;
        bytes observers; // ith element is the index of the ith observer
        int192[] observations; // ith element is the ith observation
        int192 juelsPerFeeCoin;
      }
      // _decodeReport decodes a serialized report into a Report struct
      function _decodeReport(bytes memory rawReport)
        internal
        pure
        returns (
          Report memory
        )
      {
        uint32 observationsTimestamp;
        bytes32 rawObservers;
        int192[] memory observations;
        int192 juelsPerFeeCoin;
        (observationsTimestamp, rawObservers, observations, juelsPerFeeCoin) = abi.decode(rawReport, (uint32, bytes32, int192[], int192));
        _requireExpectedReportLength(rawReport, observations);
        uint256 numObservations = observations.length;
        bytes memory observers = abi.encodePacked(rawObservers);
        assembly {
          // we truncate observers from length 32 to the number of observations
          mstore(observers, numObservations)
        }
        return Report({
          observationsTimestamp: observationsTimestamp,
          observers: observers,
          observations: observations,
          juelsPerFeeCoin: juelsPerFeeCoin
        });
      }
      // The constant-length components of the msg.data sent to transmit.
      // See the "If we wanted to call sam" example on for example reasoning
      // https://solidity.readthedocs.io/en/v0.7.2/abi-spec.html
      uint256 private constant TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT =
        4 + // function selector
        32 * 3 + // 3 words containing reportContext
        32 + // word containing start location of abiencoded report value
        32 + // word containing start location of abiencoded rs value
        32 + // word containing start location of abiencoded ss value
        32 + // rawVs value
        32 + // word containing length of report
        32 + // word containing length rs
        32 + // word containing length of ss
        0; // placeholder
      // Make sure the calldata length matches the inputs. Otherwise, the
      // transmitter could append an arbitrarily long (up to gas-block limit)
      // string of 0 bytes, which we would reimburse at a rate of 16 gas/byte, but
      // which would only cost the transmitter 4 gas/byte.
      function _requireExpectedMsgDataLength(
        bytes calldata report,
        bytes32[] calldata rs,
        bytes32[] calldata ss
      )
        private
        pure
      {
        // calldata will never be big enough to make this overflow
        uint256 expected = TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT +
          report.length + // one byte per entry in report
          rs.length * 32 + // 32 bytes per entry in rs
          ss.length * 32 + // 32 bytes per entry in ss
          0; // placeholder
        require(msg.data.length == expected, "calldata length mismatch");
      }
      /// @inheritdoc OCR2Abstract
      function transmit(
        // reportContext consists of:
        // reportContext[0]: ConfigDigest
        // reportContext[1]: 27 byte padding, 4-byte epoch and 1-byte round
        // reportContext[2]: ExtraHash
        bytes32[3] calldata reportContext,
        bytes calldata report,
        // ECDSA signatures
        bytes32[] calldata rs,
        bytes32[] calldata ss,
        bytes32 rawVs
      )
        external
        override
      {
        // NOTE: If the arguments to this function are changed, _requireExpectedMsgDataLength and/or
        // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly
        uint256 initialGas = gasleft(); // This line must come first
        HotVars memory hotVars = s_hotVars;
        uint40 epochAndRound = uint40(uint256(reportContext[1]));
        require(hotVars.latestEpochAndRound < epochAndRound, "stale report");
        require(s_transmitters[msg.sender].active, "unauthorized transmitter");
        require(s_latestConfigDigest == reportContext[0], "configDigest mismatch");
        _requireExpectedMsgDataLength(report, rs, ss);
        require(rs.length == hotVars.f + 1, "wrong number of signatures");
        require(rs.length == ss.length, "signatures out of registration");
        // Verify signatures attached to report
        {
          bytes32 h = keccak256(abi.encode(keccak256(report), reportContext));
          // i-th byte counts number of sigs made by i-th signer
          uint256 signedCount = 0;
          Signer memory signer;
          for (uint i = 0; i < rs.length; i++) {
            address signerAddress = ecrecover(h, uint8(rawVs[i])+27, rs[i], ss[i]);
            signer = s_signers[signerAddress];
            require(signer.active, "signature error");
            unchecked{
              signedCount += 1 << (8 * signer.index);
            }
          }
          // The first byte of the mask can be 0, because we only ever have 31 oracles
          require(signedCount & 0x0001010101010101010101010101010101010101010101010101010101010101 == signedCount, "duplicate signer");
        }
        int192 juelsPerFeeCoin = _report(hotVars, reportContext[0], epochAndRound, report);
        _payTransmitter(hotVars, juelsPerFeeCoin, uint32(initialGas), msg.sender);
      }
      /**
       * @notice details about the most recent report
       * @return configDigest domain separation tag for the latest report
       * @return epoch epoch in which the latest report was generated
       * @return round OCR round in which the latest report was generated
       * @return latestAnswer_ median value from latest report
       * @return latestTimestamp_ when the latest report was transmitted
       */
      function latestTransmissionDetails()
        external
        view
        returns (
          bytes32 configDigest,
          uint32 epoch,
          uint8 round,
          int192 latestAnswer_,
          uint64 latestTimestamp_
        )
      {
        require(msg.sender == tx.origin, "Only callable by EOA");
        return (
          s_latestConfigDigest,
          uint32(s_hotVars.latestEpochAndRound >> 8),
          uint8(s_hotVars.latestEpochAndRound),
          s_transmissions[s_hotVars.latestAggregatorRoundId].answer,
          s_transmissions[s_hotVars.latestAggregatorRoundId].transmissionTimestamp
        );
      }
      /// @inheritdoc OCR2Abstract
      function latestConfigDigestAndEpoch()
        external
        override
        view
        virtual
        returns(
          bool scanLogs,
          bytes32 configDigest,
          uint32 epoch
        )
      {
        return (false, s_latestConfigDigest, uint32(s_hotVars.latestEpochAndRound >> 8));
      }
      function _requireExpectedReportLength(
        bytes memory report,
        int192[] memory observations
      )
        private
        pure
      {
        uint256 expected =
          32 + // observationsTimestamp
          32 + // rawObservers
          32 + // observations offset
          32 + // juelsPerFeeCoin
          32 + // observations length
          32 * observations.length + // observations payload
          0;
        require(report.length == expected, "report length mismatch");
      }
      function _report(
        HotVars memory hotVars,
        bytes32 configDigest,
        uint40 epochAndRound,
        bytes memory rawReport
      )
        internal
        returns (int192 juelsPerFeeCoin)
      {
        Report memory report = _decodeReport(rawReport);
        require(report.observations.length <= maxNumOracles, "num observations out of bounds");
        // Offchain logic ensures that a quorum of oracles is operating on a matching set of at least
        // 2f+1 observations. By assumption, up to f of those can be faulty, which includes being
        // malformed. Conversely, more than f observations have to be well-formed and sent on chain.
        require(hotVars.f < report.observations.length, "too few values to trust median");
        hotVars.latestEpochAndRound = epochAndRound;
        // get median, validate its range, store it in new aggregator round
        int192 median = report.observations[report.observations.length/2];
        require(minAnswer <= median && median <= maxAnswer, "median is out of min-max range");
        hotVars.latestAggregatorRoundId++;
        s_transmissions[hotVars.latestAggregatorRoundId] =
          Transmission({
            answer: median,
            observationsTimestamp: report.observationsTimestamp,
            transmissionTimestamp: uint32(block.timestamp)
          });
        // persist updates to hotVars
        s_hotVars = hotVars;
        emit NewTransmission(
          hotVars.latestAggregatorRoundId,
          median,
          msg.sender,
          report.observationsTimestamp,
          report.observations,
          report.observers,
          report.juelsPerFeeCoin,
          configDigest,
          epochAndRound
        );
        // Emit these for backwards compatibility with offchain consumers
        // that only support legacy events
        emit NewRound(
          hotVars.latestAggregatorRoundId,
          address(0x0), // use zero address since we don't have anybody "starting" the round here
          report.observationsTimestamp
        );
        emit AnswerUpdated(
          median,
          hotVars.latestAggregatorRoundId,
          block.timestamp
        );
        _validateAnswer(hotVars.latestAggregatorRoundId, median);
        return report.juelsPerFeeCoin;
      }
      /***************************************************************************
       * Section: v2 AggregatorInterface
       **************************************************************************/
      /**
       * @notice median from the most recent report
       */
      function latestAnswer()
        public
        override
        view
        virtual
        returns (int256)
      {
        return s_transmissions[s_hotVars.latestAggregatorRoundId].answer;
      }
      /**
       * @notice timestamp of block in which last report was transmitted
       */
      function latestTimestamp()
        public
        override
        view
        virtual
        returns (uint256)
      {
        return s_transmissions[s_hotVars.latestAggregatorRoundId].transmissionTimestamp;
      }
      /**
       * @notice Aggregator round (NOT OCR round) in which last report was transmitted
       */
      function latestRound()
        public
        override
        view
        virtual
        returns (uint256)
      {
        return s_hotVars.latestAggregatorRoundId;
      }
      /**
       * @notice median of report from given aggregator round (NOT OCR round)
       * @param roundId the aggregator round of the target report
       */
      function getAnswer(uint256 roundId)
        public
        override
        view
        virtual
        returns (int256)
      {
        if (roundId > 0xFFFFFFFF) { return 0; }
        return s_transmissions[uint32(roundId)].answer;
      }
      /**
       * @notice timestamp of block in which report from given aggregator round was transmitted
       * @param roundId aggregator round (NOT OCR round) of target report
       */
      function getTimestamp(uint256 roundId)
        public
        override
        view
        virtual
        returns (uint256)
      {
        if (roundId > 0xFFFFFFFF) { return 0; }
        return s_transmissions[uint32(roundId)].transmissionTimestamp;
      }
      /***************************************************************************
       * Section: v3 AggregatorInterface
       **************************************************************************/
      /**
       * @return answers are stored in fixed-point format, with this many digits of precision
       */
      uint8 immutable public override decimals;
      /**
       * @notice aggregator contract version
       */
      uint256 constant public override version = 6;
      string internal s_description;
      /**
       * @notice human-readable description of observable this contract is reporting on
       */
      function description()
        public
        override
        view
        virtual
        returns (string memory)
      {
        return s_description;
      }
      /**
       * @notice details for the given aggregator round
       * @param roundId target aggregator round (NOT OCR round). Must fit in uint32
       * @return roundId_ roundId
       * @return answer median of report from given roundId
       * @return startedAt timestamp of when observations were made offchain
       * @return updatedAt timestamp of block in which report from given roundId was transmitted
       * @return answeredInRound roundId
       */
      function getRoundData(uint80 roundId)
        public
        override
        view
        virtual
        returns (
          uint80 roundId_,
          int256 answer,
          uint256 startedAt,
          uint256 updatedAt,
          uint80 answeredInRound
        )
      {
        if(roundId > type(uint32).max) { return (0, 0, 0, 0, 0); }
        Transmission memory transmission = s_transmissions[uint32(roundId)];
        return (
          roundId,
          transmission.answer,
          transmission.observationsTimestamp,
          transmission.transmissionTimestamp,
          roundId
        );
      }
      /**
       * @notice aggregator details for the most recently transmitted report
       * @return roundId aggregator round of latest report (NOT OCR round)
       * @return answer median of latest report
       * @return startedAt timestamp of when observations were made offchain
       * @return updatedAt timestamp of block containing latest report
       * @return answeredInRound aggregator round of latest report
       */
      function latestRoundData()
        public
        override
        view
        virtual
        returns (
          uint80 roundId,
          int256 answer,
          uint256 startedAt,
          uint256 updatedAt,
          uint80 answeredInRound
        )
      {
        uint32 latestAggregatorRoundId = s_hotVars.latestAggregatorRoundId;
        Transmission memory transmission = s_transmissions[latestAggregatorRoundId];
        return (
          latestAggregatorRoundId,
          transmission.answer,
          transmission.observationsTimestamp,
          transmission.transmissionTimestamp,
          latestAggregatorRoundId
        );
      }
      /***************************************************************************
       * Section: Configurable LINK Token
       **************************************************************************/
      // We assume that the token contract is correct. This contract is not written
      // to handle misbehaving ERC20 tokens!
      LinkTokenInterface internal s_linkToken;
      /*
       * @notice emitted when the LINK token contract is set
       * @param oldLinkToken the address of the old LINK token contract
       * @param newLinkToken the address of the new LINK token contract
       */
      event LinkTokenSet(
        LinkTokenInterface indexed oldLinkToken,
        LinkTokenInterface indexed newLinkToken
      );
      /**
       * @notice sets the LINK token contract used for paying oracles
       * @param linkToken the address of the LINK token contract
       * @param recipient remaining funds from the previous token contract are transferred
       * here
       * @dev this function will return early (without an error) without changing any state
       * if linkToken equals getLinkToken().
       * @dev this will trigger a payout so that a malicious owner cannot take from oracles
       * what is already owed to them.
       * @dev we assume that the token contract is correct. This contract is not written
       * to handle misbehaving ERC20 tokens!
       */
      function setLinkToken(
        LinkTokenInterface linkToken,
        address recipient
      ) external
        onlyOwner()
      {
        LinkTokenInterface oldLinkToken = s_linkToken;
        if (linkToken == oldLinkToken) {
          // No change, nothing to be done
          return;
        }
        // call balanceOf as a sanity check on whether we're talking to a token
        // contract
        linkToken.balanceOf(address(this));
        // we break CEI here, but that's okay because we're dealing with a correct
        // token contract (by assumption).
        _payOracles();
        uint256 remainingBalance = oldLinkToken.balanceOf(address(this));
        require(oldLinkToken.transfer(recipient, remainingBalance), "transfer remaining funds failed");
        s_linkToken = linkToken;
        emit LinkTokenSet(oldLinkToken, linkToken);
      }
      /*
       * @notice gets the LINK token contract used for paying oracles
       * @return linkToken the address of the LINK token contract
       */
      function getLinkToken()
        external
        view
        returns(LinkTokenInterface linkToken)
      {
        return s_linkToken;
      }
      /***************************************************************************
       * Section: BillingAccessController Management
       **************************************************************************/
      // Controls who can change billing parameters. A billingAdmin is not able to
      // affect any OCR protocol settings and therefore cannot tamper with the
      // liveness or integrity of a data feed. However, a billingAdmin can set
      // faulty billing parameters causing oracles to be underpaid, or causing them
      // to be paid so much that further calls to setConfig, setBilling,
      // setLinkToken will always fail due to the contract being underfunded.
      AccessControllerInterface internal s_billingAccessController;
      /**
       * @notice emitted when a new access-control contract is set
       * @param old the address prior to the current setting
       * @param current the address of the new access-control contract
       */
      event BillingAccessControllerSet(AccessControllerInterface old, AccessControllerInterface current);
      function _setBillingAccessController(AccessControllerInterface billingAccessController)
        internal
      {
        AccessControllerInterface oldController = s_billingAccessController;
        if (billingAccessController != oldController) {
          s_billingAccessController = billingAccessController;
          emit BillingAccessControllerSet(
            oldController,
            billingAccessController
          );
        }
      }
      /**
       * @notice sets billingAccessController
       * @param _billingAccessController new billingAccessController contract address
       * @dev only owner can call this
       */
      function setBillingAccessController(AccessControllerInterface _billingAccessController)
        external
        onlyOwner
      {
        _setBillingAccessController(_billingAccessController);
      }
      /**
       * @notice gets billingAccessController
       * @return address of billingAccessController contract
       */
      function getBillingAccessController()
        external
        view
        returns (AccessControllerInterface)
      {
        return s_billingAccessController;
      }
      /***************************************************************************
       * Section: Billing Configuration
       **************************************************************************/
      /**
       * @notice emitted when billing parameters are set
       * @param maximumGasPriceGwei highest gas price for which transmitter will be compensated
       * @param reasonableGasPriceGwei transmitter will receive reward for gas prices under this value
       * @param observationPaymentGjuels reward to oracle for contributing an observation to a successfully transmitted report
       * @param transmissionPaymentGjuels reward to transmitter of a successful report
       * @param accountingGas gas overhead incurred by accounting logic
       */
      event BillingSet(
        uint32 maximumGasPriceGwei,
        uint32 reasonableGasPriceGwei,
        uint32 observationPaymentGjuels,
        uint32 transmissionPaymentGjuels,
        uint24 accountingGas
      );
      /**
       * @notice sets billing parameters
       * @param maximumGasPriceGwei highest gas price for which transmitter will be compensated
       * @param reasonableGasPriceGwei transmitter will receive reward for gas prices under this value
       * @param observationPaymentGjuels reward to oracle for contributing an observation to a successfully transmitted report
       * @param transmissionPaymentGjuels reward to transmitter of a successful report
       * @param accountingGas gas overhead incurred by accounting logic
       * @dev access control provided by billingAccessController
       */
      function setBilling(
        uint32 maximumGasPriceGwei,
        uint32 reasonableGasPriceGwei,
        uint32 observationPaymentGjuels,
        uint32 transmissionPaymentGjuels,
        uint24 accountingGas
      )
        external
      {
        AccessControllerInterface access = s_billingAccessController;
        require(msg.sender == owner() || access.hasAccess(msg.sender, msg.data),
          "Only owner&billingAdmin can call");
        _payOracles();
        s_hotVars.maximumGasPriceGwei = maximumGasPriceGwei;
        s_hotVars.reasonableGasPriceGwei = reasonableGasPriceGwei;
        s_hotVars.observationPaymentGjuels = observationPaymentGjuels;
        s_hotVars.transmissionPaymentGjuels = transmissionPaymentGjuels;
        s_hotVars.accountingGas = accountingGas;
        emit BillingSet(maximumGasPriceGwei, reasonableGasPriceGwei,
          observationPaymentGjuels, transmissionPaymentGjuels, accountingGas);
      }
      /**
       * @notice gets billing parameters
       * @param maximumGasPriceGwei highest gas price for which transmitter will be compensated
       * @param reasonableGasPriceGwei transmitter will receive reward for gas prices under this value
       * @param observationPaymentGjuels reward to oracle for contributing an observation to a successfully transmitted report
       * @param transmissionPaymentGjuels reward to transmitter of a successful report
       * @param accountingGas gas overhead of the accounting logic
       */
      function getBilling()
        external
        view
        returns (
          uint32 maximumGasPriceGwei,
          uint32 reasonableGasPriceGwei,
          uint32 observationPaymentGjuels,
          uint32 transmissionPaymentGjuels,
          uint24 accountingGas
        )
      {
        return (
          s_hotVars.maximumGasPriceGwei,
          s_hotVars.reasonableGasPriceGwei,
          s_hotVars.observationPaymentGjuels,
          s_hotVars.transmissionPaymentGjuels,
          s_hotVars.accountingGas
        );
      }
      /***************************************************************************
       * Section: Payments and Withdrawals
       **************************************************************************/
      /**
       * @notice withdraws an oracle's payment from the contract
       * @param transmitter the transmitter address of the oracle
       * @dev must be called by oracle's payee address
       */
      function withdrawPayment(address transmitter)
        external
      {
        require(msg.sender == s_payees[transmitter], "Only payee can withdraw");
        _payOracle(transmitter);
      }
      /**
       * @notice query an oracle's payment amount, denominated in juels
       * @param transmitterAddress the transmitter address of the oracle
       */
      function owedPayment(address transmitterAddress)
        public
        view
        returns (uint256)
      {
        Transmitter memory transmitter = s_transmitters[transmitterAddress];
        if (!transmitter.active) { return 0; }
        // safe from overflow:
        // s_hotVars.latestAggregatorRoundId - s_rewardFromAggregatorRoundId[transmitter.index] <= 2**32
        // s_hotVars.observationPaymentGjuels <= 2**32
        // 1 gwei <= 2**32
        // hence juelsAmount <= 2**96
        uint256 juelsAmount =
          uint256(s_hotVars.latestAggregatorRoundId - s_rewardFromAggregatorRoundId[transmitter.index]) *
          uint256(s_hotVars.observationPaymentGjuels) *
          (1 gwei);
        juelsAmount += transmitter.paymentJuels;
        return juelsAmount;
      }
      /**
       * @notice emitted when an oracle has been paid LINK
       * @param transmitter address from which the oracle sends reports to the transmit method
       * @param payee address to which the payment is sent
       * @param amount amount of LINK sent
       * @param linkToken address of the LINK token contract
       */
      event OraclePaid(
        address indexed transmitter,
        address indexed payee,
        uint256 amount,
        LinkTokenInterface indexed linkToken
      );
      // _payOracle pays out transmitter's balance to the corresponding payee, and zeros it out
      function _payOracle(address transmitterAddress)
        internal
      {
        Transmitter memory transmitter = s_transmitters[transmitterAddress];
        if (!transmitter.active) { return; }
        uint256 juelsAmount = owedPayment(transmitterAddress);
        if (juelsAmount > 0) {
          address payee = s_payees[transmitterAddress];
          // Poses no re-entrancy issues, because LINK.transfer does not yield
          // control flow.
          require(s_linkToken.transfer(payee, juelsAmount), "insufficient funds");
          s_rewardFromAggregatorRoundId[transmitter.index] = s_hotVars.latestAggregatorRoundId;
          s_transmitters[transmitterAddress].paymentJuels = 0;
          emit OraclePaid(transmitterAddress, payee, juelsAmount, s_linkToken);
        }
      }
      // _payOracles pays out all transmitters, and zeros out their balances.
      //
      // It's much more gas-efficient to do this as a single operation, to avoid
      // hitting storage too much.
      function _payOracles()
        internal
      {
        unchecked {
          LinkTokenInterface linkToken = s_linkToken;
          uint32 latestAggregatorRoundId = s_hotVars.latestAggregatorRoundId;
          uint32[maxNumOracles] memory rewardFromAggregatorRoundId = s_rewardFromAggregatorRoundId;
          address[] memory transmitters = s_transmittersList;
          for (uint transmitteridx = 0; transmitteridx < transmitters.length; transmitteridx++) {
            uint256 reimbursementAmountJuels = s_transmitters[transmitters[transmitteridx]].paymentJuels;
            s_transmitters[transmitters[transmitteridx]].paymentJuels = 0;
            uint256 obsCount = latestAggregatorRoundId - rewardFromAggregatorRoundId[transmitteridx];
            uint256 juelsAmount =
              obsCount * uint256(s_hotVars.observationPaymentGjuels) * (1 gwei) + reimbursementAmountJuels;
            if (juelsAmount > 0) {
                address payee = s_payees[transmitters[transmitteridx]];
                // Poses no re-entrancy issues, because LINK.transfer does not yield
                // control flow.
                require(linkToken.transfer(payee, juelsAmount), "insufficient funds");
                rewardFromAggregatorRoundId[transmitteridx] = latestAggregatorRoundId;
                emit OraclePaid(transmitters[transmitteridx], payee, juelsAmount, linkToken);
              }
          }
          // "Zero" the accounting storage variables
          s_rewardFromAggregatorRoundId = rewardFromAggregatorRoundId;
        }
      }
      /**
       * @notice withdraw any available funds left in the contract, up to amount, after accounting for the funds due to participants in past reports
       * @param recipient address to send funds to
       * @param amount maximum amount to withdraw, denominated in LINK-wei.
       * @dev access control provided by billingAccessController
       */
      function withdrawFunds(
        address recipient,
        uint256 amount
      )
        external
      {
        require(msg.sender == owner() || s_billingAccessController.hasAccess(msg.sender, msg.data),
          "Only owner&billingAdmin can call");
        uint256 linkDue = _totalLinkDue();
        uint256 linkBalance = s_linkToken.balanceOf(address(this));
        require(linkBalance >= linkDue, "insufficient balance");
        require(s_linkToken.transfer(recipient, _min(linkBalance - linkDue, amount)), "insufficient funds");
      }
      // Total LINK due to participants in past reports (denominated in Juels).
      function _totalLinkDue()
        internal
        view
        returns (uint256 linkDue)
      {
        // Argument for overflow safety: We do all computations in
        // uint256s. The inputs to linkDue are:
        // - the <= 31 observation rewards each of which has less than
        //   64 bits (32 bits for observationPaymentGjuels, 32 bits
        //   for wei/gwei conversion). Hence 69 bits are sufficient for this part.
        // - the <= 31 gas reimbursements, each of which consists of at most 96
        //   bits. Hence 101 bits are sufficient for this part.
        // So we never need more than 102 bits.
        address[] memory transmitters = s_transmittersList;
        uint256 n = transmitters.length;
        uint32 latestAggregatorRoundId = s_hotVars.latestAggregatorRoundId;
        uint32[maxNumOracles] memory rewardFromAggregatorRoundId = s_rewardFromAggregatorRoundId;
        for (uint i = 0; i < n; i++) {
          linkDue += latestAggregatorRoundId - rewardFromAggregatorRoundId[i];
        }
        // Convert observationPaymentGjuels to uint256, or this overflows!
        linkDue *= uint256(s_hotVars.observationPaymentGjuels) * (1 gwei);
        for (uint i = 0; i < n; i++) {
          linkDue += uint256(s_transmitters[transmitters[i]].paymentJuels);
        }
      }
      /**
       * @notice allows oracles to check that sufficient LINK balance is available
       * @return availableBalance LINK available on this contract, after accounting for outstanding obligations. can become negative
       */
      function linkAvailableForPayment()
        external
        view
        returns (int256 availableBalance)
      {
        // there are at most one billion LINK, so this cast is safe
        int256 balance = int256(s_linkToken.balanceOf(address(this)));
        // according to the argument in the definition of _totalLinkDue,
        // _totalLinkDue is never greater than 2**102, so this cast is safe
        int256 due = int256(_totalLinkDue());
        // safe from overflow according to above sizes
        return int256(balance) - int256(due);
      }
      /**
       * @notice number of observations oracle is due to be reimbursed for
       * @param transmitterAddress address used by oracle for signing or transmitting reports
       */
      function oracleObservationCount(address transmitterAddress)
        external
        view
        returns (uint32)
      {
        Transmitter memory transmitter = s_transmitters[transmitterAddress];
        if (!transmitter.active) { return 0; }
        return s_hotVars.latestAggregatorRoundId - s_rewardFromAggregatorRoundId[transmitter.index];
      }
      /***************************************************************************
       * Section: Transmitter Payment
       **************************************************************************/
      // Gas price at which the transmitter should be reimbursed, in gwei/gas
      function _reimbursementGasPriceGwei(
        uint256 txGasPriceGwei,
        uint256 reasonableGasPriceGwei,
        uint256 maximumGasPriceGwei
      )
        internal
        pure
        returns (uint256)
      {
        // this happens on the path for transmissions. we'd rather pay out
        // a wrong reward than risk a liveness failure due to a revert.
        unchecked {
          // Reward the transmitter for choosing an efficient gas price: if they manage
          // to come in lower than considered reasonable, give them half the savings.
          uint256 gasPriceGwei = txGasPriceGwei;
          if (txGasPriceGwei < reasonableGasPriceGwei) {
            // Give transmitter half the savings for coming in under the reasonable gas price
            gasPriceGwei += (reasonableGasPriceGwei - txGasPriceGwei) / 2;
          }
          // Don't reimburse a gas price higher than maximumGasPriceGwei
          return _min(gasPriceGwei, maximumGasPriceGwei);
        }
      }
      // gas reimbursement due the transmitter, in wei
      function _transmitterGasCostWei(
        uint256 initialGas,
        uint256 gasPriceGwei,
        uint256 callDataGas,
        uint256 accountingGas,
        uint256 leftGas
      )
        internal
        pure
        returns (uint256)
      {
        // this happens on the path for transmissions. we'd rather pay out
        // a wrong reward than risk a liveness failure due to a revert.
        unchecked {
          require(initialGas >= leftGas, "leftGas cannot exceed initialGas");
          uint256 usedGas =
            initialGas - leftGas + // observed gas usage
            callDataGas + accountingGas; // estimated gas usage
          uint256 fullGasCostWei = usedGas * gasPriceGwei * (1 gwei);
          return fullGasCostWei;
        }
      }
      function _payTransmitter(
        HotVars memory hotVars,
        int192 juelsPerFeeCoin,
        uint32 initialGas,
        address transmitter
      )
        internal
        virtual
      {
        // this happens on the path for transmissions. we'd rather pay out
        // a wrong reward than risk a liveness failure due to a revert.
        unchecked {
          // we can't deal with negative juelsPerFeeCoin, better to just not pay
          if (juelsPerFeeCoin < 0) {
            return;
          }
          // Reimburse transmitter of the report for gas usage
          uint256 gasPriceGwei = _reimbursementGasPriceGwei(
            tx.gasprice / (1 gwei), // convert to ETH-gwei units
            hotVars.reasonableGasPriceGwei,
            hotVars.maximumGasPriceGwei
          );
          // The following is only an upper bound, as it ignores the cheaper cost for
          // 0 bytes. Safe from overflow, because calldata just isn't that long.
          uint256 callDataGasCost = 16 * msg.data.length;
          uint256 gasLeft = gasleft();
          uint256 gasCostEthWei = _transmitterGasCostWei(
            uint256(initialGas),
            gasPriceGwei,
            callDataGasCost,
            hotVars.accountingGas,
            gasLeft
          );
          // Even if we assume absurdly large values, this still does not overflow. With
          // - usedGas <= 1'000'000 gas <= 2**20 gas
          // - weiPerGas <= 1'000'000 gwei <= 2**50 wei
          // - hence gasCostEthWei <= 2**70
          // - juelsPerFeeCoin <= 2**96 (more than the entire supply)
          // we still fit into 166 bits
          uint256 gasCostJuels = (gasCostEthWei * uint192(juelsPerFeeCoin))/1e18;
          uint96 oldTransmitterPaymentJuels = s_transmitters[transmitter].paymentJuels;
          uint96 newTransmitterPaymentJuels = uint96(uint256(oldTransmitterPaymentJuels) +
            gasCostJuels + uint256(hotVars.transmissionPaymentGjuels) * (1 gwei));
          // overflow *should* never happen, but if it does, let's not persist it.
          if (newTransmitterPaymentJuels < oldTransmitterPaymentJuels) {
            return;
          }
          s_transmitters[transmitter].paymentJuels = newTransmitterPaymentJuels;
        }
      }
      /***************************************************************************
       * Section: Payee Management
       **************************************************************************/
      // Addresses at which oracles want to receive payments, by transmitter address
      mapping (address /* transmitter */ => address /* payment address */)
        internal
        s_payees;
      // Payee addresses which must be approved by the owner
      mapping (address /* transmitter */ => address /* payment address */)
        internal
        s_proposedPayees;
      /**
       * @notice emitted when a transfer of an oracle's payee address has been initiated
       * @param transmitter address from which the oracle sends reports to the transmit method
       * @param current the payee address for the oracle, prior to this setting
       * @param proposed the proposed new payee address for the oracle
       */
      event PayeeshipTransferRequested(
        address indexed transmitter,
        address indexed current,
        address indexed proposed
      );
      /**
       * @notice emitted when a transfer of an oracle's payee address has been completed
       * @param transmitter address from which the oracle sends reports to the transmit method
       * @param current the payee address for the oracle, prior to this setting
       */
      event PayeeshipTransferred(
        address indexed transmitter,
        address indexed previous,
        address indexed current
      );
      /**
       * @notice sets the payees for transmitting addresses
       * @param transmitters addresses oracles use to transmit the reports
       * @param payees addresses of payees corresponding to list of transmitters
       * @dev must be called by owner
       * @dev cannot be used to change payee addresses, only to initially populate them
       */
      function setPayees(
        address[] calldata transmitters,
        address[] calldata payees
      )
        external
        onlyOwner()
      {
        require(transmitters.length == payees.length, "transmitters.size != payees.size");
        for (uint i = 0; i < transmitters.length; i++) {
          address transmitter = transmitters[i];
          address payee = payees[i];
          address currentPayee = s_payees[transmitter];
          bool zeroedOut = currentPayee == address(0);
          require(zeroedOut || currentPayee == payee, "payee already set");
          s_payees[transmitter] = payee;
          if (currentPayee != payee) {
            emit PayeeshipTransferred(transmitter, currentPayee, payee);
          }
        }
      }
      /**
       * @notice first step of payeeship transfer (safe transfer pattern)
       * @param transmitter transmitter address of oracle whose payee is changing
       * @param proposed new payee address
       * @dev can only be called by payee address
       */
      function transferPayeeship(
        address transmitter,
        address proposed
      )
        external
      {
        require(msg.sender == s_payees[transmitter], "only current payee can update");
        require(msg.sender != proposed, "cannot transfer to self");
        address previousProposed = s_proposedPayees[transmitter];
        s_proposedPayees[transmitter] = proposed;
        if (previousProposed != proposed) {
          emit PayeeshipTransferRequested(transmitter, msg.sender, proposed);
        }
      }
      /**
       * @notice second step of payeeship transfer (safe transfer pattern)
       * @param transmitter transmitter address of oracle whose payee is changing
       * @dev can only be called by proposed new payee address
       */
      function acceptPayeeship(
        address transmitter
      )
        external
      {
        require(msg.sender == s_proposedPayees[transmitter], "only proposed payees can accept");
        address currentPayee = s_payees[transmitter];
        s_payees[transmitter] = msg.sender;
        s_proposedPayees[transmitter] = address(0);
        emit PayeeshipTransferred(transmitter, currentPayee, msg.sender);
      }
      /***************************************************************************
       * Section: TypeAndVersionInterface
       **************************************************************************/
      function typeAndVersion()
        external
        override
        pure
        virtual
        returns (string memory)
      {
        return "OCR2Aggregator 1.0.0";
      }
      /***************************************************************************
       * Section: Helper Functions
       **************************************************************************/
      function _min(
        uint256 a,
        uint256 b
      )
        internal
        pure
        returns (uint256)
      {
        unchecked {
          if (a < b) { return a; }
          return b;
        }
      }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity =0.8.19;
    import "./interfaces/TypeAndVersionInterface.sol";
    import "./lib/ConfigDigestUtilEVMSimple.sol";
    import "./OwnerIsCreator.sol";
    import "./OCR2Abstract.sol";
    /// @title OCRConfigurationStoreEVMSimple
    /// @notice This contract stores configurations for protocol versions OCR2 and
    /// above in contract storage. It uses the "EVMSimple" config digester.
    contract OCRConfigurationStoreEVMSimple is TypeAndVersionInterface {
        struct ConfigurationEVMSimple {
            address[] signers;
            address[] transmitters;
            bytes onchainConfig;
            bytes offchainConfig;
            address contractAddress;
            uint64 offchainConfigVersion;
            uint32 configCount;
            uint8 f;
        }
        /// @notice a list of configurations keyed by their digest
        mapping(bytes32 => ConfigurationEVMSimple) internal s_configurations;
        /// @notice emitted when a new configuration is added
        event NewConfiguration(bytes32 indexed configDigest);
        /// @notice adds a new configuration to the store
        function addConfig(ConfigurationEVMSimple calldata configuration) external returns (bytes32) {
            bytes32 configDigest = ConfigDigestUtilEVMSimple.configDigestFromConfigData(
                block.chainid,
                configuration.contractAddress,
                configuration.configCount,
                configuration.signers,
                configuration.transmitters,
                configuration.f,
                configuration.onchainConfig,
                configuration.offchainConfigVersion,
                configuration.offchainConfig
            );
            s_configurations[configDigest] = configuration;
            emit NewConfiguration(configDigest);
            return configDigest;
        }
        /// @notice reads a configuration from the store
        function readConfig(bytes32 configDigest) external view returns (ConfigurationEVMSimple memory) {
            return s_configurations[configDigest];
        }
        /// @inheritdoc TypeAndVersionInterface
        function typeAndVersion() external override pure virtual returns (string memory)
        {
            return "OCRConfigurationStoreEVMSimple 1.0.0";
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "./ConfirmedOwner.sol";
    /**
     * @title The OwnerIsCreator contract
     * @notice A contract with helpers for basic contract ownership.
     */
    contract OwnerIsCreator is ConfirmedOwner {
      constructor(
      )
        ConfirmedOwner(
          msg.sender
        )
      {
      }
    }// SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "./SimpleWriteAccessController.sol";
    /**
     * @title SimpleReadAccessController
     * @notice Gives access to:
     * - any externally owned account (note that offchain actors can always read
     * any contract storage regardless of onchain access control measures, so this
     * does not weaken the access control while improving usability)
     * - accounts explicitly added to an access list
     * @dev SimpleReadAccessController is not suitable for access controlling writes
     * since it grants any externally owned account access! See
     * SimpleWriteAccessController for that.
     */
    contract SimpleReadAccessController is SimpleWriteAccessController {
      /**
       * @notice Returns the access of an address
       * @param _user The address to query
       */
      function hasAccess(
        address _user,
        bytes memory _calldata
      )
        public
        view
        virtual
        override
        returns (bool)
      {
        return super.hasAccess(_user, _calldata) || _user == tx.origin;
      }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "./OwnerIsCreator.sol";
    import "./interfaces/AccessControllerInterface.sol";
    /**
     * @title SimpleWriteAccessController
     * @notice Gives access to accounts explicitly added to an access list by the
     * controller's owner.
     * @dev does not make any special permissions for externally, see
     * SimpleReadAccessController for that.
     */
    contract SimpleWriteAccessController is AccessControllerInterface, OwnerIsCreator {
      bool public checkEnabled;
      mapping(address => bool) internal accessList;
      event AddedAccess(address user);
      event RemovedAccess(address user);
      event CheckAccessEnabled();
      event CheckAccessDisabled();
      constructor()
      // TODO
      // this is modified from the version in the Chainlink monorepo
      //  OwnerIsCreator()
      {
        checkEnabled = true;
      }
      /**
       * @notice Returns the access of an address
       * @param _user The address to query
       */
      function hasAccess(
        address _user,
        bytes memory
      )
        public
        view
        virtual
        override
        returns (bool)
      {
        return accessList[_user] || !checkEnabled;
      }
      /**
       * @notice Adds an address to the access list
       * @param _user The address to add
       */
      function addAccess(address _user)
        external
        onlyOwner()
      {
        if (!accessList[_user]) {
          accessList[_user] = true;
          emit AddedAccess(_user);
        }
      }
      /**
       * @notice Removes an address from the access list
       * @param _user The address to remove
       */
      function removeAccess(address _user)
        external
        onlyOwner()
      {
        if (accessList[_user]) {
          accessList[_user] = false;
          emit RemovedAccess(_user);
        }
      }
      /**
       * @notice makes the access check enforced
       */
      function enableAccessCheck()
        external
        onlyOwner()
      {
        if (!checkEnabled) {
          checkEnabled = true;
          emit CheckAccessEnabled();
        }
      }
      /**
       * @notice makes the access check unenforced
       */
      function disableAccessCheck()
        external
        onlyOwner()
      {
        if (checkEnabled) {
          checkEnabled = false;
          emit CheckAccessDisabled();
        }
      }
      /**
       * @dev reverts if the caller does not have access
       */
      modifier checkAccess() {
        require(hasAccess(msg.sender, msg.data), "No access");
        _;
      }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    interface AccessControllerInterface {
      function hasAccess(address user, bytes calldata data) external view returns (bool);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    interface AggregatorInterface {
      function latestAnswer() external view returns (int256);
      function latestTimestamp() external view returns (uint256);
      function latestRound() external view returns (uint256);
      function getAnswer(uint256 roundId) external view returns (int256);
      function getTimestamp(uint256 roundId) external view returns (uint256);
      event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);
      event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "./AggregatorInterface.sol";
    import "./AggregatorV3Interface.sol";
    interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface
    {
    }// SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    interface AggregatorV3Interface {
      function decimals() external view returns (uint8);
      function description() external view returns (string memory);
      function version() external view returns (uint256);
      function getRoundData(uint80 _roundId)
        external
        view
        returns (
          uint80 roundId,
          int256 answer,
          uint256 startedAt,
          uint256 updatedAt,
          uint80 answeredInRound
        );
      function latestRoundData()
        external
        view
        returns (
          uint80 roundId,
          int256 answer,
          uint256 startedAt,
          uint256 updatedAt,
          uint80 answeredInRound
        );
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    interface AggregatorValidatorInterface {
      function validate(
        uint256 previousRoundId,
        int256 previousAnswer,
        uint256 currentRoundId,
        int256 currentAnswer
      ) external returns (bool);
    }// SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    interface LinkTokenInterface {
      function allowance(address owner, address spender) external view returns (uint256 remaining);
      function approve(address spender, uint256 value) external returns (bool success);
      function balanceOf(address owner) external view returns (uint256 balance);
      function decimals() external view returns (uint8 decimalPlaces);
      function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);
      function increaseApproval(address spender, uint256 subtractedValue) external;
      function name() external view returns (string memory tokenName);
      function symbol() external view returns (string memory tokenSymbol);
      function totalSupply() external view returns (uint256 totalTokensIssued);
      function transfer(address to, uint256 value) external returns (bool success);
      function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool success);
      function transferFrom(address from, address to, uint256 value) external returns (bool success);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    interface OwnableInterface {
      function owner()
        external
        returns (
          address
        );
      function transferOwnership(
        address recipient
      )
        external;
      function acceptOwnership()
        external;
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    interface TypeAndVersionInterface{
      function typeAndVersion()
        external
        pure
        returns (string memory);
    }// SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /// @title ConfigDigestUtilEVMSimple
    /// @notice ConfigDigest related utility functions for "EVMSimple" config
    /// digester
    library ConfigDigestUtilEVMSimple {
        function configDigestFromConfigData(
            uint256 chainId,
            address contractAddress,
            uint64 configCount,
            address[] memory signers,
            address[] memory transmitters,
            uint8 f,
            bytes memory onchainConfig,
            uint64 offchainConfigVersion,
            bytes memory offchainConfig
        ) internal pure returns (bytes32)
        {
            uint256 hash = uint256(
                keccak256(
                    abi.encode(
                        chainId,
                        contractAddress,
                        configCount,
                        signers,
                        transmitters,
                        f,
                        onchainConfig,
                        offchainConfigVersion,
                        offchainConfig
            )));
            uint256 prefixMask = type(uint256).max << (256-16); // 0xFFFF00..00
            uint256 prefix = 0x0001 << (256-16); // 0x000100..00
            return bytes32((prefix & prefixMask) | (hash & ~prefixMask));
        }
    }