ETH Price: $2,289.73 (-5.56%)

Transaction Decoder

Block:
18592405 at Nov-17-2023 03:11:23 PM +UTC
Transaction Fee:
0.008651862768111607 ETH $19.81
Gas Used:
205,073 Gas / 42.189185159 Gwei

Emitted Events:

199 TransparentUpgradeableProxy.0x4d8aead3491b7eba4b5c7a65fc17e493b9e63f9e433522fc5f6a85a168fc9d36( 0x4d8aead3491b7eba4b5c7a65fc17e493b9e63f9e433522fc5f6a85a168fc9d36, 0x000000000000000000000000f9d146ccafa2d1184d46077ad8ff5d0083ee7ba8, 0x00000000000000000000000000000000000000000000000000000000000112dc, 0x0000000000000000000000000000000000000000000000000000000000000000, 00000000000000000000000000000000000000000000000002b853b3e50a57ec, 0000000000000000000000000000000000000000000000149914fc0e542a0000, 000000000000000000000000000000000000000000000000000000006557829b )

Account State Difference:

  Address   Before After State Difference Code
0x2Edb788c...789cf8E86 87.933041970746348408 Eth87.9800816385617552 Eth0.047039667815406792
0x4D5eC8f9...b90ce7840 87.933041970746348408 Eth87.9800816385617552 Eth0.047039667815406792
0x527aFE11...7C10e1af1 87.933041970746348408 Eth87.9800816385617552 Eth0.047039667815406792
0x5a65B0aA...cF07C8d8e
0x6DbCeFb3...8eCe6eFd5 87.933041970746348408 Eth87.9800816385617552 Eth0.047039667815406792
(beaverbuild)
18.033520779875021665 Eth18.033541287175021665 Eth0.0000205073
0xEeb2524a...5ee345256 14.714505987338206339 Eth14.722345931974107471 Eth0.007839944635901132
0xf9d146cC...083Ee7BA8
0.360457367364455095 Eth
Nonce: 114
0.155806888698815188 Eth
Nonce: 115
0.204650478665639907

Execution Trace

