ETH Price: $3,097.48 (-13.99%)

Transaction Decoder

Block:
23455144 at Sep-27-2025 03:10:23 PM +UTC
Transaction Fee:
0.000162861760168073 ETH $0.50
Gas Used:
147,971 Gas / 1.100632963 Gwei

Emitted Events:

159 AccessControlledOCR2Aggregator.NewTransmission( aggregatorRoundId=10877, answer=99722632, transmitter=[Receiver] AuthorizedForwarder, observationsTimestamp=1758985801, observations=[99718276, 99718276, 99718876, 99718876, 99720915, 99720915, 99722632, 99722632, 99722632, 99722632, 99723232, 99723232, 99723832, 99723832, 99723832, 99723832, 99725271, 99725871, 99725899], observers=0x0E0B02070C1200040811030A0D0F0905061001, juelsPerFeeCoin=191762811034322171396, configDigest=0001A0B18AB1E1A67513AFF1A75B8009CEC2570E457608CC58A0618DDE6ABAE7, epochAndRound=24592385 )
160 AccessControlledOCR2Aggregator.NewRound( roundId=10877, startedBy=0x00000000...000000000, startedAt=1758985801 )
161 AccessControlledOCR2Aggregator.AnswerUpdated( current=99722632, roundId=10877, updatedAt=1758985823 )

Account State Difference:

  Address   Before After State Difference Code
(Titan Builder)
1.406050540812734003 Eth1.406124526312734003 Eth0.0000739855
0x8F73090a...cC4f01E8c
0xb976d012...9264466D0
8.75031777613544183 Eth
Nonce: 153796
8.750154914375273757 Eth
Nonce: 153797
0.000162861760168073

Execution Trace

AuthorizedForwarder.forward( to=0x8F73090a7c58B8BDcC9A93cBB6816e5cC4f01E8c, data=0xB1DC65A40001A0B18AB1E1A67513AFF1A75B8009CEC2570E457608CC58A0618DDE6ABAE7000000000000000000000000000000000000000000000000000000000177400122C641A818D674FEE8B66EDE028EC9F7E2B5B1E74CF7E3AD88E2893B606A366800000000000000000000000000000000000000000000000000000000000000E000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000500010100010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000068D7FE490E0B02070C1200040811030A0D0F090506100100000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000A653E5CA1FF21760400000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000005F194840000000000000000000000000000000000000000000000000000000005F194840000000000000000000000000000000000000000000000000000000005F196DC0000000000000000000000000000000000000000000000000000000005F196DC0000000000000000000000000000000000000000000000000000000005F19ED30000000000000000000000000000000000000000000000000000000005F19ED30000000000000000000000000000000000000000000000000000000005F1A5880000000000000000000000000000000000000000000000000000000005F1A5880000000000000000000000000000000000000000000000000000000005F1A5880000000000000000000000000000000000000000000000000000000005F1A5880000000000000000000000000000000000000000000000000000000005F1A7E00000000000000000000000000000000000000000000000000000000005F1A7E00000000000000000000000000000000000000000000000000000000005F1AA380000000000000000000000000000000000000000000000000000000005F1AA380000000000000000000000000000000000000000000000000000000005F1AA380000000000000000000000000000000000000000000000000000000005F1AA380000000000000000000000000000000000000000000000000000000005F1AFD70000000000000000000000000000000000000000000000000000000005F1B22F0000000000000000000000000000000000000000000000000000000005F1B24B00000000000000000000000000000000000000000000000000000000000000074B7ABE71A26CDD25B4207C8213E722FF1C8B8DDEF88BFCD1BF1CC06CA805E86D68521DADCF67E07BD499A588EC0EC79AD8D6AB058F34F92FB4243FE5A78BA4D0C9117876C4F03DF858C9F746628A2EF049B74A79B8D20F483FA72803583336DB38612AAA6221C91AB4064B5C32060E30553CCED3B95C0682D58691D9F76619B3E414BDF443815EC3700CC04A9F01330A6D9D707029D119B7AB73B6093294DD0D5946F694C233605CCA6C249CD210D6DD01B64DDBF9E12604838BE21849FEADA1290D441C6F93222CE5B4B038471E56BE5ACB5679F919864A39A537BC58A4CFE400000000000000000000000000000000000000000000000000000000000000071E1131D7EF6B555B7813190405B99F316D868033D446E42047F04DFBD74945EB22EA1F3F11EFCB7349B12F1A5674C4E2657007B686D9F446C0796859DF5835570ACCAAE55ADFB361AB9C863FA1EA9BE0B4AB583B8ED3423F130670A5EFCE1E3434C6283BE625C22216A954F1FA0B99AC8AA39095ABA2E2ADFAC6434EEC80FFA635B4188E908CE4247B3C721770D1DD244C1211617A73BFE0E28E73FDFDF1ED9A7690A2791131E872DCBAC04490F9FEA0732FEDA83680A06AE07E691C59D88712732CE999D6D89DAED0E4F2C0E68B6C76816F7CD5066CA60DB53DD858CAA3F315 )
  • AccessControlledOCR2Aggregator.transmit( )
    • Null: 0x000...001.c8a2a260( )
    • Null: 0x000...001.c8a2a260( )
    • Null: 0x000...001.c8a2a260( )
    • Null: 0x000...001.c8a2a260( )
    • Null: 0x000...001.c8a2a260( )
    • Null: 0x000...001.c8a2a260( )
    • Null: 0x000...001.c8a2a260( )
      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));
          }
      }