ETH Price: $1,905.03 (-0.93%)

Transaction Decoder

Block:
20237285 at Jul-05-2024 02:20:59 AM +UTC
Transaction Fee:
0.0006834201737055 ETH $1.30
Gas Used:
131,725 Gas / 5.18823438 Gwei

Emitted Events:

285 TransparentUpgradeableProxy.0x4d8aead3491b7eba4b5c7a65fc17e493b9e63f9e433522fc5f6a85a168fc9d36( 0x4d8aead3491b7eba4b5c7a65fc17e493b9e63f9e433522fc5f6a85a168fc9d36, 0x000000000000000000000000d7f2b7fdcc012db94c545e3b50d2487b239b856d, 0x000000000000000000000000000000000000000000000000000000000000dc15, 0x0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000020af4ca4b1bb4e, 00000000000000000000000000000000000000000000000188e62119495e0800, 000000000000000000000000000000000000000000000000000000006687588b )

Account State Difference:

  Address   Before After State Difference Code
0x05811Df0...d0c0ED505
(Titan Builder)
12.157865979963400509 Eth12.157897297146535934 Eth0.000031317183135425
0x989593B2...109c0C490 3.044379284942485793 Eth3.053579227912713327 Eth0.009199942970227534
0xd7F2b7fd...b239b856D
0.014154980342897392 Eth
Nonce: 19
0.004271617198964358 Eth
Nonce: 20
0.009883363143933034

Execution Trace

