ETH Price: $2,766.20 (-1.32%)

Transaction Decoder

Block:
20876146 at Oct-02-2024 06:53:35 AM +UTC
Transaction Fee:
0.000590535622599948 ETH $1.63
Gas Used:
89,543 Gas / 6.594994836 Gwei

Emitted Events:

886 AethirToken.Transfer( from=[Receiver] 0x865215eabecc74062a6748f26f2d0d130bc18fcb, to=[Sender] 0x272ce9cf8f219a35501985bff7662a591a5d701e, value=967000000000000000000 )
887 0x865215eabecc74062a6748f26f2d0d130bc18fcb.0xb245a221ddc541d8c0feb01abb9f4a759456ce4dc4b33825118bd0a519663c3a( 0xb245a221ddc541d8c0feb01abb9f4a759456ce4dc4b33825118bd0a519663c3a, 000000000000000000000000272ce9cf8f219a35501985bff7662a591a5d701e, 000000000000000000000000000000000000000000000000000000000000002f, 0000000000000000000000000000000000000000000000000000000000000002, 0000000000000000000000000000000000000000000000000000000000001c29, 00000000000000000000000000000000000000000000000000000000000003c7 )

Account State Difference:

  Address   Before After State Difference Code
0x272CE9cF...91A5d701E
0.008632901761833898 Eth
Nonce: 1775
0.00804236613923395 Eth
Nonce: 1776
0.000590535622599948
(Titan Builder)
12.203504321494429152 Eth12.203599524112126807 Eth0.000095202617697655
0x865215EA...30bC18fCb
0xbe0Ed413...7E6c5226B

Execution Trace