ETH 0.2 TransparentUpgradeableProxy.2c65169e( )
  • ETH 0.2 0x517bc044953dc1632ae14589e247f0b32460ad1c.2c65169e( )
    • EACAggregatorProxy.STATICCALL( )
      • AccessControlledOffchainAggregator.STATICCALL( )
      • ETH 0.047039667815406792 0x527afe11a8c39effc6c2876273240cc7c10e1af1.CALL( )
      • ETH 0.047039667815406792 0x6dbcefb314af0a99c8df2a2de8c6abf8ece6efd5.CALL( )
      • ETH 0.047039667815406792 0x4d5ec8f9b3e89316d4afe88f226a729b90ce7840.CALL( )
      • ETH 0.047039667815406792 0x2edb788cf62ef7adc2e7f4d46301de8789cf8e86.CALL( )
      • ETH 0.007839944635901132 0xeeb2524a858ad398212e96fe046a64c5ee345256.CALL( )
      • ETH 0.0040013841024717 0xf9d146ccafa2d1184d46077ad8ff5d0083ee7ba8.CALL( )
        File 1 of 3: TransparentUpgradeableProxy
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
        import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
        import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
        import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
        import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
        // Kept for backwards compatibility with older versions of Hardhat and Truffle plugins.
        contract AdminUpgradeabilityProxy is TransparentUpgradeableProxy {
            constructor(address logic, address admin, bytes memory data) payable TransparentUpgradeableProxy(logic, admin, data) {}
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        import "./IBeacon.sol";
        import "../Proxy.sol";
        import "../ERC1967/ERC1967Upgrade.sol";
        /**
         * @dev This contract implements a proxy that gets the implementation address for each call from a {UpgradeableBeacon}.
         *
         * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't
         * conflict with the storage layout of the implementation behind the proxy.
         *
         * _Available since v3.4._
         */
        contract BeaconProxy is Proxy, ERC1967Upgrade {
            /**
             * @dev Initializes the proxy with `beacon`.
             *
             * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This
             * will typically be an encoded function call, and allows initializating the storage of the proxy like a Solidity
             * constructor.
             *
             * Requirements:
             *
             * - `beacon` must be a contract with the interface {IBeacon}.
             */
            constructor(address beacon, bytes memory data) payable {
                assert(_BEACON_SLOT == bytes32(uint256(keccak256("eip1967.proxy.beacon")) - 1));
                _upgradeBeaconToAndCall(beacon, data, false);
            }
            /**
             * @dev Returns the current beacon address.
             */
            function _beacon() internal view virtual returns (address) {
                return _getBeacon();
            }
            /**
             * @dev Returns the current implementation address of the associated beacon.
             */
            function _implementation() internal view virtual override returns (address) {
                return IBeacon(_getBeacon()).implementation();
            }
            /**
             * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}.
             *
             * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.
             *
             * Requirements:
             *
             * - `beacon` must be a contract.
             * - The implementation returned by `beacon` must be a contract.
             */
            function _setBeacon(address beacon, bytes memory data) internal virtual {
                _upgradeBeaconToAndCall(beacon, data, false);
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        import "./IBeacon.sol";
        import "../../access/Ownable.sol";
        import "../../utils/Address.sol";
        /**
         * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their
         * implementation contract, which is where they will delegate all function calls.
         *
         * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon.
         */
        contract UpgradeableBeacon is IBeacon, Ownable {
            address private _implementation;
            /**
             * @dev Emitted when the implementation returned by the beacon is changed.
             */
            event Upgraded(address indexed implementation);
            /**
             * @dev Sets the address of the initial implementation, and the deployer account as the owner who can upgrade the
             * beacon.
             */
            constructor(address implementation_) {
                _setImplementation(implementation_);
            }
            /**
             * @dev Returns the current implementation address.
             */
            function implementation() public view virtual override returns (address) {
                return _implementation;
            }
            /**
             * @dev Upgrades the beacon to a new implementation.
             *
             * Emits an {Upgraded} event.
             *
             * Requirements:
             *
             * - msg.sender must be the owner of the contract.
             * - `newImplementation` must be a contract.
             */
            function upgradeTo(address newImplementation) public virtual onlyOwner {
                _setImplementation(newImplementation);
                emit Upgraded(newImplementation);
            }
            /**
             * @dev Sets the implementation contract address for this beacon
             *
             * Requirements:
             *
             * - `newImplementation` must be a contract.
             */
            function _setImplementation(address newImplementation) private {
                require(Address.isContract(newImplementation), "UpgradeableBeacon: implementation is not a contract");
                _implementation = newImplementation;
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        import "../Proxy.sol";
        import "./ERC1967Upgrade.sol";
        /**
         * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
         * implementation address that can be changed. This address is stored in storage in the location specified by
         * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
         * implementation behind the proxy.
         */
        contract ERC1967Proxy is Proxy, ERC1967Upgrade {
            /**
             * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
             *
             * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
             * function call, and allows initializating the storage of the proxy like a Solidity constructor.
             */
            constructor(address _logic, bytes memory _data) payable {
                assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
                _upgradeToAndCall(_logic, _data, false);
            }
            /**
             * @dev Returns the current implementation address.
             */
            function _implementation() internal view virtual override returns (address impl) {
                return ERC1967Upgrade._getImplementation();
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        import "../ERC1967/ERC1967Proxy.sol";
        /**
         * @dev This contract implements a proxy that is upgradeable by an admin.
         *
         * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
         * clashing], which can potentially be used in an attack, this contract uses the
         * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
         * things that go hand in hand:
         *
         * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
         * that call matches one of the admin functions exposed by the proxy itself.
         * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
         * implementation. If the admin tries to call a function on the implementation it will fail with an error that says
         * "admin cannot fallback to proxy target".
         *
         * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
         * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
         * to sudden errors when trying to call a function from the proxy implementation.
         *
         * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
         * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
         */
        contract TransparentUpgradeableProxy is ERC1967Proxy {
            /**
             * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
             * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
             */
            constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
                assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
                _changeAdmin(admin_);
            }
            /**
             * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
             */
            modifier ifAdmin() {
                if (msg.sender == _getAdmin()) {
                    _;
                } else {
                    _fallback();
                }
            }
            /**
             * @dev Returns the current admin.
             *
             * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
             *
             * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
             * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
             * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
             */
            function admin() external ifAdmin returns (address admin_) {
                admin_ = _getAdmin();
            }
            /**
             * @dev Returns the current implementation.
             *
             * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
             *
             * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
             * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
             * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
             */
            function implementation() external ifAdmin returns (address implementation_) {
                implementation_ = _implementation();
            }
            /**
             * @dev Changes the admin of the proxy.
             *
             * Emits an {AdminChanged} event.
             *
             * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
             */
            function changeAdmin(address newAdmin) external virtual ifAdmin {
                _changeAdmin(newAdmin);
            }
            /**
             * @dev Upgrade the implementation of the proxy.
             *
             * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
             */
            function upgradeTo(address newImplementation) external ifAdmin {
                _upgradeToAndCall(newImplementation, bytes(""), false);
            }
            /**
             * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
             * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
             * proxied contract.
             *
             * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
             */
            function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
                _upgradeToAndCall(newImplementation, data, true);
            }
            /**
             * @dev Returns the current admin.
             */
            function _admin() internal view virtual returns (address) {
                return _getAdmin();
            }
            /**
             * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
             */
            function _beforeFallback() internal virtual override {
                require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
                super._beforeFallback();
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        import "./TransparentUpgradeableProxy.sol";
        import "../../access/Ownable.sol";
        /**
         * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
         * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
         */
        contract ProxyAdmin is Ownable {
            /**
             * @dev Returns the current implementation of `proxy`.
             *
             * Requirements:
             *
             * - This contract must be the admin of `proxy`.
             */
            function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                // We need to manually run the static call since the getter cannot be flagged as view
                // bytes4(keccak256("implementation()")) == 0x5c60da1b
                (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
                require(success);
                return abi.decode(returndata, (address));
            }
            /**
             * @dev Returns the current admin of `proxy`.
             *
             * Requirements:
             *
             * - This contract must be the admin of `proxy`.
             */
            function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                // We need to manually run the static call since the getter cannot be flagged as view
                // bytes4(keccak256("admin()")) == 0xf851a440
                (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
                require(success);
                return abi.decode(returndata, (address));
            }
            /**
             * @dev Changes the admin of `proxy` to `newAdmin`.
             *
             * Requirements:
             *
             * - This contract must be the current admin of `proxy`.
             */
            function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
                proxy.changeAdmin(newAdmin);
            }
            /**
             * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.
             *
             * Requirements:
             *
             * - This contract must be the admin of `proxy`.
             */
            function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
                proxy.upgradeTo(implementation);
            }
            /**
             * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See
             * {TransparentUpgradeableProxy-upgradeToAndCall}.
             *
             * Requirements:
             *
             * - This contract must be the admin of `proxy`.
             */
            function upgradeAndCall(TransparentUpgradeableProxy proxy, address implementation, bytes memory data) public payable virtual onlyOwner {
                proxy.upgradeToAndCall{value: msg.value}(implementation, data);
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /**
         * @dev This is the interface that {BeaconProxy} expects of its beacon.
         */
        interface IBeacon {
            /**
             * @dev Must return an address that can be used as a delegate call target.
             *
             * {BeaconProxy} will check that this address is a contract.
             */
            function implementation() external view returns (address);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /**
         * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
         * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
         * be specified by overriding the virtual {_implementation} function.
         *
         * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
         * different contract through the {_delegate} function.
         *
         * The success and return data of the delegated call will be returned back to the caller of the proxy.
         */
        abstract contract Proxy {
            /**
             * @dev Delegates the current call to `implementation`.
             *
             * This function does not return to its internall call site, it will return directly to the external caller.
             */
            function _delegate(address implementation) internal virtual {
                // solhint-disable-next-line no-inline-assembly
                assembly {
                    // Copy msg.data. We take full control of memory in this inline assembly
                    // block because it will not return to Solidity code. We overwrite the
                    // Solidity scratch pad at memory position 0.
                    calldatacopy(0, 0, calldatasize())
                    // Call the implementation.
                    // out and outsize are 0 because we don't know the size yet.
                    let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                    // Copy the returned data.
                    returndatacopy(0, 0, returndatasize())
                    switch result
                    // delegatecall returns 0 on error.
                    case 0 { revert(0, returndatasize()) }
                    default { return(0, returndatasize()) }
                }
            }
            /**
             * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
             * and {_fallback} should delegate.
             */
            function _implementation() internal view virtual returns (address);
            /**
             * @dev Delegates the current call to the address returned by `_implementation()`.
             *
             * This function does not return to its internall call site, it will return directly to the external caller.
             */
            function _fallback() internal virtual {
                _beforeFallback();
                _delegate(_implementation());
            }
            /**
             * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
             * function in the contract matches the call data.
             */
            fallback () external payable virtual {
                _fallback();
            }
            /**
             * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
             * is empty.
             */
            receive () external payable virtual {
                _fallback();
            }
            /**
             * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
             * call, or as part of the Solidity `fallback` or `receive` functions.
             *
             * If overriden should call `super._beforeFallback()`.
             */
            function _beforeFallback() internal virtual {
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.2;
        import "../beacon/IBeacon.sol";
        import "../../utils/Address.sol";
        import "../../utils/StorageSlot.sol";
        /**
         * @dev This abstract contract provides getters and event emitting update functions for
         * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
         *
         * _Available since v4.1._
         *
         * @custom:oz-upgrades-unsafe-allow delegatecall
         */
        abstract contract ERC1967Upgrade {
            // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
            bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
            /**
             * @dev Storage slot with the address of the current implementation.
             * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
             * validated in the constructor.
             */
            bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
            /**
             * @dev Emitted when the implementation is upgraded.
             */
            event Upgraded(address indexed implementation);
            /**
             * @dev Returns the current implementation address.
             */
            function _getImplementation() internal view returns (address) {
                return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
            }
            /**
             * @dev Stores a new address in the EIP1967 implementation slot.
             */
            function _setImplementation(address newImplementation) private {
                require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
            }
            /**
             * @dev Perform implementation upgrade
             *
             * Emits an {Upgraded} event.
             */
            function _upgradeTo(address newImplementation) internal {
                _setImplementation(newImplementation);
                emit Upgraded(newImplementation);
            }
            /**
             * @dev Perform implementation upgrade with additional setup call.
             *
             * Emits an {Upgraded} event.
             */
            function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
                _setImplementation(newImplementation);
                emit Upgraded(newImplementation);
                if (data.length > 0 || forceCall) {
                    Address.functionDelegateCall(newImplementation, data);
                }
            }
            /**
             * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
             *
             * Emits an {Upgraded} event.
             */
            function _upgradeToAndCallSecure(address newImplementation, bytes memory data, bool forceCall) internal {
                address oldImplementation = _getImplementation();
                // Initial upgrade and setup call
                _setImplementation(newImplementation);
                if (data.length > 0 || forceCall) {
                    Address.functionDelegateCall(newImplementation, data);
                }
                // Perform rollback test if not already in progress
                StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT);
                if (!rollbackTesting.value) {
                    // Trigger rollback using upgradeTo from the new implementation
                    rollbackTesting.value = true;
                    Address.functionDelegateCall(
                        newImplementation,
                        abi.encodeWithSignature(
                            "upgradeTo(address)",
                            oldImplementation
                        )
                    );
                    rollbackTesting.value = false;
                    // Check rollback was effective
                    require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
                    // Finally reset to the new implementation and log the upgrade
                    _setImplementation(newImplementation);
                    emit Upgraded(newImplementation);
                }
            }
            /**
             * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
             * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
             *
             * Emits a {BeaconUpgraded} event.
             */
            function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
                _setBeacon(newBeacon);
                emit BeaconUpgraded(newBeacon);
                if (data.length > 0 || forceCall) {
                    Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                }
            }
            /**
             * @dev Storage slot with the admin of the contract.
             * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
             * validated in the constructor.
             */
            bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
            /**
             * @dev Emitted when the admin account has changed.
             */
            event AdminChanged(address previousAdmin, address newAdmin);
            /**
             * @dev Returns the current admin.
             */
            function _getAdmin() internal view returns (address) {
                return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
            }
            /**
             * @dev Stores a new address in the EIP1967 admin slot.
             */
            function _setAdmin(address newAdmin) private {
                require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
            }
            /**
             * @dev Changes the admin of the proxy.
             *
             * Emits an {AdminChanged} event.
             */
            function _changeAdmin(address newAdmin) internal {
                emit AdminChanged(_getAdmin(), newAdmin);
                _setAdmin(newAdmin);
            }
            /**
             * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
             * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
             */
            bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
            /**
             * @dev Emitted when the beacon is upgraded.
             */
            event BeaconUpgraded(address indexed beacon);
            /**
             * @dev Returns the current beacon.
             */
            function _getBeacon() internal view returns (address) {
                return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
            }
            /**
             * @dev Stores a new beacon in the EIP1967 beacon slot.
             */
            function _setBeacon(address newBeacon) private {
                require(
                    Address.isContract(newBeacon),
                    "ERC1967: new beacon is not a contract"
                );
                require(
                    Address.isContract(IBeacon(newBeacon).implementation()),
                    "ERC1967: beacon implementation is not a contract"
                );
                StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /**
         * @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
             * ====
             */
            function isContract(address account) internal view returns (bool) {
                // This method relies on extcodesize, which returns 0 for contracts in
                // construction, since the code is only stored at the end of the
                // constructor execution.
                uint256 size;
                // solhint-disable-next-line no-inline-assembly
                assembly { size := extcodesize(account) }
                return size > 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://diligence.consensys.net/posts/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.5.11/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");
                // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                (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 functionCall(target, data, "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");
                require(isContract(target), "Address: call to non-contract");
                // solhint-disable-next-line avoid-low-level-calls
                (bool success, bytes memory returndata) = target.call{ value: value }(data);
                return _verifyCallResult(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) {
                require(isContract(target), "Address: static call to non-contract");
                // solhint-disable-next-line avoid-low-level-calls
                (bool success, bytes memory returndata) = target.staticcall(data);
                return _verifyCallResult(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) {
                require(isContract(target), "Address: delegate call to non-contract");
                // solhint-disable-next-line avoid-low-level-calls
                (bool success, bytes memory returndata) = target.delegatecall(data);
                return _verifyCallResult(success, returndata, errorMessage);
            }
            function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                if (success) {
                    return returndata;
                } else {
                    // 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
                        // solhint-disable-next-line no-inline-assembly
                        assembly {
                            let returndata_size := mload(returndata)
                            revert(add(32, returndata), returndata_size)
                        }
                    } else {
                        revert(errorMessage);
                    }
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /**
         * @dev Library for reading and writing primitive types to specific storage slots.
         *
         * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
         * This library helps with reading and writing to such slots without the need for inline assembly.
         *
         * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
         *
         * Example usage to set ERC1967 implementation slot:
         * ```
         * contract ERC1967 {
         *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
         *
         *     function _getImplementation() internal view returns (address) {
         *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
         *     }
         *
         *     function _setImplementation(address newImplementation) internal {
         *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
         *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
         *     }
         * }
         * ```
         *
         * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
         */
        library StorageSlot {
            struct AddressSlot {
                address value;
            }
            struct BooleanSlot {
                bool value;
            }
            struct Bytes32Slot {
                bytes32 value;
            }
            struct Uint256Slot {
                uint256 value;
            }
            /**
             * @dev Returns an `AddressSlot` with member `value` located at `slot`.
             */
            function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                assembly {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
             */
            function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                assembly {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
             */
            function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                assembly {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
             */
            function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                assembly {
                    r.slot := slot
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        import "../utils/Context.sol";
        /**
         * @dev Contract module which provides a basic access control mechanism, where
         * there is an account (an owner) that can be granted exclusive access to
         * specific functions.
         *
         * By default, the owner account will be the one that deploys the contract. This
         * can later be changed with {transferOwnership}.
         *
         * This module is used through inheritance. It will make available the modifier
         * `onlyOwner`, which can be applied to your functions to restrict their use to
         * the owner.
         */
        abstract contract Ownable is Context {
            address private _owner;
            event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            /**
             * @dev Initializes the contract setting the deployer as the initial owner.
             */
            constructor () {
                address msgSender = _msgSender();
                _owner = msgSender;
                emit OwnershipTransferred(address(0), msgSender);
            }
            /**
             * @dev Returns the address of the current owner.
             */
            function owner() public view virtual returns (address) {
                return _owner;
            }
            /**
             * @dev Throws if called by any account other than the owner.
             */
            modifier onlyOwner() {
                require(owner() == _msgSender(), "Ownable: caller is not the owner");
                _;
            }
            /**
             * @dev Leaves the contract without owner. It will not be possible to call
             * `onlyOwner` functions anymore. Can only be called by the current owner.
             *
             * NOTE: Renouncing ownership will leave the contract without an owner,
             * thereby removing any functionality that is only available to the owner.
             */
            function renounceOwnership() public virtual onlyOwner {
                emit OwnershipTransferred(_owner, address(0));
                _owner = address(0);
            }
            /**
             * @dev Transfers ownership of the contract to a new account (`newOwner`).
             * Can only be called by the current owner.
             */
            function transferOwnership(address newOwner) public virtual onlyOwner {
                require(newOwner != address(0), "Ownable: new owner is the zero address");
                emit OwnershipTransferred(_owner, newOwner);
                _owner = newOwner;
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.8.0;
        /*
         * @dev Provides information about the current execution context, including the
         * sender of the transaction and its data. While these are generally available
         * via msg.sender and msg.data, they should not be accessed in such a direct
         * manner, since when dealing with meta-transactions the account sending and
         * paying for execution may not be the actual sender (as far as an application
         * is concerned).
         *
         * This contract is only required for intermediate, library-like contracts.
         */
        abstract contract Context {
            function _msgSender() internal view virtual returns (address) {
                return msg.sender;
            }
            function _msgData() internal view virtual returns (bytes calldata) {
                this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                return msg.data;
            }
        }
        

        File 2 of 3: EACAggregatorProxy
        pragma solidity 0.6.6;
        
        
        /**
         * @title The Owned contract
         * @notice A contract with helpers for basic contract ownership.
         */
        contract Owned {
        
          address payable public owner;
          address private pendingOwner;
        
          event OwnershipTransferRequested(
            address indexed from,
            address indexed to
          );
          event OwnershipTransferred(
            address indexed from,
            address indexed to
          );
        
          constructor() public {
            owner = msg.sender;
          }
        
          /**
           * @dev Allows an owner to begin transferring ownership to a new address,
           * pending.
           */
          function transferOwnership(address _to)
            external
            onlyOwner()
          {
            pendingOwner = _to;
        
            emit OwnershipTransferRequested(owner, _to);
          }
        
          /**
           * @dev Allows an ownership transfer to be completed by the recipient.
           */
          function acceptOwnership()
            external
          {
            require(msg.sender == pendingOwner, "Must be proposed owner");
        
            address oldOwner = owner;
            owner = msg.sender;
            pendingOwner = address(0);
        
            emit OwnershipTransferred(oldOwner, msg.sender);
          }
        
          /**
           * @dev Reverts if called by anyone other than the contract owner.
           */
          modifier onlyOwner() {
            require(msg.sender == owner, "Only callable by owner");
            _;
          }
        
        }
        
        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);
        }
        
        interface AggregatorV3Interface {
        
          function decimals() external view returns (uint8);
          function description() external view returns (string memory);
          function version() external view returns (uint256);
        
          // getRoundData and latestRoundData should both raise "No data present"
          // if they do not have data to report, instead of returning unset values
          // which could be misinterpreted as actual reported values.
          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
            );
        
        }
        
        interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface
        {
        }
        
        /**
         * @title A trusted proxy for updating where current answers are read from
         * @notice This contract provides a consistent address for the
         * CurrentAnwerInterface but delegates where it reads from to the owner, who is
         * trusted to update it.
         */
        contract AggregatorProxy is AggregatorV2V3Interface, Owned {
        
          struct Phase {
            uint16 id;
            AggregatorV2V3Interface aggregator;
          }
          Phase private currentPhase;
          AggregatorV2V3Interface public proposedAggregator;
          mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators;
        
          uint256 constant private PHASE_OFFSET = 64;
          uint256 constant private PHASE_SIZE = 16;
          uint256 constant private MAX_ID = 2**(PHASE_OFFSET+PHASE_SIZE) - 1;
        
          constructor(address _aggregator) public Owned() {
            setAggregator(_aggregator);
          }
        
          /**
           * @notice Reads the current answer from aggregator delegated to.
           *
           * @dev #[deprecated] Use latestRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended latestRoundData
           * instead which includes better verification information.
           */
          function latestAnswer()
            public
            view
            virtual
            override
            returns (int256 answer)
          {
            return currentPhase.aggregator.latestAnswer();
          }
        
          /**
           * @notice Reads the last updated height from aggregator delegated to.
           *
           * @dev #[deprecated] Use latestRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended latestRoundData
           * instead which includes better verification information.
           */
          function latestTimestamp()
            public
            view
            virtual
            override
            returns (uint256 updatedAt)
          {
            return currentPhase.aggregator.latestTimestamp();
          }
        
          /**
           * @notice get past rounds answers
           * @param _roundId the answer number to retrieve the answer for
           *
           * @dev #[deprecated] Use getRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended getRoundData
           * instead which includes better verification information.
           */
          function getAnswer(uint256 _roundId)
            public
            view
            virtual
            override
            returns (int256 answer)
          {
            if (_roundId > MAX_ID) return 0;
        
            (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
            AggregatorV2V3Interface aggregator = phaseAggregators[phaseId];
            if (address(aggregator) == address(0)) return 0;
        
            return aggregator.getAnswer(aggregatorRoundId);
          }
        
          /**
           * @notice get block timestamp when an answer was last updated
           * @param _roundId the answer number to retrieve the updated timestamp for
           *
           * @dev #[deprecated] Use getRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended getRoundData
           * instead which includes better verification information.
           */
          function getTimestamp(uint256 _roundId)
            public
            view
            virtual
            override
            returns (uint256 updatedAt)
          {
            if (_roundId > MAX_ID) return 0;
        
            (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
            AggregatorV2V3Interface aggregator = phaseAggregators[phaseId];
            if (address(aggregator) == address(0)) return 0;
        
            return aggregator.getTimestamp(aggregatorRoundId);
          }
        
          /**
           * @notice get the latest completed round where the answer was updated. This
           * ID includes the proxy's phase, to make sure round IDs increase even when
           * switching to a newly deployed aggregator.
           *
           * @dev #[deprecated] Use latestRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended latestRoundData
           * instead which includes better verification information.
           */
          function latestRound()
            public
            view
            virtual
            override
            returns (uint256 roundId)
          {
            Phase memory phase = currentPhase; // cache storage reads
            return addPhase(phase.id, uint64(phase.aggregator.latestRound()));
          }
        
          /**
           * @notice get data about a round. Consumers are encouraged to check
           * that they're receiving fresh data by inspecting the updatedAt and
           * answeredInRound return values.
           * Note that different underlying implementations of AggregatorV3Interface
           * have slightly different semantics for some of the return values. Consumers
           * should determine what implementations they expect to receive
           * data from and validate that they can properly handle return data from all
           * of them.
           * @param _roundId the requested round ID as presented through the proxy, this
           * is made up of the aggregator's round ID with the phase ID encoded in the
           * two highest order bytes
           * @return roundId is the round ID from the aggregator for which the data was
           * retrieved combined with an phase to ensure that round IDs get larger as
           * time moves forward.
           * @return answer is the answer for the given round
           * @return startedAt is the timestamp when the round was started.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @return updatedAt is the timestamp when the round last was updated (i.e.
           * answer was last computed)
           * @return answeredInRound is the round ID of the round in which the answer
           * was computed.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @dev Note that answer and updatedAt may change between queries.
           */
          function getRoundData(uint80 _roundId)
            public
            view
            virtual
            override
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
        
            (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 ansIn
            ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId);
        
            return addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId);
          }
        
          /**
           * @notice get data about the latest round. Consumers are encouraged to check
           * that they're receiving fresh data by inspecting the updatedAt and
           * answeredInRound return values.
           * Note that different underlying implementations of AggregatorV3Interface
           * have slightly different semantics for some of the return values. Consumers
           * should determine what implementations they expect to receive
           * data from and validate that they can properly handle return data from all
           * of them.
           * @return roundId is the round ID from the aggregator for which the data was
           * retrieved combined with an phase to ensure that round IDs get larger as
           * time moves forward.
           * @return answer is the answer for the given round
           * @return startedAt is the timestamp when the round was started.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @return updatedAt is the timestamp when the round last was updated (i.e.
           * answer was last computed)
           * @return answeredInRound is the round ID of the round in which the answer
           * was computed.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @dev Note that answer and updatedAt may change between queries.
           */
          function latestRoundData()
            public
            view
            virtual
            override
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            Phase memory current = currentPhase; // cache storage reads
        
            (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 ansIn
            ) = current.aggregator.latestRoundData();
        
            return addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, current.id);
          }
        
          /**
           * @notice Used if an aggregator contract has been proposed.
           * @param _roundId the round ID to retrieve the round data for
           * @return roundId is the round ID for which data was retrieved
           * @return answer is the answer for the given round
           * @return startedAt is the timestamp when the round was started.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @return updatedAt is the timestamp when the round last was updated (i.e.
           * answer was last computed)
           * @return answeredInRound is the round ID of the round in which the answer
           * was computed.
          */
          function proposedGetRoundData(uint80 _roundId)
            public
            view
            virtual
            hasProposal()
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            return proposedAggregator.getRoundData(_roundId);
          }
        
          /**
           * @notice Used if an aggregator contract has been proposed.
           * @return roundId is the round ID for which data was retrieved
           * @return answer is the answer for the given round
           * @return startedAt is the timestamp when the round was started.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @return updatedAt is the timestamp when the round last was updated (i.e.
           * answer was last computed)
           * @return answeredInRound is the round ID of the round in which the answer
           * was computed.
          */
          function proposedLatestRoundData()
            public
            view
            virtual
            hasProposal()
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            return proposedAggregator.latestRoundData();
          }
        
          /**
           * @notice returns the current phase's aggregator address.
           */
          function aggregator()
            external
            view
            returns (address)
          {
            return address(currentPhase.aggregator);
          }
        
          /**
           * @notice returns the current phase's ID.
           */
          function phaseId()
            external
            view
            returns (uint16)
          {
            return currentPhase.id;
          }
        
          /**
           * @notice represents the number of decimals the aggregator responses represent.
           */
          function decimals()
            external
            view
            override
            returns (uint8)
          {
            return currentPhase.aggregator.decimals();
          }
        
          /**
           * @notice the version number representing the type of aggregator the proxy
           * points to.
           */
          function version()
            external
            view
            override
            returns (uint256)
          {
            return currentPhase.aggregator.version();
          }
        
          /**
           * @notice returns the description of the aggregator the proxy points to.
           */
          function description()
            external
            view
            override
            returns (string memory)
          {
            return currentPhase.aggregator.description();
          }
        
          /**
           * @notice Allows the owner to propose a new address for the aggregator
           * @param _aggregator The new address for the aggregator contract
           */
          function proposeAggregator(address _aggregator)
            external
            onlyOwner()
          {
            proposedAggregator = AggregatorV2V3Interface(_aggregator);
          }
        
          /**
           * @notice Allows the owner to confirm and change the address
           * to the proposed aggregator
           * @dev Reverts if the given address doesn't match what was previously
           * proposed
           * @param _aggregator The new address for the aggregator contract
           */
          function confirmAggregator(address _aggregator)
            external
            onlyOwner()
          {
            require(_aggregator == address(proposedAggregator), "Invalid proposed aggregator");
            delete proposedAggregator;
            setAggregator(_aggregator);
          }
        
        
          /*
           * Internal
           */
        
          function setAggregator(address _aggregator)
            internal
          {
            uint16 id = currentPhase.id + 1;
            currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator));
            phaseAggregators[id] = AggregatorV2V3Interface(_aggregator);
          }
        
          function addPhase(
            uint16 _phase,
            uint64 _originalId
          )
            internal
            view
            returns (uint80)
          {
            return uint80(uint256(_phase) << PHASE_OFFSET | _originalId);
          }
        
          function parseIds(
            uint256 _roundId
          )
            internal
            view
            returns (uint16, uint64)
          {
            uint16 phaseId = uint16(_roundId >> PHASE_OFFSET);
            uint64 aggregatorRoundId = uint64(_roundId);
        
            return (phaseId, aggregatorRoundId);
          }
        
          function addPhaseIds(
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound,
              uint16 phaseId
          )
            internal
            view
            returns (uint80, int256, uint256, uint256, uint80)
          {
            return (
              addPhase(phaseId, uint64(roundId)),
              answer,
              startedAt,
              updatedAt,
              addPhase(phaseId, uint64(answeredInRound))
            );
          }
        
          /*
           * Modifiers
           */
        
          modifier hasProposal() {
            require(address(proposedAggregator) != address(0), "No proposed aggregator present");
            _;
          }
        
        }
        
        interface AccessControllerInterface {
          function hasAccess(address user, bytes calldata data) external view returns (bool);
        }
        
        /**
         * @title External Access Controlled Aggregator Proxy
         * @notice A trusted proxy for updating where current answers are read from
         * @notice This contract provides a consistent address for the
         * Aggregator and AggregatorV3Interface but delegates where it reads from to the owner, who is
         * trusted to update it.
         * @notice Only access enabled addresses are allowed to access getters for
         * aggregated answers and round information.
         */
        contract EACAggregatorProxy is AggregatorProxy {
        
          AccessControllerInterface public accessController;
        
          constructor(
            address _aggregator,
            address _accessController
          )
            public
            AggregatorProxy(_aggregator)
          {
            setController(_accessController);
          }
        
          /**
           * @notice Allows the owner to update the accessController contract address.
           * @param _accessController The new address for the accessController contract
           */
          function setController(address _accessController)
            public
            onlyOwner()
          {
            accessController = AccessControllerInterface(_accessController);
          }
        
          /**
           * @notice Reads the current answer from aggregator delegated to.
           * @dev overridden function to add the checkAccess() modifier
           *
           * @dev #[deprecated] Use latestRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended latestRoundData
           * instead which includes better verification information.
           */
          function latestAnswer()
            public
            view
            override
            checkAccess()
            returns (int256)
          {
            return super.latestAnswer();
          }
        
          /**
           * @notice get the latest completed round where the answer was updated. This
           * ID includes the proxy's phase, to make sure round IDs increase even when
           * switching to a newly deployed aggregator.
           *
           * @dev #[deprecated] Use latestRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended latestRoundData
           * instead which includes better verification information.
           */
          function latestTimestamp()
            public
            view
            override
            checkAccess()
            returns (uint256)
          {
            return super.latestTimestamp();
          }
        
          /**
           * @notice get past rounds answers
           * @param _roundId the answer number to retrieve the answer for
           * @dev overridden function to add the checkAccess() modifier
           *
           * @dev #[deprecated] Use getRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended getRoundData
           * instead which includes better verification information.
           */
          function getAnswer(uint256 _roundId)
            public
            view
            override
            checkAccess()
            returns (int256)
          {
            return super.getAnswer(_roundId);
          }
        
          /**
           * @notice get block timestamp when an answer was last updated
           * @param _roundId the answer number to retrieve the updated timestamp for
           * @dev overridden function to add the checkAccess() modifier
           *
           * @dev #[deprecated] Use getRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended getRoundData
           * instead which includes better verification information.
           */
          function getTimestamp(uint256 _roundId)
            public
            view
            override
            checkAccess()
            returns (uint256)
          {
            return super.getTimestamp(_roundId);
          }
        
          /**
           * @notice get the latest completed round where the answer was updated
           * @dev overridden function to add the checkAccess() modifier
           *
           * @dev #[deprecated] Use latestRoundData instead. This does not error if no
           * answer has been reached, it will simply return 0. Either wait to point to
           * an already answered Aggregator or use the recommended latestRoundData
           * instead which includes better verification information.
           */
          function latestRound()
            public
            view
            override
            checkAccess()
            returns (uint256)
          {
            return super.latestRound();
          }
        
          /**
           * @notice get data about a round. Consumers are encouraged to check
           * that they're receiving fresh data by inspecting the updatedAt and
           * answeredInRound return values.
           * Note that different underlying implementations of AggregatorV3Interface
           * have slightly different semantics for some of the return values. Consumers
           * should determine what implementations they expect to receive
           * data from and validate that they can properly handle return data from all
           * of them.
           * @param _roundId the round ID to retrieve the round data for
           * @return roundId is the round ID from the aggregator for which the data was
           * retrieved combined with a phase to ensure that round IDs get larger as
           * time moves forward.
           * @return answer is the answer for the given round
           * @return startedAt is the timestamp when the round was started.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @return updatedAt is the timestamp when the round last was updated (i.e.
           * answer was last computed)
           * @return answeredInRound is the round ID of the round in which the answer
           * was computed.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @dev Note that answer and updatedAt may change between queries.
           */
          function getRoundData(uint80 _roundId)
            public
            view
            checkAccess()
            override
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            return super.getRoundData(_roundId);
          }
        
          /**
           * @notice get data about the latest round. Consumers are encouraged to check
           * that they're receiving fresh data by inspecting the updatedAt and
           * answeredInRound return values.
           * Note that different underlying implementations of AggregatorV3Interface
           * have slightly different semantics for some of the return values. Consumers
           * should determine what implementations they expect to receive
           * data from and validate that they can properly handle return data from all
           * of them.
           * @return roundId is the round ID from the aggregator for which the data was
           * retrieved combined with a phase to ensure that round IDs get larger as
           * time moves forward.
           * @return answer is the answer for the given round
           * @return startedAt is the timestamp when the round was started.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @return updatedAt is the timestamp when the round last was updated (i.e.
           * answer was last computed)
           * @return answeredInRound is the round ID of the round in which the answer
           * was computed.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @dev Note that answer and updatedAt may change between queries.
           */
          function latestRoundData()
            public
            view
            checkAccess()
            override
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            return super.latestRoundData();
          }
        
          /**
           * @notice Used if an aggregator contract has been proposed.
           * @param _roundId the round ID to retrieve the round data for
           * @return roundId is the round ID for which data was retrieved
           * @return answer is the answer for the given round
           * @return startedAt is the timestamp when the round was started.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @return updatedAt is the timestamp when the round last was updated (i.e.
           * answer was last computed)
           * @return answeredInRound is the round ID of the round in which the answer
           * was computed.
          */
          function proposedGetRoundData(uint80 _roundId)
            public
            view
            checkAccess()
            hasProposal()
            override
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            return super.proposedGetRoundData(_roundId);
          }
        
          /**
           * @notice Used if an aggregator contract has been proposed.
           * @return roundId is the round ID for which data was retrieved
           * @return answer is the answer for the given round
           * @return startedAt is the timestamp when the round was started.
           * (Only some AggregatorV3Interface implementations return meaningful values)
           * @return updatedAt is the timestamp when the round last was updated (i.e.
           * answer was last computed)
           * @return answeredInRound is the round ID of the round in which the answer
           * was computed.
          */
          function proposedLatestRoundData()
            public
            view
            checkAccess()
            hasProposal()
            override
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            return super.proposedLatestRoundData();
          }
        
          /**
           * @dev reverts if the caller does not have access by the accessController
           * contract or is the contract itself.
           */
          modifier checkAccess() {
            AccessControllerInterface ac = accessController;
            require(address(ac) == address(0) || ac.hasAccess(msg.sender, msg.data), "No access");
            _;
          }
        }

        File 3 of 3: AccessControlledOffchainAggregator
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.6;
        import "./OffchainAggregator.sol";
        import "./SimpleReadAccessController.sol";
        /**
         * @notice Wrapper of OffchainAggregator which checks read access on Aggregator-interface methods
         */
        contract AccessControlledOffchainAggregator is OffchainAggregator, SimpleReadAccessController {
          constructor(
            uint32 _maximumGasPrice,
            uint32 _reasonableGasPrice,
            uint32 _microLinkPerEth,
            uint32 _linkGweiPerObservation,
            uint32 _linkGweiPerTransmission,
            LinkTokenInterface _link,
            int192 _minAnswer,
            int192 _maxAnswer,
            AccessControllerInterface _billingAccessController,
            AccessControllerInterface _requesterAccessController,
            uint8 _decimals,
            string memory description
          )
            OffchainAggregator(
              _maximumGasPrice,
              _reasonableGasPrice,
              _microLinkPerEth,
              _linkGweiPerObservation,
              _linkGweiPerTransmission,
              _link,
              _minAnswer,
              _maxAnswer,
              _billingAccessController,
              _requesterAccessController,
              _decimals,
              description
            ) {
            }
          /*
           * Versioning
           */
          function typeAndVersion()
            external
            override
            pure
            virtual
            returns (string memory)
          {
            return "AccessControlledOffchainAggregator 4.0.0";
          }
          /*
           * v2 Aggregator interface
           */
          /// @inheritdoc OffchainAggregator
          function latestAnswer()
            public
            override
            view
            checkAccess()
            returns (int256)
          {
            return super.latestAnswer();
          }
          /// @inheritdoc OffchainAggregator
          function latestTimestamp()
            public
            override
            view
            checkAccess()
            returns (uint256)
          {
            return super.latestTimestamp();
          }
          /// @inheritdoc OffchainAggregator
          function latestRound()
            public
            override
            view
            checkAccess()
            returns (uint256)
          {
            return super.latestRound();
          }
          /// @inheritdoc OffchainAggregator
          function getAnswer(uint256 _roundId)
            public
            override
            view
            checkAccess()
            returns (int256)
          {
            return super.getAnswer(_roundId);
          }
          /// @inheritdoc OffchainAggregator
          function getTimestamp(uint256 _roundId)
            public
            override
            view
            checkAccess()
            returns (uint256)
          {
            return super.getTimestamp(_roundId);
          }
          /*
           * v3 Aggregator interface
           */
          /// @inheritdoc OffchainAggregator
          function description()
            public
            override
            view
            checkAccess()
            returns (string memory)
          {
            return super.description();
          }
          /// @inheritdoc OffchainAggregator
          function getRoundData(uint80 _roundId)
            public
            override
            view
            checkAccess()
            returns (
              uint80 roundId,
              int256 answer,
              uint256 startedAt,
              uint256 updatedAt,
              uint80 answeredInRound
            )
          {
            return super.getRoundData(_roundId);
          }
          /// @inheritdoc OffchainAggregator
          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.7.0;
        interface AccessControllerInterface {
          function hasAccess(address user, bytes calldata data) external view returns (bool);
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.7.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.7.0;
        import "./AggregatorInterface.sol";
        import "./AggregatorV3Interface.sol";
        interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface
        {
        }// SPDX-License-Identifier: MIT
        pragma solidity ^0.7.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.7.0;
        interface AggregatorValidatorInterface {
          function validate(
            uint256 previousRoundId,
            int256 previousAnswer,
            uint256 currentRoundId,
            int256 currentAnswer
          ) external returns (bool);
        }// SPDX-License-Identifier: MIT
        pragma solidity ^0.7.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.7.6;
        import "./AccessControllerInterface.sol";
        import "./AggregatorV2V3Interface.sol";
        import "./AggregatorValidatorInterface.sol";
        import "./LinkTokenInterface.sol";
        import "./Owned.sol";
        import "./OffchainAggregatorBilling.sol";
        import "./TypeAndVersionInterface.sol";
        /**
          * @notice Onchain verification of reports from the offchain reporting protocol
          * @dev For details on its operation, see the offchain reporting protocol design
          * @dev doc, which refers to this contract as simply the "contract".
        */
        contract OffchainAggregator is Owned, OffchainAggregatorBilling, AggregatorV2V3Interface, TypeAndVersionInterface {
          uint256 constant private maxUint32 = (1 << 32) - 1;
          // Storing these fields used on the hot path in a HotVars variable reduces the
          // retrieval of all of them to a single SLOAD. If any further fields are
          // added, make sure that storage of the struct still takes at most 32 bytes.
          struct HotVars {
            // Provides 128 bits of security against 2nd pre-image attacks, but only
            // 64 bits against collisions. This is acceptable, since a malicious owner has
            // easier way of messing up the protocol than to find hash collisions.
            bytes16 latestConfigDigest;
            uint40 latestEpochAndRound; // 32 most sig bits for epoch, 8 least sig bits for round
            // Current bound assumed on number of faulty/dishonest oracles participating
            // in the protocol, this value is referred to as f in the design
            uint8 threshold;
            // 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;
          }
          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
            uint64 timestamp;
          }
          mapping(uint32 /* aggregator round ID */ => Transmission) internal s_transmissions;
          // incremented each time a new config is posted. This count is incorporated
          // into the config digest, to prevent replay attacks.
          uint32 internal s_configCount;
          uint32 internal s_latestConfigBlockNumber; // makes it easier for offchain systems
                                                     // to extract config from logs.
          // 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;
          /*
           * @param _maximumGasPrice highest gas price for which transmitter will be compensated
           * @param _reasonableGasPrice transmitter will receive reward for gas prices under this value
           * @param _microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
           * @param _linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
           * @param _linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
           * @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 _billingAccessController access controller for billing admin functions
           * @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(
            uint32 _maximumGasPrice,
            uint32 _reasonableGasPrice,
            uint32 _microLinkPerEth,
            uint32 _linkGweiPerObservation,
            uint32 _linkGweiPerTransmission,
            LinkTokenInterface _link,
            int192 _minAnswer,
            int192 _maxAnswer,
            AccessControllerInterface _billingAccessController,
            AccessControllerInterface _requesterAccessController,
            uint8 _decimals,
            string memory _description
          )
            OffchainAggregatorBilling(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
              _linkGweiPerObservation, _linkGweiPerTransmission, _link,
              _billingAccessController
            )
          {
            decimals = _decimals;
            s_description = _description;
            setRequesterAccessController(_requesterAccessController);
            setValidatorConfig(AggregatorValidatorInterface(0x0), 0);
            minAnswer = _minAnswer;
            maxAnswer = _maxAnswer;
          }
          /*
           * Versioning
           */
          function typeAndVersion()
            external
            override
            pure
            virtual
            returns (string memory)
          {
            return "OffchainAggregator 4.0.0";
          }
          /*
           * Config logic
           */
          /**
           * @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 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 threshold maximum number of faulty/dishonest oracles the protocol can tolerate while still working correctly
           * @param encodedConfigVersion version of the serialization format used for "encoded" parameter
           * @param encoded serialized data used by oracles to configure their offchain operation
           */
          event ConfigSet(
            uint32 previousConfigBlockNumber,
            uint64 configCount,
            address[] signers,
            address[] transmitters,
            uint8 threshold,
            uint64 encodedConfigVersion,
            bytes encoded
          );
          // Reverts transaction if config args are invalid
          modifier checkConfigValid (
            uint256 _numSigners, uint256 _numTransmitters, uint256 _threshold
          ) {
            require(_numSigners <= maxNumOracles, "too many signers");
            require(_threshold > 0, "threshold must be positive");
            require(
              _numSigners == _numTransmitters,
              "oracle addresses out of registration"
            );
            require(_numSigners > 3*_threshold, "faulty-oracle threshold too high");
            _;
          }
          /**
           * @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 _threshold number of faulty oracles the system can tolerate
           * @param _encodedConfigVersion version number for offchainEncoding schema
           * @param _encoded encoded off-chain oracle configuration
           */
          function setConfig(
            address[] calldata _signers,
            address[] calldata _transmitters,
            uint8 _threshold,
            uint64 _encodedConfigVersion,
            bytes calldata _encoded
          )
            external
            checkConfigValid(_signers.length, _transmitters.length, _threshold)
            onlyOwner()
          {
            while (s_signers.length != 0) { // remove any old signer/transmitter addresses
              uint lastIdx = s_signers.length - 1;
              address signer = s_signers[lastIdx];
              address transmitter = s_transmitters[lastIdx];
              payOracle(transmitter);
              delete s_oracles[signer];
              delete s_oracles[transmitter];
              s_signers.pop();
              s_transmitters.pop();
            }
            for (uint i = 0; i < _signers.length; i++) { // add new signer/transmitter addresses
              require(
                s_oracles[_signers[i]].role == Role.Unset,
                "repeated signer address"
              );
              s_oracles[_signers[i]] = Oracle(uint8(i), Role.Signer);
              require(s_payees[_transmitters[i]] != address(0), "payee must be set");
              require(
                s_oracles[_transmitters[i]].role == Role.Unset,
                "repeated transmitter address"
              );
              s_oracles[_transmitters[i]] = Oracle(uint8(i), Role.Transmitter);
              s_signers.push(_signers[i]);
              s_transmitters.push(_transmitters[i]);
            }
            s_hotVars.threshold = _threshold;
            uint32 previousConfigBlockNumber = s_latestConfigBlockNumber;
            s_latestConfigBlockNumber = uint32(block.number);
            s_configCount += 1;
            uint64 configCount = s_configCount;
            {
              s_hotVars.latestConfigDigest = configDigestFromConfigData(
                address(this),
                configCount,
                _signers,
                _transmitters,
                _threshold,
                _encodedConfigVersion,
                _encoded
              );
              s_hotVars.latestEpochAndRound = 0;
            }
            emit ConfigSet(
              previousConfigBlockNumber,
              configCount,
              _signers,
              _transmitters,
              _threshold,
              _encodedConfigVersion,
              _encoded
            );
          }
          function configDigestFromConfigData(
            address _contractAddress,
            uint64 _configCount,
            address[] calldata _signers,
            address[] calldata _transmitters,
            uint8 _threshold,
            uint64 _encodedConfigVersion,
            bytes calldata _encodedConfig
          ) internal pure returns (bytes16) {
            return bytes16(keccak256(abi.encode(_contractAddress, _configCount,
              _signers, _transmitters, _threshold, _encodedConfigVersion, _encodedConfig
            )));
          }
          /**
           * @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
            returns (
              uint32 configCount,
              uint32 blockNumber,
              bytes16 configDigest
            )
          {
            return (s_configCount, s_latestConfigBlockNumber, s_hotVars.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 transmitters()
            external
            view
            returns(address[] memory)
          {
              return s_transmitters;
          }
          /*
           * On-chain validation logc
           */
          // 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 validatorConfig()
            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
                }
              }
            }
          }
          /*
           * requestNewRound logic
           */
          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, bytes16 configDigest, uint32 epoch, uint8 round);
          /**
           * @notice address of the requester access controller contract
           * @return requester access controller address
           */
          function requesterAccessController()
            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");
            HotVars memory hotVars = s_hotVars;
            emit RoundRequested(
              msg.sender,
              hotVars.latestConfigDigest,
              uint32(s_hotVars.latestEpochAndRound >> 8),
              uint8(s_hotVars.latestEpochAndRound)
            );
            return hotVars.latestAggregatorRoundId + 1;
          }
          /*
           * Transmission logic
           */
          /**
           * @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 this report
           * @param transmitter address from which the report was transmitted
           * @param observations observations transmitted with this report
           * @param rawReportContext signature-replay-prevention domain-separation tag
           */
          event NewTransmission(
            uint32 indexed aggregatorRoundId,
            int192 answer,
            address transmitter,
            int192[] observations,
            bytes observers,
            bytes32 rawReportContext
          );
          // decodeReport is used to check that the solidity and go code are using the
          // same format. See TestOffchainAggregator.testDecodeReport and TestReportParsing
          function decodeReport(bytes memory _report)
            internal
            pure
            returns (
              bytes32 rawReportContext,
              bytes32 rawObservers,
              int192[] memory observations
            )
          {
            (rawReportContext, rawObservers, observations) = abi.decode(_report,
              (bytes32, bytes32, int192[]));
          }
          // Used to relieve stack pressure in transmit
          struct ReportData {
            HotVars hotVars; // Only read from storage once
            bytes observers; // ith element is the index of the ith observer
            int192[] observations; // ith element is the ith observation
            bytes vs; // jth element is the v component of the jth signature
            bytes32 rawReportContext;
          }
          /*
           * @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 (
              bytes16 configDigest,
              uint32 epoch,
              uint8 round,
              int192 latestAnswer,
              uint64 latestTimestamp
            )
          {
            require(msg.sender == tx.origin, "Only callable by EOA");
            return (
              s_hotVars.latestConfigDigest,
              uint32(s_hotVars.latestEpochAndRound >> 8),
              uint8(s_hotVars.latestEpochAndRound),
              s_transmissions[s_hotVars.latestAggregatorRoundId].answer,
              s_transmissions[s_hotVars.latestAggregatorRoundId].timestamp
            );
          }
          // 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
          uint16 private constant TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT =
            4 + // function selector
            32 + // word containing start location of abiencoded _report value
            32 + // word containing location start 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
          function expectedMsgDataLength(
            bytes calldata _report, bytes32[] calldata _rs, bytes32[] calldata _ss
          ) private pure returns (uint256 length)
          {
            // calldata will never be big enough to make this overflow
            return uint256(TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT) +
              _report.length + // one byte pure entry in _report
              _rs.length * 32 + // 32 bytes per entry in _rs
              _ss.length * 32 + // 32 bytes per entry in _ss
              0; // placeholder
          }
          /**
           * @notice transmit is called to post a new report to the contract
           * @param _report serialized report, which the signatures are signing. See parsing code below for format. The ith element of the observers component must be the index in s_signers of the address for the ith signature
           * @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
            bytes calldata _report,
            bytes32[] calldata _rs, bytes32[] calldata _ss, bytes32 _rawVs // signatures
          )
            external
          {
            uint256 initialGas = gasleft(); // This line must come first
            // Make sure the transmit message-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. (Appendix G of the
            // yellow paper, p. 25, for G_txdatazero and EIP 2028 for G_txdatanonzero.)
            // This could amount to reimbursement profit of 36 million gas, given a 3MB
            // zero tail.
            require(msg.data.length == expectedMsgDataLength(_report, _rs, _ss),
              "transmit message too long");
            ReportData memory r; // Relieves stack pressure
            {
              r.hotVars = s_hotVars; // cache read from storage
              bytes32 rawObservers;
              (r.rawReportContext, rawObservers, r.observations) = abi.decode(
                _report, (bytes32, bytes32, int192[])
              );
              // rawReportContext consists of:
              // 11-byte zero padding
              // 16-byte configDigest
              // 4-byte epoch
              // 1-byte round
              bytes16 configDigest = bytes16(r.rawReportContext << 88);
              require(
                r.hotVars.latestConfigDigest == configDigest,
                "configDigest mismatch"
              );
              uint40 epochAndRound = uint40(uint256(r.rawReportContext));
              // direct numerical comparison works here, because
              //
              //   ((e,r) <= (e',r')) implies (epochAndRound <= epochAndRound')
              //
              // because alphabetic ordering implies e <= e', and if e = e', then r<=r',
              // so e*256+r <= e'*256+r', because r, r' < 256
              require(r.hotVars.latestEpochAndRound < epochAndRound, "stale report");
              require(_rs.length > r.hotVars.threshold, "not enough signatures");
              require(_rs.length <= maxNumOracles, "too many signatures");
              require(_ss.length == _rs.length, "signatures out of registration");
              require(r.observations.length <= maxNumOracles,
                      "num observations out of bounds");
              require(r.observations.length > 2 * r.hotVars.threshold,
                      "too few values to trust median");
              // Copy signature parities in bytes32 _rawVs to bytes r.v
              r.vs = new bytes(_rs.length);
              for (uint8 i = 0; i < _rs.length; i++) {
                r.vs[i] = _rawVs[i];
              }
              // Copy observer identities in bytes32 rawObservers to bytes r.observers
              r.observers = new bytes(r.observations.length);
              bool[maxNumOracles] memory seen;
              for (uint8 i = 0; i < r.observations.length; i++) {
                uint8 observerIdx = uint8(rawObservers[i]);
                require(!seen[observerIdx], "observer index repeated");
                seen[observerIdx] = true;
                r.observers[i] = rawObservers[i];
              }
              Oracle memory transmitter = s_oracles[msg.sender];
              require( // Check that sender is authorized to report
                transmitter.role == Role.Transmitter &&
                msg.sender == s_transmitters[transmitter.index],
                "unauthorized transmitter"
              );
              // record epochAndRound here, so that we don't have to carry the local
              // variable in transmit. The change is reverted if something fails later.
              r.hotVars.latestEpochAndRound = epochAndRound;
            }
            { // Verify signatures attached to report
              bytes32 h = keccak256(_report);
              bool[maxNumOracles] memory signed;
              Oracle memory o;
              for (uint i = 0; i < _rs.length; i++) {
                address signer = ecrecover(h, uint8(r.vs[i])+27, _rs[i], _ss[i]);
                o = s_oracles[signer];
                require(o.role == Role.Signer, "address not authorized to sign");
                require(!signed[o.index], "non-unique signature");
                signed[o.index] = true;
              }
            }
            { // Check the report contents, and record the result
              for (uint i = 0; i < r.observations.length - 1; i++) {
                bool inOrder = r.observations[i] <= r.observations[i+1];
                require(inOrder, "observations not sorted");
              }
              int192 median = r.observations[r.observations.length/2];
              require(minAnswer <= median && median <= maxAnswer, "median is out of min-max range");
              r.hotVars.latestAggregatorRoundId++;
              s_transmissions[r.hotVars.latestAggregatorRoundId] =
                Transmission(median, uint64(block.timestamp));
              emit NewTransmission(
                r.hotVars.latestAggregatorRoundId,
                median,
                msg.sender,
                r.observations,
                r.observers,
                r.rawReportContext
              );
              // Emit these for backwards compatability with offchain consumers
              // that only support legacy events
              emit NewRound(
                r.hotVars.latestAggregatorRoundId,
                address(0x0), // use zero address since we don't have anybody "starting" the round here
                block.timestamp
              );
              emit AnswerUpdated(
                median,
                r.hotVars.latestAggregatorRoundId,
                block.timestamp
              );
              validateAnswer(r.hotVars.latestAggregatorRoundId, median);
            }
            s_hotVars = r.hotVars;
            assert(initialGas < maxUint32);
            reimburseAndRewardOracles(uint32(initialGas), r.observers);
          }
          /*
           * v2 Aggregator interface
           */
          /**
           * @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].timestamp;
          }
          /**
           * @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)].timestamp;
          }
          /*
           * v3 Aggregator interface
           */
          string constant private V3_NO_DATA_ERROR = "No data present";
          /**
           * @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 = 4;
          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 block in which report from given _roundId was transmitted
           * @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
            )
          {
            require(_roundId <= 0xFFFFFFFF, V3_NO_DATA_ERROR);
            Transmission memory transmission = s_transmissions[uint32(_roundId)];
            return (
              _roundId,
              transmission.answer,
              transmission.timestamp,
              transmission.timestamp,
              _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 block containing latest report
           * @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
            )
          {
            roundId = s_hotVars.latestAggregatorRoundId;
            // Skipped for compatability with existing FluxAggregator in which latestRoundData never reverts.
            // require(roundId != 0, V3_NO_DATA_ERROR);
            Transmission memory transmission = s_transmissions[uint32(roundId)];
            return (
              roundId,
              transmission.answer,
              transmission.timestamp,
              transmission.timestamp,
              roundId
            );
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.6;
        import "./AccessControllerInterface.sol";
        import "./LinkTokenInterface.sol";
        import "./Owned.sol";
        /**
         * @notice tracks administration of oracle-reward and gas-reimbursement parameters.
         * @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
         * 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 OffchainAggregatorBilling is Owned {
          // Maximum number of oracles the offchain reporting protocol is designed for
          uint256 constant internal maxNumOracles = 31;
          // Parameters for oracle payments
          struct Billing {
            // Highest compensated gas price, in ETH-gwei uints
            uint32 maximumGasPrice;
            // If gas price is less (in ETH-gwei units), transmitter gets half the savings
            uint32 reasonableGasPrice;
            // Pay transmitter back this much LINK per unit eth spent on gas
            // (1e-6LINK/ETH units)
            uint32 microLinkPerEth;
            // Fixed LINK reward for each observer, in LINK-gwei units
            uint32 linkGweiPerObservation;
            // Fixed reward for transmitter, in linkGweiPerObservation units
            uint32 linkGweiPerTransmission;
          }
          Billing internal s_billing;
          // We assume that the token contract is correct. This contract is not written
          // to handle misbehaving ERC20 tokens!
          LinkTokenInterface internal s_linkToken;
          AccessControllerInterface internal s_billingAccessController;
          // ith element is number of observation rewards due to ith process, plus one.
          // This is expected to saturate after an oracle has submitted 65,535
          // observations, or about 65535/(3*24*20) = 45 days, given a transmission
          // every 3 minutes.
          //
          // This is always one greater than the actual value, so that when the value is
          // reset to zero, we don't end up with a zero value in storage (which would
          // result in a higher gas cost, the next time the value is incremented.)
          // Calculations using this variable need to take that offset into account.
          uint16[maxNumOracles] internal s_oracleObservationsCounts;
          // 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;
          // LINK-wei-denominated reimbursements for gas used by transmitters.
          //
          // This is always one greater than the actual value, so that when the value is
          // reset to zero, we don't end up with a zero value in storage (which would
          // result in a higher gas cost, the next time the value is incremented.)
          // Calculations using this variable need to take that offset into account.
          //
          // Argument for overflow safety:
          // We have the following maximum intermediate values:
          // - 2**40 additions to this variable (epochAndRound is a uint40)
          // - 2**32 gas price in ethgwei/gas
          // - 1e9 ethwei/ethgwei
          // - 2**32 gas since the block gas limit is at ~20 million
          // - 2**32 (microlink/eth)
          // And we have 2**40 * 2**32 * 1e9 * 2**32 * 2**32 < 2**166
          // (we also divide in some places, but that only makes the value smaller)
          // We can thus safely use uint256 intermediate values for the computation
          // updating this variable.
          uint256[maxNumOracles] internal s_gasReimbursementsLinkWei;
          // Used for s_oracles[a].role, where a is an address, to track the purpose
          // of the address, or to indicate that the address is unset.
          enum Role {
            // No oracle role has been set for address a
            Unset,
            // Signing address for the s_oracles[a].index'th oracle. I.e., report
            // signatures from this oracle should ecrecover back to address a.
            Signer,
            // Transmission address for the s_oracles[a].index'th oracle. I.e., if a
            // report is received by OffchainAggregator.transmit in which msg.sender is
            // a, it is attributed to the s_oracles[a].index'th oracle.
            Transmitter
          }
          struct Oracle {
            uint8 index; // Index of oracle in s_signers/s_transmitters
            Role role;   // Role of the address which mapped to this struct
          }
          mapping (address /* signer OR transmitter address */ => Oracle)
            internal s_oracles;
          // s_signers contains the signing address of each oracle
          address[] internal s_signers;
          // s_transmitters contains the transmission address of each oracle,
          // i.e. the address the oracle actually sends transactions to the contract from
          address[] internal s_transmitters;
          uint256 constant private  maxUint16 = (1 << 16) - 1;
          uint256 constant internal maxUint128 = (1 << 128) - 1;
          constructor(
            uint32 _maximumGasPrice,
            uint32 _reasonableGasPrice,
            uint32 _microLinkPerEth,
            uint32 _linkGweiPerObservation,
            uint32 _linkGweiPerTransmission,
            LinkTokenInterface _link,
            AccessControllerInterface _billingAccessController
          )
          {
            setBillingInternal(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
              _linkGweiPerObservation, _linkGweiPerTransmission);
            s_linkToken = _link;
            emit LinkTokenSet(LinkTokenInterface(address(0)), _link);
            setBillingAccessControllerInternal(_billingAccessController);
            uint16[maxNumOracles] memory counts; // See s_oracleObservationsCounts docstring
            uint256[maxNumOracles] memory gas; // see s_gasReimbursementsLinkWei docstring
            for (uint8 i = 0; i < maxNumOracles; i++) {
              counts[i] = 1;
              gas[i] = 1;
            }
            s_oracleObservationsCounts = counts;
            s_gasReimbursementsLinkWei = gas;
          }
          /*
           * @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 transfered
           * 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;
          }
          /**
           * @notice emitted when billing parameters are set
           * @param maximumGasPrice highest gas price for which transmitter will be compensated
           * @param reasonableGasPrice transmitter will receive reward for gas prices under this value
           * @param microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
           * @param linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
           * @param linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
           */
          event BillingSet(
            uint32 maximumGasPrice,
            uint32 reasonableGasPrice,
            uint32 microLinkPerEth,
            uint32 linkGweiPerObservation,
            uint32 linkGweiPerTransmission
          );
          function setBillingInternal(
            uint32 _maximumGasPrice,
            uint32 _reasonableGasPrice,
            uint32 _microLinkPerEth,
            uint32 _linkGweiPerObservation,
            uint32 _linkGweiPerTransmission
          )
            internal
          {
            s_billing = Billing(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
              _linkGweiPerObservation, _linkGweiPerTransmission);
            emit BillingSet(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
              _linkGweiPerObservation, _linkGweiPerTransmission);
          }
          /**
           * @notice sets billing parameters
           * @param _maximumGasPrice highest gas price for which transmitter will be compensated
           * @param _reasonableGasPrice transmitter will receive reward for gas prices under this value
           * @param _microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
           * @param _linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
           * @param _linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
           * @dev access control provided by billingAccessController
           */
          function setBilling(
            uint32 _maximumGasPrice,
            uint32 _reasonableGasPrice,
            uint32 _microLinkPerEth,
            uint32 _linkGweiPerObservation,
            uint32 _linkGweiPerTransmission
          )
            external
          {
            AccessControllerInterface access = s_billingAccessController;
            require(msg.sender == owner || access.hasAccess(msg.sender, msg.data),
              "Only owner&billingAdmin can call");
            payOracles();
            setBillingInternal(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
              _linkGweiPerObservation, _linkGweiPerTransmission);
          }
          /**
           * @notice gets billing parameters
           * @param maximumGasPrice highest gas price for which transmitter will be compensated
           * @param reasonableGasPrice transmitter will receive reward for gas prices under this value
           * @param microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
           * @param linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
           * @param linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
           */
          function getBilling()
            external
            view
            returns (
              uint32 maximumGasPrice,
              uint32 reasonableGasPrice,
              uint32 microLinkPerEth,
              uint32 linkGweiPerObservation,
              uint32 linkGweiPerTransmission
            )
          {
            Billing memory billing = s_billing;
            return (
              billing.maximumGasPrice,
              billing.reasonableGasPrice,
              billing.microLinkPerEth,
              billing.linkGweiPerObservation,
              billing.linkGweiPerTransmission
            );
          }
          /**
           * @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 setBillingAccessControllerInternal(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
          {
            setBillingAccessControllerInternal(_billingAccessController);
          }
          /**
           * @notice gets billingAccessController
           * @return address of billingAccessController contract
           */
          function billingAccessController()
            external
            view
            returns (AccessControllerInterface)
          {
            return s_billingAccessController;
          }
          /**
           * @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
           * @param _transmitter the transmitter address of the oracle
           */
          function owedPayment(address _transmitter)
            public
            view
            returns (uint256)
          {
            Oracle memory oracle = s_oracles[_transmitter];
            if (oracle.role == Role.Unset) { return 0; }
            Billing memory billing = s_billing;
            uint256 linkWeiAmount =
              uint256(s_oracleObservationsCounts[oracle.index] - 1) *
              uint256(billing.linkGweiPerObservation) *
              (1 gwei);
            linkWeiAmount += s_gasReimbursementsLinkWei[oracle.index] - 1;
            return linkWeiAmount;
          }
          /**
           * @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 _transmitter)
            internal
          {
            Oracle memory oracle = s_oracles[_transmitter];
            uint256 linkWeiAmount = owedPayment(_transmitter);
            if (linkWeiAmount > 0) {
              address payee = s_payees[_transmitter];
              // Poses no re-entrancy issues, because LINK.transfer does not yield
              // control flow.
              require(s_linkToken.transfer(payee, linkWeiAmount), "insufficient funds");
              s_oracleObservationsCounts[oracle.index] = 1; // "zero" the counts. see var's docstring
              s_gasReimbursementsLinkWei[oracle.index] = 1; // "zero" the counts. see var's docstring
              emit OraclePaid(_transmitter, payee, linkWeiAmount, 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
          {
            Billing memory billing = s_billing;
            LinkTokenInterface linkToken = s_linkToken;
            uint16[maxNumOracles] memory observationsCounts = s_oracleObservationsCounts;
            uint256[maxNumOracles] memory gasReimbursementsLinkWei =
              s_gasReimbursementsLinkWei;
            address[] memory transmitters = s_transmitters;
            for (uint transmitteridx = 0; transmitteridx < transmitters.length; transmitteridx++) {
              uint256 reimbursementAmountLinkWei = gasReimbursementsLinkWei[transmitteridx] - 1;
              uint256 obsCount = observationsCounts[transmitteridx] - 1;
              uint256 linkWeiAmount =
                obsCount * uint256(billing.linkGweiPerObservation) * (1 gwei) + reimbursementAmountLinkWei;
              if (linkWeiAmount > 0) {
                  address payee = s_payees[transmitters[transmitteridx]];
                  // Poses no re-entrancy issues, because LINK.transfer does not yield
                  // control flow.
                  require(linkToken.transfer(payee, linkWeiAmount), "insufficient funds");
                  observationsCounts[transmitteridx] = 1;       // "zero" the counts.
                  gasReimbursementsLinkWei[transmitteridx] = 1; // "zero" the counts.
                  emit OraclePaid(transmitters[transmitteridx], payee, linkWeiAmount, linkToken);
                }
            }
            // "Zero" the accounting storage variables
            s_oracleObservationsCounts = observationsCounts;
            s_gasReimbursementsLinkWei = gasReimbursementsLinkWei;
          }
          function oracleRewards(
            bytes memory observers,
            uint16[maxNumOracles] memory observations
          )
            internal
            pure
            returns (uint16[maxNumOracles] memory)
          {
            // reward each observer-participant with the observer reward
            for (uint obsIdx = 0; obsIdx < observers.length; obsIdx++) {
              uint8 observer = uint8(observers[obsIdx]);
              observations[observer] = saturatingAddUint16(observations[observer], 1);
            }
            return observations;
          }
          // This value needs to change if maxNumOracles is increased, or the accounting
          // calculations at the bottom of reimburseAndRewardOracles change.
          //
          // To recalculate it, run the profiler as described in
          // ../../profile/README.md, and add up the gas-usage values reported for the
          // lines in reimburseAndRewardOracles following the "gasLeft = gasleft()"
          // line. E.g., you will see output like this:
          //
          //      7        uint256 gasLeft = gasleft();
          //     29        uint256 gasCostEthWei = transmitterGasCostEthWei(
          //      9          uint256(initialGas),
          //      3          gasPrice,
          //      3          callDataGasCost,
          //      3          gasLeft
          //      .
          //      .
          //      .
          //     59        uint256 gasCostLinkWei = (gasCostEthWei * billing.microLinkPerEth)/ 1e6;
          //      .
          //      .
          //      .
          //   5047        s_gasReimbursementsLinkWei[txOracle.index] =
          //    856          s_gasReimbursementsLinkWei[txOracle.index] + gasCostLinkWei +
          //     26          uint256(billing.linkGweiPerTransmission) * (1 gwei);
          //
          // If those were the only lines to be accounted for, you would add up
          // 29+9+3+3+3+59+5047+856+26=6035.
          uint256 internal constant accountingGasCost = 6035;
          // Uncomment the following declaration to compute the remaining gas cost after
          // above gasleft(). (This must exist in a base class to OffchainAggregator, so
          // it can't go in TestOffchainAggregator.)
          //
          // uint256 public gasUsedInAccounting;
          // Gas price at which the transmitter should be reimbursed, in ETH-gwei/gas
          function impliedGasPrice(
            uint256 txGasPrice,         // ETH-gwei/gas units
            uint256 reasonableGasPrice, // ETH-gwei/gas units
            uint256 maximumGasPrice     // ETH-gwei/gas units
          )
            internal
            pure
            returns (uint256)
          {
            // Reward the transmitter for choosing an efficient gas price: if they manage
            // to come in lower than considered reasonable, give them half the savings.
            //
            // The following calculations are all in units of gwei/gas, i.e. 1e-9ETH/gas
            uint256 gasPrice = txGasPrice;
            if (txGasPrice < reasonableGasPrice) {
              // Give transmitter half the savings for coming in under the reasonable gas price
              gasPrice += (reasonableGasPrice - txGasPrice) / 2;
            }
            // Don't reimburse a gas price higher than maximumGasPrice
            return min(gasPrice, maximumGasPrice);
          }
          // gas reimbursement due the transmitter, in ETH-wei
          //
          // If this function is changed, accountingGasCost needs to change, too. See
          // its docstring
          function transmitterGasCostEthWei(
            uint256 initialGas,
            uint256 gasPrice, // ETH-gwei/gas units
            uint256 callDataCost, // gas units
            uint256 gasLeft
          )
            internal
            pure
            returns (uint128 gasCostEthWei)
          {
            require(initialGas >= gasLeft, "gasLeft cannot exceed initialGas");
            uint256 gasUsed = // gas units
              initialGas - gasLeft + // observed gas usage
              callDataCost + accountingGasCost; // estimated gas usage
            // gasUsed is in gas units, gasPrice is in ETH-gwei/gas units; convert to ETH-wei
            uint256 fullGasCostEthWei = gasUsed * gasPrice * (1 gwei);
            assert(fullGasCostEthWei < maxUint128); // the entire ETH supply fits in a uint128...
            return uint128(fullGasCostEthWei);
          }
          /**
           * @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.
          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 billing.linkGweiPerObservation, 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 166
            //   bits (see s_gasReimbursementsLinkWei docstring). Hence 171 bits are
            //   sufficient for this part
            // In total, 172 bits are enough.
            uint16[maxNumOracles] memory observationCounts = s_oracleObservationsCounts;
            for (uint i = 0; i < maxNumOracles; i++) {
              linkDue += observationCounts[i] - 1; // Stored value is one greater than actual value
            }
            Billing memory billing = s_billing;
            // Convert linkGweiPerObservation to uint256, or this overflows!
            linkDue *= uint256(billing.linkGweiPerObservation) * (1 gwei);
            address[] memory transmitters = s_transmitters;
            uint256[maxNumOracles] memory gasReimbursementsLinkWei =
              s_gasReimbursementsLinkWei;
            for (uint i = 0; i < transmitters.length; i++) {
              linkDue += uint256(gasReimbursementsLinkWei[i]-1); // Stored value is one greater than actual value
            }
          }
          /**
           * @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**172, 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 _signerOrTransmitter address used by oracle for signing or transmitting reports
           */
          function oracleObservationCount(address _signerOrTransmitter)
            external
            view
            returns (uint16)
          {
            Oracle memory oracle = s_oracles[_signerOrTransmitter];
            if (oracle.role == Role.Unset) { return 0; }
            return s_oracleObservationsCounts[oracle.index] - 1;
          }
          function reimburseAndRewardOracles(
            uint32 initialGas,
            bytes memory observers
          )
            internal
          {
            Oracle memory txOracle = s_oracles[msg.sender];
            Billing memory billing = s_billing;
            // Reward oracles for providing observations. Oracles are not rewarded
            // for providing signatures, because signing is essentially free.
            s_oracleObservationsCounts =
              oracleRewards(observers, s_oracleObservationsCounts);
            // Reimburse transmitter of the report for gas usage
            require(txOracle.role == Role.Transmitter,
              "sent by undesignated transmitter"
            );
            uint256 gasPrice = impliedGasPrice(
              tx.gasprice / (1 gwei), // convert to ETH-gwei units
              billing.reasonableGasPrice,
              billing.maximumGasPrice
            );
            // 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;
            // If any changes are made to subsequent calculations, accountingGasCost
            // needs to change, too.
            uint256 gasLeft = gasleft();
            uint256 gasCostEthWei = transmitterGasCostEthWei(
              uint256(initialGas),
              gasPrice,
              callDataGasCost,
              gasLeft
            );
            // microLinkPerEth is 1e-6LINK/ETH units, gasCostEthWei is 1e-18ETH units
            // (ETH-wei), product is 1e-24LINK-wei units, dividing by 1e6 gives
            // 1e-18LINK units, i.e. LINK-wei units
            // Safe from over/underflow, since all components are non-negative,
            // gasCostEthWei will always fit into uint128 and microLinkPerEth is a
            // uint32 (128+32 < 256!).
            uint256 gasCostLinkWei = (gasCostEthWei * billing.microLinkPerEth)/ 1e6;
            // Safe from overflow, because gasCostLinkWei < 2**160 and
            // billing.linkGweiPerTransmission * (1 gwei) < 2**64 and we increment
            // s_gasReimbursementsLinkWei[txOracle.index] at most 2**40 times.
            s_gasReimbursementsLinkWei[txOracle.index] =
              s_gasReimbursementsLinkWei[txOracle.index] + gasCostLinkWei +
              uint256(billing.linkGweiPerTransmission) * (1 gwei); // convert from linkGwei to linkWei
            // Uncomment next line to compute the remaining gas cost after above gasleft().
            // See OffchainAggregatorBilling.accountingGasCost docstring for more information.
            //
            // gasUsedInAccounting = gasLeft - gasleft();
          }
          /*
           * Payee management
           */
          /**
           * @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 payeee 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 payeee 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);
          }
          /*
           * Helper functions
           */
          function saturatingAddUint16(uint16 _x, uint16 _y)
            internal
            pure
            returns (uint16)
          {
            return uint16(min(uint256(_x)+uint256(_y), maxUint16));
          }
          function min(uint256 a, uint256 b)
            internal
            pure
            returns (uint256)
          {
            if (a < b) { return a; }
            return b;
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.6;
        /**
         * @title The Owned contract
         * @notice A contract with helpers for basic contract ownership.
         */
        contract Owned {
          address payable public owner;
          address private pendingOwner;
          event OwnershipTransferRequested(
            address indexed from,
            address indexed to
          );
          event OwnershipTransferred(
            address indexed from,
            address indexed to
          );
          constructor() {
            owner = msg.sender;
          }
          /**
           * @dev Allows an owner to begin transferring ownership to a new address,
           * pending.
           */
          function transferOwnership(address _to)
            external
            onlyOwner()
          {
            pendingOwner = _to;
            emit OwnershipTransferRequested(owner, _to);
          }
          /**
           * @dev Allows an ownership transfer to be completed by the recipient.
           */
          function acceptOwnership()
            external
          {
            require(msg.sender == pendingOwner, "Must be proposed owner");
            address oldOwner = owner;
            owner = msg.sender;
            pendingOwner = address(0);
            emit OwnershipTransferred(oldOwner, msg.sender);
          }
          /**
           * @dev Reverts if called by anyone other than the contract owner.
           */
          modifier onlyOwner() {
            require(msg.sender == owner, "Only callable by owner");
            _;
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.6;
        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.7.6;
        import "./Owned.sol";
        import "./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, Owned {
          bool public checkEnabled;
          mapping(address => bool) internal accessList;
          event AddedAccess(address user);
          event RemovedAccess(address user);
          event CheckAccessEnabled();
          event CheckAccessDisabled();
          constructor()
          {
            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() {
            addAccessInternal(_user);
          }
          function addAccessInternal(address _user) internal {
            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.7.0;
        abstract contract TypeAndVersionInterface{
          function typeAndVersion()
            external
            pure
            virtual
            returns (string memory);
        }