creation_sourcecode: // Sources flattened with hardhat v2.4.1 https://hardhat.org
  
  // File @openzeppelin/contracts/utils/Context.sol@v4.8.0
  
  // SPDX-License-Identifier: MIT
  // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
  
  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) {
          return msg.data;
      }
  }
  
  
  // File @openzeppelin/contracts/access/Ownable.sol@v4.8.0
  
   
  // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
  
  pragma solidity ^0.8.0;
  
  /**
   * @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 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);
      }
  }
  
  
  // File @openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol@v4.8.0
  
   
  // 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 IERC20Permit {
      /**
       * @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);
  }
  
  
  // File @openzeppelin/contracts/token/ERC20/IERC20.sol@v4.8.0
  
   
  // 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 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);
  }
  
  
  // File @openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol@v4.8.0
  
   
  // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
  
  pragma solidity ^0.8.0;
  
  /**
   * @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);
  }
  
  
  // File @openzeppelin/contracts/token/ERC20/ERC20.sol@v4.8.0
  
   
  // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)
  
  pragma solidity ^0.8.0;
  
  
  
  /**
   * @dev Implementation of the {IERC20} interface.
   *
   * This implementation is agnostic to the way tokens are created. This means
   * that a supply mechanism has to be added in a derived contract using {_mint}.
   * For a generic mechanism see {ERC20PresetMinterPauser}.
   *
   * TIP: For a detailed writeup see our guide
   * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
   * to implement supply mechanisms].
   *
   * We have followed general OpenZeppelin Contracts guidelines: functions revert
   * instead returning `false` on failure. This behavior is nonetheless
   * conventional and does not conflict with the expectations of ERC20
   * applications.
   *
   * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
   * This allows applications to reconstruct the allowance for all accounts just
   * by listening to said events. Other implementations of the EIP may not emit
   * these events, as it isn't required by the specification.
   *
   * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
   * functions have been added to mitigate the well-known issues around setting
   * allowances. See {IERC20-approve}.
   */
  contract ERC20 is Context, IERC20, IERC20Metadata {
      mapping(address => uint256) private _balances;
  
      mapping(address => mapping(address => uint256)) private _allowances;
  
      uint256 private _totalSupply;
  
      string private _name;
      string private _symbol;
  
      /**
       * @dev Sets the values for {name} and {symbol}.
       *
       * The default value of {decimals} is 18. To select a different value for
       * {decimals} you should overload it.
       *
       * All two of these values are immutable: they can only be set once during
       * construction.
       */
      constructor(string memory name_, string memory symbol_) {
          _name = name_;
          _symbol = symbol_;
      }
  
      /**
       * @dev Returns the name of the token.
       */
      function name() public view virtual override returns (string memory) {
          return _name;
      }
  
      /**
       * @dev Returns the symbol of the token, usually a shorter version of the
       * name.
       */
      function symbol() public view virtual override returns (string memory) {
          return _symbol;
      }
  
      /**
       * @dev Returns the number of decimals used to get its user representation.
       * For example, if `decimals` equals `2`, a balance of `505` tokens should
       * be displayed to a user as `5.05` (`505 / 10 ** 2`).
       *
       * Tokens usually opt for a value of 18, imitating the relationship between
       * Ether and Wei. This is the value {ERC20} uses, unless this function is
       * overridden;
       *
       * NOTE: This information is only used for _display_ purposes: it in
       * no way affects any of the arithmetic of the contract, including
       * {IERC20-balanceOf} and {IERC20-transfer}.
       */
      function decimals() public view virtual override returns (uint8) {
          return 18;
      }
  
      /**
       * @dev See {IERC20-totalSupply}.
       */
      function totalSupply() public view virtual override returns (uint256) {
          return _totalSupply;
      }
  
      /**
       * @dev See {IERC20-balanceOf}.
       */
      function balanceOf(address account) public view virtual override returns (uint256) {
          return _balances[account];
      }
  
      /**
       * @dev See {IERC20-transfer}.
       *
       * Requirements:
       *
       * - `to` cannot be the zero address.
       * - the caller must have a balance of at least `amount`.
       */
      function transfer(address to, uint256 amount) public virtual override returns (bool) {
          address owner = _msgSender();
          _transfer(owner, to, amount);
          return true;
      }
  
      /**
       * @dev See {IERC20-allowance}.
       */
      function allowance(address owner, address spender) public view virtual override returns (uint256) {
          return _allowances[owner][spender];
      }
  
      /**
       * @dev See {IERC20-approve}.
       *
       * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
       * `transferFrom`. This is semantically equivalent to an infinite approval.
       *
       * Requirements:
       *
       * - `spender` cannot be the zero address.
       */
      function approve(address spender, uint256 amount) public virtual override returns (bool) {
          address owner = _msgSender();
          _approve(owner, spender, amount);
          return true;
      }
  
      /**
       * @dev See {IERC20-transferFrom}.
       *
       * Emits an {Approval} event indicating the updated allowance. This is not
       * required by the EIP. See the note at the beginning of {ERC20}.
       *
       * NOTE: Does not update the allowance if the current allowance
       * is the maximum `uint256`.
       *
       * Requirements:
       *
       * - `from` and `to` cannot be the zero address.
       * - `from` must have a balance of at least `amount`.
       * - the caller must have allowance for ``from``'s tokens of at least
       * `amount`.
       */
      function transferFrom(
          address from,
          address to,
          uint256 amount
      ) public virtual override returns (bool) {
          address spender = _msgSender();
          _spendAllowance(from, spender, amount);
          _transfer(from, to, amount);
          return true;
      }
  
      /**
       * @dev Atomically increases the allowance granted to `spender` by the caller.
       *
       * This is an alternative to {approve} that can be used as a mitigation for
       * problems described in {IERC20-approve}.
       *
       * Emits an {Approval} event indicating the updated allowance.
       *
       * Requirements:
       *
       * - `spender` cannot be the zero address.
       */
      function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
          address owner = _msgSender();
          _approve(owner, spender, allowance(owner, spender) + addedValue);
          return true;
      }
  
      /**
       * @dev Atomically decreases the allowance granted to `spender` by the caller.
       *
       * This is an alternative to {approve} that can be used as a mitigation for
       * problems described in {IERC20-approve}.
       *
       * Emits an {Approval} event indicating the updated allowance.
       *
       * Requirements:
       *
       * - `spender` cannot be the zero address.
       * - `spender` must have allowance for the caller of at least
       * `subtractedValue`.
       */
      function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
          address owner = _msgSender();
          uint256 currentAllowance = allowance(owner, spender);
          require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
          unchecked {
              _approve(owner, spender, currentAllowance - subtractedValue);
          }
  
          return true;
      }
  
      /**
       * @dev Moves `amount` of tokens from `from` to `to`.
       *
       * This internal function is equivalent to {transfer}, and can be used to
       * e.g. implement automatic token fees, slashing mechanisms, etc.
       *
       * Emits a {Transfer} event.
       *
       * Requirements:
       *
       * - `from` cannot be the zero address.
       * - `to` cannot be the zero address.
       * - `from` must have a balance of at least `amount`.
       */
      function _transfer(
          address from,
          address to,
          uint256 amount
      ) internal virtual {
          require(from != address(0), "ERC20: transfer from the zero address");
          require(to != address(0), "ERC20: transfer to the zero address");
  
          _beforeTokenTransfer(from, to, amount);
  
          uint256 fromBalance = _balances[from];
          require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
          unchecked {
              _balances[from] = fromBalance - amount;
              // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
              // decrementing then incrementing.
              _balances[to] += amount;
          }
  
          emit Transfer(from, to, amount);
  
          _afterTokenTransfer(from, to, amount);
      }
  
      /** @dev Creates `amount` tokens and assigns them to `account`, increasing
       * the total supply.
       *
       * Emits a {Transfer} event with `from` set to the zero address.
       *
       * Requirements:
       *
       * - `account` cannot be the zero address.
       */
      function _mint(address account, uint256 amount) internal virtual {
          require(account != address(0), "ERC20: mint to the zero address");
  
          _beforeTokenTransfer(address(0), account, amount);
  
          _totalSupply += amount;
          unchecked {
              // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
              _balances[account] += amount;
          }
          emit Transfer(address(0), account, amount);
  
          _afterTokenTransfer(address(0), account, amount);
      }
  
      /**
       * @dev Destroys `amount` tokens from `account`, reducing the
       * total supply.
       *
       * Emits a {Transfer} event with `to` set to the zero address.
       *
       * Requirements:
       *
       * - `account` cannot be the zero address.
       * - `account` must have at least `amount` tokens.
       */
      function _burn(address account, uint256 amount) internal virtual {
          require(account != address(0), "ERC20: burn from the zero address");
  
          _beforeTokenTransfer(account, address(0), amount);
  
          uint256 accountBalance = _balances[account];
          require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
          unchecked {
              _balances[account] = accountBalance - amount;
              // Overflow not possible: amount <= accountBalance <= totalSupply.
              _totalSupply -= amount;
          }
  
          emit Transfer(account, address(0), amount);
  
          _afterTokenTransfer(account, address(0), amount);
      }
  
      /**
       * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
       *
       * This internal function is equivalent to `approve`, and can be used to
       * e.g. set automatic allowances for certain subsystems, etc.
       *
       * Emits an {Approval} event.
       *
       * Requirements:
       *
       * - `owner` cannot be the zero address.
       * - `spender` cannot be the zero address.
       */
      function _approve(
          address owner,
          address spender,
          uint256 amount
      ) internal virtual {
          require(owner != address(0), "ERC20: approve from the zero address");
          require(spender != address(0), "ERC20: approve to the zero address");
  
          _allowances[owner][spender] = amount;
          emit Approval(owner, spender, amount);
      }
  
      /**
       * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
       *
       * Does not update the allowance amount in case of infinite allowance.
       * Revert if not enough allowance is available.
       *
       * Might emit an {Approval} event.
       */
      function _spendAllowance(
          address owner,
          address spender,
          uint256 amount
      ) internal virtual {
          uint256 currentAllowance = allowance(owner, spender);
          if (currentAllowance != type(uint256).max) {
              require(currentAllowance >= amount, "ERC20: insufficient allowance");
              unchecked {
                  _approve(owner, spender, currentAllowance - amount);
              }
          }
      }
  
      /**
       * @dev Hook that is called before any transfer of tokens. This includes
       * minting and burning.
       *
       * Calling conditions:
       *
       * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
       * will be transferred to `to`.
       * - when `from` is zero, `amount` tokens will be minted for `to`.
       * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
       * - `from` and `to` are never both zero.
       *
       * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
       */
      function _beforeTokenTransfer(
          address from,
          address to,
          uint256 amount
      ) internal virtual {}
  
      /**
       * @dev Hook that is called after any transfer of tokens. This includes
       * minting and burning.
       *
       * Calling conditions:
       *
       * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
       * has been transferred to `to`.
       * - when `from` is zero, `amount` tokens have been minted for `to`.
       * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
       * - `from` and `to` are never both zero.
       *
       * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
       */
      function _afterTokenTransfer(
          address from,
          address to,
          uint256 amount
      ) internal virtual {}
  }
  
  
  // File @openzeppelin/contracts/utils/math/Math.sol@v4.8.0
  
   
  // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
  
  pragma solidity ^0.8.0;
  
  /**
   * @dev Standard math utilities missing in the Solidity language.
   */
  library Math {
      enum Rounding {
          Down, // Toward negative infinity
          Up, // Toward infinity
          Zero // Toward zero
      }
  
      /**
       * @dev Returns the largest of two numbers.
       */
      function max(uint256 a, uint256 b) internal pure returns (uint256) {
          return a > b ? a : b;
      }
  
      /**
       * @dev Returns the smallest of two numbers.
       */
      function min(uint256 a, uint256 b) internal pure returns (uint256) {
          return a < b ? a : b;
      }
  
      /**
       * @dev Returns the average of two numbers. The result is rounded towards
       * zero.
       */
      function average(uint256 a, uint256 b) internal pure returns (uint256) {
          // (a + b) / 2 can overflow.
          return (a & b) + (a ^ b) / 2;
      }
  
      /**
       * @dev Returns the ceiling of the division of two numbers.
       *
       * This differs from standard division with `/` in that it rounds up instead
       * of rounding down.
       */
      function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
          // (a + b - 1) / b can overflow on addition, so we distribute.
          return a == 0 ? 0 : (a - 1) / b + 1;
      }
  
      /**
       * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
       * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
       * with further edits by Uniswap Labs also under MIT license.
       */
      function mulDiv(
          uint256 x,
          uint256 y,
          uint256 denominator
      ) internal pure returns (uint256 result) {
          unchecked {
              // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
              // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
              // variables such that product = prod1 * 2^256 + prod0.
              uint256 prod0; // Least significant 256 bits of the product
              uint256 prod1; // Most significant 256 bits of the product
              assembly {
                  let mm := mulmod(x, y, not(0))
                  prod0 := mul(x, y)
                  prod1 := sub(sub(mm, prod0), lt(mm, prod0))
              }
  
              // Handle non-overflow cases, 256 by 256 division.
              if (prod1 == 0) {
                  return prod0 / denominator;
              }
  
              // Make sure the result is less than 2^256. Also prevents denominator == 0.
              require(denominator > prod1);
  
              ///////////////////////////////////////////////
              // 512 by 256 division.
              ///////////////////////////////////////////////
  
              // Make division exact by subtracting the remainder from [prod1 prod0].
              uint256 remainder;
              assembly {
                  // Compute remainder using mulmod.
                  remainder := mulmod(x, y, denominator)
  
                  // Subtract 256 bit number from 512 bit number.
                  prod1 := sub(prod1, gt(remainder, prod0))
                  prod0 := sub(prod0, remainder)
              }
  
              // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
              // See https://cs.stackexchange.com/q/138556/92363.
  
              // Does not overflow because the denominator cannot be zero at this stage in the function.
              uint256 twos = denominator & (~denominator + 1);
              assembly {
                  // Divide denominator by twos.
                  denominator := div(denominator, twos)
  
                  // Divide [prod1 prod0] by twos.
                  prod0 := div(prod0, twos)
  
                  // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                  twos := add(div(sub(0, twos), twos), 1)
              }
  
              // Shift in bits from prod1 into prod0.
              prod0 |= prod1 * twos;
  
              // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
              // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
              // four bits. That is, denominator * inv = 1 mod 2^4.
              uint256 inverse = (3 * denominator) ^ 2;
  
              // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
              // in modular arithmetic, doubling the correct bits in each step.
              inverse *= 2 - denominator * inverse; // inverse mod 2^8
              inverse *= 2 - denominator * inverse; // inverse mod 2^16
              inverse *= 2 - denominator * inverse; // inverse mod 2^32
              inverse *= 2 - denominator * inverse; // inverse mod 2^64
              inverse *= 2 - denominator * inverse; // inverse mod 2^128
              inverse *= 2 - denominator * inverse; // inverse mod 2^256
  
              // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
              // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
              // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
              // is no longer required.
              result = prod0 * inverse;
              return result;
          }
      }
  
      /**
       * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
       */
      function mulDiv(
          uint256 x,
          uint256 y,
          uint256 denominator,
          Rounding rounding
      ) internal pure returns (uint256) {
          uint256 result = mulDiv(x, y, denominator);
          if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
              result += 1;
          }
          return result;
      }
  
      /**
       * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
       *
       * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
       */
      function sqrt(uint256 a) internal pure returns (uint256) {
          if (a == 0) {
              return 0;
          }
  
          // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
          //
          // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
          // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
          //
          // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
          // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
          // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
          //
          // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
          uint256 result = 1 << (log2(a) >> 1);
  
          // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
          // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
          // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
          // into the expected uint128 result.
          unchecked {
              result = (result + a / result) >> 1;
              result = (result + a / result) >> 1;
              result = (result + a / result) >> 1;
              result = (result + a / result) >> 1;
              result = (result + a / result) >> 1;
              result = (result + a / result) >> 1;
              result = (result + a / result) >> 1;
              return min(result, a / result);
          }
      }
  
      /**
       * @notice Calculates sqrt(a), following the selected rounding direction.
       */
      function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
          unchecked {
              uint256 result = sqrt(a);
              return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
          }
      }
  
      /**
       * @dev Return the log in base 2, rounded down, of a positive value.
       * Returns 0 if given 0.
       */
      function log2(uint256 value) internal pure returns (uint256) {
          uint256 result = 0;
          unchecked {
              if (value >> 128 > 0) {
                  value >>= 128;
                  result += 128;
              }
              if (value >> 64 > 0) {
                  value >>= 64;
                  result += 64;
              }
              if (value >> 32 > 0) {
                  value >>= 32;
                  result += 32;
              }
              if (value >> 16 > 0) {
                  value >>= 16;
                  result += 16;
              }
              if (value >> 8 > 0) {
                  value >>= 8;
                  result += 8;
              }
              if (value >> 4 > 0) {
                  value >>= 4;
                  result += 4;
              }
              if (value >> 2 > 0) {
                  value >>= 2;
                  result += 2;
              }
              if (value >> 1 > 0) {
                  result += 1;
              }
          }
          return result;
      }
  
      /**
       * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
       * Returns 0 if given 0.
       */
      function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
          unchecked {
              uint256 result = log2(value);
              return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
          }
      }
  
      /**
       * @dev Return the log in base 10, rounded down, of a positive value.
       * Returns 0 if given 0.
       */
      function log10(uint256 value) internal pure returns (uint256) {
          uint256 result = 0;
          unchecked {
              if (value >= 10**64) {
                  value /= 10**64;
                  result += 64;
              }
              if (value >= 10**32) {
                  value /= 10**32;
                  result += 32;
              }
              if (value >= 10**16) {
                  value /= 10**16;
                  result += 16;
              }
              if (value >= 10**8) {
                  value /= 10**8;
                  result += 8;
              }
              if (value >= 10**4) {
                  value /= 10**4;
                  result += 4;
              }
              if (value >= 10**2) {
                  value /= 10**2;
                  result += 2;
              }
              if (value >= 10**1) {
                  result += 1;
              }
          }
          return result;
      }
  
      /**
       * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
       * Returns 0 if given 0.
       */
      function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
          unchecked {
              uint256 result = log10(value);
              return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
          }
      }
  
      /**
       * @dev Return the log in base 256, rounded down, of a positive value.
       * Returns 0 if given 0.
       *
       * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
       */
      function log256(uint256 value) internal pure returns (uint256) {
          uint256 result = 0;
          unchecked {
              if (value >> 128 > 0) {
                  value >>= 128;
                  result += 16;
              }
              if (value >> 64 > 0) {
                  value >>= 64;
                  result += 8;
              }
              if (value >> 32 > 0) {
                  value >>= 32;
                  result += 4;
              }
              if (value >> 16 > 0) {
                  value >>= 16;
                  result += 2;
              }
              if (value >> 8 > 0) {
                  result += 1;
              }
          }
          return result;
      }
  
      /**
       * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
       * Returns 0 if given 0.
       */
      function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
          unchecked {
              uint256 result = log256(value);
              return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
          }
      }
  }
  
  
  // File @openzeppelin/contracts/utils/Strings.sol@v4.8.0
  
   
  // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
  
  pragma solidity ^0.8.0;
  
  /**
   * @dev String operations.
   */
  library Strings {
      bytes16 private constant _SYMBOLS = "0123456789abcdef";
      uint8 private constant _ADDRESS_LENGTH = 20;
  
      /**
       * @dev Converts a `uint256` to its ASCII `string` decimal representation.
       */
      function toString(uint256 value) internal pure returns (string memory) {
          unchecked {
              uint256 length = Math.log10(value) + 1;
              string memory buffer = new string(length);
              uint256 ptr;
              /// @solidity memory-safe-assembly
              assembly {
                  ptr := add(buffer, add(32, length))
              }
              while (true) {
                  ptr--;
                  /// @solidity memory-safe-assembly
                  assembly {
                      mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                  }
                  value /= 10;
                  if (value == 0) break;
              }
              return buffer;
          }
      }
  
      /**
       * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
       */
      function toHexString(uint256 value) internal pure returns (string memory) {
          unchecked {
              return toHexString(value, Math.log256(value) + 1);
          }
      }
  
      /**
       * @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] = _SYMBOLS[value & 0xf];
              value >>= 4;
          }
          require(value == 0, "Strings: hex length insufficient");
          return string(buffer);
      }
  
      /**
       * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
       */
      function toHexString(address addr) internal pure returns (string memory) {
          return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
      }
  }
  
  
  // File @openzeppelin/contracts/utils/cryptography/ECDSA.sol@v4.8.0
  
   
  // OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)
  
  pragma solidity ^0.8.0;
  
  /**
   * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
   *
   * These functions can be used to verify that a message was signed by the holder
   * of the private keys of a given address.
   */
  library ECDSA {
      enum RecoverError {
          NoError,
          InvalidSignature,
          InvalidSignatureLength,
          InvalidSignatureS,
          InvalidSignatureV // Deprecated in v4.8
      }
  
      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");
          }
      }
  
      /**
       * @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) {
          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.
              /// @solidity memory-safe-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 {
              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 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));
      }
  }
  
  
  // File @openzeppelin/contracts/utils/cryptography/EIP712.sol@v4.8.0
  
   
  // OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)
  
  pragma solidity ^0.8.0;
  
  /**
   * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
   *
   * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
   * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
   * they need in their contracts using a combination of `abi.encode` and `keccak256`.
   *
   * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
   * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
   * ({_hashTypedDataV4}).
   *
   * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
   * the chain id to protect against replay attacks on an eventual fork of the chain.
   *
   * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
   * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
   *
   * _Available since v3.4._
   */
  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);
      }
  }
  
  
  // File @openzeppelin/contracts/utils/Counters.sol@v4.8.0
  
   
  // OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)
  
  pragma solidity ^0.8.0;
  
  /**
   * @title Counters
   * @author Matt Condon (@shrugs)
   * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
   * of elements in a mapping, issuing ERC721 ids, or counting request ids.
   *
   * Include with `using Counters for Counters.Counter;`
   */
  library Counters {
      struct Counter {
          // This variable should never be directly accessed by users of the library: interactions must be restricted to
          // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
          // this feature: see https://github.com/ethereum/solidity/issues/4637
          uint256 _value; // default: 0
      }
  
      function current(Counter storage counter) internal view returns (uint256) {
          return counter._value;
      }
  
      function increment(Counter storage counter) internal {
          unchecked {
              counter._value += 1;
          }
      }
  
      function decrement(Counter storage counter) internal {
          uint256 value = counter._value;
          require(value > 0, "Counter: decrement overflow");
          unchecked {
              counter._value = value - 1;
          }
      }
  
      function reset(Counter storage counter) internal {
          counter._value = 0;
      }
  }
  
  
  // File @openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol@v4.8.0
  
   
  // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/draft-ERC20Permit.sol)
  
  pragma solidity ^0.8.0;
  
  
  
  
  
  /**
   * @dev Implementation 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.
   *
   * _Available since v3.4._
   */
  abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {
      using Counters for Counters.Counter;
  
      mapping(address => Counters.Counter) private _nonces;
  
      // solhint-disable-next-line var-name-mixedcase
      bytes32 private constant _PERMIT_TYPEHASH =
          keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
      /**
       * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`.
       * However, to ensure consistency with the upgradeable transpiler, we will continue
       * to reserve a slot.
       * @custom:oz-renamed-from _PERMIT_TYPEHASH
       */
      // solhint-disable-next-line var-name-mixedcase
      bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;
  
      /**
       * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
       *
       * It's a good idea to use the same `name` that is defined as the ERC20 token name.
       */
      constructor(string memory name) EIP712(name, "1") {}
  
      /**
       * @dev See {IERC20Permit-permit}.
       */
      function permit(
          address owner,
          address spender,
          uint256 value,
          uint256 deadline,
          uint8 v,
          bytes32 r,
          bytes32 s
      ) public virtual override {
          require(block.timestamp <= deadline, "ERC20Permit: expired deadline");
  
          bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));
  
          bytes32 hash = _hashTypedDataV4(structHash);
  
          address signer = ECDSA.recover(hash, v, r, s);
          require(signer == owner, "ERC20Permit: invalid signature");
  
          _approve(owner, spender, value);
      }
  
      /**
       * @dev See {IERC20Permit-nonces}.
       */
      function nonces(address owner) public view virtual override returns (uint256) {
          return _nonces[owner].current();
      }
  
      /**
       * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.
       */
      // solhint-disable-next-line func-name-mixedcase
      function DOMAIN_SEPARATOR() external view override returns (bytes32) {
          return _domainSeparatorV4();
      }
  
      /**
       * @dev "Consume a nonce": return the current value and increment.
       *
       * _Available since v4.1._
       */
      function _useNonce(address owner) internal virtual returns (uint256 current) {
          Counters.Counter storage nonce = _nonces[owner];
          current = nonce.current();
          nonce.increment();
      }
  }
  
  
  // File @openzeppelin/contracts/governance/utils/IVotes.sol@v4.8.0
  
   
  // OpenZeppelin Contracts (last updated v4.5.0) (governance/utils/IVotes.sol)
  pragma solidity ^0.8.0;
  
  /**
   * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.
   *
   * _Available since v4.5._
   */
  interface IVotes {
      /**
       * @dev Emitted when an account changes their delegate.
       */
      event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
  
      /**
       * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes.
       */
      event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);
  
      /**
       * @dev Returns the current amount of votes that `account` has.
       */
      function getVotes(address account) external view returns (uint256);
  
      /**
       * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).
       */
      function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);
  
      /**
       * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).
       *
       * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.
       * Votes that have not been delegated are still part of total supply, even though they would not participate in a
       * vote.
       */
      function getPastTotalSupply(uint256 blockNumber) external view returns (uint256);
  
      /**
       * @dev Returns the delegate that `account` has chosen.
       */
      function delegates(address account) external view returns (address);
  
      /**
       * @dev Delegates votes from the sender to `delegatee`.
       */
      function delegate(address delegatee) external;
  
      /**
       * @dev Delegates votes from signer to `delegatee`.
       */
      function delegateBySig(
          address delegatee,
          uint256 nonce,
          uint256 expiry,
          uint8 v,
          bytes32 r,
          bytes32 s
      ) external;
  }
  
  
  // File @openzeppelin/contracts/utils/math/SafeCast.sol@v4.8.0
  
   
  // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
  // This file was procedurally generated from scripts/generate/templates/SafeCast.js.
  
  pragma solidity ^0.8.0;
  
  /**
   * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
   * checks.
   *
   * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
   * easily result in undesired exploitation or bugs, since developers usually
   * assume that overflows raise errors. `SafeCast` restores this intuition by
   * reverting the transaction when such an operation overflows.
   *
   * Using this library instead of the unchecked operations eliminates an entire
   * class of bugs, so it's recommended to use it always.
   *
   * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
   * all math on `uint256` and `int256` and then downcasting.
   */
  library SafeCast {
      /**
       * @dev Returns the downcasted uint248 from uint256, reverting on
       * overflow (when the input is greater than largest uint248).
       *
       * Counterpart to Solidity's `uint248` operator.
       *
       * Requirements:
       *
       * - input must fit into 248 bits
       *
       * _Available since v4.7._
       */
      function toUint248(uint256 value) internal pure returns (uint248) {
          require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
          return uint248(value);
      }
  
      /**
       * @dev Returns the downcasted uint240 from uint256, reverting on
       * overflow (when the input is greater than largest uint240).
       *
       * Counterpart to Solidity's `uint240` operator.
       *
       * Requirements:
       *
       * - input must fit into 240 bits
       *
       * _Available since v4.7._
       */
      function toUint240(uint256 value) internal pure returns (uint240) {
          require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
          return uint240(value);
      }
  
      /**
       * @dev Returns the downcasted uint232 from uint256, reverting on
       * overflow (when the input is greater than largest uint232).
       *
       * Counterpart to Solidity's `uint232` operator.
       *
       * Requirements:
       *
       * - input must fit into 232 bits
       *
       * _Available since v4.7._
       */
      function toUint232(uint256 value) internal pure returns (uint232) {
          require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
          return uint232(value);
      }
  
      /**
       * @dev Returns the downcasted uint224 from uint256, reverting on
       * overflow (when the input is greater than largest uint224).
       *
       * Counterpart to Solidity's `uint224` operator.
       *
       * Requirements:
       *
       * - input must fit into 224 bits
       *
       * _Available since v4.2._
       */
      function toUint224(uint256 value) internal pure returns (uint224) {
          require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
          return uint224(value);
      }
  
      /**
       * @dev Returns the downcasted uint216 from uint256, reverting on
       * overflow (when the input is greater than largest uint216).
       *
       * Counterpart to Solidity's `uint216` operator.
       *
       * Requirements:
       *
       * - input must fit into 216 bits
       *
       * _Available since v4.7._
       */
      function toUint216(uint256 value) internal pure returns (uint216) {
          require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
          return uint216(value);
      }
  
      /**
       * @dev Returns the downcasted uint208 from uint256, reverting on
       * overflow (when the input is greater than largest uint208).
       *
       * Counterpart to Solidity's `uint208` operator.
       *
       * Requirements:
       *
       * - input must fit into 208 bits
       *
       * _Available since v4.7._
       */
      function toUint208(uint256 value) internal pure returns (uint208) {
          require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
          return uint208(value);
      }
  
      /**
       * @dev Returns the downcasted uint200 from uint256, reverting on
       * overflow (when the input is greater than largest uint200).
       *
       * Counterpart to Solidity's `uint200` operator.
       *
       * Requirements:
       *
       * - input must fit into 200 bits
       *
       * _Available since v4.7._
       */
      function toUint200(uint256 value) internal pure returns (uint200) {
          require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
          return uint200(value);
      }
  
      /**
       * @dev Returns the downcasted uint192 from uint256, reverting on
       * overflow (when the input is greater than largest uint192).
       *
       * Counterpart to Solidity's `uint192` operator.
       *
       * Requirements:
       *
       * - input must fit into 192 bits
       *
       * _Available since v4.7._
       */
      function toUint192(uint256 value) internal pure returns (uint192) {
          require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
          return uint192(value);
      }
  
      /**
       * @dev Returns the downcasted uint184 from uint256, reverting on
       * overflow (when the input is greater than largest uint184).
       *
       * Counterpart to Solidity's `uint184` operator.
       *
       * Requirements:
       *
       * - input must fit into 184 bits
       *
       * _Available since v4.7._
       */
      function toUint184(uint256 value) internal pure returns (uint184) {
          require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
          return uint184(value);
      }
  
      /**
       * @dev Returns the downcasted uint176 from uint256, reverting on
       * overflow (when the input is greater than largest uint176).
       *
       * Counterpart to Solidity's `uint176` operator.
       *
       * Requirements:
       *
       * - input must fit into 176 bits
       *
       * _Available since v4.7._
       */
      function toUint176(uint256 value) internal pure returns (uint176) {
          require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
          return uint176(value);
      }
  
      /**
       * @dev Returns the downcasted uint168 from uint256, reverting on
       * overflow (when the input is greater than largest uint168).
       *
       * Counterpart to Solidity's `uint168` operator.
       *
       * Requirements:
       *
       * - input must fit into 168 bits
       *
       * _Available since v4.7._
       */
      function toUint168(uint256 value) internal pure returns (uint168) {
          require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
          return uint168(value);
      }
  
      /**
       * @dev Returns the downcasted uint160 from uint256, reverting on
       * overflow (when the input is greater than largest uint160).
       *
       * Counterpart to Solidity's `uint160` operator.
       *
       * Requirements:
       *
       * - input must fit into 160 bits
       *
       * _Available since v4.7._
       */
      function toUint160(uint256 value) internal pure returns (uint160) {
          require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
          return uint160(value);
      }
  
      /**
       * @dev Returns the downcasted uint152 from uint256, reverting on
       * overflow (when the input is greater than largest uint152).
       *
       * Counterpart to Solidity's `uint152` operator.
       *
       * Requirements:
       *
       * - input must fit into 152 bits
       *
       * _Available since v4.7._
       */
      function toUint152(uint256 value) internal pure returns (uint152) {
          require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
          return uint152(value);
      }
  
      /**
       * @dev Returns the downcasted uint144 from uint256, reverting on
       * overflow (when the input is greater than largest uint144).
       *
       * Counterpart to Solidity's `uint144` operator.
       *
       * Requirements:
       *
       * - input must fit into 144 bits
       *
       * _Available since v4.7._
       */
      function toUint144(uint256 value) internal pure returns (uint144) {
          require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
          return uint144(value);
      }
  
      /**
       * @dev Returns the downcasted uint136 from uint256, reverting on
       * overflow (when the input is greater than largest uint136).
       *
       * Counterpart to Solidity's `uint136` operator.
       *
       * Requirements:
       *
       * - input must fit into 136 bits
       *
       * _Available since v4.7._
       */
      function toUint136(uint256 value) internal pure returns (uint136) {
          require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
          return uint136(value);
      }
  
      /**
       * @dev Returns the downcasted uint128 from uint256, reverting on
       * overflow (when the input is greater than largest uint128).
       *
       * Counterpart to Solidity's `uint128` operator.
       *
       * Requirements:
       *
       * - input must fit into 128 bits
       *
       * _Available since v2.5._
       */
      function toUint128(uint256 value) internal pure returns (uint128) {
          require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
          return uint128(value);
      }
  
      /**
       * @dev Returns the downcasted uint120 from uint256, reverting on
       * overflow (when the input is greater than largest uint120).
       *
       * Counterpart to Solidity's `uint120` operator.
       *
       * Requirements:
       *
       * - input must fit into 120 bits
       *
       * _Available since v4.7._
       */
      function toUint120(uint256 value) internal pure returns (uint120) {
          require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
          return uint120(value);
      }
  
      /**
       * @dev Returns the downcasted uint112 from uint256, reverting on
       * overflow (when the input is greater than largest uint112).
       *
       * Counterpart to Solidity's `uint112` operator.
       *
       * Requirements:
       *
       * - input must fit into 112 bits
       *
       * _Available since v4.7._
       */
      function toUint112(uint256 value) internal pure returns (uint112) {
          require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
          return uint112(value);
      }
  
      /**
       * @dev Returns the downcasted uint104 from uint256, reverting on
       * overflow (when the input is greater than largest uint104).
       *
       * Counterpart to Solidity's `uint104` operator.
       *
       * Requirements:
       *
       * - input must fit into 104 bits
       *
       * _Available since v4.7._
       */
      function toUint104(uint256 value) internal pure returns (uint104) {
          require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
          return uint104(value);
      }
  
      /**
       * @dev Returns the downcasted uint96 from uint256, reverting on
       * overflow (when the input is greater than largest uint96).
       *
       * Counterpart to Solidity's `uint96` operator.
       *
       * Requirements:
       *
       * - input must fit into 96 bits
       *
       * _Available since v4.2._
       */
      function toUint96(uint256 value) internal pure returns (uint96) {
          require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
          return uint96(value);
      }
  
      /**
       * @dev Returns the downcasted uint88 from uint256, reverting on
       * overflow (when the input is greater than largest uint88).
       *
       * Counterpart to Solidity's `uint88` operator.
       *
       * Requirements:
       *
       * - input must fit into 88 bits
       *
       * _Available since v4.7._
       */
      function toUint88(uint256 value) internal pure returns (uint88) {
          require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
          return uint88(value);
      }
  
      /**
       * @dev Returns the downcasted uint80 from uint256, reverting on
       * overflow (when the input is greater than largest uint80).
       *
       * Counterpart to Solidity's `uint80` operator.
       *
       * Requirements:
       *
       * - input must fit into 80 bits
       *
       * _Available since v4.7._
       */
      function toUint80(uint256 value) internal pure returns (uint80) {
          require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
          return uint80(value);
      }
  
      /**
       * @dev Returns the downcasted uint72 from uint256, reverting on
       * overflow (when the input is greater than largest uint72).
       *
       * Counterpart to Solidity's `uint72` operator.
       *
       * Requirements:
       *
       * - input must fit into 72 bits
       *
       * _Available since v4.7._
       */
      function toUint72(uint256 value) internal pure returns (uint72) {
          require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
          return uint72(value);
      }
  
      /**
       * @dev Returns the downcasted uint64 from uint256, reverting on
       * overflow (when the input is greater than largest uint64).
       *
       * Counterpart to Solidity's `uint64` operator.
       *
       * Requirements:
       *
       * - input must fit into 64 bits
       *
       * _Available since v2.5._
       */
      function toUint64(uint256 value) internal pure returns (uint64) {
          require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
          return uint64(value);
      }
  
      /**
       * @dev Returns the downcasted uint56 from uint256, reverting on
       * overflow (when the input is greater than largest uint56).
       *
       * Counterpart to Solidity's `uint56` operator.
       *
       * Requirements:
       *
       * - input must fit into 56 bits
       *
       * _Available since v4.7._
       */
      function toUint56(uint256 value) internal pure returns (uint56) {
          require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
          return uint56(value);
      }
  
      /**
       * @dev Returns the downcasted uint48 from uint256, reverting on
       * overflow (when the input is greater than largest uint48).
       *
       * Counterpart to Solidity's `uint48` operator.
       *
       * Requirements:
       *
       * - input must fit into 48 bits
       *
       * _Available since v4.7._
       */
      function toUint48(uint256 value) internal pure returns (uint48) {
          require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
          return uint48(value);
      }
  
      /**
       * @dev Returns the downcasted uint40 from uint256, reverting on
       * overflow (when the input is greater than largest uint40).
       *
       * Counterpart to Solidity's `uint40` operator.
       *
       * Requirements:
       *
       * - input must fit into 40 bits
       *
       * _Available since v4.7._
       */
      function toUint40(uint256 value) internal pure returns (uint40) {
          require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
          return uint40(value);
      }
  
      /**
       * @dev Returns the downcasted uint32 from uint256, reverting on
       * overflow (when the input is greater than largest uint32).
       *
       * Counterpart to Solidity's `uint32` operator.
       *
       * Requirements:
       *
       * - input must fit into 32 bits
       *
       * _Available since v2.5._
       */
      function toUint32(uint256 value) internal pure returns (uint32) {
          require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
          return uint32(value);
      }
  
      /**
       * @dev Returns the downcasted uint24 from uint256, reverting on
       * overflow (when the input is greater than largest uint24).
       *
       * Counterpart to Solidity's `uint24` operator.
       *
       * Requirements:
       *
       * - input must fit into 24 bits
       *
       * _Available since v4.7._
       */
      function toUint24(uint256 value) internal pure returns (uint24) {
          require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
          return uint24(value);
      }
  
      /**
       * @dev Returns the downcasted uint16 from uint256, reverting on
       * overflow (when the input is greater than largest uint16).
       *
       * Counterpart to Solidity's `uint16` operator.
       *
       * Requirements:
       *
       * - input must fit into 16 bits
       *
       * _Available since v2.5._
       */
      function toUint16(uint256 value) internal pure returns (uint16) {
          require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
          return uint16(value);
      }
  
      /**
       * @dev Returns the downcasted uint8 from uint256, reverting on
       * overflow (when the input is greater than largest uint8).
       *
       * Counterpart to Solidity's `uint8` operator.
       *
       * Requirements:
       *
       * - input must fit into 8 bits
       *
       * _Available since v2.5._
       */
      function toUint8(uint256 value) internal pure returns (uint8) {
          require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
          return uint8(value);
      }
  
      /**
       * @dev Converts a signed int256 into an unsigned uint256.
       *
       * Requirements:
       *
       * - input must be greater than or equal to 0.
       *
       * _Available since v3.0._
       */
      function toUint256(int256 value) internal pure returns (uint256) {
          require(value >= 0, "SafeCast: value must be positive");
          return uint256(value);
      }
  
      /**
       * @dev Returns the downcasted int248 from int256, reverting on
       * overflow (when the input is less than smallest int248 or
       * greater than largest int248).
       *
       * Counterpart to Solidity's `int248` operator.
       *
       * Requirements:
       *
       * - input must fit into 248 bits
       *
       * _Available since v4.7._
       */
      function toInt248(int256 value) internal pure returns (int248 downcasted) {
          downcasted = int248(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
      }
  
      /**
       * @dev Returns the downcasted int240 from int256, reverting on
       * overflow (when the input is less than smallest int240 or
       * greater than largest int240).
       *
       * Counterpart to Solidity's `int240` operator.
       *
       * Requirements:
       *
       * - input must fit into 240 bits
       *
       * _Available since v4.7._
       */
      function toInt240(int256 value) internal pure returns (int240 downcasted) {
          downcasted = int240(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
      }
  
      /**
       * @dev Returns the downcasted int232 from int256, reverting on
       * overflow (when the input is less than smallest int232 or
       * greater than largest int232).
       *
       * Counterpart to Solidity's `int232` operator.
       *
       * Requirements:
       *
       * - input must fit into 232 bits
       *
       * _Available since v4.7._
       */
      function toInt232(int256 value) internal pure returns (int232 downcasted) {
          downcasted = int232(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
      }
  
      /**
       * @dev Returns the downcasted int224 from int256, reverting on
       * overflow (when the input is less than smallest int224 or
       * greater than largest int224).
       *
       * Counterpart to Solidity's `int224` operator.
       *
       * Requirements:
       *
       * - input must fit into 224 bits
       *
       * _Available since v4.7._
       */
      function toInt224(int256 value) internal pure returns (int224 downcasted) {
          downcasted = int224(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
      }
  
      /**
       * @dev Returns the downcasted int216 from int256, reverting on
       * overflow (when the input is less than smallest int216 or
       * greater than largest int216).
       *
       * Counterpart to Solidity's `int216` operator.
       *
       * Requirements:
       *
       * - input must fit into 216 bits
       *
       * _Available since v4.7._
       */
      function toInt216(int256 value) internal pure returns (int216 downcasted) {
          downcasted = int216(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
      }
  
      /**
       * @dev Returns the downcasted int208 from int256, reverting on
       * overflow (when the input is less than smallest int208 or
       * greater than largest int208).
       *
       * Counterpart to Solidity's `int208` operator.
       *
       * Requirements:
       *
       * - input must fit into 208 bits
       *
       * _Available since v4.7._
       */
      function toInt208(int256 value) internal pure returns (int208 downcasted) {
          downcasted = int208(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
      }
  
      /**
       * @dev Returns the downcasted int200 from int256, reverting on
       * overflow (when the input is less than smallest int200 or
       * greater than largest int200).
       *
       * Counterpart to Solidity's `int200` operator.
       *
       * Requirements:
       *
       * - input must fit into 200 bits
       *
       * _Available since v4.7._
       */
      function toInt200(int256 value) internal pure returns (int200 downcasted) {
          downcasted = int200(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
      }
  
      /**
       * @dev Returns the downcasted int192 from int256, reverting on
       * overflow (when the input is less than smallest int192 or
       * greater than largest int192).
       *
       * Counterpart to Solidity's `int192` operator.
       *
       * Requirements:
       *
       * - input must fit into 192 bits
       *
       * _Available since v4.7._
       */
      function toInt192(int256 value) internal pure returns (int192 downcasted) {
          downcasted = int192(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
      }
  
      /**
       * @dev Returns the downcasted int184 from int256, reverting on
       * overflow (when the input is less than smallest int184 or
       * greater than largest int184).
       *
       * Counterpart to Solidity's `int184` operator.
       *
       * Requirements:
       *
       * - input must fit into 184 bits
       *
       * _Available since v4.7._
       */
      function toInt184(int256 value) internal pure returns (int184 downcasted) {
          downcasted = int184(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
      }
  
      /**
       * @dev Returns the downcasted int176 from int256, reverting on
       * overflow (when the input is less than smallest int176 or
       * greater than largest int176).
       *
       * Counterpart to Solidity's `int176` operator.
       *
       * Requirements:
       *
       * - input must fit into 176 bits
       *
       * _Available since v4.7._
       */
      function toInt176(int256 value) internal pure returns (int176 downcasted) {
          downcasted = int176(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
      }
  
      /**
       * @dev Returns the downcasted int168 from int256, reverting on
       * overflow (when the input is less than smallest int168 or
       * greater than largest int168).
       *
       * Counterpart to Solidity's `int168` operator.
       *
       * Requirements:
       *
       * - input must fit into 168 bits
       *
       * _Available since v4.7._
       */
      function toInt168(int256 value) internal pure returns (int168 downcasted) {
          downcasted = int168(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
      }
  
      /**
       * @dev Returns the downcasted int160 from int256, reverting on
       * overflow (when the input is less than smallest int160 or
       * greater than largest int160).
       *
       * Counterpart to Solidity's `int160` operator.
       *
       * Requirements:
       *
       * - input must fit into 160 bits
       *
       * _Available since v4.7._
       */
      function toInt160(int256 value) internal pure returns (int160 downcasted) {
          downcasted = int160(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
      }
  
      /**
       * @dev Returns the downcasted int152 from int256, reverting on
       * overflow (when the input is less than smallest int152 or
       * greater than largest int152).
       *
       * Counterpart to Solidity's `int152` operator.
       *
       * Requirements:
       *
       * - input must fit into 152 bits
       *
       * _Available since v4.7._
       */
      function toInt152(int256 value) internal pure returns (int152 downcasted) {
          downcasted = int152(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
      }
  
      /**
       * @dev Returns the downcasted int144 from int256, reverting on
       * overflow (when the input is less than smallest int144 or
       * greater than largest int144).
       *
       * Counterpart to Solidity's `int144` operator.
       *
       * Requirements:
       *
       * - input must fit into 144 bits
       *
       * _Available since v4.7._
       */
      function toInt144(int256 value) internal pure returns (int144 downcasted) {
          downcasted = int144(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
      }
  
      /**
       * @dev Returns the downcasted int136 from int256, reverting on
       * overflow (when the input is less than smallest int136 or
       * greater than largest int136).
       *
       * Counterpart to Solidity's `int136` operator.
       *
       * Requirements:
       *
       * - input must fit into 136 bits
       *
       * _Available since v4.7._
       */
      function toInt136(int256 value) internal pure returns (int136 downcasted) {
          downcasted = int136(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
      }
  
      /**
       * @dev Returns the downcasted int128 from int256, reverting on
       * overflow (when the input is less than smallest int128 or
       * greater than largest int128).
       *
       * Counterpart to Solidity's `int128` operator.
       *
       * Requirements:
       *
       * - input must fit into 128 bits
       *
       * _Available since v3.1._
       */
      function toInt128(int256 value) internal pure returns (int128 downcasted) {
          downcasted = int128(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
      }
  
      /**
       * @dev Returns the downcasted int120 from int256, reverting on
       * overflow (when the input is less than smallest int120 or
       * greater than largest int120).
       *
       * Counterpart to Solidity's `int120` operator.
       *
       * Requirements:
       *
       * - input must fit into 120 bits
       *
       * _Available since v4.7._
       */
      function toInt120(int256 value) internal pure returns (int120 downcasted) {
          downcasted = int120(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
      }
  
      /**
       * @dev Returns the downcasted int112 from int256, reverting on
       * overflow (when the input is less than smallest int112 or
       * greater than largest int112).
       *
       * Counterpart to Solidity's `int112` operator.
       *
       * Requirements:
       *
       * - input must fit into 112 bits
       *
       * _Available since v4.7._
       */
      function toInt112(int256 value) internal pure returns (int112 downcasted) {
          downcasted = int112(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
      }
  
      /**
       * @dev Returns the downcasted int104 from int256, reverting on
       * overflow (when the input is less than smallest int104 or
       * greater than largest int104).
       *
       * Counterpart to Solidity's `int104` operator.
       *
       * Requirements:
       *
       * - input must fit into 104 bits
       *
       * _Available since v4.7._
       */
      function toInt104(int256 value) internal pure returns (int104 downcasted) {
          downcasted = int104(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
      }
  
      /**
       * @dev Returns the downcasted int96 from int256, reverting on
       * overflow (when the input is less than smallest int96 or
       * greater than largest int96).
       *
       * Counterpart to Solidity's `int96` operator.
       *
       * Requirements:
       *
       * - input must fit into 96 bits
       *
       * _Available since v4.7._
       */
      function toInt96(int256 value) internal pure returns (int96 downcasted) {
          downcasted = int96(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
      }
  
      /**
       * @dev Returns the downcasted int88 from int256, reverting on
       * overflow (when the input is less than smallest int88 or
       * greater than largest int88).
       *
       * Counterpart to Solidity's `int88` operator.
       *
       * Requirements:
       *
       * - input must fit into 88 bits
       *
       * _Available since v4.7._
       */
      function toInt88(int256 value) internal pure returns (int88 downcasted) {
          downcasted = int88(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
      }
  
      /**
       * @dev Returns the downcasted int80 from int256, reverting on
       * overflow (when the input is less than smallest int80 or
       * greater than largest int80).
       *
       * Counterpart to Solidity's `int80` operator.
       *
       * Requirements:
       *
       * - input must fit into 80 bits
       *
       * _Available since v4.7._
       */
      function toInt80(int256 value) internal pure returns (int80 downcasted) {
          downcasted = int80(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
      }
  
      /**
       * @dev Returns the downcasted int72 from int256, reverting on
       * overflow (when the input is less than smallest int72 or
       * greater than largest int72).
       *
       * Counterpart to Solidity's `int72` operator.
       *
       * Requirements:
       *
       * - input must fit into 72 bits
       *
       * _Available since v4.7._
       */
      function toInt72(int256 value) internal pure returns (int72 downcasted) {
          downcasted = int72(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
      }
  
      /**
       * @dev Returns the downcasted int64 from int256, reverting on
       * overflow (when the input is less than smallest int64 or
       * greater than largest int64).
       *
       * Counterpart to Solidity's `int64` operator.
       *
       * Requirements:
       *
       * - input must fit into 64 bits
       *
       * _Available since v3.1._
       */
      function toInt64(int256 value) internal pure returns (int64 downcasted) {
          downcasted = int64(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
      }
  
      /**
       * @dev Returns the downcasted int56 from int256, reverting on
       * overflow (when the input is less than smallest int56 or
       * greater than largest int56).
       *
       * Counterpart to Solidity's `int56` operator.
       *
       * Requirements:
       *
       * - input must fit into 56 bits
       *
       * _Available since v4.7._
       */
      function toInt56(int256 value) internal pure returns (int56 downcasted) {
          downcasted = int56(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
      }
  
      /**
       * @dev Returns the downcasted int48 from int256, reverting on
       * overflow (when the input is less than smallest int48 or
       * greater than largest int48).
       *
       * Counterpart to Solidity's `int48` operator.
       *
       * Requirements:
       *
       * - input must fit into 48 bits
       *
       * _Available since v4.7._
       */
      function toInt48(int256 value) internal pure returns (int48 downcasted) {
          downcasted = int48(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
      }
  
      /**
       * @dev Returns the downcasted int40 from int256, reverting on
       * overflow (when the input is less than smallest int40 or
       * greater than largest int40).
       *
       * Counterpart to Solidity's `int40` operator.
       *
       * Requirements:
       *
       * - input must fit into 40 bits
       *
       * _Available since v4.7._
       */
      function toInt40(int256 value) internal pure returns (int40 downcasted) {
          downcasted = int40(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
      }
  
      /**
       * @dev Returns the downcasted int32 from int256, reverting on
       * overflow (when the input is less than smallest int32 or
       * greater than largest int32).
       *
       * Counterpart to Solidity's `int32` operator.
       *
       * Requirements:
       *
       * - input must fit into 32 bits
       *
       * _Available since v3.1._
       */
      function toInt32(int256 value) internal pure returns (int32 downcasted) {
          downcasted = int32(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
      }
  
      /**
       * @dev Returns the downcasted int24 from int256, reverting on
       * overflow (when the input is less than smallest int24 or
       * greater than largest int24).
       *
       * Counterpart to Solidity's `int24` operator.
       *
       * Requirements:
       *
       * - input must fit into 24 bits
       *
       * _Available since v4.7._
       */
      function toInt24(int256 value) internal pure returns (int24 downcasted) {
          downcasted = int24(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
      }
  
      /**
       * @dev Returns the downcasted int16 from int256, reverting on
       * overflow (when the input is less than smallest int16 or
       * greater than largest int16).
       *
       * Counterpart to Solidity's `int16` operator.
       *
       * Requirements:
       *
       * - input must fit into 16 bits
       *
       * _Available since v3.1._
       */
      function toInt16(int256 value) internal pure returns (int16 downcasted) {
          downcasted = int16(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
      }
  
      /**
       * @dev Returns the downcasted int8 from int256, reverting on
       * overflow (when the input is less than smallest int8 or
       * greater than largest int8).
       *
       * Counterpart to Solidity's `int8` operator.
       *
       * Requirements:
       *
       * - input must fit into 8 bits
       *
       * _Available since v3.1._
       */
      function toInt8(int256 value) internal pure returns (int8 downcasted) {
          downcasted = int8(value);
          require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
      }
  
      /**
       * @dev Converts an unsigned uint256 into a signed int256.
       *
       * Requirements:
       *
       * - input must be less than or equal to maxInt256.
       *
       * _Available since v3.0._
       */
      function toInt256(uint256 value) internal pure returns (int256) {
          // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
          require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
          return int256(value);
      }
  }
  
  
  // File @openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol@v4.8.0
  
   
  // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/ERC20Votes.sol)
  
  pragma solidity ^0.8.0;
  
  
  
  
  
  /**
   * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's,
   * and supports token supply up to 2^224^ - 1, while COMP is limited to 2^96^ - 1.
   *
   * NOTE: If exact COMP compatibility is required, use the {ERC20VotesComp} variant of this module.
   *
   * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either
   * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting
   * power can be queried through the public accessors {getVotes} and {getPastVotes}.
   *
   * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it
   * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked.
   *
   * _Available since v4.2._
   */
  abstract contract ERC20Votes is IVotes, ERC20Permit {
      struct Checkpoint {
          uint32 fromBlock;
          uint224 votes;
      }
  
      bytes32 private constant _DELEGATION_TYPEHASH =
          keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
  
      mapping(address => address) private _delegates;
      mapping(address => Checkpoint[]) private _checkpoints;
      Checkpoint[] private _totalSupplyCheckpoints;
  
      /**
       * @dev Get the `pos`-th checkpoint for `account`.
       */
      function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoint memory) {
          return _checkpoints[account][pos];
      }
  
      /**
       * @dev Get number of checkpoints for `account`.
       */
      function numCheckpoints(address account) public view virtual returns (uint32) {
          return SafeCast.toUint32(_checkpoints[account].length);
      }
  
      /**
       * @dev Get the address `account` is currently delegating to.
       */
      function delegates(address account) public view virtual override returns (address) {
          return _delegates[account];
      }
  
      /**
       * @dev Gets the current votes balance for `account`
       */
      function getVotes(address account) public view virtual override returns (uint256) {
          uint256 pos = _checkpoints[account].length;
          return pos == 0 ? 0 : _checkpoints[account][pos - 1].votes;
      }
  
      /**
       * @dev Retrieve the number of votes for `account` at the end of `blockNumber`.
       *
       * Requirements:
       *
       * - `blockNumber` must have been already mined
       */
      function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {
          require(blockNumber < block.number, "ERC20Votes: block not yet mined");
          return _checkpointsLookup(_checkpoints[account], blockNumber);
      }
  
      /**
       * @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.
       * It is but NOT the sum of all the delegated votes!
       *
       * Requirements:
       *
       * - `blockNumber` must have been already mined
       */
      function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {
          require(blockNumber < block.number, "ERC20Votes: block not yet mined");
          return _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);
      }
  
      /**
       * @dev Lookup a value in a list of (sorted) checkpoints.
       */
      function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 blockNumber) private view returns (uint256) {
          // We run a binary search to look for the earliest checkpoint taken after `blockNumber`.
          //
          // Initially we check if the block is recent to narrow the search range.
          // During the loop, the index of the wanted checkpoint remains in the range [low-1, high).
          // With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant.
          // - If the middle checkpoint is after `blockNumber`, we look in [low, mid)
          // - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high)
          // Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not
          // out of bounds (in which case we're looking too far in the past and the result is 0).
          // Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is
          // past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out
          // the same.
          uint256 length = ckpts.length;
  
          uint256 low = 0;
          uint256 high = length;
  
          if (length > 5) {
              uint256 mid = length - Math.sqrt(length);
              if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
                  high = mid;
              } else {
                  low = mid + 1;
              }
          }
  
          while (low < high) {
              uint256 mid = Math.average(low, high);
              if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
                  high = mid;
              } else {
                  low = mid + 1;
              }
          }
  
          return high == 0 ? 0 : _unsafeAccess(ckpts, high - 1).votes;
      }
  
      /**
       * @dev Delegate votes from the sender to `delegatee`.
       */
      function delegate(address delegatee) public virtual override {
          _delegate(_msgSender(), delegatee);
      }
  
      /**
       * @dev Delegates votes from signer to `delegatee`
       */
      function delegateBySig(
          address delegatee,
          uint256 nonce,
          uint256 expiry,
          uint8 v,
          bytes32 r,
          bytes32 s
      ) public virtual override {
          require(block.timestamp <= expiry, "ERC20Votes: signature expired");
          address signer = ECDSA.recover(
              _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),
              v,
              r,
              s
          );
          require(nonce == _useNonce(signer), "ERC20Votes: invalid nonce");
          _delegate(signer, delegatee);
      }
  
      /**
       * @dev Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1).
       */
      function _maxSupply() internal view virtual returns (uint224) {
          return type(uint224).max;
      }
  
      /**
       * @dev Snapshots the totalSupply after it has been increased.
       */
      function _mint(address account, uint256 amount) internal virtual override {
          super._mint(account, amount);
          require(totalSupply() <= _maxSupply(), "ERC20Votes: total supply risks overflowing votes");
  
          _writeCheckpoint(_totalSupplyCheckpoints, _add, amount);
      }
  
      /**
       * @dev Snapshots the totalSupply after it has been decreased.
       */
      function _burn(address account, uint256 amount) internal virtual override {
          super._burn(account, amount);
  
          _writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount);
      }
  
      /**
       * @dev Move voting power when tokens are transferred.
       *
       * Emits a {IVotes-DelegateVotesChanged} event.
       */
      function _afterTokenTransfer(
          address from,
          address to,
          uint256 amount
      ) internal virtual override {
          super._afterTokenTransfer(from, to, amount);
  
          _moveVotingPower(delegates(from), delegates(to), amount);
      }
  
      /**
       * @dev Change delegation for `delegator` to `delegatee`.
       *
       * Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}.
       */
      function _delegate(address delegator, address delegatee) internal virtual {
          address currentDelegate = delegates(delegator);
          uint256 delegatorBalance = balanceOf(delegator);
          _delegates[delegator] = delegatee;
  
          emit DelegateChanged(delegator, currentDelegate, delegatee);
  
          _moveVotingPower(currentDelegate, delegatee, delegatorBalance);
      }
  
      function _moveVotingPower(
          address src,
          address dst,
          uint256 amount
      ) private {
          if (src != dst && amount > 0) {
              if (src != address(0)) {
                  (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[src], _subtract, amount);
                  emit DelegateVotesChanged(src, oldWeight, newWeight);
              }
  
              if (dst != address(0)) {
                  (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[dst], _add, amount);
                  emit DelegateVotesChanged(dst, oldWeight, newWeight);
              }
          }
      }
  
      function _writeCheckpoint(
          Checkpoint[] storage ckpts,
          function(uint256, uint256) view returns (uint256) op,
          uint256 delta
      ) private returns (uint256 oldWeight, uint256 newWeight) {
          uint256 pos = ckpts.length;
  
          Checkpoint memory oldCkpt = pos == 0 ? Checkpoint(0, 0) : _unsafeAccess(ckpts, pos - 1);
  
          oldWeight = oldCkpt.votes;
          newWeight = op(oldWeight, delta);
  
          if (pos > 0 && oldCkpt.fromBlock == block.number) {
              _unsafeAccess(ckpts, pos - 1).votes = SafeCast.toUint224(newWeight);
          } else {
              ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)}));
          }
      }
  
      function _add(uint256 a, uint256 b) private pure returns (uint256) {
          return a + b;
      }
  
      function _subtract(uint256 a, uint256 b) private pure returns (uint256) {
          return a - b;
      }
  
      function _unsafeAccess(Checkpoint[] storage ckpts, uint256 pos) private pure returns (Checkpoint storage result) {
          assembly {
              mstore(0, ckpts.slot)
              result.slot := add(keccak256(0, 0x20), pos)
          }
      }
  }
  
  
  // File contracts/SkyCredits.sol
  
   
  pragma solidity 0.8.17;
  
  
  contract SkyCredit is ERC20, Ownable, ERC20Permit, ERC20Votes {
    error NullAddress();
    error Unauthorized();
    
  
    //uint public maxSupply;
    address private managementAddress;
      constructor(address _management)
          ERC20("SkyCredit", "SKY")
          ERC20Permit("SkyCredit")
      {
           if (_management==address(0)) revert NullAddress();
          managementAddress = _management;
          transferOwnership(0x1CdaC19722f3c3515cF27617EaBa34c008BF3f01);
      }
  
      modifier onlyManagement {
          require(msg.sender == managementAddress, "Unauthorized: Only callable through the management contract");
          _;
      }
      function mintSkyCredits(address account, uint256 amount) external onlyOwner {
          _mint(account,amount);
      }
  
     function mint(address account, uint256 amount)
          external
         onlyManagement
      {
          _mint(account,amount);
      }
    
      function burn(address account, uint256 amount)
          external
          onlyManagement
      {
          _burn(account, amount);
      }
      // The following functions are overrides required by Solidity.
  
     function _afterTokenTransfer(
      address from,
      address to,
      uint256 amount
    ) internal override(ERC20, ERC20Votes) {
      super._afterTokenTransfer(from, to, amount);
    }
    
     function _mint(address to, uint256 amount) internal override(ERC20, ERC20Votes) {
      super._mint(to, amount);
    }
  
    function _burn(address account, uint256 amount) internal override(ERC20, ERC20Votes) {
      super._burn(account, amount);
    }
  
  }
  interface ISkyCredit {
    function burn(address account, uint256 amount) external;
    function mint(address account, uint256 amount) external;
    function balanceOf(address account) external view returns (uint256);
  }