creation_sourcecode: /**
   *Submitted for verification at Etherscan.io on 2024-06-11
  */
  
  /**
   *Submitted for verification at Etherscan.io on 2024-06-10
  */
  
  /**
   *Submitted for verification at Etherscan.io on 2024-05-13
  */
  
  pragma solidity ^0.8.12;
  
  interface IBEP20 {
      /**
       * @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 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
      );
  }
  library Strings {
      bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
  
      /**
       * @dev Converts a `uint256` to its ASCII `string` decimal representation.
       */
      function toString(uint256 value) internal pure returns (string memory) {
          // Inspired by OraclizeAPI's implementation - MIT licence
          // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
  
          if (value == 0) {
              return "0";
          }
          uint256 temp = value;
          uint256 digits;
          while (temp != 0) {
              digits++;
              temp /= 10;
          }
          bytes memory buffer = new bytes(digits);
          while (value != 0) {
              digits -= 1;
              buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
              value /= 10;
          }
          return string(buffer);
      }
  
      /**
       * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
       */
      function toHexString(uint256 value) internal pure returns (string memory) {
          if (value == 0) {
              return "0x00";
          }
          uint256 temp = value;
          uint256 length = 0;
          while (temp != 0) {
              length++;
              temp >>= 8;
          }
          return toHexString(value, length);
      }
  
      /**
       * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
       */
      function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
          bytes memory buffer = new bytes(2 * length + 2);
          buffer[0] = "0";
          buffer[1] = "x";
          for (uint256 i = 2 * length + 1; i > 1; --i) {
              buffer[i] = _HEX_SYMBOLS[value & 0xf];
              value >>= 4;
          }
          require(value == 0, "Strings: hex length insufficient");
          return string(buffer);
      }
  }
  library ECDSA {
      enum RecoverError {
          NoError,
          InvalidSignature,
          InvalidSignatureLength,
          InvalidSignatureS,
          InvalidSignatureV
      }
  
      function _throwError(RecoverError error) private pure {
          if (error == RecoverError.NoError) {
              return; // no error: do nothing
          } else if (error == RecoverError.InvalidSignature) {
              revert("ECDSA: invalid signature");
          } else if (error == RecoverError.InvalidSignatureLength) {
              revert("ECDSA: invalid signature length");
          } else if (error == RecoverError.InvalidSignatureS) {
              revert("ECDSA: invalid signature 's' value");
          } else if (error == RecoverError.InvalidSignatureV) {
              revert("ECDSA: invalid signature 'v' value");
          }
      }
  
      /**
       * @dev Returns the address that signed a hashed message (`hash`) with
       * `signature` or error string. This address can then be used for verification purposes.
       *
       * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
       * this function rejects them by requiring the `s` value to be in the lower
       * half order, and the `v` value to be either 27 or 28.
       *
       * IMPORTANT: `hash` _must_ be the result of a hash operation for the
       * verification to be secure: it is possible to craft signatures that
       * recover to arbitrary addresses for non-hashed data. A safe way to ensure
       * this is by receiving a hash of the original message (which may otherwise
       * be too long), and then calling {toEthSignedMessageHash} on it.
       *
       * Documentation for signature generation:
       * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
       * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
       *
       * _Available since v4.3._
       */
      function tryRecover(bytes32 hash, bytes memory signature)
          internal
          pure
          returns (address, RecoverError)
      {
          // Check the signature length
          // - case 65: r,s,v signature (standard)
          // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
          if (signature.length == 65) {
              bytes32 r;
              bytes32 s;
              uint8 v;
              // ecrecover takes the signature parameters, and the only way to get them
              // currently is to use assembly.
              assembly {
                  r := mload(add(signature, 0x20))
                  s := mload(add(signature, 0x40))
                  v := byte(0, mload(add(signature, 0x60)))
              }
              return tryRecover(hash, v, r, s);
          } else if (signature.length == 64) {
              bytes32 r;
              bytes32 vs;
              // ecrecover takes the signature parameters, and the only way to get them
              // currently is to use assembly.
              assembly {
                  r := mload(add(signature, 0x20))
                  vs := mload(add(signature, 0x40))
              }
              return tryRecover(hash, r, vs);
          } else {
              return (address(0), RecoverError.InvalidSignatureLength);
          }
      }
  
      /**
       * @dev Returns the address that signed a hashed message (`hash`) with
       * `signature`. This address can then be used for verification purposes.
       *
       * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
       * this function rejects them by requiring the `s` value to be in the lower
       * half order, and the `v` value to be either 27 or 28.
       *
       * IMPORTANT: `hash` _must_ be the result of a hash operation for the
       * verification to be secure: it is possible to craft signatures that
       * recover to arbitrary addresses for non-hashed data. A safe way to ensure
       * this is by receiving a hash of the original message (which may otherwise
       * be too long), and then calling {toEthSignedMessageHash} on it.
       */
      function recover(bytes32 hash, bytes memory signature)
          internal
          pure
          returns (address)
      {
          (address recovered, RecoverError error) = tryRecover(hash, signature);
          _throwError(error);
          return recovered;
      }
  
      /**
       * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
       *
       * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
       *
       * _Available since v4.3._
       */
      function tryRecover(
          bytes32 hash,
          bytes32 r,
          bytes32 vs
      ) internal pure returns (address, RecoverError) {
          bytes32 s = vs &
              bytes32(
                  0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
              );
          uint8 v = uint8((uint256(vs) >> 255) + 27);
          return tryRecover(hash, v, r, s);
      }
  
      /**
       * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
       *
       * _Available since v4.2._
       */
      function recover(
          bytes32 hash,
          bytes32 r,
          bytes32 vs
      ) internal pure returns (address) {
          (address recovered, RecoverError error) = tryRecover(hash, r, vs);
          _throwError(error);
          return recovered;
      }
  
      /**
       * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
       * `r` and `s` signature fields separately.
       *
       * _Available since v4.3._
       */
      function tryRecover(
          bytes32 hash,
          uint8 v,
          bytes32 r,
          bytes32 s
      ) internal pure returns (address, RecoverError) {
          // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
          // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
          // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
          // signatures from current libraries generate a unique signature with an s-value in the lower half order.
          //
          // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
          // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
          // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
          // these malleable signatures as well.
          if (
              uint256(s) >
              0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0
          ) {
              return (address(0), RecoverError.InvalidSignatureS);
          }
          if (v != 27 && v != 28) {
              return (address(0), RecoverError.InvalidSignatureV);
          }
  
          // If the signature is valid (and not malleable), return the signer address
          address signer = ecrecover(hash, v, r, s);
          if (signer == address(0)) {
              return (address(0), RecoverError.InvalidSignature);
          }
  
          return (signer, RecoverError.NoError);
      }
  
      /**
       * @dev Overload of {ECDSA-recover} that receives the `v`,
       * `r` and `s` signature fields separately.
       */
      function recover(
          bytes32 hash,
          uint8 v,
          bytes32 r,
          bytes32 s
      ) internal pure returns (address) {
          (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
          _throwError(error);
          return recovered;
      }
  
      /**
       * @dev Returns an Ethereum Signed Message, created from a `hash`. This
       * produces hash corresponding to the one signed with the
       * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
       * JSON-RPC method as part of EIP-191.
       *
       * See {recover}.
       */
      function toEthSignedMessageHash(bytes32 hash)
          internal
          pure
          returns (bytes32)
      {
          // 32 is the length in bytes of hash,
          // enforced by the type signature above
          return
              keccak256(
                  abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)
              );
      }
  
      /**
       * @dev Returns an Ethereum Signed Message, created from `s`. This
       * produces hash corresponding to the one signed with the
       * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
       * JSON-RPC method as part of EIP-191.
       *
       * See {recover}.
       */
      function toEthSignedMessageHash(bytes memory s)
          internal
          pure
          returns (bytes32)
      {
          return
              keccak256(
                  abi.encodePacked(
                      "\x19Ethereum Signed Message:\n",
                      Strings.toString(s.length),
                      s
                  )
              );
      }
      /**
       * @dev Returns an Ethereum Signed Typed Data, created from a
       * `domainSeparator` and a `structHash`. This produces hash corresponding
       * to the one signed with the
       * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
       * JSON-RPC method as part of EIP-712.
       *
       * See {recover}.
       */
      function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash)
          internal
          pure
          returns (bytes32)
      {
          return
              keccak256(
                  abi.encodePacked("\x19\x01", domainSeparator, structHash)
              );
      }
  }
  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);
          }
      }
  }
  abstract contract EIP712 {
      /* solhint-disable var-name-mixedcase */
      // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
      // invalidate the cached domain separator if the chain id changes.
      bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
      uint256 private immutable _CACHED_CHAIN_ID;
      address private immutable _CACHED_THIS;
  
      bytes32 private immutable _HASHED_NAME;
      bytes32 private immutable _HASHED_VERSION;
      bytes32 private immutable _TYPE_HASH;
  
      /* solhint-enable var-name-mixedcase */
  
      /**
       * @dev Initializes the domain separator and parameter caches.
       *
       * The meaning of `name` and `version` is specified in
       * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
       *
       * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
       * - `version`: the current major version of the signing domain.
       *
       * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
       * contract upgrade].
       */
      constructor(string memory name, string memory version) {
          bytes32 hashedName = keccak256(bytes(name));
          bytes32 hashedVersion = keccak256(bytes(version));
          bytes32 typeHash = keccak256(
              "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
          );
          _HASHED_NAME = hashedName;
          _HASHED_VERSION = hashedVersion;
          _CACHED_CHAIN_ID = block.chainid;
          _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(
              typeHash,
              hashedName,
              hashedVersion
          );
          _CACHED_THIS = address(this);
          _TYPE_HASH = typeHash;
      }
  
      /**
       * @dev Returns the domain separator for the current chain.
       */
      function _domainSeparatorV4() internal view returns (bytes32) {
          if (
              address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID
          ) {
              return _CACHED_DOMAIN_SEPARATOR;
          } else {
              return
                  _buildDomainSeparator(
                      _TYPE_HASH,
                      _HASHED_NAME,
                      _HASHED_VERSION
                  );
          }
      }
  
      function _buildDomainSeparator(
          bytes32 typeHash,
          bytes32 nameHash,
          bytes32 versionHash
      ) private view returns (bytes32) {
          return
              keccak256(
                  abi.encode(
                      typeHash,
                      nameHash,
                      versionHash,
                      block.chainid,
                      address(this)
                  )
              );
      }
  
      /**
       * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
       * function returns the hash of the fully encoded EIP712 message for this domain.
       *
       * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
       *
       * ```solidity
       * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
       *     keccak256("Mail(address to,string contents)"),
       *     mailTo,
       *     keccak256(bytes(mailContents))
       * )));
       * address signer = ECDSA.recover(digest, signature);
       * ```
       */
      function _hashTypedDataV4(bytes32 structHash)
          internal
          view
          virtual
          returns (bytes32)
      {
          return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
      }
  }
  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 Internal function that returns the initialized version. Returns `_initialized`
       */
      function _getInitializedVersion() internal view returns (uint8) {
          return _initialized;
      }
  
      /**
       * @dev Internal function that returns the initialized version. Returns `_initializing`
       */
      function _isInitializing() internal view returns (bool) {
          return _initializing;
      }
  }
  
  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;
  }
  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 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 {
      //     _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) internal 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;
  }
  
  
  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;
  }
  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);
  }
  
  interface IERC20Upgradeable {
      /**
       * @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 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);
  }
  pragma solidity ^0.8.12;
  
  contract whitelistChecker is EIP712 {
      string private constant SIGNING_DOMAIN = "DevvE_LAUNCHPAD";
      string private constant SIGNATURE_VERSION = "1";
  
      struct Signer {
          address userAddress;
          address contractAddress;
          uint256 id;
          uint256 timestamp;
          bytes signature;
      }
  
      constructor() EIP712(SIGNING_DOMAIN, SIGNATURE_VERSION) {}
  
      function getSigner(Signer memory whitelist) public view returns (address) {
          return _verify(whitelist);
      }
  
      /// @notice Returns a hash of the given whitelist, prepared using EIP712 typed data hashing rules.
  
      function _hash(Signer memory whitelist) internal view returns (bytes32) {
          return
              _hashTypedDataV4(
                  keccak256(
                      abi.encode(
                          keccak256(
                              "Signer(address userAddress,address contractAddress,uint256 id,uint256 timestamp)"
                          ),
                          whitelist.userAddress,
                          whitelist.contractAddress,
                          whitelist.id,
                          whitelist.timestamp
                      )
                  )
              );
      }
  
      function _verify(Signer memory whitelist) internal view returns (address) {
          bytes32 digest = _hash(whitelist);
          return ECDSA.recover(digest, whitelist.signature);
      }
  }
  
  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");
          }
      }
  }
  contract FiasDevvDropVesting is OwnableUpgradeable, whitelistChecker ,ReentrancyGuardUpgradeable{
      using SafeERC20Upgradeable for IERC20Upgradeable;
      IERC20Upgradeable public token;
      address public projectOwner;
      address public signer;
      bool private isStart;
      bool private iscollect;
      bool private ischeck;
      uint256 public activeLockDate;
      uint256 public totalDepositTokens;
      uint256 public totalAllocatedamount;
      uint256 public totalAirdropAllocationamount;
      uint256 public vestingEndTime;
  
      mapping(address=>mapping(uint=>bool)) public usedNonce;
      mapping (address => bool) public isUserAdded;
      mapping (address => bool) public isAirdropUserAdded;
      address private pendingOwner;
  
      uint256 day;
      event TokenWithdraw(address indexed buyer, uint256 value,uint256 id);
      event RecoverToken(address indexed token, uint256 indexed amount);
      event RemoveUser(address _userAddress);
      event InvestorAddress(address account, uint256 _amout);
      event AirdropAddress(address account, uint256 _amout);
      event startDate(uint256 date);
      event setTokens(address _userAddress);
      event OwnershipTransferInitiated(address indexed currentOwner, address indexed pendingOwner);
  
      modifier setDate() {
          require(isStart == true, "wait for start date");
          _;
      }
      modifier _iscollect() {
          require(iscollect == true, "wait");
          _;
      }
      modifier check() {
          require(ischeck == true);
          _;
      }
  
      uint256 public TGEStartDate;
      uint256 vestingPeriodDays = 12 * 30; // 12 months * 30 days
  
      receive() external payable {}
  
      
      function getContractTokenBalance() public view returns (uint256) {
          return token.balanceOf(address(this));
      }
  
      function setSigner(address _addr) public onlyOwner {
          signer = _addr;
      }
  
      function remainningTokens() external view returns (uint256) {
          return totalDepositTokens - totalAllocatedamount;
      }
  
      struct Investor {
          address account;
          uint256 amount;
      }
      struct AirDropDetails {
          uint256 timeDifference;
          uint256 lastVestedTime;
          uint256 airdropvestingBalance;
          uint256 airdropTokensPerDay;
          uint256 lastWithdrawalTimestamp;
          uint256 airdropVestingDays;
          uint256 airdroptotalBalance;
          bool isInitialAmountClaimed;
      }
  
      function getAirdropDetails(address _addr) public view returns (AirDropDetails memory){
          return AirDrops[_addr];
      }
      mapping(address => AirDropDetails) public AirDrops;
      // Adds details of a new airdrop user .
      function addAirdrop(uint airdropamount, Signer memory _signer ) public nonReentrant {
          require(!usedNonce[msg.sender][_signer.timestamp],"Nonce : Invalid Nonce");
          require(getSigner(_signer) == signer, "Invalid Signer");
          usedNonce[msg.sender][_signer.timestamp]=true;
          require (!isAirdropUserAdded[msg.sender],'User already added');
          isAirdropUserAdded[msg.sender] = true;
          AirDropDetails memory investor;
          investor.airdroptotalBalance = airdropamount;
          investor.airdropvestingBalance = investor.airdroptotalBalance;
          investor.airdropVestingDays = vestingPeriodDays;
          investor.airdropTokensPerDay = investor.airdroptotalBalance / vestingPeriodDays;
          investor.lastWithdrawalTimestamp = 0;//TGEStartDate;
          AirDrops[_signer.userAddress] = investor; 
          totalAirdropAllocationamount += investor.airdroptotalBalance;
          emit AirdropAddress(msg.sender,airdropamount);
      }
      // Allows the admin to add multiple airdrop user
      function addAirdropbyadmin(Investor[] memory vest) external onlyOwner nonReentrant{
          require(vest.length<=50,"Max Length Reached");
          for (uint i = 0;i < vest.length;i++) {
              require (!isAirdropUserAdded[vest[i].account],'User already added');
              isAirdropUserAdded[vest[i].account] = true;
              AirDropDetails memory investor;
              investor.airdroptotalBalance = vest[i].amount;
              investor.airdropvestingBalance = investor.airdroptotalBalance;
              investor.airdropVestingDays = vestingPeriodDays;
              investor.airdropTokensPerDay = investor.airdroptotalBalance / vestingPeriodDays;
              investor.lastWithdrawalTimestamp = 0;//TGEStartDate;
              AirDrops[vest[i].account] = investor; 
              totalAirdropAllocationamount += investor.airdroptotalBalance;
              emit AirdropAddress(vest[i].account,vest[i].amount);
          }
      }
      //Allows the withdrawal of a specified amount of tokens from the contract.
      function withdrawAirdropfunction(Signer memory _signer) external nonReentrant {
          require(isStart = true, "wait for start date");
          require(block.timestamp >= TGEStartDate, "TGE has not started yet");
          require(!usedNonce[msg.sender][_signer.timestamp],"Nonce : Invalid Nonce");
          require(getSigner(_signer) == signer, "Invalid Signer");
          usedNonce[msg.sender][_signer.timestamp]=true;
          uint256 id = 2;
          uint256 airdroptoekns = withdrawAirdropTokens();
          uint256 totaltokens = airdroptoekns;// airdroptoekns + lineartoken;
          require(totaltokens > 0, "wait for start date");
          token.safeTransfer(msg.sender, totaltokens);
          emit TokenWithdraw(msg.sender, totaltokens, id);
      }
      function withdrawAirdropTokens() private returns(uint256) {
          AirDropDetails storage investor = AirDrops[msg.sender];
          require(investor.airdropvestingBalance > 0, "No airdrop tokens to withdraw");
          require(block.timestamp >= TGEStartDate, "TGE has not started yet");
          uint256 elapsedTime;
          if(investor.lastWithdrawalTimestamp==0){
              elapsedTime = block.timestamp - TGEStartDate;
          }else{
              elapsedTime = block.timestamp - investor.lastWithdrawalTimestamp;
          }
  
          uint256 minutesElapsed = elapsedTime / 1 days;
          uint256 tokensToWithdraw;
          if(minutesElapsed >= 1){
               tokensToWithdraw = minutesElapsed * investor.airdropTokensPerDay; 
              
              if (tokensToWithdraw > investor.airdropvestingBalance) {
                  tokensToWithdraw = investor.airdropvestingBalance;
                  investor.airdropvestingBalance = 0; // Set balance to 0
              } else {
                  investor.airdropvestingBalance -= tokensToWithdraw;
              }
               investor.lastWithdrawalTimestamp = block.timestamp;
          }else{
               tokensToWithdraw = 0;
          }
          
          return tokensToWithdraw;
      }
      function getCurrentAirdropBalance(address investorAddress) public view returns (uint256){
          AirDropDetails storage investor = AirDrops[investorAddress];
          require(investor.airdropvestingBalance > 0,"No airdrop tokens available");
          require(block.timestamp >= TGEStartDate, "TGE has not started yet");
          uint256 elapsedTime;
          if(investor.lastWithdrawalTimestamp==0){
              elapsedTime = block.timestamp - TGEStartDate;
          }else{
              elapsedTime = block.timestamp - investor.lastWithdrawalTimestamp;
          }
          uint256 minutesElapsed = elapsedTime / 1 days;
          uint256 tokensToWithdraw;
          if(minutesElapsed >= 1){
               tokensToWithdraw = minutesElapsed * investor.airdropTokensPerDay;
          }else{
               tokensToWithdraw = 0;
          }
          if (tokensToWithdraw > investor.airdropvestingBalance) {
              tokensToWithdraw = investor.airdropvestingBalance;
          }
          return tokensToWithdraw;
      }
      function removeAirdropUser(address _userAddress)public onlyOwner{
        require(isAirdropUserAdded[_userAddress],"Not a Investor");
        delete AirDrops[_userAddress];
        isAirdropUserAdded[_userAddress]=false;
        emit RemoveUser(_userAddress);
      }
      // Allows the deposit of a specified amount of Airdrop tokens into the contract.
      function depositToken(uint256 amount) public onlyOwner {
          token.safeTransferFrom(msg.sender, address(this), amount);
          totalDepositTokens += amount;
      }
      function recoverTokens(address _token,address _userAddress,uint256 amount) public onlyOwner {
          IERC20Upgradeable(_token).safeTransfer(_userAddress, amount);
          emit RecoverToken(_token, amount);
      }
      //Sets the airdrop start date
      function setStartDate(uint256 _startDate) external onlyOwner {
          TGEStartDate = _startDate;
          emit startDate (_startDate);
      }
      //Sets the address of the ERC-20 token contract to be used by the platform.
      function setToken(address _token) external onlyOwner {
          require(_token != address(0), "Invalid Token Address");
          token = IERC20Upgradeable(_token);
          emit setTokens (_token);
      }
      function initialize(address Signer,uint256 _startDate,address _tokenAddress) external initializer{
          require(_tokenAddress != address(0));
          TGEStartDate = _startDate;
          isStart = true;
           token = IERC20Upgradeable(_tokenAddress);
          signer = Signer;
          __Ownable_init();
          __ReentrancyGuard_init();
      }
       modifier onlyPendingOwner() {
          require(msg.sender == pendingOwner, "Caller is not the pending owner");
           _;
      }
      // Function to initiate ownership transfer
      function initiateOwnershipTransfer(address newOwner) external onlyOwner {
          require(newOwner != address(0), "Invalid Wallet Address");
          pendingOwner = newOwner;
          emit OwnershipTransferInitiated(owner(), pendingOwner);
      }
      // Function to confirm ownership transfer
      function confirmOwnershipTransfer() external onlyPendingOwner {
          _transferOwnership(pendingOwner);
          pendingOwner = address(0); // Reset pending owner
      }
  }