ETH Price: $1,780.47 (-3.38%)

Transaction Decoder

Block:
21392986 at Dec-13-2024 10:26:47 AM +UTC
Transaction Fee:
0.001915966614643872 ETH $3.41
Gas Used:
169,372 Gas / 11.312180376 Gwei

Emitted Events:

256 TransparentUpgradeableProxy.0x4d8aead3491b7eba4b5c7a65fc17e493b9e63f9e433522fc5f6a85a168fc9d36( 0x4d8aead3491b7eba4b5c7a65fc17e493b9e63f9e433522fc5f6a85a168fc9d36, 0x000000000000000000000000b297eae0d63502346c1caa7c96e8293b3446e4cc, 0x0000000000000000000000000000000000000000000000000000000000084cae, 0x0000000000000000000000000000000000000000000000000000000000000000, 00000000000000000000000000000000000000000000000000b50bc834816620, 00000000000000000000000000000000000000000000000ab714adf1e4546000, 00000000000000000000000000000000000000000000000000000000675c0be7 )

Account State Difference:

  Address   Before After State Difference Code
(Titan Builder)
10.722607517979278868 Eth10.722624455179278868 Eth0.0000169372
0x5b92DEA0...A3b22F5b4 107.813763823313792009 Eth107.815802220325267569 Eth0.00203839701147556
0x9a15bB3a...5d42360F7
0xa239327B...7982A5Ef3 2,587.530331759530713974 Eth2,587.579253287806127406 Eth0.048921528275413432
0xb297eae0...b3446e4CC
0.077633156245222326 Eth
Nonce: 51
0.024757264343689462 Eth
Nonce: 52
0.052875891901532864

