ETH Price: $2,665.73 (+1.17%)

Transaction Decoder

Block:
20370824 at Jul-23-2024 05:47:59 PM +UTC
Transaction Fee:
0.00142581488330901 ETH $3.80
Gas Used:
307,470 Gas / 4.637248783 Gwei

Emitted Events:

277 TransparentUpgradeableProxy.0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c( 0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c, 0x000000000000000000000000a3965c175f83d0c1515f97cd55b08dac6ea3a9df, 00000000000000000000000000000000000000000000003c1096c1907cd00000 )
278 Token.Transfer( from=[Receiver] TransparentUpgradeableProxy, to=TransparentUpgradeableProxy, value=1108000000000000000000 )
279 Token.Approval( owner=[Receiver] TransparentUpgradeableProxy, spender=TransparentUpgradeableProxy, value=115792089237316195423570985008687907853269984665640554696132584007913129639935 )
280 TransparentUpgradeableProxy.0x6f225532a9c33b023b8e48247ad8df9d98f132ae17c769b97ff22d2b278fa73a( 0x6f225532a9c33b023b8e48247ad8df9d98f132ae17c769b97ff22d2b278fa73a, 0x000000000000000000000000a3965c175f83d0c1515f97cd55b08dac6ea3a9df, 0x0000000000000000000000000000000000000000000000000000000000000454, 0x0000000000000000000000000000000000000000000000000000000000000000, 000000000000000000000000000000000000000000000000000a71c435f0a78a, 0000000000000000000000000000000000000000000000008b287b2c2cc08000, 00000000000000000000000000000000000000000000000000000000669feccf )
281 TransparentUpgradeableProxy.0x5d30f9e9bc12ca7d1874e44ae92ba80e3b4ab4d05ae5b3d4f0e44c2b749aa520( 0x5d30f9e9bc12ca7d1874e44ae92ba80e3b4ab4d05ae5b3d4f0e44c2b749aa520, 0x000000000000000000000000a3965c175f83d0c1515f97cd55b08dac6ea3a9df, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000454, 0000000000000000000000000000000000000000000000000000000000000000, 00000000000000000000000000000000000000000000000000000000669feccf )

Account State Difference:

  Address   Before After State Difference Code
0x1208AA49...deA9B557F 1.289703221163490922 Eth1.289850213028470885 Eth0.000146991864979963
0x2Da979a7...a781b21B8 24.504361202106322921 Eth24.5071540475409422 Eth0.002792845434619279
0x6E601f5b...a29375eB1
0x8cb8eeaE...AF4b711FE
0x92F8a244...A56d9816c
(beaverbuild)
7.000155078209911801 Eth7.000163411441106811 Eth0.00000833323119501
0xA3965C17...C6ea3A9Df
0.018018306572519791 Eth
Nonce: 25
0.013652654389611539 Eth
Nonce: 26
0.004365652182908252

Execution Trace