0x865215eabecc74062a6748f26f2d0d130bc18fcb.b01b645a( )
  • 0xe36319449b8064a6615ec83a4909a4215c83a19d.b01b645a( )
    • Null: 0x000...001.647767f0( )
    • AethirToken.transfer( to=0x272CE9cF8F219A35501985bff7662A591A5d701E, amount=967000000000000000000 ) => ( True )
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
      pragma solidity ^0.8.0;
      import "../utils/Context.sol";
      /**
       * @dev Contract module which provides a basic access control mechanism, where
       * there is an account (an owner) that can be granted exclusive access to
       * specific functions.
       *
       * By default, the owner account will be the one that deploys the contract. This
       * can later be changed with {transferOwnership}.
       *
       * This module is used through inheritance. It will make available the modifier
       * `onlyOwner`, which can be applied to your functions to restrict their use to
       * the owner.
       */
      abstract contract Ownable is Context {
          address private _owner;
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
          /**
           * @dev Initializes the contract setting the deployer as the initial owner.
           */
          constructor() {
              _transferOwnership(_msgSender());
          }
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
              _checkOwner();
              _;
          }
          /**
           * @dev Returns the address of the current owner.
           */
          function owner() public view virtual returns (address) {
              return _owner;
          }
          /**
           * @dev Throws if the sender is not the owner.
           */
          function _checkOwner() internal view virtual {
              require(owner() == _msgSender(), "Ownable: caller is not the owner");
          }
          /**
           * @dev Leaves the contract without owner. It will not be possible to call
           * `onlyOwner` functions. Can only be called by the current owner.
           *
           * NOTE: Renouncing ownership will leave the contract without an owner,
           * thereby disabling any functionality that is only available to the owner.
           */
          function renounceOwnership() public virtual onlyOwner {
              _transferOwnership(address(0));
          }
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Can only be called by the current owner.
           */
          function transferOwnership(address newOwner) public virtual onlyOwner {
              require(newOwner != address(0), "Ownable: new owner is the zero address");
              _transferOwnership(newOwner);
          }
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Internal function without access restriction.
           */
          function _transferOwnership(address newOwner) internal virtual {
              address oldOwner = _owner;
              _owner = newOwner;
              emit OwnershipTransferred(oldOwner, newOwner);
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol)
      pragma solidity ^0.8.0;
      interface IERC5267 {
          /**
           * @dev MAY be emitted to signal that the domain could have changed.
           */
          event EIP712DomainChanged();
          /**
           * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
           * signature.
           */
          function eip712Domain()
              external
              view
              returns (
                  bytes1 fields,
                  string memory name,
                  string memory version,
                  uint256 chainId,
                  address verifyingContract,
                  bytes32 salt,
                  uint256[] memory extensions
              );
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)
      pragma solidity ^0.8.0;
      import "./IERC20.sol";
      import "./extensions/IERC20Metadata.sol";
      import "../../utils/Context.sol";
      /**
       * @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].
       *
       * The default value of {decimals} is 18. To change this, you should override
       * this function so it returns a different value.
       *
       * 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}.
           *
           * 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 default value returned by this function, unless
           * it's 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 {}
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.9.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);
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/ERC20Permit.sol)
      pragma solidity ^0.8.0;
      import "./IERC20Permit.sol";
      import "../ERC20.sol";
      import "../../../utils/cryptography/ECDSA.sol";
      import "../../../utils/cryptography/EIP712.sol";
      import "../../../utils/Counters.sol";
      /**
       * @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") {}
          /**
           * @inheritdoc IERC20Permit
           */
          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);
          }
          /**
           * @inheritdoc IERC20Permit
           */
          function nonces(address owner) public view virtual override returns (uint256) {
              return _nonces[owner].current();
          }
          /**
           * @inheritdoc IERC20Permit
           */
          // 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();
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
      pragma solidity ^0.8.0;
      import "../IERC20.sol";
      /**
       * @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);
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/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.
       *
       * ==== Security Considerations
       *
       * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
       * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
       * considered as an intention to spend the allowance in any specific way. The second is that because permits have
       * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
       * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
       * generally recommended is:
       *
       * ```solidity
       * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
       *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
       *     doThing(..., value);
       * }
       *
       * function doThing(..., uint256 value) public {
       *     token.safeTransferFrom(msg.sender, address(this), value);
       *     ...
       * }
       * ```
       *
       * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
       * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
       * {SafeERC20-safeTransferFrom}).
       *
       * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
       * contracts should have entry points that don't rely on permit.
       */
      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].
           *
           * CAUTION: See Security Considerations above.
           */
          function permit(
              address owner,
              address spender,
              uint256 value,
              uint256 deadline,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) external;
          /**
           * @dev Returns the current nonce for `owner`. This value must be
           * included whenever a signature is generated for {permit}.
           *
           * Every successful call to {permit} increases ``owner``'s nonce by one. This
           * prevents a signature from being used multiple times.
           */
          function nonces(address owner) external view returns (uint256);
          /**
           * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
           */
          // solhint-disable-next-line func-name-mixedcase
          function DOMAIN_SEPARATOR() external view returns (bytes32);
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
      pragma solidity ^0.8.0;
      import "../IERC20.sol";
      import "../extensions/IERC20Permit.sol";
      import "../../../utils/Address.sol";
      /**
       * @title SafeERC20
       * @dev Wrappers around ERC20 operations that throw on failure (when the token
       * contract returns false). Tokens that return no value (and instead revert or
       * throw on failure) are also supported, non-reverting calls are assumed to be
       * successful.
       * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
       * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
       */
      library SafeERC20 {
          using Address for address;
          /**
           * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
           * non-reverting calls are assumed to be successful.
           */
          function safeTransfer(IERC20 token, address to, uint256 value) internal {
              _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
          }
          /**
           * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
           * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
           */
          function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
              _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
          }
          /**
           * @dev Deprecated. This function has issues similar to the ones found in
           * {IERC20-approve}, and its usage is discouraged.
           *
           * Whenever possible, use {safeIncreaseAllowance} and
           * {safeDecreaseAllowance} instead.
           */
          function safeApprove(IERC20 token, address spender, uint256 value) internal {
              // safeApprove should only be called when setting an initial allowance,
              // or when resetting it to zero. To increase and decrease it, use
              // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
              require(
                  (value == 0) || (token.allowance(address(this), spender) == 0),
                  "SafeERC20: approve from non-zero to non-zero allowance"
              );
              _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
          }
          /**
           * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
           * non-reverting calls are assumed to be successful.
           */
          function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
              uint256 oldAllowance = token.allowance(address(this), spender);
              _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
          }
          /**
           * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
           * non-reverting calls are assumed to be successful.
           */
          function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
              unchecked {
                  uint256 oldAllowance = token.allowance(address(this), spender);
                  require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
                  _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
              }
          }
          /**
           * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
           * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
           * to be set to zero before setting it to a non-zero value, such as USDT.
           */
          function forceApprove(IERC20 token, address spender, uint256 value) internal {
              bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
              if (!_callOptionalReturnBool(token, approvalCall)) {
                  _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
                  _callOptionalReturn(token, approvalCall);
              }
          }
          /**
           * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
           * Revert on invalid signature.
           */
          function safePermit(
              IERC20Permit token,
              address owner,
              address spender,
              uint256 value,
              uint256 deadline,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) internal {
              uint256 nonceBefore = token.nonces(owner);
              token.permit(owner, spender, value, deadline, v, r, s);
              uint256 nonceAfter = token.nonces(owner);
              require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
          }
          /**
           * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
           * on the return value: the return value is optional (but if data is returned, it must not be false).
           * @param token The token targeted by the call.
           * @param data The call data (encoded using abi.encode or one of its variants).
           */
          function _callOptionalReturn(IERC20 token, bytes memory data) private {
              // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
              // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
              // the target address contains contract code and also asserts for success in the low-level call.
              bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
              require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
          }
          /**
           * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
           * on the return value: the return value is optional (but if data is returned, it must not be false).
           * @param token The token targeted by the call.
           * @param data The call data (encoded using abi.encode or one of its variants).
           *
           * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
           */
          function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
              // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
              // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
              // and not revert is the subcall reverts.
              (bool success, bytes memory returndata) = address(token).call(data);
              return
                  success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
      pragma solidity ^0.8.1;
      /**
       * @dev Collection of functions related to the address type
       */
      library Address {
          /**
           * @dev Returns true if `account` is a contract.
           *
           * [IMPORTANT]
           * ====
           * It is unsafe to assume that an address for which this function returns
           * false is an externally-owned account (EOA) and not a contract.
           *
           * Among others, `isContract` will return false for the following
           * types of addresses:
           *
           *  - an externally-owned account
           *  - a contract in construction
           *  - an address where a contract will be created
           *  - an address where a contract lived, but was destroyed
           *
           * Furthermore, `isContract` will also return true if the target contract within
           * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
           * which only has an effect at the end of a transaction.
           * ====
           *
           * [IMPORTANT]
           * ====
           * You shouldn't rely on `isContract` to protect against flash loan attacks!
           *
           * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
           * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
           * constructor.
           * ====
           */
          function isContract(address account) internal view returns (bool) {
              // This method relies on extcodesize/address.code.length, which returns 0
              // for contracts in construction, since the code is only stored at the end
              // of the constructor execution.
              return account.code.length > 0;
          }
          /**
           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
           * `recipient`, forwarding all available gas and reverting on errors.
           *
           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
           * of certain opcodes, possibly making contracts go over the 2300 gas limit
           * imposed by `transfer`, making them unable to receive funds via
           * `transfer`. {sendValue} removes this limitation.
           *
           * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
           *
           * IMPORTANT: because control is transferred to `recipient`, care must be
           * taken to not create reentrancy vulnerabilities. Consider using
           * {ReentrancyGuard} or the
           * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           */
          function sendValue(address payable recipient, uint256 amount) internal {
              require(address(this).balance >= amount, "Address: insufficient balance");
              (bool success, ) = recipient.call{value: amount}("");
              require(success, "Address: unable to send value, recipient may have reverted");
          }
          /**
           * @dev Performs a Solidity function call using a low level `call`. A
           * plain `call` is an unsafe replacement for a function call: use this
           * function instead.
           *
           * If `target` reverts with a revert reason, it is bubbled up by this
           * function (like regular Solidity function calls).
           *
           * Returns the raw returned data. To convert to the expected return value,
           * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
           *
           * Requirements:
           *
           * - `target` must be a contract.
           * - calling `target` with `data` must not revert.
           *
           * _Available since v3.1._
           */
          function functionCall(address target, bytes memory data) internal returns (bytes memory) {
              return functionCallWithValue(target, data, 0, "Address: low-level call failed");
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
           * `errorMessage` as a fallback revert reason when `target` reverts.
           *
           * _Available since v3.1._
           */
          function functionCall(
              address target,
              bytes memory data,
              string memory errorMessage
          ) internal returns (bytes memory) {
              return functionCallWithValue(target, data, 0, errorMessage);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but also transferring `value` wei to `target`.
           *
           * Requirements:
           *
           * - the calling contract must have an ETH balance of at least `value`.
           * - the called Solidity function must be `payable`.
           *
           * _Available since v3.1._
           */
          function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
              return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
          }
          /**
           * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
           * with `errorMessage` as a fallback revert reason when `target` reverts.
           *
           * _Available since v3.1._
           */
          function functionCallWithValue(
              address target,
              bytes memory data,
              uint256 value,
              string memory errorMessage
          ) internal returns (bytes memory) {
              require(address(this).balance >= value, "Address: insufficient balance for call");
              (bool success, bytes memory returndata) = target.call{value: value}(data);
              return verifyCallResultFromTarget(target, success, returndata, errorMessage);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a static call.
           *
           * _Available since v3.3._
           */
          function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
              return functionStaticCall(target, data, "Address: low-level static call failed");
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
           * but performing a static call.
           *
           * _Available since v3.3._
           */
          function functionStaticCall(
              address target,
              bytes memory data,
              string memory errorMessage
          ) internal view returns (bytes memory) {
              (bool success, bytes memory returndata) = target.staticcall(data);
              return verifyCallResultFromTarget(target, success, returndata, errorMessage);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a delegate call.
           *
           * _Available since v3.4._
           */
          function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
              return functionDelegateCall(target, data, "Address: low-level delegate call failed");
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
           * but performing a delegate call.
           *
           * _Available since v3.4._
           */
          function functionDelegateCall(
              address target,
              bytes memory data,
              string memory errorMessage
          ) internal returns (bytes memory) {
              (bool success, bytes memory returndata) = target.delegatecall(data);
              return verifyCallResultFromTarget(target, success, returndata, errorMessage);
          }
          /**
           * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
           * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
           *
           * _Available since v4.8._
           */
          function verifyCallResultFromTarget(
              address target,
              bool success,
              bytes memory returndata,
              string memory errorMessage
          ) internal view returns (bytes memory) {
              if (success) {
                  if (returndata.length == 0) {
                      // only check isContract if the call was successful and the return data is empty
                      // otherwise we already know that it was a contract
                      require(isContract(target), "Address: call to non-contract");
                  }
                  return returndata;
              } else {
                  _revert(returndata, errorMessage);
              }
          }
          /**
           * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
           * revert reason or using the provided one.
           *
           * _Available since v4.3._
           */
          function verifyCallResult(
              bool success,
              bytes memory returndata,
              string memory errorMessage
          ) internal pure returns (bytes memory) {
              if (success) {
                  return returndata;
              } else {
                  _revert(returndata, errorMessage);
              }
          }
          function _revert(bytes memory returndata, string memory errorMessage) private pure {
              // Look for revert reason and bubble it up if present
              if (returndata.length > 0) {
                  // The easiest way to bubble the revert reason is using memory via assembly
                  /// @solidity memory-safe-assembly
                  assembly {
                      let returndata_size := mload(returndata)
                      revert(add(32, returndata), returndata_size)
                  }
              } else {
                  revert(errorMessage);
              }
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.9.4) (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;
          }
          function _contextSuffixLength() internal view virtual returns (uint256) {
              return 0;
          }
      }
      // SPDX-License-Identifier: MIT
      // 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;
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.9.0) (utils/ShortStrings.sol)
      pragma solidity ^0.8.8;
      import "./StorageSlot.sol";
      // | string  | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA   |
      // | length  | 0x                                                              BB |
      type ShortString is bytes32;
      /**
       * @dev This library provides functions to convert short memory strings
       * into a `ShortString` type that can be used as an immutable variable.
       *
       * Strings of arbitrary length can be optimized using this library if
       * they are short enough (up to 31 bytes) by packing them with their
       * length (1 byte) in a single EVM word (32 bytes). Additionally, a
       * fallback mechanism can be used for every other case.
       *
       * Usage example:
       *
       * ```solidity
       * contract Named {
       *     using ShortStrings for *;
       *
       *     ShortString private immutable _name;
       *     string private _nameFallback;
       *
       *     constructor(string memory contractName) {
       *         _name = contractName.toShortStringWithFallback(_nameFallback);
       *     }
       *
       *     function name() external view returns (string memory) {
       *         return _name.toStringWithFallback(_nameFallback);
       *     }
       * }
       * ```
       */
      library ShortStrings {
          // Used as an identifier for strings longer than 31 bytes.
          bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
          error StringTooLong(string str);
          error InvalidShortString();
          /**
           * @dev Encode a string of at most 31 chars into a `ShortString`.
           *
           * This will trigger a `StringTooLong` error is the input string is too long.
           */
          function toShortString(string memory str) internal pure returns (ShortString) {
              bytes memory bstr = bytes(str);
              if (bstr.length > 31) {
                  revert StringTooLong(str);
              }
              return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
          }
          /**
           * @dev Decode a `ShortString` back to a "normal" string.
           */
          function toString(ShortString sstr) internal pure returns (string memory) {
              uint256 len = byteLength(sstr);
              // using `new string(len)` would work locally but is not memory safe.
              string memory str = new string(32);
              /// @solidity memory-safe-assembly
              assembly {
                  mstore(str, len)
                  mstore(add(str, 0x20), sstr)
              }
              return str;
          }
          /**
           * @dev Return the length of a `ShortString`.
           */
          function byteLength(ShortString sstr) internal pure returns (uint256) {
              uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
              if (result > 31) {
                  revert InvalidShortString();
              }
              return result;
          }
          /**
           * @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
           */
          function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
              if (bytes(value).length < 32) {
                  return toShortString(value);
              } else {
                  StorageSlot.getStringSlot(store).value = value;
                  return ShortString.wrap(_FALLBACK_SENTINEL);
              }
          }
          /**
           * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
           */
          function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
              if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
                  return toString(value);
              } else {
                  return store;
              }
          }
          /**
           * @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
           *
           * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
           * actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
           */
          function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
              if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
                  return byteLength(value);
              } else {
                  return bytes(store).length;
              }
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
      // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
      pragma solidity ^0.8.0;
      /**
       * @dev Library for reading and writing primitive types to specific storage slots.
       *
       * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
       * This library helps with reading and writing to such slots without the need for inline assembly.
       *
       * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
       *
       * Example usage to set ERC1967 implementation slot:
       * ```solidity
       * contract ERC1967 {
       *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
       *
       *     function _getImplementation() internal view returns (address) {
       *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
       *     }
       *
       *     function _setImplementation(address newImplementation) internal {
       *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
       *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
       *     }
       * }
       * ```
       *
       * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
       * _Available since v4.9 for `string`, `bytes`._
       */
      library StorageSlot {
          struct AddressSlot {
              address value;
          }
          struct BooleanSlot {
              bool value;
          }
          struct Bytes32Slot {
              bytes32 value;
          }
          struct Uint256Slot {
              uint256 value;
          }
          struct StringSlot {
              string value;
          }
          struct BytesSlot {
              bytes value;
          }
          /**
           * @dev Returns an `AddressSlot` with member `value` located at `slot`.
           */
          function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
              /// @solidity memory-safe-assembly
              assembly {
                  r.slot := slot
              }
          }
          /**
           * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
           */
          function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
              /// @solidity memory-safe-assembly
              assembly {
                  r.slot := slot
              }
          }
          /**
           * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
           */
          function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
              /// @solidity memory-safe-assembly
              assembly {
                  r.slot := slot
              }
          }
          /**
           * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
           */
          function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
              /// @solidity memory-safe-assembly
              assembly {
                  r.slot := slot
              }
          }
          /**
           * @dev Returns an `StringSlot` with member `value` located at `slot`.
           */
          function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
              /// @solidity memory-safe-assembly
              assembly {
                  r.slot := slot
              }
          }
          /**
           * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
           */
          function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
              /// @solidity memory-safe-assembly
              assembly {
                  r.slot := store.slot
              }
          }
          /**
           * @dev Returns an `BytesSlot` with member `value` located at `slot`.
           */
          function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
              /// @solidity memory-safe-assembly
              assembly {
                  r.slot := slot
              }
          }
          /**
           * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
           */
          function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
              /// @solidity memory-safe-assembly
              assembly {
                  r.slot := store.slot
              }
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
      pragma solidity ^0.8.0;
      import "./math/Math.sol";
      import "./math/SignedMath.sol";
      /**
       * @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 `int256` to its ASCII `string` decimal representation.
           */
          function toString(int256 value) internal pure returns (string memory) {
              return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
          }
          /**
           * @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);
          }
          /**
           * @dev Returns true if the two strings are equal.
           */
          function equal(string memory a, string memory b) internal pure returns (bool) {
              return keccak256(bytes(a)) == keccak256(bytes(b));
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)
      pragma solidity ^0.8.0;
      import "../Strings.sol";
      /**
       * @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 message) {
              // 32 is the length in bytes of hash,
              // enforced by the type signature above
              /// @solidity memory-safe-assembly
              assembly {
                  mstore(0x00, "\\x19Ethereum Signed Message:\
      32")
                  mstore(0x1c, hash)
                  message := keccak256(0x00, 0x3c)
              }
          }
          /**
           * @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:\
      ", 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 data) {
              /// @solidity memory-safe-assembly
              assembly {
                  let ptr := mload(0x40)
                  mstore(ptr, "\\x19\\x01")
                  mstore(add(ptr, 0x02), domainSeparator)
                  mstore(add(ptr, 0x22), structHash)
                  data := keccak256(ptr, 0x42)
              }
          }
          /**
           * @dev Returns an Ethereum Signed Data with intended validator, created from a
           * `validator` and `data` according to the version 0 of EIP-191.
           *
           * See {recover}.
           */
          function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
              return keccak256(abi.encodePacked("\\x19\\x00", validator, data));
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol)
      pragma solidity ^0.8.8;
      import "./ECDSA.sol";
      import "../ShortStrings.sol";
      import "../../interfaces/IERC5267.sol";
      /**
       * @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].
       *
       * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
       * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the
       * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
       *
       * _Available since v3.4._
       *
       * @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
       */
      abstract contract EIP712 is IERC5267 {
          using ShortStrings for *;
          bytes32 private constant _TYPE_HASH =
              keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
          // 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 _cachedDomainSeparator;
          uint256 private immutable _cachedChainId;
          address private immutable _cachedThis;
          bytes32 private immutable _hashedName;
          bytes32 private immutable _hashedVersion;
          ShortString private immutable _name;
          ShortString private immutable _version;
          string private _nameFallback;
          string private _versionFallback;
          /**
           * @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) {
              _name = name.toShortStringWithFallback(_nameFallback);
              _version = version.toShortStringWithFallback(_versionFallback);
              _hashedName = keccak256(bytes(name));
              _hashedVersion = keccak256(bytes(version));
              _cachedChainId = block.chainid;
              _cachedDomainSeparator = _buildDomainSeparator();
              _cachedThis = address(this);
          }
          /**
           * @dev Returns the domain separator for the current chain.
           */
          function _domainSeparatorV4() internal view returns (bytes32) {
              if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
                  return _cachedDomainSeparator;
              } else {
                  return _buildDomainSeparator();
              }
          }
          function _buildDomainSeparator() private view returns (bytes32) {
              return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, 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);
          }
          /**
           * @dev See {EIP-5267}.
           *
           * _Available since v4.9._
           */
          function eip712Domain()
              public
              view
              virtual
              override
              returns (
                  bytes1 fields,
                  string memory name,
                  string memory version,
                  uint256 chainId,
                  address verifyingContract,
                  bytes32 salt,
                  uint256[] memory extensions
              )
          {
              return (
                  hex"0f", // 01111
                  _name.toStringWithFallback(_nameFallback),
                  _version.toStringWithFallback(_versionFallback),
                  block.chainid,
                  address(this),
                  bytes32(0),
                  new uint256[](0)
              );
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.9.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) {
                      // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                      // The surrounding unchecked block does not change this fact.
                      // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                      return prod0 / denominator;
                  }
                  // Make sure the result is less than 2^256. Also prevents denominator == 0.
                  require(denominator > prod1, "Math: mulDiv overflow");
                  ///////////////////////////////////////////////
                  // 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 256, 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 << 3) < value ? 1 : 0);
              }
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
      pragma solidity ^0.8.0;
      /**
       * @dev Standard signed math utilities missing in the Solidity language.
       */
      library SignedMath {
          /**
           * @dev Returns the largest of two signed numbers.
           */
          function max(int256 a, int256 b) internal pure returns (int256) {
              return a > b ? a : b;
          }
          /**
           * @dev Returns the smallest of two signed numbers.
           */
          function min(int256 a, int256 b) internal pure returns (int256) {
              return a < b ? a : b;
          }
          /**
           * @dev Returns the average of two signed numbers without overflow.
           * The result is rounded towards zero.
           */
          function average(int256 a, int256 b) internal pure returns (int256) {
              // Formula from the book "Hacker's Delight"
              int256 x = (a & b) + ((a ^ b) >> 1);
              return x + (int256(uint256(x) >> 255) & (a ^ b));
          }
          /**
           * @dev Returns the absolute unsigned value of a signed value.
           */
          function abs(int256 n) internal pure returns (uint256) {
              unchecked {
                  // must be unchecked in order to support `n = type(int256).min`
                  return uint256(n >= 0 ? n : -n);
              }
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity =0.8.18;
      import {
          ERC20,
          ERC20Permit
      } from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
      import {
          SafeERC20
      } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
      import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
      /**
       * @title AethirToken
       * @dev This contract is an implementation of the ERC20 token standard with additional features.
       * The admin multisig wallet can manage addresses from the whitelist, update the maximum allowed token amount for a whitelisted address.
       * The contract also includes a mint function that can be called by the admin multisig wallet to mint tokens to the contract itself.
       */
      contract AethirToken is ERC20Permit, Ownable {
          // Events that the contract emits when changes are made
          event WhitelistedAdded(address account, uint256 maxAmount);
          event WhitelistedRemoved(address account);
          event WhitelistedMaxAmountUpdated(address account, uint256 newMaxAmount);
          event WhitelistedAddressUpdated(address account, address newAddress);
          // Constant that defines the maximum supply of tokens
          uint256 public constant MAX_SUPPLY = 42_000_000_000 * 10 ** 18;
          // Mappings that keep track of the allowed and transferred amounts for each address
          mapping(address => uint256) public allowedAmount;
          mapping(address => uint256) public transferredAmount;
          // Variable that keeps track of the remain amount of tokens that have been whitelisted
          uint256 public remainWhitelisted;
          // Variable that keeps track of the amount of tokens that have been transferred out
          uint256 public totalTransferred;
          /**
           * @dev Contract constructor.
           *
           * This constructor sets the name and symbol of the token using the ERC20
           * constructor, and sets the name of the permit using the ERC20Permit
           * constructor. It also transfers the ownership of the contract to the
           * provided admin multisig wallet.
           *
           * @param _adminMultisigWallet The address of the admin multisig wallet that will own the contract.
           */
          constructor(
              address _adminMultisigWallet
          ) ERC20("Cethir Token", "CTH") ERC20Permit("CTH") {
              transferOwnership(_adminMultisigWallet);
          }
          /**
           * @dev Mints a specified amount of tokens and store inside the token contract.
           *
           * This function can only be called by the admin multisig wallet. It mints
           * a specified amount of tokens and assigns them to the contract itself,
           * increasing the total supply.
           *
           * Requirements:
           *
           * - The total supply of tokens after the minting operation must not exceed the maximum supply.
           *
           * @param amount The amount of tokens to mint.
           */
          function mint(uint256 amount) public onlyOwner {
              require(
                  totalSupply() + amount <= MAX_SUPPLY,
                  "Cannot mint more than max supply"
              );
              _mint(address(this), amount);
          }
          /**
           * @dev Transfers tokens to a whitelisted address.
           *
           * This function can only be called by the admin multisig wallet. It transfers
           * a specified amount of tokens to a given address, provided that the address
           * is whitelisted and the amount does not exceed the maximum allowed amount
           * for that address.
           *
           * Requirements:
           *
           * - `to` must be a whitelisted address.
           * - The sum of `amount` and the previously transferred amount to `to` must not exceed the maximum allowed amount for `to`.
           *
           * @param to The address to transfer tokens to.
           * @param amount The amount of tokens to transfer.
           */
          function transferToWhitelisted(
              address to,
              uint256 amount
          ) public onlyOwner {
              require(
                  transferredAmount[to] + amount <= allowedAmount[to],
                  "Cannot transfer more than max allowed amount"
              );
              transferredAmount[to] += amount;
              totalTransferred += amount;
              remainWhitelisted -= amount;
              SafeERC20.safeTransfer(this, to, amount);
          }
          /**
           * @dev Adds an address to the whitelist and sets its maximum allowed token amount.
           *
           * Requirements:
           *
           * - `account` cannot be the zero address.
           * - `account` must not already be whitelisted.
           * - `maxAmount` must be greater than 0.
           *
           * Emits an {WhitelistedAdded} event.
           *
           * @param account The address to add to the whitelist.
           * @param maxAmount The maximum amount of tokens that the address is allowed to hold.
           */
          function addWhitelisted(
              address account,
              uint256 maxAmount
          ) public onlyOwner {
              require(account != address(0), "Account is the zero address");
              require(account != address(this), "Account is the token address");
              require(allowedAmount[account] == 0, "Account was whitelisted");
              require(maxAmount > 0, "Max amount must be greater than 0");
              require(
                  remainWhitelisted + totalTransferred + maxAmount <= MAX_SUPPLY,
                  "Cannot whitelist more than max supply"
              );
              emit WhitelistedAdded(account, maxAmount);
              remainWhitelisted += maxAmount;
              allowedAmount[account] = maxAmount;
          }
          /**
           * @dev Removes an address from the whitelist.
           *
           * This function can only be called by the admin multisig wallet. It removes
           * a given address from the whitelist by setting its maximum allowed token
           * amount to 0.
           *
           * Requirements:
           *
           * - `account` must be a whitelisted address.
           *
           * Emits a {WhitelistedRemoved} event.
           *
           * @param account The address to remove from the whitelist.
           */
          function removeWhitelisted(address account) public onlyOwner {
              require(allowedAmount[account] > 0, "Account is not whitelisted");
              emit WhitelistedRemoved(account);
              remainWhitelisted -=
                  allowedAmount[account] -
                  transferredAmount[account];
              allowedAmount[account] = 0;
              transferredAmount[account] = 0;
          }
          /**
           * @dev Updates the maximum allowed token amount for a whitelisted address.
           *
           * This function can only be called by the admin multisig wallet. It updates
           * the maximum allowed token amount for a given address, provided that the address
           * is whitelisted and the new maximum amount is greater than 0.
           *
           * Requirements:
           *
           * - `account` must be a whitelisted address.
           * - `newMaxAmount` must be greater than 0.
           *
           * Emits an {WhitelistedMaxAmountUpdated} event.
           *
           * @param account The address to update the maximum allowed token amount for.
           * @param newMaxAmount The new maximum amount of tokens that the address is allowed to hold.
           */
          function updateWhitelistedMaxAmount(
              address account,
              uint256 newMaxAmount
          ) public onlyOwner {
              require(allowedAmount[account] > 0, "Account is not whitelisted");
              require(newMaxAmount > 0, "Max amount must be greater than 0");
              require(
                  newMaxAmount >= transferredAmount[account],
                  "Max amount must not less than transferred amount"
              );
              require(
                  remainWhitelisted + totalTransferred + newMaxAmount <=
                      MAX_SUPPLY + allowedAmount[account],
                  "Cannot whitelist more than max supply"
              );
              emit WhitelistedMaxAmountUpdated(account, newMaxAmount);
              remainWhitelisted =
                  remainWhitelisted +
                  newMaxAmount -
                  allowedAmount[account];
              allowedAmount[account] = newMaxAmount;
          }
          /**
           * @dev Updates the whitelisted address.
           *
           * This function can only be called by the admin multisig wallet. It updates
           * the whitelisted address to a new address, provided that the original address
           * is whitelisted, and the new address is not already whitelisted.
           *
           * The function also transfers the allowed and transferred amounts from the
           * original address to the new address, and resets the allowed and transferred
           * amounts for the original address to 0.
           *
           * Requirements:
           *
           * - `account` must be a whitelisted address.
           * - `newAddress` cannot be the zero address.
           * - `newAddress` must not already be whitelisted.
           *
           * Emits an {WhitelistedAddressUpdated} event.
           *
           * @param account The original address to update.
           * @param newAddress The new address to update to.
           */
          function updateWhitelistedAddress(
              address account,
              address newAddress
          ) public onlyOwner {
              require(newAddress != address(0), "New address is the zero address");
              require(allowedAmount[account] > 0, "Account is not whitelisted");
              require(allowedAmount[newAddress] == 0, "New address was whitelisted");
              emit WhitelistedAddressUpdated(account, newAddress);
              allowedAmount[newAddress] = allowedAmount[account];
              transferredAmount[newAddress] = transferredAmount[account];
              allowedAmount[account] = 0;
              transferredAmount[account] = 0;
          }
          function _afterTokenTransfer(
              address from,
              address to,
              uint256 amount
          ) internal override {
              super._afterTokenTransfer(from, to, amount);
              // Allow any wallet addresses to transfer token back to the contract
              // If the wallet address is whitelisted, the transfered amount will be updated
              if (to == address(this) && from != address(0)) {
                  totalTransferred -= amount;
                  if (transferredAmount[from] >= amount) {
                      transferredAmount[from] -= amount;
                  } else {
                      transferredAmount[from] = 0;
                  }
              }
          }
      }