Execution Trace

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

        File 2 of 4: PresaleV2
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
        pragma solidity ^0.8.0;
        import "../utils/ContextUpgradeable.sol";
        import "../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.
         *
         * By default, the owner account will be the one that deploys the contract. This
         * can later be changed with {transferOwnership}.
         *
         * This module is used through inheritance. It will make available the modifier
         * `onlyOwner`, which can be applied to your functions to restrict their use to
         * the owner.
         */
        abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
            address private _owner;
            event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            /**
             * @dev Initializes the contract setting the deployer as the initial owner.
             */
            function __Ownable_init() internal onlyInitializing {
                __Ownable_init_unchained();
            }
            function __Ownable_init_unchained() internal onlyInitializing {
                _transferOwnership(_msgSender());
            }
            /**
             * @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 {
                require(owner() == _msgSender(), "Ownable: caller is not the owner");
            }
            /**
             * @dev Leaves the contract without owner. It will not be possible to call
             * `onlyOwner` functions anymore. Can only be called by the current owner.
             *
             * NOTE: Renouncing ownership will leave the contract without an owner,
             * thereby removing any functionality that is only available to the owner.
             */
            function renounceOwnership() public virtual onlyOwner {
                _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 {
                require(newOwner != address(0), "Ownable: new owner is the zero address");
                _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);
            }
            /**
             * @dev This empty reserved space is put in place to allow future versions to add new
             * variables without shifting down storage in the inheritance chain.
             * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
             */
            uint256[49] private __gap;
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)
        pragma solidity ^0.8.2;
        import "../../utils/AddressUpgradeable.sol";
        /**
         * @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]
         * ```
         * 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 Indicates that the contract has been initialized.
             * @custom:oz-retyped-from bool
             */
            uint8 private _initialized;
            /**
             * @dev Indicates that the contract is in the process of being initialized.
             */
            bool private _initializing;
            /**
             * @dev Triggered when the contract has been initialized or reinitialized.
             */
            event Initialized(uint8 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 functions marked with `initializer` can be nested in the context of a
             * constructor.
             *
             * Emits an {Initialized} event.
             */
            modifier initializer() {
                bool isTopLevelCall = !_initializing;
                require(
                    (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
                    "Initializable: contract is already initialized"
                );
                _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 255 will prevent any future reinitialization.
             *
             * Emits an {Initialized} event.
             */
            modifier reinitializer(uint8 version) {
                require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
                _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() {
                require(_initializing, "Initializable: contract is not initializing");
                _;
            }
            /**
             * @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 {
                require(!_initializing, "Initializable: contract is initializing");
                if (_initialized < type(uint8).max) {
                    _initialized = type(uint8).max;
                    emit Initialized(type(uint8).max);
                }
            }
            /**
             * @dev Returns the highest version that has been initialized. See {reinitializer}.
             */
            function _getInitializedVersion() internal view returns (uint8) {
                return _initialized;
            }
            /**
             * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
             */
            function _isInitializing() internal view returns (bool) {
                return _initializing;
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
        pragma solidity ^0.8.0;
        import "../utils/ContextUpgradeable.sol";
        import "../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 {
            /**
             * @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);
            bool private _paused;
            /**
             * @dev Initializes the contract in unpaused state.
             */
            function __Pausable_init() internal onlyInitializing {
                __Pausable_init_unchained();
            }
            function __Pausable_init_unchained() internal onlyInitializing {
                _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) {
                return _paused;
            }
            /**
             * @dev Throws if the contract is paused.
             */
            function _requireNotPaused() internal view virtual {
                require(!paused(), "Pausable: paused");
            }
            /**
             * @dev Throws if the contract is not paused.
             */
            function _requirePaused() internal view virtual {
                require(paused(), "Pausable: not paused");
            }
            /**
             * @dev Triggers stopped state.
             *
             * Requirements:
             *
             * - The contract must not be paused.
             */
            function _pause() internal virtual whenNotPaused {
                _paused = true;
                emit Paused(_msgSender());
            }
            /**
             * @dev Returns to normal state.
             *
             * Requirements:
             *
             * - The contract must be paused.
             */
            function _unpause() internal virtual whenPaused {
                _paused = false;
                emit Unpaused(_msgSender());
            }
            /**
             * @dev This empty reserved space is put in place to allow future versions to add new
             * variables without shifting down storage in the inheritance chain.
             * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
             */
            uint256[49] private __gap;
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)
        pragma solidity ^0.8.0;
        import "../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;
            uint256 private _status;
            function __ReentrancyGuard_init() internal onlyInitializing {
                __ReentrancyGuard_init_unchained();
            }
            function __ReentrancyGuard_init_unchained() internal onlyInitializing {
                _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 {
                // On the first call to nonReentrant, _status will be _NOT_ENTERED
                require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
                // Any calls to nonReentrant after this point will fail
                _status = _ENTERED;
            }
            function _nonReentrantAfter() private {
                // By storing the original value once again, a refund is triggered (see
                // https://eips.ethereum.org/EIPS/eip-2200)
                _status = _NOT_ENTERED;
            }
            /**
             * @dev This empty reserved space is put in place to allow future versions to add new
             * variables without shifting down storage in the inheritance chain.
             * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
             */
            uint256[49] private __gap;
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
        pragma solidity ^0.8.0;
        /**
         * @dev Interface of the ERC20 standard as defined in the EIP.
         */
        interface IERC20Upgradeable {
            /**
             * @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 amount of tokens in existence.
             */
            function totalSupply() external view returns (uint256);
            /**
             * @dev Returns the amount of tokens owned by `account`.
             */
            function balanceOf(address account) external view returns (uint256);
            /**
             * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);
            /**
             * @dev Moves `amount` tokens from `from` to `to` using the
             * allowance mechanism. `amount` 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 amount
            ) external returns (bool);
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
        pragma solidity ^0.8.1;
        /**
         * @dev Collection of functions related to the address type
         */
        library AddressUpgradeable {
            /**
             * @dev Returns true if `account` is a contract.
             *
             * [IMPORTANT]
             * ====
             * It is unsafe to assume that an address for which this function returns
             * false is an externally-owned account (EOA) and not a contract.
             *
             * Among others, `isContract` will return false for the following
             * types of addresses:
             *
             *  - an externally-owned account
             *  - a contract in construction
             *  - an address where a contract will be created
             *  - an address where a contract lived, but was destroyed
             * ====
             *
             * [IMPORTANT]
             * ====
             * You shouldn't rely on `isContract` to protect against flash loan attacks!
             *
             * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
             * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
             * constructor.
             * ====
             */
            function isContract(address account) internal view returns (bool) {
                // This method relies on extcodesize/address.code.length, which returns 0
                // for contracts in construction, since the code is only stored at the end
                // of the constructor execution.
                return account.code.length > 0;
            }
            /**
             * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
             * `recipient`, forwarding all available gas and reverting on errors.
             *
             * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
             * of certain opcodes, possibly making contracts go over the 2300 gas limit
             * imposed by `transfer`, making them unable to receive funds via
             * `transfer`. {sendValue} removes this limitation.
             *
             * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
             *
             * IMPORTANT: because control is transferred to `recipient`, care must be
             * taken to not create reentrancy vulnerabilities. Consider using
             * {ReentrancyGuard} or the
             * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
             */
            function sendValue(address payable recipient, uint256 amount) internal {
                require(address(this).balance >= amount, "Address: insufficient balance");
                (bool success, ) = recipient.call{value: amount}("");
                require(success, "Address: unable to send value, recipient may have reverted");
            }
            /**
             * @dev Performs a Solidity function call using a low level `call`. A
             * plain `call` is an unsafe replacement for a function call: use this
             * function instead.
             *
             * If `target` reverts with a revert reason, it is bubbled up by this
             * function (like regular Solidity function calls).
             *
             * Returns the raw returned data. To convert to the expected return value,
             * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
             *
             * Requirements:
             *
             * - `target` must be a contract.
             * - calling `target` with `data` must not revert.
             *
             * _Available since v3.1._
             */
            function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                return functionCallWithValue(target, data, 0, "Address: low-level call failed");
            }
            /**
             * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
             * `errorMessage` as a fallback revert reason when `target` reverts.
             *
             * _Available since v3.1._
             */
            function functionCall(
                address target,
                bytes memory data,
                string memory errorMessage
            ) internal returns (bytes memory) {
                return functionCallWithValue(target, data, 0, errorMessage);
            }
            /**
             * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
             * but also transferring `value` wei to `target`.
             *
             * Requirements:
             *
             * - the calling contract must have an ETH balance of at least `value`.
             * - the called Solidity function must be `payable`.
             *
             * _Available since v3.1._
             */
            function functionCallWithValue(
                address target,
                bytes memory data,
                uint256 value
            ) internal returns (bytes memory) {
                return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
            }
            /**
             * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
             * with `errorMessage` as a fallback revert reason when `target` reverts.
             *
             * _Available since v3.1._
             */
            function functionCallWithValue(
                address target,
                bytes memory data,
                uint256 value,
                string memory errorMessage
            ) internal returns (bytes memory) {
                require(address(this).balance >= value, "Address: insufficient balance for call");
                (bool success, bytes memory returndata) = target.call{value: value}(data);
                return verifyCallResultFromTarget(target, success, returndata, errorMessage);
            }
            /**
             * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
             * but performing a static call.
             *
             * _Available since v3.3._
             */
            function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                return functionStaticCall(target, data, "Address: low-level static call failed");
            }
            /**
             * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
             * but performing a static call.
             *
             * _Available since v3.3._
             */
            function functionStaticCall(
                address target,
                bytes memory data,
                string memory errorMessage
            ) internal view returns (bytes memory) {
                (bool success, bytes memory returndata) = target.staticcall(data);
                return verifyCallResultFromTarget(target, success, returndata, errorMessage);
            }
            /**
             * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
             * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
             *
             * _Available since v4.8._
             */
            function verifyCallResultFromTarget(
                address target,
                bool success,
                bytes memory returndata,
                string memory errorMessage
            ) internal view returns (bytes memory) {
                if (success) {
                    if (returndata.length == 0) {
                        // only check isContract if the call was successful and the return data is empty
                        // otherwise we already know that it was a contract
                        require(isContract(target), "Address: call to non-contract");
                    }
                    return returndata;
                } else {
                    _revert(returndata, errorMessage);
                }
            }
            /**
             * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
             * revert reason or using the provided one.
             *
             * _Available since v4.3._
             */
            function verifyCallResult(
                bool success,
                bytes memory returndata,
                string memory errorMessage
            ) internal pure returns (bytes memory) {
                if (success) {
                    return returndata;
                } else {
                    _revert(returndata, errorMessage);
                }
            }
            function _revert(bytes memory returndata, string memory errorMessage) private pure {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
                    /// @solidity memory-safe-assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
        // SPDX-License-Identifier: MIT
        // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
        pragma solidity ^0.8.0;
        import "../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;
            }
            /**
             * @dev This empty reserved space is put in place to allow future versions to add new
             * variables without shifting down storage in the inheritance chain.
             * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
             */
            uint256[50] private __gap;
        }
        //SPDX-License-Identifier: MIT
        //               _    _____                                        _
        // __      _____| |__|___ / _ __   __ _ _   _ _ __ ___   ___ _ __ | |_ ___
        // \\ \\ /\\ / / _ \\ '_ \\ |_ \\| '_ \\ / _` | | | | '_ ` _ \\ / _ \\ '_ \\| __/ __|
        //  \\ V  V /  __/ |_) |__) | |_) | (_| | |_| | | | | | |  __/ | | | |_\\__ \\
        //   \\_/\\_/ \\___|_.__/____/| .__/ \\__,_|\\__, |_| |_| |_|\\___|_| |_|\\__|___/
        //                         |_|          |___/
        //
        pragma solidity 0.8.9;
        import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
        import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
        import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
        import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
        interface Aggregator {
          function latestRoundData() external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
        }
        interface StakingManager {
          function depositByPresale(address _user, uint256 _amount) external;
        }
        contract PresaleV2 is Initializable, ReentrancyGuardUpgradeable, OwnableUpgradeable, PausableUpgradeable {
          uint256 public totalTokensSold;
          uint256 public startTime;
          uint256 public endTime;
          uint256 public claimStart;
          address public saleToken;
          uint256 public baseDecimals;
          uint256 public maxTokensToBuy;
          uint256 public currentStep;
          uint256 public checkPoint;
          uint256 public usdRaised;
          uint256 public timeConstant;
          uint256 public totalBoughtAndStaked;
          uint256[][3] public rounds;
          uint256[] public prevCheckpoints;
          uint256[] public remainingTokensTracker;
          uint256[] public percentages;
          address[] public wallets;
          address public paymentWallet;
          address public admin;
          bool public dynamicTimeFlag;
          bool public whitelistClaimOnly;
          bool public stakeingWhitelistStatus;
          IERC20Upgradeable public USDTInterface;
          Aggregator public aggregatorInterface;
          mapping(address => uint256) public userDeposits;
          mapping(address => bool) public hasClaimed;
          mapping(address => bool) public isBlacklisted;
          mapping(address => bool) public isWhitelisted;
          mapping(address => bool) public wertWhitelisted;
          StakingManager public stakingManagerInterface;
          event SaleTimeSet(uint256 _start, uint256 _end, uint256 timestamp);
          event SaleTimeUpdated(bytes32 indexed key, uint256 prevValue, uint256 newValue, uint256 timestamp);
          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 ClaimStartUpdated(uint256 prevValue, uint256 newValue, uint256 timestamp);
          event MaxTokensUpdated(uint256 prevValue, uint256 newValue, uint256 timestamp);
          event TokensBoughtAndStaked(address indexed user, uint256 indexed tokensBought, address indexed purchaseToken, uint256 amountPaid, uint256 usdEq, uint256 timestamp);
          event TokensClaimedAndStaked(address indexed user, uint256 amount, uint256 timestamp);
          /// @custom:oz-upgrades-unsafe-allow constructor
          constructor() initializer {}
          /**
           * @dev To pause the presale
           */
          function pause() external onlyOwner {
            _pause();
          }
          /**
           * @dev To unpause the presale
           */
          function unpause() external onlyOwner {
            _unpause();
          }
          /**
           * @dev To calculate the price in USD for given amount of tokens.
           * @param _amount No of tokens
           */
          function calculatePrice(uint256 _amount) public view returns (uint256) {
            uint256 USDTAmount;
            uint256 total = checkPoint == 0 ? totalTokensSold : checkPoint;
            require(_amount <= maxTokensToBuy, "Amount exceeds max tokens to buy");
            if (_amount + total > rounds[0][currentStep] || block.timestamp >= rounds[2][currentStep]) {
              require(currentStep < (rounds[0].length - 1), "Wrong params");
              if (block.timestamp >= rounds[2][currentStep]) {
                require(rounds[0][currentStep] + _amount <= rounds[0][currentStep + 1], "Cant Purchase More in individual tx");
                USDTAmount = _amount * rounds[1][currentStep + 1];
              } else {
                uint256 tokenAmountForCurrentPrice = rounds[0][currentStep] - total;
                USDTAmount = tokenAmountForCurrentPrice * rounds[1][currentStep] + (_amount - tokenAmountForCurrentPrice) * rounds[1][currentStep + 1];
              }
            } else USDTAmount = _amount * rounds[1][currentStep];
            return USDTAmount;
          }
          /**
           * @dev To update the sale times
           * @param _startTime New start time
           * @param _endTime New end time
           */
          function changeSaleTimes(uint256 _startTime, uint256 _endTime) external onlyOwner {
            require(_startTime > 0 || _endTime > 0, "Invalid parameters");
            if (_startTime > 0) {
              require(block.timestamp < startTime, "Sale already started");
              require(block.timestamp < _startTime, "Sale time in past");
              uint256 prevValue = startTime;
              startTime = _startTime;
              emit SaleTimeUpdated(bytes32("START"), prevValue, _startTime, block.timestamp);
            }
            if (_endTime > 0) {
              require(_endTime > startTime, "Invalid endTime");
              uint256 prevValue = endTime;
              endTime = _endTime;
              emit SaleTimeUpdated(bytes32("END"), prevValue, _endTime, block.timestamp);
            }
          }
          /**
           * @dev To get latest ETH price in 10**18 format
           */
          function getLatestPrice() public view returns (uint256) {
            (, int256 price, , , ) = aggregatorInterface.latestRoundData();
            price = (price * (10 ** 10));
            return uint256(price);
          }
          function setSplits(address[] memory _wallets, uint256[] memory _percentages) public onlyOwner {
            require(_wallets.length == _percentages.length, "Mismatched arrays");
            delete wallets;
            delete percentages;
            uint256 totalPercentage = 0;
            for (uint256 i = 0; i < _wallets.length; i++) {
              require(_percentages[i] > 0, "Percentage must be greater than 0");
              totalPercentage += _percentages[i];
              wallets.push(_wallets[i]);
              percentages.push(_percentages[i]);
            }
            require(totalPercentage == 100, "Total percentage must equal 100");
          }
          modifier checkSaleState(uint256 amount) {
            require(block.timestamp >= startTime && block.timestamp <= endTime, "Invalid time for buying");
            require(amount > 0, "Invalid sale amount");
            _;
          }
          /**
           * @dev To buy into a presale using USDT
           * @param amount No of tokens to buy
           * @param stake boolean flag for token staking
           */
          function buyWithUSDT(uint256 amount, bool stake) external checkSaleState(amount) whenNotPaused returns (bool) {
            uint256 usdPrice = calculatePrice(amount);
            totalTokensSold += amount;
            uint256 price = usdPrice / (10 ** 12);
            if (checkPoint != 0) checkPoint += amount;
            uint256 total = totalTokensSold > checkPoint ? totalTokensSold : checkPoint;
            if (total > rounds[0][currentStep] || block.timestamp >= rounds[2][currentStep]) {
              if (block.timestamp >= rounds[2][currentStep]) {
                checkPoint = rounds[0][currentStep] + amount;
              }
              if (dynamicTimeFlag) {
                manageTimeDiff();
              }
              uint256 unsoldTokens = total > rounds[0][currentStep] ? 0 : rounds[0][currentStep] - total - amount;
              remainingTokensTracker.push(unsoldTokens);
              currentStep += 1;
            }
            if (stake) {
              if (stakeingWhitelistStatus) {
                require(isWhitelisted[_msgSender()], "User not whitelisted for stake");
              }
              stakingManagerInterface.depositByPresale(_msgSender(), amount * baseDecimals);
              totalBoughtAndStaked += amount;
              emit TokensBoughtAndStaked(_msgSender(), amount, address(USDTInterface), price, usdPrice, block.timestamp);
            } else {
              userDeposits[_msgSender()] += (amount * baseDecimals);
              emit TokensBought(_msgSender(), amount, address(USDTInterface), price, usdPrice, block.timestamp);
            }
            usdRaised += usdPrice;
            uint256 ourAllowance = USDTInterface.allowance(_msgSender(), address(this));
            require(price <= ourAllowance, "Make sure to add enough allowance");
            splitUSDTValue(price);
            return true;
          }
          /**
           * @dev To buy into a presale using ETH
           * @param amount No of tokens to buy
           * @param stake boolean flag for token staking
           */
          function buyWithEth(uint256 amount, bool stake) external payable checkSaleState(amount) whenNotPaused nonReentrant returns (bool) {
            uint256 usdPrice = calculatePrice(amount);
            uint256 ethAmount = (usdPrice * baseDecimals) / getLatestPrice();
            require(msg.value >= ethAmount, "Less payment");
            uint256 excess = msg.value - ethAmount;
            totalTokensSold += amount;
            if (checkPoint != 0) checkPoint += amount;
            uint256 total = totalTokensSold > checkPoint ? totalTokensSold : checkPoint;
            if (total > rounds[0][currentStep] || block.timestamp >= rounds[2][currentStep]) {
              if (block.timestamp >= rounds[2][currentStep]) {
                checkPoint = rounds[0][currentStep] + amount;
              }
              if (dynamicTimeFlag) {
                manageTimeDiff();
              }
              uint256 unsoldTokens = total > rounds[0][currentStep] ? 0 : rounds[0][currentStep] - total - amount;
              remainingTokensTracker.push(unsoldTokens);
              currentStep += 1;
            }
            if (stake) {
              if (stakeingWhitelistStatus) {
                require(isWhitelisted[_msgSender()], "User not whitelisted for stake");
              }
              stakingManagerInterface.depositByPresale(_msgSender(), amount * baseDecimals);
              totalBoughtAndStaked += amount;
              emit TokensBoughtAndStaked(_msgSender(), amount, address(0), ethAmount, usdPrice, block.timestamp);
            } else {
              userDeposits[_msgSender()] += (amount * baseDecimals);
              emit TokensBought(_msgSender(), amount, address(0), ethAmount, usdPrice, block.timestamp);
            }
            usdRaised += usdPrice;
            splitETHValue(ethAmount);
            if (excess > 0) sendValue(payable(_msgSender()), excess);
            return true;
          }
          /**
           * @dev To buy ETH directly from wert .*wert contract address should be whitelisted if wertBuyRestrictionStatus is set true
           * @param _user address of the user
           * @param _amount No of ETH to buy
           * @param stake boolean flag for token staking
           */
          function buyWithETHWert(address _user, uint256 _amount, bool stake) external payable checkSaleState(_amount) whenNotPaused nonReentrant returns (bool) {
            require(wertWhitelisted[_msgSender()], "User not whitelisted for this tx");
            uint256 usdPrice = calculatePrice(_amount);
            uint256 ethAmount = (usdPrice * baseDecimals) / getLatestPrice();
            require(msg.value >= ethAmount, "Less payment");
            uint256 excess = msg.value - ethAmount;
            totalTokensSold += _amount;
            if (checkPoint != 0) checkPoint += _amount;
            uint256 total = totalTokensSold > checkPoint ? totalTokensSold : checkPoint;
            if (total > rounds[0][currentStep] || block.timestamp >= rounds[2][currentStep]) {
              if (block.timestamp >= rounds[2][currentStep]) {
                checkPoint = rounds[0][currentStep] + _amount;
              }
              if (dynamicTimeFlag) {
                manageTimeDiff();
              }
              uint256 unsoldTokens = total > rounds[0][currentStep] ? 0 : rounds[0][currentStep] - total - _amount;
              remainingTokensTracker.push(unsoldTokens);
              currentStep += 1;
            }
            if (stake) {
              if (stakeingWhitelistStatus) {
                require(isWhitelisted[_user], "User not whitelisted for stake");
              }
              stakingManagerInterface.depositByPresale(_user, _amount * baseDecimals);
              totalBoughtAndStaked += _amount;
              emit TokensBoughtAndStaked(_user, _amount, address(0), ethAmount, usdPrice, block.timestamp);
            } else {
              userDeposits[_user] += (_amount * baseDecimals);
              emit TokensBought(_user, _amount, address(0), ethAmount, usdPrice, block.timestamp);
            }
            usdRaised += usdPrice;
            splitETHValue(ethAmount);
            if (excess > 0) sendValue(payable(_user), excess);
            return true;
          }
          /**
           * @dev Helper funtion to get ETH price for given amount
           * @param amount No of tokens to buy
           */
          function ethBuyHelper(uint256 amount) external view returns (uint256 ethAmount) {
            uint256 usdPrice = calculatePrice(amount);
            ethAmount = (usdPrice * baseDecimals) / getLatestPrice();
          }
          /**
           * @dev Helper funtion to get USDT price for given amount
           * @param amount No of tokens to buy
           */
          function usdtBuyHelper(uint256 amount) external view returns (uint256 usdPrice) {
            usdPrice = calculatePrice(amount);
            usdPrice = usdPrice / (10 ** 12);
          }
          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 splitETHValue(uint256 _amount) internal {
            if (wallets.length == 0) {
              require(paymentWallet != address(0), "Payment wallet not set");
              sendValue(payable(paymentWallet), _amount);
            } else {
              uint256 tempCalc;
              for (uint256 i = 0; i < wallets.length; i++) {
                uint256 amountToTransfer = (_amount * percentages[i]) / 100;
                sendValue(payable(wallets[i]), amountToTransfer);
                tempCalc += amountToTransfer;
              }
              if ((_amount - tempCalc) > 0) {
                sendValue(payable(wallets[wallets.length - 1]), _amount - tempCalc);
              }
            }
          }
          function splitUSDTValue(uint256 _amount) internal {
            if (wallets.length == 0) {
              require(paymentWallet != address(0), "Payment wallet not set");
              (bool success, ) = address(USDTInterface).call(abi.encodeWithSignature("transferFrom(address,address,uint256)", _msgSender(), paymentWallet, _amount));
              require(success, "Token payment failed");
            } else {
              uint256 tempCalc;
              for (uint256 i = 0; i < wallets.length; i++) {
                uint256 amountToTransfer = (_amount * percentages[i]) / 100;
                (bool success, ) = address(USDTInterface).call(abi.encodeWithSignature("transferFrom(address,address,uint256)", _msgSender(), wallets[i], amountToTransfer));
                require(success, "Token payment failed");
                tempCalc += amountToTransfer;
              }
              if ((_amount - tempCalc) > 0) {
                (bool success, ) = address(USDTInterface).call(abi.encodeWithSignature("transferFrom(address,address,uint256)", _msgSender(), wallets[wallets.length - 1], _amount - tempCalc));
                require(success, "Token payment failed");
              }
            }
          }
          /**
           * @dev to initialize staking manager with new addredd
           * @param _stakingManagerAddress address of the staking smartcontract
           */
          function setStakingManager(address _stakingManagerAddress) external onlyOwner {
            require(_stakingManagerAddress != address(0), "staking manager cannot be inatialized with zero address");
            stakingManagerInterface = StakingManager(_stakingManagerAddress);
            IERC20Upgradeable(saleToken).approve(_stakingManagerAddress, type(uint256).max);
          }
          /**
           * @dev To set the claim start time and sale token address by the owner
           * @param _claimStart claim start time
           * @param noOfTokens no of tokens to add to the contract
           * @param _saleToken sale toke address
           */
          function startClaim(uint256 _claimStart, uint256 noOfTokens, address _saleToken, address _stakingManagerAddress) external onlyOwner returns (bool) {
            require(_saleToken != address(0), "Zero token address");
            // require(claimStart == 0, "Claim already set");
            claimStart = _claimStart;
            saleToken = _saleToken;
            whitelistClaimOnly = true;
            stakingManagerInterface = StakingManager(_stakingManagerAddress);
            IERC20Upgradeable(_saleToken).approve(_stakingManagerAddress, type(uint256).max);
            bool success = IERC20Upgradeable(_saleToken).transferFrom(_msgSender(), address(this), noOfTokens);
            require(success, "Token transfer failed");
            emit TokensAdded(_saleToken, noOfTokens, block.timestamp);
            return true;
          }
          /**
           * @dev To set status for claim whitelisting
           * @param _status bool value
           */
          function setStakeingWhitelistStatus(bool _status) external onlyOwner {
            stakeingWhitelistStatus = _status;
          }
          /**
           * @dev To change the claim start time by the owner
           * @param _claimStart new claim start time
           */
          function changeClaimStart(uint256 _claimStart) external onlyOwner returns (bool) {
            require(claimStart > 0, "Initial claim data not set");
            require(_claimStart > endTime, "Sale in progress");
            require(_claimStart > block.timestamp, "Claim start in past");
            uint256 prevValue = claimStart;
            claimStart = _claimStart;
            emit ClaimStartUpdated(prevValue, _claimStart, block.timestamp);
            return true;
          }
          /**
           * @dev To claim tokens after claiming starts
           */
          function claim() external whenNotPaused returns (bool) {
            require(saleToken != address(0), "Sale token not added");
            require(!isBlacklisted[_msgSender()], "This Address is Blacklisted");
            if (whitelistClaimOnly) {
              require(isWhitelisted[_msgSender()], "User not whitelisted for claim");
            }
            require(block.timestamp >= claimStart, "Claim has not started yet");
            require(!hasClaimed[_msgSender()], "Already claimed");
            hasClaimed[_msgSender()] = true;
            uint256 amount = userDeposits[_msgSender()];
            require(amount > 0, "Nothing to claim");
            delete userDeposits[_msgSender()];
            bool success = IERC20Upgradeable(saleToken).transfer(_msgSender(), amount);
            require(success, "Token transfer failed");
            emit TokensClaimed(_msgSender(), amount, block.timestamp);
            return true;
          }
          function claimAndStake() external whenNotPaused returns (bool) {
            require(saleToken != address(0), "Sale token not added");
            require(!isBlacklisted[_msgSender()], "This Address is Blacklisted");
            if (stakeingWhitelistStatus) {
              require(isWhitelisted[_msgSender()], "User not whitelisted for stake");
            }
            uint256 amount = userDeposits[_msgSender()];
            require(amount > 0, "Nothing to stake");
            stakingManagerInterface.depositByPresale(_msgSender(), amount);
            delete userDeposits[_msgSender()];
            emit TokensClaimedAndStaked(_msgSender(), amount, block.timestamp);
            return true;
          }
          /**
           * @dev To add wert contract addresses to whitelist
           * @param _addressesToWhitelist addresses of the contract
           */
          function whitelistUsersForWERT(address[] calldata _addressesToWhitelist) external onlyOwner {
            for (uint256 i = 0; i < _addressesToWhitelist.length; i++) {
              wertWhitelisted[_addressesToWhitelist[i]] = true;
            }
          }
          /**
           * @dev To remove wert contract addresses to whitelist
           * @param _addressesToRemoveFromWhitelist addresses of the contracts
           */
          function removeFromWhitelistForWERT(address[] calldata _addressesToRemoveFromWhitelist) external onlyOwner {
            for (uint256 i = 0; i < _addressesToRemoveFromWhitelist.length; i++) {
              wertWhitelisted[_addressesToRemoveFromWhitelist[i]] = false;
            }
          }
          function changeMaxTokensToBuy(uint256 _maxTokensToBuy) external onlyOwner {
            require(_maxTokensToBuy > 0, "Zero max tokens to buy value");
            uint256 prevValue = maxTokensToBuy;
            maxTokensToBuy = _maxTokensToBuy;
            emit MaxTokensUpdated(prevValue, _maxTokensToBuy, block.timestamp);
          }
          function changeRoundsData(uint256[][3] memory _rounds) external onlyOwner {
            rounds = _rounds;
          }
          /**
           * @dev To add users to blacklist which restricts blacklisted users from claiming
           * @param _usersToBlacklist addresses of the users
           */
          function blacklistUsers(address[] calldata _usersToBlacklist) external onlyOwner {
            for (uint256 i = 0; i < _usersToBlacklist.length; i++) {
              isBlacklisted[_usersToBlacklist[i]] = true;
            }
          }
          /**
           * @dev To remove users from blacklist which restricts blacklisted users from claiming
           * @param _userToRemoveFromBlacklist addresses of the users
           */
          function removeFromBlacklist(address[] calldata _userToRemoveFromBlacklist) external onlyOwner {
            for (uint256 i = 0; i < _userToRemoveFromBlacklist.length; i++) {
              isBlacklisted[_userToRemoveFromBlacklist[i]] = false;
            }
          }
          /**
           * @dev To add users to whitelist which restricts users from claiming if claimWhitelistStatus is true
           * @param _usersToWhitelist addresses of the users
           */
          function whitelistUsers(address[] calldata _usersToWhitelist) external onlyOwner {
            for (uint256 i = 0; i < _usersToWhitelist.length; i++) {
              isWhitelisted[_usersToWhitelist[i]] = true;
            }
          }
          /**
           * @dev To remove users from whitelist which restricts users from claiming if claimWhitelistStatus is true
           * @param _userToRemoveFromWhitelist addresses of the users
           */
          function removeFromWhitelist(address[] calldata _userToRemoveFromWhitelist) external onlyOwner {
            for (uint256 i = 0; i < _userToRemoveFromWhitelist.length; i++) {
              isWhitelisted[_userToRemoveFromWhitelist[i]] = false;
            }
          }
          /**
           * @dev To set status for claim whitelisting
           * @param _status bool value
           */
          function setClaimWhitelistStatus(bool _status) external onlyOwner {
            whitelistClaimOnly = _status;
          }
          /**
           * @dev To set payment wallet address
           * @param _newPaymentWallet new payment wallet address
           */
          function changePaymentWallet(address _newPaymentWallet) external onlyOwner {
            require(_newPaymentWallet != address(0), "address cannot be zero");
            paymentWallet = _newPaymentWallet;
          }
          /**
           * @dev To manage time gap between two rounds
           */
          function manageTimeDiff() internal {
            for (uint256 i; i < rounds[2].length - currentStep; i++) {
              rounds[2][currentStep + i] = block.timestamp + i * timeConstant;
            }
          }
          /**
           * @dev To set time constant for manageTimeDiff()
           * @param _timeConstant time in <days>*24*60*60 format
           */
          function setTimeConstant(uint256 _timeConstant) external onlyOwner {
            timeConstant = _timeConstant;
          }
          /**
           * @dev To get array of round details at once
           * @param _no array index
           */
          function roundDetails(uint256 _no) external view returns (uint256[] memory) {
            return rounds[_no];
          }
          /**
           * @dev to update userDeposits for purchases made on BSC
           * @param _users array of users
           * @param _userDeposits array of userDeposits associated with users
           */
          function updateFromBSC(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];
            }
          }
          /**
           * @dev To increment the rounds from backend
           */
          function incrementCurrentStep() external {
            require(msg.sender == admin || msg.sender == owner(), "caller not admin or owner");
            prevCheckpoints.push(checkPoint);
            if (dynamicTimeFlag) {
              manageTimeDiff();
            }
            if (checkPoint < rounds[0][currentStep]) {
              if (currentStep == 0) {
                remainingTokensTracker.push(rounds[0][currentStep] - totalTokensSold);
              } else {
                remainingTokensTracker.push(rounds[0][currentStep] - checkPoint);
              }
              checkPoint = rounds[0][currentStep];
            }
            currentStep++;
          }
          /**
           * @dev To set admin
           * @param _admin new admin wallet address
           */
          function setAdmin(address _admin) external onlyOwner {
            admin = _admin;
          }
          /**
           * @dev To change details of the round
           * @param _step round for which you want to change the details
           * @param _checkpoint token tracker amount
           */
          function setCurrentStep(uint256 _step, uint256 _checkpoint) external onlyOwner {
            currentStep = _step;
            checkPoint = _checkpoint;
          }
          /**
           * @dev To set time shift functionality on/off
           * @param _dynamicTimeFlag bool value
           */
          function setDynamicTimeFlag(bool _dynamicTimeFlag) external onlyOwner {
            dynamicTimeFlag = _dynamicTimeFlag;
          }
          /**
           * @dev     Function to return remainingTokenTracker Array
           */
          function trackRemainingTokens() external view returns (uint256[] memory) {
            return remainingTokensTracker;
          }
          /**
           * @dev     To update remainingTokensTracker Array
           * @param   _unsoldTokens  input parameters in uint256 array format
           */
          function setRemainingTokensArray(uint256[] memory _unsoldTokens) public {
            require(msg.sender == admin || msg.sender == owner(), "caller not admin or owner");
            require(_unsoldTokens.length != 0, "cannot update invalid values");
            delete remainingTokensTracker;
            for (uint256 i; i < _unsoldTokens.length; i++) {
              remainingTokensTracker.push(_unsoldTokens[i]);
            }
          }
        }
        

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