ETH 0.003 TransparentUpgradeableProxy.2c65169e( )
  • ETH 0.003 PresaleV2.buyWithEth( amount=1108, stake=True ) => ( True )
    • EACAggregatorProxy.STATICCALL( )
      • AccessControlledOffchainAggregator.STATICCALL( )
      • 0x90f1073be7cc44eeaf3feed23577fcf24b96fd76.daffac4c( )
      • TransparentUpgradeableProxy.91c61966( )
        • stakingManager.depositByPresale( _user=0xA3965C175F83d0c1515F97CD55B08daC6ea3A9Df, _amount=1108000000000000000000 )
          • Token.transferFrom( sender=0x6E601f5bB9aFBc97757Ab268AdB96C9a29375eB1, recipient=0x8cb8eeaE7CB99990b510C604fFb4A82AF4b711FE, amount=1108000000000000000000 ) => ( True )
          • ETH 0.002792845434619279 0x2da979a72717d5d7e77e528ca2e5386a781b21b8.CALL( )
          • ETH 0.000146991864979962 0x1208aa4961dc7337da9b7e1a21cfcbcdea9b557f.CALL( )
          • ETH 0.000000000000000001 0x1208aa4961dc7337da9b7e1a21cfcbcdea9b557f.CALL( )
          • ETH 0.000060162700400758 0xa3965c175f83d0c1515f97cd55b08dac6ea3a9df.CALL( )
            File 1 of 7: 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 7: 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 3 of 7: Token
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.9;
            /**
             * @dev Interface of the ERC20 standard as defined in the EIP.
             */
            interface IERC20 {
                /**
                 * @dev Emitted when `value` tokens are moved from one account (`from`) to
                 * another (`to`).
                 *
                 * Note that `value` may be zero.
                 */
                event Transfer(address indexed from, address indexed to, uint256 value);
                /**
                 * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                 * a call to {approve}. `value` is the new allowance.
                 */
                event Approval(
                    address indexed owner,
                    address indexed spender,
                    uint256 value
                );
                /**
                 * @dev Returns the 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);
            }
            /**
             * @dev Interface for the optional metadata functions from the ERC20 standard.
             *
             * _Available since v4.1._
             */
            interface IERC20Metadata is IERC20 {
                /**
                 * @dev Returns the name of the token.
                 */
                function name() external view returns (string memory);
                /**
                 * @dev Returns the symbol of the token.
                 */
                function symbol() external view returns (string memory);
                /**
                 * @dev Returns the decimals places of the token.
                 */
                function decimals() external view returns (uint8);
            }
            /**
             * @dev Provides information about the current execution context, including the
             * sender of the transaction and its data. While these are generally available
             * via msg.sender and msg.data, they should not be accessed in such a direct
             * manner, since when dealing with meta-transactions the account sending and
             * paying for execution may not be the actual sender (as far as an application
             * is concerned).
             *
             * This contract is only required for intermediate, library-like contracts.
             */
            abstract contract Context {
                function _msgSender() internal view virtual returns (address) {
                    return msg.sender;
                }
                function _msgData() internal view virtual returns (bytes calldata) {
                    return msg.data;
                }
            }
            /**
             * @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() {
                    _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. Can only be called by the current owner.
                 *
                 * NOTE: Renouncing ownership will leave the contract without an owner,
                 * thereby disabling any functionality that is only available to the owner.
                 */
                function renounceOwnership() public virtual onlyOwner {
                    _transferOwnership(address(0));
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Can only be called by the current owner.
                 */
                function transferOwnership(address newOwner) public virtual onlyOwner {
                    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);
                }
            }
            contract Token is Context, IERC20Metadata, Ownable {
                mapping(address => uint256) private _balances;
                mapping(address => mapping(address => uint256)) private _allowances;
                uint256 private _totalSupply;
                string private _name;
                string private _symbol;
                uint8 private constant _decimals = 18;
                uint256 public constant presaleReserve = 714_472_000 * (10 ** _decimals);
                uint256 public constant stakingReserve = 202_400_000 * (10 ** _decimals);
                uint256 public constant projectFundsReserve =
                    358_248_000 * (10 ** _decimals);
                uint256 public constant communityRewardsReserve =
                    242_880_000 * (10 ** _decimals);
                uint256 public constant liquidityReserve = 202_400_000 * (10 ** _decimals);
                uint256 public constant marketingReserve = 303_600_000 * (10 ** _decimals);
                /**
                 * @dev Contract constructor.
                 */
                constructor() {
                    _name = "The Meme Games";
                    _symbol = "MGMES";
                    _mint(0x01575A16a09693660dB03286De6d3B1C49280292, presaleReserve);
                    _mint(0x9E5E3BfC253538dDc8CdE66bE1F0c8a71b86a420, stakingReserve);
                    _mint(0xD1b0fBe747aAc4E3173462E4EF724551270A2614, projectFundsReserve);
                    _mint(
                        0xB8900762701868e7684C8577918bF680d983B635,
                        communityRewardsReserve
                    );
                    _mint(0x2C2928A31c6a8a6EBC3a524aAEDf7d873A066129, liquidityReserve);
                    _mint(0x4eC39611ED355504ab9F1547649F7B67CA64a94C, marketingReserve);
                }
                /**
                 * @dev Returns the name of the token.
                 * @return The name of the token.
                 */
                function name() public view virtual override returns (string memory) {
                    return _name;
                }
                /**
                 * @dev Returns the symbol of the token.
                 * @return The symbol of the token.
                 */
                function symbol() public view virtual override returns (string memory) {
                    return _symbol;
                }
                /**
                 * @dev Returns the number of decimals used for token display.
                 * @return The number of decimals.
                 */
                function decimals() public view virtual override returns (uint8) {
                    return _decimals;
                }
                /**
                 * @dev Returns the total supply of the token.
                 * @return The total supply.
                 */
                function totalSupply() public view virtual override returns (uint256) {
                    return _totalSupply;
                }
                /**
                 * @dev Returns the balance of the specified account.
                 * @param account The address to check the balance for.
                 * @return The balance of the account.
                 */
                function balanceOf(
                    address account
                ) public view virtual override returns (uint256) {
                    return _balances[account];
                }
                /**
                 * @dev Transfers tokens from the caller to a specified recipient.
                 * @param recipient The address to transfer tokens to.
                 * @param amount The amount of tokens to transfer.
                 * @return A boolean value indicating whether the transfer was successful.
                 */
                function transfer(
                    address recipient,
                    uint256 amount
                ) public virtual override returns (bool) {
                    _transfer(_msgSender(), recipient, amount);
                    return true;
                }
                /**
                 * @dev Returns the amount of tokens that the spender is allowed to spend on behalf of the owner.
                 * @param from The address that approves the spending.
                 * @param to The address that is allowed to spend.
                 * @return The remaining allowance for the spender.
                 */
                function allowance(
                    address from,
                    address to
                ) public view virtual override returns (uint256) {
                    return _allowances[from][to];
                }
                /**
                 * @dev Approves the specified address to spend the specified amount of tokens on behalf of the caller.
                 * @param to The address to approve the spending for.
                 * @param amount The amount of tokens to approve.
                 * @return A boolean value indicating whether the approval was successful.
                 */
                function approve(
                    address to,
                    uint256 amount
                ) public virtual override returns (bool) {
                    _approve(_msgSender(), to, amount);
                    return true;
                }
                /**
                 * @dev Transfers tokens from one address to another.
                 * @param sender The address to transfer tokens from.
                 * @param recipient The address to transfer tokens to.
                 * @param amount The amount of tokens to transfer.
                 * @return A boolean value indicating whether the transfer was successful.
                 */
                function transferFrom(
                    address sender,
                    address recipient,
                    uint256 amount
                ) public virtual override returns (bool) {
                    _transfer(sender, recipient, amount);
                    uint256 currentAllowance = _allowances[sender][_msgSender()];
                    require(
                        currentAllowance >= amount,
                        "ERC20: transfer amount exceeds allowance"
                    );
                    unchecked {
                        _approve(sender, _msgSender(), currentAllowance - amount);
                    }
                    return true;
                }
                /**
                 * @dev Increases the allowance of the specified address to spend tokens on behalf of the caller.
                 * @param to The address to increase the allowance for.
                 * @param addedValue The amount of tokens to increase the allowance by.
                 * @return A boolean value indicating whether the increase was successful.
                 */
                function increaseAllowance(
                    address to,
                    uint256 addedValue
                ) public virtual returns (bool) {
                    _approve(_msgSender(), to, _allowances[_msgSender()][to] + addedValue);
                    return true;
                }
                /**
                 * @dev Decreases the allowance granted by the owner of the tokens to `to` account.
                 * @param to The account allowed to spend the tokens.
                 * @param subtractedValue The amount of tokens to decrease the allowance by.
                 * @return A boolean value indicating whether the operation succeeded.
                 */
                function decreaseAllowance(
                    address to,
                    uint256 subtractedValue
                ) public virtual returns (bool) {
                    uint256 currentAllowance = _allowances[_msgSender()][to];
                    require(
                        currentAllowance >= subtractedValue,
                        "ERC20: decreased allowance below zero"
                    );
                    unchecked {
                        _approve(_msgSender(), to, currentAllowance - subtractedValue);
                    }
                    return true;
                }
                /**
                 * @dev Transfers `amount` tokens from `sender` to `recipient`.
                 * @param sender The account to transfer tokens from.
                 * @param recipient The account to transfer tokens to.
                 * @param amount The amount of tokens to transfer.
                 */
                function _transfer(
                    address sender,
                    address recipient,
                    uint256 amount
                ) internal virtual {
                    require(amount > 0, "ERC20: transfer amount zero");
                    require(sender != address(0), "ERC20: transfer from the zero address");
                    require(recipient != address(0), "ERC20: transfer to the zero address");
                    uint256 senderBalance = _balances[sender];
                    require(
                        senderBalance >= amount,
                        "ERC20: transfer amount exceeds balance"
                    );
                    unchecked {
                        _balances[sender] = senderBalance - amount;
                    }
                    _balances[recipient] += amount;
                    emit Transfer(sender, recipient, amount);
                }
                /**
                 * @dev Creates `amount` tokens and assigns them to `account`.
                 * @param account The account to assign the newly created tokens to.
                 * @param amount The amount of tokens to create.
                 */
                function _mint(address account, uint256 amount) internal virtual {
                    require(account != address(0), "ERC20: mint to the zero address");
                    _totalSupply += amount;
                    _balances[account] += amount;
                    emit Transfer(address(0), account, amount);
                }
                /**
                 * @dev Destroys `amount` tokens from `account`, reducing the total supply.
                 * @param account The account to burn tokens from.
                 * @param amount The amount of tokens to burn.
                 */
                function _burn(address account, uint256 amount) internal virtual {
                    require(account != address(0), "ERC20: burn from the zero address");
                    uint256 accountBalance = _balances[account];
                    require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
                    unchecked {
                        _balances[account] = accountBalance - amount;
                    }
                    _totalSupply -= amount;
                    emit Transfer(account, address(0), amount);
                }
                /**
                 * @dev Destroys `amount` tokens from the caller's account, reducing the total supply.
                 * @param amount The amount of tokens to burn.
                 */
                function burn(uint256 amount) external {
                    _burn(_msgSender(), amount);
                }
                /**
                 * @dev Sets `amount` as the allowance of `to` over the caller's tokens.
                 * @param from The account granting the allowance.
                 * @param to The account allowed to spend the tokens.
                 * @param amount The amount of tokens to allow.
                 */
                function _approve(
                    address from,
                    address to,
                    uint256 amount
                ) internal virtual {
                    require(from != address(0), "ERC20: approve from the zero address");
                    require(to != address(0), "ERC20: approve to the zero address");
                    _allowances[from][to] = amount;
                    emit Approval(from, to, amount);
                }
            }
            

            File 4 of 7: 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
            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;
            }
            interface IVerifier {
                function verify(
                    address _user,
                    uint256 _amount,
                    uint256 _checkPoint,
                    uint256 _tokensSold
                ) external view returns (bool);
            }
            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;
                IVerifier public verifier;
                uint256 public winPercent;
                uint256 public totalWinAmount;
                mapping(address => uint256) public userWinnings;
                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
                );
                event VerifierStatus(
                    address indexed user,
                    bool winStatus,
                    uint256 amount,
                    uint256 totalAmount,
                    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;
                    bool winStatus = verifier.verify(
                        _msgSender(),
                        amount,
                        checkPoint,
                        totalTokensSold
                    );
                    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 + (winStatus ? ((amount * winPercent) / 100) : 0)) *
                                baseDecimals
                        );
                        totalBoughtAndStaked += amount;
                        emit TokensBoughtAndStaked(
                            _msgSender(),
                            amount,
                            address(USDTInterface),
                            price,
                            usdPrice,
                            block.timestamp
                        );
                    } else {
                        userDeposits[_msgSender()] += ((amount +
                            (winStatus ? ((amount * winPercent) / 100) : 0)) *
                            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);
                    if (winStatus) {
                        totalWinAmount += (amount * winPercent) / 100;
                        userWinnings[_msgSender()] += (amount * winPercent) / 100;
                    }
                    emit VerifierStatus(
                        _msgSender(),
                        winStatus,
                        amount,
                        (winStatus ? ((amount * winPercent) / 100) : 0),
                        block.timestamp
                    );
                    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;
                    bool winStatus = verifier.verify(
                        _msgSender(),
                        amount,
                        checkPoint,
                        totalTokensSold
                    );
                    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 + (winStatus ? ((amount * winPercent) / 100) : 0)) *
                                baseDecimals
                        );
                        totalBoughtAndStaked += amount;
                        emit TokensBoughtAndStaked(
                            _msgSender(),
                            amount,
                            address(0),
                            ethAmount,
                            usdPrice,
                            block.timestamp
                        );
                    } else {
                        userDeposits[_msgSender()] += ((amount +
                            (winStatus ? ((amount * winPercent) / 100) : 0)) *
                            baseDecimals);
                        emit TokensBought(
                            _msgSender(),
                            amount,
                            address(0),
                            ethAmount,
                            usdPrice,
                            block.timestamp
                        );
                    }
                    usdRaised += usdPrice;
                    splitETHValue(ethAmount);
                    if (excess > 0) sendValue(payable(_msgSender()), excess);
                    if (winStatus) {
                        totalWinAmount += (amount * winPercent) / 100;
                        userWinnings[_msgSender()] += (amount * winPercent) / 100;
                    }
                    emit VerifierStatus(
                        _msgSender(),
                        winStatus,
                        amount,
                        (winStatus ? ((amount * winPercent) / 100) : 0),
                        block.timestamp
                    );
                    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;
                    bool winStatus = verifier.verify(
                        _user,
                        _amount,
                        checkPoint,
                        totalTokensSold
                    );
                    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 + (winStatus ? ((_amount * winPercent) / 100) : 0)) *
                                baseDecimals
                        );
                        totalBoughtAndStaked += _amount;
                        emit TokensBoughtAndStaked(
                            _user,
                            _amount,
                            address(0),
                            ethAmount,
                            usdPrice,
                            block.timestamp
                        );
                    } else {
                        userDeposits[_user] += ((_amount +
                            (winStatus ? ((_amount * winPercent) / 100) : 0)) *
                            baseDecimals);
                        emit TokensBought(
                            _user,
                            _amount,
                            address(0),
                            ethAmount,
                            usdPrice,
                            block.timestamp
                        );
                    }
                    usdRaised += usdPrice;
                    splitETHValue(ethAmount);
                    if (excess > 0) sendValue(payable(_user), excess);
                    if (winStatus) {
                        totalWinAmount += (_amount * winPercent) / 100;
                        userWinnings[_user] += (_amount * winPercent) / 100;
                    }
                    emit VerifierStatus(
                        _user,
                        winStatus,
                        _amount,
                        (winStatus ? ((_amount * winPercent) / 100) : 0),
                        block.timestamp
                    );
                    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;
                }
                function setVerifier(address _verifier) external onlyOwner {
                    verifier = IVerifier(_verifier);
                }
                function setWinPercent(uint256 _winPercent) external onlyOwner {
                    winPercent = _winPercent;
                }
                /**
                 * @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 5 of 7: 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 6 of 7: AccessControlledOffchainAggregator
            // SPDX-License-Identifier: MIT
            pragma solidity 0.7.6;
            import "./OffchainAggregator.sol";
            import "./SimpleReadAccessController.sol";
            /**
             * @notice Wrapper of OffchainAggregator which checks read access on Aggregator-interface methods
             */
            contract AccessControlledOffchainAggregator is OffchainAggregator, SimpleReadAccessController {
              constructor(
                uint32 _maximumGasPrice,
                uint32 _reasonableGasPrice,
                uint32 _microLinkPerEth,
                uint32 _linkGweiPerObservation,
                uint32 _linkGweiPerTransmission,
                LinkTokenInterface _link,
                int192 _minAnswer,
                int192 _maxAnswer,
                AccessControllerInterface _billingAccessController,
                AccessControllerInterface _requesterAccessController,
                uint8 _decimals,
                string memory description
              )
                OffchainAggregator(
                  _maximumGasPrice,
                  _reasonableGasPrice,
                  _microLinkPerEth,
                  _linkGweiPerObservation,
                  _linkGweiPerTransmission,
                  _link,
                  _minAnswer,
                  _maxAnswer,
                  _billingAccessController,
                  _requesterAccessController,
                  _decimals,
                  description
                ) {
                }
              /*
               * Versioning
               */
              function typeAndVersion()
                external
                override
                pure
                virtual
                returns (string memory)
              {
                return "AccessControlledOffchainAggregator 4.0.0";
              }
              /*
               * v2 Aggregator interface
               */
              /// @inheritdoc OffchainAggregator
              function latestAnswer()
                public
                override
                view
                checkAccess()
                returns (int256)
              {
                return super.latestAnswer();
              }
              /// @inheritdoc OffchainAggregator
              function latestTimestamp()
                public
                override
                view
                checkAccess()
                returns (uint256)
              {
                return super.latestTimestamp();
              }
              /// @inheritdoc OffchainAggregator
              function latestRound()
                public
                override
                view
                checkAccess()
                returns (uint256)
              {
                return super.latestRound();
              }
              /// @inheritdoc OffchainAggregator
              function getAnswer(uint256 _roundId)
                public
                override
                view
                checkAccess()
                returns (int256)
              {
                return super.getAnswer(_roundId);
              }
              /// @inheritdoc OffchainAggregator
              function getTimestamp(uint256 _roundId)
                public
                override
                view
                checkAccess()
                returns (uint256)
              {
                return super.getTimestamp(_roundId);
              }
              /*
               * v3 Aggregator interface
               */
              /// @inheritdoc OffchainAggregator
              function description()
                public
                override
                view
                checkAccess()
                returns (string memory)
              {
                return super.description();
              }
              /// @inheritdoc OffchainAggregator
              function getRoundData(uint80 _roundId)
                public
                override
                view
                checkAccess()
                returns (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 answeredInRound
                )
              {
                return super.getRoundData(_roundId);
              }
              /// @inheritdoc OffchainAggregator
              function latestRoundData()
                public
                override
                view
                checkAccess()
                returns (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 answeredInRound
                )
              {
                return super.latestRoundData();
              }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.7.0;
            interface AccessControllerInterface {
              function hasAccess(address user, bytes calldata data) external view returns (bool);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.7.0;
            interface AggregatorInterface {
              function latestAnswer() external view returns (int256);
              function latestTimestamp() external view returns (uint256);
              function latestRound() external view returns (uint256);
              function getAnswer(uint256 roundId) external view returns (int256);
              function getTimestamp(uint256 roundId) external view returns (uint256);
              event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);
              event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.7.0;
            import "./AggregatorInterface.sol";
            import "./AggregatorV3Interface.sol";
            interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface
            {
            }// SPDX-License-Identifier: MIT
            pragma solidity ^0.7.0;
            interface AggregatorV3Interface {
              function decimals() external view returns (uint8);
              function description() external view returns (string memory);
              function version() external view returns (uint256);
              function getRoundData(uint80 _roundId)
                external
                view
                returns (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 answeredInRound
                );
              function latestRoundData()
                external
                view
                returns (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 answeredInRound
                );
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.7.0;
            interface AggregatorValidatorInterface {
              function validate(
                uint256 previousRoundId,
                int256 previousAnswer,
                uint256 currentRoundId,
                int256 currentAnswer
              ) external returns (bool);
            }// SPDX-License-Identifier: MIT
            pragma solidity ^0.7.0;
            interface LinkTokenInterface {
              function allowance(address owner, address spender) external view returns (uint256 remaining);
              function approve(address spender, uint256 value) external returns (bool success);
              function balanceOf(address owner) external view returns (uint256 balance);
              function decimals() external view returns (uint8 decimalPlaces);
              function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);
              function increaseApproval(address spender, uint256 subtractedValue) external;
              function name() external view returns (string memory tokenName);
              function symbol() external view returns (string memory tokenSymbol);
              function totalSupply() external view returns (uint256 totalTokensIssued);
              function transfer(address to, uint256 value) external returns (bool success);
              function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool success);
              function transferFrom(address from, address to, uint256 value) external returns (bool success);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.7.6;
            import "./AccessControllerInterface.sol";
            import "./AggregatorV2V3Interface.sol";
            import "./AggregatorValidatorInterface.sol";
            import "./LinkTokenInterface.sol";
            import "./Owned.sol";
            import "./OffchainAggregatorBilling.sol";
            import "./TypeAndVersionInterface.sol";
            /**
              * @notice Onchain verification of reports from the offchain reporting protocol
              * @dev For details on its operation, see the offchain reporting protocol design
              * @dev doc, which refers to this contract as simply the "contract".
            */
            contract OffchainAggregator is Owned, OffchainAggregatorBilling, AggregatorV2V3Interface, TypeAndVersionInterface {
              uint256 constant private maxUint32 = (1 << 32) - 1;
              // Storing these fields used on the hot path in a HotVars variable reduces the
              // retrieval of all of them to a single SLOAD. If any further fields are
              // added, make sure that storage of the struct still takes at most 32 bytes.
              struct HotVars {
                // Provides 128 bits of security against 2nd pre-image attacks, but only
                // 64 bits against collisions. This is acceptable, since a malicious owner has
                // easier way of messing up the protocol than to find hash collisions.
                bytes16 latestConfigDigest;
                uint40 latestEpochAndRound; // 32 most sig bits for epoch, 8 least sig bits for round
                // Current bound assumed on number of faulty/dishonest oracles participating
                // in the protocol, this value is referred to as f in the design
                uint8 threshold;
                // Chainlink Aggregators expose a roundId to consumers. The offchain reporting
                // protocol does not use this id anywhere. We increment it whenever a new
                // transmission is made to provide callers with contiguous ids for successive
                // reports.
                uint32 latestAggregatorRoundId;
              }
              HotVars internal s_hotVars;
              // Transmission records the median answer from the transmit transaction at
              // time timestamp
              struct Transmission {
                int192 answer; // 192 bits ought to be enough for anyone
                uint64 timestamp;
              }
              mapping(uint32 /* aggregator round ID */ => Transmission) internal s_transmissions;
              // incremented each time a new config is posted. This count is incorporated
              // into the config digest, to prevent replay attacks.
              uint32 internal s_configCount;
              uint32 internal s_latestConfigBlockNumber; // makes it easier for offchain systems
                                                         // to extract config from logs.
              // Lowest answer the system is allowed to report in response to transmissions
              int192 immutable public minAnswer;
              // Highest answer the system is allowed to report in response to transmissions
              int192 immutable public maxAnswer;
              /*
               * @param _maximumGasPrice highest gas price for which transmitter will be compensated
               * @param _reasonableGasPrice transmitter will receive reward for gas prices under this value
               * @param _microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
               * @param _linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
               * @param _linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
               * @param _link address of the LINK contract
               * @param _minAnswer lowest answer the median of a report is allowed to be
               * @param _maxAnswer highest answer the median of a report is allowed to be
               * @param _billingAccessController access controller for billing admin functions
               * @param _requesterAccessController access controller for requesting new rounds
               * @param _decimals answers are stored in fixed-point format, with this many digits of precision
               * @param _description short human-readable description of observable this contract's answers pertain to
               */
              constructor(
                uint32 _maximumGasPrice,
                uint32 _reasonableGasPrice,
                uint32 _microLinkPerEth,
                uint32 _linkGweiPerObservation,
                uint32 _linkGweiPerTransmission,
                LinkTokenInterface _link,
                int192 _minAnswer,
                int192 _maxAnswer,
                AccessControllerInterface _billingAccessController,
                AccessControllerInterface _requesterAccessController,
                uint8 _decimals,
                string memory _description
              )
                OffchainAggregatorBilling(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
                  _linkGweiPerObservation, _linkGweiPerTransmission, _link,
                  _billingAccessController
                )
              {
                decimals = _decimals;
                s_description = _description;
                setRequesterAccessController(_requesterAccessController);
                setValidatorConfig(AggregatorValidatorInterface(0x0), 0);
                minAnswer = _minAnswer;
                maxAnswer = _maxAnswer;
              }
              /*
               * Versioning
               */
              function typeAndVersion()
                external
                override
                pure
                virtual
                returns (string memory)
              {
                return "OffchainAggregator 4.0.0";
              }
              /*
               * Config logic
               */
              /**
               * @notice triggers a new run of the offchain reporting protocol
               * @param previousConfigBlockNumber block in which the previous config was set, to simplify historic analysis
               * @param configCount ordinal number of this config setting among all config settings over the life of this contract
               * @param signers ith element is address ith oracle uses to sign a report
               * @param transmitters ith element is address ith oracle uses to transmit a report via the transmit method
               * @param threshold maximum number of faulty/dishonest oracles the protocol can tolerate while still working correctly
               * @param encodedConfigVersion version of the serialization format used for "encoded" parameter
               * @param encoded serialized data used by oracles to configure their offchain operation
               */
              event ConfigSet(
                uint32 previousConfigBlockNumber,
                uint64 configCount,
                address[] signers,
                address[] transmitters,
                uint8 threshold,
                uint64 encodedConfigVersion,
                bytes encoded
              );
              // Reverts transaction if config args are invalid
              modifier checkConfigValid (
                uint256 _numSigners, uint256 _numTransmitters, uint256 _threshold
              ) {
                require(_numSigners <= maxNumOracles, "too many signers");
                require(_threshold > 0, "threshold must be positive");
                require(
                  _numSigners == _numTransmitters,
                  "oracle addresses out of registration"
                );
                require(_numSigners > 3*_threshold, "faulty-oracle threshold too high");
                _;
              }
              /**
               * @notice sets offchain reporting protocol configuration incl. participating oracles
               * @param _signers addresses with which oracles sign the reports
               * @param _transmitters addresses oracles use to transmit the reports
               * @param _threshold number of faulty oracles the system can tolerate
               * @param _encodedConfigVersion version number for offchainEncoding schema
               * @param _encoded encoded off-chain oracle configuration
               */
              function setConfig(
                address[] calldata _signers,
                address[] calldata _transmitters,
                uint8 _threshold,
                uint64 _encodedConfigVersion,
                bytes calldata _encoded
              )
                external
                checkConfigValid(_signers.length, _transmitters.length, _threshold)
                onlyOwner()
              {
                while (s_signers.length != 0) { // remove any old signer/transmitter addresses
                  uint lastIdx = s_signers.length - 1;
                  address signer = s_signers[lastIdx];
                  address transmitter = s_transmitters[lastIdx];
                  payOracle(transmitter);
                  delete s_oracles[signer];
                  delete s_oracles[transmitter];
                  s_signers.pop();
                  s_transmitters.pop();
                }
                for (uint i = 0; i < _signers.length; i++) { // add new signer/transmitter addresses
                  require(
                    s_oracles[_signers[i]].role == Role.Unset,
                    "repeated signer address"
                  );
                  s_oracles[_signers[i]] = Oracle(uint8(i), Role.Signer);
                  require(s_payees[_transmitters[i]] != address(0), "payee must be set");
                  require(
                    s_oracles[_transmitters[i]].role == Role.Unset,
                    "repeated transmitter address"
                  );
                  s_oracles[_transmitters[i]] = Oracle(uint8(i), Role.Transmitter);
                  s_signers.push(_signers[i]);
                  s_transmitters.push(_transmitters[i]);
                }
                s_hotVars.threshold = _threshold;
                uint32 previousConfigBlockNumber = s_latestConfigBlockNumber;
                s_latestConfigBlockNumber = uint32(block.number);
                s_configCount += 1;
                uint64 configCount = s_configCount;
                {
                  s_hotVars.latestConfigDigest = configDigestFromConfigData(
                    address(this),
                    configCount,
                    _signers,
                    _transmitters,
                    _threshold,
                    _encodedConfigVersion,
                    _encoded
                  );
                  s_hotVars.latestEpochAndRound = 0;
                }
                emit ConfigSet(
                  previousConfigBlockNumber,
                  configCount,
                  _signers,
                  _transmitters,
                  _threshold,
                  _encodedConfigVersion,
                  _encoded
                );
              }
              function configDigestFromConfigData(
                address _contractAddress,
                uint64 _configCount,
                address[] calldata _signers,
                address[] calldata _transmitters,
                uint8 _threshold,
                uint64 _encodedConfigVersion,
                bytes calldata _encodedConfig
              ) internal pure returns (bytes16) {
                return bytes16(keccak256(abi.encode(_contractAddress, _configCount,
                  _signers, _transmitters, _threshold, _encodedConfigVersion, _encodedConfig
                )));
              }
              /**
               * @notice information about current offchain reporting protocol configuration
               * @return configCount ordinal number of current config, out of all configs applied to this contract so far
               * @return blockNumber block at which this config was set
               * @return configDigest domain-separation tag for current config (see configDigestFromConfigData)
               */
              function latestConfigDetails()
                external
                view
                returns (
                  uint32 configCount,
                  uint32 blockNumber,
                  bytes16 configDigest
                )
              {
                return (s_configCount, s_latestConfigBlockNumber, s_hotVars.latestConfigDigest);
              }
              /**
               * @return list of addresses permitted to transmit reports to this contract
               * @dev The list will match the order used to specify the transmitter during setConfig
               */
              function transmitters()
                external
                view
                returns(address[] memory)
              {
                  return s_transmitters;
              }
              /*
               * On-chain validation logc
               */
              // Configuration for validator
              struct ValidatorConfig {
                AggregatorValidatorInterface validator;
                uint32 gasLimit;
              }
              ValidatorConfig private s_validatorConfig;
              /**
               * @notice indicates that the validator configuration has been set
               * @param previousValidator previous validator contract
               * @param previousGasLimit previous gas limit for validate calls
               * @param currentValidator current validator contract
               * @param currentGasLimit current gas limit for validate calls
               */
              event ValidatorConfigSet(
                AggregatorValidatorInterface indexed previousValidator,
                uint32 previousGasLimit,
                AggregatorValidatorInterface indexed currentValidator,
                uint32 currentGasLimit
              );
              /**
               * @notice validator configuration
               * @return validator validator contract
               * @return gasLimit gas limit for validate calls
               */
              function validatorConfig()
                external
                view
                returns (AggregatorValidatorInterface validator, uint32 gasLimit)
              {
                ValidatorConfig memory vc = s_validatorConfig;
                return (vc.validator, vc.gasLimit);
              }
              /**
               * @notice sets validator configuration
               * @dev set _newValidator to 0x0 to disable validate calls
               * @param _newValidator address of the new validator contract
               * @param _newGasLimit new gas limit for validate calls
               */
              function setValidatorConfig(AggregatorValidatorInterface _newValidator, uint32 _newGasLimit)
                public
                onlyOwner()
              {
                ValidatorConfig memory previous = s_validatorConfig;
                if (previous.validator != _newValidator || previous.gasLimit != _newGasLimit) {
                  s_validatorConfig = ValidatorConfig({
                    validator: _newValidator,
                    gasLimit: _newGasLimit
                  });
                  emit ValidatorConfigSet(previous.validator, previous.gasLimit, _newValidator, _newGasLimit);
                }
              }
              function validateAnswer(
                uint32 _aggregatorRoundId,
                int256 _answer
              )
                private
              {
                ValidatorConfig memory vc = s_validatorConfig;
                if (address(vc.validator) == address(0)) {
                  return;
                }
                uint32 prevAggregatorRoundId = _aggregatorRoundId - 1;
                int256 prevAggregatorRoundAnswer = s_transmissions[prevAggregatorRoundId].answer;
                require(
                  callWithExactGasEvenIfTargetIsNoContract(
                    vc.gasLimit,
                    address(vc.validator),
                    abi.encodeWithSignature(
                      "validate(uint256,int256,uint256,int256)",
                      uint256(prevAggregatorRoundId),
                      prevAggregatorRoundAnswer,
                      uint256(_aggregatorRoundId),
                      _answer
                    )
                  ),
                  "insufficient gas"
                );
              }
              uint256 private constant CALL_WITH_EXACT_GAS_CUSHION = 5_000;
              /**
               * @dev calls target address with exactly gasAmount gas and data as calldata
               * or reverts if at least gasAmount gas is not available.
               */
              function callWithExactGasEvenIfTargetIsNoContract(
                uint256 _gasAmount,
                address _target,
                bytes memory _data
              )
                private
                returns (bool sufficientGas)
              {
                // solhint-disable-next-line no-inline-assembly
                assembly {
                  let g := gas()
                  // Compute g -= CALL_WITH_EXACT_GAS_CUSHION and check for underflow. We
                  // need the cushion since the logic following the above call to gas also
                  // costs gas which we cannot account for exactly. So cushion is a
                  // conservative upper bound for the cost of this logic.
                  if iszero(lt(g, CALL_WITH_EXACT_GAS_CUSHION)) {
                    g := sub(g, CALL_WITH_EXACT_GAS_CUSHION)
                    // If g - g//64 <= _gasAmount, we don't have enough gas. (We subtract g//64
                    // because of EIP-150.)
                    if gt(sub(g, div(g, 64)), _gasAmount) {
                      // Call and ignore success/return data. Note that we did not check
                      // whether a contract actually exists at the _target address.
                      pop(call(_gasAmount, _target, 0, add(_data, 0x20), mload(_data), 0, 0))
                      sufficientGas := true
                    }
                  }
                }
              }
              /*
               * requestNewRound logic
               */
              AccessControllerInterface internal s_requesterAccessController;
              /**
               * @notice emitted when a new requester access controller contract is set
               * @param old the address prior to the current setting
               * @param current the address of the new access controller contract
               */
              event RequesterAccessControllerSet(AccessControllerInterface old, AccessControllerInterface current);
              /**
               * @notice emitted to immediately request a new round
               * @param requester the address of the requester
               * @param configDigest the latest transmission's configDigest
               * @param epoch the latest transmission's epoch
               * @param round the latest transmission's round
               */
              event RoundRequested(address indexed requester, bytes16 configDigest, uint32 epoch, uint8 round);
              /**
               * @notice address of the requester access controller contract
               * @return requester access controller address
               */
              function requesterAccessController()
                external
                view
                returns (AccessControllerInterface)
              {
                return s_requesterAccessController;
              }
              /**
               * @notice sets the requester access controller
               * @param _requesterAccessController designates the address of the new requester access controller
               */
              function setRequesterAccessController(AccessControllerInterface _requesterAccessController)
                public
                onlyOwner()
              {
                AccessControllerInterface oldController = s_requesterAccessController;
                if (_requesterAccessController != oldController) {
                  s_requesterAccessController = AccessControllerInterface(_requesterAccessController);
                  emit RequesterAccessControllerSet(oldController, _requesterAccessController);
                }
              }
              /**
               * @notice immediately requests a new round
               * @return the aggregatorRoundId of the next round. Note: The report for this round may have been
               * transmitted (but not yet mined) *before* requestNewRound() was even called. There is *no*
               * guarantee of causality between the request and the report at aggregatorRoundId.
               */
              function requestNewRound() external returns (uint80) {
                require(msg.sender == owner || s_requesterAccessController.hasAccess(msg.sender, msg.data),
                  "Only owner&requester can call");
                HotVars memory hotVars = s_hotVars;
                emit RoundRequested(
                  msg.sender,
                  hotVars.latestConfigDigest,
                  uint32(s_hotVars.latestEpochAndRound >> 8),
                  uint8(s_hotVars.latestEpochAndRound)
                );
                return hotVars.latestAggregatorRoundId + 1;
              }
              /*
               * Transmission logic
               */
              /**
               * @notice indicates that a new report was transmitted
               * @param aggregatorRoundId the round to which this report was assigned
               * @param answer median of the observations attached this report
               * @param transmitter address from which the report was transmitted
               * @param observations observations transmitted with this report
               * @param rawReportContext signature-replay-prevention domain-separation tag
               */
              event NewTransmission(
                uint32 indexed aggregatorRoundId,
                int192 answer,
                address transmitter,
                int192[] observations,
                bytes observers,
                bytes32 rawReportContext
              );
              // decodeReport is used to check that the solidity and go code are using the
              // same format. See TestOffchainAggregator.testDecodeReport and TestReportParsing
              function decodeReport(bytes memory _report)
                internal
                pure
                returns (
                  bytes32 rawReportContext,
                  bytes32 rawObservers,
                  int192[] memory observations
                )
              {
                (rawReportContext, rawObservers, observations) = abi.decode(_report,
                  (bytes32, bytes32, int192[]));
              }
              // Used to relieve stack pressure in transmit
              struct ReportData {
                HotVars hotVars; // Only read from storage once
                bytes observers; // ith element is the index of the ith observer
                int192[] observations; // ith element is the ith observation
                bytes vs; // jth element is the v component of the jth signature
                bytes32 rawReportContext;
              }
              /*
               * @notice details about the most recent report
               * @return configDigest domain separation tag for the latest report
               * @return epoch epoch in which the latest report was generated
               * @return round OCR round in which the latest report was generated
               * @return latestAnswer median value from latest report
               * @return latestTimestamp when the latest report was transmitted
               */
              function latestTransmissionDetails()
                external
                view
                returns (
                  bytes16 configDigest,
                  uint32 epoch,
                  uint8 round,
                  int192 latestAnswer,
                  uint64 latestTimestamp
                )
              {
                require(msg.sender == tx.origin, "Only callable by EOA");
                return (
                  s_hotVars.latestConfigDigest,
                  uint32(s_hotVars.latestEpochAndRound >> 8),
                  uint8(s_hotVars.latestEpochAndRound),
                  s_transmissions[s_hotVars.latestAggregatorRoundId].answer,
                  s_transmissions[s_hotVars.latestAggregatorRoundId].timestamp
                );
              }
              // The constant-length components of the msg.data sent to transmit.
              // See the "If we wanted to call sam" example on for example reasoning
              // https://solidity.readthedocs.io/en/v0.7.2/abi-spec.html
              uint16 private constant TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT =
                4 + // function selector
                32 + // word containing start location of abiencoded _report value
                32 + // word containing location start of abiencoded  _rs value
                32 + // word containing start location of abiencoded _ss value
                32 + // _rawVs value
                32 + // word containing length of _report
                32 + // word containing length _rs
                32 + // word containing length of _ss
                0; // placeholder
              function expectedMsgDataLength(
                bytes calldata _report, bytes32[] calldata _rs, bytes32[] calldata _ss
              ) private pure returns (uint256 length)
              {
                // calldata will never be big enough to make this overflow
                return uint256(TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT) +
                  _report.length + // one byte pure entry in _report
                  _rs.length * 32 + // 32 bytes per entry in _rs
                  _ss.length * 32 + // 32 bytes per entry in _ss
                  0; // placeholder
              }
              /**
               * @notice transmit is called to post a new report to the contract
               * @param _report serialized report, which the signatures are signing. See parsing code below for format. The ith element of the observers component must be the index in s_signers of the address for the ith signature
               * @param _rs ith element is the R components of the ith signature on report. Must have at most maxNumOracles entries
               * @param _ss ith element is the S components of the ith signature on report. Must have at most maxNumOracles entries
               * @param _rawVs ith element is the the V component of the ith signature
               */
              function transmit(
                // NOTE: If these parameters are changed, expectedMsgDataLength and/or
                // TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT need to be changed accordingly
                bytes calldata _report,
                bytes32[] calldata _rs, bytes32[] calldata _ss, bytes32 _rawVs // signatures
              )
                external
              {
                uint256 initialGas = gasleft(); // This line must come first
                // Make sure the transmit message-length matches the inputs. Otherwise, the
                // transmitter could append an arbitrarily long (up to gas-block limit)
                // string of 0 bytes, which we would reimburse at a rate of 16 gas/byte, but
                // which would only cost the transmitter 4 gas/byte. (Appendix G of the
                // yellow paper, p. 25, for G_txdatazero and EIP 2028 for G_txdatanonzero.)
                // This could amount to reimbursement profit of 36 million gas, given a 3MB
                // zero tail.
                require(msg.data.length == expectedMsgDataLength(_report, _rs, _ss),
                  "transmit message too long");
                ReportData memory r; // Relieves stack pressure
                {
                  r.hotVars = s_hotVars; // cache read from storage
                  bytes32 rawObservers;
                  (r.rawReportContext, rawObservers, r.observations) = abi.decode(
                    _report, (bytes32, bytes32, int192[])
                  );
                  // rawReportContext consists of:
                  // 11-byte zero padding
                  // 16-byte configDigest
                  // 4-byte epoch
                  // 1-byte round
                  bytes16 configDigest = bytes16(r.rawReportContext << 88);
                  require(
                    r.hotVars.latestConfigDigest == configDigest,
                    "configDigest mismatch"
                  );
                  uint40 epochAndRound = uint40(uint256(r.rawReportContext));
                  // direct numerical comparison works here, because
                  //
                  //   ((e,r) <= (e',r')) implies (epochAndRound <= epochAndRound')
                  //
                  // because alphabetic ordering implies e <= e', and if e = e', then r<=r',
                  // so e*256+r <= e'*256+r', because r, r' < 256
                  require(r.hotVars.latestEpochAndRound < epochAndRound, "stale report");
                  require(_rs.length > r.hotVars.threshold, "not enough signatures");
                  require(_rs.length <= maxNumOracles, "too many signatures");
                  require(_ss.length == _rs.length, "signatures out of registration");
                  require(r.observations.length <= maxNumOracles,
                          "num observations out of bounds");
                  require(r.observations.length > 2 * r.hotVars.threshold,
                          "too few values to trust median");
                  // Copy signature parities in bytes32 _rawVs to bytes r.v
                  r.vs = new bytes(_rs.length);
                  for (uint8 i = 0; i < _rs.length; i++) {
                    r.vs[i] = _rawVs[i];
                  }
                  // Copy observer identities in bytes32 rawObservers to bytes r.observers
                  r.observers = new bytes(r.observations.length);
                  bool[maxNumOracles] memory seen;
                  for (uint8 i = 0; i < r.observations.length; i++) {
                    uint8 observerIdx = uint8(rawObservers[i]);
                    require(!seen[observerIdx], "observer index repeated");
                    seen[observerIdx] = true;
                    r.observers[i] = rawObservers[i];
                  }
                  Oracle memory transmitter = s_oracles[msg.sender];
                  require( // Check that sender is authorized to report
                    transmitter.role == Role.Transmitter &&
                    msg.sender == s_transmitters[transmitter.index],
                    "unauthorized transmitter"
                  );
                  // record epochAndRound here, so that we don't have to carry the local
                  // variable in transmit. The change is reverted if something fails later.
                  r.hotVars.latestEpochAndRound = epochAndRound;
                }
                { // Verify signatures attached to report
                  bytes32 h = keccak256(_report);
                  bool[maxNumOracles] memory signed;
                  Oracle memory o;
                  for (uint i = 0; i < _rs.length; i++) {
                    address signer = ecrecover(h, uint8(r.vs[i])+27, _rs[i], _ss[i]);
                    o = s_oracles[signer];
                    require(o.role == Role.Signer, "address not authorized to sign");
                    require(!signed[o.index], "non-unique signature");
                    signed[o.index] = true;
                  }
                }
                { // Check the report contents, and record the result
                  for (uint i = 0; i < r.observations.length - 1; i++) {
                    bool inOrder = r.observations[i] <= r.observations[i+1];
                    require(inOrder, "observations not sorted");
                  }
                  int192 median = r.observations[r.observations.length/2];
                  require(minAnswer <= median && median <= maxAnswer, "median is out of min-max range");
                  r.hotVars.latestAggregatorRoundId++;
                  s_transmissions[r.hotVars.latestAggregatorRoundId] =
                    Transmission(median, uint64(block.timestamp));
                  emit NewTransmission(
                    r.hotVars.latestAggregatorRoundId,
                    median,
                    msg.sender,
                    r.observations,
                    r.observers,
                    r.rawReportContext
                  );
                  // Emit these for backwards compatability with offchain consumers
                  // that only support legacy events
                  emit NewRound(
                    r.hotVars.latestAggregatorRoundId,
                    address(0x0), // use zero address since we don't have anybody "starting" the round here
                    block.timestamp
                  );
                  emit AnswerUpdated(
                    median,
                    r.hotVars.latestAggregatorRoundId,
                    block.timestamp
                  );
                  validateAnswer(r.hotVars.latestAggregatorRoundId, median);
                }
                s_hotVars = r.hotVars;
                assert(initialGas < maxUint32);
                reimburseAndRewardOracles(uint32(initialGas), r.observers);
              }
              /*
               * v2 Aggregator interface
               */
              /**
               * @notice median from the most recent report
               */
              function latestAnswer()
                public
                override
                view
                virtual
                returns (int256)
              {
                return s_transmissions[s_hotVars.latestAggregatorRoundId].answer;
              }
              /**
               * @notice timestamp of block in which last report was transmitted
               */
              function latestTimestamp()
                public
                override
                view
                virtual
                returns (uint256)
              {
                return s_transmissions[s_hotVars.latestAggregatorRoundId].timestamp;
              }
              /**
               * @notice Aggregator round (NOT OCR round) in which last report was transmitted
               */
              function latestRound()
                public
                override
                view
                virtual
                returns (uint256)
              {
                return s_hotVars.latestAggregatorRoundId;
              }
              /**
               * @notice median of report from given aggregator round (NOT OCR round)
               * @param _roundId the aggregator round of the target report
               */
              function getAnswer(uint256 _roundId)
                public
                override
                view
                virtual
                returns (int256)
              {
                if (_roundId > 0xFFFFFFFF) { return 0; }
                return s_transmissions[uint32(_roundId)].answer;
              }
              /**
               * @notice timestamp of block in which report from given aggregator round was transmitted
               * @param _roundId aggregator round (NOT OCR round) of target report
               */
              function getTimestamp(uint256 _roundId)
                public
                override
                view
                virtual
                returns (uint256)
              {
                if (_roundId > 0xFFFFFFFF) { return 0; }
                return s_transmissions[uint32(_roundId)].timestamp;
              }
              /*
               * v3 Aggregator interface
               */
              string constant private V3_NO_DATA_ERROR = "No data present";
              /**
               * @return answers are stored in fixed-point format, with this many digits of precision
               */
              uint8 immutable public override decimals;
              /**
               * @notice aggregator contract version
               */
              uint256 constant public override version = 4;
              string internal s_description;
              /**
               * @notice human-readable description of observable this contract is reporting on
               */
              function description()
                public
                override
                view
                virtual
                returns (string memory)
              {
                return s_description;
              }
              /**
               * @notice details for the given aggregator round
               * @param _roundId target aggregator round (NOT OCR round). Must fit in uint32
               * @return roundId _roundId
               * @return answer median of report from given _roundId
               * @return startedAt timestamp of block in which report from given _roundId was transmitted
               * @return updatedAt timestamp of block in which report from given _roundId was transmitted
               * @return answeredInRound _roundId
               */
              function getRoundData(uint80 _roundId)
                public
                override
                view
                virtual
                returns (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 answeredInRound
                )
              {
                require(_roundId <= 0xFFFFFFFF, V3_NO_DATA_ERROR);
                Transmission memory transmission = s_transmissions[uint32(_roundId)];
                return (
                  _roundId,
                  transmission.answer,
                  transmission.timestamp,
                  transmission.timestamp,
                  _roundId
                );
              }
              /**
               * @notice aggregator details for the most recently transmitted report
               * @return roundId aggregator round of latest report (NOT OCR round)
               * @return answer median of latest report
               * @return startedAt timestamp of block containing latest report
               * @return updatedAt timestamp of block containing latest report
               * @return answeredInRound aggregator round of latest report
               */
              function latestRoundData()
                public
                override
                view
                virtual
                returns (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 answeredInRound
                )
              {
                roundId = s_hotVars.latestAggregatorRoundId;
                // Skipped for compatability with existing FluxAggregator in which latestRoundData never reverts.
                // require(roundId != 0, V3_NO_DATA_ERROR);
                Transmission memory transmission = s_transmissions[uint32(roundId)];
                return (
                  roundId,
                  transmission.answer,
                  transmission.timestamp,
                  transmission.timestamp,
                  roundId
                );
              }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.7.6;
            import "./AccessControllerInterface.sol";
            import "./LinkTokenInterface.sol";
            import "./Owned.sol";
            /**
             * @notice tracks administration of oracle-reward and gas-reimbursement parameters.
             * @dev
             * If you read or change this, be sure to read or adjust the comments. They
             * track the units of the values under consideration, and are crucial to
             * the readability of the operations it specifies.
             * @notice
             * Trust Model:
             * Nothing in this contract prevents a billing admin from setting insane
             * values for the billing parameters in setBilling. Oracles
             * participating in this contract should regularly check that the
             * parameters make sense. Similarly, the outstanding obligations of this
             * contract to the oracles can exceed the funds held by the contract.
             * Oracles participating in this contract should regularly check that it
             * holds sufficient funds and stop interacting with it if funding runs
             * out.
             * This still leaves oracles with some risk due to TOCTOU issues.
             * However, since the sums involved are pretty small (Ethereum
             * transactions aren't that expensive in the end) and an oracle would
             * likely stop participating in a contract it repeatedly lost money on,
             * this risk is deemed acceptable. Oracles should also regularly
             * withdraw any funds in the contract to prevent issues where the
             * contract becomes underfunded at a later time, and different oracles
             * are competing for the left-over funds.
             * Finally, note that any change to the set of oracles or to the billing
             * parameters will trigger payout of all oracles first (using the old
             * parameters), a billing admin cannot take away funds that are already
             * marked for payment.
            */
            contract OffchainAggregatorBilling is Owned {
              // Maximum number of oracles the offchain reporting protocol is designed for
              uint256 constant internal maxNumOracles = 31;
              // Parameters for oracle payments
              struct Billing {
                // Highest compensated gas price, in ETH-gwei uints
                uint32 maximumGasPrice;
                // If gas price is less (in ETH-gwei units), transmitter gets half the savings
                uint32 reasonableGasPrice;
                // Pay transmitter back this much LINK per unit eth spent on gas
                // (1e-6LINK/ETH units)
                uint32 microLinkPerEth;
                // Fixed LINK reward for each observer, in LINK-gwei units
                uint32 linkGweiPerObservation;
                // Fixed reward for transmitter, in linkGweiPerObservation units
                uint32 linkGweiPerTransmission;
              }
              Billing internal s_billing;
              // We assume that the token contract is correct. This contract is not written
              // to handle misbehaving ERC20 tokens!
              LinkTokenInterface internal s_linkToken;
              AccessControllerInterface internal s_billingAccessController;
              // ith element is number of observation rewards due to ith process, plus one.
              // This is expected to saturate after an oracle has submitted 65,535
              // observations, or about 65535/(3*24*20) = 45 days, given a transmission
              // every 3 minutes.
              //
              // This is always one greater than the actual value, so that when the value is
              // reset to zero, we don't end up with a zero value in storage (which would
              // result in a higher gas cost, the next time the value is incremented.)
              // Calculations using this variable need to take that offset into account.
              uint16[maxNumOracles] internal s_oracleObservationsCounts;
              // Addresses at which oracles want to receive payments, by transmitter address
              mapping (address /* transmitter */ => address /* payment address */)
                internal
                s_payees;
              // Payee addresses which must be approved by the owner
              mapping (address /* transmitter */ => address /* payment address */)
                internal
                s_proposedPayees;
              // LINK-wei-denominated reimbursements for gas used by transmitters.
              //
              // This is always one greater than the actual value, so that when the value is
              // reset to zero, we don't end up with a zero value in storage (which would
              // result in a higher gas cost, the next time the value is incremented.)
              // Calculations using this variable need to take that offset into account.
              //
              // Argument for overflow safety:
              // We have the following maximum intermediate values:
              // - 2**40 additions to this variable (epochAndRound is a uint40)
              // - 2**32 gas price in ethgwei/gas
              // - 1e9 ethwei/ethgwei
              // - 2**32 gas since the block gas limit is at ~20 million
              // - 2**32 (microlink/eth)
              // And we have 2**40 * 2**32 * 1e9 * 2**32 * 2**32 < 2**166
              // (we also divide in some places, but that only makes the value smaller)
              // We can thus safely use uint256 intermediate values for the computation
              // updating this variable.
              uint256[maxNumOracles] internal s_gasReimbursementsLinkWei;
              // Used for s_oracles[a].role, where a is an address, to track the purpose
              // of the address, or to indicate that the address is unset.
              enum Role {
                // No oracle role has been set for address a
                Unset,
                // Signing address for the s_oracles[a].index'th oracle. I.e., report
                // signatures from this oracle should ecrecover back to address a.
                Signer,
                // Transmission address for the s_oracles[a].index'th oracle. I.e., if a
                // report is received by OffchainAggregator.transmit in which msg.sender is
                // a, it is attributed to the s_oracles[a].index'th oracle.
                Transmitter
              }
              struct Oracle {
                uint8 index; // Index of oracle in s_signers/s_transmitters
                Role role;   // Role of the address which mapped to this struct
              }
              mapping (address /* signer OR transmitter address */ => Oracle)
                internal s_oracles;
              // s_signers contains the signing address of each oracle
              address[] internal s_signers;
              // s_transmitters contains the transmission address of each oracle,
              // i.e. the address the oracle actually sends transactions to the contract from
              address[] internal s_transmitters;
              uint256 constant private  maxUint16 = (1 << 16) - 1;
              uint256 constant internal maxUint128 = (1 << 128) - 1;
              constructor(
                uint32 _maximumGasPrice,
                uint32 _reasonableGasPrice,
                uint32 _microLinkPerEth,
                uint32 _linkGweiPerObservation,
                uint32 _linkGweiPerTransmission,
                LinkTokenInterface _link,
                AccessControllerInterface _billingAccessController
              )
              {
                setBillingInternal(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
                  _linkGweiPerObservation, _linkGweiPerTransmission);
                s_linkToken = _link;
                emit LinkTokenSet(LinkTokenInterface(address(0)), _link);
                setBillingAccessControllerInternal(_billingAccessController);
                uint16[maxNumOracles] memory counts; // See s_oracleObservationsCounts docstring
                uint256[maxNumOracles] memory gas; // see s_gasReimbursementsLinkWei docstring
                for (uint8 i = 0; i < maxNumOracles; i++) {
                  counts[i] = 1;
                  gas[i] = 1;
                }
                s_oracleObservationsCounts = counts;
                s_gasReimbursementsLinkWei = gas;
              }
              /*
               * @notice emitted when the LINK token contract is set
               * @param _oldLinkToken the address of the old LINK token contract
               * @param _newLinkToken the address of the new LINK token contract
               */
              event LinkTokenSet(
                LinkTokenInterface indexed _oldLinkToken,
                LinkTokenInterface indexed _newLinkToken
              );
              /*
               * @notice sets the LINK token contract used for paying oracles
               * @param _linkToken the address of the LINK token contract
               * @param _recipient remaining funds from the previous token contract are transfered
               * here
               * @dev this function will return early (without an error) without changing any state
               * if _linkToken equals getLinkToken().
               * @dev this will trigger a payout so that a malicious owner cannot take from oracles
               * what is already owed to them.
               * @dev we assume that the token contract is correct. This contract is not written
               * to handle misbehaving ERC20 tokens!
               */
              function setLinkToken(
                LinkTokenInterface _linkToken,
                address _recipient
              ) external
                onlyOwner()
              {
                LinkTokenInterface oldLinkToken = s_linkToken;
                if (_linkToken == oldLinkToken) {
                  // No change, nothing to be done
                  return;
                }
                // call balanceOf as a sanity check on whether we're talking to a token
                // contract
                _linkToken.balanceOf(address(this));
                // we break CEI here, but that's okay because we're dealing with a correct
                // token contract (by assumption).
                payOracles();
                uint256 remainingBalance = oldLinkToken.balanceOf(address(this));
                require(oldLinkToken.transfer(_recipient, remainingBalance), "transfer remaining funds failed");
                s_linkToken = _linkToken;
                emit LinkTokenSet(oldLinkToken, _linkToken);
              }
              /*
               * @notice gets the LINK token contract used for paying oracles
               * @return linkToken the address of the LINK token contract
               */
              function getLinkToken()
                external
                view
                returns(LinkTokenInterface linkToken)
              {
                return s_linkToken;
              }
              /**
               * @notice emitted when billing parameters are set
               * @param maximumGasPrice highest gas price for which transmitter will be compensated
               * @param reasonableGasPrice transmitter will receive reward for gas prices under this value
               * @param microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
               * @param linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
               * @param linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
               */
              event BillingSet(
                uint32 maximumGasPrice,
                uint32 reasonableGasPrice,
                uint32 microLinkPerEth,
                uint32 linkGweiPerObservation,
                uint32 linkGweiPerTransmission
              );
              function setBillingInternal(
                uint32 _maximumGasPrice,
                uint32 _reasonableGasPrice,
                uint32 _microLinkPerEth,
                uint32 _linkGweiPerObservation,
                uint32 _linkGweiPerTransmission
              )
                internal
              {
                s_billing = Billing(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
                  _linkGweiPerObservation, _linkGweiPerTransmission);
                emit BillingSet(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
                  _linkGweiPerObservation, _linkGweiPerTransmission);
              }
              /**
               * @notice sets billing parameters
               * @param _maximumGasPrice highest gas price for which transmitter will be compensated
               * @param _reasonableGasPrice transmitter will receive reward for gas prices under this value
               * @param _microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
               * @param _linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
               * @param _linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
               * @dev access control provided by billingAccessController
               */
              function setBilling(
                uint32 _maximumGasPrice,
                uint32 _reasonableGasPrice,
                uint32 _microLinkPerEth,
                uint32 _linkGweiPerObservation,
                uint32 _linkGweiPerTransmission
              )
                external
              {
                AccessControllerInterface access = s_billingAccessController;
                require(msg.sender == owner || access.hasAccess(msg.sender, msg.data),
                  "Only owner&billingAdmin can call");
                payOracles();
                setBillingInternal(_maximumGasPrice, _reasonableGasPrice, _microLinkPerEth,
                  _linkGweiPerObservation, _linkGweiPerTransmission);
              }
              /**
               * @notice gets billing parameters
               * @param maximumGasPrice highest gas price for which transmitter will be compensated
               * @param reasonableGasPrice transmitter will receive reward for gas prices under this value
               * @param microLinkPerEth reimbursement per ETH of gas cost, in 1e-6LINK units
               * @param linkGweiPerObservation reward to oracle for contributing an observation to a successfully transmitted report, in 1e-9LINK units
               * @param linkGweiPerTransmission reward to transmitter of a successful report, in 1e-9LINK units
               */
              function getBilling()
                external
                view
                returns (
                  uint32 maximumGasPrice,
                  uint32 reasonableGasPrice,
                  uint32 microLinkPerEth,
                  uint32 linkGweiPerObservation,
                  uint32 linkGweiPerTransmission
                )
              {
                Billing memory billing = s_billing;
                return (
                  billing.maximumGasPrice,
                  billing.reasonableGasPrice,
                  billing.microLinkPerEth,
                  billing.linkGweiPerObservation,
                  billing.linkGweiPerTransmission
                );
              }
              /**
               * @notice emitted when a new access-control contract is set
               * @param old the address prior to the current setting
               * @param current the address of the new access-control contract
               */
              event BillingAccessControllerSet(AccessControllerInterface old, AccessControllerInterface current);
              function setBillingAccessControllerInternal(AccessControllerInterface _billingAccessController)
                internal
              {
                AccessControllerInterface oldController = s_billingAccessController;
                if (_billingAccessController != oldController) {
                  s_billingAccessController = _billingAccessController;
                  emit BillingAccessControllerSet(
                    oldController,
                    _billingAccessController
                  );
                }
              }
              /**
               * @notice sets billingAccessController
               * @param _billingAccessController new billingAccessController contract address
               * @dev only owner can call this
               */
              function setBillingAccessController(AccessControllerInterface _billingAccessController)
                external
                onlyOwner
              {
                setBillingAccessControllerInternal(_billingAccessController);
              }
              /**
               * @notice gets billingAccessController
               * @return address of billingAccessController contract
               */
              function billingAccessController()
                external
                view
                returns (AccessControllerInterface)
              {
                return s_billingAccessController;
              }
              /**
               * @notice withdraws an oracle's payment from the contract
               * @param _transmitter the transmitter address of the oracle
               * @dev must be called by oracle's payee address
               */
              function withdrawPayment(address _transmitter)
                external
              {
                require(msg.sender == s_payees[_transmitter], "Only payee can withdraw");
                payOracle(_transmitter);
              }
              /**
               * @notice query an oracle's payment amount
               * @param _transmitter the transmitter address of the oracle
               */
              function owedPayment(address _transmitter)
                public
                view
                returns (uint256)
              {
                Oracle memory oracle = s_oracles[_transmitter];
                if (oracle.role == Role.Unset) { return 0; }
                Billing memory billing = s_billing;
                uint256 linkWeiAmount =
                  uint256(s_oracleObservationsCounts[oracle.index] - 1) *
                  uint256(billing.linkGweiPerObservation) *
                  (1 gwei);
                linkWeiAmount += s_gasReimbursementsLinkWei[oracle.index] - 1;
                return linkWeiAmount;
              }
              /**
               * @notice emitted when an oracle has been paid LINK
               * @param transmitter address from which the oracle sends reports to the transmit method
               * @param payee address to which the payment is sent
               * @param amount amount of LINK sent
               * @param linkToken address of the LINK token contract
               */
              event OraclePaid(
                address indexed transmitter,
                address indexed payee,
                uint256 amount,
                LinkTokenInterface indexed linkToken
              );
              // payOracle pays out _transmitter's balance to the corresponding payee, and zeros it out
              function payOracle(address _transmitter)
                internal
              {
                Oracle memory oracle = s_oracles[_transmitter];
                uint256 linkWeiAmount = owedPayment(_transmitter);
                if (linkWeiAmount > 0) {
                  address payee = s_payees[_transmitter];
                  // Poses no re-entrancy issues, because LINK.transfer does not yield
                  // control flow.
                  require(s_linkToken.transfer(payee, linkWeiAmount), "insufficient funds");
                  s_oracleObservationsCounts[oracle.index] = 1; // "zero" the counts. see var's docstring
                  s_gasReimbursementsLinkWei[oracle.index] = 1; // "zero" the counts. see var's docstring
                  emit OraclePaid(_transmitter, payee, linkWeiAmount, s_linkToken);
                }
              }
              // payOracles pays out all transmitters, and zeros out their balances.
              //
              // It's much more gas-efficient to do this as a single operation, to avoid
              // hitting storage too much.
              function payOracles()
                internal
              {
                Billing memory billing = s_billing;
                LinkTokenInterface linkToken = s_linkToken;
                uint16[maxNumOracles] memory observationsCounts = s_oracleObservationsCounts;
                uint256[maxNumOracles] memory gasReimbursementsLinkWei =
                  s_gasReimbursementsLinkWei;
                address[] memory transmitters = s_transmitters;
                for (uint transmitteridx = 0; transmitteridx < transmitters.length; transmitteridx++) {
                  uint256 reimbursementAmountLinkWei = gasReimbursementsLinkWei[transmitteridx] - 1;
                  uint256 obsCount = observationsCounts[transmitteridx] - 1;
                  uint256 linkWeiAmount =
                    obsCount * uint256(billing.linkGweiPerObservation) * (1 gwei) + reimbursementAmountLinkWei;
                  if (linkWeiAmount > 0) {
                      address payee = s_payees[transmitters[transmitteridx]];
                      // Poses no re-entrancy issues, because LINK.transfer does not yield
                      // control flow.
                      require(linkToken.transfer(payee, linkWeiAmount), "insufficient funds");
                      observationsCounts[transmitteridx] = 1;       // "zero" the counts.
                      gasReimbursementsLinkWei[transmitteridx] = 1; // "zero" the counts.
                      emit OraclePaid(transmitters[transmitteridx], payee, linkWeiAmount, linkToken);
                    }
                }
                // "Zero" the accounting storage variables
                s_oracleObservationsCounts = observationsCounts;
                s_gasReimbursementsLinkWei = gasReimbursementsLinkWei;
              }
              function oracleRewards(
                bytes memory observers,
                uint16[maxNumOracles] memory observations
              )
                internal
                pure
                returns (uint16[maxNumOracles] memory)
              {
                // reward each observer-participant with the observer reward
                for (uint obsIdx = 0; obsIdx < observers.length; obsIdx++) {
                  uint8 observer = uint8(observers[obsIdx]);
                  observations[observer] = saturatingAddUint16(observations[observer], 1);
                }
                return observations;
              }
              // This value needs to change if maxNumOracles is increased, or the accounting
              // calculations at the bottom of reimburseAndRewardOracles change.
              //
              // To recalculate it, run the profiler as described in
              // ../../profile/README.md, and add up the gas-usage values reported for the
              // lines in reimburseAndRewardOracles following the "gasLeft = gasleft()"
              // line. E.g., you will see output like this:
              //
              //      7        uint256 gasLeft = gasleft();
              //     29        uint256 gasCostEthWei = transmitterGasCostEthWei(
              //      9          uint256(initialGas),
              //      3          gasPrice,
              //      3          callDataGasCost,
              //      3          gasLeft
              //      .
              //      .
              //      .
              //     59        uint256 gasCostLinkWei = (gasCostEthWei * billing.microLinkPerEth)/ 1e6;
              //      .
              //      .
              //      .
              //   5047        s_gasReimbursementsLinkWei[txOracle.index] =
              //    856          s_gasReimbursementsLinkWei[txOracle.index] + gasCostLinkWei +
              //     26          uint256(billing.linkGweiPerTransmission) * (1 gwei);
              //
              // If those were the only lines to be accounted for, you would add up
              // 29+9+3+3+3+59+5047+856+26=6035.
              uint256 internal constant accountingGasCost = 6035;
              // Uncomment the following declaration to compute the remaining gas cost after
              // above gasleft(). (This must exist in a base class to OffchainAggregator, so
              // it can't go in TestOffchainAggregator.)
              //
              // uint256 public gasUsedInAccounting;
              // Gas price at which the transmitter should be reimbursed, in ETH-gwei/gas
              function impliedGasPrice(
                uint256 txGasPrice,         // ETH-gwei/gas units
                uint256 reasonableGasPrice, // ETH-gwei/gas units
                uint256 maximumGasPrice     // ETH-gwei/gas units
              )
                internal
                pure
                returns (uint256)
              {
                // Reward the transmitter for choosing an efficient gas price: if they manage
                // to come in lower than considered reasonable, give them half the savings.
                //
                // The following calculations are all in units of gwei/gas, i.e. 1e-9ETH/gas
                uint256 gasPrice = txGasPrice;
                if (txGasPrice < reasonableGasPrice) {
                  // Give transmitter half the savings for coming in under the reasonable gas price
                  gasPrice += (reasonableGasPrice - txGasPrice) / 2;
                }
                // Don't reimburse a gas price higher than maximumGasPrice
                return min(gasPrice, maximumGasPrice);
              }
              // gas reimbursement due the transmitter, in ETH-wei
              //
              // If this function is changed, accountingGasCost needs to change, too. See
              // its docstring
              function transmitterGasCostEthWei(
                uint256 initialGas,
                uint256 gasPrice, // ETH-gwei/gas units
                uint256 callDataCost, // gas units
                uint256 gasLeft
              )
                internal
                pure
                returns (uint128 gasCostEthWei)
              {
                require(initialGas >= gasLeft, "gasLeft cannot exceed initialGas");
                uint256 gasUsed = // gas units
                  initialGas - gasLeft + // observed gas usage
                  callDataCost + accountingGasCost; // estimated gas usage
                // gasUsed is in gas units, gasPrice is in ETH-gwei/gas units; convert to ETH-wei
                uint256 fullGasCostEthWei = gasUsed * gasPrice * (1 gwei);
                assert(fullGasCostEthWei < maxUint128); // the entire ETH supply fits in a uint128...
                return uint128(fullGasCostEthWei);
              }
              /**
               * @notice withdraw any available funds left in the contract, up to _amount, after accounting for the funds due to participants in past reports
               * @param _recipient address to send funds to
               * @param _amount maximum amount to withdraw, denominated in LINK-wei.
               * @dev access control provided by billingAccessController
               */
              function withdrawFunds(address _recipient, uint256 _amount)
                external
              {
                require(msg.sender == owner || s_billingAccessController.hasAccess(msg.sender, msg.data),
                  "Only owner&billingAdmin can call");
                uint256 linkDue = totalLINKDue();
                uint256 linkBalance = s_linkToken.balanceOf(address(this));
                require(linkBalance >= linkDue, "insufficient balance");
                require(s_linkToken.transfer(_recipient, min(linkBalance - linkDue, _amount)), "insufficient funds");
              }
              // Total LINK due to participants in past reports.
              function totalLINKDue()
                internal
                view
                returns (uint256 linkDue)
              {
                // Argument for overflow safety: We do all computations in
                // uint256s. The inputs to linkDue are:
                // - the <= 31 observation rewards each of which has less than
                //   64 bits (32 bits for billing.linkGweiPerObservation, 32 bits
                //   for wei/gwei conversion). Hence 69 bits are sufficient for this part.
                // - the <= 31 gas reimbursements, each of which consists of at most 166
                //   bits (see s_gasReimbursementsLinkWei docstring). Hence 171 bits are
                //   sufficient for this part
                // In total, 172 bits are enough.
                uint16[maxNumOracles] memory observationCounts = s_oracleObservationsCounts;
                for (uint i = 0; i < maxNumOracles; i++) {
                  linkDue += observationCounts[i] - 1; // Stored value is one greater than actual value
                }
                Billing memory billing = s_billing;
                // Convert linkGweiPerObservation to uint256, or this overflows!
                linkDue *= uint256(billing.linkGweiPerObservation) * (1 gwei);
                address[] memory transmitters = s_transmitters;
                uint256[maxNumOracles] memory gasReimbursementsLinkWei =
                  s_gasReimbursementsLinkWei;
                for (uint i = 0; i < transmitters.length; i++) {
                  linkDue += uint256(gasReimbursementsLinkWei[i]-1); // Stored value is one greater than actual value
                }
              }
              /**
               * @notice allows oracles to check that sufficient LINK balance is available
               * @return availableBalance LINK available on this contract, after accounting for outstanding obligations. can become negative
               */
              function linkAvailableForPayment()
                external
                view
                returns (int256 availableBalance)
              {
                // there are at most one billion LINK, so this cast is safe
                int256 balance = int256(s_linkToken.balanceOf(address(this)));
                // according to the argument in the definition of totalLINKDue,
                // totalLINKDue is never greater than 2**172, so this cast is safe
                int256 due = int256(totalLINKDue());
                // safe from overflow according to above sizes
                return int256(balance) - int256(due);
              }
              /**
               * @notice number of observations oracle is due to be reimbursed for
               * @param _signerOrTransmitter address used by oracle for signing or transmitting reports
               */
              function oracleObservationCount(address _signerOrTransmitter)
                external
                view
                returns (uint16)
              {
                Oracle memory oracle = s_oracles[_signerOrTransmitter];
                if (oracle.role == Role.Unset) { return 0; }
                return s_oracleObservationsCounts[oracle.index] - 1;
              }
              function reimburseAndRewardOracles(
                uint32 initialGas,
                bytes memory observers
              )
                internal
              {
                Oracle memory txOracle = s_oracles[msg.sender];
                Billing memory billing = s_billing;
                // Reward oracles for providing observations. Oracles are not rewarded
                // for providing signatures, because signing is essentially free.
                s_oracleObservationsCounts =
                  oracleRewards(observers, s_oracleObservationsCounts);
                // Reimburse transmitter of the report for gas usage
                require(txOracle.role == Role.Transmitter,
                  "sent by undesignated transmitter"
                );
                uint256 gasPrice = impliedGasPrice(
                  tx.gasprice / (1 gwei), // convert to ETH-gwei units
                  billing.reasonableGasPrice,
                  billing.maximumGasPrice
                );
                // The following is only an upper bound, as it ignores the cheaper cost for
                // 0 bytes. Safe from overflow, because calldata just isn't that long.
                uint256 callDataGasCost = 16 * msg.data.length;
                // If any changes are made to subsequent calculations, accountingGasCost
                // needs to change, too.
                uint256 gasLeft = gasleft();
                uint256 gasCostEthWei = transmitterGasCostEthWei(
                  uint256(initialGas),
                  gasPrice,
                  callDataGasCost,
                  gasLeft
                );
                // microLinkPerEth is 1e-6LINK/ETH units, gasCostEthWei is 1e-18ETH units
                // (ETH-wei), product is 1e-24LINK-wei units, dividing by 1e6 gives
                // 1e-18LINK units, i.e. LINK-wei units
                // Safe from over/underflow, since all components are non-negative,
                // gasCostEthWei will always fit into uint128 and microLinkPerEth is a
                // uint32 (128+32 < 256!).
                uint256 gasCostLinkWei = (gasCostEthWei * billing.microLinkPerEth)/ 1e6;
                // Safe from overflow, because gasCostLinkWei < 2**160 and
                // billing.linkGweiPerTransmission * (1 gwei) < 2**64 and we increment
                // s_gasReimbursementsLinkWei[txOracle.index] at most 2**40 times.
                s_gasReimbursementsLinkWei[txOracle.index] =
                  s_gasReimbursementsLinkWei[txOracle.index] + gasCostLinkWei +
                  uint256(billing.linkGweiPerTransmission) * (1 gwei); // convert from linkGwei to linkWei
                // Uncomment next line to compute the remaining gas cost after above gasleft().
                // See OffchainAggregatorBilling.accountingGasCost docstring for more information.
                //
                // gasUsedInAccounting = gasLeft - gasleft();
              }
              /*
               * Payee management
               */
              /**
               * @notice emitted when a transfer of an oracle's payee address has been initiated
               * @param transmitter address from which the oracle sends reports to the transmit method
               * @param current the payeee address for the oracle, prior to this setting
               * @param proposed the proposed new payee address for the oracle
               */
              event PayeeshipTransferRequested(
                address indexed transmitter,
                address indexed current,
                address indexed proposed
              );
              /**
               * @notice emitted when a transfer of an oracle's payee address has been completed
               * @param transmitter address from which the oracle sends reports to the transmit method
               * @param current the payeee address for the oracle, prior to this setting
               */
              event PayeeshipTransferred(
                address indexed transmitter,
                address indexed previous,
                address indexed current
              );
              /**
               * @notice sets the payees for transmitting addresses
               * @param _transmitters addresses oracles use to transmit the reports
               * @param _payees addresses of payees corresponding to list of transmitters
               * @dev must be called by owner
               * @dev cannot be used to change payee addresses, only to initially populate them
               */
              function setPayees(
                address[] calldata _transmitters,
                address[] calldata _payees
              )
                external
                onlyOwner()
              {
                require(_transmitters.length == _payees.length, "transmitters.size != payees.size");
                for (uint i = 0; i < _transmitters.length; i++) {
                  address transmitter = _transmitters[i];
                  address payee = _payees[i];
                  address currentPayee = s_payees[transmitter];
                  bool zeroedOut = currentPayee == address(0);
                  require(zeroedOut || currentPayee == payee, "payee already set");
                  s_payees[transmitter] = payee;
                  if (currentPayee != payee) {
                    emit PayeeshipTransferred(transmitter, currentPayee, payee);
                  }
                }
              }
              /**
               * @notice first step of payeeship transfer (safe transfer pattern)
               * @param _transmitter transmitter address of oracle whose payee is changing
               * @param _proposed new payee address
               * @dev can only be called by payee address
               */
              function transferPayeeship(
                address _transmitter,
                address _proposed
              )
                external
              {
                  require(msg.sender == s_payees[_transmitter], "only current payee can update");
                  require(msg.sender != _proposed, "cannot transfer to self");
                  address previousProposed = s_proposedPayees[_transmitter];
                  s_proposedPayees[_transmitter] = _proposed;
                  if (previousProposed != _proposed) {
                    emit PayeeshipTransferRequested(_transmitter, msg.sender, _proposed);
                  }
              }
              /**
               * @notice second step of payeeship transfer (safe transfer pattern)
               * @param _transmitter transmitter address of oracle whose payee is changing
               * @dev can only be called by proposed new payee address
               */
              function acceptPayeeship(
                address _transmitter
              )
                external
              {
                require(msg.sender == s_proposedPayees[_transmitter], "only proposed payees can accept");
                address currentPayee = s_payees[_transmitter];
                s_payees[_transmitter] = msg.sender;
                s_proposedPayees[_transmitter] = address(0);
                emit PayeeshipTransferred(_transmitter, currentPayee, msg.sender);
              }
              /*
               * Helper functions
               */
              function saturatingAddUint16(uint16 _x, uint16 _y)
                internal
                pure
                returns (uint16)
              {
                return uint16(min(uint256(_x)+uint256(_y), maxUint16));
              }
              function min(uint256 a, uint256 b)
                internal
                pure
                returns (uint256)
              {
                if (a < b) { return a; }
                return b;
              }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.7.6;
            /**
             * @title The Owned contract
             * @notice A contract with helpers for basic contract ownership.
             */
            contract Owned {
              address payable public owner;
              address private pendingOwner;
              event OwnershipTransferRequested(
                address indexed from,
                address indexed to
              );
              event OwnershipTransferred(
                address indexed from,
                address indexed to
              );
              constructor() {
                owner = msg.sender;
              }
              /**
               * @dev Allows an owner to begin transferring ownership to a new address,
               * pending.
               */
              function transferOwnership(address _to)
                external
                onlyOwner()
              {
                pendingOwner = _to;
                emit OwnershipTransferRequested(owner, _to);
              }
              /**
               * @dev Allows an ownership transfer to be completed by the recipient.
               */
              function acceptOwnership()
                external
              {
                require(msg.sender == pendingOwner, "Must be proposed owner");
                address oldOwner = owner;
                owner = msg.sender;
                pendingOwner = address(0);
                emit OwnershipTransferred(oldOwner, msg.sender);
              }
              /**
               * @dev Reverts if called by anyone other than the contract owner.
               */
              modifier onlyOwner() {
                require(msg.sender == owner, "Only callable by owner");
                _;
              }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.7.6;
            import "./SimpleWriteAccessController.sol";
            /**
             * @title SimpleReadAccessController
             * @notice Gives access to:
             * - any externally owned account (note that offchain actors can always read
             * any contract storage regardless of onchain access control measures, so this
             * does not weaken the access control while improving usability)
             * - accounts explicitly added to an access list
             * @dev SimpleReadAccessController is not suitable for access controlling writes
             * since it grants any externally owned account access! See
             * SimpleWriteAccessController for that.
             */
            contract SimpleReadAccessController is SimpleWriteAccessController {
              /**
               * @notice Returns the access of an address
               * @param _user The address to query
               */
              function hasAccess(
                address _user,
                bytes memory _calldata
              )
                public
                view
                virtual
                override
                returns (bool)
              {
                return super.hasAccess(_user, _calldata) || _user == tx.origin;
              }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.7.6;
            import "./Owned.sol";
            import "./AccessControllerInterface.sol";
            /**
             * @title SimpleWriteAccessController
             * @notice Gives access to accounts explicitly added to an access list by the
             * controller's owner.
             * @dev does not make any special permissions for externally, see
             * SimpleReadAccessController for that.
             */
            contract SimpleWriteAccessController is AccessControllerInterface, Owned {
              bool public checkEnabled;
              mapping(address => bool) internal accessList;
              event AddedAccess(address user);
              event RemovedAccess(address user);
              event CheckAccessEnabled();
              event CheckAccessDisabled();
              constructor()
              {
                checkEnabled = true;
              }
              /**
               * @notice Returns the access of an address
               * @param _user The address to query
               */
              function hasAccess(
                address _user,
                bytes memory
              )
                public
                view
                virtual
                override
                returns (bool)
              {
                return accessList[_user] || !checkEnabled;
              }
              /**
               * @notice Adds an address to the access list
               * @param _user The address to add
               */
              function addAccess(address _user) external onlyOwner() {
                addAccessInternal(_user);
              }
              function addAccessInternal(address _user) internal {
                if (!accessList[_user]) {
                  accessList[_user] = true;
                  emit AddedAccess(_user);
                }
              }
              /**
               * @notice Removes an address from the access list
               * @param _user The address to remove
               */
              function removeAccess(address _user)
                external
                onlyOwner()
              {
                if (accessList[_user]) {
                  accessList[_user] = false;
                  emit RemovedAccess(_user);
                }
              }
              /**
               * @notice makes the access check enforced
               */
              function enableAccessCheck()
                external
                onlyOwner()
              {
                if (!checkEnabled) {
                  checkEnabled = true;
                  emit CheckAccessEnabled();
                }
              }
              /**
               * @notice makes the access check unenforced
               */
              function disableAccessCheck()
                external
                onlyOwner()
              {
                if (checkEnabled) {
                  checkEnabled = false;
                  emit CheckAccessDisabled();
                }
              }
              /**
               * @dev reverts if the caller does not have access
               */
              modifier checkAccess() {
                require(hasAccess(msg.sender, msg.data), "No access");
                _;
              }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.7.0;
            abstract contract TypeAndVersionInterface{
              function typeAndVersion()
                external
                pure
                virtual
                returns (string memory);
            }

            File 7 of 7: stakingManager
            // 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 v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
            pragma solidity ^0.8.0;
            /**
             * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
             * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
             *
             * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
             * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
             * need to send a transaction, and thus is not required to hold Ether at all.
             */
            interface IERC20PermitUpgradeable {
                /**
                 * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
                 * given ``owner``'s signed approval.
                 *
                 * IMPORTANT: The same issues {IERC20-approve} has related to transaction
                 * ordering also apply here.
                 *
                 * Emits an {Approval} event.
                 *
                 * Requirements:
                 *
                 * - `spender` cannot be the zero address.
                 * - `deadline` must be a timestamp in the future.
                 * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
                 * over the EIP712-formatted function arguments.
                 * - the signature must use ``owner``'s current nonce (see {nonces}).
                 *
                 * For more information on the signature format, see the
                 * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
                 * section].
                 */
                function permit(
                    address owner,
                    address spender,
                    uint256 value,
                    uint256 deadline,
                    uint8 v,
                    bytes32 r,
                    bytes32 s
                ) external;
                /**
                 * @dev Returns the current nonce for `owner`. This value must be
                 * included whenever a signature is generated for {permit}.
                 *
                 * Every successful call to {permit} increases ``owner``'s nonce by one. This
                 * prevents a signature from being used multiple times.
                 */
                function nonces(address owner) external view returns (uint256);
                /**
                 * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
                 */
                // solhint-disable-next-line func-name-mixedcase
                function DOMAIN_SEPARATOR() external view returns (bytes32);
            }
            // 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) (token/ERC20/utils/SafeERC20.sol)
            pragma solidity ^0.8.0;
            import "../IERC20Upgradeable.sol";
            import "../extensions/draft-IERC20PermitUpgradeable.sol";
            import "../../../utils/AddressUpgradeable.sol";
            /**
             * @title SafeERC20
             * @dev Wrappers around ERC20 operations that throw on failure (when the token
             * contract returns false). Tokens that return no value (and instead revert or
             * throw on failure) are also supported, non-reverting calls are assumed to be
             * successful.
             * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
             * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
             */
            library SafeERC20Upgradeable {
                using AddressUpgradeable for address;
                function safeTransfer(
                    IERC20Upgradeable token,
                    address to,
                    uint256 value
                ) internal {
                    _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
                }
                function safeTransferFrom(
                    IERC20Upgradeable token,
                    address from,
                    address to,
                    uint256 value
                ) internal {
                    _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
                }
                /**
                 * @dev Deprecated. This function has issues similar to the ones found in
                 * {IERC20-approve}, and its usage is discouraged.
                 *
                 * Whenever possible, use {safeIncreaseAllowance} and
                 * {safeDecreaseAllowance} instead.
                 */
                function safeApprove(
                    IERC20Upgradeable token,
                    address spender,
                    uint256 value
                ) internal {
                    // safeApprove should only be called when setting an initial allowance,
                    // or when resetting it to zero. To increase and decrease it, use
                    // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
                    require(
                        (value == 0) || (token.allowance(address(this), spender) == 0),
                        "SafeERC20: approve from non-zero to non-zero allowance"
                    );
                    _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
                }
                function safeIncreaseAllowance(
                    IERC20Upgradeable token,
                    address spender,
                    uint256 value
                ) internal {
                    uint256 newAllowance = token.allowance(address(this), spender) + value;
                    _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                }
                function safeDecreaseAllowance(
                    IERC20Upgradeable token,
                    address spender,
                    uint256 value
                ) internal {
                    unchecked {
                        uint256 oldAllowance = token.allowance(address(this), spender);
                        require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
                        uint256 newAllowance = oldAllowance - value;
                        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                    }
                }
                function safePermit(
                    IERC20PermitUpgradeable token,
                    address owner,
                    address spender,
                    uint256 value,
                    uint256 deadline,
                    uint8 v,
                    bytes32 r,
                    bytes32 s
                ) internal {
                    uint256 nonceBefore = token.nonces(owner);
                    token.permit(owner, spender, value, deadline, v, r, s);
                    uint256 nonceAfter = token.nonces(owner);
                    require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
                }
                /**
                 * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
                 * on the return value: the return value is optional (but if data is returned, it must not be false).
                 * @param token The token targeted by the call.
                 * @param data The call data (encoded using abi.encode or one of its variants).
                 */
                function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {
                    // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                    // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
                    // the target address contains contract code and also asserts for success in the low-level call.
                    bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
                    if (returndata.length > 0) {
                        // Return data is optional
                        require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
                    }
                }
            }
            // 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: Unlicense
            pragma solidity 0.8.9;
            import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
            import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
            import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
            contract stakingManager is OwnableUpgradeable {
                using SafeERC20Upgradeable for IERC20Upgradeable; // Wrappers around ERC20 operations that throw on failure
                IERC20Upgradeable public stakeToken; // Token to be staked and rewarded
                address public presaleContract; //presale contract address
                uint256 public tokensStakedByPresale; //total tokens staked by preSale
                uint256 public tokensStaked; // Total tokens staked
                uint256 private lastRewardedBlock; // Last block number the user had their rewards calculated
                uint256 private accumulatedRewardsPerShare; // Accumulated rewards per share times REWARDS_PRECISION
                uint256 public rewardTokensPerBlock; // Number of reward tokens minted per block
                uint256 private constant REWARDS_PRECISION = 1e12; // A big number to perform mul and div operations
                uint256 public lockedTime; //To lock the tokens in contract for definite time.
                bool public harvestLock; //To lock the harvest/claim.
                uint public endBlock; //At this block,the rewards generation will be stopped.
                uint256 public claimStart; //Users can claim after this time in epoch.
                // Staking user for a pool
                struct PoolStaker {
                    uint256 amount; // The tokens quantity the user has staked.
                    uint256 stakedTime; //the time at tokens staked
                    uint256 lastUpdatedBlock;
                    uint256 Harvestedrewards; // The reward tokens quantity the user  harvested
                    uint256 rewardDebt; // The amount relative to accumulatedRewardsPerShare the user can't get as reward
                }
                //  staker address => PoolStaker
                mapping(address => PoolStaker) public poolStakers;
                mapping(address => bool) public isBlacklisted;
                mapping(address => uint) public userLockedRewards;
                // Events
                event Deposit(address indexed user, uint256 amount);
                event Withdraw(address indexed user, uint256 amount);
                event HarvestRewards(address indexed user, uint256 amount);
                /// @custom:oz-upgrades-unsafe-allow constructor
                constructor() {
                    _disableInitializers();
                }
                function initialize(
                    address _rewardTokenAddress,
                    address _presale,
                    uint256 _rewardTokensPerBlock,
                    uint _lockTime,
                    uint _endBlock
                ) public initializer {
                    __Ownable_init_unchained();
                    rewardTokensPerBlock = _rewardTokensPerBlock;
                    stakeToken = IERC20Upgradeable(_rewardTokenAddress);
                    presaleContract = _presale;
                    lockedTime = _lockTime;
                    endBlock = _endBlock;
                    harvestLock = true;
                }
                modifier onlyPresale() {
                    require(
                        msg.sender == presaleContract,
                        "This method is only for presale Contract"
                    );
                    _;
                }
                /**
                 * @dev Deposit tokens to the pool
                 */
                function deposit(uint256 _amount) external {
                    require(block.number < endBlock, "staking has been ended");
                    require(_amount > 0, "Deposit amount can't be zero");
                    PoolStaker storage staker = poolStakers[msg.sender];
                    // Update pool stakers
                    harvestRewards();
                    // Update current staker
                    staker.amount += _amount;
                    staker.rewardDebt =
                        (staker.amount * accumulatedRewardsPerShare) /
                        REWARDS_PRECISION;
                    staker.stakedTime = block.timestamp;
                    staker.lastUpdatedBlock = block.number;
                    // Update pool
                    tokensStaked += _amount;
                    // Deposit tokens
                    emit Deposit(msg.sender, _amount);
                    stakeToken.safeTransferFrom(msg.sender, address(this), _amount);
                }
                /**
                 * @dev Deposit tokens to  pool by presale contract
                 */
                function depositByPresale(
                    address _user,
                    uint256 _amount
                ) external onlyPresale {
                    require(block.number < endBlock, "staking has been ended");
                    require(_amount > 0, "Deposit amount can't be zero");
                    PoolStaker storage staker = poolStakers[_user];
                    // Update pool stakers
                    _harvestRewards(_user);
                    // Update current staker
                    staker.amount += _amount;
                    staker.rewardDebt =
                        (staker.amount * accumulatedRewardsPerShare) /
                        REWARDS_PRECISION;
                    staker.stakedTime = block.timestamp;
                    // Update pool
                    tokensStaked += _amount;
                    tokensStakedByPresale += _amount;
                    // Deposit tokens
                    emit Deposit(_user, _amount);
                    stakeToken.safeTransferFrom(presaleContract, address(this), _amount);
                }
                /**
                 * @dev Withdraw all tokens from existing pool
                 */
                function withdraw() external {
                    PoolStaker memory staker = poolStakers[msg.sender];
                    uint256 amount = staker.amount;
                    require(
                        staker.stakedTime + lockedTime <= block.timestamp &&
                            claimStart + lockedTime <= block.timestamp,
                        "you are not allowed to withdraw before locked Time"
                    );
                    require(amount > 0, "Withdraw amount can't be zero");
                    // Pay rewards
                    harvestRewards();
                    //delete staker
                    delete poolStakers[msg.sender];
                    // Update pool
                    tokensStaked -= amount;
                    // Withdraw tokens
                    emit Withdraw(msg.sender, amount);
                    stakeToken.safeTransfer(msg.sender, amount);
                }
                /**
                 * @dev Harvest user rewards
                 */
                function harvestRewards() public {
                    _harvestRewards(msg.sender);
                }
                /**
                 * @dev Harvest user rewards
                 */
                function _harvestRewards(address _user) private {
                    require(!isBlacklisted[_user], "This Address is Blacklisted");
                    updatePoolRewards();
                    PoolStaker storage staker = poolStakers[_user];
                    uint256 rewardsToHarvest = ((staker.amount *
                        accumulatedRewardsPerShare) / REWARDS_PRECISION) -
                        staker.rewardDebt;
                    if (rewardsToHarvest == 0) {
                        return;
                    }
                    staker.Harvestedrewards += rewardsToHarvest;
                    staker.rewardDebt =
                        (staker.amount * accumulatedRewardsPerShare) /
                        REWARDS_PRECISION;
                    if (!harvestLock) {
                        if (userLockedRewards[_user] > 0) {
                            rewardsToHarvest += userLockedRewards[_user];
                            userLockedRewards[_user] = 0;
                        }
                        emit HarvestRewards(_user, rewardsToHarvest);
                        stakeToken.safeTransfer(_user, rewardsToHarvest);
                    } else {
                        userLockedRewards[_user] += rewardsToHarvest;
                    }
                }
                /**
                 * @dev Update pool's accumulatedRewardsPerShare and lastRewardedBlock
                 */
                function updatePoolRewards() private {
                    if (tokensStaked == 0) {
                        lastRewardedBlock = block.number;
                        return;
                    }
                    uint256 blocksSinceLastReward = block.number > endBlock
                        ? endBlock - lastRewardedBlock
                        : block.number - lastRewardedBlock;
                    uint256 rewards = blocksSinceLastReward * rewardTokensPerBlock;
                    accumulatedRewardsPerShare =
                        accumulatedRewardsPerShare +
                        ((rewards * REWARDS_PRECISION) / tokensStaked);
                    lastRewardedBlock = block.number > endBlock ? endBlock : block.number;
                }
                /**
                 *@dev To get the number of rewards that user can get
                 */
                function getRewards(address _user) public view returns (uint) {
                    if (tokensStaked == 0) {
                        return 0;
                    }
                    uint256 blocksSinceLastReward = block.number > endBlock
                        ? endBlock - lastRewardedBlock
                        : block.number - lastRewardedBlock;
                    uint256 rewards = blocksSinceLastReward * rewardTokensPerBlock;
                    uint256 accCalc = accumulatedRewardsPerShare +
                        ((rewards * REWARDS_PRECISION) / tokensStaked);
                    PoolStaker memory staker = poolStakers[_user];
                    return
                        ((staker.amount * accCalc) / REWARDS_PRECISION) -
                        staker.rewardDebt +
                        userLockedRewards[_user];
                }
                function setHarvestLock(bool _harvestlock) external onlyOwner {
                    harvestLock = _harvestlock;
                }
                function setPresale(address _presale) external onlyOwner {
                    presaleContract = _presale;
                }
                function setStakeToken(address _stakeToken) external onlyOwner {
                    stakeToken = IERC20Upgradeable(_stakeToken);
                }
                function setLockedTime(uint _time) external onlyOwner {
                    lockedTime = _time;
                }
                function setEndBlock(uint _endBlock) external onlyOwner {
                    endBlock = _endBlock;
                }
                function setClaimStart(uint _claimStart) external onlyOwner {
                    claimStart = _claimStart;
                }
                /**
                 * @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;
                    }
                }
            }