ETH 0.009199942970227534 TransparentUpgradeableProxy.94dc9cf3( )
  • ETH 0.009199942970227534 EthereumPresale.buyWithETH( amount=56341 )
    • EACAggregatorProxy.STATICCALL( )
      • AccessControlledOffchainAggregator.STATICCALL( )
      • ETH 0.009199942970227534 0x989593b2b035cf547c84793516260f9109c0c490.CALL( )
        File 1 of 4: TransparentUpgradeableProxy
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
        pragma solidity ^0.8.20;
        import {Context} from "../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.
         *
         * The initial owner is set to the address provided by the deployer. 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;
            /**
             * @dev The caller account is not authorized to perform an operation.
             */
            error OwnableUnauthorizedAccount(address account);
            /**
             * @dev The owner is not a valid owner account. (eg. `address(0)`)
             */
            error OwnableInvalidOwner(address owner);
            event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            /**
             * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
             */
            constructor(address initialOwner) {
                if (initialOwner == address(0)) {
                    revert OwnableInvalidOwner(address(0));
                }
                _transferOwnership(initialOwner);
            }
            /**
             * @dev Throws if called by any account other than the owner.
             */
            modifier onlyOwner() {
                _checkOwner();
                _;
            }
            /**
             * @dev Returns the address of the current owner.
             */
            function owner() public view virtual returns (address) {
                return _owner;
            }
            /**
             * @dev Throws if the sender is not the owner.
             */
            function _checkOwner() internal view virtual {
                if (owner() != _msgSender()) {
                    revert OwnableUnauthorizedAccount(_msgSender());
                }
            }
            /**
             * @dev Leaves the contract without owner. It will not be possible to call
             * `onlyOwner` functions. Can only be called by the current owner.
             *
             * NOTE: Renouncing ownership will leave the contract without an owner,
             * thereby disabling any functionality that is only available to the owner.
             */
            function renounceOwnership() public virtual onlyOwner {
                _transferOwnership(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 {
                if (newOwner == address(0)) {
                    revert OwnableInvalidOwner(address(0));
                }
                _transferOwnership(newOwner);
            }
            /**
             * @dev Transfers ownership of the contract to a new account (`newOwner`).
             * Internal function without access restriction.
             */
            function _transferOwnership(address newOwner) internal virtual {
                address oldOwner = _owner;
                _owner = newOwner;
                emit OwnershipTransferred(oldOwner, newOwner);
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol)
        pragma solidity ^0.8.20;
        /**
         * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
         */
        interface IERC1967 {
            /**
             * @dev Emitted when the implementation is upgraded.
             */
            event Upgraded(address indexed implementation);
            /**
             * @dev Emitted when the admin account has changed.
             */
            event AdminChanged(address previousAdmin, address newAdmin);
            /**
             * @dev Emitted when the beacon is changed.
             */
            event BeaconUpgraded(address indexed beacon);
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
        pragma solidity ^0.8.20;
        /**
         * @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.
             *
             * {UpgradeableBeacon} will check that this address is a contract.
             */
            function implementation() external view returns (address);
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Proxy.sol)
        pragma solidity ^0.8.20;
        import {Proxy} from "../Proxy.sol";
        import {ERC1967Utils} from "./ERC1967Utils.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 {
            /**
             * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`.
             *
             * If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an
             * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.
             *
             * Requirements:
             *
             * - If `data` is empty, `msg.value` must be zero.
             */
            constructor(address implementation, bytes memory _data) payable {
                ERC1967Utils.upgradeToAndCall(implementation, _data);
            }
            /**
             * @dev Returns the current implementation address.
             *
             * 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() internal view virtual override returns (address) {
                return ERC1967Utils.getImplementation();
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
        pragma solidity ^0.8.20;
        import {IBeacon} from "../beacon/IBeacon.sol";
        import {Address} from "../../utils/Address.sol";
        import {StorageSlot} from "../../utils/StorageSlot.sol";
        /**
         * @dev This abstract contract provides getters and event emitting update functions for
         * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
         */
        library ERC1967Utils {
            // We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
            // This will be fixed in Solidity 0.8.21. At that point we should remove these events.
            /**
             * @dev Emitted when the implementation is upgraded.
             */
            event Upgraded(address indexed implementation);
            /**
             * @dev Emitted when the admin account has changed.
             */
            event AdminChanged(address previousAdmin, address newAdmin);
            /**
             * @dev Emitted when the beacon is changed.
             */
            event BeaconUpgraded(address indexed beacon);
            /**
             * @dev Storage slot with the address of the current implementation.
             * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
             */
            // solhint-disable-next-line private-vars-leading-underscore
            bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
            /**
             * @dev The `implementation` of the proxy is invalid.
             */
            error ERC1967InvalidImplementation(address implementation);
            /**
             * @dev The `admin` of the proxy is invalid.
             */
            error ERC1967InvalidAdmin(address admin);
            /**
             * @dev The `beacon` of the proxy is invalid.
             */
            error ERC1967InvalidBeacon(address beacon);
            /**
             * @dev An upgrade function sees `msg.value > 0` that may be lost.
             */
            error ERC1967NonPayable();
            /**
             * @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 {
                if (newImplementation.code.length == 0) {
                    revert ERC1967InvalidImplementation(newImplementation);
                }
                StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
            }
            /**
             * @dev Performs implementation upgrade with additional setup call if data is nonempty.
             * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
             * to avoid stuck value in the contract.
             *
             * Emits an {IERC1967-Upgraded} event.
             */
            function upgradeToAndCall(address newImplementation, bytes memory data) internal {
                _setImplementation(newImplementation);
                emit Upgraded(newImplementation);
                if (data.length > 0) {
                    Address.functionDelegateCall(newImplementation, data);
                } else {
                    _checkNonPayable();
                }
            }
            /**
             * @dev Storage slot with the admin of the contract.
             * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
             */
            // solhint-disable-next-line private-vars-leading-underscore
            bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
            /**
             * @dev Returns the current admin.
             *
             * 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 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 {
                if (newAdmin == address(0)) {
                    revert ERC1967InvalidAdmin(address(0));
                }
                StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
            }
            /**
             * @dev Changes the admin of the proxy.
             *
             * Emits an {IERC1967-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 the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
             */
            // solhint-disable-next-line private-vars-leading-underscore
            bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
            /**
             * @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 {
                if (newBeacon.code.length == 0) {
                    revert ERC1967InvalidBeacon(newBeacon);
                }
                StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
                address beaconImplementation = IBeacon(newBeacon).implementation();
                if (beaconImplementation.code.length == 0) {
                    revert ERC1967InvalidImplementation(beaconImplementation);
                }
            }
            /**
             * @dev Change the beacon and trigger a setup call if data is nonempty.
             * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
             * to avoid stuck value in the contract.
             *
             * Emits an {IERC1967-BeaconUpgraded} event.
             *
             * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
             * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
             * efficiency.
             */
            function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
                _setBeacon(newBeacon);
                emit BeaconUpgraded(newBeacon);
                if (data.length > 0) {
                    Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                } else {
                    _checkNonPayable();
                }
            }
            /**
             * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
             * if an upgrade doesn't perform an initialization call.
             */
            function _checkNonPayable() private {
                if (msg.value > 0) {
                    revert ERC1967NonPayable();
                }
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol)
        pragma solidity ^0.8.20;
        /**
         * @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 internal call site, it will return directly to the external caller.
             */
            function _delegate(address implementation) internal virtual {
                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 overridden 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 internal call site, it will return directly to the external caller.
             */
            function _fallback() internal virtual {
                _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();
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/ProxyAdmin.sol)
        pragma solidity ^0.8.20;
        import {ITransparentUpgradeableProxy} from "./TransparentUpgradeableProxy.sol";
        import {Ownable} from "../../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 The version of the upgrade interface of the contract. If this getter is missing, both `upgrade(address)`
             * and `upgradeAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
             * while `upgradeAndCall` will invoke the `receive` function if the second argument is the empty byte string.
             * If the getter returns `"5.0.0"`, only `upgradeAndCall(address,bytes)` is present, and the second argument must
             * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
             * during an upgrade.
             */
            string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
            /**
             * @dev Sets the initial owner who can perform upgrades.
             */
            constructor(address initialOwner) Ownable(initialOwner) {}
            /**
             * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation.
             * See {TransparentUpgradeableProxy-_dispatchUpgradeToAndCall}.
             *
             * Requirements:
             *
             * - This contract must be the admin of `proxy`.
             * - If `data` is empty, `msg.value` must be zero.
             */
            function upgradeAndCall(
                ITransparentUpgradeableProxy proxy,
                address implementation,
                bytes memory data
            ) public payable virtual onlyOwner {
                proxy.upgradeToAndCall{value: msg.value}(implementation, data);
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/TransparentUpgradeableProxy.sol)
        pragma solidity ^0.8.20;
        import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol";
        import {ERC1967Proxy} from "../ERC1967/ERC1967Proxy.sol";
        import {IERC1967} from "../../interfaces/IERC1967.sol";
        import {ProxyAdmin} from "./ProxyAdmin.sol";
        /**
         * @dev Interface for {TransparentUpgradeableProxy}. In order to implement transparency, {TransparentUpgradeableProxy}
         * does not implement this interface directly, and its upgradeability mechanism is implemented by an internal dispatch
         * mechanism. The compiler is unaware that these functions are implemented by {TransparentUpgradeableProxy} and will not
         * include them in the ABI so this interface must be used to interact with it.
         */
        interface ITransparentUpgradeableProxy is IERC1967 {
            function upgradeToAndCall(address, bytes calldata) external payable;
        }
        /**
         * @dev This contract implements a proxy that is upgradeable through an associated {ProxyAdmin} instance.
         *
         * 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 the {ITransparentUpgradeableProxy-upgradeToAndCall} function exposed by the proxy itself.
         * 2. If the admin calls the proxy, it can call the `upgradeToAndCall` function but any other call won't be forwarded to
         * the implementation. If the admin tries to call a function on the implementation it will fail with an error indicating
         * the proxy admin cannot fallback to the target implementation.
         *
         * These properties mean that the admin account can only be used for upgrading the proxy, 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. For this reason, the proxy deploys an instance of {ProxyAdmin} and
         * allows upgrades only if they come through it. You should think of the `ProxyAdmin` instance as the administrative
         * interface of the proxy, including the ability to change who can trigger upgrades by transferring ownership.
         *
         * NOTE: The real interface of this proxy is that defined in `ITransparentUpgradeableProxy`. This contract does not
         * inherit from that interface, and instead `upgradeToAndCall` is implicitly implemented using a custom dispatch
         * mechanism in `_fallback`. Consequently, the compiler will not produce an ABI for this contract. This is necessary to
         * fully implement transparency without decoding reverts caused by selector clashes between the proxy and the
         * implementation.
         *
         * NOTE: This proxy does not inherit from {Context} deliberately. The {ProxyAdmin} of this contract won't send a
         * meta-transaction in any way, and any other meta-transaction setup should be made in the implementation contract.
         *
         * IMPORTANT: This contract avoids unnecessary storage reads by setting the admin only during construction as an
         * immutable variable, preventing any changes thereafter. However, the admin slot defined in ERC-1967 can still be
         * overwritten by the implementation logic pointed to by this proxy. In such cases, the contract may end up in an
         * undesirable state where the admin slot is different from the actual admin.
         *
         * WARNING: It is not recommended to extend this contract to add additional external functions. If you do so, the
         * compiler will not check that there are no selector conflicts, due to the note above. A selector clash between any new
         * function and the functions declared in {ITransparentUpgradeableProxy} will be resolved in favor of the new one. This
         * could render the `upgradeToAndCall` function inaccessible, preventing upgradeability and compromising transparency.
         */
        contract TransparentUpgradeableProxy is ERC1967Proxy {
            // An immutable address for the admin to avoid unnecessary SLOADs before each call
            // at the expense of removing the ability to change the admin once it's set.
            // This is acceptable if the admin is always a ProxyAdmin instance or similar contract
            // with its own ability to transfer the permissions to another account.
            address private immutable _admin;
            /**
             * @dev The proxy caller is the current admin, and can't fallback to the proxy target.
             */
            error ProxyDeniedAdminAccess();
            /**
             * @dev Initializes an upgradeable proxy managed by an instance of a {ProxyAdmin} with an `initialOwner`,
             * backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in
             * {ERC1967Proxy-constructor}.
             */
            constructor(address _logic, address initialOwner, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
                _admin = address(new ProxyAdmin(initialOwner));
                // Set the storage value and emit an event for ERC-1967 compatibility
                ERC1967Utils.changeAdmin(_proxyAdmin());
            }
            /**
             * @dev Returns the admin of this proxy.
             */
            function _proxyAdmin() internal virtual returns (address) {
                return _admin;
            }
            /**
             * @dev If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior.
             */
            function _fallback() internal virtual override {
                if (msg.sender == _proxyAdmin()) {
                    if (msg.sig != ITransparentUpgradeableProxy.upgradeToAndCall.selector) {
                        revert ProxyDeniedAdminAccess();
                    } else {
                        _dispatchUpgradeToAndCall();
                    }
                } else {
                    super._fallback();
                }
            }
            /**
             * @dev Upgrade the implementation of the proxy. See {ERC1967Utils-upgradeToAndCall}.
             *
             * Requirements:
             *
             * - If `data` is empty, `msg.value` must be zero.
             */
            function _dispatchUpgradeToAndCall() private {
                (address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes));
                ERC1967Utils.upgradeToAndCall(newImplementation, data);
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
        pragma solidity ^0.8.20;
        /**
         * @dev Collection of functions related to the address type
         */
        library Address {
            /**
             * @dev The ETH balance of the account is not enough to perform the operation.
             */
            error AddressInsufficientBalance(address account);
            /**
             * @dev There's no code at `target` (it is not a contract).
             */
            error AddressEmptyCode(address target);
            /**
             * @dev A call to an address target failed. The target may have reverted.
             */
            error FailedInnerCall();
            /**
             * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
             * `recipient`, forwarding all available gas and reverting on errors.
             *
             * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
             * of certain opcodes, possibly making contracts go over the 2300 gas limit
             * imposed by `transfer`, making them unable to receive funds via
             * `transfer`. {sendValue} removes this limitation.
             *
             * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
             *
             * IMPORTANT: because control is transferred to `recipient`, care must be
             * taken to not create reentrancy vulnerabilities. Consider using
             * {ReentrancyGuard} or the
             * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
             */
            function sendValue(address payable recipient, uint256 amount) internal {
                if (address(this).balance < amount) {
                    revert AddressInsufficientBalance(address(this));
                }
                (bool success, ) = recipient.call{value: amount}("");
                if (!success) {
                    revert FailedInnerCall();
                }
            }
            /**
             * @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 or custom error, it is bubbled
             * up by this function (like regular Solidity function calls). However, if
             * the call reverted with no returned reason, this function reverts with a
             * {FailedInnerCall} error.
             *
             * 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.
             */
            function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                return functionCallWithValue(target, data, 0);
            }
            /**
             * @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`.
             */
            function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                if (address(this).balance < value) {
                    revert AddressInsufficientBalance(address(this));
                }
                (bool success, bytes memory returndata) = target.call{value: value}(data);
                return verifyCallResultFromTarget(target, success, returndata);
            }
            /**
             * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
             * but performing a static call.
             */
            function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                (bool success, bytes memory returndata) = target.staticcall(data);
                return verifyCallResultFromTarget(target, success, returndata);
            }
            /**
             * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
             * but performing a delegate call.
             */
            function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                (bool success, bytes memory returndata) = target.delegatecall(data);
                return verifyCallResultFromTarget(target, success, returndata);
            }
            /**
             * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
             * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
             * unsuccessful call.
             */
            function verifyCallResultFromTarget(
                address target,
                bool success,
                bytes memory returndata
            ) internal view returns (bytes memory) {
                if (!success) {
                    _revert(returndata);
                } else {
                    // only check if target is a contract if the call was successful and the return data is empty
                    // otherwise we already know that it was a contract
                    if (returndata.length == 0 && target.code.length == 0) {
                        revert AddressEmptyCode(target);
                    }
                    return returndata;
                }
            }
            /**
             * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
             * revert reason or with a default {FailedInnerCall} error.
             */
            function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
                if (!success) {
                    _revert(returndata);
                } else {
                    return returndata;
                }
            }
            /**
             * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
             */
            function _revert(bytes memory returndata) private pure {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
                    /// @solidity memory-safe-assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert FailedInnerCall();
                }
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
        pragma solidity ^0.8.20;
        /**
         * @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) {
                return msg.data;
            }
            function _contextSuffixLength() internal view virtual returns (uint256) {
                return 0;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
        // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
        pragma solidity ^0.8.20;
        /**
         * @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:
         * ```solidity
         * 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(newImplementation.code.length > 0);
         *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
         *     }
         * }
         * ```
         */
        library StorageSlot {
            struct AddressSlot {
                address value;
            }
            struct BooleanSlot {
                bool value;
            }
            struct Bytes32Slot {
                bytes32 value;
            }
            struct Uint256Slot {
                uint256 value;
            }
            struct StringSlot {
                string value;
            }
            struct BytesSlot {
                bytes value;
            }
            /**
             * @dev Returns an `AddressSlot` with member `value` located at `slot`.
             */
            function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                /// @solidity memory-safe-assembly
                assembly {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
             */
            function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                /// @solidity memory-safe-assembly
                assembly {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
             */
            function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                /// @solidity memory-safe-assembly
                assembly {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
             */
            function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                /// @solidity memory-safe-assembly
                assembly {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns an `StringSlot` with member `value` located at `slot`.
             */
            function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                /// @solidity memory-safe-assembly
                assembly {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
             */
            function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                /// @solidity memory-safe-assembly
                assembly {
                    r.slot := store.slot
                }
            }
            /**
             * @dev Returns an `BytesSlot` with member `value` located at `slot`.
             */
            function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                /// @solidity memory-safe-assembly
                assembly {
                    r.slot := slot
                }
            }
            /**
             * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
             */
            function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                /// @solidity memory-safe-assembly
                assembly {
                    r.slot := store.slot
                }
            }
        }
        

        File 2 of 4: EthereumPresale
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
        pragma solidity ^0.8.20;
        import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
        import {Initializable} from "../proxy/utils/Initializable.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.
         *
         * The initial owner is set to the address provided by the deployer. 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 OwnableUpgradeable is Initializable, ContextUpgradeable {
            /// @custom:storage-location erc7201:openzeppelin.storage.Ownable
            struct OwnableStorage {
                address _owner;
            }
            // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
            bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
            function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
                assembly {
                    $.slot := OwnableStorageLocation
                }
            }
            /**
             * @dev The caller account is not authorized to perform an operation.
             */
            error OwnableUnauthorizedAccount(address account);
            /**
             * @dev The owner is not a valid owner account. (eg. `address(0)`)
             */
            error OwnableInvalidOwner(address owner);
            event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            /**
             * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
             */
            function __Ownable_init(address initialOwner) internal onlyInitializing {
                __Ownable_init_unchained(initialOwner);
            }
            function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
                if (initialOwner == address(0)) {
                    revert OwnableInvalidOwner(address(0));
                }
                _transferOwnership(initialOwner);
            }
            /**
             * @dev Throws if called by any account other than the owner.
             */
            modifier onlyOwner() {
                _checkOwner();
                _;
            }
            /**
             * @dev Returns the address of the current owner.
             */
            function owner() public view virtual returns (address) {
                OwnableStorage storage $ = _getOwnableStorage();
                return $._owner;
            }
            /**
             * @dev Throws if the sender is not the owner.
             */
            function _checkOwner() internal view virtual {
                if (owner() != _msgSender()) {
                    revert OwnableUnauthorizedAccount(_msgSender());
                }
            }
            /**
             * @dev Leaves the contract without owner. It will not be possible to call
             * `onlyOwner` functions. Can only be called by the current owner.
             *
             * NOTE: Renouncing ownership will leave the contract without an owner,
             * thereby disabling any functionality that is only available to the owner.
             */
            function renounceOwnership() public virtual onlyOwner {
                _transferOwnership(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 {
                if (newOwner == address(0)) {
                    revert OwnableInvalidOwner(address(0));
                }
                _transferOwnership(newOwner);
            }
            /**
             * @dev Transfers ownership of the contract to a new account (`newOwner`).
             * Internal function without access restriction.
             */
            function _transferOwnership(address newOwner) internal virtual {
                OwnableStorage storage $ = _getOwnableStorage();
                address oldOwner = $._owner;
                $._owner = newOwner;
                emit OwnershipTransferred(oldOwner, newOwner);
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
        pragma solidity ^0.8.20;
        /**
         * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
         * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
         * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
         * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
         *
         * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
         * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
         * case an upgrade adds a module that needs to be initialized.
         *
         * For example:
         *
         * [.hljs-theme-light.nopadding]
         * ```solidity
         * contract MyToken is ERC20Upgradeable {
         *     function initialize() initializer public {
         *         __ERC20_init("MyToken", "MTK");
         *     }
         * }
         *
         * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
         *     function initializeV2() reinitializer(2) public {
         *         __ERC20Permit_init("MyToken");
         *     }
         * }
         * ```
         *
         * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
         * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
         *
         * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
         * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
         *
         * [CAUTION]
         * ====
         * Avoid leaving a contract uninitialized.
         *
         * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
         * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
         * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
         *
         * [.hljs-theme-light.nopadding]
         * ```
         * /// @custom:oz-upgrades-unsafe-allow constructor
         * constructor() {
         *     _disableInitializers();
         * }
         * ```
         * ====
         */
        abstract contract Initializable {
            /**
             * @dev Storage of the initializable contract.
             *
             * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
             * when using with upgradeable contracts.
             *
             * @custom:storage-location erc7201:openzeppelin.storage.Initializable
             */
            struct InitializableStorage {
                /**
                 * @dev Indicates that the contract has been initialized.
                 */
                uint64 _initialized;
                /**
                 * @dev Indicates that the contract is in the process of being initialized.
                 */
                bool _initializing;
            }
            // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
            bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
            /**
             * @dev The contract is already initialized.
             */
            error InvalidInitialization();
            /**
             * @dev The contract is not initializing.
             */
            error NotInitializing();
            /**
             * @dev Triggered when the contract has been initialized or reinitialized.
             */
            event Initialized(uint64 version);
            /**
             * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
             * `onlyInitializing` functions can be used to initialize parent contracts.
             *
             * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
             * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
             * production.
             *
             * Emits an {Initialized} event.
             */
            modifier initializer() {
                // solhint-disable-next-line var-name-mixedcase
                InitializableStorage storage $ = _getInitializableStorage();
                // Cache values to avoid duplicated sloads
                bool isTopLevelCall = !$._initializing;
                uint64 initialized = $._initialized;
                // Allowed calls:
                // - initialSetup: the contract is not in the initializing state and no previous version was
                //                 initialized
                // - construction: the contract is initialized at version 1 (no reininitialization) and the
                //                 current contract is just being deployed
                bool initialSetup = initialized == 0 && isTopLevelCall;
                bool construction = initialized == 1 && address(this).code.length == 0;
                if (!initialSetup && !construction) {
                    revert InvalidInitialization();
                }
                $._initialized = 1;
                if (isTopLevelCall) {
                    $._initializing = true;
                }
                _;
                if (isTopLevelCall) {
                    $._initializing = false;
                    emit Initialized(1);
                }
            }
            /**
             * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
             * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
             * used to initialize parent contracts.
             *
             * A reinitializer may be used after the original initialization step. This is essential to configure modules that
             * are added through upgrades and that require initialization.
             *
             * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
             * cannot be nested. If one is invoked in the context of another, execution will revert.
             *
             * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
             * a contract, executing them in the right order is up to the developer or operator.
             *
             * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
             *
             * Emits an {Initialized} event.
             */
            modifier reinitializer(uint64 version) {
                // solhint-disable-next-line var-name-mixedcase
                InitializableStorage storage $ = _getInitializableStorage();
                if ($._initializing || $._initialized >= version) {
                    revert InvalidInitialization();
                }
                $._initialized = version;
                $._initializing = true;
                _;
                $._initializing = false;
                emit Initialized(version);
            }
            /**
             * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
             * {initializer} and {reinitializer} modifiers, directly or indirectly.
             */
            modifier onlyInitializing() {
                _checkInitializing();
                _;
            }
            /**
             * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
             */
            function _checkInitializing() internal view virtual {
                if (!_isInitializing()) {
                    revert NotInitializing();
                }
            }
            /**
             * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
             * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
             * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
             * through proxies.
             *
             * Emits an {Initialized} event the first time it is successfully executed.
             */
            function _disableInitializers() internal virtual {
                // solhint-disable-next-line var-name-mixedcase
                InitializableStorage storage $ = _getInitializableStorage();
                if ($._initializing) {
                    revert InvalidInitialization();
                }
                if ($._initialized != type(uint64).max) {
                    $._initialized = type(uint64).max;
                    emit Initialized(type(uint64).max);
                }
            }
            /**
             * @dev Returns the highest version that has been initialized. See {reinitializer}.
             */
            function _getInitializedVersion() internal view returns (uint64) {
                return _getInitializableStorage()._initialized;
            }
            /**
             * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
             */
            function _isInitializing() internal view returns (bool) {
                return _getInitializableStorage()._initializing;
            }
            /**
             * @dev Returns a pointer to the storage namespace.
             */
            // solhint-disable-next-line var-name-mixedcase
            function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
                assembly {
                    $.slot := INITIALIZABLE_STORAGE
                }
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
        pragma solidity ^0.8.20;
        import {Initializable} from "../proxy/utils/Initializable.sol";
        /**
         * @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 ContextUpgradeable is Initializable {
            function __Context_init() internal onlyInitializing {
            }
            function __Context_init_unchained() internal onlyInitializing {
            }
            function _msgSender() internal view virtual returns (address) {
                return msg.sender;
            }
            function _msgData() internal view virtual returns (bytes calldata) {
                return msg.data;
            }
            function _contextSuffixLength() internal view virtual returns (uint256) {
                return 0;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)
        pragma solidity ^0.8.20;
        import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
        import {Initializable} from "../proxy/utils/Initializable.sol";
        /**
         * @dev Contract module which allows children to implement an emergency stop
         * mechanism that can be triggered by an authorized account.
         *
         * This module is used through inheritance. It will make available the
         * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
         * the functions of your contract. Note that they will not be pausable by
         * simply including this module, only once the modifiers are put in place.
         */
        abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
            /// @custom:storage-location erc7201:openzeppelin.storage.Pausable
            struct PausableStorage {
                bool _paused;
            }
            // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff))
            bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;
            function _getPausableStorage() private pure returns (PausableStorage storage $) {
                assembly {
                    $.slot := PausableStorageLocation
                }
            }
            /**
             * @dev Emitted when the pause is triggered by `account`.
             */
            event Paused(address account);
            /**
             * @dev Emitted when the pause is lifted by `account`.
             */
            event Unpaused(address account);
            /**
             * @dev The operation failed because the contract is paused.
             */
            error EnforcedPause();
            /**
             * @dev The operation failed because the contract is not paused.
             */
            error ExpectedPause();
            /**
             * @dev Initializes the contract in unpaused state.
             */
            function __Pausable_init() internal onlyInitializing {
                __Pausable_init_unchained();
            }
            function __Pausable_init_unchained() internal onlyInitializing {
                PausableStorage storage $ = _getPausableStorage();
                $._paused = false;
            }
            /**
             * @dev Modifier to make a function callable only when the contract is not paused.
             *
             * Requirements:
             *
             * - The contract must not be paused.
             */
            modifier whenNotPaused() {
                _requireNotPaused();
                _;
            }
            /**
             * @dev Modifier to make a function callable only when the contract is paused.
             *
             * Requirements:
             *
             * - The contract must be paused.
             */
            modifier whenPaused() {
                _requirePaused();
                _;
            }
            /**
             * @dev Returns true if the contract is paused, and false otherwise.
             */
            function paused() public view virtual returns (bool) {
                PausableStorage storage $ = _getPausableStorage();
                return $._paused;
            }
            /**
             * @dev Throws if the contract is paused.
             */
            function _requireNotPaused() internal view virtual {
                if (paused()) {
                    revert EnforcedPause();
                }
            }
            /**
             * @dev Throws if the contract is not paused.
             */
            function _requirePaused() internal view virtual {
                if (!paused()) {
                    revert ExpectedPause();
                }
            }
            /**
             * @dev Triggers stopped state.
             *
             * Requirements:
             *
             * - The contract must not be paused.
             */
            function _pause() internal virtual whenNotPaused {
                PausableStorage storage $ = _getPausableStorage();
                $._paused = true;
                emit Paused(_msgSender());
            }
            /**
             * @dev Returns to normal state.
             *
             * Requirements:
             *
             * - The contract must be paused.
             */
            function _unpause() internal virtual whenPaused {
                PausableStorage storage $ = _getPausableStorage();
                $._paused = false;
                emit Unpaused(_msgSender());
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
        pragma solidity ^0.8.20;
        import {Initializable} from "../proxy/utils/Initializable.sol";
        /**
         * @dev Contract module that helps prevent reentrant calls to a function.
         *
         * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
         * available, which can be applied to functions to make sure there are no nested
         * (reentrant) calls to them.
         *
         * Note that because there is a single `nonReentrant` guard, functions marked as
         * `nonReentrant` may not call one another. This can be worked around by making
         * those functions `private`, and then adding `external` `nonReentrant` entry
         * points to them.
         *
         * TIP: If you would like to learn more about reentrancy and alternative ways
         * to protect against it, check out our blog post
         * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
         */
        abstract contract ReentrancyGuardUpgradeable is Initializable {
            // Booleans are more expensive than uint256 or any type that takes up a full
            // word because each write operation emits an extra SLOAD to first read the
            // slot's contents, replace the bits taken up by the boolean, and then write
            // back. This is the compiler's defense against contract upgrades and
            // pointer aliasing, and it cannot be disabled.
            // The values being non-zero value makes deployment a bit more expensive,
            // but in exchange the refund on every call to nonReentrant will be lower in
            // amount. Since refunds are capped to a percentage of the total
            // transaction's gas, it is best to keep them low in cases like this one, to
            // increase the likelihood of the full refund coming into effect.
            uint256 private constant NOT_ENTERED = 1;
            uint256 private constant ENTERED = 2;
            /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
            struct ReentrancyGuardStorage {
                uint256 _status;
            }
            // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
            bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
            function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
                assembly {
                    $.slot := ReentrancyGuardStorageLocation
                }
            }
            /**
             * @dev Unauthorized reentrant call.
             */
            error ReentrancyGuardReentrantCall();
            function __ReentrancyGuard_init() internal onlyInitializing {
                __ReentrancyGuard_init_unchained();
            }
            function __ReentrancyGuard_init_unchained() internal onlyInitializing {
                ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
                $._status = NOT_ENTERED;
            }
            /**
             * @dev Prevents a contract from calling itself, directly or indirectly.
             * Calling a `nonReentrant` function from another `nonReentrant`
             * function is not supported. It is possible to prevent this from happening
             * by making the `nonReentrant` function external, and making it call a
             * `private` function that does the actual work.
             */
            modifier nonReentrant() {
                _nonReentrantBefore();
                _;
                _nonReentrantAfter();
            }
            function _nonReentrantBefore() private {
                ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
                // On the first call to nonReentrant, _status will be NOT_ENTERED
                if ($._status == ENTERED) {
                    revert ReentrancyGuardReentrantCall();
                }
                // Any calls to nonReentrant after this point will fail
                $._status = ENTERED;
            }
            function _nonReentrantAfter() private {
                ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
                // By storing the original value once again, a refund is triggered (see
                // https://eips.ethereum.org/EIPS/eip-2200)
                $._status = NOT_ENTERED;
            }
            /**
             * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
             * `nonReentrant` function in the call stack.
             */
            function _reentrancyGuardEntered() internal view returns (bool) {
                ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
                return $._status == ENTERED;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
        pragma solidity ^0.8.20;
        /**
         * @dev Interface of the ERC20 standard as defined in the EIP.
         */
        interface IERC20 {
            /**
             * @dev Emitted when `value` tokens are moved from one account (`from`) to
             * another (`to`).
             *
             * Note that `value` may be zero.
             */
            event Transfer(address indexed from, address indexed to, uint256 value);
            /**
             * @dev Emitted when the allowance of a `spender` for an `owner` is set by
             * a call to {approve}. `value` is the new allowance.
             */
            event Approval(address indexed owner, address indexed spender, uint256 value);
            /**
             * @dev Returns the value of tokens in existence.
             */
            function totalSupply() external view returns (uint256);
            /**
             * @dev Returns the value of tokens owned by `account`.
             */
            function balanceOf(address account) external view returns (uint256);
            /**
             * @dev Moves a `value` amount of tokens from the caller's account to `to`.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * Emits a {Transfer} event.
             */
            function transfer(address to, uint256 value) external returns (bool);
            /**
             * @dev Returns the remaining number of tokens that `spender` will be
             * allowed to spend on behalf of `owner` through {transferFrom}. This is
             * zero by default.
             *
             * This value changes when {approve} or {transferFrom} are called.
             */
            function allowance(address owner, address spender) external view returns (uint256);
            /**
             * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
             * caller's tokens.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * IMPORTANT: Beware that changing an allowance with this method brings the risk
             * that someone may use both the old and the new allowance by unfortunate
             * transaction ordering. One possible solution to mitigate this race
             * condition is to first reduce the spender's allowance to 0 and set the
             * desired value afterwards:
             * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
             *
             * Emits an {Approval} event.
             */
            function approve(address spender, uint256 value) external returns (bool);
            /**
             * @dev Moves a `value` amount of tokens from `from` to `to` using the
             * allowance mechanism. `value` is then deducted from the caller's
             * allowance.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * Emits a {Transfer} event.
             */
            function transferFrom(address from, address to, uint256 value) external returns (bool);
        }
        //SPDX-License-Identifier: MIT
        pragma solidity ^0.8.20;
        import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
        import '@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol';
        import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol';
        import '@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol';
        interface IAggregator {
            function latestRoundData()
                external
                view
                returns (
                    uint80 roundId,
                    int256 answer,
                    uint256 startedAt,
                    uint256 updatedAt,
                    uint80 answeredInRound
                );
        }
        contract EthereumPresale is
            Initializable,
            ReentrancyGuardUpgradeable,
            OwnableUpgradeable,
            PausableUpgradeable
        {
            uint256 public totalTokensSold;
            uint256 public claimStart;
            uint256 public baseScale;
            uint256 public baseDecimals;
            uint256 public maxTokensToBuy;
            uint256 public minTokensToBuy;
            uint256 public currentStep;
            uint256 public checkPoint;
            uint256 public usdRaised;
            uint256 public timeConstant;
            uint256[][3] private rounds;
            uint256[] private remainingTokensTracker;
            address public saleToken;
            address private paymentWallet;
            address public USDTtoken;
            address public USDCtoken;
            address public DAItoken;
            address public aggregatorInterface;
            bool public dynamicTimeFlag;
            mapping(address => uint256) public userDeposits;
            mapping(uint256 => uint256) public usdTokenDecimals;
            event TokensBought(
                address indexed user,
                uint256 indexed tokensBought,
                address indexed purchaseToken,
                uint256 amountPaid,
                uint256 usdEq,
                uint256 timestamp
            );
            event TokensAdded(
                address indexed token,
                uint256 noOfTokens,
                uint256 timestamp
            );
            event TokensClaimed(
                address indexed user,
                uint256 amount,
                uint256 timestamp
            );
            event StepIncremented(uint256 newStep, uint256 timestamp);
            constructor() initializer {}
            function initialize(
                address _oracle,
                address _usdt,
                address _usdc,
                address _dai,
                uint256[][3] memory _rounds,
                uint256 _timeConstant,
                uint256 _maxTokensToBuy,
                uint256 _minTokensToBuy,
                address _paymentWallet
            ) external initializer {
                require(_oracle != address(0), 'Zero aggregator address');
                require(_usdt != address(0), 'Zero USDT address');
                require(_usdc != address(0), 'Zero USDC address');
                require(_dai != address(0), 'Zero DAI address');
                __Pausable_init_unchained();
                __Ownable_init_unchained(_msgSender());
                __ReentrancyGuard_init_unchained();
                baseScale = 18;
                baseDecimals = (10 ** baseScale);
                aggregatorInterface = _oracle;
                USDTtoken = _usdt;
                USDCtoken = _usdc;
                DAItoken = _dai;
                rounds = _rounds;
                maxTokensToBuy = _maxTokensToBuy > _rounds[0][0]
                    ? _rounds[0][0]
                    : _maxTokensToBuy;
                minTokensToBuy = _minTokensToBuy >= _maxTokensToBuy
                    ? 0
                    : _minTokensToBuy;
                paymentWallet = _paymentWallet;
                dynamicTimeFlag = true;
                timeConstant = _timeConstant;
                usdTokenDecimals[0] = 6; //USDT
                usdTokenDecimals[1] = 6; //USDC
                usdTokenDecimals[2] = 18; //DAI
            }
            function pause() external onlyOwner {
                _pause();
            }
            function unpause() external onlyOwner {
                _unpause();
            }
            function calculatePrice(uint256 _amount) public view returns (uint256) {
                uint256 usdAmount;
                bool isLastRound = currentStep >= rounds[0].length - 1;
                uint256 total = (isLastRound || checkPoint == 0)
                    ? totalTokensSold
                    : checkPoint;
                if (
                    !isLastRound &&
                    (_amount + total > rounds[0][currentStep] ||
                        block.timestamp >= rounds[2][currentStep])
                ) {
                    if (block.timestamp >= rounds[2][currentStep]) {
                        require(
                            rounds[0][currentStep] + _amount <=
                                rounds[0][currentStep + 1],
                            'Cant purchase more in one transaction'
                        );
                        usdAmount = _amount * rounds[1][currentStep + 1];
                    } else {
                        uint256 tokenAmountForCurrentPrice = rounds[0][currentStep] -
                            total;
                        uint256 tokenAmountForNextPrice = _amount -
                            tokenAmountForCurrentPrice;
                        usdAmount =
                            tokenAmountForCurrentPrice *
                            rounds[1][currentStep] +
                            tokenAmountForNextPrice *
                            rounds[1][currentStep + 1];
                    }
                } else {
                    usdAmount = _amount * rounds[1][currentStep];
                }
                return usdAmount;
            }
            function getLatestPrice() public view returns (uint256) {
                (, int256 price, , , ) = IAggregator(aggregatorInterface)
                    .latestRoundData();
                price = (price * (10 ** 10));
                return uint256(price);
            }
            function manageRounds(uint256 amount) private {
                uint256 totalBefore = totalTokensSold > checkPoint
                    ? totalTokensSold
                    : checkPoint;
                totalTokensSold += amount;
                if (checkPoint != 0) checkPoint += amount;
                uint256 total = totalTokensSold > checkPoint
                    ? totalTokensSold
                    : checkPoint;
                if (
                    currentStep < (rounds[0].length - 1) &&
                    (total >= rounds[0][currentStep] ||
                        block.timestamp >= rounds[2][currentStep])
                ) {
                    uint256 unsoldTokens = total >= rounds[0][currentStep]
                        ? 0
                        : rounds[0][currentStep] - total;
                    if (block.timestamp >= rounds[2][currentStep]) {
                        checkPoint = rounds[0][currentStep] + amount;
                        unsoldTokens = totalBefore >= rounds[0][currentStep]
                            ? 0
                            : rounds[0][currentStep] - totalBefore;
                    }
                    if (dynamicTimeFlag) manageTimeDiff();
                    remainingTokensTracker.push(unsoldTokens);
                    currentStep += 1;
                }
            }
            modifier checkSaleState(uint256 amount) {
                require(
                    amount >= minTokensToBuy &&
                        amount <= maxTokensToBuy &&
                        totalTokensSold + amount <= rounds[0][rounds[0].length - 1],
                    'Invalid sale amount'
                );
                _;
            }
            function buyWithUSD(
                uint256 amount,
                uint256 purchaseToken
            ) external checkSaleState(amount) whenNotPaused {
                require(
                    usdTokenDecimals[purchaseToken] != 0,
                    'Incorrect USD token provided'
                );
                uint256 usdPrice = calculatePrice(amount);
                uint256 price = usdPrice /
                    getDecimalsDivider(usdTokenDecimals[purchaseToken]);
                manageRounds(amount);
                userDeposits[_msgSender()] += (amount * baseDecimals);
                usdRaised += usdPrice;
                IERC20 usdInterface;
                if (purchaseToken == 0) usdInterface = IERC20(USDTtoken);
                else if (purchaseToken == 1) usdInterface = IERC20(USDCtoken);
                else if (purchaseToken == 2) usdInterface = IERC20(DAItoken);
                else revert('Incorrect USD token provided');
                uint256 ourAllowance = usdInterface.allowance(
                    _msgSender(),
                    address(this)
                );
                require(price <= ourAllowance, 'Make sure to add enough allowance');
                (bool success, ) = address(usdInterface).call(
                    abi.encodeWithSignature(
                        'transferFrom(address,address,uint256)',
                        _msgSender(),
                        paymentWallet,
                        price
                    )
                );
                require(success, 'Token payment failed');
                emit TokensBought(
                    _msgSender(),
                    amount,
                    address(usdInterface),
                    price,
                    usdPrice,
                    block.timestamp
                );
            }
            function buyWithETH(
                uint256 amount
            ) external payable checkSaleState(amount) whenNotPaused nonReentrant {
                uint256 usdPrice = calculatePrice(amount);
                uint256 ethAmount = (usdPrice * baseDecimals) / getLatestPrice();
                require(msg.value >= ethAmount, 'Less payment');
                uint256 excess = msg.value - ethAmount;
                manageRounds(amount);
                userDeposits[_msgSender()] += (amount * baseDecimals);
                usdRaised += usdPrice;
                sendValue(payable(paymentWallet), ethAmount);
                if (excess > 0) sendValue(payable(_msgSender()), excess);
                emit TokensBought(
                    _msgSender(),
                    amount,
                    address(0),
                    ethAmount,
                    usdPrice,
                    block.timestamp
                );
            }
            function ethBuyHelper(
                uint256 amount
            ) external view returns (uint256 ethAmount) {
                uint256 usdPrice = calculatePrice(amount);
                ethAmount = (usdPrice * baseDecimals) / getLatestPrice();
            }
            function usdBuyHelper(
                uint256 amount,
                uint256 purchaseToken
            ) external view returns (uint256 usdPrice) {
                require(
                    usdTokenDecimals[purchaseToken] != 0,
                    'Incorrect USD token provided'
                );
                usdPrice = calculatePrice(amount);
                usdPrice =
                    usdPrice /
                    getDecimalsDivider(usdTokenDecimals[purchaseToken]);
            }
            function claim() external whenNotPaused {
                require(saleToken != address(0), 'Sale token not added');
                require(block.timestamp >= claimStart, 'Claim has not started yet');
                uint256 amount = userDeposits[_msgSender()];
                require(amount > 0, 'Nothing to claim');
                delete userDeposits[_msgSender()];
                bool success = IERC20(saleToken).transfer(_msgSender(), amount);
                require(success, 'Token transfer failed');
                emit TokensClaimed(_msgSender(), amount, block.timestamp);
            }
            function getDecimalsDivider(
                uint256 decimals
            ) internal view returns (uint256) {
                if (baseDecimals > (10 ** decimals))
                    return (10 ** (baseScale - decimals));
                else return 1;
            }
            function sendValue(address payable recipient, uint256 amount) internal {
                require(address(this).balance >= amount, 'Low balance');
                (bool success, ) = recipient.call{value: amount}('');
                require(success, 'ETH Payment failed');
            }
            function changeMaxTokensToBuy(uint256 _maxTokensToBuy) external onlyOwner {
                require(
                    _maxTokensToBuy > 0 && _maxTokensToBuy <= rounds[0][0],
                    'Zero max tokens to buy value'
                );
                maxTokensToBuy = _maxTokensToBuy;
            }
            function changeMinTokensToBuy(uint256 _minTokensToBuy) external onlyOwner {
                require(
                    _minTokensToBuy >= 0 && _minTokensToBuy < maxTokensToBuy,
                    'Invalid min tokens to buy value'
                );
                minTokensToBuy = _minTokensToBuy;
            }
            function startClaim(
                uint256 _claimStart,
                uint256 amountOfTokens,
                address _saleToken
            ) external onlyOwner {
                require(_saleToken != address(0), 'Zero token address');
                require(claimStart == 0, 'Claim already set');
                claimStart = _claimStart;
                saleToken = _saleToken;
                bool success = IERC20(saleToken).transferFrom(
                    _msgSender(),
                    address(this),
                    amountOfTokens
                );
                require(success, 'Token transfer failed');
                emit TokensAdded(saleToken, amountOfTokens, block.timestamp);
            }
            function changeClaimStart(uint256 _claimStart) external onlyOwner {
                require(claimStart > 0, 'Initial claim data not set');
                claimStart = _claimStart;
            }
            function changeRoundsData(uint256[][3] memory _rounds) external onlyOwner {
                rounds = _rounds;
            }
            function changePaymentWallet(address _newPaymentWallet) external onlyOwner {
                require(_newPaymentWallet != address(0), 'Address cannot be zero');
                paymentWallet = _newPaymentWallet;
            }
            function manageTimeDiff() internal {
                for (uint256 i; i < rounds[2].length - currentStep; i++) {
                    rounds[2][currentStep + i] = block.timestamp + i * timeConstant;
                }
            }
            function setTimeConstant(uint256 _timeConstant) external onlyOwner {
                timeConstant = _timeConstant;
            }
            function updateUserDeposits(
                address[] calldata _users,
                uint256[] calldata _userDeposits
            ) external onlyOwner {
                require(_users.length == _userDeposits.length, 'Length mismatch');
                for (uint256 i = 0; i < _users.length; i++) {
                    userDeposits[_users[i]] += _userDeposits[i];
                }
            }
            function incrementCurrentStep() external onlyOwner {
                require(
                    currentStep < (rounds[0].length - 1),
                    'Current round is the last one'
                );
                if (dynamicTimeFlag) manageTimeDiff();
                if (checkPoint < rounds[0][currentStep]) {
                    uint256 sub = totalTokensSold > checkPoint
                        ? totalTokensSold
                        : checkPoint;
                    remainingTokensTracker.push(rounds[0][currentStep] - sub);
                    checkPoint = rounds[0][currentStep];
                }
                currentStep++;
                emit StepIncremented(currentStep, block.timestamp);
            }
            function setDynamicTimeFlag(bool _dynamicTimeFlag) external onlyOwner {
                dynamicTimeFlag = _dynamicTimeFlag;
            }
            function setCurrentStep(
                uint256 _step,
                uint256 _checkpoint
            ) external onlyOwner {
                currentStep = _step;
                checkPoint = _checkpoint;
            }
            function trackRemainingTokens() external view returns (uint256[] memory) {
                return remainingTokensTracker;
            }
            function setRemainingTokensArray(
                uint256[] memory _unsoldTokens
            ) public onlyOwner {
                require(_unsoldTokens.length != 0, 'cannot update invalid values');
                delete remainingTokensTracker;
                for (uint256 i; i < _unsoldTokens.length; i++) {
                    remainingTokensTracker.push(_unsoldTokens[i]);
                }
            }
            function roundDetails(
                uint256 _no
            ) external view returns (uint256[] memory) {
                return rounds[_no];
            }
            function withdrawTokens(address token, uint256 amount) external onlyOwner {
                IERC20(token).transfer(paymentWallet, amount);
            }
            function withdrawEthers() external onlyOwner {
                (bool success, ) = paymentWallet.call{value: address(this).balance}('');
                require(success, 'Failed to withdraw');
            }
        }
        

        File 3 of 4: 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 4 of 4: 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);
        }