ETH Price: $2,428.15 (-0.17%)

Transaction Decoder

Block:
22788452 at Jun-26-2025 11:55:11 AM +UTC
Transaction Fee:
0.00018814492585698 ETH $0.46
Gas Used:
175,817 Gas / 1.07011794 Gwei

Emitted Events:

652 EntryPoint.Deposited( account=0xc1507c3b5aec1a50e5d82a9656f283ab69f1fa1b, totalDeposit=321279831341506 )
653 EntryPoint.BeforeExecution( )
654 ERC1967Proxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000c1507c3b5aec1a50e5d82a9656f283ab69f1fa1b, 0x000000000000000000000000771697eb31ec46544177df42c6dffb80aa24ad9a, 000000000000000000000000000000000000000000000002a802f8630a240000 )
655 EntryPoint.UserOperationEvent( userOpHash=428C6BBB83968E0C645B50ED1E947937CF6811C3F058732A59B96FECC813C783, sender=0xc1507c3b5aec1a50e5d82a9656f283ab69f1fa1b, paymaster=0x00000000...000000000, nonce=11208939894671191301950526257515835557638629901759676203802466203718394052608, success=True, actualGasCost=213783481621400, actualGasUsed=199310 )

Account State Difference:

  Address   Before After State Difference Code
0x00000000...6f37da032
(Entry Point 0.7.0)
111.139726354658246518 Eth111.139833851007966624 Eth0.000107496349720106
0x4337004e...d6ACf9E5d
(Pimlico: ERC-4337 Bundler 4)
0.312186759511645273 Eth
Nonce: 24957
0.312212398067409693 Eth
Nonce: 24958
0.00002563855576442
(Titan Builder)
3.893957593695594987 Eth3.893966384545594987 Eth0.00000879085
0xc1507C3b...B69F1Fa1b
0.000398976229245912 Eth
Nonce: 1
0.000077696397904406 Eth
Nonce: 2
0.000321279831341506From: 0 To: 22892026286103371638235752333974922913221768060735732483
0xD0eC028a...03679285D

Execution Trace

EntryPoint.handleOps( ops=, beneficiary=0x4337004ec9c1417F1c7a26EBD4B4fbed6ACf9E5d )
  • 0xc1507c3b5aec1a50e5d82a9656f283ab69f1fa1b.19822f7c( )
    • K1MeeValidator.validateUserOp( userOp=[{name:sender, type:address, order:1, indexed:false, value:0xc1507C3b5AEc1A50e5d82A9656f283aB69F1Fa1b, valueString:0xc1507C3b5AEc1A50e5d82A9656f283aB69F1Fa1b}, {name:nonce, type:uint256, order:2, indexed:false, value:11208939894671191301950526257515835557638629901759676203802466203718394052608, valueString:11208939894671191301950526257515835557638629901759676203802466203718394052608}, {name:initCode, type:bytes, order:3, indexed:false, value:0x, valueString:0x}, {name:callData, type:bytes, order:4, indexed:false, value:0xE9AE5C53000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000078D0EC028A3D21533FDD200838F39C85B03679285D0000000000000000000000000000000000000000000000000000000000000000A9059CBB000000000000000000000000771697EB31EC46544177DF42C6DFFB80AA24AD9A000000000000000000000000000000000000000000000002A802F8630A2400000000000000000000, valueString:0xE9AE5C53000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000078D0EC028A3D21533FDD200838F39C85B03679285D0000000000000000000000000000000000000000000000000000000000000000A9059CBB000000000000000000000000771697EB31EC46544177DF42C6DFFB80AA24AD9A000000000000000000000000000000000000000000000002A802F8630A2400000000000000000000}, {name:accountGasLimits, type:bytes32, order:5, indexed:false, value:0000000000000000000000000001A1A00000000000000000000000000000C404, valueString:0000000000000000000000000001A1A00000000000000000000000000000C404}, {name:preVerificationGas, type:uint256, order:6, indexed:false, value:76325, valueString:76325}, {name:gasFees, type:bytes32, order:7, indexed:false, value:00000000000000000000000003211620000000000000000000000000520A80B2, valueString:00000000000000000000000003211620000000000000000000000000520A80B2}, {name:paymasterAndData, type:bytes, order:8, indexed:false, value:0x, valueString:0x}, {name:signature, type:bytes, order:9, indexed:false, value:0x30030B78C7EFE0218571D198C9693F3C76A0A32B368A0C924056B20386E6D0E87C09786AF922D1FF3CE15A92375F7D2B265D60735403E99B19352AA423E1F45D1C, valueString:0x30030B78C7EFE0218571D198C9693F3C76A0A32B368A0C924056B20386E6D0E87C09786AF922D1FF3CE15A92375F7D2B265D60735403E99B19352AA423E1F45D1C}], userOpHash=428C6BBB83968E0C645B50ED1E947937CF6811C3F058732A59B96FECC813C783 ) => ( 0 )
      • Null: 0x000...001.428c6bbb( )
      • Null: 0x000...001.5f88a67a( )
      • ETH 0.000321279831341506 EntryPoint.CALL( )
      • EntryPoint.innerHandleOp( callData=0xE9AE5C53000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000078D0EC028A3D21533FDD200838F39C85B03679285D0000000000000000000000000000000000000000000000000000000000000000A9059CBB000000000000000000000000771697EB31EC46544177DF42C6DFFB80AA24AD9A000000000000000000000000000000000000000000000002A802F8630A2400000000000000000000, opInfo=[{name:mUserOp, type:tuple, order:1, indexed:false, value:[{name:sender, type:address, order:1, indexed:false, value:0xc1507C3b5AEc1A50e5d82A9656f283aB69F1Fa1b, valueString:0xc1507C3b5AEc1A50e5d82A9656f283aB69F1Fa1b}, {name:nonce, type:uint256, order:2, indexed:false, value:11208939894671191301950526257515835557638629901759676203802466203718394052608, valueString:11208939894671191301950526257515835557638629901759676203802466203718394052608}, {name:verificationGasLimit, type:uint256, order:3, indexed:false, value:106912, valueString:106912}, {name:callGasLimit, type:uint256, order:4, indexed:false, value:50180, valueString:50180}, {name:paymasterVerificationGasLimit, type:uint256, order:5, indexed:false, value:0, valueString:0}, {name:paymasterPostOpGasLimit, type:uint256, order:6, indexed:false, value:0, valueString:0}, {name:preVerificationGas, type:uint256, order:7, indexed:false, value:76325, valueString:76325}, {name:paymaster, type:address, order:8, indexed:false, value:0x0000000000000000000000000000000000000000, valueString:0x0000000000000000000000000000000000000000}, {name:maxFeePerGas, type:uint256, order:9, indexed:false, value:1376420018, valueString:1376420018}, {name:maxPriorityFeePerGas, type:uint256, order:10, indexed:false, value:52500000, valueString:52500000}], valueString:[{name:sender, type:address, order:1, indexed:false, value:0xc1507C3b5AEc1A50e5d82A9656f283aB69F1Fa1b, valueString:0xc1507C3b5AEc1A50e5d82A9656f283aB69F1Fa1b}, {name:nonce, type:uint256, order:2, indexed:false, value:11208939894671191301950526257515835557638629901759676203802466203718394052608, valueString:11208939894671191301950526257515835557638629901759676203802466203718394052608}, {name:verificationGasLimit, type:uint256, order:3, indexed:false, value:106912, valueString:106912}, {name:callGasLimit, type:uint256, order:4, indexed:false, value:50180, valueString:50180}, {name:paymasterVerificationGasLimit, type:uint256, order:5, indexed:false, value:0, valueString:0}, {name:paymasterPostOpGasLimit, type:uint256, order:6, indexed:false, value:0, valueString:0}, {name:preVerificationGas, type:uint256, order:7, indexed:false, value:76325, valueString:76325}, {name:paymaster, type:address, order:8, indexed:false, value:0x0000000000000000000000000000000000000000, valueString:0x0000000000000000000000000000000000000000}, {name:maxFeePerGas, type:uint256, order:9, indexed:false, value:1376420018, valueString:1376420018}, {name:maxPriorityFeePerGas, type:uint256, order:10, indexed:false, value:52500000, valueString:52500000}]}, {name:userOpHash, type:bytes32, order:2, indexed:false, value:428C6BBB83968E0C645B50ED1E947937CF6811C3F058732A59B96FECC813C783, valueString:428C6BBB83968E0C645B50ED1E947937CF6811C3F058732A59B96FECC813C783}, {name:prefund, type:uint256, order:3, indexed:false, value:321279831341506, valueString:321279831341506}, {name:contextOffset, type:uint256, order:4, indexed:false, value:96, valueString:96}, {name:preOpGas, type:uint256, order:5, indexed:false, value:156161, valueString:156161}], context=0x ) => ( actualGasCost=213783481621400 )
        • 0xc1507c3b5aec1a50e5d82a9656f283ab69f1fa1b.e9ae5c53( )
          • ERC1967Proxy.a9059cbb( )
            • CustomTokenFinal.transfer( to=0x771697EB31EC46544177df42C6DFfB80aA24aD9A, value=49000000000000000000 ) => ( True )
            • ETH 0.0002137834816214 Pimlico: ERC-4337 Bundler 4.CALL( )
              File 1 of 4: EntryPoint
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
              pragma solidity ^0.8.20;
              import {IERC165} from "./IERC165.sol";
              /**
               * @dev Implementation of the {IERC165} interface.
               *
               * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
               * for the additional interface id that will be supported. For example:
               *
               * ```solidity
               * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
               *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
               * }
               * ```
               */
              abstract contract ERC165 is IERC165 {
                  /**
                   * @dev See {IERC165-supportsInterface}.
                   */
                  function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
                      return interfaceId == type(IERC165).interfaceId;
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev Interface of the ERC165 standard, as defined in the
               * https://eips.ethereum.org/EIPS/eip-165[EIP].
               *
               * Implementers can declare support of contract interfaces, which can then be
               * queried by others ({ERC165Checker}).
               *
               * For an implementation, see {ERC165}.
               */
              interface IERC165 {
                  /**
                   * @dev Returns true if this contract implements the interface defined by
                   * `interfaceId`. See the corresponding
                   * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
                   * to learn more about how these ids are created.
                   *
                   * This function call must use less than 30 000 gas.
                   */
                  function supportsInterface(bytes4 interfaceId) external view returns (bool);
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev Contract module that helps prevent reentrant calls to a function.
               *
               * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
               * available, which can be applied to functions to make sure there are no nested
               * (reentrant) calls to them.
               *
               * Note that because there is a single `nonReentrant` guard, functions marked as
               * `nonReentrant` may not call one another. This can be worked around by making
               * those functions `private`, and then adding `external` `nonReentrant` entry
               * points to them.
               *
               * TIP: If you would like to learn more about reentrancy and alternative ways
               * to protect against it, check out our blog post
               * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
               */
              abstract contract ReentrancyGuard {
                  // Booleans are more expensive than uint256 or any type that takes up a full
                  // word because each write operation emits an extra SLOAD to first read the
                  // slot's contents, replace the bits taken up by the boolean, and then write
                  // back. This is the compiler's defense against contract upgrades and
                  // pointer aliasing, and it cannot be disabled.
                  // The values being non-zero value makes deployment a bit more expensive,
                  // but in exchange the refund on every call to nonReentrant will be lower in
                  // amount. Since refunds are capped to a percentage of the total
                  // transaction's gas, it is best to keep them low in cases like this one, to
                  // increase the likelihood of the full refund coming into effect.
                  uint256 private constant NOT_ENTERED = 1;
                  uint256 private constant ENTERED = 2;
                  uint256 private _status;
                  /**
                   * @dev Unauthorized reentrant call.
                   */
                  error ReentrancyGuardReentrantCall();
                  constructor() {
                      _status = NOT_ENTERED;
                  }
                  /**
                   * @dev Prevents a contract from calling itself, directly or indirectly.
                   * Calling a `nonReentrant` function from another `nonReentrant`
                   * function is not supported. It is possible to prevent this from happening
                   * by making the `nonReentrant` function external, and making it call a
                   * `private` function that does the actual work.
                   */
                  modifier nonReentrant() {
                      _nonReentrantBefore();
                      _;
                      _nonReentrantAfter();
                  }
                  function _nonReentrantBefore() private {
                      // On the first call to nonReentrant, _status will be NOT_ENTERED
                      if (_status == ENTERED) {
                          revert ReentrancyGuardReentrantCall();
                      }
                      // Any calls to nonReentrant after this point will fail
                      _status = ENTERED;
                  }
                  function _nonReentrantAfter() private {
                      // By storing the original value once again, a refund is triggered (see
                      // https://eips.ethereum.org/EIPS/eip-2200)
                      _status = NOT_ENTERED;
                  }
                  /**
                   * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
                   * `nonReentrant` function in the call stack.
                   */
                  function _reentrancyGuardEntered() internal view returns (bool) {
                      return _status == ENTERED;
                  }
              }
              // SPDX-License-Identifier: GPL-3.0
              pragma solidity ^0.8.23;
              /* solhint-disable avoid-low-level-calls */
              /* solhint-disable no-inline-assembly */
              import "../interfaces/IAccount.sol";
              import "../interfaces/IAccountExecute.sol";
              import "../interfaces/IPaymaster.sol";
              import "../interfaces/IEntryPoint.sol";
              import "../utils/Exec.sol";
              import "./StakeManager.sol";
              import "./SenderCreator.sol";
              import "./Helpers.sol";
              import "./NonceManager.sol";
              import "./UserOperationLib.sol";
              import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
              import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
              /*
               * Account-Abstraction (EIP-4337) singleton EntryPoint implementation.
               * Only one instance required on each chain.
               */
              /// @custom:security-contact https://bounty.ethereum.org
              contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard, ERC165 {
                  using UserOperationLib for PackedUserOperation;
                  SenderCreator private immutable _senderCreator = new SenderCreator();
                  function senderCreator() internal view virtual returns (SenderCreator) {
                      return _senderCreator;
                  }
                  //compensate for innerHandleOps' emit message and deposit refund.
                  // allow some slack for future gas price changes.
                  uint256 private constant INNER_GAS_OVERHEAD = 10000;
                  // Marker for inner call revert on out of gas
                  bytes32 private constant INNER_OUT_OF_GAS = hex"deaddead";
                  bytes32 private constant INNER_REVERT_LOW_PREFUND = hex"deadaa51";
                  uint256 private constant REVERT_REASON_MAX_LEN = 2048;
                  uint256 private constant PENALTY_PERCENT = 10;
                  /// @inheritdoc IERC165
                  function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                      // note: solidity "type(IEntryPoint).interfaceId" is without inherited methods but we want to check everything
                      return interfaceId == (type(IEntryPoint).interfaceId ^ type(IStakeManager).interfaceId ^ type(INonceManager).interfaceId) ||
                          interfaceId == type(IEntryPoint).interfaceId ||
                          interfaceId == type(IStakeManager).interfaceId ||
                          interfaceId == type(INonceManager).interfaceId ||
                          super.supportsInterface(interfaceId);
                  }
                  /**
                   * Compensate the caller's beneficiary address with the collected fees of all UserOperations.
                   * @param beneficiary - The address to receive the fees.
                   * @param amount      - Amount to transfer.
                   */
                  function _compensate(address payable beneficiary, uint256 amount) internal {
                      require(beneficiary != address(0), "AA90 invalid beneficiary");
                      (bool success, ) = beneficiary.call{value: amount}("");
                      require(success, "AA91 failed send to beneficiary");
                  }
                  /**
                   * Execute a user operation.
                   * @param opIndex    - Index into the opInfo array.
                   * @param userOp     - The userOp to execute.
                   * @param opInfo     - The opInfo filled by validatePrepayment for this userOp.
                   * @return collected - The total amount this userOp paid.
                   */
                  function _executeUserOp(
                      uint256 opIndex,
                      PackedUserOperation calldata userOp,
                      UserOpInfo memory opInfo
                  )
                  internal
                  returns
                  (uint256 collected) {
                      uint256 preGas = gasleft();
                      bytes memory context = getMemoryBytesFromOffset(opInfo.contextOffset);
                      bool success;
                      {
                          uint256 saveFreePtr;
                          assembly ("memory-safe") {
                              saveFreePtr := mload(0x40)
                          }
                          bytes calldata callData = userOp.callData;
                          bytes memory innerCall;
                          bytes4 methodSig;
                          assembly {
                              let len := callData.length
                              if gt(len, 3) {
                                  methodSig := calldataload(callData.offset)
                              }
                          }
                          if (methodSig == IAccountExecute.executeUserOp.selector) {
                              bytes memory executeUserOp = abi.encodeCall(IAccountExecute.executeUserOp, (userOp, opInfo.userOpHash));
                              innerCall = abi.encodeCall(this.innerHandleOp, (executeUserOp, opInfo, context));
                          } else
                          {
                              innerCall = abi.encodeCall(this.innerHandleOp, (callData, opInfo, context));
                          }
                          assembly ("memory-safe") {
                              success := call(gas(), address(), 0, add(innerCall, 0x20), mload(innerCall), 0, 32)
                              collected := mload(0)
                              mstore(0x40, saveFreePtr)
                          }
                      }
                      if (!success) {
                          bytes32 innerRevertCode;
                          assembly ("memory-safe") {
                              let len := returndatasize()
                              if eq(32,len) {
                                  returndatacopy(0, 0, 32)
                                  innerRevertCode := mload(0)
                              }
                          }
                          if (innerRevertCode == INNER_OUT_OF_GAS) {
                              // handleOps was called with gas limit too low. abort entire bundle.
                              //can only be caused by bundler (leaving not enough gas for inner call)
                              revert FailedOp(opIndex, "AA95 out of gas");
                          } else if (innerRevertCode == INNER_REVERT_LOW_PREFUND) {
                              // innerCall reverted on prefund too low. treat entire prefund as "gas cost"
                              uint256 actualGas = preGas - gasleft() + opInfo.preOpGas;
                              uint256 actualGasCost = opInfo.prefund;
                              emitPrefundTooLow(opInfo);
                              emitUserOperationEvent(opInfo, false, actualGasCost, actualGas);
                              collected = actualGasCost;
                          } else {
                              emit PostOpRevertReason(
                                  opInfo.userOpHash,
                                  opInfo.mUserOp.sender,
                                  opInfo.mUserOp.nonce,
                                  Exec.getReturnData(REVERT_REASON_MAX_LEN)
                              );
                              uint256 actualGas = preGas - gasleft() + opInfo.preOpGas;
                              collected = _postExecution(
                                  IPaymaster.PostOpMode.postOpReverted,
                                  opInfo,
                                  context,
                                  actualGas
                              );
                          }
                      }
                  }
                  function emitUserOperationEvent(UserOpInfo memory opInfo, bool success, uint256 actualGasCost, uint256 actualGas) internal virtual {
                      emit UserOperationEvent(
                          opInfo.userOpHash,
                          opInfo.mUserOp.sender,
                          opInfo.mUserOp.paymaster,
                          opInfo.mUserOp.nonce,
                          success,
                          actualGasCost,
                          actualGas
                      );
                  }
                  function emitPrefundTooLow(UserOpInfo memory opInfo) internal virtual {
                      emit UserOperationPrefundTooLow(
                          opInfo.userOpHash,
                          opInfo.mUserOp.sender,
                          opInfo.mUserOp.nonce
                      );
                  }
                  /// @inheritdoc IEntryPoint
                  function handleOps(
                      PackedUserOperation[] calldata ops,
                      address payable beneficiary
                  ) public nonReentrant {
                      uint256 opslen = ops.length;
                      UserOpInfo[] memory opInfos = new UserOpInfo[](opslen);
                      unchecked {
                          for (uint256 i = 0; i < opslen; i++) {
                              UserOpInfo memory opInfo = opInfos[i];
                              (
                                  uint256 validationData,
                                  uint256 pmValidationData
                              ) = _validatePrepayment(i, ops[i], opInfo);
                              _validateAccountAndPaymasterValidationData(
                                  i,
                                  validationData,
                                  pmValidationData,
                                  address(0)
                              );
                          }
                          uint256 collected = 0;
                          emit BeforeExecution();
                          for (uint256 i = 0; i < opslen; i++) {
                              collected += _executeUserOp(i, ops[i], opInfos[i]);
                          }
                          _compensate(beneficiary, collected);
                      }
                  }
                  /// @inheritdoc IEntryPoint
                  function handleAggregatedOps(
                      UserOpsPerAggregator[] calldata opsPerAggregator,
                      address payable beneficiary
                  ) public nonReentrant {
                      uint256 opasLen = opsPerAggregator.length;
                      uint256 totalOps = 0;
                      for (uint256 i = 0; i < opasLen; i++) {
                          UserOpsPerAggregator calldata opa = opsPerAggregator[i];
                          PackedUserOperation[] calldata ops = opa.userOps;
                          IAggregator aggregator = opa.aggregator;
                          //address(1) is special marker of "signature error"
                          require(
                              address(aggregator) != address(1),
                              "AA96 invalid aggregator"
                          );
                          if (address(aggregator) != address(0)) {
                              // solhint-disable-next-line no-empty-blocks
                              try aggregator.validateSignatures(ops, opa.signature) {} catch {
                                  revert SignatureValidationFailed(address(aggregator));
                              }
                          }
                          totalOps += ops.length;
                      }
                      UserOpInfo[] memory opInfos = new UserOpInfo[](totalOps);
                      uint256 opIndex = 0;
                      for (uint256 a = 0; a < opasLen; a++) {
                          UserOpsPerAggregator calldata opa = opsPerAggregator[a];
                          PackedUserOperation[] calldata ops = opa.userOps;
                          IAggregator aggregator = opa.aggregator;
                          uint256 opslen = ops.length;
                          for (uint256 i = 0; i < opslen; i++) {
                              UserOpInfo memory opInfo = opInfos[opIndex];
                              (
                                  uint256 validationData,
                                  uint256 paymasterValidationData
                              ) = _validatePrepayment(opIndex, ops[i], opInfo);
                              _validateAccountAndPaymasterValidationData(
                                  i,
                                  validationData,
                                  paymasterValidationData,
                                  address(aggregator)
                              );
                              opIndex++;
                          }
                      }
                      emit BeforeExecution();
                      uint256 collected = 0;
                      opIndex = 0;
                      for (uint256 a = 0; a < opasLen; a++) {
                          UserOpsPerAggregator calldata opa = opsPerAggregator[a];
                          emit SignatureAggregatorChanged(address(opa.aggregator));
                          PackedUserOperation[] calldata ops = opa.userOps;
                          uint256 opslen = ops.length;
                          for (uint256 i = 0; i < opslen; i++) {
                              collected += _executeUserOp(opIndex, ops[i], opInfos[opIndex]);
                              opIndex++;
                          }
                      }
                      emit SignatureAggregatorChanged(address(0));
                      _compensate(beneficiary, collected);
                  }
                  /**
                   * A memory copy of UserOp static fields only.
                   * Excluding: callData, initCode and signature. Replacing paymasterAndData with paymaster.
                   */
                  struct MemoryUserOp {
                      address sender;
                      uint256 nonce;
                      uint256 verificationGasLimit;
                      uint256 callGasLimit;
                      uint256 paymasterVerificationGasLimit;
                      uint256 paymasterPostOpGasLimit;
                      uint256 preVerificationGas;
                      address paymaster;
                      uint256 maxFeePerGas;
                      uint256 maxPriorityFeePerGas;
                  }
                  struct UserOpInfo {
                      MemoryUserOp mUserOp;
                      bytes32 userOpHash;
                      uint256 prefund;
                      uint256 contextOffset;
                      uint256 preOpGas;
                  }
                  /**
                   * Inner function to handle a UserOperation.
                   * Must be declared "external" to open a call context, but it can only be called by handleOps.
                   * @param callData - The callData to execute.
                   * @param opInfo   - The UserOpInfo struct.
                   * @param context  - The context bytes.
                   * @return actualGasCost - the actual cost in eth this UserOperation paid for gas
                   */
                  function innerHandleOp(
                      bytes memory callData,
                      UserOpInfo memory opInfo,
                      bytes calldata context
                  ) external returns (uint256 actualGasCost) {
                      uint256 preGas = gasleft();
                      require(msg.sender == address(this), "AA92 internal call only");
                      MemoryUserOp memory mUserOp = opInfo.mUserOp;
                      uint256 callGasLimit = mUserOp.callGasLimit;
                      unchecked {
                          // handleOps was called with gas limit too low. abort entire bundle.
                          if (
                              gasleft() * 63 / 64 <
                              callGasLimit +
                              mUserOp.paymasterPostOpGasLimit +
                              INNER_GAS_OVERHEAD
                          ) {
                              assembly ("memory-safe") {
                                  mstore(0, INNER_OUT_OF_GAS)
                                  revert(0, 32)
                              }
                          }
                      }
                      IPaymaster.PostOpMode mode = IPaymaster.PostOpMode.opSucceeded;
                      if (callData.length > 0) {
                          bool success = Exec.call(mUserOp.sender, 0, callData, callGasLimit);
                          if (!success) {
                              bytes memory result = Exec.getReturnData(REVERT_REASON_MAX_LEN);
                              if (result.length > 0) {
                                  emit UserOperationRevertReason(
                                      opInfo.userOpHash,
                                      mUserOp.sender,
                                      mUserOp.nonce,
                                      result
                                  );
                              }
                              mode = IPaymaster.PostOpMode.opReverted;
                          }
                      }
                      unchecked {
                          uint256 actualGas = preGas - gasleft() + opInfo.preOpGas;
                          return _postExecution(mode, opInfo, context, actualGas);
                      }
                  }
                  /// @inheritdoc IEntryPoint
                  function getUserOpHash(
                      PackedUserOperation calldata userOp
                  ) public view returns (bytes32) {
                      return
                          keccak256(abi.encode(userOp.hash(), address(this), block.chainid));
                  }
                  /**
                   * Copy general fields from userOp into the memory opInfo structure.
                   * @param userOp  - The user operation.
                   * @param mUserOp - The memory user operation.
                   */
                  function _copyUserOpToMemory(
                      PackedUserOperation calldata userOp,
                      MemoryUserOp memory mUserOp
                  ) internal pure {
                      mUserOp.sender = userOp.sender;
                      mUserOp.nonce = userOp.nonce;
                      (mUserOp.verificationGasLimit, mUserOp.callGasLimit) = UserOperationLib.unpackUints(userOp.accountGasLimits);
                      mUserOp.preVerificationGas = userOp.preVerificationGas;
                      (mUserOp.maxPriorityFeePerGas, mUserOp.maxFeePerGas) = UserOperationLib.unpackUints(userOp.gasFees);
                      bytes calldata paymasterAndData = userOp.paymasterAndData;
                      if (paymasterAndData.length > 0) {
                          require(
                              paymasterAndData.length >= UserOperationLib.PAYMASTER_DATA_OFFSET,
                              "AA93 invalid paymasterAndData"
                          );
                          (mUserOp.paymaster, mUserOp.paymasterVerificationGasLimit, mUserOp.paymasterPostOpGasLimit) = UserOperationLib.unpackPaymasterStaticFields(paymasterAndData);
                      } else {
                          mUserOp.paymaster = address(0);
                          mUserOp.paymasterVerificationGasLimit = 0;
                          mUserOp.paymasterPostOpGasLimit = 0;
                      }
                  }
                  /**
                   * Get the required prefunded gas fee amount for an operation.
                   * @param mUserOp - The user operation in memory.
                   */
                  function _getRequiredPrefund(
                      MemoryUserOp memory mUserOp
                  ) internal pure returns (uint256 requiredPrefund) {
                      unchecked {
                          uint256 requiredGas = mUserOp.verificationGasLimit +
                              mUserOp.callGasLimit +
                              mUserOp.paymasterVerificationGasLimit +
                              mUserOp.paymasterPostOpGasLimit +
                              mUserOp.preVerificationGas;
                          requiredPrefund = requiredGas * mUserOp.maxFeePerGas;
                      }
                  }
                  /**
                   * Create sender smart contract account if init code is provided.
                   * @param opIndex  - The operation index.
                   * @param opInfo   - The operation info.
                   * @param initCode - The init code for the smart contract account.
                   */
                  function _createSenderIfNeeded(
                      uint256 opIndex,
                      UserOpInfo memory opInfo,
                      bytes calldata initCode
                  ) internal {
                      if (initCode.length != 0) {
                          address sender = opInfo.mUserOp.sender;
                          if (sender.code.length != 0)
                              revert FailedOp(opIndex, "AA10 sender already constructed");
                          address sender1 = senderCreator().createSender{
                              gas: opInfo.mUserOp.verificationGasLimit
                          }(initCode);
                          if (sender1 == address(0))
                              revert FailedOp(opIndex, "AA13 initCode failed or OOG");
                          if (sender1 != sender)
                              revert FailedOp(opIndex, "AA14 initCode must return sender");
                          if (sender1.code.length == 0)
                              revert FailedOp(opIndex, "AA15 initCode must create sender");
                          address factory = address(bytes20(initCode[0:20]));
                          emit AccountDeployed(
                              opInfo.userOpHash,
                              sender,
                              factory,
                              opInfo.mUserOp.paymaster
                          );
                      }
                  }
                  /// @inheritdoc IEntryPoint
                  function getSenderAddress(bytes calldata initCode) public {
                      address sender = senderCreator().createSender(initCode);
                      revert SenderAddressResult(sender);
                  }
                  /**
                   * Call account.validateUserOp.
                   * Revert (with FailedOp) in case validateUserOp reverts, or account didn't send required prefund.
                   * Decrement account's deposit if needed.
                   * @param opIndex         - The operation index.
                   * @param op              - The user operation.
                   * @param opInfo          - The operation info.
                   * @param requiredPrefund - The required prefund amount.
                   */
                  function _validateAccountPrepayment(
                      uint256 opIndex,
                      PackedUserOperation calldata op,
                      UserOpInfo memory opInfo,
                      uint256 requiredPrefund,
                      uint256 verificationGasLimit
                  )
                      internal
                      returns (
                          uint256 validationData
                      )
                  {
                      unchecked {
                          MemoryUserOp memory mUserOp = opInfo.mUserOp;
                          address sender = mUserOp.sender;
                          _createSenderIfNeeded(opIndex, opInfo, op.initCode);
                          address paymaster = mUserOp.paymaster;
                          uint256 missingAccountFunds = 0;
                          if (paymaster == address(0)) {
                              uint256 bal = balanceOf(sender);
                              missingAccountFunds = bal > requiredPrefund
                                  ? 0
                                  : requiredPrefund - bal;
                          }
                          try
                              IAccount(sender).validateUserOp{
                                  gas: verificationGasLimit
                              }(op, opInfo.userOpHash, missingAccountFunds)
                          returns (uint256 _validationData) {
                              validationData = _validationData;
                          } catch {
                              revert FailedOpWithRevert(opIndex, "AA23 reverted", Exec.getReturnData(REVERT_REASON_MAX_LEN));
                          }
                          if (paymaster == address(0)) {
                              DepositInfo storage senderInfo = deposits[sender];
                              uint256 deposit = senderInfo.deposit;
                              if (requiredPrefund > deposit) {
                                  revert FailedOp(opIndex, "AA21 didn't pay prefund");
                              }
                              senderInfo.deposit = deposit - requiredPrefund;
                          }
                      }
                  }
                  /**
                   * In case the request has a paymaster:
                   *  - Validate paymaster has enough deposit.
                   *  - Call paymaster.validatePaymasterUserOp.
                   *  - Revert with proper FailedOp in case paymaster reverts.
                   *  - Decrement paymaster's deposit.
                   * @param opIndex                            - The operation index.
                   * @param op                                 - The user operation.
                   * @param opInfo                             - The operation info.
                   * @param requiredPreFund                    - The required prefund amount.
                   */
                  function _validatePaymasterPrepayment(
                      uint256 opIndex,
                      PackedUserOperation calldata op,
                      UserOpInfo memory opInfo,
                      uint256 requiredPreFund
                  ) internal returns (bytes memory context, uint256 validationData) {
                      unchecked {
                          uint256 preGas = gasleft();
                          MemoryUserOp memory mUserOp = opInfo.mUserOp;
                          address paymaster = mUserOp.paymaster;
                          DepositInfo storage paymasterInfo = deposits[paymaster];
                          uint256 deposit = paymasterInfo.deposit;
                          if (deposit < requiredPreFund) {
                              revert FailedOp(opIndex, "AA31 paymaster deposit too low");
                          }
                          paymasterInfo.deposit = deposit - requiredPreFund;
                          uint256 pmVerificationGasLimit = mUserOp.paymasterVerificationGasLimit;
                          try
                              IPaymaster(paymaster).validatePaymasterUserOp{gas: pmVerificationGasLimit}(
                                  op,
                                  opInfo.userOpHash,
                                  requiredPreFund
                              )
                          returns (bytes memory _context, uint256 _validationData) {
                              context = _context;
                              validationData = _validationData;
                          } catch {
                              revert FailedOpWithRevert(opIndex, "AA33 reverted", Exec.getReturnData(REVERT_REASON_MAX_LEN));
                          }
                          if (preGas - gasleft() > pmVerificationGasLimit) {
                              revert FailedOp(opIndex, "AA36 over paymasterVerificationGasLimit");
                          }
                      }
                  }
                  /**
                   * Revert if either account validationData or paymaster validationData is expired.
                   * @param opIndex                 - The operation index.
                   * @param validationData          - The account validationData.
                   * @param paymasterValidationData - The paymaster validationData.
                   * @param expectedAggregator      - The expected aggregator.
                   */
                  function _validateAccountAndPaymasterValidationData(
                      uint256 opIndex,
                      uint256 validationData,
                      uint256 paymasterValidationData,
                      address expectedAggregator
                  ) internal view {
                      (address aggregator, bool outOfTimeRange) = _getValidationData(
                          validationData
                      );
                      if (expectedAggregator != aggregator) {
                          revert FailedOp(opIndex, "AA24 signature error");
                      }
                      if (outOfTimeRange) {
                          revert FailedOp(opIndex, "AA22 expired or not due");
                      }
                      // pmAggregator is not a real signature aggregator: we don't have logic to handle it as address.
                      // Non-zero address means that the paymaster fails due to some signature check (which is ok only during estimation).
                      address pmAggregator;
                      (pmAggregator, outOfTimeRange) = _getValidationData(
                          paymasterValidationData
                      );
                      if (pmAggregator != address(0)) {
                          revert FailedOp(opIndex, "AA34 signature error");
                      }
                      if (outOfTimeRange) {
                          revert FailedOp(opIndex, "AA32 paymaster expired or not due");
                      }
                  }
                  /**
                   * Parse validationData into its components.
                   * @param validationData - The packed validation data (sigFailed, validAfter, validUntil).
                   * @return aggregator the aggregator of the validationData
                   * @return outOfTimeRange true if current time is outside the time range of this validationData.
                   */
                  function _getValidationData(
                      uint256 validationData
                  ) internal view returns (address aggregator, bool outOfTimeRange) {
                      if (validationData == 0) {
                          return (address(0), false);
                      }
                      ValidationData memory data = _parseValidationData(validationData);
                      // solhint-disable-next-line not-rely-on-time
                      outOfTimeRange = block.timestamp > data.validUntil || block.timestamp < data.validAfter;
                      aggregator = data.aggregator;
                  }
                  /**
                   * Validate account and paymaster (if defined) and
                   * also make sure total validation doesn't exceed verificationGasLimit.
                   * This method is called off-chain (simulateValidation()) and on-chain (from handleOps)
                   * @param opIndex - The index of this userOp into the "opInfos" array.
                   * @param userOp  - The userOp to validate.
                   */
                  function _validatePrepayment(
                      uint256 opIndex,
                      PackedUserOperation calldata userOp,
                      UserOpInfo memory outOpInfo
                  )
                      internal
                      returns (uint256 validationData, uint256 paymasterValidationData)
                  {
                      uint256 preGas = gasleft();
                      MemoryUserOp memory mUserOp = outOpInfo.mUserOp;
                      _copyUserOpToMemory(userOp, mUserOp);
                      outOpInfo.userOpHash = getUserOpHash(userOp);
                      // Validate all numeric values in userOp are well below 128 bit, so they can safely be added
                      // and multiplied without causing overflow.
                      uint256 verificationGasLimit = mUserOp.verificationGasLimit;
                      uint256 maxGasValues = mUserOp.preVerificationGas |
                          verificationGasLimit |
                          mUserOp.callGasLimit |
                          mUserOp.paymasterVerificationGasLimit |
                          mUserOp.paymasterPostOpGasLimit |
                          mUserOp.maxFeePerGas |
                          mUserOp.maxPriorityFeePerGas;
                      require(maxGasValues <= type(uint120).max, "AA94 gas values overflow");
                      uint256 requiredPreFund = _getRequiredPrefund(mUserOp);
                      validationData = _validateAccountPrepayment(
                          opIndex,
                          userOp,
                          outOpInfo,
                          requiredPreFund,
                          verificationGasLimit
                      );
                      if (!_validateAndUpdateNonce(mUserOp.sender, mUserOp.nonce)) {
                          revert FailedOp(opIndex, "AA25 invalid account nonce");
                      }
                      unchecked {
                          if (preGas - gasleft() > verificationGasLimit) {
                              revert FailedOp(opIndex, "AA26 over verificationGasLimit");
                          }
                      }
                      bytes memory context;
                      if (mUserOp.paymaster != address(0)) {
                          (context, paymasterValidationData) = _validatePaymasterPrepayment(
                              opIndex,
                              userOp,
                              outOpInfo,
                              requiredPreFund
                          );
                      }
                      unchecked {
                          outOpInfo.prefund = requiredPreFund;
                          outOpInfo.contextOffset = getOffsetOfMemoryBytes(context);
                          outOpInfo.preOpGas = preGas - gasleft() + userOp.preVerificationGas;
                      }
                  }
                  /**
                   * Process post-operation, called just after the callData is executed.
                   * If a paymaster is defined and its validation returned a non-empty context, its postOp is called.
                   * The excess amount is refunded to the account (or paymaster - if it was used in the request).
                   * @param mode      - Whether is called from innerHandleOp, or outside (postOpReverted).
                   * @param opInfo    - UserOp fields and info collected during validation.
                   * @param context   - The context returned in validatePaymasterUserOp.
                   * @param actualGas - The gas used so far by this user operation.
                   */
                  function _postExecution(
                      IPaymaster.PostOpMode mode,
                      UserOpInfo memory opInfo,
                      bytes memory context,
                      uint256 actualGas
                  ) private returns (uint256 actualGasCost) {
                      uint256 preGas = gasleft();
                      unchecked {
                          address refundAddress;
                          MemoryUserOp memory mUserOp = opInfo.mUserOp;
                          uint256 gasPrice = getUserOpGasPrice(mUserOp);
                          address paymaster = mUserOp.paymaster;
                          if (paymaster == address(0)) {
                              refundAddress = mUserOp.sender;
                          } else {
                              refundAddress = paymaster;
                              if (context.length > 0) {
                                  actualGasCost = actualGas * gasPrice;
                                  if (mode != IPaymaster.PostOpMode.postOpReverted) {
                                      try IPaymaster(paymaster).postOp{
                                          gas: mUserOp.paymasterPostOpGasLimit
                                      }(mode, context, actualGasCost, gasPrice)
                                      // solhint-disable-next-line no-empty-blocks
                                      {} catch {
                                          bytes memory reason = Exec.getReturnData(REVERT_REASON_MAX_LEN);
                                          revert PostOpReverted(reason);
                                      }
                                  }
                              }
                          }
                          actualGas += preGas - gasleft();
                          // Calculating a penalty for unused execution gas
                          {
                              uint256 executionGasLimit = mUserOp.callGasLimit + mUserOp.paymasterPostOpGasLimit;
                              uint256 executionGasUsed = actualGas - opInfo.preOpGas;
                              // this check is required for the gas used within EntryPoint and not covered by explicit gas limits
                              if (executionGasLimit > executionGasUsed) {
                                  uint256 unusedGas = executionGasLimit - executionGasUsed;
                                  uint256 unusedGasPenalty = (unusedGas * PENALTY_PERCENT) / 100;
                                  actualGas += unusedGasPenalty;
                              }
                          }
                          actualGasCost = actualGas * gasPrice;
                          uint256 prefund = opInfo.prefund;
                          if (prefund < actualGasCost) {
                              if (mode == IPaymaster.PostOpMode.postOpReverted) {
                                  actualGasCost = prefund;
                                  emitPrefundTooLow(opInfo);
                                  emitUserOperationEvent(opInfo, false, actualGasCost, actualGas);
                              } else {
                                  assembly ("memory-safe") {
                                      mstore(0, INNER_REVERT_LOW_PREFUND)
                                      revert(0, 32)
                                  }
                              }
                          } else {
                              uint256 refund = prefund - actualGasCost;
                              _incrementDeposit(refundAddress, refund);
                              bool success = mode == IPaymaster.PostOpMode.opSucceeded;
                              emitUserOperationEvent(opInfo, success, actualGasCost, actualGas);
                          }
                      } // unchecked
                  }
                  /**
                   * The gas price this UserOp agrees to pay.
                   * Relayer/block builder might submit the TX with higher priorityFee, but the user should not.
                   * @param mUserOp - The userOp to get the gas price from.
                   */
                  function getUserOpGasPrice(
                      MemoryUserOp memory mUserOp
                  ) internal view returns (uint256) {
                      unchecked {
                          uint256 maxFeePerGas = mUserOp.maxFeePerGas;
                          uint256 maxPriorityFeePerGas = mUserOp.maxPriorityFeePerGas;
                          if (maxFeePerGas == maxPriorityFeePerGas) {
                              //legacy mode (for networks that don't support basefee opcode)
                              return maxFeePerGas;
                          }
                          return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee);
                      }
                  }
                  /**
                   * The offset of the given bytes in memory.
                   * @param data - The bytes to get the offset of.
                   */
                  function getOffsetOfMemoryBytes(
                      bytes memory data
                  ) internal pure returns (uint256 offset) {
                      assembly {
                          offset := data
                      }
                  }
                  /**
                   * The bytes in memory at the given offset.
                   * @param offset - The offset to get the bytes from.
                   */
                  function getMemoryBytesFromOffset(
                      uint256 offset
                  ) internal pure returns (bytes memory data) {
                      assembly ("memory-safe") {
                          data := offset
                      }
                  }
                  /// @inheritdoc IEntryPoint
                  function delegateAndRevert(address target, bytes calldata data) external {
                      (bool success, bytes memory ret) = target.delegatecall(data);
                      revert DelegateAndRevert(success, ret);
                  }
              }
              // SPDX-License-Identifier: GPL-3.0
              pragma solidity ^0.8.23;
              /* solhint-disable no-inline-assembly */
               /*
                * For simulation purposes, validateUserOp (and validatePaymasterUserOp)
                * must return this value in case of signature failure, instead of revert.
                */
              uint256 constant SIG_VALIDATION_FAILED = 1;
              /*
               * For simulation purposes, validateUserOp (and validatePaymasterUserOp)
               * return this value on success.
               */
              uint256 constant SIG_VALIDATION_SUCCESS = 0;
              /**
               * Returned data from validateUserOp.
               * validateUserOp returns a uint256, which is created by `_packedValidationData` and
               * parsed by `_parseValidationData`.
               * @param aggregator  - address(0) - The account validated the signature by itself.
               *                      address(1) - The account failed to validate the signature.
               *                      otherwise - This is an address of a signature aggregator that must
               *                                  be used to validate the signature.
               * @param validAfter  - This UserOp is valid only after this timestamp.
               * @param validaUntil - This UserOp is valid only up to this timestamp.
               */
              struct ValidationData {
                  address aggregator;
                  uint48 validAfter;
                  uint48 validUntil;
              }
              /**
               * Extract sigFailed, validAfter, validUntil.
               * Also convert zero validUntil to type(uint48).max.
               * @param validationData - The packed validation data.
               */
              function _parseValidationData(
                  uint256 validationData
              ) pure returns (ValidationData memory data) {
                  address aggregator = address(uint160(validationData));
                  uint48 validUntil = uint48(validationData >> 160);
                  if (validUntil == 0) {
                      validUntil = type(uint48).max;
                  }
                  uint48 validAfter = uint48(validationData >> (48 + 160));
                  return ValidationData(aggregator, validAfter, validUntil);
              }
              /**
               * Helper to pack the return value for validateUserOp.
               * @param data - The ValidationData to pack.
               */
              function _packValidationData(
                  ValidationData memory data
              ) pure returns (uint256) {
                  return
                      uint160(data.aggregator) |
                      (uint256(data.validUntil) << 160) |
                      (uint256(data.validAfter) << (160 + 48));
              }
              /**
               * Helper to pack the return value for validateUserOp, when not using an aggregator.
               * @param sigFailed  - True for signature failure, false for success.
               * @param validUntil - Last timestamp this UserOperation is valid (or zero for infinite).
               * @param validAfter - First timestamp this UserOperation is valid.
               */
              function _packValidationData(
                  bool sigFailed,
                  uint48 validUntil,
                  uint48 validAfter
              ) pure returns (uint256) {
                  return
                      (sigFailed ? 1 : 0) |
                      (uint256(validUntil) << 160) |
                      (uint256(validAfter) << (160 + 48));
              }
              /**
               * keccak function over calldata.
               * @dev copy calldata into memory, do keccak and drop allocated memory. Strangely, this is more efficient than letting solidity do it.
               */
                  function calldataKeccak(bytes calldata data) pure returns (bytes32 ret) {
                      assembly ("memory-safe") {
                          let mem := mload(0x40)
                          let len := data.length
                          calldatacopy(mem, data.offset, len)
                          ret := keccak256(mem, len)
                      }
                  }
              /**
               * The minimum of two numbers.
               * @param a - First number.
               * @param b - Second number.
               */
                  function min(uint256 a, uint256 b) pure returns (uint256) {
                      return a < b ? a : b;
                  }
              // SPDX-License-Identifier: GPL-3.0
              pragma solidity ^0.8.23;
              import "../interfaces/INonceManager.sol";
              /**
               * nonce management functionality
               */
              abstract contract NonceManager is INonceManager {
                  /**
                   * The next valid sequence number for a given nonce key.
                   */
                  mapping(address => mapping(uint192 => uint256)) public nonceSequenceNumber;
                  /// @inheritdoc INonceManager
                  function getNonce(address sender, uint192 key)
                  public view override returns (uint256 nonce) {
                      return nonceSequenceNumber[sender][key] | (uint256(key) << 64);
                  }
                  // allow an account to manually increment its own nonce.
                  // (mainly so that during construction nonce can be made non-zero,
                  // to "absorb" the gas cost of first nonce increment to 1st transaction (construction),
                  // not to 2nd transaction)
                  function incrementNonce(uint192 key) public override {
                      nonceSequenceNumber[msg.sender][key]++;
                  }
                  /**
                   * validate nonce uniqueness for this account.
                   * called just after validateUserOp()
                   * @return true if the nonce was incremented successfully.
                   *         false if the current nonce doesn't match the given one.
                   */
                  function _validateAndUpdateNonce(address sender, uint256 nonce) internal returns (bool) {
                      uint192 key = uint192(nonce >> 64);
                      uint64 seq = uint64(nonce);
                      return nonceSequenceNumber[sender][key]++ == seq;
                  }
              }
              // SPDX-License-Identifier: GPL-3.0
              pragma solidity ^0.8.23;
              /**
               * Helper contract for EntryPoint, to call userOp.initCode from a "neutral" address,
               * which is explicitly not the entryPoint itself.
               */
              contract SenderCreator {
                  /**
                   * Call the "initCode" factory to create and return the sender account address.
                   * @param initCode - The initCode value from a UserOp. contains 20 bytes of factory address,
                   *                   followed by calldata.
                   * @return sender  - The returned address of the created account, or zero address on failure.
                   */
                  function createSender(
                      bytes calldata initCode
                  ) external returns (address sender) {
                      address factory = address(bytes20(initCode[0:20]));
                      bytes memory initCallData = initCode[20:];
                      bool success;
                      /* solhint-disable no-inline-assembly */
                      assembly ("memory-safe") {
                          success := call(
                              gas(),
                              factory,
                              0,
                              add(initCallData, 0x20),
                              mload(initCallData),
                              0,
                              32
                          )
                          sender := mload(0)
                      }
                      if (!success) {
                          sender = address(0);
                      }
                  }
              }
              // SPDX-License-Identifier: GPL-3.0-only
              pragma solidity ^0.8.23;
              import "../interfaces/IStakeManager.sol";
              /* solhint-disable avoid-low-level-calls */
              /* solhint-disable not-rely-on-time */
              /**
               * Manage deposits and stakes.
               * Deposit is just a balance used to pay for UserOperations (either by a paymaster or an account).
               * Stake is value locked for at least "unstakeDelay" by a paymaster.
               */
              abstract contract StakeManager is IStakeManager {
                  /// maps paymaster to their deposits and stakes
                  mapping(address => DepositInfo) public deposits;
                  /// @inheritdoc IStakeManager
                  function getDepositInfo(
                      address account
                  ) public view returns (DepositInfo memory info) {
                      return deposits[account];
                  }
                  /**
                   * Internal method to return just the stake info.
                   * @param addr - The account to query.
                   */
                  function _getStakeInfo(
                      address addr
                  ) internal view returns (StakeInfo memory info) {
                      DepositInfo storage depositInfo = deposits[addr];
                      info.stake = depositInfo.stake;
                      info.unstakeDelaySec = depositInfo.unstakeDelaySec;
                  }
                  /// @inheritdoc IStakeManager
                  function balanceOf(address account) public view returns (uint256) {
                      return deposits[account].deposit;
                  }
                  receive() external payable {
                      depositTo(msg.sender);
                  }
                  /**
                   * Increments an account's deposit.
                   * @param account - The account to increment.
                   * @param amount  - The amount to increment by.
                   * @return the updated deposit of this account
                   */
                  function _incrementDeposit(address account, uint256 amount) internal returns (uint256) {
                      DepositInfo storage info = deposits[account];
                      uint256 newAmount = info.deposit + amount;
                      info.deposit = newAmount;
                      return newAmount;
                  }
                  /**
                   * Add to the deposit of the given account.
                   * @param account - The account to add to.
                   */
                  function depositTo(address account) public virtual payable {
                      uint256 newDeposit = _incrementDeposit(account, msg.value);
                      emit Deposited(account, newDeposit);
                  }
                  /**
                   * Add to the account's stake - amount and delay
                   * any pending unstake is first cancelled.
                   * @param unstakeDelaySec The new lock duration before the deposit can be withdrawn.
                   */
                  function addStake(uint32 unstakeDelaySec) public payable {
                      DepositInfo storage info = deposits[msg.sender];
                      require(unstakeDelaySec > 0, "must specify unstake delay");
                      require(
                          unstakeDelaySec >= info.unstakeDelaySec,
                          "cannot decrease unstake time"
                      );
                      uint256 stake = info.stake + msg.value;
                      require(stake > 0, "no stake specified");
                      require(stake <= type(uint112).max, "stake overflow");
                      deposits[msg.sender] = DepositInfo(
                          info.deposit,
                          true,
                          uint112(stake),
                          unstakeDelaySec,
                          0
                      );
                      emit StakeLocked(msg.sender, stake, unstakeDelaySec);
                  }
                  /**
                   * Attempt to unlock the stake.
                   * The value can be withdrawn (using withdrawStake) after the unstake delay.
                   */
                  function unlockStake() external {
                      DepositInfo storage info = deposits[msg.sender];
                      require(info.unstakeDelaySec != 0, "not staked");
                      require(info.staked, "already unstaking");
                      uint48 withdrawTime = uint48(block.timestamp) + info.unstakeDelaySec;
                      info.withdrawTime = withdrawTime;
                      info.staked = false;
                      emit StakeUnlocked(msg.sender, withdrawTime);
                  }
                  /**
                   * Withdraw from the (unlocked) stake.
                   * Must first call unlockStake and wait for the unstakeDelay to pass.
                   * @param withdrawAddress - The address to send withdrawn value.
                   */
                  function withdrawStake(address payable withdrawAddress) external {
                      DepositInfo storage info = deposits[msg.sender];
                      uint256 stake = info.stake;
                      require(stake > 0, "No stake to withdraw");
                      require(info.withdrawTime > 0, "must call unlockStake() first");
                      require(
                          info.withdrawTime <= block.timestamp,
                          "Stake withdrawal is not due"
                      );
                      info.unstakeDelaySec = 0;
                      info.withdrawTime = 0;
                      info.stake = 0;
                      emit StakeWithdrawn(msg.sender, withdrawAddress, stake);
                      (bool success,) = withdrawAddress.call{value: stake}("");
                      require(success, "failed to withdraw stake");
                  }
                  /**
                   * Withdraw from the deposit.
                   * @param withdrawAddress - The address to send withdrawn value.
                   * @param withdrawAmount  - The amount to withdraw.
                   */
                  function withdrawTo(
                      address payable withdrawAddress,
                      uint256 withdrawAmount
                  ) external {
                      DepositInfo storage info = deposits[msg.sender];
                      require(withdrawAmount <= info.deposit, "Withdraw amount too large");
                      info.deposit = info.deposit - withdrawAmount;
                      emit Withdrawn(msg.sender, withdrawAddress, withdrawAmount);
                      (bool success,) = withdrawAddress.call{value: withdrawAmount}("");
                      require(success, "failed to withdraw");
                  }
              }
              // SPDX-License-Identifier: GPL-3.0
              pragma solidity ^0.8.23;
              /* solhint-disable no-inline-assembly */
              import "../interfaces/PackedUserOperation.sol";
              import {calldataKeccak, min} from "./Helpers.sol";
              /**
               * Utility functions helpful when working with UserOperation structs.
               */
              library UserOperationLib {
                  uint256 public constant PAYMASTER_VALIDATION_GAS_OFFSET = 20;
                  uint256 public constant PAYMASTER_POSTOP_GAS_OFFSET = 36;
                  uint256 public constant PAYMASTER_DATA_OFFSET = 52;
                  /**
                   * Get sender from user operation data.
                   * @param userOp - The user operation data.
                   */
                  function getSender(
                      PackedUserOperation calldata userOp
                  ) internal pure returns (address) {
                      address data;
                      //read sender from userOp, which is first userOp member (saves 800 gas...)
                      assembly {
                          data := calldataload(userOp)
                      }
                      return address(uint160(data));
                  }
                  /**
                   * Relayer/block builder might submit the TX with higher priorityFee,
                   * but the user should not pay above what he signed for.
                   * @param userOp - The user operation data.
                   */
                  function gasPrice(
                      PackedUserOperation calldata userOp
                  ) internal view returns (uint256) {
                      unchecked {
                          (uint256 maxPriorityFeePerGas, uint256 maxFeePerGas) = unpackUints(userOp.gasFees);
                          if (maxFeePerGas == maxPriorityFeePerGas) {
                              //legacy mode (for networks that don't support basefee opcode)
                              return maxFeePerGas;
                          }
                          return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee);
                      }
                  }
                  /**
                   * Pack the user operation data into bytes for hashing.
                   * @param userOp - The user operation data.
                   */
                  function encode(
                      PackedUserOperation calldata userOp
                  ) internal pure returns (bytes memory ret) {
                      address sender = getSender(userOp);
                      uint256 nonce = userOp.nonce;
                      bytes32 hashInitCode = calldataKeccak(userOp.initCode);
                      bytes32 hashCallData = calldataKeccak(userOp.callData);
                      bytes32 accountGasLimits = userOp.accountGasLimits;
                      uint256 preVerificationGas = userOp.preVerificationGas;
                      bytes32 gasFees = userOp.gasFees;
                      bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData);
                      return abi.encode(
                          sender, nonce,
                          hashInitCode, hashCallData,
                          accountGasLimits, preVerificationGas, gasFees,
                          hashPaymasterAndData
                      );
                  }
                  function unpackUints(
                      bytes32 packed
                  ) internal pure returns (uint256 high128, uint256 low128) {
                      return (uint128(bytes16(packed)), uint128(uint256(packed)));
                  }
                  //unpack just the high 128-bits from a packed value
                  function unpackHigh128(bytes32 packed) internal pure returns (uint256) {
                      return uint256(packed) >> 128;
                  }
                  // unpack just the low 128-bits from a packed value
                  function unpackLow128(bytes32 packed) internal pure returns (uint256) {
                      return uint128(uint256(packed));
                  }
                  function unpackMaxPriorityFeePerGas(PackedUserOperation calldata userOp)
                  internal pure returns (uint256) {
                      return unpackHigh128(userOp.gasFees);
                  }
                  function unpackMaxFeePerGas(PackedUserOperation calldata userOp)
                  internal pure returns (uint256) {
                      return unpackLow128(userOp.gasFees);
                  }
                  function unpackVerificationGasLimit(PackedUserOperation calldata userOp)
                  internal pure returns (uint256) {
                      return unpackHigh128(userOp.accountGasLimits);
                  }
                  function unpackCallGasLimit(PackedUserOperation calldata userOp)
                  internal pure returns (uint256) {
                      return unpackLow128(userOp.accountGasLimits);
                  }
                  function unpackPaymasterVerificationGasLimit(PackedUserOperation calldata userOp)
                  internal pure returns (uint256) {
                      return uint128(bytes16(userOp.paymasterAndData[PAYMASTER_VALIDATION_GAS_OFFSET : PAYMASTER_POSTOP_GAS_OFFSET]));
                  }
                  function unpackPostOpGasLimit(PackedUserOperation calldata userOp)
                  internal pure returns (uint256) {
                      return uint128(bytes16(userOp.paymasterAndData[PAYMASTER_POSTOP_GAS_OFFSET : PAYMASTER_DATA_OFFSET]));
                  }
                  function unpackPaymasterStaticFields(
                      bytes calldata paymasterAndData
                  ) internal pure returns (address paymaster, uint256 validationGasLimit, uint256 postOpGasLimit) {
                      return (
                          address(bytes20(paymasterAndData[: PAYMASTER_VALIDATION_GAS_OFFSET])),
                          uint128(bytes16(paymasterAndData[PAYMASTER_VALIDATION_GAS_OFFSET : PAYMASTER_POSTOP_GAS_OFFSET])),
                          uint128(bytes16(paymasterAndData[PAYMASTER_POSTOP_GAS_OFFSET : PAYMASTER_DATA_OFFSET]))
                      );
                  }
                  /**
                   * Hash the user operation data.
                   * @param userOp - The user operation data.
                   */
                  function hash(
                      PackedUserOperation calldata userOp
                  ) internal pure returns (bytes32) {
                      return keccak256(encode(userOp));
                  }
              }
              // SPDX-License-Identifier: GPL-3.0
              pragma solidity >=0.7.5;
              import "./PackedUserOperation.sol";
              interface IAccount {
                  /**
                   * Validate user's signature and nonce
                   * the entryPoint will make the call to the recipient only if this validation call returns successfully.
                   * signature failure should be reported by returning SIG_VALIDATION_FAILED (1).
                   * This allows making a "simulation call" without a valid signature
                   * Other failures (e.g. nonce mismatch, or invalid signature format) should still revert to signal failure.
                   *
                   * @dev Must validate caller is the entryPoint.
                   *      Must validate the signature and nonce
                   * @param userOp              - The operation that is about to be executed.
                   * @param userOpHash          - Hash of the user's request data. can be used as the basis for signature.
                   * @param missingAccountFunds - Missing funds on the account's deposit in the entrypoint.
                   *                              This is the minimum amount to transfer to the sender(entryPoint) to be
                   *                              able to make the call. The excess is left as a deposit in the entrypoint
                   *                              for future calls. Can be withdrawn anytime using "entryPoint.withdrawTo()".
                   *                              In case there is a paymaster in the request (or the current deposit is high
                   *                              enough), this value will be zero.
                   * @return validationData       - Packaged ValidationData structure. use `_packValidationData` and
                   *                              `_unpackValidationData` to encode and decode.
                   *                              <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure,
                   *                                 otherwise, an address of an "authorizer" contract.
                   *                              <6-byte> validUntil - Last timestamp this operation is valid. 0 for "indefinite"
                   *                              <6-byte> validAfter - First timestamp this operation is valid
                   *                                                    If an account doesn't use time-range, it is enough to
                   *                                                    return SIG_VALIDATION_FAILED value (1) for signature failure.
                   *                              Note that the validation code cannot use block.timestamp (or block.number) directly.
                   */
                  function validateUserOp(
                      PackedUserOperation calldata userOp,
                      bytes32 userOpHash,
                      uint256 missingAccountFunds
                  ) external returns (uint256 validationData);
              }
              // SPDX-License-Identifier: GPL-3.0
              pragma solidity >=0.7.5;
              import "./PackedUserOperation.sol";
              interface IAccountExecute {
                  /**
                   * Account may implement this execute method.
                   * passing this methodSig at the beginning of callData will cause the entryPoint to pass the full UserOp (and hash)
                   * to the account.
                   * The account should skip the methodSig, and use the callData (and optionally, other UserOp fields)
                   *
                   * @param userOp              - The operation that was just validated.
                   * @param userOpHash          - Hash of the user's request data.
                   */
                  function executeUserOp(
                      PackedUserOperation calldata userOp,
                      bytes32 userOpHash
                  ) external;
              }
              // SPDX-License-Identifier: GPL-3.0
              pragma solidity >=0.7.5;
              import "./PackedUserOperation.sol";
              /**
               * Aggregated Signatures validator.
               */
              interface IAggregator {
                  /**
                   * Validate aggregated signature.
                   * Revert if the aggregated signature does not match the given list of operations.
                   * @param userOps   - Array of UserOperations to validate the signature for.
                   * @param signature - The aggregated signature.
                   */
                  function validateSignatures(
                      PackedUserOperation[] calldata userOps,
                      bytes calldata signature
                  ) external view;
                  /**
                   * Validate signature of a single userOp.
                   * This method should be called by bundler after EntryPointSimulation.simulateValidation() returns
                   * the aggregator this account uses.
                   * First it validates the signature over the userOp. Then it returns data to be used when creating the handleOps.
                   * @param userOp        - The userOperation received from the user.
                   * @return sigForUserOp - The value to put into the signature field of the userOp when calling handleOps.
                   *                        (usually empty, unless account and aggregator support some kind of "multisig".
                   */
                  function validateUserOpSignature(
                      PackedUserOperation calldata userOp
                  ) external view returns (bytes memory sigForUserOp);
                  /**
                   * Aggregate multiple signatures into a single value.
                   * This method is called off-chain to calculate the signature to pass with handleOps()
                   * bundler MAY use optimized custom code perform this aggregation.
                   * @param userOps              - Array of UserOperations to collect the signatures from.
                   * @return aggregatedSignature - The aggregated signature.
                   */
                  function aggregateSignatures(
                      PackedUserOperation[] calldata userOps
                  ) external view returns (bytes memory aggregatedSignature);
              }
              /**
               ** Account-Abstraction (EIP-4337) singleton EntryPoint implementation.
               ** Only one instance required on each chain.
               **/
              // SPDX-License-Identifier: GPL-3.0
              pragma solidity >=0.7.5;
              /* solhint-disable avoid-low-level-calls */
              /* solhint-disable no-inline-assembly */
              /* solhint-disable reason-string */
              import "./PackedUserOperation.sol";
              import "./IStakeManager.sol";
              import "./IAggregator.sol";
              import "./INonceManager.sol";
              interface IEntryPoint is IStakeManager, INonceManager {
                  /***
                   * An event emitted after each successful request.
                   * @param userOpHash    - Unique identifier for the request (hash its entire content, except signature).
                   * @param sender        - The account that generates this request.
                   * @param paymaster     - If non-null, the paymaster that pays for this request.
                   * @param nonce         - The nonce value from the request.
                   * @param success       - True if the sender transaction succeeded, false if reverted.
                   * @param actualGasCost - Actual amount paid (by account or paymaster) for this UserOperation.
                   * @param actualGasUsed - Total gas used by this UserOperation (including preVerification, creation,
                   *                        validation and execution).
                   */
                  event UserOperationEvent(
                      bytes32 indexed userOpHash,
                      address indexed sender,
                      address indexed paymaster,
                      uint256 nonce,
                      bool success,
                      uint256 actualGasCost,
                      uint256 actualGasUsed
                  );
                  /**
                   * Account "sender" was deployed.
                   * @param userOpHash - The userOp that deployed this account. UserOperationEvent will follow.
                   * @param sender     - The account that is deployed
                   * @param factory    - The factory used to deploy this account (in the initCode)
                   * @param paymaster  - The paymaster used by this UserOp
                   */
                  event AccountDeployed(
                      bytes32 indexed userOpHash,
                      address indexed sender,
                      address factory,
                      address paymaster
                  );
                  /**
                   * An event emitted if the UserOperation "callData" reverted with non-zero length.
                   * @param userOpHash   - The request unique identifier.
                   * @param sender       - The sender of this request.
                   * @param nonce        - The nonce used in the request.
                   * @param revertReason - The return bytes from the (reverted) call to "callData".
                   */
                  event UserOperationRevertReason(
                      bytes32 indexed userOpHash,
                      address indexed sender,
                      uint256 nonce,
                      bytes revertReason
                  );
                  /**
                   * An event emitted if the UserOperation Paymaster's "postOp" call reverted with non-zero length.
                   * @param userOpHash   - The request unique identifier.
                   * @param sender       - The sender of this request.
                   * @param nonce        - The nonce used in the request.
                   * @param revertReason - The return bytes from the (reverted) call to "callData".
                   */
                  event PostOpRevertReason(
                      bytes32 indexed userOpHash,
                      address indexed sender,
                      uint256 nonce,
                      bytes revertReason
                  );
                  /**
                   * UserOp consumed more than prefund. The UserOperation is reverted, and no refund is made.
                   * @param userOpHash   - The request unique identifier.
                   * @param sender       - The sender of this request.
                   * @param nonce        - The nonce used in the request.
                   */
                  event UserOperationPrefundTooLow(
                      bytes32 indexed userOpHash,
                      address indexed sender,
                      uint256 nonce
                  );
                  /**
                   * An event emitted by handleOps(), before starting the execution loop.
                   * Any event emitted before this event, is part of the validation.
                   */
                  event BeforeExecution();
                  /**
                   * Signature aggregator used by the following UserOperationEvents within this bundle.
                   * @param aggregator - The aggregator used for the following UserOperationEvents.
                   */
                  event SignatureAggregatorChanged(address indexed aggregator);
                  /**
                   * A custom revert error of handleOps, to identify the offending op.
                   * Should be caught in off-chain handleOps simulation and not happen on-chain.
                   * Useful for mitigating DoS attempts against batchers or for troubleshooting of factory/account/paymaster reverts.
                   * NOTE: If simulateValidation passes successfully, there should be no reason for handleOps to fail on it.
                   * @param opIndex - Index into the array of ops to the failed one (in simulateValidation, this is always zero).
                   * @param reason  - Revert reason. The string starts with a unique code "AAmn",
                   *                  where "m" is "1" for factory, "2" for account and "3" for paymaster issues,
                   *                  so a failure can be attributed to the correct entity.
                   */
                  error FailedOp(uint256 opIndex, string reason);
                  /**
                   * A custom revert error of handleOps, to report a revert by account or paymaster.
                   * @param opIndex - Index into the array of ops to the failed one (in simulateValidation, this is always zero).
                   * @param reason  - Revert reason. see FailedOp(uint256,string), above
                   * @param inner   - data from inner cought revert reason
                   * @dev note that inner is truncated to 2048 bytes
                   */
                  error FailedOpWithRevert(uint256 opIndex, string reason, bytes inner);
                  error PostOpReverted(bytes returnData);
                  /**
                   * Error case when a signature aggregator fails to verify the aggregated signature it had created.
                   * @param aggregator The aggregator that failed to verify the signature
                   */
                  error SignatureValidationFailed(address aggregator);
                  // Return value of getSenderAddress.
                  error SenderAddressResult(address sender);
                  // UserOps handled, per aggregator.
                  struct UserOpsPerAggregator {
                      PackedUserOperation[] userOps;
                      // Aggregator address
                      IAggregator aggregator;
                      // Aggregated signature
                      bytes signature;
                  }
                  /**
                   * Execute a batch of UserOperations.
                   * No signature aggregator is used.
                   * If any account requires an aggregator (that is, it returned an aggregator when
                   * performing simulateValidation), then handleAggregatedOps() must be used instead.
                   * @param ops         - The operations to execute.
                   * @param beneficiary - The address to receive the fees.
                   */
                  function handleOps(
                      PackedUserOperation[] calldata ops,
                      address payable beneficiary
                  ) external;
                  /**
                   * Execute a batch of UserOperation with Aggregators
                   * @param opsPerAggregator - The operations to execute, grouped by aggregator (or address(0) for no-aggregator accounts).
                   * @param beneficiary      - The address to receive the fees.
                   */
                  function handleAggregatedOps(
                      UserOpsPerAggregator[] calldata opsPerAggregator,
                      address payable beneficiary
                  ) external;
                  /**
                   * Generate a request Id - unique identifier for this request.
                   * The request ID is a hash over the content of the userOp (except the signature), the entrypoint and the chainid.
                   * @param userOp - The user operation to generate the request ID for.
                   * @return hash the hash of this UserOperation
                   */
                  function getUserOpHash(
                      PackedUserOperation calldata userOp
                  ) external view returns (bytes32);
                  /**
                   * Gas and return values during simulation.
                   * @param preOpGas         - The gas used for validation (including preValidationGas)
                   * @param prefund          - The required prefund for this operation
                   * @param accountValidationData   - returned validationData from account.
                   * @param paymasterValidationData - return validationData from paymaster.
                   * @param paymasterContext - Returned by validatePaymasterUserOp (to be passed into postOp)
                   */
                  struct ReturnInfo {
                      uint256 preOpGas;
                      uint256 prefund;
                      uint256 accountValidationData;
                      uint256 paymasterValidationData;
                      bytes paymasterContext;
                  }
                  /**
                   * Returned aggregated signature info:
                   * The aggregator returned by the account, and its current stake.
                   */
                  struct AggregatorStakeInfo {
                      address aggregator;
                      StakeInfo stakeInfo;
                  }
                  /**
                   * Get counterfactual sender address.
                   * Calculate the sender contract address that will be generated by the initCode and salt in the UserOperation.
                   * This method always revert, and returns the address in SenderAddressResult error
                   * @param initCode - The constructor code to be passed into the UserOperation.
                   */
                  function getSenderAddress(bytes memory initCode) external;
                  error DelegateAndRevert(bool success, bytes ret);
                  /**
                   * Helper method for dry-run testing.
                   * @dev calling this method, the EntryPoint will make a delegatecall to the given data, and report (via revert) the result.
                   *  The method always revert, so is only useful off-chain for dry run calls, in cases where state-override to replace
                   *  actual EntryPoint code is less convenient.
                   * @param target a target contract to make a delegatecall from entrypoint
                   * @param data data to pass to target in a delegatecall
                   */
                  function delegateAndRevert(address target, bytes calldata data) external;
              }
              // SPDX-License-Identifier: GPL-3.0
              pragma solidity >=0.7.5;
              interface INonceManager {
                  /**
                   * Return the next nonce for this sender.
                   * Within a given key, the nonce values are sequenced (starting with zero, and incremented by one on each userop)
                   * But UserOp with different keys can come with arbitrary order.
                   *
                   * @param sender the account address
                   * @param key the high 192 bit of the nonce
                   * @return nonce a full nonce to pass for next UserOp with this sender.
                   */
                  function getNonce(address sender, uint192 key)
                  external view returns (uint256 nonce);
                  /**
                   * Manually increment the nonce of the sender.
                   * This method is exposed just for completeness..
                   * Account does NOT need to call it, neither during validation, nor elsewhere,
                   * as the EntryPoint will update the nonce regardless.
                   * Possible use-case is call it with various keys to "initialize" their nonces to one, so that future
                   * UserOperations will not pay extra for the first transaction with a given key.
                   */
                  function incrementNonce(uint192 key) external;
              }
              // SPDX-License-Identifier: GPL-3.0
              pragma solidity >=0.7.5;
              import "./PackedUserOperation.sol";
              /**
               * The interface exposed by a paymaster contract, who agrees to pay the gas for user's operations.
               * A paymaster must hold a stake to cover the required entrypoint stake and also the gas for the transaction.
               */
              interface IPaymaster {
                  enum PostOpMode {
                      // User op succeeded.
                      opSucceeded,
                      // User op reverted. Still has to pay for gas.
                      opReverted,
                      // Only used internally in the EntryPoint (cleanup after postOp reverts). Never calling paymaster with this value
                      postOpReverted
                  }
                  /**
                   * Payment validation: check if paymaster agrees to pay.
                   * Must verify sender is the entryPoint.
                   * Revert to reject this request.
                   * Note that bundlers will reject this method if it changes the state, unless the paymaster is trusted (whitelisted).
                   * The paymaster pre-pays using its deposit, and receive back a refund after the postOp method returns.
                   * @param userOp          - The user operation.
                   * @param userOpHash      - Hash of the user's request data.
                   * @param maxCost         - The maximum cost of this transaction (based on maximum gas and gas price from userOp).
                   * @return context        - Value to send to a postOp. Zero length to signify postOp is not required.
                   * @return validationData - Signature and time-range of this operation, encoded the same as the return
                   *                          value of validateUserOperation.
                   *                          <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure,
                   *                                                    other values are invalid for paymaster.
                   *                          <6-byte> validUntil - last timestamp this operation is valid. 0 for "indefinite"
                   *                          <6-byte> validAfter - first timestamp this operation is valid
                   *                          Note that the validation code cannot use block.timestamp (or block.number) directly.
                   */
                  function validatePaymasterUserOp(
                      PackedUserOperation calldata userOp,
                      bytes32 userOpHash,
                      uint256 maxCost
                  ) external returns (bytes memory context, uint256 validationData);
                  /**
                   * Post-operation handler.
                   * Must verify sender is the entryPoint.
                   * @param mode          - Enum with the following options:
                   *                        opSucceeded - User operation succeeded.
                   *                        opReverted  - User op reverted. The paymaster still has to pay for gas.
                   *                        postOpReverted - never passed in a call to postOp().
                   * @param context       - The context value returned by validatePaymasterUserOp
                   * @param actualGasCost - Actual gas used so far (without this postOp call).
                   * @param actualUserOpFeePerGas - the gas price this UserOp pays. This value is based on the UserOp's maxFeePerGas
                   *                        and maxPriorityFee (and basefee)
                   *                        It is not the same as tx.gasprice, which is what the bundler pays.
                   */
                  function postOp(
                      PostOpMode mode,
                      bytes calldata context,
                      uint256 actualGasCost,
                      uint256 actualUserOpFeePerGas
                  ) external;
              }
              // SPDX-License-Identifier: GPL-3.0-only
              pragma solidity >=0.7.5;
              /**
               * Manage deposits and stakes.
               * Deposit is just a balance used to pay for UserOperations (either by a paymaster or an account).
               * Stake is value locked for at least "unstakeDelay" by the staked entity.
               */
              interface IStakeManager {
                  event Deposited(address indexed account, uint256 totalDeposit);
                  event Withdrawn(
                      address indexed account,
                      address withdrawAddress,
                      uint256 amount
                  );
                  // Emitted when stake or unstake delay are modified.
                  event StakeLocked(
                      address indexed account,
                      uint256 totalStaked,
                      uint256 unstakeDelaySec
                  );
                  // Emitted once a stake is scheduled for withdrawal.
                  event StakeUnlocked(address indexed account, uint256 withdrawTime);
                  event StakeWithdrawn(
                      address indexed account,
                      address withdrawAddress,
                      uint256 amount
                  );
                  /**
                   * @param deposit         - The entity's deposit.
                   * @param staked          - True if this entity is staked.
                   * @param stake           - Actual amount of ether staked for this entity.
                   * @param unstakeDelaySec - Minimum delay to withdraw the stake.
                   * @param withdrawTime    - First block timestamp where 'withdrawStake' will be callable, or zero if already locked.
                   * @dev Sizes were chosen so that deposit fits into one cell (used during handleOp)
                   *      and the rest fit into a 2nd cell (used during stake/unstake)
                   *      - 112 bit allows for 10^15 eth
                   *      - 48 bit for full timestamp
                   *      - 32 bit allows 150 years for unstake delay
                   */
                  struct DepositInfo {
                      uint256 deposit;
                      bool staked;
                      uint112 stake;
                      uint32 unstakeDelaySec;
                      uint48 withdrawTime;
                  }
                  // API struct used by getStakeInfo and simulateValidation.
                  struct StakeInfo {
                      uint256 stake;
                      uint256 unstakeDelaySec;
                  }
                  /**
                   * Get deposit info.
                   * @param account - The account to query.
                   * @return info   - Full deposit information of given account.
                   */
                  function getDepositInfo(
                      address account
                  ) external view returns (DepositInfo memory info);
                  /**
                   * Get account balance.
                   * @param account - The account to query.
                   * @return        - The deposit (for gas payment) of the account.
                   */
                  function balanceOf(address account) external view returns (uint256);
                  /**
                   * Add to the deposit of the given account.
                   * @param account - The account to add to.
                   */
                  function depositTo(address account) external payable;
                  /**
                   * Add to the account's stake - amount and delay
                   * any pending unstake is first cancelled.
                   * @param _unstakeDelaySec - The new lock duration before the deposit can be withdrawn.
                   */
                  function addStake(uint32 _unstakeDelaySec) external payable;
                  /**
                   * Attempt to unlock the stake.
                   * The value can be withdrawn (using withdrawStake) after the unstake delay.
                   */
                  function unlockStake() external;
                  /**
                   * Withdraw from the (unlocked) stake.
                   * Must first call unlockStake and wait for the unstakeDelay to pass.
                   * @param withdrawAddress - The address to send withdrawn value.
                   */
                  function withdrawStake(address payable withdrawAddress) external;
                  /**
                   * Withdraw from the deposit.
                   * @param withdrawAddress - The address to send withdrawn value.
                   * @param withdrawAmount  - The amount to withdraw.
                   */
                  function withdrawTo(
                      address payable withdrawAddress,
                      uint256 withdrawAmount
                  ) external;
              }
              // SPDX-License-Identifier: GPL-3.0
              pragma solidity >=0.7.5;
              /**
               * User Operation struct
               * @param sender                - The sender account of this request.
               * @param nonce                 - Unique value the sender uses to verify it is not a replay.
               * @param initCode              - If set, the account contract will be created by this constructor/
               * @param callData              - The method call to execute on this account.
               * @param accountGasLimits      - Packed gas limits for validateUserOp and gas limit passed to the callData method call.
               * @param preVerificationGas    - Gas not calculated by the handleOps method, but added to the gas paid.
               *                                Covers batch overhead.
               * @param gasFees               - packed gas fields maxPriorityFeePerGas and maxFeePerGas - Same as EIP-1559 gas parameters.
               * @param paymasterAndData      - If set, this field holds the paymaster address, verification gas limit, postOp gas limit and paymaster-specific extra data
               *                                The paymaster will pay for the transaction instead of the sender.
               * @param signature             - Sender-verified signature over the entire request, the EntryPoint address and the chain ID.
               */
              struct PackedUserOperation {
                  address sender;
                  uint256 nonce;
                  bytes initCode;
                  bytes callData;
                  bytes32 accountGasLimits;
                  uint256 preVerificationGas;
                  bytes32 gasFees;
                  bytes paymasterAndData;
                  bytes signature;
              }
              // SPDX-License-Identifier: LGPL-3.0-only
              pragma solidity ^0.8.23;
              // solhint-disable no-inline-assembly
              /**
               * Utility functions helpful when making different kinds of contract calls in Solidity.
               */
              library Exec {
                  function call(
                      address to,
                      uint256 value,
                      bytes memory data,
                      uint256 txGas
                  ) internal returns (bool success) {
                      assembly ("memory-safe") {
                          success := call(txGas, to, value, add(data, 0x20), mload(data), 0, 0)
                      }
                  }
                  function staticcall(
                      address to,
                      bytes memory data,
                      uint256 txGas
                  ) internal view returns (bool success) {
                      assembly ("memory-safe") {
                          success := staticcall(txGas, to, add(data, 0x20), mload(data), 0, 0)
                      }
                  }
                  function delegateCall(
                      address to,
                      bytes memory data,
                      uint256 txGas
                  ) internal returns (bool success) {
                      assembly ("memory-safe") {
                          success := delegatecall(txGas, to, add(data, 0x20), mload(data), 0, 0)
                      }
                  }
                  // get returned data from last call or calldelegate
                  function getReturnData(uint256 maxLen) internal pure returns (bytes memory returnData) {
                      assembly ("memory-safe") {
                          let len := returndatasize()
                          if gt(len, maxLen) {
                              len := maxLen
                          }
                          let ptr := mload(0x40)
                          mstore(0x40, add(ptr, add(len, 0x20)))
                          mstore(ptr, len)
                          returndatacopy(add(ptr, 0x20), 0, len)
                          returnData := ptr
                      }
                  }
                  // revert with explicit byte array (probably reverted info from call)
                  function revertWithData(bytes memory returnData) internal pure {
                      assembly ("memory-safe") {
                          revert(add(returnData, 32), mload(returnData))
                      }
                  }
                  function callAndRevert(address to, bytes memory data, uint256 maxLen) internal {
                      bool success = call(to,0,data,gasleft());
                      if (!success) {
                          revertWithData(getReturnData(maxLen));
                      }
                  }
              }
              

              File 2 of 4: ERC1967Proxy
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
              pragma solidity ^0.8.20;
              import {Context} from "../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.
               *
               * The initial owner is set to the address provided by the deployer. 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;
                  /**
                   * @dev The caller account is not authorized to perform an operation.
                   */
                  error OwnableUnauthorizedAccount(address account);
                  /**
                   * @dev The owner is not a valid owner account. (eg. `address(0)`)
                   */
                  error OwnableInvalidOwner(address owner);
                  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                  /**
                   * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
                   */
                  constructor(address initialOwner) {
                      if (initialOwner == address(0)) {
                          revert OwnableInvalidOwner(address(0));
                      }
                      _transferOwnership(initialOwner);
                  }
                  /**
                   * @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 {
                      if (owner() != _msgSender()) {
                          revert OwnableUnauthorizedAccount(_msgSender());
                      }
                  }
                  /**
                   * @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 {
                      if (newOwner == address(0)) {
                          revert OwnableInvalidOwner(address(0));
                      }
                      _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 v5.0.0) (interfaces/IERC1967.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
               */
              interface IERC1967 {
                  /**
                   * @dev Emitted when the implementation is upgraded.
                   */
                  event Upgraded(address indexed implementation);
                  /**
                   * @dev Emitted when the admin account has changed.
                   */
                  event AdminChanged(address previousAdmin, address newAdmin);
                  /**
                   * @dev Emitted when the beacon is changed.
                   */
                  event BeaconUpgraded(address indexed beacon);
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/BeaconProxy.sol)
              pragma solidity ^0.8.20;
              import {IBeacon} from "./IBeacon.sol";
              import {Proxy} from "../Proxy.sol";
              import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol";
              /**
               * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}.
               *
               * The beacon address can only be set once during construction, and cannot be changed afterwards. It is stored in an
               * immutable variable to avoid unnecessary storage reads, and also in the beacon storage slot specified by
               * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] so that it can be accessed externally.
               *
               * CAUTION: Since the beacon address can never be changed, you must ensure that you either control the beacon, or trust
               * the beacon to not upgrade the implementation maliciously.
               *
               * IMPORTANT: Do not use the implementation logic to modify the beacon storage slot. Doing so would leave the proxy in
               * an inconsistent state where the beacon storage slot does not match the beacon address.
               */
              contract BeaconProxy is Proxy {
                  // An immutable address for the beacon to avoid unnecessary SLOADs before each delegate call.
                  address private immutable _beacon;
                  /**
                   * @dev Initializes the proxy with `beacon`.
                   *
                   * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This
                   * will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity
                   * constructor.
                   *
                   * Requirements:
                   *
                   * - `beacon` must be a contract with the interface {IBeacon}.
                   * - If `data` is empty, `msg.value` must be zero.
                   */
                  constructor(address beacon, bytes memory data) payable {
                      ERC1967Utils.upgradeBeaconToAndCall(beacon, data);
                      _beacon = beacon;
                  }
                  /**
                   * @dev Returns the current implementation address of the associated beacon.
                   */
                  function _implementation() internal view virtual override returns (address) {
                      return IBeacon(_getBeacon()).implementation();
                  }
                  /**
                   * @dev Returns the beacon.
                   */
                  function _getBeacon() internal view virtual returns (address) {
                      return _beacon;
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev This is the interface that {BeaconProxy} expects of its beacon.
               */
              interface IBeacon {
                  /**
                   * @dev Must return an address that can be used as a delegate call target.
                   *
                   * {UpgradeableBeacon} will check that this address is a contract.
                   */
                  function implementation() external view returns (address);
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/UpgradeableBeacon.sol)
              pragma solidity ^0.8.20;
              import {IBeacon} from "./IBeacon.sol";
              import {Ownable} from "../../access/Ownable.sol";
              /**
               * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their
               * implementation contract, which is where they will delegate all function calls.
               *
               * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon.
               */
              contract UpgradeableBeacon is IBeacon, Ownable {
                  address private _implementation;
                  /**
                   * @dev The `implementation` of the beacon is invalid.
                   */
                  error BeaconInvalidImplementation(address implementation);
                  /**
                   * @dev Emitted when the implementation returned by the beacon is changed.
                   */
                  event Upgraded(address indexed implementation);
                  /**
                   * @dev Sets the address of the initial implementation, and the initial owner who can upgrade the beacon.
                   */
                  constructor(address implementation_, address initialOwner) Ownable(initialOwner) {
                      _setImplementation(implementation_);
                  }
                  /**
                   * @dev Returns the current implementation address.
                   */
                  function implementation() public view virtual returns (address) {
                      return _implementation;
                  }
                  /**
                   * @dev Upgrades the beacon to a new implementation.
                   *
                   * Emits an {Upgraded} event.
                   *
                   * Requirements:
                   *
                   * - msg.sender must be the owner of the contract.
                   * - `newImplementation` must be a contract.
                   */
                  function upgradeTo(address newImplementation) public virtual onlyOwner {
                      _setImplementation(newImplementation);
                  }
                  /**
                   * @dev Sets the implementation contract address for this beacon
                   *
                   * Requirements:
                   *
                   * - `newImplementation` must be a contract.
                   */
                  function _setImplementation(address newImplementation) private {
                      if (newImplementation.code.length == 0) {
                          revert BeaconInvalidImplementation(newImplementation);
                      }
                      _implementation = newImplementation;
                      emit Upgraded(newImplementation);
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Proxy.sol)
              pragma solidity ^0.8.20;
              import {Proxy} from "../Proxy.sol";
              import {ERC1967Utils} from "./ERC1967Utils.sol";
              /**
               * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
               * implementation address that can be changed. This address is stored in storage in the location specified by
               * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
               * implementation behind the proxy.
               */
              contract ERC1967Proxy is Proxy {
                  /**
                   * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`.
                   *
                   * If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an
                   * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.
                   *
                   * Requirements:
                   *
                   * - If `data` is empty, `msg.value` must be zero.
                   */
                  constructor(address implementation, bytes memory _data) payable {
                      ERC1967Utils.upgradeToAndCall(implementation, _data);
                  }
                  /**
                   * @dev Returns the current implementation address.
                   *
                   * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
                   * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                   * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
                   */
                  function _implementation() internal view virtual override returns (address) {
                      return ERC1967Utils.getImplementation();
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
              pragma solidity ^0.8.20;
              import {IBeacon} from "../beacon/IBeacon.sol";
              import {Address} from "../../utils/Address.sol";
              import {StorageSlot} from "../../utils/StorageSlot.sol";
              /**
               * @dev This abstract contract provides getters and event emitting update functions for
               * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
               */
              library ERC1967Utils {
                  // We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
                  // This will be fixed in Solidity 0.8.21. At that point we should remove these events.
                  /**
                   * @dev Emitted when the implementation is upgraded.
                   */
                  event Upgraded(address indexed implementation);
                  /**
                   * @dev Emitted when the admin account has changed.
                   */
                  event AdminChanged(address previousAdmin, address newAdmin);
                  /**
                   * @dev Emitted when the beacon is changed.
                   */
                  event BeaconUpgraded(address indexed beacon);
                  /**
                   * @dev Storage slot with the address of the current implementation.
                   * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
                   */
                  // solhint-disable-next-line private-vars-leading-underscore
                  bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                  /**
                   * @dev The `implementation` of the proxy is invalid.
                   */
                  error ERC1967InvalidImplementation(address implementation);
                  /**
                   * @dev The `admin` of the proxy is invalid.
                   */
                  error ERC1967InvalidAdmin(address admin);
                  /**
                   * @dev The `beacon` of the proxy is invalid.
                   */
                  error ERC1967InvalidBeacon(address beacon);
                  /**
                   * @dev An upgrade function sees `msg.value > 0` that may be lost.
                   */
                  error ERC1967NonPayable();
                  /**
                   * @dev Returns the current implementation address.
                   */
                  function getImplementation() internal view returns (address) {
                      return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
                  }
                  /**
                   * @dev Stores a new address in the EIP1967 implementation slot.
                   */
                  function _setImplementation(address newImplementation) private {
                      if (newImplementation.code.length == 0) {
                          revert ERC1967InvalidImplementation(newImplementation);
                      }
                      StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
                  }
                  /**
                   * @dev Performs implementation upgrade with additional setup call if data is nonempty.
                   * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
                   * to avoid stuck value in the contract.
                   *
                   * Emits an {IERC1967-Upgraded} event.
                   */
                  function upgradeToAndCall(address newImplementation, bytes memory data) internal {
                      _setImplementation(newImplementation);
                      emit Upgraded(newImplementation);
                      if (data.length > 0) {
                          Address.functionDelegateCall(newImplementation, data);
                      } else {
                          _checkNonPayable();
                      }
                  }
                  /**
                   * @dev Storage slot with the admin of the contract.
                   * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
                   */
                  // solhint-disable-next-line private-vars-leading-underscore
                  bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                  /**
                   * @dev Returns the current admin.
                   *
                   * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
                   * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                   * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                   */
                  function getAdmin() internal view returns (address) {
                      return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
                  }
                  /**
                   * @dev Stores a new address in the EIP1967 admin slot.
                   */
                  function _setAdmin(address newAdmin) private {
                      if (newAdmin == address(0)) {
                          revert ERC1967InvalidAdmin(address(0));
                      }
                      StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
                  }
                  /**
                   * @dev Changes the admin of the proxy.
                   *
                   * Emits an {IERC1967-AdminChanged} event.
                   */
                  function changeAdmin(address newAdmin) internal {
                      emit AdminChanged(getAdmin(), newAdmin);
                      _setAdmin(newAdmin);
                  }
                  /**
                   * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                   * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
                   */
                  // solhint-disable-next-line private-vars-leading-underscore
                  bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                  /**
                   * @dev Returns the current beacon.
                   */
                  function getBeacon() internal view returns (address) {
                      return StorageSlot.getAddressSlot(BEACON_SLOT).value;
                  }
                  /**
                   * @dev Stores a new beacon in the EIP1967 beacon slot.
                   */
                  function _setBeacon(address newBeacon) private {
                      if (newBeacon.code.length == 0) {
                          revert ERC1967InvalidBeacon(newBeacon);
                      }
                      StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
                      address beaconImplementation = IBeacon(newBeacon).implementation();
                      if (beaconImplementation.code.length == 0) {
                          revert ERC1967InvalidImplementation(beaconImplementation);
                      }
                  }
                  /**
                   * @dev Change the beacon and trigger a setup call if data is nonempty.
                   * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
                   * to avoid stuck value in the contract.
                   *
                   * Emits an {IERC1967-BeaconUpgraded} event.
                   *
                   * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
                   * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
                   * efficiency.
                   */
                  function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
                      _setBeacon(newBeacon);
                      emit BeaconUpgraded(newBeacon);
                      if (data.length > 0) {
                          Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                      } else {
                          _checkNonPayable();
                      }
                  }
                  /**
                   * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
                   * if an upgrade doesn't perform an initialization call.
                   */
                  function _checkNonPayable() private {
                      if (msg.value > 0) {
                          revert ERC1967NonPayable();
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
               * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
               * be specified by overriding the virtual {_implementation} function.
               *
               * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
               * different contract through the {_delegate} function.
               *
               * The success and return data of the delegated call will be returned back to the caller of the proxy.
               */
              abstract contract Proxy {
                  /**
                   * @dev Delegates the current call to `implementation`.
                   *
                   * This function does not return to its internal call site, it will return directly to the external caller.
                   */
                  function _delegate(address implementation) internal virtual {
                      assembly {
                          // Copy msg.data. We take full control of memory in this inline assembly
                          // block because it will not return to Solidity code. We overwrite the
                          // Solidity scratch pad at memory position 0.
                          calldatacopy(0, 0, calldatasize())
                          // Call the implementation.
                          // out and outsize are 0 because we don't know the size yet.
                          let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                          // Copy the returned data.
                          returndatacopy(0, 0, returndatasize())
                          switch result
                          // delegatecall returns 0 on error.
                          case 0 {
                              revert(0, returndatasize())
                          }
                          default {
                              return(0, returndatasize())
                          }
                      }
                  }
                  /**
                   * @dev This is a virtual function that should be overridden so it returns the address to which the fallback
                   * function and {_fallback} should delegate.
                   */
                  function _implementation() internal view virtual returns (address);
                  /**
                   * @dev Delegates the current call to the address returned by `_implementation()`.
                   *
                   * This function does not return to its internal call site, it will return directly to the external caller.
                   */
                  function _fallback() internal virtual {
                      _delegate(_implementation());
                  }
                  /**
                   * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
                   * function in the contract matches the call data.
                   */
                  fallback() external payable virtual {
                      _fallback();
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/ProxyAdmin.sol)
              pragma solidity ^0.8.20;
              import {ITransparentUpgradeableProxy} from "./TransparentUpgradeableProxy.sol";
              import {Ownable} from "../../access/Ownable.sol";
              /**
               * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
               * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
               */
              contract ProxyAdmin is Ownable {
                  /**
                   * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgrade(address)`
                   * and `upgradeAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
                   * while `upgradeAndCall` will invoke the `receive` function if the second argument is the empty byte string.
                   * If the getter returns `"5.0.0"`, only `upgradeAndCall(address,bytes)` is present, and the second argument must
                   * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
                   * during an upgrade.
                   */
                  string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
                  /**
                   * @dev Sets the initial owner who can perform upgrades.
                   */
                  constructor(address initialOwner) Ownable(initialOwner) {}
                  /**
                   * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation.
                   * See {TransparentUpgradeableProxy-_dispatchUpgradeToAndCall}.
                   *
                   * Requirements:
                   *
                   * - This contract must be the admin of `proxy`.
                   * - If `data` is empty, `msg.value` must be zero.
                   */
                  function upgradeAndCall(
                      ITransparentUpgradeableProxy proxy,
                      address implementation,
                      bytes memory data
                  ) public payable virtual onlyOwner {
                      proxy.upgradeToAndCall{value: msg.value}(implementation, data);
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/TransparentUpgradeableProxy.sol)
              pragma solidity ^0.8.20;
              import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol";
              import {ERC1967Proxy} from "../ERC1967/ERC1967Proxy.sol";
              import {IERC1967} from "../../interfaces/IERC1967.sol";
              import {ProxyAdmin} from "./ProxyAdmin.sol";
              /**
               * @dev Interface for {TransparentUpgradeableProxy}. In order to implement transparency, {TransparentUpgradeableProxy}
               * does not implement this interface directly, and its upgradeability mechanism is implemented by an internal dispatch
               * mechanism. The compiler is unaware that these functions are implemented by {TransparentUpgradeableProxy} and will not
               * include them in the ABI so this interface must be used to interact with it.
               */
              interface ITransparentUpgradeableProxy is IERC1967 {
                  function upgradeToAndCall(address, bytes calldata) external payable;
              }
              /**
               * @dev This contract implements a proxy that is upgradeable through an associated {ProxyAdmin} instance.
               *
               * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
               * clashing], which can potentially be used in an attack, this contract uses the
               * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
               * things that go hand in hand:
               *
               * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
               * that call matches the {ITransparentUpgradeableProxy-upgradeToAndCall} function exposed by the proxy itself.
               * 2. If the admin calls the proxy, it can call the `upgradeToAndCall` function but any other call won't be forwarded to
               * the implementation. If the admin tries to call a function on the implementation it will fail with an error indicating
               * the proxy admin cannot fallback to the target implementation.
               *
               * These properties mean that the admin account can only be used for upgrading the proxy, so it's best if it's a
               * dedicated account that is not used for anything else. This will avoid headaches due to sudden errors when trying to
               * call a function from the proxy implementation. For this reason, the proxy deploys an instance of {ProxyAdmin} and
               * allows upgrades only if they come through it. You should think of the `ProxyAdmin` instance as the administrative
               * interface of the proxy, including the ability to change who can trigger upgrades by transferring ownership.
               *
               * NOTE: The real interface of this proxy is that defined in `ITransparentUpgradeableProxy`. This contract does not
               * inherit from that interface, and instead `upgradeToAndCall` is implicitly implemented using a custom dispatch
               * mechanism in `_fallback`. Consequently, the compiler will not produce an ABI for this contract. This is necessary to
               * fully implement transparency without decoding reverts caused by selector clashes between the proxy and the
               * implementation.
               *
               * NOTE: This proxy does not inherit from {Context} deliberately. The {ProxyAdmin} of this contract won't send a
               * meta-transaction in any way, and any other meta-transaction setup should be made in the implementation contract.
               *
               * IMPORTANT: This contract avoids unnecessary storage reads by setting the admin only during construction as an
               * immutable variable, preventing any changes thereafter. However, the admin slot defined in ERC-1967 can still be
               * overwritten by the implementation logic pointed to by this proxy. In such cases, the contract may end up in an
               * undesirable state where the admin slot is different from the actual admin.
               *
               * WARNING: It is not recommended to extend this contract to add additional external functions. If you do so, the
               * compiler will not check that there are no selector conflicts, due to the note above. A selector clash between any new
               * function and the functions declared in {ITransparentUpgradeableProxy} will be resolved in favor of the new one. This
               * could render the `upgradeToAndCall` function inaccessible, preventing upgradeability and compromising transparency.
               */
              contract TransparentUpgradeableProxy is ERC1967Proxy {
                  // An immutable address for the admin to avoid unnecessary SLOADs before each call
                  // at the expense of removing the ability to change the admin once it's set.
                  // This is acceptable if the admin is always a ProxyAdmin instance or similar contract
                  // with its own ability to transfer the permissions to another account.
                  address private immutable _admin;
                  /**
                   * @dev The proxy caller is the current admin, and can't fallback to the proxy target.
                   */
                  error ProxyDeniedAdminAccess();
                  /**
                   * @dev Initializes an upgradeable proxy managed by an instance of a {ProxyAdmin} with an `initialOwner`,
                   * backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in
                   * {ERC1967Proxy-constructor}.
                   */
                  constructor(address _logic, address initialOwner, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
                      _admin = address(new ProxyAdmin(initialOwner));
                      // Set the storage value and emit an event for ERC-1967 compatibility
                      ERC1967Utils.changeAdmin(_proxyAdmin());
                  }
                  /**
                   * @dev Returns the admin of this proxy.
                   */
                  function _proxyAdmin() internal virtual returns (address) {
                      return _admin;
                  }
                  /**
                   * @dev If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior.
                   */
                  function _fallback() internal virtual override {
                      if (msg.sender == _proxyAdmin()) {
                          if (msg.sig != ITransparentUpgradeableProxy.upgradeToAndCall.selector) {
                              revert ProxyDeniedAdminAccess();
                          } else {
                              _dispatchUpgradeToAndCall();
                          }
                      } else {
                          super._fallback();
                      }
                  }
                  /**
                   * @dev Upgrade the implementation of the proxy. See {ERC1967Utils-upgradeToAndCall}.
                   *
                   * Requirements:
                   *
                   * - If `data` is empty, `msg.value` must be zero.
                   */
                  function _dispatchUpgradeToAndCall() private {
                      (address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes));
                      ERC1967Utils.upgradeToAndCall(newImplementation, data);
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev Collection of functions related to the address type
               */
              library Address {
                  /**
                   * @dev The ETH balance of the account is not enough to perform the operation.
                   */
                  error AddressInsufficientBalance(address account);
                  /**
                   * @dev There's no code at `target` (it is not a contract).
                   */
                  error AddressEmptyCode(address target);
                  /**
                   * @dev A call to an address target failed. The target may have reverted.
                   */
                  error FailedInnerCall();
                  /**
                   * @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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                   */
                  function sendValue(address payable recipient, uint256 amount) internal {
                      if (address(this).balance < amount) {
                          revert AddressInsufficientBalance(address(this));
                      }
                      (bool success, ) = recipient.call{value: amount}("");
                      if (!success) {
                          revert FailedInnerCall();
                      }
                  }
                  /**
                   * @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 or custom error, it is bubbled
                   * up by this function (like regular Solidity function calls). However, if
                   * the call reverted with no returned reason, this function reverts with a
                   * {FailedInnerCall} error.
                   *
                   * 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.
                   */
                  function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                      return functionCallWithValue(target, data, 0);
                  }
                  /**
                   * @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`.
                   */
                  function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                      if (address(this).balance < value) {
                          revert AddressInsufficientBalance(address(this));
                      }
                      (bool success, bytes memory returndata) = target.call{value: value}(data);
                      return verifyCallResultFromTarget(target, success, returndata);
                  }
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a static call.
                   */
                  function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                      (bool success, bytes memory returndata) = target.staticcall(data);
                      return verifyCallResultFromTarget(target, success, returndata);
                  }
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a delegate call.
                   */
                  function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                      (bool success, bytes memory returndata) = target.delegatecall(data);
                      return verifyCallResultFromTarget(target, success, returndata);
                  }
                  /**
                   * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
                   * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
                   * unsuccessful call.
                   */
                  function verifyCallResultFromTarget(
                      address target,
                      bool success,
                      bytes memory returndata
                  ) internal view returns (bytes memory) {
                      if (!success) {
                          _revert(returndata);
                      } else {
                          // only check if target is a contract if the call was successful and the return data is empty
                          // otherwise we already know that it was a contract
                          if (returndata.length == 0 && target.code.length == 0) {
                              revert AddressEmptyCode(target);
                          }
                          return returndata;
                      }
                  }
                  /**
                   * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
                   * revert reason or with a default {FailedInnerCall} error.
                   */
                  function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
                      if (!success) {
                          _revert(returndata);
                      } else {
                          return returndata;
                      }
                  }
                  /**
                   * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
                   */
                  function _revert(bytes memory returndata) 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 FailedInnerCall();
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
              pragma solidity ^0.8.20;
              /**
               * @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 (last updated v5.0.0) (utils/StorageSlot.sol)
              // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
              pragma solidity ^0.8.20;
              /**
               * @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(newImplementation.code.length > 0);
               *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
               *     }
               * }
               * ```
               */
              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
                      }
                  }
              }
              

              File 3 of 4: K1MeeValidator
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.27;
              import {IValidator, MODULE_TYPE_VALIDATOR} from "erc7579/interfaces/IERC7579Module.sol";
              import {ISessionValidator} from "contracts/interfaces/ISessionValidator.sol";
              import {EnumerableSet} from "EnumerableSet4337/EnumerableSet4337.sol";
              import {PackedUserOperation} from "account-abstraction/interfaces/PackedUserOperation.sol";
              import {ERC7739Validator} from "erc7739Validator/ERC7739Validator.sol";
              import {
                  SIG_TYPE_SIMPLE,
                  SIG_TYPE_ON_CHAIN,
                  SIG_TYPE_ERC20_PERMIT,
                  EIP1271_SUCCESS,
                  EIP1271_FAILED,
                  MODULE_TYPE_STATELESS_VALIDATOR,
                  SIG_TYPE_MEE_FLOW
              } from "contracts/types/Constants.sol";
              // Fusion libraries - validate userOp using on-chain tx or off-chain permit
              import {PermitValidatorLib} from "contracts/lib/fusion/PermitValidatorLib.sol";
              import {TxValidatorLib} from "contracts/lib/fusion/TxValidatorLib.sol";
              import {SimpleValidatorLib} from "contracts/lib/fusion/SimpleValidatorLib.sol";
              import {NoMeeFlowLib} from "contracts/lib/fusion/NoMeeFlowLib.sol";
              import {EcdsaLib} from "contracts/lib/util/EcdsaLib.sol";
              /**
               * @title K1MeeValidator
               * @dev   An ERC-7579 validator (module type 1) and stateless validator (module type 7) for the MEE stack.
               *        Supports 3 MEE modes:
               *        - Simple (Super Tx hash is signed)
               *        - On-chain Tx (Super Tx hash is appended to a regular txn and signed)
               *        - ERC-2612 Permit (Super Tx hash is pasted into deadline field of the ERC-2612 Permit and signed)
               *
               *        Further improvements:
               *        - Further gas optimizations
               *        - Use EIP-712 to make superTx hash not blind => use 7739 for the MEE 1271 flows
               *
               *        Using erc7739 for MEE flows makes no sense currently because user signs blind hashes anyways
               *        (except permit mode, but the superTx hash is still blind in it).
               *        So we just hash smart account address into the og hash for 1271 MEE flow currently.
               *        In future full scale 7739 will replace it when superTx hash is 712 and transparent.
               *
               */
              contract K1MeeValidator is IValidator, ISessionValidator, ERC7739Validator {
                  using EnumerableSet for EnumerableSet.AddressSet;
                  /*//////////////////////////////////////////////////////////////////////////
                                          CONSTANTS & STORAGE
                  //////////////////////////////////////////////////////////////////////////*/
                  /// @notice Mapping of smart account addresses to their respective owner addresses
                  mapping(address => address) public smartAccountOwners;
                  /// @notice Set of safe senders for each smart account
                  EnumerableSet.AddressSet private _safeSenders;
                  /// @notice Error to indicate that no owner was provided during installation
                  error NoOwnerProvided();
                  /// @notice Error to indicate that the new owner cannot be the zero address
                  error ZeroAddressNotAllowed();
                  /// @notice Error to indicate the module is already initialized
                  error ModuleAlreadyInitialized();
                  /// @notice Error to indicate that the new owner cannot be a contract address
                  error NewOwnerIsContract();
                  /// @notice Error to indicate that the owner cannot be the zero address
                  error OwnerCannotBeZeroAddress();
                  /// @notice Error to indicate that the data length is invalid
                  error InvalidDataLength();
                  /// @notice Error to indicate that the safe senders length is invalid
                  error SafeSendersLengthInvalid();
                  /*//////////////////////////////////////////////////////////////////////////
                                                   CONFIG
                  //////////////////////////////////////////////////////////////////////////*/
                  /**
                   * Initialize the module with the given data
                   *
                   * @param data The data to initialize the module with
                   */
                  function onInstall(bytes calldata data) external override {
                      require(data.length != 0, NoOwnerProvided());
                      require(!_isInitialized(msg.sender), ModuleAlreadyInitialized());
                      address newOwner = address(bytes20(data[:20]));
                      require(newOwner != address(0), OwnerCannotBeZeroAddress());
                      require(!_isContract(newOwner), NewOwnerIsContract());
                      smartAccountOwners[msg.sender] = newOwner;
                      if (data.length > 20) {
                          _fillSafeSenders(data[20:]);
                      }
                  }
                  /**
                   * De-initialize the module with the given data
                   */
                  function onUninstall(bytes calldata) external override {
                      delete smartAccountOwners[msg.sender];
                      _safeSenders.removeAll(msg.sender);
                  }
                  /// @notice Transfers ownership of the validator to a new owner
                  /// @param newOwner The address of the new owner
                  function transferOwnership(address newOwner) external {
                      require(newOwner != address(0), ZeroAddressNotAllowed());
                      require(!_isContract(newOwner), NewOwnerIsContract());
                      smartAccountOwners[msg.sender] = newOwner;
                  }
                  /**
                   * Check if the module is initialized
                   * @param smartAccount The smart account to check
                   *
                   * @return true if the module is initialized, false otherwise
                   */
                  function isInitialized(address smartAccount) external view returns (bool) {
                      return _isInitialized(smartAccount);
                  }
                  /// @notice Adds a safe sender to the _safeSenders list for the smart account
                  function addSafeSender(address sender) external {
                      _safeSenders.add(msg.sender, sender);
                  }
                  /// @notice Removes a safe sender from the _safeSenders list for the smart account
                  function removeSafeSender(address sender) external {
                      _safeSenders.remove(msg.sender, sender);
                  }
                  /// @notice Checks if a sender is in the _safeSenders list for the smart account
                  function isSafeSender(address sender, address smartAccount) external view returns (bool) {
                      return _safeSenders.contains(smartAccount, sender);
                  }
                  /*//////////////////////////////////////////////////////////////////////////
                                                   MODULE LOGIC
                  //////////////////////////////////////////////////////////////////////////*/
                  /**
                   * Validates PackedUserOperation
                   *
                   * @param userOp UserOperation to be validated
                   * @param userOpHash Hash of the UserOperation to be validated
                   * @dev fallback flow => non MEE flow => no dedicated prefix introduced for the sake of compatibility.
                   *      It may lead to a case where some signature turns out to have first bytes matching the prefix.
                   *      However, this is very unlikely to happen and even if it does, the consequences are just
                   *      that the signature is not validated which is easily solved by altering userOp => hash => sig.
                   *
                   * @return uint256 the result of the signature validation, which can be:
                   *  - 0 if the signature is valid
                   *  - 1 if the signature is invalid
                   *  - <20-byte> aggregatorOrSigFail, <6-byte> validUntil and <6-byte> validAfter (see ERC-4337
                   * for more details)
                   */
                  function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash)
                      external
                      override
                      returns (uint256)
                  {
                      bytes4 sigType = bytes4(userOp.signature[0:4]);
                      address owner = getOwner(userOp.sender);
                      if (sigType == SIG_TYPE_SIMPLE) {
                          return SimpleValidatorLib.validateUserOp(userOpHash, userOp.signature[4:], owner);
                      } else if (sigType == SIG_TYPE_ON_CHAIN) {
                          return TxValidatorLib.validateUserOp(userOpHash, userOp.signature[4:], owner);
                      } else if (sigType == SIG_TYPE_ERC20_PERMIT) {
                          return PermitValidatorLib.validateUserOp(userOpHash, userOp.signature[4:], owner);
                      } else {
                          // fallback flow => non MEE flow => no prefix
                          return NoMeeFlowLib.validateUserOp(userOpHash, userOp.signature, owner);
                      }
                  }
                  /**
                   * Validates an ERC-1271 signature
                   *
                   * @param sender The sender of the ERC-1271 call to the account
                   * @param hash The hash of the message
                   * @param signature The signature of the message
                   *
                   * @return sigValidationResult the result of the signature validation, which can be:
                   *  - EIP1271_SUCCESS if the signature is valid
                   *  - EIP1271_FAILED if the signature is invalid
                   */
                  function isValidSignatureWithSender(address sender, bytes32 hash, bytes calldata signature)
                      external
                      view
                      virtual
                      override
                      returns (bytes4 sigValidationResult)
                  {
                      if (bytes3(signature[0:3]) != SIG_TYPE_MEE_FLOW) {
                          // Non MEE 7739 flow
                          // goes to ERC7739Validator to apply 7739 magic and then returns back
                          // to this contract's _erc1271IsValidSignatureNowCalldata() method.
                          return _erc1271IsValidSignatureWithSender(sender, hash, _erc1271UnwrapSignature(signature));
                      } else {
                          // non-7739 flow
                          // hash the SA into the `hash` to protect against two SA's with same owner vector
                          return _validateSignatureForOwner(
                              getOwner(msg.sender), keccak256(abi.encodePacked(hash, msg.sender)), _erc1271UnwrapSignature(signature)
                          ) ? EIP1271_SUCCESS : EIP1271_FAILED;
                      }
                  }
                  /// @notice ISessionValidator interface for smart session
                  /// @param hash The hash of the data to validate
                  /// @param sig The signature data
                  /// @param data The data to validate against (owner address in this case)
                  function validateSignatureWithData(bytes32 hash, bytes calldata sig, bytes calldata data)
                      external
                      view
                      returns (bool validSig)
                  {
                      require(data.length >= 20, InvalidDataLength());
                      return _validateSignatureForOwner(address(bytes20(data[:20])), hash, sig);
                  }
                  /**
                   * Get the owner of the smart account
                   * @param smartAccount The address of the smart account
                   * @return The owner of the smart account
                   */
                  function getOwner(address smartAccount) public view returns (address) {
                      address owner = smartAccountOwners[smartAccount];
                      return owner == address(0) ? smartAccount : owner;
                  }
                  /*//////////////////////////////////////////////////////////////////////////
                                                   METADATA
                  //////////////////////////////////////////////////////////////////////////*/
                  /// @notice Returns the name of the module
                  /// @return The name of the module
                  function name() external pure returns (string memory) {
                      return "K1MeeValidator";
                  }
                  /// @notice Returns the version of the module
                  /// @return The version of the module
                  function version() external pure returns (string memory) {
                      return "1.0.1";
                  }
                  /// @notice Checks if the module is of the specified type
                  /// @param typeId The type ID to check
                  /// @return True if the module is of the specified type, false otherwise
                  function isModuleType(uint256 typeId) external pure returns (bool) {
                      return typeId == MODULE_TYPE_VALIDATOR || typeId == MODULE_TYPE_STATELESS_VALIDATOR;
                  }
                  /*//////////////////////////////////////////////////////////////////////////
                                                   INTERNAL
                  //////////////////////////////////////////////////////////////////////////*/
                  /// @notice Internal method that does the job of validating the signature via ECDSA (secp256k1)
                  /// @param owner The address of the owner
                  /// @param hash The hash of the data to validate
                  /// @param signature The signature data
                  function _validateSignatureForOwner(address owner, bytes32 hash, bytes calldata signature)
                      internal
                      view
                      returns (bool)
                  {
                      bytes4 sigType = bytes4(signature[0:4]);
                      if (sigType == SIG_TYPE_SIMPLE) {
                          return SimpleValidatorLib.validateSignatureForOwner(owner, hash, signature[4:]);
                      } else if (sigType == SIG_TYPE_ON_CHAIN) {
                          return TxValidatorLib.validateSignatureForOwner(owner, hash, signature[4:]);
                      } else if (sigType == SIG_TYPE_ERC20_PERMIT) {
                          return PermitValidatorLib.validateSignatureForOwner(owner, hash, signature[4:]);
                      } else {
                          // fallback flow => non MEE flow => no prefix
                          return NoMeeFlowLib.validateSignatureForOwner(owner, hash, signature);
                      }
                  }
                  /// @notice Checks if the smart account is initialized with an owner
                  /// @param smartAccount The address of the smart account
                  /// @return True if the smart account has an owner, false otherwise
                  function _isInitialized(address smartAccount) private view returns (bool) {
                      return smartAccountOwners[smartAccount] != address(0);
                  }
                  // @notice Fills the _safeSenders list from the given data
                  function _fillSafeSenders(bytes calldata data) private {
                      require(data.length % 20 == 0, SafeSendersLengthInvalid());
                      for (uint256 i; i < data.length / 20; i++) {
                          _safeSenders.add(msg.sender, address(bytes20(data[20 * i:20 * (i + 1)])));
                      }
                  }
                  /// @notice Checks if the address is a contract
                  /// @param account The address to check
                  /// @return True if the address is a contract, false otherwise
                  function _isContract(address account) private view returns (bool) {
                      uint256 size;
                      assembly {
                          size := extcodesize(account)
                      }
                      return size > 0;
                  }
                  /// @dev Returns whether the `hash` and `signature` are valid.
                  ///      Obtains the authorized signer's credentials and calls some
                  ///      module's specific internal function to validate the signature
                  ///      against credentials.
                  function _erc1271IsValidSignatureNowCalldata(bytes32 hash, bytes calldata signature)
                      internal
                      view
                      override
                      returns (bool)
                  {
                      // call custom internal function to validate the signature against credentials
                      return EcdsaLib.isValidSignature(getOwner(msg.sender), hash, signature);
                  }
                  /// @dev Returns whether the `sender` is considered safe, such
                  /// that we don't need to use the nested EIP-712 workflow.
                  /// See: https://mirror.xyz/curiousapple.eth/pFqAdW2LiJ-6S4sg_u1z08k4vK6BCJ33LcyXpnNb8yU
                  // The canonical `MulticallerWithSigner` at 0x000000000000D9ECebf3C23529de49815Dac1c4c
                  // is known to include the account in the hash to be signed.
                  // msg.sender = Smart Account
                  // sender = 1271 og request sender
                  function _erc1271CallerIsSafe(address sender) internal view virtual override returns (bool) {
                      return (
                          sender == 0x000000000000D9ECebf3C23529de49815Dac1c4c // MulticallerWithSigner
                              || sender == msg.sender // Smart Account. Assume smart account never sends non safe eip-712 struct
                              || _safeSenders.contains(msg.sender, sender)
                      ); // check if sender is in _safeSenders for the Smart Account
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.21;
              import { PackedUserOperation } from "account-abstraction/interfaces/PackedUserOperation.sol";
              uint256 constant VALIDATION_SUCCESS = 0;
              uint256 constant VALIDATION_FAILED = 1;
              uint256 constant MODULE_TYPE_VALIDATOR = 1;
              uint256 constant MODULE_TYPE_EXECUTOR = 2;
              uint256 constant MODULE_TYPE_FALLBACK = 3;
              uint256 constant MODULE_TYPE_HOOK = 4;
              uint256 constant MODULE_TYPE_PREVALIDATION_HOOK_ERC1271 = 8;
              uint256 constant MODULE_TYPE_PREVALIDATION_HOOK_ERC4337 = 9;
              interface IModule {
                  error AlreadyInitialized(address smartAccount);
                  error NotInitialized(address smartAccount);
                  /**
                   * @dev This function is called by the smart account during installation of the module
                   * @param data arbitrary data that may be required on the module during `onInstall`
                   * initialization
                   *
                   * MUST revert on error (i.e. if module is already enabled)
                   */
                  function onInstall(bytes calldata data) external;
                  /**
                   * @dev This function is called by the smart account during uninstallation of the module
                   * @param data arbitrary data that may be required on the module during `onUninstall`
                   * de-initialization
                   *
                   * MUST revert on error
                   */
                  function onUninstall(bytes calldata data) external;
                  /**
                   * @dev Returns boolean value if module is a certain type
                   * @param moduleTypeId the module type ID according the ERC-7579 spec
                   *
                   * MUST return true if the module is of the given type and false otherwise
                   */
                  function isModuleType(uint256 moduleTypeId) external view returns (bool);
                  /**
                   * @dev Returns if the module was already initialized for a provided smartaccount
                   */
                  function isInitialized(address smartAccount) external view returns (bool);
              }
              interface IValidator is IModule {
                  error InvalidTargetAddress(address target);
                  /**
                   * @dev Validates a transaction on behalf of the account.
                   *         This function is intended to be called by the MSA during the ERC-4337 validaton phase
                   *         Note: solely relying on bytes32 hash and signature is not suffcient for some
                   * validation implementations (i.e. SessionKeys often need access to userOp.calldata)
                   * @param userOp The user operation to be validated. The userOp MUST NOT contain any metadata.
                   * The MSA MUST clean up the userOp before sending it to the validator.
                   * @param userOpHash The hash of the user operation to be validated
                   * @return return value according to ERC-4337
                   */
                  function validateUserOp(
                      PackedUserOperation calldata userOp,
                      bytes32 userOpHash
                  )
                      external
                      returns (uint256);
                  /**
                   * Validator can be used for ERC-1271 validation
                   */
                  function isValidSignatureWithSender(
                      address sender,
                      bytes32 hash,
                      bytes calldata data
                  )
                      external
                      view
                      returns (bytes4);
              }
              interface IExecutor is IModule { }
              interface IHook is IModule {
                  function preCheck(
                      address msgSender,
                      uint256 msgValue,
                      bytes calldata msgData
                  )
                      external
                      returns (bytes memory hookData);
                  function postCheck(bytes calldata hookData) external;
              }
              interface IFallback is IModule { }
              interface IPreValidationHookERC1271 is IModule {
                  function preValidationHookERC1271(
                      address sender,
                      bytes32 hash,
                      bytes calldata data
                  )
                      external
                      view
                      returns (bytes32 hookHash, bytes memory hookSignature);
              }
              interface IPreValidationHookERC4337 is IModule {
                  function preValidationHookERC4337(
                      PackedUserOperation calldata userOp,
                      uint256 missingAccountFunds,
                      bytes32 userOpHash
                  )
                      external
                      returns (bytes32 hookHash, bytes memory hookSignature);
              }
              // SPDX-License-Identifier: LGPL-3.0-only
              pragma solidity ^0.8.23;
              import {IModule} from "erc7579/interfaces/IERC7579Module.sol";
              uint256 constant ERC7579_MODULE_TYPE_STATELESS_VALIDATOR = 7;
              /**
               * ISessionValidator is a contract that validates signatures for a given session.
               * this interface expects to validate the signature in a stateless way.
               * all parameters required to validate the signature are passed in the function call.
               * Only one ISessionValidator is responsible to validate a userOp.
               * if you want to use multiple validators, you can create a ISessionValidator that aggregates multiple signatures that
               * are packed into userOp.signature
               * It is used to validate the signature of a session.
               *  hash The userOp hash
               *  sig The signature of userOp
               *  data the config data that is used to validate the signature
               */
              interface ISessionValidator is IModule {
                  function validateSignatureWithData(bytes32 hash, bytes calldata sig, bytes calldata data)
                      external
                      view
                      returns (bool validSig);
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.20;
              import "./AssociatedArrayLib.sol";
              /**
               * Fork of OZ's EnumerableSet that makes all storage access ERC-4337 compliant via associated storage
               * @author zeroknots.eth (rhinestone)
               */
              library EnumerableSet {
                  using AssociatedArrayLib for AssociatedArrayLib.Bytes32Array;
                  // To implement this library for multiple types with as little code
                  // repetition as possible, we write it in terms of a generic Set type with
                  // bytes32 values.
                  // The Set implementation uses private functions, and user-facing
                  // implementations (such as AddressSet) are just wrappers around the
                  // underlying Set.
                  // This means that we can only create new EnumerableSets for types that fit
                  // in bytes32.
                  struct Set {
                      // Storage of set values
                      AssociatedArrayLib.Bytes32Array _values;
                      // Position is the index of the value in the `values` array plus 1.
                      // Position 0 is used to mean a value is not in the set.
                      mapping(bytes32 value => mapping(address account => uint256)) _positions;
                  }
                  /**
                   * @dev Add a value to a set. O(1).
                   *
                   * Returns true if the value was added to the set, that is if it was not
                   * already present.
                   */
                  function _add(Set storage set, address account, bytes32 value) private returns (bool) {
                      if (!_contains(set, account, value)) {
                          set._values.push(account, value);
                          // The value is stored at length-1, but we add 1 to all indexes
                          // and use 0 as a sentinel value
                          set._positions[value][account] = set._values.length(account);
                          return true;
                      } else {
                          return false;
                      }
                  }
                  /**
                   * @dev Removes a value from a set. O(1).
                   *
                   * Returns true if the value was removed from the set, that is if it was
                   * present.
                   */
                  function _remove(Set storage set, address account, bytes32 value) private returns (bool) {
                      // We cache the value's position to prevent multiple reads from the same storage slot
                      uint256 position = set._positions[value][account];
                      if (position != 0) {
                          // Equivalent to contains(set, value)
                          // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
                          // the array, and then remove the last element (sometimes called as 'swap and pop').
                          // This modifies the order of the array, as noted in {at}.
                          uint256 valueIndex = position - 1;
                          uint256 lastIndex = set._values.length(account) - 1;
                          if (valueIndex != lastIndex) {
                              bytes32 lastValue = set._values.get(account, lastIndex);
                              // Move the lastValue to the index where the value to delete is
                              set._values.set(account, valueIndex, lastValue);
                              // Update the tracked position of the lastValue (that was just moved)
                              set._positions[lastValue][account] = position;
                          }
                          // Delete the slot where the moved value was stored
                          set._values.pop(account);
                          // Delete the tracked position for the deleted slot
                          delete set._positions[value][account];
                          return true;
                      } else {
                          return false;
                      }
                  }
                  function _removeAll(Set storage set, address account) internal {
                      // get length of the array
                      uint256 len = _length(set, account);
                      for (uint256 i = 1; i <= len; i++) {
                          // get last value
                          bytes32 value = _at(set, account, len - i);
                          _remove(set, account, value);
                      }
                  }
                  /**
                   * @dev Returns true if the value is in the set. O(1).
                   */
                  function _contains(Set storage set, address account, bytes32 value) private view returns (bool) {
                      return set._positions[value][account] != 0;
                  }
                  /**
                   * @dev Returns the number of values on the set. O(1).
                   */
                  function _length(Set storage set, address account) private view returns (uint256) {
                      return set._values.length(account);
                  }
                  /**
                   * @dev Returns the value stored at position `index` in the set. O(1).
                   *
                   * Note that there are no guarantees on the ordering of values inside the
                   * array, and it may change when more values are added or removed.
                   *
                   * Requirements:
                   *
                   * - `index` must be strictly less than {length}.
                   */
                  function _at(Set storage set, address account, uint256 index) private view returns (bytes32) {
                      return set._values.get(account, index);
                  }
                  /**
                   * @dev Return the entire set in an array
                   *
                   * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
                   * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
                   * this function has an unbounded cost, and using it as part of a state-changing function may render the function
                   * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
                   */
                  function _values(Set storage set, address account) private view returns (bytes32[] memory) {
                      return set._values.getAll(account);
                  }
                  // Bytes32Set
                  struct Bytes32Set {
                      Set _inner;
                  }
                  /**
                   * @dev Add a value to a set. O(1).
                   *
                   * Returns true if the value was added to the set, that is if it was not
                   * already present.
                   */
                  function add(Bytes32Set storage set, address account, bytes32 value) internal returns (bool) {
                      return _add(set._inner, account, value);
                  }
                  /**
                   * @dev Removes a value from a set. O(1).
                   *
                   * Returns true if the value was removed from the set, that is if it was
                   * present.
                   */
                  function remove(Bytes32Set storage set, address account, bytes32 value) internal returns (bool) {
                      return _remove(set._inner, account, value);
                  }
                  function removeAll(Bytes32Set storage set, address account) internal {
                      return _removeAll(set._inner, account);
                  }
                  /**
                   * @dev Returns true if the value is in the set. O(1).
                   */
                  function contains(Bytes32Set storage set, address account, bytes32 value) internal view returns (bool) {
                      return _contains(set._inner, account, value);
                  }
                  /**
                   * @dev Returns the number of values in the set. O(1).
                   */
                  function length(Bytes32Set storage set, address account) internal view returns (uint256) {
                      return _length(set._inner, account);
                  }
                  /**
                   * @dev Returns the value stored at position `index` in the set. O(1).
                   *
                   * Note that there are no guarantees on the ordering of values inside the
                   * array, and it may change when more values are added or removed.
                   *
                   * Requirements:
                   *
                   * - `index` must be strictly less than {length}.
                   */
                  function at(Bytes32Set storage set, address account, uint256 index) internal view returns (bytes32) {
                      return _at(set._inner, account, index);
                  }
                  /**
                   * @dev Return the entire set in an array
                   *
                   * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
                   * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
                   * this function has an unbounded cost, and using it as part of a state-changing function may render the function
                   * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
                   */
                  function values(Bytes32Set storage set, address account) internal view returns (bytes32[] memory) {
                      bytes32[] memory store = _values(set._inner, account);
                      bytes32[] memory result;
                      /// @solidity memory-safe-assembly
                      assembly {
                          result := store
                      }
                      return result;
                  }
                  // AddressSet
                  struct AddressSet {
                      Set _inner;
                  }
                  /**
                   * @dev Add a value to a set. O(1).
                   *
                   * Returns true if the value was added to the set, that is if it was not
                   * already present.
                   */
                  function add(AddressSet storage set, address account, address value) internal returns (bool) {
                      return _add(set._inner, account, bytes32(uint256(uint160(value))));
                  }
                  /**
                   * @dev Removes a value from a set. O(1).
                   *
                   * Returns true if the value was removed from the set, that is if it was
                   * present.
                   */
                  function remove(AddressSet storage set, address account, address value) internal returns (bool) {
                      return _remove(set._inner, account, bytes32(uint256(uint160(value))));
                  }
                  function removeAll(AddressSet storage set, address account) internal {
                      return _removeAll(set._inner, account);
                  }
                  /**
                   * @dev Returns true if the value is in the set. O(1).
                   */
                  function contains(AddressSet storage set, address account, address value) internal view returns (bool) {
                      return _contains(set._inner, account, bytes32(uint256(uint160(value))));
                  }
                  /**
                   * @dev Returns the number of values in the set. O(1).
                   */
                  function length(AddressSet storage set, address account) internal view returns (uint256) {
                      return _length(set._inner, account);
                  }
                  /**
                   * @dev Returns the value stored at position `index` in the set. O(1).
                   *
                   * Note that there are no guarantees on the ordering of values inside the
                   * array, and it may change when more values are added or removed.
                   *
                   * Requirements:
                   *
                   * - `index` must be strictly less than {length}.
                   */
                  function at(AddressSet storage set, address account, uint256 index) internal view returns (address) {
                      return address(uint160(uint256(_at(set._inner, account, index))));
                  }
                  /**
                   * @dev Return the entire set in an array
                   *
                   * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
                   * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
                   * this function has an unbounded cost, and using it as part of a state-changing function may render the function
                   * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
                   */
                  function values(AddressSet storage set, address account) internal view returns (address[] memory) {
                      bytes32[] memory store = _values(set._inner, account);
                      address[] memory result;
                      /// @solidity memory-safe-assembly
                      assembly {
                          result := store
                      }
                      return result;
                  }
                  // UintSet
                  struct UintSet {
                      Set _inner;
                  }
                  /**
                   * @dev Add a value to a set. O(1).
                   *
                   * Returns true if the value was added to the set, that is if it was not
                   * already present.
                   */
                  function add(UintSet storage set, address account, uint256 value) internal returns (bool) {
                      return _add(set._inner, account, bytes32(value));
                  }
                  /**
                   * @dev Removes a value from a set. O(1).
                   *
                   * Returns true if the value was removed from the set, that is if it was
                   * present.
                   */
                  function remove(UintSet storage set, address account, uint256 value) internal returns (bool) {
                      return _remove(set._inner, account, bytes32(value));
                  }
                  function removeAll(UintSet storage set, address account) internal {
                      return _removeAll(set._inner, account);
                  }
                  /**
                   * @dev Returns true if the value is in the set. O(1).
                   */
                  function contains(UintSet storage set, address account, uint256 value) internal view returns (bool) {
                      return _contains(set._inner, account, bytes32(value));
                  }
                  /**
                   * @dev Returns the number of values in the set. O(1).
                   */
                  function length(UintSet storage set, address account) internal view returns (uint256) {
                      return _length(set._inner, account);
                  }
                  /**
                   * @dev Returns the value stored at position `index` in the set. O(1).
                   *
                   * Note that there are no guarantees on the ordering of values inside the
                   * array, and it may change when more values are added or removed.
                   *
                   * Requirements:
                   *
                   * - `index` must be strictly less than {length}.
                   */
                  function at(UintSet storage set, address account, uint256 index) internal view returns (uint256) {
                      return uint256(_at(set._inner, account, index));
                  }
                  /**
                   * @dev Return the entire set in an array
                   *
                   * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
                   * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
                   * this function has an unbounded cost, and using it as part of a state-changing function may render the function
                   * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
                   */
                  function values(UintSet storage set, address account) internal view returns (uint256[] memory) {
                      bytes32[] memory store = _values(set._inner, account);
                      uint256[] memory result;
                      /// @solidity memory-safe-assembly
                      assembly {
                          result := store
                      }
                      return result;
                  }
              }
              // SPDX-License-Identifier: GPL-3.0
              pragma solidity >=0.7.5;
              /**
               * User Operation struct
               * @param sender                - The sender account of this request.
               * @param nonce                 - Unique value the sender uses to verify it is not a replay.
               * @param initCode              - If set, the account contract will be created by this constructor/
               * @param callData              - The method call to execute on this account.
               * @param accountGasLimits      - Packed gas limits for validateUserOp and gas limit passed to the callData method call.
               * @param preVerificationGas    - Gas not calculated by the handleOps method, but added to the gas paid.
               *                                Covers batch overhead.
               * @param gasFees               - packed gas fields maxPriorityFeePerGas and maxFeePerGas - Same as EIP-1559 gas parameters.
               * @param paymasterAndData      - If set, this field holds the paymaster address, verification gas limit, postOp gas limit and paymaster-specific extra data
               *                                The paymaster will pay for the transaction instead of the sender.
               * @param signature             - Sender-verified signature over the entire request, the EntryPoint address and the chain ID.
               */
              struct PackedUserOperation {
                  address sender;
                  uint256 nonce;
                  bytes initCode;
                  bytes callData;
                  bytes32 accountGasLimits;
                  uint256 preVerificationGas;
                  bytes32 gasFees;
                  bytes paymasterAndData;
                  bytes signature;
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.27;
              interface IERC5267 {
                  function eip712Domain() external view returns (
                      bytes1 fields,
                      string memory name,
                      string memory version,
                      uint256 chainId,
                      address verifyingContract,
                      bytes32 salt,
                      uint256[] memory extensions
                  );
              }
              /// @title ERC-7739: Nested Typed Data Sign Support for ERC-7579 Validators
              abstract contract ERC7739Validator {
                  error InvalidSignature();
                  
                  /// @dev `keccak256("PersonalSign(bytes prefixed)")`.
                  bytes32 internal constant _PERSONAL_SIGN_TYPEHASH = 0x983e65e5148e570cd828ead231ee759a8d7958721a768f93bc4483ba005c32de;
                  bytes32 internal constant _DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;
                  bytes4 internal constant SUPPORTS_ERC7739_V1 = 0x77390001;
                  /*//////////////////////////////////////////////////////////////////////////
                                                   INTERNAL
                  //////////////////////////////////////////////////////////////////////////*/
                  /// @dev Returns whether the `signature` is valid for the `hash.
                  /// Use this in your validator's `isValidSignatureWithSender` implementation.
                  function _erc1271IsValidSignatureWithSender(address sender, bytes32 hash, bytes calldata signature)
                      internal
                      view
                      virtual
                      returns (bytes4)
                  {   
                      // detection request
                      // this check only takes 17 gas units
                      // in theory, it can be moved out of this function so it doesn't apply to every
                      // isValidSignatureWithSender() call, but it would require an additional standard
                      // interface for SA to check if the IValidator supports ERC-7739
                      // while isValidSignatureWithSender() is specified by ERC-7579, so
                      // it makes sense to use it in SA to check if the validator supports ERC-7739
                      unchecked {
                          if (signature.length == uint256(0)) {
                              // Forces the compiler to optimize for smaller bytecode size.
                              if (uint256(hash) == ~signature.length / 0xffff * 0x7739) 
                                  return SUPPORTS_ERC7739_V1;
                          }
                      }
                      // sig malleability prevention
                      bytes32 s;
                      assembly {
                          // same as `s := mload(add(signature, 0x40))` but for calldata
                          s := calldataload(add(signature.offset, 0x20))
                      }
                      if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
                          revert InvalidSignature();
                      }
                      bool success = _erc1271IsValidSignatureViaSafeCaller(sender, hash, signature)
                          || _erc1271IsValidSignatureViaNestedEIP712(hash, signature)
                          || _erc1271IsValidSignatureViaRPC(hash, signature);
                      bytes4 sigValidationResult;
                      assembly {
                          // `success ? bytes4(keccak256("isValidSignature(bytes32,bytes)")) : 0xffffffff`.
                          // We use `0xffffffff` for invalid, in convention with the reference implementation.
                          sigValidationResult := shl(224, or(0x1626ba7e, sub(0, iszero(success))))
                      }
                      return sigValidationResult;
                  }
                  /// @dev Returns whether the `msg.sender` is considered safe, such
                  /// that we don't need to use the nested EIP-712 workflow.
                  /// Override to return true for more callers.
                  /// See: https://mirror.xyz/curiousapple.eth/pFqAdW2LiJ-6S4sg_u1z08k4vK6BCJ33LcyXpnNb8yU
                  function _erc1271CallerIsSafe(address sender) internal view virtual returns (bool) {
                      // The canonical `MulticallerWithSigner` at 0x000000000000D9ECebf3C23529de49815Dac1c4c
                      // is known to include the account in the hash to be signed.
                      return sender == 0x000000000000D9ECebf3C23529de49815Dac1c4c;
                  }
                  /// @dev Returns whether the `hash` and `signature` are valid.
                  ///      Obtains the authorized signer's credentials and calls some
                  ///      module's specific internal function to validate the signature
                  ///      against credentials.
                  /// Override for your module's custom logic.
                  function _erc1271IsValidSignatureNowCalldata(bytes32 hash, bytes calldata signature)
                      internal
                      view
                      virtual
                      returns (bool);
                  /// @dev Unwraps and returns the signature.
                  function _erc1271UnwrapSignature(bytes calldata signature)
                      internal
                      view
                      virtual
                      returns (bytes calldata result)
                  {
                      result = signature;
                      /// @solidity memory-safe-assembly
                      assembly {
                          // Unwraps the ERC6492 wrapper if it exists.
                          // See: https://eips.ethereum.org/EIPS/eip-6492
                          if eq(
                              calldataload(add(result.offset, sub(result.length, 0x20))),
                              mul(0x6492, div(not(shr(address(), address())), 0xffff)) // `0x6492...6492`.
                          ) {
                              let o := add(result.offset, calldataload(add(result.offset, 0x40)))
                              result.length := calldataload(o)
                              result.offset := add(o, 0x20)
                          }
                      }
                  }
                  /// @dev Performs the signature validation without nested EIP-712 if the caller is
                  /// a safe caller. A safe caller must include the address of this account in the hash.
                  function _erc1271IsValidSignatureViaSafeCaller(address sender, bytes32 hash, bytes calldata signature)
                      internal
                      view
                      virtual
                      returns (bool result)
                  {
                      if (_erc1271CallerIsSafe(sender)) result = _erc1271IsValidSignatureNowCalldata(hash, signature);
                  }
                  /// @dev ERC1271 signature validation (Nested EIP-712 workflow).
                  ///
                  /// This uses ECDSA recovery by default (see: `_erc1271IsValidSignatureNowCalldata`).
                  /// It also uses a nested EIP-712 approach to prevent signature replays when a single EOA
                  /// owns multiple smart contract accounts,
                  /// while still enabling wallet UIs (e.g. Metamask) to show the EIP-712 values.
                  ///
                  /// Crafted for phishing resistance, efficiency, flexibility.
                  /// __________________________________________________________________________________________
                  ///
                  /// Glossary:
                  ///
                  /// - `APP_DOMAIN_SEPARATOR`: The domain separator of the `hash` passed in by the application.
                  ///   Provided by the front end. Intended to be the domain separator of the contract
                  ///   that will call `isValidSignature` on this account.
                  ///
                  /// - `ACCOUNT_DOMAIN_SEPARATOR`: The domain separator of this account.
                  ///   See: `EIP712._domainSeparator()`.
                  /// __________________________________________________________________________________________
                  ///
                  /// For the `TypedDataSign` workflow, the final hash will be:
                  /// ```
                  ///     keccak256(\\x19\\x01 ‖ APP_DOMAIN_SEPARATOR ‖
                  ///         hashStruct(TypedDataSign({
                  ///             contents: hashStruct(originalStruct),
                  ///             name: keccak256(bytes(eip712Domain().name)),
                  ///             version: keccak256(bytes(eip712Domain().version)),
                  ///             chainId: eip712Domain().chainId,
                  ///             verifyingContract: eip712Domain().verifyingContract,
                  ///             salt: eip712Domain().salt
                  ///         }))
                  ///     )
                  /// ```
                  /// where `‖` denotes the concatenation operator for bytes.
                  /// The order of the fields is important: `contents` comes before `name`.
                  ///
                  /// The signature will be `r ‖ s ‖ v ‖ APP_DOMAIN_SEPARATOR ‖
                  ///     contents ‖ contentsDescription ‖ uint16(contentsDescription.length)`,
                  /// where:
                  /// - `contents` is the bytes32 struct hash of the original struct.
                  /// - `contentsDescription` can be either:
                  ///     a) `contentsType` (implicit mode)
                  ///         where `contentsType` starts with `contentsName`.
                  ///     b) `contentsType ‖ contentsName` (explicit mode)
                  ///         where `contentsType` may not necessarily start with `contentsName`.
                  ///
                  /// The `APP_DOMAIN_SEPARATOR` and `contents` will be used to verify if `hash` is indeed correct.
                  /// __________________________________________________________________________________________
                  ///
                  /// For the `PersonalSign` workflow, the final hash will be:
                  /// ```
                  ///     keccak256(\\x19\\x01 ‖ ACCOUNT_DOMAIN_SEPARATOR ‖
                  ///         hashStruct(PersonalSign({
                  ///             prefixed: keccak256(bytes(\\x19Ethereum Signed Message:\
               ‖
                  ///                 base10(bytes(someString).length) ‖ someString))
                  ///         }))
                  ///     )
                  /// ```
                  /// where `‖` denotes the concatenation operator for bytes.
                  ///
                  /// The `PersonalSign` type hash will be `keccak256("PersonalSign(bytes prefixed)")`.
                  /// The signature will be `r ‖ s ‖ v`.
                  /// __________________________________________________________________________________________
                  ///
                  /// For demo and typescript code, see:
                  /// - https://github.com/junomonster/nested-eip-712
                  /// - https://github.com/frangio/eip712-wrapper-for-eip1271
                  ///
                  /// Their nomenclature may differ from ours, although the high-level idea is similar.
                  ///
                  /// Of course, if you have control over the codebase of the wallet client(s) too,
                  /// you can choose a more minimalistic signature scheme like
                  /// `keccak256(abi.encode(address(this), hash))` instead of all these acrobatics.
                  /// All these are just for widespread out-of-the-box compatibility with other wallet clients.
                  /// We want to create bazaars, not walled castles.
                  /// And we'll use push the Turing Completeness of the EVM to the limits to do so.
                  function _erc1271IsValidSignatureViaNestedEIP712(bytes32 hash, bytes calldata signature)
                      internal
                      view
                      virtual
                      returns (bool result)
                  {
                      //bytes32 t = _typedDataSignFieldsForAccount(msg.sender);
                      uint256 t = uint256(uint160(address(this)));
                      // Forces the compiler to pop the variables after the scope, avoiding stack-too-deep.
                      if (t != uint256(0)) {
                          (
                              ,
                              string memory name,
                              string memory version,
                              uint256 chainId,
                              address verifyingContract,
                              bytes32 salt,
                          ) = IERC5267(msg.sender).eip712Domain();
                          /// @solidity memory-safe-assembly
                          assembly {
                              t := mload(0x40) // Grab the free memory pointer.
                              // Skip 2 words for the `typedDataSignTypehash` and `contents` struct hash.
                              mstore(add(t, 0x40), keccak256(add(name, 0x20), mload(name)))
                              mstore(add(t, 0x60), keccak256(add(version, 0x20), mload(version)))
                              mstore(add(t, 0x80), chainId)
                              mstore(add(t, 0xa0), shr(96, shl(96, verifyingContract)))
                              mstore(add(t, 0xc0), salt)
                              mstore(0x40, add(t, 0xe0)) // Allocate the memory.
                          }
                      }
                      /// @solidity memory-safe-assembly
                      assembly {
                          let m := mload(0x40) // Cache the free memory pointer.
                          // `c` is `contentsDescription.length`, which is stored in the last 2 bytes of the signature.
                          let c := shr(240, calldataload(add(signature.offset, sub(signature.length, 2))))
                          for {} 1 {} {
                              let l := add(0x42, c) // Total length of appended data (32 + 32 + c + 2).
                              let o := add(signature.offset, sub(signature.length, l)) // Offset of appended data.
                              mstore(0x00, 0x1901) // Store the "\\x19\\x01" prefix.
                              calldatacopy(0x20, o, 0x40) // Copy the `APP_DOMAIN_SEPARATOR` and `contents` struct hash.
                              // Use the `PersonalSign` workflow if the reconstructed hash doesn't match,
                              // or if the appended data is invalid, i.e.
                              // `appendedData.length > signature.length || contentsDescription.length == 0`.
                              if or(xor(keccak256(0x1e, 0x42), hash), or(lt(signature.length, l), iszero(c))) {
                                  t := 0 // Set `t` to 0, denoting that we need to `hash = _hashTypedData(hash)`.
                                  mstore(t, _PERSONAL_SIGN_TYPEHASH)
                                  mstore(0x20, hash) // Store the `prefixed`.
                                  hash := keccak256(t, 0x40) // Compute the `PersonalSign` struct hash.
                                  break
                              }
                              // Else, use the `TypedDataSign` workflow.
                              // `TypedDataSign({ContentsName} contents,string name,...){ContentsType}`.
                              mstore(m, "TypedDataSign(") // Store the start of `TypedDataSign`'s type encoding.
                              let p := add(m, 0x0e) // Advance 14 bytes to skip "TypedDataSign(".
                              
                              calldatacopy(p, add(o, 0x40), c) // Copy `contentsName`, optimistically.
                              mstore(add(p, c), 40) // Store a '(' after the end.
                              if iszero(eq(byte(0, mload(sub(add(p, c), 1))), 41)) {
                                  let e := 0 // Length of `contentsName` in explicit mode.
                                  for { let q := sub(add(p, c), 1) } 1 {} {
                                      e := add(e, 1) // Scan backwards until we encounter a ')'.
                                      if iszero(gt(lt(e, c), eq(byte(0, mload(sub(q, e))), 41))) { break }
                                  }
                                  c := sub(c, e) // Truncate `contentsDescription` to `contentsType`.
                                  calldatacopy(p, add(add(o, 0x40), c), e) // Copy `contentsName`.
                                  mstore8(add(p, e), 40) // Store a '(' exactly right after the end.
                              }
                              // `d & 1 == 1` means that `contentsName` is invalid.
                              let d := shr(byte(0, mload(p)), 0x7fffffe000000000000010000000000) // Starts with `[a-z(]`.
                              // Advance `p` until we encounter '('.
                              for {} iszero(eq(byte(0, mload(p)), 40)) { p := add(p, 1) } {
                                  d := or(shr(byte(0, mload(p)), 0x120100000001), d) // Has a byte in ", )\\x00".
                              }
                              mstore(p, " contents,string name,string") // Store the rest of the encoding.
                              mstore(add(p, 0x1c), " version,uint256 chainId,address")
                              mstore(add(p, 0x3c), " verifyingContract,bytes32 salt)")
                              p := add(p, 0x5c)
                              calldatacopy(p, add(o, 0x40), c) // Copy `contentsType`.
                              // Fill in the missing fields of the `TypedDataSign`.
                              calldatacopy(t, o, 0x40) // Copy the `contents` struct hash to `add(t, 0x20)`.
                              mstore(t, keccak256(m, sub(add(p, c), m))) // Store `typedDataSignTypehash`.
                              // The "\\x19\\x01" prefix is already at 0x00.
                              // `APP_DOMAIN_SEPARATOR` is already at 0x20.
                              mstore(0x40, keccak256(t, 0xe0)) // `hashStruct(typedDataSign)`.
                              // Compute the final hash, corrupted if `contentsName` is invalid.
                              hash := keccak256(0x1e, add(0x42, and(1, d)))
                              signature.length := sub(signature.length, l) // Truncate the signature.
                              break
                          }
                          mstore(0x40, m) // Restore the free memory pointer.
                      }
                      if (t == uint256(0)) hash = _hashTypedDataForAccount(msg.sender, hash); // `PersonalSign` workflow.
                      result = _erc1271IsValidSignatureNowCalldata(hash, signature);
                  }
                  /// @dev Performs the signature validation without nested EIP-712 to allow for easy sign ins.
                  /// This function must always return false or revert if called on-chain.
                  function _erc1271IsValidSignatureViaRPC(bytes32 hash, bytes calldata signature)
                      internal
                      view
                      virtual
                      returns (bool result)
                  {
                      // Non-zero gasprice is a heuristic to check if a call is on-chain,
                      // but we can't fully depend on it because it can be manipulated.
                      // See: https://x.com/NoahCitron/status/1580359718341484544
                      if (tx.gasprice == uint256(0)) {
                          /// @solidity memory-safe-assembly
                          assembly {
                              mstore(gasprice(), gasprice())
                              // See: https://gist.github.com/Vectorized/3c9b63524d57492b265454f62d895f71
                              let b := 0x000000000000378eDCD5B5B0A24f5342d8C10485 // Basefee contract,
                              pop(staticcall(0xffff, b, codesize(), gasprice(), gasprice(), 0x20))
                              // If `gasprice < basefee`, the call cannot be on-chain, and we can skip the gas burn.
                              if iszero(mload(gasprice())) {
                                  let m := mload(0x40) // Cache the free memory pointer.
                                  mstore(gasprice(), 0x1626ba7e) // `isValidSignature(bytes32,bytes)`.
                                  mstore(0x20, b) // Recycle `b` to denote if we need to burn gas.
                                  mstore(0x40, 0x40)
                                  let gasToBurn := or(add(0xffff, gaslimit()), gaslimit())
                                  // Burns gas computationally efficiently. Also, requires that `gas > gasToBurn`.
                                  if or(eq(hash, b), lt(gas(), gasToBurn)) { invalid() }
                                  // Make a call to this with `b`, efficiently burning the gas provided.
                                  // No valid transaction can consume more than the gaslimit.
                                  // See: https://ethereum.github.io/yellowpaper/paper.pdf
                                  // Most RPCs perform calls with a gas budget greater than the gaslimit.
                                  pop(staticcall(gasToBurn, address(), 0x1c, 0x64, gasprice(), gasprice()))
                                  mstore(0x40, m) // Restore the free memory pointer.
                              }
                          }
                          result = _erc1271IsValidSignatureNowCalldata(hash, signature);
                      }
                  }
                  /// @notice Hashes typed data according to eip-712
                  ///         Uses account's domain separator
                  /// @param account the smart account, who's domain separator will be used
                  /// @param structHash the typed data struct hash
                  function _hashTypedDataForAccount(address account, bytes32 structHash) private view returns (bytes32 digest) {
                      (
                          /*bytes1 fields*/,
                          string memory name,
                          string memory version,
                          uint256 chainId,
                          address verifyingContract,
                          /*bytes32 salt*/,
                          /*uint256[] memory extensions*/
                      ) = IERC5267(account).eip712Domain();
                      /// @solidity memory-safe-assembly
                      assembly {
                          //Rebuild domain separator out of 712 domain
                          let m := mload(0x40) // Load the free memory pointer.
                          mstore(m, _DOMAIN_TYPEHASH)
                          mstore(add(m, 0x20), keccak256(add(name, 0x20), mload(name))) // Name hash.
                          mstore(add(m, 0x40), keccak256(add(version, 0x20), mload(version))) // Version hash.
                          mstore(add(m, 0x60), chainId)
                          mstore(add(m, 0x80), verifyingContract)
                          digest := keccak256(m, 0xa0) //domain separator
                          // Hash typed data
                          mstore(0x00, 0x1901000000000000) // Store "\\x19\\x01".
                          mstore(0x1a, digest) // Store the domain separator.
                          mstore(0x3a, structHash) // Store the struct hash.
                          digest := keccak256(0x18, 0x42)
                          // Restore the part of the free memory slot that was overwritten.
                          mstore(0x3a, 0)
                      }
                  }
                  /// @dev Backwards compatibility stuff
                  /// For automatic detection that the smart account supports the nested EIP-712 workflow.
                  /// By default, it returns `bytes32(bytes4(keccak256("supportsNestedTypedDataSign()")))`,
                  /// denoting support for the default behavior, as implemented in
                  /// `_erc1271IsValidSignatureViaNestedEIP712`, which is called in `isValidSignature`.
                  /// Future extensions should return a different non-zero `result` to denote different behavior.
                  /// This method intentionally returns bytes32 to allow freedom for future extensions.
                  function supportsNestedTypedDataSign() public view virtual returns (bytes32 result) {
                      result = bytes4(0xd620c85a);
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.27;
              bytes3 constant SIG_TYPE_MEE_FLOW = 0x177eee;
              bytes4 constant SIG_TYPE_SIMPLE = 0x177eee00;
              bytes4 constant SIG_TYPE_ON_CHAIN = 0x177eee01;
              bytes4 constant SIG_TYPE_ERC20_PERMIT = 0x177eee02;
              // ...other sig types: ERC-7683, Permit2, etc
              bytes4 constant EIP1271_SUCCESS = 0x1626ba7e;
              bytes4 constant EIP1271_FAILED = 0xffffffff;
              uint256 constant MODULE_TYPE_STATELESS_VALIDATOR = 7;
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.27;
              import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
              import {MerkleProof} from "openzeppelin/utils/cryptography/MerkleProof.sol";
              import {EcdsaLib} from "../util/EcdsaLib.sol";
              import {MEEUserOpHashLib} from "../util/MEEUserOpHashLib.sol";
              import {IERC20Permit} from "openzeppelin/token/ERC20/extensions/IERC20Permit.sol";
              import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
              import "account-abstraction/core/Helpers.sol";
              /**
               * @dev Library to validate the signature for MEE ERC-2612 Permit mode
               *      This is the mode where superTx hash is pasted into deadline field of the ERC-2612 Permit
               *      So the whole permit is signed along with the superTx hash
               *      For more details see Fusion docs:
               *      - https://ethresear.ch/t/fusion-module-7702-alternative-with-no-protocol-changes/20949
               *      - https://docs.biconomy.io/explained/eoa#fusion-module
               *
               *      @dev Important: since ERC20 permit token knows nothing about the MEE, it will treat the superTx hash as a deadline:
               *      -  if (very unlikely) the superTx hash being converted to uint256 is a timestamp in the past, the permit will fail
               *      -  the deadline with most superTx hashes will be very far in the future
               *
               *      @dev Since at this point bytes32 superTx hash is a blind hash, users and wallets should pay attention if
               *           the permit2 deadline field does not make sense as the timestamp. In this case, it can be a sign of a
               *           phishing attempt (injecting super txn hash as the deadline) and the user should not sign the permit.
               *           This is going to be mitigated in the future by making superTx hash a EIP-712 hash.
               */
              bytes32 constant PERMIT_TYPEHASH =
                  keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
              struct DecodedErc20PermitSig {
                  IERC20Permit token;
                  address spender;
                  bytes32 domainSeparator;
                  uint256 amount;
                  uint256 nonce;
                  bool isPermitTx;
                  bytes32 superTxHash;
                  uint48 lowerBoundTimestamp;
                  uint48 upperBoundTimestamp;
                  uint8 v;
                  bytes32 r;
                  bytes32 s;
                  bytes32[] proof;
              }
              struct DecodedErc20PermitSigShort {
                  address spender;
                  bytes32 domainSeparator;
                  uint256 amount;
                  uint256 nonce;
                  bytes32 superTxHash;
                  uint8 v;
                  bytes32 r;
                  bytes32 s;
                  bytes32[] proof;
              }
              library PermitValidatorLib {
                  error PermitFailed();
                  uint8 constant EIP_155_MIN_V_VALUE = 37;
                  using MessageHashUtils for bytes32;
                  /**
                   * This function parses the given userOpSignature into a DecodedErc20PermitSig data structure.
                   *
                   * Once parsed, the function will check for two conditions:
                   *      1. is the userOp part of the merkle tree
                   *      2. is the recovered message signer equal to the expected signer?
                   *
                   * NOTES: This function will revert if either of following is met:
                   *    1. the userOpSignature couldn't be abi.decoded into a valid DecodedErc20PermitSig struct as defined in this contract
                   *    2. userOp is not part of the merkle tree
                   *    3. recovered Permit message signer wasn't equal to the expected signer
                   *
                   * The function will also perform the Permit approval on the given token in case the
                   * isPermitTx flag was set to true in the decoded signature struct.
                   *
                   * @param userOpHash UserOp hash being validated.
                   * @param parsedSignature Signature provided as the userOp.signature parameter (minus the prepended tx type byte).
                   * @param expectedSigner Signer expected to be recovered when decoding the ERC20OPermit signature.
                   */
                  function validateUserOp(bytes32 userOpHash, bytes calldata parsedSignature, address expectedSigner)
                      internal
                      returns (uint256)
                  {
                      DecodedErc20PermitSig memory decodedSig = _decodeFullPermitSig(parsedSignature);
                      bytes32 meeUserOpHash = MEEUserOpHashLib.getMEEUserOpHash(
                          userOpHash, decodedSig.lowerBoundTimestamp, decodedSig.upperBoundTimestamp
                      );
                      if (
                          !EcdsaLib.isValidSignature(
                              expectedSigner,
                              _getSignedDataHash(expectedSigner, decodedSig),
                              abi.encodePacked(decodedSig.r, decodedSig.s, uint8(decodedSig.v))
                          )
                      ) {
                          return SIG_VALIDATION_FAILED;
                      }
                      if (!MerkleProof.verify(decodedSig.proof, decodedSig.superTxHash, meeUserOpHash)) {
                          return SIG_VALIDATION_FAILED;
                      }
                      if (decodedSig.isPermitTx) {
                          try decodedSig.token.permit(
                              expectedSigner,
                              decodedSig.spender,
                              decodedSig.amount,
                              uint256(decodedSig.superTxHash),
                              uint8(decodedSig.v),
                              decodedSig.r,
                              decodedSig.s
                          ) {
                              // all good
                          } catch {
                              // check if by some reason this permit was already successfully used (and not spent yet)
                              if (IERC20(address(decodedSig.token)).allowance(expectedSigner, decodedSig.spender) < decodedSig.amount)
                              {
                                  // if the above expectationis not true, revert
                                  revert PermitFailed();
                              }
                          }
                      }
                      return _packValidationData(false, decodedSig.upperBoundTimestamp, decodedSig.lowerBoundTimestamp);
                  }
                  function validateSignatureForOwner(address expectedSigner, bytes32 dataHash, bytes calldata parsedSignature)
                      internal
                      view
                      returns (bool)
                  {
                      DecodedErc20PermitSigShort calldata decodedSig = _decodeShortPermitSig(parsedSignature);
                      if (
                          !EcdsaLib.isValidSignature(
                              expectedSigner,
                              _getSignedDataHash(expectedSigner, decodedSig),
                              abi.encodePacked(decodedSig.r, decodedSig.s, uint8(decodedSig.v))
                          )
                      ) {
                          return false;
                      }
                      if (!MerkleProof.verify(decodedSig.proof, decodedSig.superTxHash, dataHash)) {
                          return false;
                      }
                      return true;
                  }
                  function _decodeFullPermitSig(bytes calldata parsedSignature)
                      private
                      pure
                      returns (DecodedErc20PermitSig calldata decodedSig)
                  {
                      assembly {
                          decodedSig := add(parsedSignature.offset, 0x20)
                      }
                  }
                  function _decodeShortPermitSig(bytes calldata parsedSignature)
                      private
                      pure
                      returns (DecodedErc20PermitSigShort calldata)
                  {
                      DecodedErc20PermitSigShort calldata decodedSig;
                      assembly {
                          decodedSig := add(parsedSignature.offset, 0x20)
                      }
                      return decodedSig;
                  }
                  function _getSignedDataHash(address expectedSigner, DecodedErc20PermitSig memory decodedSig)
                      private
                      pure
                      returns (bytes32)
                  {
                      uint256 deadline = uint256(decodedSig.superTxHash);
                      bytes32 structHash = keccak256(
                          abi.encode(
                              PERMIT_TYPEHASH, expectedSigner, decodedSig.spender, decodedSig.amount, decodedSig.nonce, deadline
                          )
                      );
                      return _hashTypedData(structHash, decodedSig.domainSeparator);
                  }
                  function _getSignedDataHash(address expectedSigner, DecodedErc20PermitSigShort memory decodedSig)
                      private
                      pure
                      returns (bytes32)
                  {
                      uint256 deadline = uint256(decodedSig.superTxHash);
                      bytes32 structHash = keccak256(
                          abi.encode(
                              PERMIT_TYPEHASH, expectedSigner, decodedSig.spender, decodedSig.amount, decodedSig.nonce, deadline
                          )
                      );
                      return _hashTypedData(structHash, decodedSig.domainSeparator);
                  }
                  function _hashTypedData(bytes32 structHash, bytes32 domainSeparator) private pure returns (bytes32) {
                      return MessageHashUtils.toTypedDataHash(domainSeparator, structHash);
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.27;
              import {MerkleProof} from "openzeppelin/utils/cryptography/MerkleProof.sol";
              import {RLPReader as RLPDecoder} from "rlp-reader/RLPReader.sol";
              import {RLPEncoder} from "../rlp/RLPEncoder.sol";
              import {MEEUserOpHashLib} from "../util/MEEUserOpHashLib.sol";
              import {EcdsaLib} from "../util/EcdsaLib.sol";
              import {BytesLib} from "byteslib/BytesLib.sol";
              import "account-abstraction/core/Helpers.sol";
              /**
               * @dev Library to validate the signature for MEE on-chain Txn mode
               *      This is the mode where superTx hash is appended to a regular txn (legacy or 1559) calldata
               *      Type 1 (EIP-2930) transactions are not supported.
               *      The whole txn is signed along with the superTx hash
               *      Txn is executed prior to a superTx, so it can pass some funds from the EOA to the smart account
               *      For more details see Fusion docs:
               *      - https://ethresear.ch/t/fusion-module-7702-alternative-with-no-protocol-changes/20949
               *      - https://docs.biconomy.io/explained/eoa#fusion-module
               *      @dev Some smart contracts may not be able to consume the txn with bytes32 appended to the calldata.
               *           However this is very small subset. One of the cases when it can happen is when the smart contract
               *           is has separate receive() and fallback() functions. Then if a txn is a value transfer, it will
               *           be expected to be consumed by the receive() function. However, if there's bytes32 appended to the calldata,
               *           it will be consumed by the fallback() function which may not be expected. In this case, the provided
               *           contracts/forwarder/Forwarder.sol can be used to 'clear' the bytes32 from the calldata.
               *      @dev In theory, the last 32 bytes of calldata from any transaction by the EOA can be interpreted as
               *           a superTx hash. Even if it was not assumed. This introduces the potential risk of phishing attacks
               *           where the user may unknowingly sign a transaction where the last 32 bytes of the calldata end up
               *           being a superTx hash. However, it is not easy to craft a txn that makes sense for a user and allows
               *           arbitrary bytes32 as last 32 bytes. Thus, wallets and users should be aware of this potential risk
               *           and should not sign txns where the last 32 bytes of the calldata do not belong to the function arguments
               *           and are just appended at the end.
               */
              library TxValidatorLib {
                  uint8 constant LEGACY_TX_TYPE = 0x00;
                  uint8 constant EIP1559_TX_TYPE = 0x02;
                  uint8 constant EIP_155_MIN_V_VALUE = 37;
                  uint8 constant HASH_BYTE_SIZE = 32;
                  uint8 constant TIMESTAMP_BYTE_SIZE = 6;
                  uint8 constant PROOF_ITEM_BYTE_SIZE = 32;
                  uint8 constant ITX_HASH_BYTE_SIZE = 32;
                  using RLPDecoder for RLPDecoder.RLPItem;
                  using RLPDecoder for bytes;
                  using RLPEncoder for uint256;
                  using BytesLib for bytes;
                  struct TxData {
                      uint8 txType;
                      uint8 v;
                      bytes32 r;
                      bytes32 s;
                      bytes32 utxHash;
                      bytes32 superTxHash;
                      bytes32[] proof;
                      uint48 lowerBoundTimestamp;
                      uint48 upperBoundTimestamp;
                  }
                  // To save a bit of gas, not pass timestamps where not needed
                  struct TxDataShort {
                      uint8 txType;
                      uint8 v;
                      bytes32 r;
                      bytes32 s;
                      bytes32 utxHash;
                      bytes32 superTxHash;
                      bytes32[] proof;
                  }
                  struct TxParams {
                      uint256 v;
                      bytes32 r;
                      bytes32 s;
                      bytes callData;
                  }
                  /**
                   * This function parses the given userOpSignature into a valid fully signed EVM transaction.
                   * Once parsed, the function will check for three conditions:
                   *      1. is the userOp part of the superTX merkle tree
                   *      2. is the recovered tx signer equal to the expected signer?
                   *      3. is the given UserOp a part of the merkle tree
                   *
                   * If all the conditions are met - outside contract can be sure that the expected signer has indeed
                   * approved the given hash by performing given on-chain transaction.
                   *
                   * NOTES: This function will revert if either of following is met:
                   *    1. the userOpSignature couldn't be parsed to a valid fully signed EVM transaction
                   *    2. hash couldn't be extracted from the tx.data
                   *    3. extracted hash wasn't equal to the provided expected hash
                   *    4. recovered signer wasn't equal to the expected signer
                   *
                   * @param userOpHash UserOp hash being validated.
                   * @param parsedSignature Signature provided as the userOp.signature parameter (minus the prepended tx type byte).
                   *                        Expecting to receive fully signed serialized EVM transaction here of type 0x00 (LEGACY)
                   *                        or 0x02 (EIP1556).
                   *                        For LEGACY tx type the "0x00" prefix has to be added manually while the EIP1559 tx type
                   *                        already contains 0x02 prefix.
                   * @param expectedSigner Expected EOA signer of the given EVM transaction => superTX.
                   */
                  function validateUserOp(bytes32 userOpHash, bytes calldata parsedSignature, address expectedSigner)
                      internal
                      view
                      returns (uint256)
                  {
                      TxData memory decodedTx = decodeTx(parsedSignature);
                      bytes32 meeUserOpHash =
                          MEEUserOpHashLib.getMEEUserOpHash(userOpHash, decodedTx.lowerBoundTimestamp, decodedTx.upperBoundTimestamp);
                      bytes memory signature = abi.encodePacked(decodedTx.r, decodedTx.s, decodedTx.v);
                      if (!EcdsaLib.isValidSignature(expectedSigner, decodedTx.utxHash, signature)) {
                          return SIG_VALIDATION_FAILED;
                      }
                      if (!MerkleProof.verify(decodedTx.proof, decodedTx.superTxHash, meeUserOpHash)) {
                          return SIG_VALIDATION_FAILED;
                      }
                      return _packValidationData(false, decodedTx.upperBoundTimestamp, decodedTx.lowerBoundTimestamp);
                  }
                  /**
                   * @dev validate the signature for the owner of the superTx
                   *      used fot the 1271 flow and for the stateless validators (erc7579 module type 7)
                   * @param expectedSigner the expected signer of the superTx
                   * @param dataHash the hash of the data to be signed
                   * @param parsedSignature the signature to be validated
                   * @return true if the signature is valid, false otherwise
                   */
                  function validateSignatureForOwner(address expectedSigner, bytes32 dataHash, bytes calldata parsedSignature)
                      internal
                      view
                      returns (bool)
                  {
                      TxDataShort memory decodedTx = decodeTxShort(parsedSignature);
                      bytes memory signature = abi.encodePacked(decodedTx.r, decodedTx.s, decodedTx.v);
                      if (!EcdsaLib.isValidSignature(expectedSigner, decodedTx.utxHash, signature)) {
                          return false;
                      }
                      if (!MerkleProof.verify(decodedTx.proof, decodedTx.superTxHash, dataHash)) {
                          return false;
                      }
                      return true;
                  }
                  function decodeTx(bytes calldata self) internal pure returns (TxData memory) {
                      uint8 txType = uint8(self[0]); //first byte is tx type
                      uint48 lowerBoundTimestamp =
                          uint48(bytes6((self[self.length - 2 * TIMESTAMP_BYTE_SIZE:self.length - TIMESTAMP_BYTE_SIZE])));
                      uint48 upperBoundTimestamp = uint48(bytes6(self[self.length - TIMESTAMP_BYTE_SIZE:]));
                      uint8 proofItemsCount = uint8(self[self.length - 2 * TIMESTAMP_BYTE_SIZE - 1]);
                      uint256 appendedDataLen = (uint256(proofItemsCount) * PROOF_ITEM_BYTE_SIZE + 1) + 2 * TIMESTAMP_BYTE_SIZE;
                      bytes calldata rlpEncodedTx = self[1:self.length - appendedDataLen];
                      RLPDecoder.RLPItem memory parsedRlpEncodedTx = rlpEncodedTx.toRlpItem();
                      RLPDecoder.RLPItem[] memory parsedRlpEncodedTxItems = parsedRlpEncodedTx.toList();
                      TxParams memory params = extractParams(txType, parsedRlpEncodedTxItems);
                      return TxData(
                          txType,
                          _adjustV(params.v),
                          params.r,
                          params.s,
                          calculateUnsignedTxHash(txType, rlpEncodedTx, parsedRlpEncodedTx.payloadLen(), params.v, params.r, params.s),
                          extractAppendedHash(params.callData),
                          extractProof(self, proofItemsCount),
                          lowerBoundTimestamp,
                          upperBoundTimestamp
                      );
                  }
                  function decodeTxShort(bytes calldata self) internal pure returns (TxDataShort memory) {
                      uint8 txType = uint8(self[0]); //first byte is tx type
                      uint8 proofItemsCount = uint8(self[self.length - 1]);
                      uint256 appendedDataLen = (uint256(proofItemsCount) * PROOF_ITEM_BYTE_SIZE + 1);
                      bytes calldata rlpEncodedTx = self[1:self.length - appendedDataLen];
                      RLPDecoder.RLPItem memory parsedRlpEncodedTx = rlpEncodedTx.toRlpItem();
                      RLPDecoder.RLPItem[] memory parsedRlpEncodedTxItems = parsedRlpEncodedTx.toList();
                      TxParams memory params = extractParams(txType, parsedRlpEncodedTxItems);
                      return TxDataShort(
                          txType,
                          _adjustV(params.v),
                          params.r,
                          params.s,
                          calculateUnsignedTxHash(txType, rlpEncodedTx, parsedRlpEncodedTx.payloadLen(), params.v, params.r, params.s),
                          extractAppendedHash(params.callData),
                          extractProofShort(self, proofItemsCount)
                      );
                  }
                  function extractParams(uint8 txType, RLPDecoder.RLPItem[] memory items)
                      private
                      pure
                      returns (TxParams memory params)
                  {
                      uint8 dataPos;
                      uint8 vPos;
                      uint8 rPos;
                      uint8 sPos;
                      if (txType == LEGACY_TX_TYPE) {
                          dataPos = 5;
                          vPos = 6;
                          rPos = 7;
                          sPos = 8;
                      } else if (txType == EIP1559_TX_TYPE) {
                          dataPos = 7;
                          vPos = 9;
                          rPos = 10;
                          sPos = 11;
                      } else {
                          revert("TxValidatorLib:: unsupported evm tx type");
                      }
                      return TxParams(
                          items[vPos].toUint(), bytes32(items[rPos].toUint()), bytes32(items[sPos].toUint()), items[dataPos].toBytes()
                      );
                  }
                  function extractAppendedHash(bytes memory callData) private pure returns (bytes32 iTxHash) {
                      if (callData.length < ITX_HASH_BYTE_SIZE) revert("TxDecoder:: callData length too short");
                      iTxHash = bytes32(callData.slice(callData.length - ITX_HASH_BYTE_SIZE, ITX_HASH_BYTE_SIZE));
                  }
                  function extractProof(bytes calldata signedTx, uint8 proofItemsCount)
                      private
                      pure
                      returns (bytes32[] memory proof)
                  {
                      proof = new bytes32[](proofItemsCount);
                      uint256 pos = signedTx.length - 2 * TIMESTAMP_BYTE_SIZE - 1;
                      for (proofItemsCount; proofItemsCount > 0; proofItemsCount--) {
                          proof[proofItemsCount - 1] = bytes32(signedTx[pos - PROOF_ITEM_BYTE_SIZE:pos]);
                          pos = pos - PROOF_ITEM_BYTE_SIZE;
                      }
                  }
                  function extractProofShort(bytes calldata signedTx, uint8 proofItemsCount)
                      private
                      pure
                      returns (bytes32[] memory proof)
                  {
                      proof = new bytes32[](proofItemsCount);
                      uint256 pos = signedTx.length - 1;
                      for (proofItemsCount; proofItemsCount > 0; proofItemsCount--) {
                          proof[proofItemsCount - 1] = bytes32(signedTx[pos - PROOF_ITEM_BYTE_SIZE:pos]);
                          pos = pos - PROOF_ITEM_BYTE_SIZE;
                      }
                  }
                  function calculateUnsignedTxHash(
                      uint8 txType,
                      bytes memory rlpEncodedTx,
                      uint256 rlpEncodedTxPayloadLen,
                      uint256 v,
                      bytes32 r,
                      bytes32 s
                  ) private pure returns (bytes32 hash) {
                      uint256 totalSignatureSize =
                          uint256(r).encodeUint().length + uint256(s).encodeUint().length + v.encodeUint().length;
                      uint256 totalPrefixSize = rlpEncodedTx.length - rlpEncodedTxPayloadLen;
                      bytes memory rlpEncodedTxNoSigAndPrefix =
                          rlpEncodedTx.slice(totalPrefixSize, rlpEncodedTx.length - totalSignatureSize - totalPrefixSize);
                      if (txType == EIP1559_TX_TYPE) {
                          return keccak256(abi.encodePacked(txType, prependRlpContentSize(rlpEncodedTxNoSigAndPrefix, "")));
                      } else if (txType == LEGACY_TX_TYPE) {
                          if (v >= EIP_155_MIN_V_VALUE) {
                              return keccak256(
                                  prependRlpContentSize(
                                      rlpEncodedTxNoSigAndPrefix,
                                      abi.encodePacked(
                                          uint256(_extractChainIdFromV(v)).encodeUint(),
                                          uint256(0).encodeUint(),
                                          uint256(0).encodeUint()
                                      )
                                  )
                              );
                          } else {
                              return keccak256(prependRlpContentSize(rlpEncodedTxNoSigAndPrefix, ""));
                          }
                      } else {
                          revert("TxValidatorLib:: unsupported tx type");
                      }
                  }
                  function prependRlpContentSize(bytes memory content, bytes memory extraData) public pure returns (bytes memory) {
                      bytes memory combinedContent = abi.encodePacked(content, extraData);
                      return abi.encodePacked(combinedContent.length.encodeLength(RLPDecoder.LIST_SHORT_START), combinedContent);
                  }
                  function _adjustV(uint256 v) internal pure returns (uint8) {
                      if (v >= EIP_155_MIN_V_VALUE) {
                          return uint8((v - 2 * _extractChainIdFromV(v) - 35) + 27);
                      } else if (v <= 1) {
                          return uint8(v + 27);
                      } else {
                          return uint8(v);
                      }
                  }
                  function _extractChainIdFromV(uint256 v) internal pure returns (uint256 chainId) {
                      chainId = (v - 35) / 2;
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.27;
              import {MerkleProof} from "openzeppelin/utils/cryptography/MerkleProof.sol";
              import {EcdsaLib} from "../util/EcdsaLib.sol";
              import {MEEUserOpHashLib} from "../util/MEEUserOpHashLib.sol";
              import "account-abstraction/core/Helpers.sol";
              /**
               * @dev Library to validate the signature for MEE Simple mode
               *      In this mode, Fusion is not involved and just the superTx hash is signed
               */
              library SimpleValidatorLib {
                  /**
                   * This function parses the given userOpSignature into a Supertransaction signature
                   *
                   * Once parsed, the function will check for two conditions:
                   *      1. is the root supertransaction hash signed by the account owner's EOA
                   *      2. is the userOp actually a part of the given supertransaction
                   *      by checking the leaf based on this userOpHash is a part of the merkle tree represented by root hash = superTxHash
                   *
                   * If both conditions are met - outside contract can be sure that the expected signer has indeed
                   * approved the given userOp - and the userOp is successfully validate.
                   *
                   * @param userOpHash UserOp hash being validated.
                   * @param signatureData Signature provided as the userOp.signature parameter (minus the prepended tx type byte).
                   * @param expectedSigner Signer expected to be recovered when decoding the ERC20OPermit signature.
                   */
                  function validateUserOp(bytes32 userOpHash, bytes calldata signatureData, address expectedSigner)
                      internal
                      view
                      returns (uint256)
                  {
                      bytes32 superTxHash;
                      uint48 lowerBoundTimestamp;
                      uint48 upperBoundTimestamp;
                      bytes32[] calldata proof;
                      bytes calldata secp256k1Signature;
                      assembly {
                          superTxHash := calldataload(signatureData.offset)
                          lowerBoundTimestamp := calldataload(add(signatureData.offset, 0x20))
                          upperBoundTimestamp := calldataload(add(signatureData.offset, 0x40))
                          let u := calldataload(add(signatureData.offset, 0x60))
                          let s := add(signatureData.offset, u)
                          proof.offset := add(s, 0x20)
                          proof.length := calldataload(s)
                          u := mul(proof.length, 0x20)
                          s := add(proof.offset, u)
                          secp256k1Signature.offset := add(s, 0x20)
                          secp256k1Signature.length := calldataload(s)
                      }
                      bytes32 leaf = MEEUserOpHashLib.getMEEUserOpHash(userOpHash, lowerBoundTimestamp, upperBoundTimestamp);
                      if (!EcdsaLib.isValidSignature(expectedSigner, superTxHash, secp256k1Signature)) {
                          return SIG_VALIDATION_FAILED;
                      }
                      if (!MerkleProof.verify(proof, superTxHash, leaf)) {
                          return SIG_VALIDATION_FAILED;
                      }
                      return _packValidationData(false, upperBoundTimestamp, lowerBoundTimestamp);
                  }
                  /**
                   * @notice Validates the signature against the expected signer (owner)
                   * @param owner Signer expected to be recovered
                   * @param dataHash data hash being validated.
                   * @param signatureData Signature
                   */
                  function validateSignatureForOwner(address owner, bytes32 dataHash, bytes calldata signatureData)
                      internal
                      view
                      returns (bool)
                  {
                      bytes32 superTxHash;
                      bytes32[] calldata proof;
                      bytes calldata secp256k1Signature;
                      assembly {
                          superTxHash := calldataload(signatureData.offset)
                          let u := calldataload(add(signatureData.offset, 0x20))
                          let s := add(signatureData.offset, u)
                          proof.offset := add(s, 0x20)
                          proof.length := calldataload(s)
                          u := mul(proof.length, 0x20)
                          s := add(proof.offset, u)
                          secp256k1Signature.offset := add(s, 0x20)
                          secp256k1Signature.length := calldataload(s)
                      }
                      if (!EcdsaLib.isValidSignature(owner, superTxHash, secp256k1Signature)) {
                          return false;
                      }
                      if (!MerkleProof.verify(proof, superTxHash, dataHash)) {
                          return false;
                      }
                      return true;
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.27;
              import "account-abstraction/interfaces/PackedUserOperation.sol";
              import "account-abstraction/core/Helpers.sol";
              import "../util/EcdsaLib.sol";
              library NoMeeFlowLib {
                  /**
                   * Standard userOp validator - validates by simply checking if the userOpHash was signed by the account's EOA owner.
                   *
                   * @param userOpHash userOpHash being validated.
                   * @param parsedSignature Signature
                   * @param expectedSigner Signer expected to be recovered
                   */
                  function validateUserOp(bytes32 userOpHash, bytes memory parsedSignature, address expectedSigner)
                      internal
                      view
                      returns (uint256)
                  {
                      if (!EcdsaLib.isValidSignature(expectedSigner, userOpHash, parsedSignature)) {
                          return SIG_VALIDATION_FAILED;
                      }
                      return SIG_VALIDATION_SUCCESS;
                  }
                  /**
                   * @notice Validates the signature against the expected signer (owner)
                   * @param expectedSigner Signer expected to be recovered
                   * @param hash Hash of the userOp
                   * @param parsedSignature Signature
                   */
                  function validateSignatureForOwner(address expectedSigner, bytes32 hash, bytes memory parsedSignature)
                      internal
                      view
                      returns (bool)
                  {
                      return EcdsaLib.isValidSignature(expectedSigner, hash, parsedSignature);
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.27;
              import {ECDSA} from "solady/utils/ECDSA.sol";
              library EcdsaLib {
                  using ECDSA for bytes32;
                  /**
                   * @dev Solady ECDSA does not revert on incorrect signatures.
                   *      Instead, it returns address(0) as the recovered address.
                   *      Make sure to never pass address(0) as expectedSigner to this function.
                   */
                  function isValidSignature(address expectedSigner, bytes32 hash, bytes memory signature)
                      internal
                      view
                      returns (bool)
                  {
                      if (hash.tryRecover(signature) == expectedSigner) return true;
                      if (hash.toEthSignedMessageHash().tryRecover(signature) == expectedSigner) return true;
                      return false;
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.20;
              /**
               * Dynamic arrays associated with an account address as per ERC-7562/ERC-4337
               * @author filio.eth (Biconomy), zeroknots.eth (rhinestone)
               */
              library AssociatedArrayLib {
                  using AssociatedArrayLib for *;
                  error AssociatedArray_OutOfBounds(uint256 index);
                  struct Array {
                      uint256 _spacer;
                  }
                  function _slot(Array storage s, address account) private pure returns (bytes32 __slot) {
                      assembly {
                          mstore(0x00, account)
                          mstore(0x20, s.slot)
                          __slot := keccak256(0x00, 0x40)
                      }
                  }
                  function _length(Array storage s, address account) private view returns (uint256 __length) {
                      bytes32 slot = _slot(s, account);
                      assembly {
                          __length := sload(slot)
                      }
                  }
                  function _get(Array storage s, address account, uint256 index) private view returns (bytes32 value) {
                      return _get(_slot(s, account), index);
                  }
                  function _get(bytes32 slot, uint256 index) private view returns (bytes32 value) {
                      assembly {
                          //if (index >= _length(s, account)) revert AssociatedArray_OutOfBounds(index);
                          if iszero(lt(index, sload(slot))) {
                              mstore(0, 0x8277484f) // `AssociatedArray_OutOfBounds(uint256)`
                              mstore(0x20, index)
                              revert(0x1c, 0x24)
                          }
                          value := sload(add(slot, mul(0x20, add(index, 1))))
                      }
                  }
                  function _getAll(Array storage s, address account) private view returns (bytes32[] memory values) {
                      bytes32 slot = _slot(s, account);
                      uint256 __length;
                      assembly {
                          __length := sload(slot)
                      }
                      values = new bytes32[](__length);
                      for (uint256 i; i < __length; i++) {
                          values[i] = _get(slot, i);
                      }
                  }
                  // inefficient. complexity = O(n)
                  // use with caution
                  // in case of large arrays, consider using EnumerableSet4337 instead
                  function _contains(Array storage s, address account, bytes32 value) private view returns (bool) {
                      bytes32 slot = _slot(s, account);
                      uint256 __length;
                      assembly {
                          __length := sload(slot)
                      }
                      for (uint256 i; i < __length; i++) {
                          if (_get(slot, i) == value) {
                              return true;
                          }
                      }
                      return false;
                  }
                  function _set(Array storage s, address account, uint256 index, bytes32 value) private {
                      _set(_slot(s, account), index, value);
                  }
                  function _set(bytes32 slot, uint256 index, bytes32 value) private {
                      assembly {
                          //if (index >= _length(s, account)) revert AssociatedArray_OutOfBounds(index);
                          if iszero(lt(index, sload(slot))) {
                              mstore(0, 0x8277484f) // `AssociatedArray_OutOfBounds(uint256)`
                              mstore(0x20, index)
                              revert(0x1c, 0x24)
                          }
                          sstore(add(slot, mul(0x20, add(index, 1))), value)
                      }
                  }
                  function _push(Array storage s, address account, bytes32 value) private {
                      bytes32 slot = _slot(s, account);
                      assembly {
                          // load length (stored @ slot), add 1 to it => index.
                          // mul index by 0x20 and add it to orig slot to get the next free slot
                          let index := add(sload(slot), 1)
                          sstore(add(slot, mul(0x20, index)), value)
                          sstore(slot, index) //increment length by 1
                      }
                  }
                  function _pop(Array storage s, address account) private {
                      bytes32 slot = _slot(s, account);
                      uint256 __length;
                      assembly {
                          __length := sload(slot)
                      }
                      if (__length == 0) return;
                      _set(slot, __length - 1, 0);
                      assembly {
                          sstore(slot, sub(__length, 1))
                      }
                  }
                  function _remove(Array storage s, address account, uint256 index) private {
                      bytes32 slot = _slot(s, account);
                      uint256 __length;
                      assembly {
                          __length := sload(slot)
                          if iszero(lt(index, __length)) {
                              mstore(0, 0x8277484f) // `AssociatedArray_OutOfBounds(uint256)`
                              mstore(0x20, index)
                              revert(0x1c, 0x24)
                          }
                      }
                      _set(slot, index, _get(s, account, __length - 1));
                      assembly {
                          // clear the last slot
                          // this is the 'unchecked' version of _set(slot, __length - 1, 0)
                          // as we use length-1 as index, so the check is excessive.
                          // also removes extra -1 and +1 operations
                          sstore(add(slot, mul(0x20, __length)), 0)
                          // store new length
                          sstore(slot, sub(__length, 1))
                      }
                  }
                  struct Bytes32Array {
                      Array _inner;
                  }
                  function length(Bytes32Array storage s, address account) internal view returns (uint256) {
                      return _length(s._inner, account);
                  }
                  function get(Bytes32Array storage s, address account, uint256 index) internal view returns (bytes32) {
                      return _get(s._inner, account, index);
                  }
                  function getAll(Bytes32Array storage s, address account) internal view returns (bytes32[] memory) {
                      return _getAll(s._inner, account);
                  }
                  function contains(Bytes32Array storage s, address account, bytes32 value) internal view returns (bool) {
                      return _contains(s._inner, account, value);
                  }
                  function add(Bytes32Array storage s, address account, bytes32 value) internal {
                      if (!_contains(s._inner, account, value)) {
                          _push(s._inner, account, value);
                      }
                  }
                  function set(Bytes32Array storage s, address account, uint256 index, bytes32 value) internal {
                      _set(s._inner, account, index, value);
                  }
                  function push(Bytes32Array storage s, address account, bytes32 value) internal {
                      _push(s._inner, account, value);
                  }
                  function pop(Bytes32Array storage s, address account) internal {
                      _pop(s._inner, account);
                  }
                  function remove(Bytes32Array storage s, address account, uint256 index) internal {
                      _remove(s._inner, account, index);
                  }
                  struct AddressArray {
                      Array _inner;
                  }
                  function length(AddressArray storage s, address account) internal view returns (uint256) {
                      return _length(s._inner, account);
                  }
                  function get(AddressArray storage s, address account, uint256 index) internal view returns (address) {
                      return address(uint160(uint256(_get(s._inner, account, index))));
                  }
                  function getAll(AddressArray storage s, address account) internal view returns (address[] memory) {
                      bytes32[] memory bytes32Array = _getAll(s._inner, account);
                      address[] memory addressArray;
                      /// @solidity memory-safe-assembly
                      assembly {
                          addressArray := bytes32Array
                      }
                      return addressArray;
                  }
                  function contains(AddressArray storage s, address account, address value) internal view returns (bool) {
                      return _contains(s._inner, account, bytes32(uint256(uint160(value))));
                  }
                  function add(AddressArray storage s, address account, address value) internal {
                      if (!_contains(s._inner, account, bytes32(uint256(uint160(value))))) {
                          _push(s._inner, account, bytes32(uint256(uint160(value))));
                      }
                  }
                  function set(AddressArray storage s, address account, uint256 index, address value) internal {
                      _set(s._inner, account, index, bytes32(uint256(uint160(value))));
                  }
                  function push(AddressArray storage s, address account, address value) internal {
                      _push(s._inner, account, bytes32(uint256(uint160(value))));
                  }
                  function pop(AddressArray storage s, address account) internal {
                      _pop(s._inner, account);
                  }
                  function remove(AddressArray storage s, address account, uint256 index) internal {
                      _remove(s._inner, account, index);
                  }
                  struct UintArray {
                      Array _inner;
                  }
                  function length(UintArray storage s, address account) internal view returns (uint256) {
                      return _length(s._inner, account);
                  }
                  function get(UintArray storage s, address account, uint256 index) internal view returns (uint256) {
                      return uint256(_get(s._inner, account, index));
                  }
                  function getAll(UintArray storage s, address account) internal view returns (uint256[] memory) {
                      bytes32[] memory bytes32Array = _getAll(s._inner, account);
                      uint256[] memory uintArray;
                      /// @solidity memory-safe-assembly
                      assembly {
                          uintArray := bytes32Array
                      }
                      return uintArray;
                  }
                  function contains(UintArray storage s, address account, uint256 value) internal view returns (bool) {
                      return _contains(s._inner, account, bytes32(value));
                  }
                  function add(UintArray storage s, address account, uint256 value) internal {
                      if (!_contains(s._inner, account, bytes32(value))) {
                          _push(s._inner, account, bytes32(value));
                      }
                  }
                  function set(UintArray storage s, address account, uint256 index, uint256 value) internal {
                      _set(s._inner, account, index, bytes32(value));
                  }
                  function push(UintArray storage s, address account, uint256 value) internal {
                      _push(s._inner, account, bytes32(value));
                  }
                  function pop(UintArray storage s, address account) internal {
                      _pop(s._inner, account);
                  }
                  function remove(UintArray storage s, address account, uint256 index) internal {
                      _remove(s._inner, account, index);
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)
              pragma solidity ^0.8.20;
              import {Strings} from "../Strings.sol";
              /**
               * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
               *
               * The library provides methods for generating a hash of a message that conforms to the
               * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
               * specifications.
               */
              library MessageHashUtils {
                  /**
                   * @dev Returns the keccak256 digest of an EIP-191 signed data with version
                   * `0x45` (`personal_sign` messages).
                   *
                   * The digest is calculated by prefixing a bytes32 `messageHash` with
                   * `"\\x19Ethereum Signed Message:\
              32"` and hashing the result. It corresponds with the
                   * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
                   *
                   * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
                   * keccak256, although any bytes32 value can be safely used because the final digest will
                   * be re-hashed.
                   *
                   * See {ECDSA-recover}.
                   */
                  function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
                      /// @solidity memory-safe-assembly
                      assembly {
                          mstore(0x00, "\\x19Ethereum Signed Message:\
              32") // 32 is the bytes-length of messageHash
                          mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
                          digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
                      }
                  }
                  /**
                   * @dev Returns the keccak256 digest of an EIP-191 signed data with version
                   * `0x45` (`personal_sign` messages).
                   *
                   * The digest is calculated by prefixing an arbitrary `message` with
                   * `"\\x19Ethereum Signed Message:\
              " + len(message)` and hashing the result. It corresponds with the
                   * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
                   *
                   * See {ECDSA-recover}.
                   */
                  function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
                      return
                          keccak256(bytes.concat("\\x19Ethereum Signed Message:\
              ", bytes(Strings.toString(message.length)), message));
                  }
                  /**
                   * @dev Returns the keccak256 digest of an EIP-191 signed data with version
                   * `0x00` (data with intended validator).
                   *
                   * The digest is calculated by prefixing an arbitrary `data` with `"\\x19\\x00"` and the intended
                   * `validator` address. Then hashing the result.
                   *
                   * See {ECDSA-recover}.
                   */
                  function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
                      return keccak256(abi.encodePacked(hex"19_00", validator, data));
                  }
                  /**
                   * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
                   *
                   * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
                   * `\\x19\\x01` and hashing the result. It corresponds to the hash signed by the
                   * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
                   *
                   * See {ECDSA-recover}.
                   */
                  function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
                      /// @solidity memory-safe-assembly
                      assembly {
                          let ptr := mload(0x40)
                          mstore(ptr, hex"19_01")
                          mstore(add(ptr, 0x02), domainSeparator)
                          mstore(add(ptr, 0x22), structHash)
                          digest := keccak256(ptr, 0x42)
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MerkleProof.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev These functions deal with verification of Merkle Tree proofs.
               *
               * The tree and the proofs can be generated using our
               * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
               * You will find a quickstart guide in the readme.
               *
               * WARNING: You should avoid using leaf values that are 64 bytes long prior to
               * hashing, or use a hash function other than keccak256 for hashing leaves.
               * This is because the concatenation of a sorted pair of internal nodes in
               * the Merkle tree could be reinterpreted as a leaf value.
               * OpenZeppelin's JavaScript library generates Merkle trees that are safe
               * against this attack out of the box.
               */
              library MerkleProof {
                  /**
                   *@dev The multiproof provided is not valid.
                   */
                  error MerkleProofInvalidMultiproof();
                  /**
                   * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
                   * defined by `root`. For this, a `proof` must be provided, containing
                   * sibling hashes on the branch from the leaf to the root of the tree. Each
                   * pair of leaves and each pair of pre-images are assumed to be sorted.
                   */
                  function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
                      return processProof(proof, leaf) == root;
                  }
                  /**
                   * @dev Calldata version of {verify}
                   */
                  function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
                      return processProofCalldata(proof, leaf) == root;
                  }
                  /**
                   * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
                   * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
                   * hash matches the root of the tree. When processing the proof, the pairs
                   * of leafs & pre-images are assumed to be sorted.
                   */
                  function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
                      bytes32 computedHash = leaf;
                      for (uint256 i = 0; i < proof.length; i++) {
                          computedHash = _hashPair(computedHash, proof[i]);
                      }
                      return computedHash;
                  }
                  /**
                   * @dev Calldata version of {processProof}
                   */
                  function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
                      bytes32 computedHash = leaf;
                      for (uint256 i = 0; i < proof.length; i++) {
                          computedHash = _hashPair(computedHash, proof[i]);
                      }
                      return computedHash;
                  }
                  /**
                   * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by
                   * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
                   *
                   * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
                   */
                  function multiProofVerify(
                      bytes32[] memory proof,
                      bool[] memory proofFlags,
                      bytes32 root,
                      bytes32[] memory leaves
                  ) internal pure returns (bool) {
                      return processMultiProof(proof, proofFlags, leaves) == root;
                  }
                  /**
                   * @dev Calldata version of {multiProofVerify}
                   *
                   * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
                   */
                  function multiProofVerifyCalldata(
                      bytes32[] calldata proof,
                      bool[] calldata proofFlags,
                      bytes32 root,
                      bytes32[] memory leaves
                  ) internal pure returns (bool) {
                      return processMultiProofCalldata(proof, proofFlags, leaves) == root;
                  }
                  /**
                   * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
                   * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
                   * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
                   * respectively.
                   *
                   * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
                   * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
                   * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
                   */
                  function processMultiProof(
                      bytes32[] memory proof,
                      bool[] memory proofFlags,
                      bytes32[] memory leaves
                  ) internal pure returns (bytes32 merkleRoot) {
                      // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
                      // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
                      // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
                      // the Merkle tree.
                      uint256 leavesLen = leaves.length;
                      uint256 proofLen = proof.length;
                      uint256 totalHashes = proofFlags.length;
                      // Check proof validity.
                      if (leavesLen + proofLen != totalHashes + 1) {
                          revert MerkleProofInvalidMultiproof();
                      }
                      // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
                      // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
                      bytes32[] memory hashes = new bytes32[](totalHashes);
                      uint256 leafPos = 0;
                      uint256 hashPos = 0;
                      uint256 proofPos = 0;
                      // At each step, we compute the next hash using two values:
                      // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
                      //   get the next hash.
                      // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
                      //   `proof` array.
                      for (uint256 i = 0; i < totalHashes; i++) {
                          bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
                          bytes32 b = proofFlags[i]
                              ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                              : proof[proofPos++];
                          hashes[i] = _hashPair(a, b);
                      }
                      if (totalHashes > 0) {
                          if (proofPos != proofLen) {
                              revert MerkleProofInvalidMultiproof();
                          }
                          unchecked {
                              return hashes[totalHashes - 1];
                          }
                      } else if (leavesLen > 0) {
                          return leaves[0];
                      } else {
                          return proof[0];
                      }
                  }
                  /**
                   * @dev Calldata version of {processMultiProof}.
                   *
                   * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
                   */
                  function processMultiProofCalldata(
                      bytes32[] calldata proof,
                      bool[] calldata proofFlags,
                      bytes32[] memory leaves
                  ) internal pure returns (bytes32 merkleRoot) {
                      // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
                      // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
                      // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
                      // the Merkle tree.
                      uint256 leavesLen = leaves.length;
                      uint256 proofLen = proof.length;
                      uint256 totalHashes = proofFlags.length;
                      // Check proof validity.
                      if (leavesLen + proofLen != totalHashes + 1) {
                          revert MerkleProofInvalidMultiproof();
                      }
                      // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
                      // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
                      bytes32[] memory hashes = new bytes32[](totalHashes);
                      uint256 leafPos = 0;
                      uint256 hashPos = 0;
                      uint256 proofPos = 0;
                      // At each step, we compute the next hash using two values:
                      // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
                      //   get the next hash.
                      // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
                      //   `proof` array.
                      for (uint256 i = 0; i < totalHashes; i++) {
                          bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
                          bytes32 b = proofFlags[i]
                              ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                              : proof[proofPos++];
                          hashes[i] = _hashPair(a, b);
                      }
                      if (totalHashes > 0) {
                          if (proofPos != proofLen) {
                              revert MerkleProofInvalidMultiproof();
                          }
                          unchecked {
                              return hashes[totalHashes - 1];
                          }
                      } else if (leavesLen > 0) {
                          return leaves[0];
                      } else {
                          return proof[0];
                      }
                  }
                  /**
                   * @dev Sorts the pair (a, b) and hashes the result.
                   */
                  function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
                      return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
                  }
                  /**
                   * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory.
                   */
                  function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
                      /// @solidity memory-safe-assembly
                      assembly {
                          mstore(0x00, a)
                          mstore(0x20, b)
                          value := keccak256(0x00, 0x40)
                      }
                  }
              }
              // SPDX-License-Identifier: Unlicense
              /*
               * @title MEE UserOp Hash Lib
               *
               * @dev Calculates userOp hash for the new type of transaction - SuperTransaction (as a part of MEE stack)
               */
              pragma solidity ^0.8.27;
              library MEEUserOpHashLib {
                  /**
                   * Calculates userOp hash. Almost works like a regular 4337 userOp hash with few fields added.
                   *
                   * @param userOpHash userOp hash to calculate the hash for
                   * @param lowerBoundTimestamp lower bound timestamp set when constructing userOp
                   * @param upperBoundTimestamp upper bound timestamp set when constructing userOp
                   * Timestamps are used by the MEE node to schedule the execution of the userOps within the superTx
                   */
                  function getMEEUserOpHash(bytes32 userOpHash, uint256 lowerBoundTimestamp, uint256 upperBoundTimestamp)
                      internal
                      pure
                      returns (bytes32 meeUserOpHash)
                  {
                      meeUserOpHash =
                          keccak256(bytes.concat(keccak256(abi.encode(userOpHash, lowerBoundTimestamp, upperBoundTimestamp))));
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
              pragma solidity ^0.8.20;
              /**
               * @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 v5.0.0) (token/ERC20/IERC20.sol)
              pragma solidity ^0.8.20;
              /**
               * @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 value of tokens in existence.
                   */
                  function totalSupply() external view returns (uint256);
                  /**
                   * @dev Returns the value of tokens owned by `account`.
                   */
                  function balanceOf(address account) external view returns (uint256);
                  /**
                   * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
                  /**
                   * @dev Moves a `value` amount of tokens from `from` to `to` using the
                   * allowance mechanism. `value` 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 value) external returns (bool);
              }
              // SPDX-License-Identifier: GPL-3.0
              pragma solidity ^0.8.23;
              /* solhint-disable no-inline-assembly */
               /*
                * For simulation purposes, validateUserOp (and validatePaymasterUserOp)
                * must return this value in case of signature failure, instead of revert.
                */
              uint256 constant SIG_VALIDATION_FAILED = 1;
              /*
               * For simulation purposes, validateUserOp (and validatePaymasterUserOp)
               * return this value on success.
               */
              uint256 constant SIG_VALIDATION_SUCCESS = 0;
              /**
               * Returned data from validateUserOp.
               * validateUserOp returns a uint256, which is created by `_packedValidationData` and
               * parsed by `_parseValidationData`.
               * @param aggregator  - address(0) - The account validated the signature by itself.
               *                      address(1) - The account failed to validate the signature.
               *                      otherwise - This is an address of a signature aggregator that must
               *                                  be used to validate the signature.
               * @param validAfter  - This UserOp is valid only after this timestamp.
               * @param validaUntil - This UserOp is valid only up to this timestamp.
               */
              struct ValidationData {
                  address aggregator;
                  uint48 validAfter;
                  uint48 validUntil;
              }
              /**
               * Extract sigFailed, validAfter, validUntil.
               * Also convert zero validUntil to type(uint48).max.
               * @param validationData - The packed validation data.
               */
              function _parseValidationData(
                  uint256 validationData
              ) pure returns (ValidationData memory data) {
                  address aggregator = address(uint160(validationData));
                  uint48 validUntil = uint48(validationData >> 160);
                  if (validUntil == 0) {
                      validUntil = type(uint48).max;
                  }
                  uint48 validAfter = uint48(validationData >> (48 + 160));
                  return ValidationData(aggregator, validAfter, validUntil);
              }
              /**
               * Helper to pack the return value for validateUserOp.
               * @param data - The ValidationData to pack.
               */
              function _packValidationData(
                  ValidationData memory data
              ) pure returns (uint256) {
                  return
                      uint160(data.aggregator) |
                      (uint256(data.validUntil) << 160) |
                      (uint256(data.validAfter) << (160 + 48));
              }
              /**
               * Helper to pack the return value for validateUserOp, when not using an aggregator.
               * @param sigFailed  - True for signature failure, false for success.
               * @param validUntil - Last timestamp this UserOperation is valid (or zero for infinite).
               * @param validAfter - First timestamp this UserOperation is valid.
               */
              function _packValidationData(
                  bool sigFailed,
                  uint48 validUntil,
                  uint48 validAfter
              ) pure returns (uint256) {
                  return
                      (sigFailed ? 1 : 0) |
                      (uint256(validUntil) << 160) |
                      (uint256(validAfter) << (160 + 48));
              }
              /**
               * keccak function over calldata.
               * @dev copy calldata into memory, do keccak and drop allocated memory. Strangely, this is more efficient than letting solidity do it.
               */
                  function calldataKeccak(bytes calldata data) pure returns (bytes32 ret) {
                      assembly ("memory-safe") {
                          let mem := mload(0x40)
                          let len := data.length
                          calldatacopy(mem, data.offset, len)
                          ret := keccak256(mem, len)
                      }
                  }
              /**
               * The minimum of two numbers.
               * @param a - First number.
               * @param b - Second number.
               */
                  function min(uint256 a, uint256 b) pure returns (uint256) {
                      return a < b ? a : b;
                  }
              // SPDX-License-Identifier: Apache-2.0
              /*
               * @author Hamdi Allam [email protected]
               * Please reach out with any questions or concerns
               */
              pragma solidity >=0.5.10 <0.9.0;
              library RLPReader {
                  uint8 constant STRING_SHORT_START = 0x80;
                  uint8 constant STRING_LONG_START = 0xb8;
                  uint8 constant LIST_SHORT_START = 0xc0;
                  uint8 constant LIST_LONG_START = 0xf8;
                  uint8 constant WORD_SIZE = 32;
                  struct RLPItem {
                      uint256 len;
                      uint256 memPtr;
                  }
                  struct Iterator {
                      RLPItem item; // Item that's being iterated over.
                      uint256 nextPtr; // Position of the next item in the list.
                  }
                  /*
                   * @dev Returns the next element in the iteration. Reverts if it has not next element.
                   * @param self The iterator.
                   * @return The next element in the iteration.
                   */
                  function next(Iterator memory self) internal pure returns (RLPItem memory) {
                      require(hasNext(self));
                      uint256 ptr = self.nextPtr;
                      uint256 itemLength = _itemLength(ptr);
                      self.nextPtr = ptr + itemLength;
                      return RLPItem(itemLength, ptr);
                  }
                  /*
                   * @dev Returns true if the iteration has more elements.
                   * @param self The iterator.
                   * @return true if the iteration has more elements.
                   */
                  function hasNext(Iterator memory self) internal pure returns (bool) {
                      RLPItem memory item = self.item;
                      return self.nextPtr < item.memPtr + item.len;
                  }
                  /*
                   * @param item RLP encoded bytes
                   */
                  function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {
                      uint256 memPtr;
                      assembly {
                          memPtr := add(item, 0x20)
                      }
                      return RLPItem(item.length, memPtr);
                  }
                  /*
                   * @dev Create an iterator. Reverts if item is not a list.
                   * @param self The RLP item.
                   * @return An 'Iterator' over the item.
                   */
                  function iterator(RLPItem memory self) internal pure returns (Iterator memory) {
                      require(isList(self));
                      uint256 ptr = self.memPtr + _payloadOffset(self.memPtr);
                      return Iterator(self, ptr);
                  }
                  /*
                   * @param the RLP item.
                   */
                  function rlpLen(RLPItem memory item) internal pure returns (uint256) {
                      return item.len;
                  }
                  /*
                   * @param the RLP item.
                   * @return (memPtr, len) pair: location of the item's payload in memory.
                   */
                  function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) {
                      uint256 offset = _payloadOffset(item.memPtr);
                      uint256 memPtr = item.memPtr + offset;
                      uint256 len = item.len - offset; // data length
                      return (memPtr, len);
                  }
                  /*
                   * @param the RLP item.
                   */
                  function payloadLen(RLPItem memory item) internal pure returns (uint256) {
                      (, uint256 len) = payloadLocation(item);
                      return len;
                  }
                  /*
                   * @param the RLP item containing the encoded list.
                   */
                  function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {
                      require(isList(item));
                      uint256 items = numItems(item);
                      RLPItem[] memory result = new RLPItem[](items);
                      uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr);
                      uint256 dataLen;
                      for (uint256 i = 0; i < items; i++) {
                          dataLen = _itemLength(memPtr);
                          result[i] = RLPItem(dataLen, memPtr);
                          memPtr = memPtr + dataLen;
                      }
                      require(memPtr - item.memPtr == item.len);
                      return result;
                  }
                  // @return indicator whether encoded payload is a list. negate this function call for isData.
                  function isList(RLPItem memory item) internal pure returns (bool) {
                      if (item.len == 0) return false;
                      uint8 byte0;
                      uint256 memPtr = item.memPtr;
                      assembly {
                          byte0 := byte(0, mload(memPtr))
                      }
                      if (byte0 < LIST_SHORT_START) return false;
                      return true;
                  }
                  /*
                   * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory.
                   * @return keccak256 hash of RLP encoded bytes.
                   */
                  function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) {
                      uint256 ptr = item.memPtr;
                      uint256 len = item.len;
                      bytes32 result;
                      assembly {
                          result := keccak256(ptr, len)
                      }
                      return result;
                  }
                  /*
                   * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory.
                   * @return keccak256 hash of the item payload.
                   */
                  function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) {
                      (uint256 memPtr, uint256 len) = payloadLocation(item);
                      bytes32 result;
                      assembly {
                          result := keccak256(memPtr, len)
                      }
                      return result;
                  }
                  /** RLPItem conversions into data types **/
                  // @returns raw rlp encoding in bytes
                  function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) {
                      bytes memory result = new bytes(item.len);
                      if (result.length == 0) return result;
                      uint256 ptr;
                      assembly {
                          ptr := add(0x20, result)
                      }
                      copy(item.memPtr, ptr, item.len);
                      return result;
                  }
                  // any non-zero byte except "0x80" is considered true
                  function toBoolean(RLPItem memory item) internal pure returns (bool) {
                      require(item.len == 1);
                      uint256 result;
                      uint256 memPtr = item.memPtr;
                      assembly {
                          result := byte(0, mload(memPtr))
                      }
                      // SEE Github Issue #5.
                      // Summary: Most commonly used RLP libraries (i.e Geth) will encode
                      // "0" as "0x80" instead of as "0". We handle this edge case explicitly
                      // here.
                      if (result == 0 || result == STRING_SHORT_START) {
                          return false;
                      } else {
                          return true;
                      }
                  }
                  function toAddress(RLPItem memory item) internal pure returns (address) {
                      // 1 byte for the length prefix
                      require(item.len == 21);
                      return address(uint160(toUint(item)));
                  }
                  function toUint(RLPItem memory item) internal pure returns (uint256) {
                      require(item.len > 0 && item.len <= 33);
                      (uint256 memPtr, uint256 len) = payloadLocation(item);
                      uint256 result;
                      assembly {
                          result := mload(memPtr)
                          // shift to the correct location if neccesary
                          if lt(len, 32) {
                              result := div(result, exp(256, sub(32, len)))
                          }
                      }
                      return result;
                  }
                  // enforces 32 byte length
                  function toUintStrict(RLPItem memory item) internal pure returns (uint256) {
                      // one byte prefix
                      require(item.len == 33);
                      uint256 result;
                      uint256 memPtr = item.memPtr + 1;
                      assembly {
                          result := mload(memPtr)
                      }
                      return result;
                  }
                  function toBytes(RLPItem memory item) internal pure returns (bytes memory) {
                      require(item.len > 0);
                      (uint256 memPtr, uint256 len) = payloadLocation(item);
                      bytes memory result = new bytes(len);
                      uint256 destPtr;
                      assembly {
                          destPtr := add(0x20, result)
                      }
                      copy(memPtr, destPtr, len);
                      return result;
                  }
                  /*
                   * Private Helpers
                   */
                  // @return number of payload items inside an encoded list.
                  function numItems(RLPItem memory item) private pure returns (uint256) {
                      if (item.len == 0) return 0;
                      uint256 count = 0;
                      uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr);
                      uint256 endPtr = item.memPtr + item.len;
                      while (currPtr < endPtr) {
                          currPtr = currPtr + _itemLength(currPtr); // skip over an item
                          count++;
                      }
                      return count;
                  }
                  // @return entire rlp item byte length
                  function _itemLength(uint256 memPtr) private pure returns (uint256) {
                      uint256 itemLen;
                      uint256 byte0;
                      assembly {
                          byte0 := byte(0, mload(memPtr))
                      }
                      if (byte0 < STRING_SHORT_START) {
                          itemLen = 1;
                      } else if (byte0 < STRING_LONG_START) {
                          itemLen = byte0 - STRING_SHORT_START + 1;
                      } else if (byte0 < LIST_SHORT_START) {
                          assembly {
                              let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is
                              memPtr := add(memPtr, 1) // skip over the first byte
                              /* 32 byte word size */
                              let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len
                              itemLen := add(dataLen, add(byteLen, 1))
                          }
                      } else if (byte0 < LIST_LONG_START) {
                          itemLen = byte0 - LIST_SHORT_START + 1;
                      } else {
                          assembly {
                              let byteLen := sub(byte0, 0xf7)
                              memPtr := add(memPtr, 1)
                              let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length
                              itemLen := add(dataLen, add(byteLen, 1))
                          }
                      }
                      return itemLen;
                  }
                  // @return number of bytes until the data
                  function _payloadOffset(uint256 memPtr) private pure returns (uint256) {
                      uint256 byte0;
                      assembly {
                          byte0 := byte(0, mload(memPtr))
                      }
                      if (byte0 < STRING_SHORT_START) {
                          return 0;
                      } else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) {
                          return 1;
                      } else if (byte0 < LIST_SHORT_START) {
                          // being explicit
                          return byte0 - (STRING_LONG_START - 1) + 1;
                      } else {
                          return byte0 - (LIST_LONG_START - 1) + 1;
                      }
                  }
                  /*
                   * @param src Pointer to source
                   * @param dest Pointer to destination
                   * @param len Amount of memory to copy from the source
                   */
                  function copy(uint256 src, uint256 dest, uint256 len) private pure {
                      if (len == 0) return;
                      // copy as many word sizes as possible
                      for (; len >= WORD_SIZE; len -= WORD_SIZE) {
                          assembly {
                              mstore(dest, mload(src))
                          }
                          src += WORD_SIZE;
                          dest += WORD_SIZE;
                      }
                      if (len > 0) {
                          // left over bytes. Mask is used to remove unwanted bytes from the word
                          uint256 mask = 256**(WORD_SIZE - len) - 1;
                          assembly {
                              let srcpart := and(mload(src), not(mask)) // zero out src
                              let destpart := and(mload(dest), mask) // retrieve the bytes
                              mstore(dest, or(destpart, srcpart))
                          }
                      }
                  }
              }
              // SPDX-License-Identifier: AGPL-3.0-only
              pragma solidity ^0.8.27;
              // Had to keep it copypasted as the og lib https://github.com/bakaoh/solidity-rlp-encode has incompatible solc version
              import "byteslib/BytesLib.sol";
              /**
               * @title RLPEncoder
               * @dev A simple RLP encoding library.
               * @author Bakaoh
               */
              library RLPEncoder {
                  using BytesLib for bytes;
                  /*
                   * Internal functions
                   */
                  /**
                   * @dev RLP encodes a byte string.
                   * @param self The byte string to encode.
                   * @return The RLP encoded string in bytes.
                   */
                  function encodeBytes(bytes memory self) internal pure returns (bytes memory) {
                      bytes memory encoded;
                      if (self.length == 1 && uint8(self[0]) < 128) {
                          encoded = self;
                      } else {
                          encoded = encodeLength(self.length, 128).concat(self);
                      }
                      return encoded;
                  }
                  /**
                   * @dev RLP encodes a uint.
                   * @param self The uint to encode.
                   * @return The RLP encoded uint in bytes.
                   */
                  function encodeUint(uint256 self) internal pure returns (bytes memory) {
                      return encodeBytes(toBinary(self));
                  }
                  /**
                   * @dev Encode the first byte, followed by the `len` in binary form if `length` is more than 55.
                   * @param self The length of the string or the payload.
                   * @param offset 128 if item is string, 192 if item is list.
                   * @return RLP encoded bytes.
                   */
                  function encodeLength(uint256 self, uint256 offset) internal pure returns (bytes memory) {
                      bytes memory encoded;
                      if (self < 56) {
                          encoded = new bytes(1);
                          encoded[0] = bytes32(self + offset)[31];
                      } else {
                          uint256 lenLen;
                          uint256 i = 1;
                          while (self / i != 0) {
                              lenLen++;
                              i *= 256;
                          }
                          encoded = new bytes(lenLen + 1);
                          encoded[0] = bytes32(lenLen + offset + 55)[31];
                          for (i = 1; i <= lenLen; i++) {
                              encoded[i] = bytes32((self / (256 ** (lenLen - i))) % 256)[31];
                          }
                      }
                      return encoded;
                  }
                  /*
                   * Private functions
                   */
                  /**
                   * @dev Encode integer in big endian binary form with no leading zeroes.
                   * @notice TODO: This should be optimized with assembly to save gas costs.
                   * @param _x The integer to encode.
                   * @return RLP encoded bytes.
                   */
                  function toBinary(uint256 _x) private pure returns (bytes memory) {
                      bytes memory b = new bytes(32);
                      assembly {
                          mstore(add(b, 32), _x)
                      }
                      uint256 i;
                      for (i = 0; i < 32; i++) {
                          if (b[i] != 0) {
                              break;
                          }
                      }
                      bytes memory res = new bytes(32 - i);
                      for (uint256 j = 0; j < res.length; j++) {
                          res[j] = b[i++];
                      }
                      return res;
                  }
              }
              // SPDX-License-Identifier: Unlicense
              /*
               * @title Solidity Bytes Arrays Utils
               * @author Gonçalo Sá <[email protected]>
               *
               * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
               *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
               */
              pragma solidity >=0.8.0 <0.9.0;
              library BytesLib {
                  function concat(
                      bytes memory _preBytes,
                      bytes memory _postBytes
                  )
                      internal
                      pure
                      returns (bytes memory)
                  {
                      bytes memory tempBytes;
                      assembly {
                          // Get a location of some free memory and store it in tempBytes as
                          // Solidity does for memory variables.
                          tempBytes := mload(0x40)
                          // Store the length of the first bytes array at the beginning of
                          // the memory for tempBytes.
                          let length := mload(_preBytes)
                          mstore(tempBytes, length)
                          // Maintain a memory counter for the current write location in the
                          // temp bytes array by adding the 32 bytes for the array length to
                          // the starting location.
                          let mc := add(tempBytes, 0x20)
                          // Stop copying when the memory counter reaches the length of the
                          // first bytes array.
                          let end := add(mc, length)
                          for {
                              // Initialize a copy counter to the start of the _preBytes data,
                              // 32 bytes into its memory.
                              let cc := add(_preBytes, 0x20)
                          } lt(mc, end) {
                              // Increase both counters by 32 bytes each iteration.
                              mc := add(mc, 0x20)
                              cc := add(cc, 0x20)
                          } {
                              // Write the _preBytes data into the tempBytes memory 32 bytes
                              // at a time.
                              mstore(mc, mload(cc))
                          }
                          // Add the length of _postBytes to the current length of tempBytes
                          // and store it as the new length in the first 32 bytes of the
                          // tempBytes memory.
                          length := mload(_postBytes)
                          mstore(tempBytes, add(length, mload(tempBytes)))
                          // Move the memory counter back from a multiple of 0x20 to the
                          // actual end of the _preBytes data.
                          mc := end
                          // Stop copying when the memory counter reaches the new combined
                          // length of the arrays.
                          end := add(mc, length)
                          for {
                              let cc := add(_postBytes, 0x20)
                          } lt(mc, end) {
                              mc := add(mc, 0x20)
                              cc := add(cc, 0x20)
                          } {
                              mstore(mc, mload(cc))
                          }
                          // Update the free-memory pointer by padding our last write location
                          // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
                          // next 32 byte block, then round down to the nearest multiple of
                          // 32. If the sum of the length of the two arrays is zero then add
                          // one before rounding down to leave a blank 32 bytes (the length block with 0).
                          mstore(0x40, and(
                            add(add(end, iszero(add(length, mload(_preBytes)))), 31),
                            not(31) // Round down to the nearest 32 bytes.
                          ))
                      }
                      return tempBytes;
                  }
                  function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
                      assembly {
                          // Read the first 32 bytes of _preBytes storage, which is the length
                          // of the array. (We don't need to use the offset into the slot
                          // because arrays use the entire slot.)
                          let fslot := sload(_preBytes.slot)
                          // Arrays of 31 bytes or less have an even value in their slot,
                          // while longer arrays have an odd value. The actual length is
                          // the slot divided by two for odd values, and the lowest order
                          // byte divided by two for even values.
                          // If the slot is even, bitwise and the slot with 255 and divide by
                          // two to get the length. If the slot is odd, bitwise and the slot
                          // with -1 and divide by two.
                          let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
                          let mlength := mload(_postBytes)
                          let newlength := add(slength, mlength)
                          // slength can contain both the length and contents of the array
                          // if length < 32 bytes so let's prepare for that
                          // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                          switch add(lt(slength, 32), lt(newlength, 32))
                          case 2 {
                              // Since the new array still fits in the slot, we just need to
                              // update the contents of the slot.
                              // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
                              sstore(
                                  _preBytes.slot,
                                  // all the modifications to the slot are inside this
                                  // next block
                                  add(
                                      // we can just add to the slot contents because the
                                      // bytes we want to change are the LSBs
                                      fslot,
                                      add(
                                          mul(
                                              div(
                                                  // load the bytes from memory
                                                  mload(add(_postBytes, 0x20)),
                                                  // zero all bytes to the right
                                                  exp(0x100, sub(32, mlength))
                                              ),
                                              // and now shift left the number of bytes to
                                              // leave space for the length in the slot
                                              exp(0x100, sub(32, newlength))
                                          ),
                                          // increase length by the double of the memory
                                          // bytes length
                                          mul(mlength, 2)
                                      )
                                  )
                              )
                          }
                          case 1 {
                              // The stored value fits in the slot, but the combined value
                              // will exceed it.
                              // get the keccak hash to get the contents of the array
                              mstore(0x0, _preBytes.slot)
                              let sc := add(keccak256(0x0, 0x20), div(slength, 32))
                              // save new length
                              sstore(_preBytes.slot, add(mul(newlength, 2), 1))
                              // The contents of the _postBytes array start 32 bytes into
                              // the structure. Our first read should obtain the `submod`
                              // bytes that can fit into the unused space in the last word
                              // of the stored array. To get this, we read 32 bytes starting
                              // from `submod`, so the data we read overlaps with the array
                              // contents by `submod` bytes. Masking the lowest-order
                              // `submod` bytes allows us to add that value directly to the
                              // stored value.
                              let submod := sub(32, slength)
                              let mc := add(_postBytes, submod)
                              let end := add(_postBytes, mlength)
                              let mask := sub(exp(0x100, submod), 1)
                              sstore(
                                  sc,
                                  add(
                                      and(
                                          fslot,
                                          0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
                                      ),
                                      and(mload(mc), mask)
                                  )
                              )
                              for {
                                  mc := add(mc, 0x20)
                                  sc := add(sc, 1)
                              } lt(mc, end) {
                                  sc := add(sc, 1)
                                  mc := add(mc, 0x20)
                              } {
                                  sstore(sc, mload(mc))
                              }
                              mask := exp(0x100, sub(mc, end))
                              sstore(sc, mul(div(mload(mc), mask), mask))
                          }
                          default {
                              // get the keccak hash to get the contents of the array
                              mstore(0x0, _preBytes.slot)
                              // Start copying to the last used word of the stored array.
                              let sc := add(keccak256(0x0, 0x20), div(slength, 32))
                              // save new length
                              sstore(_preBytes.slot, add(mul(newlength, 2), 1))
                              // Copy over the first `submod` bytes of the new data as in
                              // case 1 above.
                              let slengthmod := mod(slength, 32)
                              let mlengthmod := mod(mlength, 32)
                              let submod := sub(32, slengthmod)
                              let mc := add(_postBytes, submod)
                              let end := add(_postBytes, mlength)
                              let mask := sub(exp(0x100, submod), 1)
                              sstore(sc, add(sload(sc), and(mload(mc), mask)))
                              for {
                                  sc := add(sc, 1)
                                  mc := add(mc, 0x20)
                              } lt(mc, end) {
                                  sc := add(sc, 1)
                                  mc := add(mc, 0x20)
                              } {
                                  sstore(sc, mload(mc))
                              }
                              mask := exp(0x100, sub(mc, end))
                              sstore(sc, mul(div(mload(mc), mask), mask))
                          }
                      }
                  }
                  function slice(
                      bytes memory _bytes,
                      uint256 _start,
                      uint256 _length
                  )
                      internal
                      pure
                      returns (bytes memory)
                  {
                      require(_length + 31 >= _length, "slice_overflow");
                      require(_bytes.length >= _start + _length, "slice_outOfBounds");
                      bytes memory tempBytes;
                      assembly {
                          switch iszero(_length)
                          case 0 {
                              // Get a location of some free memory and store it in tempBytes as
                              // Solidity does for memory variables.
                              tempBytes := mload(0x40)
                              // The first word of the slice result is potentially a partial
                              // word read from the original array. To read it, we calculate
                              // the length of that partial word and start copying that many
                              // bytes into the array. The first word we copy will start with
                              // data we don't care about, but the last `lengthmod` bytes will
                              // land at the beginning of the contents of the new array. When
                              // we're done copying, we overwrite the full first word with
                              // the actual length of the slice.
                              let lengthmod := and(_length, 31)
                              // The multiplication in the next line is necessary
                              // because when slicing multiples of 32 bytes (lengthmod == 0)
                              // the following copy loop was copying the origin's length
                              // and then ending prematurely not copying everything it should.
                              let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                              let end := add(mc, _length)
                              for {
                                  // The multiplication in the next line has the same exact purpose
                                  // as the one above.
                                  let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                              } lt(mc, end) {
                                  mc := add(mc, 0x20)
                                  cc := add(cc, 0x20)
                              } {
                                  mstore(mc, mload(cc))
                              }
                              mstore(tempBytes, _length)
                              //update free-memory pointer
                              //allocating the array padded to 32 bytes like the compiler does now
                              mstore(0x40, and(add(mc, 31), not(31)))
                          }
                          //if we want a zero-length slice let's just return a zero-length array
                          default {
                              tempBytes := mload(0x40)
                              //zero out the 32 bytes slice we are about to return
                              //we need to do it because Solidity does not garbage collect
                              mstore(tempBytes, 0)
                              mstore(0x40, add(tempBytes, 0x20))
                          }
                      }
                      return tempBytes;
                  }
                  function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
                      require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
                      address tempAddress;
                      assembly {
                          tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
                      }
                      return tempAddress;
                  }
                  function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
                      require(_bytes.length >= _start + 1 , "toUint8_outOfBounds");
                      uint8 tempUint;
                      assembly {
                          tempUint := mload(add(add(_bytes, 0x1), _start))
                      }
                      return tempUint;
                  }
                  function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
                      require(_bytes.length >= _start + 2, "toUint16_outOfBounds");
                      uint16 tempUint;
                      assembly {
                          tempUint := mload(add(add(_bytes, 0x2), _start))
                      }
                      return tempUint;
                  }
                  function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
                      require(_bytes.length >= _start + 4, "toUint32_outOfBounds");
                      uint32 tempUint;
                      assembly {
                          tempUint := mload(add(add(_bytes, 0x4), _start))
                      }
                      return tempUint;
                  }
                  function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
                      require(_bytes.length >= _start + 8, "toUint64_outOfBounds");
                      uint64 tempUint;
                      assembly {
                          tempUint := mload(add(add(_bytes, 0x8), _start))
                      }
                      return tempUint;
                  }
                  function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {
                      require(_bytes.length >= _start + 12, "toUint96_outOfBounds");
                      uint96 tempUint;
                      assembly {
                          tempUint := mload(add(add(_bytes, 0xc), _start))
                      }
                      return tempUint;
                  }
                  function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
                      require(_bytes.length >= _start + 16, "toUint128_outOfBounds");
                      uint128 tempUint;
                      assembly {
                          tempUint := mload(add(add(_bytes, 0x10), _start))
                      }
                      return tempUint;
                  }
                  function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
                      require(_bytes.length >= _start + 32, "toUint256_outOfBounds");
                      uint256 tempUint;
                      assembly {
                          tempUint := mload(add(add(_bytes, 0x20), _start))
                      }
                      return tempUint;
                  }
                  function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
                      require(_bytes.length >= _start + 32, "toBytes32_outOfBounds");
                      bytes32 tempBytes32;
                      assembly {
                          tempBytes32 := mload(add(add(_bytes, 0x20), _start))
                      }
                      return tempBytes32;
                  }
                  function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
                      bool success = true;
                      assembly {
                          let length := mload(_preBytes)
                          // if lengths don't match the arrays are not equal
                          switch eq(length, mload(_postBytes))
                          case 1 {
                              // cb is a circuit breaker in the for loop since there's
                              //  no said feature for inline assembly loops
                              // cb = 1 - don't breaker
                              // cb = 0 - break
                              let cb := 1
                              let mc := add(_preBytes, 0x20)
                              let end := add(mc, length)
                              for {
                                  let cc := add(_postBytes, 0x20)
                              // the next line is the loop condition:
                              // while(uint256(mc < end) + cb == 2)
                              } eq(add(lt(mc, end), cb), 2) {
                                  mc := add(mc, 0x20)
                                  cc := add(cc, 0x20)
                              } {
                                  // if any of these checks fails then arrays are not equal
                                  if iszero(eq(mload(mc), mload(cc))) {
                                      // unsuccess:
                                      success := 0
                                      cb := 0
                                  }
                              }
                          }
                          default {
                              // unsuccess:
                              success := 0
                          }
                      }
                      return success;
                  }
                  function equalStorage(
                      bytes storage _preBytes,
                      bytes memory _postBytes
                  )
                      internal
                      view
                      returns (bool)
                  {
                      bool success = true;
                      assembly {
                          // we know _preBytes_offset is 0
                          let fslot := sload(_preBytes.slot)
                          // Decode the length of the stored array like in concatStorage().
                          let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
                          let mlength := mload(_postBytes)
                          // if lengths don't match the arrays are not equal
                          switch eq(slength, mlength)
                          case 1 {
                              // slength can contain both the length and contents of the array
                              // if length < 32 bytes so let's prepare for that
                              // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                              if iszero(iszero(slength)) {
                                  switch lt(slength, 32)
                                  case 1 {
                                      // blank the last byte which is the length
                                      fslot := mul(div(fslot, 0x100), 0x100)
                                      if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
                                          // unsuccess:
                                          success := 0
                                      }
                                  }
                                  default {
                                      // cb is a circuit breaker in the for loop since there's
                                      //  no said feature for inline assembly loops
                                      // cb = 1 - don't breaker
                                      // cb = 0 - break
                                      let cb := 1
                                      // get the keccak hash to get the contents of the array
                                      mstore(0x0, _preBytes.slot)
                                      let sc := keccak256(0x0, 0x20)
                                      let mc := add(_postBytes, 0x20)
                                      let end := add(mc, mlength)
                                      // the next line is the loop condition:
                                      // while(uint256(mc < end) + cb == 2)
                                      for {} eq(add(lt(mc, end), cb), 2) {
                                          sc := add(sc, 1)
                                          mc := add(mc, 0x20)
                                      } {
                                          if iszero(eq(sload(sc), mload(mc))) {
                                              // unsuccess:
                                              success := 0
                                              cb := 0
                                          }
                                      }
                                  }
                              }
                          }
                          default {
                              // unsuccess:
                              success := 0
                          }
                      }
                      return success;
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.4;
              /// @notice Gas optimized ECDSA wrapper.
              /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol)
              /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol)
              /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol)
              ///
              /// @dev Note:
              /// - The recovery functions use the ecrecover precompile (0x1).
              /// - As of Solady version 0.0.68, the `recover` variants will revert upon recovery failure.
              ///   This is for more safety by default.
              ///   Use the `tryRecover` variants if you need to get the zero address back
              ///   upon recovery failure instead.
              /// - As of Solady version 0.0.134, all `bytes signature` variants accept both
              ///   regular 65-byte `(r, s, v)` and EIP-2098 `(r, vs)` short form signatures.
              ///   See: https://eips.ethereum.org/EIPS/eip-2098
              ///   This is for calldata efficiency on smart accounts prevalent on L2s.
              ///
              /// WARNING! Do NOT directly use signatures as unique identifiers:
              /// - The recovery operations do NOT check if a signature is non-malleable.
              /// - Use a nonce in the digest to prevent replay attacks on the same contract.
              /// - Use EIP-712 for the digest to prevent replay attacks across different chains and contracts.
              ///   EIP-712 also enables readable signing of typed data for better user safety.
              /// - If you need a unique hash from a signature, please use the `canonicalHash` functions.
              library ECDSA {
                  /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
                  /*                         CONSTANTS                          */
                  /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
                  /// @dev The order of the secp256k1 elliptic curve.
                  uint256 internal constant N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141;
                  /// @dev `N/2 + 1`. Used for checking the malleability of the signature.
                  uint256 private constant _HALF_N_PLUS_1 =
                      0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1;
                  /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
                  /*                        CUSTOM ERRORS                       */
                  /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
                  /// @dev The signature is invalid.
                  error InvalidSignature();
                  /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
                  /*                    RECOVERY OPERATIONS                     */
                  /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
                  /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
                  function recover(bytes32 hash, bytes memory signature) internal view returns (address result) {
                      /// @solidity memory-safe-assembly
                      assembly {
                          for { let m := mload(0x40) } 1 {
                              mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                              revert(0x1c, 0x04)
                          } {
                              switch mload(signature)
                              case 64 {
                                  let vs := mload(add(signature, 0x40))
                                  mstore(0x20, add(shr(255, vs), 27)) // `v`.
                                  mstore(0x60, shr(1, shl(1, vs))) // `s`.
                              }
                              case 65 {
                                  mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
                                  mstore(0x60, mload(add(signature, 0x40))) // `s`.
                              }
                              default { continue }
                              mstore(0x00, hash)
                              mstore(0x40, mload(add(signature, 0x20))) // `r`.
                              result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                              mstore(0x60, 0) // Restore the zero slot.
                              mstore(0x40, m) // Restore the free memory pointer.
                              // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                              if returndatasize() { break }
                          }
                      }
                  }
                  /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
                  function recoverCalldata(bytes32 hash, bytes calldata signature)
                      internal
                      view
                      returns (address result)
                  {
                      /// @solidity memory-safe-assembly
                      assembly {
                          for { let m := mload(0x40) } 1 {
                              mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                              revert(0x1c, 0x04)
                          } {
                              switch signature.length
                              case 64 {
                                  let vs := calldataload(add(signature.offset, 0x20))
                                  mstore(0x20, add(shr(255, vs), 27)) // `v`.
                                  mstore(0x40, calldataload(signature.offset)) // `r`.
                                  mstore(0x60, shr(1, shl(1, vs))) // `s`.
                              }
                              case 65 {
                                  mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
                                  calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.
                              }
                              default { continue }
                              mstore(0x00, hash)
                              result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                              mstore(0x60, 0) // Restore the zero slot.
                              mstore(0x40, m) // Restore the free memory pointer.
                              // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                              if returndatasize() { break }
                          }
                      }
                  }
                  /// @dev Recovers the signer's address from a message digest `hash`,
                  /// and the EIP-2098 short form signature defined by `r` and `vs`.
                  function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) {
                      /// @solidity memory-safe-assembly
                      assembly {
                          let m := mload(0x40) // Cache the free memory pointer.
                          mstore(0x00, hash)
                          mstore(0x20, add(shr(255, vs), 27)) // `v`.
                          mstore(0x40, r)
                          mstore(0x60, shr(1, shl(1, vs))) // `s`.
                          result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                          // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                          if iszero(returndatasize()) {
                              mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                              revert(0x1c, 0x04)
                          }
                          mstore(0x60, 0) // Restore the zero slot.
                          mstore(0x40, m) // Restore the free memory pointer.
                      }
                  }
                  /// @dev Recovers the signer's address from a message digest `hash`,
                  /// and the signature defined by `v`, `r`, `s`.
                  function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
                      internal
                      view
                      returns (address result)
                  {
                      /// @solidity memory-safe-assembly
                      assembly {
                          let m := mload(0x40) // Cache the free memory pointer.
                          mstore(0x00, hash)
                          mstore(0x20, and(v, 0xff))
                          mstore(0x40, r)
                          mstore(0x60, s)
                          result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                          // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                          if iszero(returndatasize()) {
                              mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                              revert(0x1c, 0x04)
                          }
                          mstore(0x60, 0) // Restore the zero slot.
                          mstore(0x40, m) // Restore the free memory pointer.
                      }
                  }
                  /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
                  /*                   TRY-RECOVER OPERATIONS                   */
                  /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
                  // WARNING!
                  // These functions will NOT revert upon recovery failure.
                  // Instead, they will return the zero address upon recovery failure.
                  // It is critical that the returned address is NEVER compared against
                  // a zero address (e.g. an uninitialized address variable).
                  /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
                  function tryRecover(bytes32 hash, bytes memory signature)
                      internal
                      view
                      returns (address result)
                  {
                      /// @solidity memory-safe-assembly
                      assembly {
                          for { let m := mload(0x40) } 1 {} {
                              switch mload(signature)
                              case 64 {
                                  let vs := mload(add(signature, 0x40))
                                  mstore(0x20, add(shr(255, vs), 27)) // `v`.
                                  mstore(0x60, shr(1, shl(1, vs))) // `s`.
                              }
                              case 65 {
                                  mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
                                  mstore(0x60, mload(add(signature, 0x40))) // `s`.
                              }
                              default { break }
                              mstore(0x00, hash)
                              mstore(0x40, mload(add(signature, 0x20))) // `r`.
                              pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
                              mstore(0x60, 0) // Restore the zero slot.
                              // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                              result := mload(xor(0x60, returndatasize()))
                              mstore(0x40, m) // Restore the free memory pointer.
                              break
                          }
                      }
                  }
                  /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
                  function tryRecoverCalldata(bytes32 hash, bytes calldata signature)
                      internal
                      view
                      returns (address result)
                  {
                      /// @solidity memory-safe-assembly
                      assembly {
                          for { let m := mload(0x40) } 1 {} {
                              switch signature.length
                              case 64 {
                                  let vs := calldataload(add(signature.offset, 0x20))
                                  mstore(0x20, add(shr(255, vs), 27)) // `v`.
                                  mstore(0x40, calldataload(signature.offset)) // `r`.
                                  mstore(0x60, shr(1, shl(1, vs))) // `s`.
                              }
                              case 65 {
                                  mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
                                  calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.
                              }
                              default { break }
                              mstore(0x00, hash)
                              pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
                              mstore(0x60, 0) // Restore the zero slot.
                              // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                              result := mload(xor(0x60, returndatasize()))
                              mstore(0x40, m) // Restore the free memory pointer.
                              break
                          }
                      }
                  }
                  /// @dev Recovers the signer's address from a message digest `hash`,
                  /// and the EIP-2098 short form signature defined by `r` and `vs`.
                  function tryRecover(bytes32 hash, bytes32 r, bytes32 vs)
                      internal
                      view
                      returns (address result)
                  {
                      /// @solidity memory-safe-assembly
                      assembly {
                          let m := mload(0x40) // Cache the free memory pointer.
                          mstore(0x00, hash)
                          mstore(0x20, add(shr(255, vs), 27)) // `v`.
                          mstore(0x40, r)
                          mstore(0x60, shr(1, shl(1, vs))) // `s`.
                          pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
                          mstore(0x60, 0) // Restore the zero slot.
                          // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                          result := mload(xor(0x60, returndatasize()))
                          mstore(0x40, m) // Restore the free memory pointer.
                      }
                  }
                  /// @dev Recovers the signer's address from a message digest `hash`,
                  /// and the signature defined by `v`, `r`, `s`.
                  function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
                      internal
                      view
                      returns (address result)
                  {
                      /// @solidity memory-safe-assembly
                      assembly {
                          let m := mload(0x40) // Cache the free memory pointer.
                          mstore(0x00, hash)
                          mstore(0x20, and(v, 0xff))
                          mstore(0x40, r)
                          mstore(0x60, s)
                          pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20))
                          mstore(0x60, 0) // Restore the zero slot.
                          // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                          result := mload(xor(0x60, returndatasize()))
                          mstore(0x40, m) // Restore the free memory pointer.
                      }
                  }
                  /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
                  /*                     HASHING OPERATIONS                     */
                  /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
                  /// @dev Returns an Ethereum Signed Message, created from a `hash`.
                  /// This produces a hash corresponding to the one signed with the
                  /// [`eth_sign`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign)
                  /// JSON-RPC method as part of EIP-191.
                  function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) {
                      /// @solidity memory-safe-assembly
                      assembly {
                          mstore(0x20, hash) // Store into scratch space for keccak256.
                          mstore(0x00, "\\x00\\x00\\x00\\x00\\x19Ethereum Signed Message:\
              32") // 28 bytes.
                          result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`.
                      }
                  }
                  /// @dev Returns an Ethereum Signed Message, created from `s`.
                  /// This produces a hash corresponding to the one signed with the
                  /// [`eth_sign`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign)
                  /// JSON-RPC method as part of EIP-191.
                  /// Note: Supports lengths of `s` up to 999999 bytes.
                  function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) {
                      /// @solidity memory-safe-assembly
                      assembly {
                          let sLength := mload(s)
                          let o := 0x20
                          mstore(o, "\\x19Ethereum Signed Message:\
              ") // 26 bytes, zero-right-padded.
                          mstore(0x00, 0x00)
                          // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`.
                          for { let temp := sLength } 1 {} {
                              o := sub(o, 1)
                              mstore8(o, add(48, mod(temp, 10)))
                              temp := div(temp, 10)
                              if iszero(temp) { break }
                          }
                          let n := sub(0x3a, o) // Header length: `26 + 32 - o`.
                          // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes.
                          returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20))
                          mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header.
                          result := keccak256(add(s, sub(0x20, n)), add(n, sLength))
                          mstore(s, sLength) // Restore the length.
                      }
                  }
                  /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
                  /*                  CANONICAL HASH FUNCTIONS                  */
                  /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
                  // The following functions returns the hash of the signature in it's canonicalized format,
                  // which is the 65-byte `abi.encodePacked(r, s, uint8(v))`, where `v` is either 27 or 28.
                  // If `s` is greater than `N / 2` then it will be converted to `N - s`
                  // and the `v` value will be flipped.
                  // If the signature has an invalid length, or if `v` is invalid,
                  // a uniquely corrupt hash will be returned.
                  // These functions are useful for "poor-mans-VRF".
                  /// @dev Returns the canonical hash of `signature`.
                  function canonicalHash(bytes memory signature) internal pure returns (bytes32 result) {
                      // @solidity memory-safe-assembly
                      assembly {
                          let l := mload(signature)
                          for {} 1 {} {
                              mstore(0x00, mload(add(signature, 0x20))) // `r`.
                              let s := mload(add(signature, 0x40))
                              let v := mload(add(signature, 0x41))
                              if eq(l, 64) {
                                  v := add(shr(255, s), 27)
                                  s := shr(1, shl(1, s))
                              }
                              if iszero(lt(s, _HALF_N_PLUS_1)) {
                                  v := xor(v, 7)
                                  s := sub(N, s)
                              }
                              mstore(0x21, v)
                              mstore(0x20, s)
                              result := keccak256(0x00, 0x41)
                              mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
                              break
                          }
                          // If the length is neither 64 nor 65, return a uniquely corrupted hash.
                          if iszero(lt(sub(l, 64), 2)) {
                              // `bytes4(keccak256("InvalidSignatureLength"))`.
                              result := xor(keccak256(add(signature, 0x20), l), 0xd62f1ab2)
                          }
                      }
                  }
                  /// @dev Returns the canonical hash of `signature`.
                  function canonicalHashCalldata(bytes calldata signature)
                      internal
                      pure
                      returns (bytes32 result)
                  {
                      // @solidity memory-safe-assembly
                      assembly {
                          for {} 1 {} {
                              mstore(0x00, calldataload(signature.offset)) // `r`.
                              let s := calldataload(add(signature.offset, 0x20))
                              let v := calldataload(add(signature.offset, 0x21))
                              if eq(signature.length, 64) {
                                  v := add(shr(255, s), 27)
                                  s := shr(1, shl(1, s))
                              }
                              if iszero(lt(s, _HALF_N_PLUS_1)) {
                                  v := xor(v, 7)
                                  s := sub(N, s)
                              }
                              mstore(0x21, v)
                              mstore(0x20, s)
                              result := keccak256(0x00, 0x41)
                              mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
                              break
                          }
                          // If the length is neither 64 nor 65, return a uniquely corrupted hash.
                          if iszero(lt(sub(signature.length, 64), 2)) {
                              calldatacopy(mload(0x40), signature.offset, signature.length)
                              // `bytes4(keccak256("InvalidSignatureLength"))`.
                              result := xor(keccak256(mload(0x40), signature.length), 0xd62f1ab2)
                          }
                      }
                  }
                  /// @dev Returns the canonical hash of `signature`.
                  function canonicalHash(bytes32 r, bytes32 vs) internal pure returns (bytes32 result) {
                      // @solidity memory-safe-assembly
                      assembly {
                          mstore(0x00, r) // `r`.
                          let v := add(shr(255, vs), 27)
                          let s := shr(1, shl(1, vs))
                          mstore(0x21, v)
                          mstore(0x20, s)
                          result := keccak256(0x00, 0x41)
                          mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
                      }
                  }
                  /// @dev Returns the canonical hash of `signature`.
                  function canonicalHash(uint8 v, bytes32 r, bytes32 s) internal pure returns (bytes32 result) {
                      // @solidity memory-safe-assembly
                      assembly {
                          mstore(0x00, r) // `r`.
                          if iszero(lt(s, _HALF_N_PLUS_1)) {
                              v := xor(v, 7)
                              s := sub(N, s)
                          }
                          mstore(0x21, v)
                          mstore(0x20, s)
                          result := keccak256(0x00, 0x41)
                          mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
                      }
                  }
                  /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
                  /*                   EMPTY CALLDATA HELPERS                   */
                  /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
                  /// @dev Returns an empty calldata bytes.
                  function emptySignature() internal pure returns (bytes calldata signature) {
                      /// @solidity memory-safe-assembly
                      assembly {
                          signature.length := 0
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
              pragma solidity ^0.8.20;
              import {Math} from "./math/Math.sol";
              import {SignedMath} from "./math/SignedMath.sol";
              /**
               * @dev String operations.
               */
              library Strings {
                  bytes16 private constant HEX_DIGITS = "0123456789abcdef";
                  uint8 private constant ADDRESS_LENGTH = 20;
                  /**
                   * @dev The `value` string doesn't fit in the specified `length`.
                   */
                  error StringsInsufficientHexLength(uint256 value, uint256 length);
                  /**
                   * @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), HEX_DIGITS))
                              }
                              value /= 10;
                              if (value == 0) break;
                          }
                          return buffer;
                      }
                  }
                  /**
                   * @dev Converts a `int256` to its ASCII `string` decimal representation.
                   */
                  function toStringSigned(int256 value) internal pure returns (string memory) {
                      return string.concat(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) {
                      uint256 localValue = value;
                      bytes memory buffer = new bytes(2 * length + 2);
                      buffer[0] = "0";
                      buffer[1] = "x";
                      for (uint256 i = 2 * length + 1; i > 1; --i) {
                          buffer[i] = HEX_DIGITS[localValue & 0xf];
                          localValue >>= 4;
                      }
                      if (localValue != 0) {
                          revert StringsInsufficientHexLength(value, length);
                      }
                      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 bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev Standard math utilities missing in the Solidity language.
               */
              library Math {
                  /**
                   * @dev Muldiv operation overflow.
                   */
                  error MathOverflowedMulDiv();
                  enum Rounding {
                      Floor, // Toward negative infinity
                      Ceil, // Toward positive infinity
                      Trunc, // Toward zero
                      Expand // Away from zero
                  }
                  /**
                   * @dev Returns the addition of two unsigned integers, with an overflow flag.
                   */
                  function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      unchecked {
                          uint256 c = a + b;
                          if (c < a) return (false, 0);
                          return (true, c);
                      }
                  }
                  /**
                   * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
                   */
                  function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      unchecked {
                          if (b > a) return (false, 0);
                          return (true, a - b);
                      }
                  }
                  /**
                   * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
                   */
                  function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      unchecked {
                          // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                          // benefit is lost if 'b' is also tested.
                          // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                          if (a == 0) return (true, 0);
                          uint256 c = a * b;
                          if (c / a != b) return (false, 0);
                          return (true, c);
                      }
                  }
                  /**
                   * @dev Returns the division of two unsigned integers, with a division by zero flag.
                   */
                  function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      unchecked {
                          if (b == 0) return (false, 0);
                          return (true, a / b);
                      }
                  }
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
                   */
                  function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      unchecked {
                          if (b == 0) return (false, 0);
                          return (true, a % b);
                      }
                  }
                  /**
                   * @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 towards infinity instead
                   * of rounding towards zero.
                   */
                  function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
                      if (b == 0) {
                          // Guarantee the same behavior as in a regular Solidity division.
                          return a / b;
                      }
                      // (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 = x * y; // Least significant 256 bits of the product
                          uint256 prod1; // Most significant 256 bits of the product
                          assembly {
                              let mm := mulmod(x, y, not(0))
                              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.
                          if (denominator <= prod1) {
                              revert MathOverflowedMulDiv();
                          }
                          ///////////////////////////////////////////////
                          // 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.
                          uint256 twos = denominator & (0 - denominator);
                          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 (unsignedRoundsUp(rounding) && 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
                   * towards zero.
                   *
                   * 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 + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
                      }
                  }
                  /**
                   * @dev Return the log in base 2 of a positive value rounded towards zero.
                   * 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 + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
                      }
                  }
                  /**
                   * @dev Return the log in base 10 of a positive value rounded towards zero.
                   * 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 + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
                      }
                  }
                  /**
                   * @dev Return the log in base 256 of a positive value rounded towards zero.
                   * 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 + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
                      }
                  }
                  /**
                   * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
                   */
                  function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
                      return uint8(rounding) % 2 == 1;
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
              pragma solidity ^0.8.20;
              /**
               * @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);
                      }
                  }
              }
              

              File 4 of 4: CustomTokenFinal
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
              pragma solidity ^0.8.20;
              import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
              import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
              import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
              import {Initializable} from "../proxy/utils/Initializable.sol";
              /**
               * @dev Contract module that allows children to implement role-based access
               * control mechanisms. This is a lightweight version that doesn't allow enumerating role
               * members except through off-chain means by accessing the contract event logs. Some
               * applications may benefit from on-chain enumerability, for those cases see
               * {AccessControlEnumerable}.
               *
               * Roles are referred to by their `bytes32` identifier. These should be exposed
               * in the external API and be unique. The best way to achieve this is by
               * using `public constant` hash digests:
               *
               * ```solidity
               * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
               * ```
               *
               * Roles can be used to represent a set of permissions. To restrict access to a
               * function call, use {hasRole}:
               *
               * ```solidity
               * function foo() public {
               *     require(hasRole(MY_ROLE, msg.sender));
               *     ...
               * }
               * ```
               *
               * Roles can be granted and revoked dynamically via the {grantRole} and
               * {revokeRole} functions. Each role has an associated admin role, and only
               * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
               *
               * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
               * that only accounts with this role will be able to grant or revoke other
               * roles. More complex role relationships can be created by using
               * {_setRoleAdmin}.
               *
               * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
               * grant and revoke this role. Extra precautions should be taken to secure
               * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
               * to enforce additional security measures for this role.
               */
              abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {
                  struct RoleData {
                      mapping(address account => bool) hasRole;
                      bytes32 adminRole;
                  }
                  bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
                  /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
                  struct AccessControlStorage {
                      mapping(bytes32 role => RoleData) _roles;
                  }
                  // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
                  bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;
                  function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
                      assembly {
                          $.slot := AccessControlStorageLocation
                      }
                  }
                  /**
                   * @dev Modifier that checks that an account has a specific role. Reverts
                   * with an {AccessControlUnauthorizedAccount} error including the required role.
                   */
                  modifier onlyRole(bytes32 role) {
                      _checkRole(role);
                      _;
                  }
                  function __AccessControl_init() internal onlyInitializing {
                  }
                  function __AccessControl_init_unchained() internal onlyInitializing {
                  }
                  /**
                   * @dev See {IERC165-supportsInterface}.
                   */
                  function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                      return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
                  }
                  /**
                   * @dev Returns `true` if `account` has been granted `role`.
                   */
                  function hasRole(bytes32 role, address account) public view virtual returns (bool) {
                      AccessControlStorage storage $ = _getAccessControlStorage();
                      return $._roles[role].hasRole[account];
                  }
                  /**
                   * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
                   * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
                   */
                  function _checkRole(bytes32 role) internal view virtual {
                      _checkRole(role, _msgSender());
                  }
                  /**
                   * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
                   * is missing `role`.
                   */
                  function _checkRole(bytes32 role, address account) internal view virtual {
                      if (!hasRole(role, account)) {
                          revert AccessControlUnauthorizedAccount(account, role);
                      }
                  }
                  /**
                   * @dev Returns the admin role that controls `role`. See {grantRole} and
                   * {revokeRole}.
                   *
                   * To change a role's admin, use {_setRoleAdmin}.
                   */
                  function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
                      AccessControlStorage storage $ = _getAccessControlStorage();
                      return $._roles[role].adminRole;
                  }
                  /**
                   * @dev Grants `role` to `account`.
                   *
                   * If `account` had not been already granted `role`, emits a {RoleGranted}
                   * event.
                   *
                   * Requirements:
                   *
                   * - the caller must have ``role``'s admin role.
                   *
                   * May emit a {RoleGranted} event.
                   */
                  function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
                      _grantRole(role, account);
                  }
                  /**
                   * @dev Revokes `role` from `account`.
                   *
                   * If `account` had been granted `role`, emits a {RoleRevoked} event.
                   *
                   * Requirements:
                   *
                   * - the caller must have ``role``'s admin role.
                   *
                   * May emit a {RoleRevoked} event.
                   */
                  function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
                      _revokeRole(role, account);
                  }
                  /**
                   * @dev Revokes `role` from the calling account.
                   *
                   * Roles are often managed via {grantRole} and {revokeRole}: this function's
                   * purpose is to provide a mechanism for accounts to lose their privileges
                   * if they are compromised (such as when a trusted device is misplaced).
                   *
                   * If the calling account had been revoked `role`, emits a {RoleRevoked}
                   * event.
                   *
                   * Requirements:
                   *
                   * - the caller must be `callerConfirmation`.
                   *
                   * May emit a {RoleRevoked} event.
                   */
                  function renounceRole(bytes32 role, address callerConfirmation) public virtual {
                      if (callerConfirmation != _msgSender()) {
                          revert AccessControlBadConfirmation();
                      }
                      _revokeRole(role, callerConfirmation);
                  }
                  /**
                   * @dev Sets `adminRole` as ``role``'s admin role.
                   *
                   * Emits a {RoleAdminChanged} event.
                   */
                  function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
                      AccessControlStorage storage $ = _getAccessControlStorage();
                      bytes32 previousAdminRole = getRoleAdmin(role);
                      $._roles[role].adminRole = adminRole;
                      emit RoleAdminChanged(role, previousAdminRole, adminRole);
                  }
                  /**
                   * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
                   *
                   * Internal function without access restriction.
                   *
                   * May emit a {RoleGranted} event.
                   */
                  function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
                      AccessControlStorage storage $ = _getAccessControlStorage();
                      if (!hasRole(role, account)) {
                          $._roles[role].hasRole[account] = true;
                          emit RoleGranted(role, account, _msgSender());
                          return true;
                      } else {
                          return false;
                      }
                  }
                  /**
                   * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
                   *
                   * Internal function without access restriction.
                   *
                   * May emit a {RoleRevoked} event.
                   */
                  function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
                      AccessControlStorage storage $ = _getAccessControlStorage();
                      if (hasRole(role, account)) {
                          $._roles[role].hasRole[account] = false;
                          emit RoleRevoked(role, account, _msgSender());
                          return true;
                      } else {
                          return false;
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
               * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
               * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
               * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
               *
               * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
               * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
               * case an upgrade adds a module that needs to be initialized.
               *
               * For example:
               *
               * [.hljs-theme-light.nopadding]
               * ```solidity
               * contract MyToken is ERC20Upgradeable {
               *     function initialize() initializer public {
               *         __ERC20_init("MyToken", "MTK");
               *     }
               * }
               *
               * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
               *     function initializeV2() reinitializer(2) public {
               *         __ERC20Permit_init("MyToken");
               *     }
               * }
               * ```
               *
               * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
               * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
               *
               * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
               * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
               *
               * [CAUTION]
               * ====
               * Avoid leaving a contract uninitialized.
               *
               * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
               * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
               * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
               *
               * [.hljs-theme-light.nopadding]
               * ```
               * /// @custom:oz-upgrades-unsafe-allow constructor
               * constructor() {
               *     _disableInitializers();
               * }
               * ```
               * ====
               */
              abstract contract Initializable {
                  /**
                   * @dev Storage of the initializable contract.
                   *
                   * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
                   * when using with upgradeable contracts.
                   *
                   * @custom:storage-location erc7201:openzeppelin.storage.Initializable
                   */
                  struct InitializableStorage {
                      /**
                       * @dev Indicates that the contract has been initialized.
                       */
                      uint64 _initialized;
                      /**
                       * @dev Indicates that the contract is in the process of being initialized.
                       */
                      bool _initializing;
                  }
                  // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
                  bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
                  /**
                   * @dev The contract is already initialized.
                   */
                  error InvalidInitialization();
                  /**
                   * @dev The contract is not initializing.
                   */
                  error NotInitializing();
                  /**
                   * @dev Triggered when the contract has been initialized or reinitialized.
                   */
                  event Initialized(uint64 version);
                  /**
                   * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
                   * `onlyInitializing` functions can be used to initialize parent contracts.
                   *
                   * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
                   * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
                   * production.
                   *
                   * Emits an {Initialized} event.
                   */
                  modifier initializer() {
                      // solhint-disable-next-line var-name-mixedcase
                      InitializableStorage storage $ = _getInitializableStorage();
                      // Cache values to avoid duplicated sloads
                      bool isTopLevelCall = !$._initializing;
                      uint64 initialized = $._initialized;
                      // Allowed calls:
                      // - initialSetup: the contract is not in the initializing state and no previous version was
                      //                 initialized
                      // - construction: the contract is initialized at version 1 (no reininitialization) and the
                      //                 current contract is just being deployed
                      bool initialSetup = initialized == 0 && isTopLevelCall;
                      bool construction = initialized == 1 && address(this).code.length == 0;
                      if (!initialSetup && !construction) {
                          revert InvalidInitialization();
                      }
                      $._initialized = 1;
                      if (isTopLevelCall) {
                          $._initializing = true;
                      }
                      _;
                      if (isTopLevelCall) {
                          $._initializing = false;
                          emit Initialized(1);
                      }
                  }
                  /**
                   * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
                   * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
                   * used to initialize parent contracts.
                   *
                   * A reinitializer may be used after the original initialization step. This is essential to configure modules that
                   * are added through upgrades and that require initialization.
                   *
                   * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
                   * cannot be nested. If one is invoked in the context of another, execution will revert.
                   *
                   * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
                   * a contract, executing them in the right order is up to the developer or operator.
                   *
                   * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
                   *
                   * Emits an {Initialized} event.
                   */
                  modifier reinitializer(uint64 version) {
                      // solhint-disable-next-line var-name-mixedcase
                      InitializableStorage storage $ = _getInitializableStorage();
                      if ($._initializing || $._initialized >= version) {
                          revert InvalidInitialization();
                      }
                      $._initialized = version;
                      $._initializing = true;
                      _;
                      $._initializing = false;
                      emit Initialized(version);
                  }
                  /**
                   * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
                   * {initializer} and {reinitializer} modifiers, directly or indirectly.
                   */
                  modifier onlyInitializing() {
                      _checkInitializing();
                      _;
                  }
                  /**
                   * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
                   */
                  function _checkInitializing() internal view virtual {
                      if (!_isInitializing()) {
                          revert NotInitializing();
                      }
                  }
                  /**
                   * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
                   * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
                   * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
                   * through proxies.
                   *
                   * Emits an {Initialized} event the first time it is successfully executed.
                   */
                  function _disableInitializers() internal virtual {
                      // solhint-disable-next-line var-name-mixedcase
                      InitializableStorage storage $ = _getInitializableStorage();
                      if ($._initializing) {
                          revert InvalidInitialization();
                      }
                      if ($._initialized != type(uint64).max) {
                          $._initialized = type(uint64).max;
                          emit Initialized(type(uint64).max);
                      }
                  }
                  /**
                   * @dev Returns the highest version that has been initialized. See {reinitializer}.
                   */
                  function _getInitializedVersion() internal view returns (uint64) {
                      return _getInitializableStorage()._initialized;
                  }
                  /**
                   * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
                   */
                  function _isInitializing() internal view returns (bool) {
                      return _getInitializableStorage()._initializing;
                  }
                  /**
                   * @dev Returns a pointer to the storage namespace.
                   */
                  // solhint-disable-next-line var-name-mixedcase
                  function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
                      assembly {
                          $.slot := INITIALIZABLE_STORAGE
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.2.0) (proxy/utils/UUPSUpgradeable.sol)
              pragma solidity ^0.8.22;
              import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
              import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
              import {Initializable} from "./Initializable.sol";
              /**
               * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
               * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
               *
               * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
               * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
               * `UUPSUpgradeable` with a custom implementation of upgrades.
               *
               * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
               */
              abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
                  /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
                  address private immutable __self = address(this);
                  /**
                   * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
                   * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
                   * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
                   * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
                   * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
                   * during an upgrade.
                   */
                  string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
                  /**
                   * @dev The call is from an unauthorized context.
                   */
                  error UUPSUnauthorizedCallContext();
                  /**
                   * @dev The storage `slot` is unsupported as a UUID.
                   */
                  error UUPSUnsupportedProxiableUUID(bytes32 slot);
                  /**
                   * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
                   * a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case
                   * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
                   * function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
                   * fail.
                   */
                  modifier onlyProxy() {
                      _checkProxy();
                      _;
                  }
                  /**
                   * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
                   * callable on the implementing contract but not through proxies.
                   */
                  modifier notDelegated() {
                      _checkNotDelegated();
                      _;
                  }
                  function __UUPSUpgradeable_init() internal onlyInitializing {
                  }
                  function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
                  }
                  /**
                   * @dev Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the
                   * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
                   *
                   * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
                   * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
                   * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
                   */
                  function proxiableUUID() external view virtual notDelegated returns (bytes32) {
                      return ERC1967Utils.IMPLEMENTATION_SLOT;
                  }
                  /**
                   * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
                   * encoded in `data`.
                   *
                   * Calls {_authorizeUpgrade}.
                   *
                   * Emits an {Upgraded} event.
                   *
                   * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
                   */
                  function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
                      _authorizeUpgrade(newImplementation);
                      _upgradeToAndCallUUPS(newImplementation, data);
                  }
                  /**
                   * @dev Reverts if the execution is not performed via delegatecall or the execution
                   * context is not of a proxy with an ERC-1967 compliant implementation pointing to self.
                   * See {_onlyProxy}.
                   */
                  function _checkProxy() internal view virtual {
                      if (
                          address(this) == __self || // Must be called through delegatecall
                          ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
                      ) {
                          revert UUPSUnauthorizedCallContext();
                      }
                  }
                  /**
                   * @dev Reverts if the execution is performed via delegatecall.
                   * See {notDelegated}.
                   */
                  function _checkNotDelegated() internal view virtual {
                      if (address(this) != __self) {
                          // Must not be called through delegatecall
                          revert UUPSUnauthorizedCallContext();
                      }
                  }
                  /**
                   * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
                   * {upgradeToAndCall}.
                   *
                   * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
                   *
                   * ```solidity
                   * function _authorizeUpgrade(address) internal onlyOwner {}
                   * ```
                   */
                  function _authorizeUpgrade(address newImplementation) internal virtual;
                  /**
                   * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
                   *
                   * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
                   * is expected to be the implementation slot in ERC-1967.
                   *
                   * Emits an {IERC1967-Upgraded} event.
                   */
                  function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
                      try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                          if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
                              revert UUPSUnsupportedProxiableUUID(slot);
                          }
                          ERC1967Utils.upgradeToAndCall(newImplementation, data);
                      } catch {
                          // The implementation is not UUPS
                          revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/ERC20.sol)
              pragma solidity ^0.8.20;
              import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
              import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
              import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol";
              import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
              import {Initializable} from "../../proxy/utils/Initializable.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}.
               *
               * 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 ERC-20
               * applications.
               */
              abstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, IERC20Metadata, IERC20Errors {
                  /// @custom:storage-location erc7201:openzeppelin.storage.ERC20
                  struct ERC20Storage {
                      mapping(address account => uint256) _balances;
                      mapping(address account => mapping(address spender => uint256)) _allowances;
                      uint256 _totalSupply;
                      string _name;
                      string _symbol;
                  }
                  // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC20")) - 1)) & ~bytes32(uint256(0xff))
                  bytes32 private constant ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00;
                  function _getERC20Storage() private pure returns (ERC20Storage storage $) {
                      assembly {
                          $.slot := ERC20StorageLocation
                      }
                  }
                  /**
                   * @dev Sets the values for {name} and {symbol}.
                   *
                   * All two of these values are immutable: they can only be set once during
                   * construction.
                   */
                  function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {
                      __ERC20_init_unchained(name_, symbol_);
                  }
                  function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
                      ERC20Storage storage $ = _getERC20Storage();
                      $._name = name_;
                      $._symbol = symbol_;
                  }
                  /**
                   * @dev Returns the name of the token.
                   */
                  function name() public view virtual returns (string memory) {
                      ERC20Storage storage $ = _getERC20Storage();
                      return $._name;
                  }
                  /**
                   * @dev Returns the symbol of the token, usually a shorter version of the
                   * name.
                   */
                  function symbol() public view virtual returns (string memory) {
                      ERC20Storage storage $ = _getERC20Storage();
                      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 returns (uint8) {
                      return 18;
                  }
                  /**
                   * @dev See {IERC20-totalSupply}.
                   */
                  function totalSupply() public view virtual returns (uint256) {
                      ERC20Storage storage $ = _getERC20Storage();
                      return $._totalSupply;
                  }
                  /**
                   * @dev See {IERC20-balanceOf}.
                   */
                  function balanceOf(address account) public view virtual returns (uint256) {
                      ERC20Storage storage $ = _getERC20Storage();
                      return $._balances[account];
                  }
                  /**
                   * @dev See {IERC20-transfer}.
                   *
                   * Requirements:
                   *
                   * - `to` cannot be the zero address.
                   * - the caller must have a balance of at least `value`.
                   */
                  function transfer(address to, uint256 value) public virtual returns (bool) {
                      address owner = _msgSender();
                      _transfer(owner, to, value);
                      return true;
                  }
                  /**
                   * @dev See {IERC20-allowance}.
                   */
                  function allowance(address owner, address spender) public view virtual returns (uint256) {
                      ERC20Storage storage $ = _getERC20Storage();
                      return $._allowances[owner][spender];
                  }
                  /**
                   * @dev See {IERC20-approve}.
                   *
                   * NOTE: If `value` 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 value) public virtual returns (bool) {
                      address owner = _msgSender();
                      _approve(owner, spender, value);
                      return true;
                  }
                  /**
                   * @dev See {IERC20-transferFrom}.
                   *
                   * Skips emitting an {Approval} event indicating an allowance update. This is not
                   * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
                   *
                   * 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 `value`.
                   * - the caller must have allowance for ``from``'s tokens of at least
                   * `value`.
                   */
                  function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
                      address spender = _msgSender();
                      _spendAllowance(from, spender, value);
                      _transfer(from, to, value);
                      return true;
                  }
                  /**
                   * @dev Moves a `value` 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.
                   *
                   * NOTE: This function is not virtual, {_update} should be overridden instead.
                   */
                  function _transfer(address from, address to, uint256 value) internal {
                      if (from == address(0)) {
                          revert ERC20InvalidSender(address(0));
                      }
                      if (to == address(0)) {
                          revert ERC20InvalidReceiver(address(0));
                      }
                      _update(from, to, value);
                  }
                  /**
                   * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
                   * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
                   * this function.
                   *
                   * Emits a {Transfer} event.
                   */
                  function _update(address from, address to, uint256 value) internal virtual {
                      ERC20Storage storage $ = _getERC20Storage();
                      if (from == address(0)) {
                          // Overflow check required: The rest of the code assumes that totalSupply never overflows
                          $._totalSupply += value;
                      } else {
                          uint256 fromBalance = $._balances[from];
                          if (fromBalance < value) {
                              revert ERC20InsufficientBalance(from, fromBalance, value);
                          }
                          unchecked {
                              // Overflow not possible: value <= fromBalance <= totalSupply.
                              $._balances[from] = fromBalance - value;
                          }
                      }
                      if (to == address(0)) {
                          unchecked {
                              // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                              $._totalSupply -= value;
                          }
                      } else {
                          unchecked {
                              // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                              $._balances[to] += value;
                          }
                      }
                      emit Transfer(from, to, value);
                  }
                  /**
                   * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
                   * Relies on the `_update` mechanism
                   *
                   * Emits a {Transfer} event with `from` set to the zero address.
                   *
                   * NOTE: This function is not virtual, {_update} should be overridden instead.
                   */
                  function _mint(address account, uint256 value) internal {
                      if (account == address(0)) {
                          revert ERC20InvalidReceiver(address(0));
                      }
                      _update(address(0), account, value);
                  }
                  /**
                   * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
                   * Relies on the `_update` mechanism.
                   *
                   * Emits a {Transfer} event with `to` set to the zero address.
                   *
                   * NOTE: This function is not virtual, {_update} should be overridden instead
                   */
                  function _burn(address account, uint256 value) internal {
                      if (account == address(0)) {
                          revert ERC20InvalidSender(address(0));
                      }
                      _update(account, address(0), value);
                  }
                  /**
                   * @dev Sets `value` 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.
                   *
                   * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
                   */
                  function _approve(address owner, address spender, uint256 value) internal {
                      _approve(owner, spender, value, true);
                  }
                  /**
                   * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
                   *
                   * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
                   * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
                   * `Approval` event during `transferFrom` operations.
                   *
                   * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
                   * true using the following override:
                   *
                   * ```solidity
                   * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
                   *     super._approve(owner, spender, value, true);
                   * }
                   * ```
                   *
                   * Requirements are the same as {_approve}.
                   */
                  function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
                      ERC20Storage storage $ = _getERC20Storage();
                      if (owner == address(0)) {
                          revert ERC20InvalidApprover(address(0));
                      }
                      if (spender == address(0)) {
                          revert ERC20InvalidSpender(address(0));
                      }
                      $._allowances[owner][spender] = value;
                      if (emitEvent) {
                          emit Approval(owner, spender, value);
                      }
                  }
                  /**
                   * @dev Updates `owner` s allowance for `spender` based on spent `value`.
                   *
                   * Does not update the allowance value in case of infinite allowance.
                   * Revert if not enough allowance is available.
                   *
                   * Does not emit an {Approval} event.
                   */
                  function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
                      uint256 currentAllowance = allowance(owner, spender);
                      if (currentAllowance < type(uint256).max) {
                          if (currentAllowance < value) {
                              revert ERC20InsufficientAllowance(spender, currentAllowance, value);
                          }
                          unchecked {
                              _approve(owner, spender, currentAllowance - value, false);
                          }
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol)
              pragma solidity ^0.8.20;
              import {ERC20Upgradeable} from "../ERC20Upgradeable.sol";
              import {ContextUpgradeable} from "../../../utils/ContextUpgradeable.sol";
              import {Initializable} from "../../../proxy/utils/Initializable.sol";
              /**
               * @dev Extension of {ERC20} that allows token holders to destroy both their own
               * tokens and those that they have an allowance for, in a way that can be
               * recognized off-chain (via event analysis).
               */
              abstract contract ERC20BurnableUpgradeable is Initializable, ContextUpgradeable, ERC20Upgradeable {
                  function __ERC20Burnable_init() internal onlyInitializing {
                  }
                  function __ERC20Burnable_init_unchained() internal onlyInitializing {
                  }
                  /**
                   * @dev Destroys a `value` amount of tokens from the caller.
                   *
                   * See {ERC20-_burn}.
                   */
                  function burn(uint256 value) public virtual {
                      _burn(_msgSender(), value);
                  }
                  /**
                   * @dev Destroys a `value` amount of tokens from `account`, deducting from
                   * the caller's allowance.
                   *
                   * See {ERC20-_burn} and {ERC20-allowance}.
                   *
                   * Requirements:
                   *
                   * - the caller must have allowance for ``accounts``'s tokens of at least
                   * `value`.
                   */
                  function burnFrom(address account, uint256 value) public virtual {
                      _spendAllowance(account, _msgSender(), value);
                      _burn(account, value);
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/ERC20Permit.sol)
              pragma solidity ^0.8.20;
              import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
              import {ERC20Upgradeable} from "../ERC20Upgradeable.sol";
              import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
              import {EIP712Upgradeable} from "../../../utils/cryptography/EIP712Upgradeable.sol";
              import {NoncesUpgradeable} from "../../../utils/NoncesUpgradeable.sol";
              import {Initializable} from "../../../proxy/utils/Initializable.sol";
              /**
               * @dev Implementation of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in
               * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612].
               *
               * Adds the {permit} method, which can be used to change an account's ERC-20 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.
               */
              abstract contract ERC20PermitUpgradeable is Initializable, ERC20Upgradeable, IERC20Permit, EIP712Upgradeable, NoncesUpgradeable {
                  bytes32 private constant PERMIT_TYPEHASH =
                      keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
                  /**
                   * @dev Permit deadline has expired.
                   */
                  error ERC2612ExpiredSignature(uint256 deadline);
                  /**
                   * @dev Mismatched signature.
                   */
                  error ERC2612InvalidSigner(address signer, address owner);
                  /**
                   * @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 ERC-20 token name.
                   */
                  function __ERC20Permit_init(string memory name) internal onlyInitializing {
                      __EIP712_init_unchained(name, "1");
                  }
                  function __ERC20Permit_init_unchained(string memory) internal onlyInitializing {}
                  /**
                   * @inheritdoc IERC20Permit
                   */
                  function permit(
                      address owner,
                      address spender,
                      uint256 value,
                      uint256 deadline,
                      uint8 v,
                      bytes32 r,
                      bytes32 s
                  ) public virtual {
                      if (block.timestamp > deadline) {
                          revert ERC2612ExpiredSignature(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);
                      if (signer != owner) {
                          revert ERC2612InvalidSigner(signer, owner);
                      }
                      _approve(owner, spender, value);
                  }
                  /**
                   * @inheritdoc IERC20Permit
                   */
                  function nonces(address owner) public view virtual override(IERC20Permit, NoncesUpgradeable) returns (uint256) {
                      return super.nonces(owner);
                  }
                  /**
                   * @inheritdoc IERC20Permit
                   */
                  // solhint-disable-next-line func-name-mixedcase
                  function DOMAIN_SEPARATOR() external view virtual returns (bytes32) {
                      return _domainSeparatorV4();
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
              pragma solidity ^0.8.20;
              import {Initializable} from "../proxy/utils/Initializable.sol";
              /**
               * @dev Provides information about the current execution context, including the
               * sender of the transaction and its data. While these are generally available
               * via msg.sender and msg.data, they should not be accessed in such a direct
               * manner, since when dealing with meta-transactions the account sending and
               * paying for execution may not be the actual sender (as far as an application
               * is concerned).
               *
               * This contract is only required for intermediate, library-like contracts.
               */
              abstract contract ContextUpgradeable is Initializable {
                  function __Context_init() internal onlyInitializing {
                  }
                  function __Context_init_unchained() internal onlyInitializing {
                  }
                  function _msgSender() internal view virtual returns (address) {
                      return msg.sender;
                  }
                  function _msgData() internal view virtual returns (bytes calldata) {
                      return msg.data;
                  }
                  function _contextSuffixLength() internal view virtual returns (uint256) {
                      return 0;
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/EIP712.sol)
              pragma solidity ^0.8.20;
              import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
              import {IERC5267} from "@openzeppelin/contracts/interfaces/IERC5267.sol";
              import {Initializable} from "../../proxy/utils/Initializable.sol";
              /**
               * @dev https://eips.ethereum.org/EIPS/eip-712[EIP-712] is a standard for hashing and signing of typed structured data.
               *
               * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
               * encoding is very generic and therefore its 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 order to
               * produce the hash of their typed data 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.
               */
              abstract contract EIP712Upgradeable is Initializable, IERC5267 {
                  bytes32 private constant TYPE_HASH =
                      keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
                  /// @custom:storage-location erc7201:openzeppelin.storage.EIP712
                  struct EIP712Storage {
                      /// @custom:oz-renamed-from _HASHED_NAME
                      bytes32 _hashedName;
                      /// @custom:oz-renamed-from _HASHED_VERSION
                      bytes32 _hashedVersion;
                      string _name;
                      string _version;
                  }
                  // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.EIP712")) - 1)) & ~bytes32(uint256(0xff))
                  bytes32 private constant EIP712StorageLocation = 0xa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100;
                  function _getEIP712Storage() private pure returns (EIP712Storage storage $) {
                      assembly {
                          $.slot := EIP712StorageLocation
                      }
                  }
                  /**
                   * @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].
                   */
                  function __EIP712_init(string memory name, string memory version) internal onlyInitializing {
                      __EIP712_init_unchained(name, version);
                  }
                  function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {
                      EIP712Storage storage $ = _getEIP712Storage();
                      $._name = name;
                      $._version = version;
                      // Reset prior values in storage if upgrading
                      $._hashedName = 0;
                      $._hashedVersion = 0;
                  }
                  /**
                   * @dev Returns the domain separator for the current chain.
                   */
                  function _domainSeparatorV4() internal view returns (bytes32) {
                      return _buildDomainSeparator();
                  }
                  function _buildDomainSeparator() private view returns (bytes32) {
                      return keccak256(abi.encode(TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), 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 MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
                  }
                  /**
                   * @dev See {IERC-5267}.
                   */
                  function eip712Domain()
                      public
                      view
                      virtual
                      returns (
                          bytes1 fields,
                          string memory name,
                          string memory version,
                          uint256 chainId,
                          address verifyingContract,
                          bytes32 salt,
                          uint256[] memory extensions
                      )
                  {
                      EIP712Storage storage $ = _getEIP712Storage();
                      // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized
                      // and the EIP712 domain is not reliable, as it will be missing name and version.
                      require($._hashedName == 0 && $._hashedVersion == 0, "EIP712: Uninitialized");
                      return (
                          hex"0f", // 01111
                          _EIP712Name(),
                          _EIP712Version(),
                          block.chainid,
                          address(this),
                          bytes32(0),
                          new uint256[](0)
                      );
                  }
                  /**
                   * @dev The name parameter for the EIP712 domain.
                   *
                   * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
                   * are a concern.
                   */
                  function _EIP712Name() internal view virtual returns (string memory) {
                      EIP712Storage storage $ = _getEIP712Storage();
                      return $._name;
                  }
                  /**
                   * @dev The version parameter for the EIP712 domain.
                   *
                   * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
                   * are a concern.
                   */
                  function _EIP712Version() internal view virtual returns (string memory) {
                      EIP712Storage storage $ = _getEIP712Storage();
                      return $._version;
                  }
                  /**
                   * @dev The hash of the name parameter for the EIP712 domain.
                   *
                   * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead.
                   */
                  function _EIP712NameHash() internal view returns (bytes32) {
                      EIP712Storage storage $ = _getEIP712Storage();
                      string memory name = _EIP712Name();
                      if (bytes(name).length > 0) {
                          return keccak256(bytes(name));
                      } else {
                          // If the name is empty, the contract may have been upgraded without initializing the new storage.
                          // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design.
                          bytes32 hashedName = $._hashedName;
                          if (hashedName != 0) {
                              return hashedName;
                          } else {
                              return keccak256("");
                          }
                      }
                  }
                  /**
                   * @dev The hash of the version parameter for the EIP712 domain.
                   *
                   * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead.
                   */
                  function _EIP712VersionHash() internal view returns (bytes32) {
                      EIP712Storage storage $ = _getEIP712Storage();
                      string memory version = _EIP712Version();
                      if (bytes(version).length > 0) {
                          return keccak256(bytes(version));
                      } else {
                          // If the version is empty, the contract may have been upgraded without initializing the new storage.
                          // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design.
                          bytes32 hashedVersion = $._hashedVersion;
                          if (hashedVersion != 0) {
                              return hashedVersion;
                          } else {
                              return keccak256("");
                          }
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)
              pragma solidity ^0.8.20;
              import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
              import {Initializable} from "../../proxy/utils/Initializable.sol";
              /**
               * @dev Implementation of the {IERC165} interface.
               *
               * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
               * for the additional interface id that will be supported. For example:
               *
               * ```solidity
               * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
               *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
               * }
               * ```
               */
              abstract contract ERC165Upgradeable is Initializable, IERC165 {
                  function __ERC165_init() internal onlyInitializing {
                  }
                  function __ERC165_init_unchained() internal onlyInitializing {
                  }
                  /**
                   * @dev See {IERC165-supportsInterface}.
                   */
                  function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
                      return interfaceId == type(IERC165).interfaceId;
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol)
              pragma solidity ^0.8.20;
              import {Initializable} from "../proxy/utils/Initializable.sol";
              /**
               * @dev Provides tracking nonces for addresses. Nonces will only increment.
               */
              abstract contract NoncesUpgradeable is Initializable {
                  /**
                   * @dev The nonce used for an `account` is not the expected current nonce.
                   */
                  error InvalidAccountNonce(address account, uint256 currentNonce);
                  /// @custom:storage-location erc7201:openzeppelin.storage.Nonces
                  struct NoncesStorage {
                      mapping(address account => uint256) _nonces;
                  }
                  // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Nonces")) - 1)) & ~bytes32(uint256(0xff))
                  bytes32 private constant NoncesStorageLocation = 0x5ab42ced628888259c08ac98db1eb0cf702fc1501344311d8b100cd1bfe4bb00;
                  function _getNoncesStorage() private pure returns (NoncesStorage storage $) {
                      assembly {
                          $.slot := NoncesStorageLocation
                      }
                  }
                  function __Nonces_init() internal onlyInitializing {
                  }
                  function __Nonces_init_unchained() internal onlyInitializing {
                  }
                  /**
                   * @dev Returns the next unused nonce for an address.
                   */
                  function nonces(address owner) public view virtual returns (uint256) {
                      NoncesStorage storage $ = _getNoncesStorage();
                      return $._nonces[owner];
                  }
                  /**
                   * @dev Consumes a nonce.
                   *
                   * Returns the current value and increments nonce.
                   */
                  function _useNonce(address owner) internal virtual returns (uint256) {
                      NoncesStorage storage $ = _getNoncesStorage();
                      // For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be
                      // decremented or reset. This guarantees that the nonce never overflows.
                      unchecked {
                          // It is important to do x++ and not ++x here.
                          return $._nonces[owner]++;
                      }
                  }
                  /**
                   * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`.
                   */
                  function _useCheckedNonce(address owner, uint256 nonce) internal virtual {
                      uint256 current = _useNonce(owner);
                      if (nonce != current) {
                          revert InvalidAccountNonce(owner, current);
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.1.0) (access/IAccessControl.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev External interface of AccessControl declared to support ERC-165 detection.
               */
              interface IAccessControl {
                  /**
                   * @dev The `account` is missing a role.
                   */
                  error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
                  /**
                   * @dev The caller of a function is not the expected one.
                   *
                   * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
                   */
                  error AccessControlBadConfirmation();
                  /**
                   * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
                   *
                   * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
                   * {RoleAdminChanged} not being emitted signaling this.
                   */
                  event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
                  /**
                   * @dev Emitted when `account` is granted `role`.
                   *
                   * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
                   * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
                   */
                  event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
                  /**
                   * @dev Emitted when `account` is revoked `role`.
                   *
                   * `sender` is the account that originated the contract call:
                   *   - if using `revokeRole`, it is the admin role bearer
                   *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
                   */
                  event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
                  /**
                   * @dev Returns `true` if `account` has been granted `role`.
                   */
                  function hasRole(bytes32 role, address account) external view returns (bool);
                  /**
                   * @dev Returns the admin role that controls `role`. See {grantRole} and
                   * {revokeRole}.
                   *
                   * To change a role's admin, use {AccessControl-_setRoleAdmin}.
                   */
                  function getRoleAdmin(bytes32 role) external view returns (bytes32);
                  /**
                   * @dev Grants `role` to `account`.
                   *
                   * If `account` had not been already granted `role`, emits a {RoleGranted}
                   * event.
                   *
                   * Requirements:
                   *
                   * - the caller must have ``role``'s admin role.
                   */
                  function grantRole(bytes32 role, address account) external;
                  /**
                   * @dev Revokes `role` from `account`.
                   *
                   * If `account` had been granted `role`, emits a {RoleRevoked} event.
                   *
                   * Requirements:
                   *
                   * - the caller must have ``role``'s admin role.
                   */
                  function revokeRole(bytes32 role, address account) external;
                  /**
                   * @dev Revokes `role` from the calling account.
                   *
                   * Roles are often managed via {grantRole} and {revokeRole}: this function's
                   * purpose is to provide a mechanism for accounts to lose their privileges
                   * if they are compromised (such as when a trusted device is misplaced).
                   *
                   * If the calling account had been granted `role`, emits a {RoleRevoked}
                   * event.
                   *
                   * Requirements:
                   *
                   * - the caller must be `callerConfirmation`.
                   */
                  function renounceRole(bytes32 role, address callerConfirmation) external;
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC1822.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev ERC-1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
               * proxy whose upgrades are fully controlled by the current implementation.
               */
              interface IERC1822Proxiable {
                  /**
                   * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
                   * address.
                   *
                   * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
                   * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
                   * function revert if invoked through a proxy.
                   */
                  function proxiableUUID() external view returns (bytes32);
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC6093.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev Standard ERC-20 Errors
               * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.
               */
              interface IERC20Errors {
                  /**
                   * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
                   * @param sender Address whose tokens are being transferred.
                   * @param balance Current balance for the interacting account.
                   * @param needed Minimum amount required to perform a transfer.
                   */
                  error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
                  /**
                   * @dev Indicates a failure with the token `sender`. Used in transfers.
                   * @param sender Address whose tokens are being transferred.
                   */
                  error ERC20InvalidSender(address sender);
                  /**
                   * @dev Indicates a failure with the token `receiver`. Used in transfers.
                   * @param receiver Address to which tokens are being transferred.
                   */
                  error ERC20InvalidReceiver(address receiver);
                  /**
                   * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
                   * @param spender Address that may be allowed to operate on tokens without being their owner.
                   * @param allowance Amount of tokens a `spender` is allowed to operate with.
                   * @param needed Minimum amount required to perform a transfer.
                   */
                  error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
                  /**
                   * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
                   * @param approver Address initiating an approval operation.
                   */
                  error ERC20InvalidApprover(address approver);
                  /**
                   * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
                   * @param spender Address that may be allowed to operate on tokens without being their owner.
                   */
                  error ERC20InvalidSpender(address spender);
              }
              /**
               * @dev Standard ERC-721 Errors
               * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.
               */
              interface IERC721Errors {
                  /**
                   * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.
                   * Used in balance queries.
                   * @param owner Address of the current owner of a token.
                   */
                  error ERC721InvalidOwner(address owner);
                  /**
                   * @dev Indicates a `tokenId` whose `owner` is the zero address.
                   * @param tokenId Identifier number of a token.
                   */
                  error ERC721NonexistentToken(uint256 tokenId);
                  /**
                   * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
                   * @param sender Address whose tokens are being transferred.
                   * @param tokenId Identifier number of a token.
                   * @param owner Address of the current owner of a token.
                   */
                  error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
                  /**
                   * @dev Indicates a failure with the token `sender`. Used in transfers.
                   * @param sender Address whose tokens are being transferred.
                   */
                  error ERC721InvalidSender(address sender);
                  /**
                   * @dev Indicates a failure with the token `receiver`. Used in transfers.
                   * @param receiver Address to which tokens are being transferred.
                   */
                  error ERC721InvalidReceiver(address receiver);
                  /**
                   * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
                   * @param operator Address that may be allowed to operate on tokens without being their owner.
                   * @param tokenId Identifier number of a token.
                   */
                  error ERC721InsufficientApproval(address operator, uint256 tokenId);
                  /**
                   * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
                   * @param approver Address initiating an approval operation.
                   */
                  error ERC721InvalidApprover(address approver);
                  /**
                   * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
                   * @param operator Address that may be allowed to operate on tokens without being their owner.
                   */
                  error ERC721InvalidOperator(address operator);
              }
              /**
               * @dev Standard ERC-1155 Errors
               * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.
               */
              interface IERC1155Errors {
                  /**
                   * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
                   * @param sender Address whose tokens are being transferred.
                   * @param balance Current balance for the interacting account.
                   * @param needed Minimum amount required to perform a transfer.
                   * @param tokenId Identifier number of a token.
                   */
                  error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
                  /**
                   * @dev Indicates a failure with the token `sender`. Used in transfers.
                   * @param sender Address whose tokens are being transferred.
                   */
                  error ERC1155InvalidSender(address sender);
                  /**
                   * @dev Indicates a failure with the token `receiver`. Used in transfers.
                   * @param receiver Address to which tokens are being transferred.
                   */
                  error ERC1155InvalidReceiver(address receiver);
                  /**
                   * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
                   * @param operator Address that may be allowed to operate on tokens without being their owner.
                   * @param owner Address of the current owner of a token.
                   */
                  error ERC1155MissingApprovalForAll(address operator, address owner);
                  /**
                   * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
                   * @param approver Address initiating an approval operation.
                   */
                  error ERC1155InvalidApprover(address approver);
                  /**
                   * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
                   * @param operator Address that may be allowed to operate on tokens without being their owner.
                   */
                  error ERC1155InvalidOperator(address operator);
                  /**
                   * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
                   * Used in batch transfers.
                   * @param idsLength Length of the array of token identifiers
                   * @param valuesLength Length of the array of token amounts
                   */
                  error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
               */
              interface IERC1967 {
                  /**
                   * @dev Emitted when the implementation is upgraded.
                   */
                  event Upgraded(address indexed implementation);
                  /**
                   * @dev Emitted when the admin account has changed.
                   */
                  event AdminChanged(address previousAdmin, address newAdmin);
                  /**
                   * @dev Emitted when the beacon is changed.
                   */
                  event BeaconUpgraded(address indexed beacon);
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)
              pragma solidity ^0.8.20;
              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 v5.0.0) (proxy/beacon/IBeacon.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev This is the interface that {BeaconProxy} expects of its beacon.
               */
              interface IBeacon {
                  /**
                   * @dev Must return an address that can be used as a delegate call target.
                   *
                   * {UpgradeableBeacon} will check that this address is a contract.
                   */
                  function implementation() external view returns (address);
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.2.0) (proxy/ERC1967/ERC1967Utils.sol)
              pragma solidity ^0.8.22;
              import {IBeacon} from "../beacon/IBeacon.sol";
              import {IERC1967} from "../../interfaces/IERC1967.sol";
              import {Address} from "../../utils/Address.sol";
              import {StorageSlot} from "../../utils/StorageSlot.sol";
              /**
               * @dev This library provides getters and event emitting update functions for
               * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots.
               */
              library ERC1967Utils {
                  /**
                   * @dev Storage slot with the address of the current implementation.
                   * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
                   */
                  // solhint-disable-next-line private-vars-leading-underscore
                  bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                  /**
                   * @dev The `implementation` of the proxy is invalid.
                   */
                  error ERC1967InvalidImplementation(address implementation);
                  /**
                   * @dev The `admin` of the proxy is invalid.
                   */
                  error ERC1967InvalidAdmin(address admin);
                  /**
                   * @dev The `beacon` of the proxy is invalid.
                   */
                  error ERC1967InvalidBeacon(address beacon);
                  /**
                   * @dev An upgrade function sees `msg.value > 0` that may be lost.
                   */
                  error ERC1967NonPayable();
                  /**
                   * @dev Returns the current implementation address.
                   */
                  function getImplementation() internal view returns (address) {
                      return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
                  }
                  /**
                   * @dev Stores a new address in the ERC-1967 implementation slot.
                   */
                  function _setImplementation(address newImplementation) private {
                      if (newImplementation.code.length == 0) {
                          revert ERC1967InvalidImplementation(newImplementation);
                      }
                      StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
                  }
                  /**
                   * @dev Performs implementation upgrade with additional setup call if data is nonempty.
                   * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
                   * to avoid stuck value in the contract.
                   *
                   * Emits an {IERC1967-Upgraded} event.
                   */
                  function upgradeToAndCall(address newImplementation, bytes memory data) internal {
                      _setImplementation(newImplementation);
                      emit IERC1967.Upgraded(newImplementation);
                      if (data.length > 0) {
                          Address.functionDelegateCall(newImplementation, data);
                      } else {
                          _checkNonPayable();
                      }
                  }
                  /**
                   * @dev Storage slot with the admin of the contract.
                   * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
                   */
                  // solhint-disable-next-line private-vars-leading-underscore
                  bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                  /**
                   * @dev Returns the current admin.
                   *
                   * TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using
                   * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                   * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                   */
                  function getAdmin() internal view returns (address) {
                      return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
                  }
                  /**
                   * @dev Stores a new address in the ERC-1967 admin slot.
                   */
                  function _setAdmin(address newAdmin) private {
                      if (newAdmin == address(0)) {
                          revert ERC1967InvalidAdmin(address(0));
                      }
                      StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
                  }
                  /**
                   * @dev Changes the admin of the proxy.
                   *
                   * Emits an {IERC1967-AdminChanged} event.
                   */
                  function changeAdmin(address newAdmin) internal {
                      emit IERC1967.AdminChanged(getAdmin(), newAdmin);
                      _setAdmin(newAdmin);
                  }
                  /**
                   * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                   * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
                   */
                  // solhint-disable-next-line private-vars-leading-underscore
                  bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                  /**
                   * @dev Returns the current beacon.
                   */
                  function getBeacon() internal view returns (address) {
                      return StorageSlot.getAddressSlot(BEACON_SLOT).value;
                  }
                  /**
                   * @dev Stores a new beacon in the ERC-1967 beacon slot.
                   */
                  function _setBeacon(address newBeacon) private {
                      if (newBeacon.code.length == 0) {
                          revert ERC1967InvalidBeacon(newBeacon);
                      }
                      StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
                      address beaconImplementation = IBeacon(newBeacon).implementation();
                      if (beaconImplementation.code.length == 0) {
                          revert ERC1967InvalidImplementation(beaconImplementation);
                      }
                  }
                  /**
                   * @dev Change the beacon and trigger a setup call if data is nonempty.
                   * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
                   * to avoid stuck value in the contract.
                   *
                   * Emits an {IERC1967-BeaconUpgraded} event.
                   *
                   * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
                   * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
                   * efficiency.
                   */
                  function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
                      _setBeacon(newBeacon);
                      emit IERC1967.BeaconUpgraded(newBeacon);
                      if (data.length > 0) {
                          Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                      } else {
                          _checkNonPayable();
                      }
                  }
                  /**
                   * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
                   * if an upgrade doesn't perform an initialization call.
                   */
                  function _checkNonPayable() private {
                      if (msg.value > 0) {
                          revert ERC1967NonPayable();
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)
              pragma solidity ^0.8.20;
              import {IERC20} from "../IERC20.sol";
              /**
               * @dev Interface for the optional metadata functions from the ERC-20 standard.
               */
              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 v5.1.0) (token/ERC20/extensions/IERC20Permit.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in
               * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612].
               *
               * Adds the {permit} method, which can be used to change an account's ERC-20 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 v5.1.0) (token/ERC20/IERC20.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev Interface of the ERC-20 standard as defined in the ERC.
               */
              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 value of tokens in existence.
                   */
                  function totalSupply() external view returns (uint256);
                  /**
                   * @dev Returns the value of tokens owned by `account`.
                   */
                  function balanceOf(address account) external view returns (uint256);
                  /**
                   * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
                  /**
                   * @dev Moves a `value` amount of tokens from `from` to `to` using the
                   * allowance mechanism. `value` 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 value) external returns (bool);
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.2.0) (utils/Address.sol)
              pragma solidity ^0.8.20;
              import {Errors} from "./Errors.sol";
              /**
               * @dev Collection of functions related to the address type
               */
              library Address {
                  /**
                   * @dev There's no code at `target` (it is not a contract).
                   */
                  error AddressEmptyCode(address target);
                  /**
                   * @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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                   */
                  function sendValue(address payable recipient, uint256 amount) internal {
                      if (address(this).balance < amount) {
                          revert Errors.InsufficientBalance(address(this).balance, amount);
                      }
                      (bool success, bytes memory returndata) = recipient.call{value: amount}("");
                      if (!success) {
                          _revert(returndata);
                      }
                  }
                  /**
                   * @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 or custom error, it is bubbled
                   * up by this function (like regular Solidity function calls). However, if
                   * the call reverted with no returned reason, this function reverts with a
                   * {Errors.FailedCall} error.
                   *
                   * 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.
                   */
                  function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                      return functionCallWithValue(target, data, 0);
                  }
                  /**
                   * @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`.
                   */
                  function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                      if (address(this).balance < value) {
                          revert Errors.InsufficientBalance(address(this).balance, value);
                      }
                      (bool success, bytes memory returndata) = target.call{value: value}(data);
                      return verifyCallResultFromTarget(target, success, returndata);
                  }
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a static call.
                   */
                  function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                      (bool success, bytes memory returndata) = target.staticcall(data);
                      return verifyCallResultFromTarget(target, success, returndata);
                  }
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a delegate call.
                   */
                  function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                      (bool success, bytes memory returndata) = target.delegatecall(data);
                      return verifyCallResultFromTarget(target, success, returndata);
                  }
                  /**
                   * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
                   * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
                   * of an unsuccessful call.
                   */
                  function verifyCallResultFromTarget(
                      address target,
                      bool success,
                      bytes memory returndata
                  ) internal view returns (bytes memory) {
                      if (!success) {
                          _revert(returndata);
                      } else {
                          // only check if target is a contract if the call was successful and the return data is empty
                          // otherwise we already know that it was a contract
                          if (returndata.length == 0 && target.code.length == 0) {
                              revert AddressEmptyCode(target);
                          }
                          return returndata;
                      }
                  }
                  /**
                   * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
                   * revert reason or with a default {Errors.FailedCall} error.
                   */
                  function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
                      if (!success) {
                          _revert(returndata);
                      } else {
                          return returndata;
                      }
                  }
                  /**
                   * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
                   */
                  function _revert(bytes memory returndata) 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
                          assembly ("memory-safe") {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert Errors.FailedCall();
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol)
              pragma solidity ^0.8.20;
              /**
               * @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
                  }
                  /**
                   * @dev The signature derives the `address(0)`.
                   */
                  error ECDSAInvalidSignature();
                  /**
                   * @dev The signature has an invalid length.
                   */
                  error ECDSAInvalidSignatureLength(uint256 length);
                  /**
                   * @dev The signature has an S value that is in the upper half order.
                   */
                  error ECDSAInvalidSignatureS(bytes32 s);
                  /**
                   * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
                   * return address(0) without also returning an error description. Errors are documented using an enum (error type)
                   * and a bytes32 providing additional information about the error.
                   *
                   * If no error is returned, then the address can be used for verification purposes.
                   *
                   * The `ecrecover` EVM precompile 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 {MessageHashUtils-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]
                   */
                  function tryRecover(
                      bytes32 hash,
                      bytes memory signature
                  ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
                      if (signature.length == 65) {
                          bytes32 r;
                          bytes32 s;
                          uint8 v;
                          // ecrecover takes the signature parameters, and the only way to get them
                          // currently is to use assembly.
                          assembly ("memory-safe") {
                              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, bytes32(signature.length));
                      }
                  }
                  /**
                   * @dev Returns the address that signed a hashed message (`hash`) with
                   * `signature`. This address can then be used for verification purposes.
                   *
                   * The `ecrecover` EVM precompile 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 {MessageHashUtils-toEthSignedMessageHash} on it.
                   */
                  function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
                      (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
                      _throwError(error, errorArg);
                      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[ERC-2098 short signatures]
                   */
                  function tryRecover(
                      bytes32 hash,
                      bytes32 r,
                      bytes32 vs
                  ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
                      unchecked {
                          bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
                          // We do not check for an overflow here since the shift operation results in 0 or 1.
                          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.
                   */
                  function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
                      (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
                      _throwError(error, errorArg);
                      return recovered;
                  }
                  /**
                   * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
                   * `r` and `s` signature fields separately.
                   */
                  function tryRecover(
                      bytes32 hash,
                      uint8 v,
                      bytes32 r,
                      bytes32 s
                  ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
                      // 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, s);
                      }
                      // 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, bytes32(0));
                      }
                      return (signer, RecoverError.NoError, bytes32(0));
                  }
                  /**
                   * @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, bytes32 errorArg) = tryRecover(hash, v, r, s);
                      _throwError(error, errorArg);
                      return recovered;
                  }
                  /**
                   * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
                   */
                  function _throwError(RecoverError error, bytes32 errorArg) private pure {
                      if (error == RecoverError.NoError) {
                          return; // no error: do nothing
                      } else if (error == RecoverError.InvalidSignature) {
                          revert ECDSAInvalidSignature();
                      } else if (error == RecoverError.InvalidSignatureLength) {
                          revert ECDSAInvalidSignatureLength(uint256(errorArg));
                      } else if (error == RecoverError.InvalidSignatureS) {
                          revert ECDSAInvalidSignatureS(errorArg);
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/MessageHashUtils.sol)
              pragma solidity ^0.8.20;
              import {Strings} from "../Strings.sol";
              /**
               * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
               *
               * The library provides methods for generating a hash of a message that conforms to the
               * https://eips.ethereum.org/EIPS/eip-191[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
               * specifications.
               */
              library MessageHashUtils {
                  /**
                   * @dev Returns the keccak256 digest of an ERC-191 signed data with version
                   * `0x45` (`personal_sign` messages).
                   *
                   * The digest is calculated by prefixing a bytes32 `messageHash` with
                   * `"\\x19Ethereum Signed Message:\
              32"` and hashing the result. It corresponds with the
                   * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
                   *
                   * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
                   * keccak256, although any bytes32 value can be safely used because the final digest will
                   * be re-hashed.
                   *
                   * See {ECDSA-recover}.
                   */
                  function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
                      assembly ("memory-safe") {
                          mstore(0x00, "\\x19Ethereum Signed Message:\
              32") // 32 is the bytes-length of messageHash
                          mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
                          digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
                      }
                  }
                  /**
                   * @dev Returns the keccak256 digest of an ERC-191 signed data with version
                   * `0x45` (`personal_sign` messages).
                   *
                   * The digest is calculated by prefixing an arbitrary `message` with
                   * `"\\x19Ethereum Signed Message:\
              " + len(message)` and hashing the result. It corresponds with the
                   * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
                   *
                   * See {ECDSA-recover}.
                   */
                  function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
                      return
                          keccak256(bytes.concat("\\x19Ethereum Signed Message:\
              ", bytes(Strings.toString(message.length)), message));
                  }
                  /**
                   * @dev Returns the keccak256 digest of an ERC-191 signed data with version
                   * `0x00` (data with intended validator).
                   *
                   * The digest is calculated by prefixing an arbitrary `data` with `"\\x19\\x00"` and the intended
                   * `validator` address. Then hashing the result.
                   *
                   * See {ECDSA-recover}.
                   */
                  function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
                      return keccak256(abi.encodePacked(hex"19_00", validator, data));
                  }
                  /**
                   * @dev Returns the keccak256 digest of an EIP-712 typed data (ERC-191 version `0x01`).
                   *
                   * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
                   * `\\x19\\x01` and hashing the result. It corresponds to the hash signed by the
                   * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
                   *
                   * See {ECDSA-recover}.
                   */
                  function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
                      assembly ("memory-safe") {
                          let ptr := mload(0x40)
                          mstore(ptr, hex"19_01")
                          mstore(add(ptr, 0x02), domainSeparator)
                          mstore(add(ptr, 0x22), structHash)
                          digest := keccak256(ptr, 0x42)
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev Collection of common custom errors used in multiple contracts
               *
               * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
               * It is recommended to avoid relying on the error API for critical functionality.
               *
               * _Available since v5.1._
               */
              library Errors {
                  /**
                   * @dev The ETH balance of the account is not enough to perform the operation.
                   */
                  error InsufficientBalance(uint256 balance, uint256 needed);
                  /**
                   * @dev A call to an address target failed. The target may have reverted.
                   */
                  error FailedCall();
                  /**
                   * @dev The deployment failed.
                   */
                  error FailedDeployment();
                  /**
                   * @dev A necessary precompile is missing.
                   */
                  error MissingPrecompile(address);
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev Interface of the ERC-165 standard, as defined in the
               * https://eips.ethereum.org/EIPS/eip-165[ERC].
               *
               * Implementers can declare support of contract interfaces, which can then be
               * queried by others ({ERC165Checker}).
               *
               * For an implementation, see {ERC165}.
               */
              interface IERC165 {
                  /**
                   * @dev Returns true if this contract implements the interface defined by
                   * `interfaceId`. See the corresponding
                   * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
                   * to learn more about how these ids are created.
                   *
                   * This function call must use less than 30 000 gas.
                   */
                  function supportsInterface(bytes4 interfaceId) external view returns (bool);
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.1.0) (utils/math/Math.sol)
              pragma solidity ^0.8.20;
              import {Panic} from "../Panic.sol";
              import {SafeCast} from "./SafeCast.sol";
              /**
               * @dev Standard math utilities missing in the Solidity language.
               */
              library Math {
                  enum Rounding {
                      Floor, // Toward negative infinity
                      Ceil, // Toward positive infinity
                      Trunc, // Toward zero
                      Expand // Away from zero
                  }
                  /**
                   * @dev Returns the addition of two unsigned integers, with an success flag (no overflow).
                   */
                  function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
                      unchecked {
                          uint256 c = a + b;
                          if (c < a) return (false, 0);
                          return (true, c);
                      }
                  }
                  /**
                   * @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow).
                   */
                  function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
                      unchecked {
                          if (b > a) return (false, 0);
                          return (true, a - b);
                      }
                  }
                  /**
                   * @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow).
                   */
                  function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
                      unchecked {
                          // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                          // benefit is lost if 'b' is also tested.
                          // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                          if (a == 0) return (true, 0);
                          uint256 c = a * b;
                          if (c / a != b) return (false, 0);
                          return (true, c);
                      }
                  }
                  /**
                   * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
                   */
                  function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
                      unchecked {
                          if (b == 0) return (false, 0);
                          return (true, a / b);
                      }
                  }
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
                   */
                  function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
                      unchecked {
                          if (b == 0) return (false, 0);
                          return (true, a % b);
                      }
                  }
                  /**
                   * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
                   *
                   * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
                   * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
                   * one branch when needed, making this function more expensive.
                   */
                  function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
                      unchecked {
                          // branchless ternary works because:
                          // b ^ (a ^ b) == a
                          // b ^ 0 == b
                          return b ^ ((a ^ b) * SafeCast.toUint(condition));
                      }
                  }
                  /**
                   * @dev Returns the largest of two numbers.
                   */
                  function max(uint256 a, uint256 b) internal pure returns (uint256) {
                      return ternary(a > b, a, b);
                  }
                  /**
                   * @dev Returns the smallest of two numbers.
                   */
                  function min(uint256 a, uint256 b) internal pure returns (uint256) {
                      return ternary(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 towards infinity instead
                   * of rounding towards zero.
                   */
                  function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
                      if (b == 0) {
                          // Guarantee the same behavior as in a regular Solidity division.
                          Panic.panic(Panic.DIVISION_BY_ZERO);
                      }
                      // The following calculation ensures accurate ceiling division without overflow.
                      // Since a is non-zero, (a - 1) / b will not overflow.
                      // The largest possible result occurs when (a - 1) / b is type(uint256).max,
                      // but the largest value we can obtain is type(uint256).max - 1, which happens
                      // when a = type(uint256).max and b = 1.
                      unchecked {
                          return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
                      }
                  }
                  /**
                   * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
                   * denominator == 0.
                   *
                   * 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²⁵⁶ and mod 2²⁵⁶ - 1, then use
                          // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
                          // variables such that product = prod1 * 2²⁵⁶ + prod0.
                          uint256 prod0 = x * y; // Least significant 256 bits of the product
                          uint256 prod1; // Most significant 256 bits of the product
                          assembly {
                              let mm := mulmod(x, y, not(0))
                              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²⁵⁶. Also prevents denominator == 0.
                          if (denominator <= prod1) {
                              Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_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.
                          uint256 twos = denominator & (0 - denominator);
                          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²⁵⁶ / 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²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
                          // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
                          // four bits. That is, denominator * inv ≡ 1 mod 2⁴.
                          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⁸
                          inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
                          inverse *= 2 - denominator * inverse; // inverse mod 2³²
                          inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
                          inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
                          inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶
                          // 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²⁵⁶. Since the preconditions guarantee that the outcome is
                          // less than 2²⁵⁶, 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;
                      }
                  }
                  /**
                   * @dev 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) {
                      return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
                  }
                  /**
                   * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
                   *
                   * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
                   * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
                   *
                   * If the input value is not inversible, 0 is returned.
                   *
                   * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
                   * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
                   */
                  function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
                      unchecked {
                          if (n == 0) return 0;
                          // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
                          // Used to compute integers x and y such that: ax + ny = gcd(a, n).
                          // When the gcd is 1, then the inverse of a modulo n exists and it's x.
                          // ax + ny = 1
                          // ax = 1 + (-y)n
                          // ax ≡ 1 (mod n) # x is the inverse of a modulo n
                          // If the remainder is 0 the gcd is n right away.
                          uint256 remainder = a % n;
                          uint256 gcd = n;
                          // Therefore the initial coefficients are:
                          // ax + ny = gcd(a, n) = n
                          // 0a + 1n = n
                          int256 x = 0;
                          int256 y = 1;
                          while (remainder != 0) {
                              uint256 quotient = gcd / remainder;
                              (gcd, remainder) = (
                                  // The old remainder is the next gcd to try.
                                  remainder,
                                  // Compute the next remainder.
                                  // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
                                  // where gcd is at most n (capped to type(uint256).max)
                                  gcd - remainder * quotient
                              );
                              (x, y) = (
                                  // Increment the coefficient of a.
                                  y,
                                  // Decrement the coefficient of n.
                                  // Can overflow, but the result is casted to uint256 so that the
                                  // next value of y is "wrapped around" to a value between 0 and n - 1.
                                  x - y * int256(quotient)
                              );
                          }
                          if (gcd != 1) return 0; // No inverse exists.
                          return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
                      }
                  }
                  /**
                   * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
                   *
                   * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
                   * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
                   * `a**(p-2)` is the modular multiplicative inverse of a in Fp.
                   *
                   * NOTE: this function does NOT check that `p` is a prime greater than `2`.
                   */
                  function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
                      unchecked {
                          return Math.modExp(a, p - 2, p);
                      }
                  }
                  /**
                   * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
                   *
                   * Requirements:
                   * - modulus can't be zero
                   * - underlying staticcall to precompile must succeed
                   *
                   * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
                   * sure the chain you're using it on supports the precompiled contract for modular exponentiation
                   * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
                   * the underlying function will succeed given the lack of a revert, but the result may be incorrectly
                   * interpreted as 0.
                   */
                  function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
                      (bool success, uint256 result) = tryModExp(b, e, m);
                      if (!success) {
                          Panic.panic(Panic.DIVISION_BY_ZERO);
                      }
                      return result;
                  }
                  /**
                   * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
                   * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
                   * to operate modulo 0 or if the underlying precompile reverted.
                   *
                   * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
                   * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
                   * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
                   * of a revert, but the result may be incorrectly interpreted as 0.
                   */
                  function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
                      if (m == 0) return (false, 0);
                      assembly ("memory-safe") {
                          let ptr := mload(0x40)
                          // | Offset    | Content    | Content (Hex)                                                      |
                          // |-----------|------------|--------------------------------------------------------------------|
                          // | 0x00:0x1f | size of b  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
                          // | 0x20:0x3f | size of e  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
                          // | 0x40:0x5f | size of m  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
                          // | 0x60:0x7f | value of b | 0x<.............................................................b> |
                          // | 0x80:0x9f | value of e | 0x<.............................................................e> |
                          // | 0xa0:0xbf | value of m | 0x<.............................................................m> |
                          mstore(ptr, 0x20)
                          mstore(add(ptr, 0x20), 0x20)
                          mstore(add(ptr, 0x40), 0x20)
                          mstore(add(ptr, 0x60), b)
                          mstore(add(ptr, 0x80), e)
                          mstore(add(ptr, 0xa0), m)
                          // Given the result < m, it's guaranteed to fit in 32 bytes,
                          // so we can use the memory scratch space located at offset 0.
                          success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
                          result := mload(0x00)
                      }
                  }
                  /**
                   * @dev Variant of {modExp} that supports inputs of arbitrary length.
                   */
                  function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
                      (bool success, bytes memory result) = tryModExp(b, e, m);
                      if (!success) {
                          Panic.panic(Panic.DIVISION_BY_ZERO);
                      }
                      return result;
                  }
                  /**
                   * @dev Variant of {tryModExp} that supports inputs of arbitrary length.
                   */
                  function tryModExp(
                      bytes memory b,
                      bytes memory e,
                      bytes memory m
                  ) internal view returns (bool success, bytes memory result) {
                      if (_zeroBytes(m)) return (false, new bytes(0));
                      uint256 mLen = m.length;
                      // Encode call args in result and move the free memory pointer
                      result = abi.encodePacked(b.length, e.length, mLen, b, e, m);
                      assembly ("memory-safe") {
                          let dataPtr := add(result, 0x20)
                          // Write result on top of args to avoid allocating extra memory.
                          success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
                          // Overwrite the length.
                          // result.length > returndatasize() is guaranteed because returndatasize() == m.length
                          mstore(result, mLen)
                          // Set the memory pointer after the returned data.
                          mstore(0x40, add(dataPtr, mLen))
                      }
                  }
                  /**
                   * @dev Returns whether the provided byte array is zero.
                   */
                  function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
                      for (uint256 i = 0; i < byteArray.length; ++i) {
                          if (byteArray[i] != 0) {
                              return false;
                          }
                      }
                      return true;
                  }
                  /**
                   * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
                   * towards zero.
                   *
                   * This method is based on Newton's method for computing square roots; the algorithm is restricted to only
                   * using integer operations.
                   */
                  function sqrt(uint256 a) internal pure returns (uint256) {
                      unchecked {
                          // Take care of easy edge cases when a == 0 or a == 1
                          if (a <= 1) {
                              return a;
                          }
                          // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
                          // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
                          // the current value as `ε_n = | x_n - sqrt(a) |`.
                          //
                          // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
                          // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
                          // bigger than any uint256.
                          //
                          // By noticing that
                          // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
                          // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
                          // to the msb function.
                          uint256 aa = a;
                          uint256 xn = 1;
                          if (aa >= (1 << 128)) {
                              aa >>= 128;
                              xn <<= 64;
                          }
                          if (aa >= (1 << 64)) {
                              aa >>= 64;
                              xn <<= 32;
                          }
                          if (aa >= (1 << 32)) {
                              aa >>= 32;
                              xn <<= 16;
                          }
                          if (aa >= (1 << 16)) {
                              aa >>= 16;
                              xn <<= 8;
                          }
                          if (aa >= (1 << 8)) {
                              aa >>= 8;
                              xn <<= 4;
                          }
                          if (aa >= (1 << 4)) {
                              aa >>= 4;
                              xn <<= 2;
                          }
                          if (aa >= (1 << 2)) {
                              xn <<= 1;
                          }
                          // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
                          //
                          // We can refine our estimation by noticing that the middle of that interval minimizes the error.
                          // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
                          // This is going to be our x_0 (and ε_0)
                          xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)
                          // From here, Newton's method give us:
                          // x_{n+1} = (x_n + a / x_n) / 2
                          //
                          // One should note that:
                          // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
                          //              = ((x_n² + a) / (2 * x_n))² - a
                          //              = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
                          //              = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
                          //              = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
                          //              = (x_n² - a)² / (2 * x_n)²
                          //              = ((x_n² - a) / (2 * x_n))²
                          //              ≥ 0
                          // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
                          //
                          // This gives us the proof of quadratic convergence of the sequence:
                          // ε_{n+1} = | x_{n+1} - sqrt(a) |
                          //         = | (x_n + a / x_n) / 2 - sqrt(a) |
                          //         = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
                          //         = | (x_n - sqrt(a))² / (2 * x_n) |
                          //         = | ε_n² / (2 * x_n) |
                          //         = ε_n² / | (2 * x_n) |
                          //
                          // For the first iteration, we have a special case where x_0 is known:
                          // ε_1 = ε_0² / | (2 * x_0) |
                          //     ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
                          //     ≤ 2**(2*e-4) / (3 * 2**(e-1))
                          //     ≤ 2**(e-3) / 3
                          //     ≤ 2**(e-3-log2(3))
                          //     ≤ 2**(e-4.5)
                          //
                          // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
                          // ε_{n+1} = ε_n² / | (2 * x_n) |
                          //         ≤ (2**(e-k))² / (2 * 2**(e-1))
                          //         ≤ 2**(2*e-2*k) / 2**e
                          //         ≤ 2**(e-2*k)
                          xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5)  -- special case, see above
                          xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9)    -- general case with k = 4.5
                          xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18)   -- general case with k = 9
                          xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36)   -- general case with k = 18
                          xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72)   -- general case with k = 36
                          xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144)  -- general case with k = 72
                          // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
                          // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
                          // sqrt(a) or sqrt(a) + 1.
                          return xn - SafeCast.toUint(xn > a / xn);
                      }
                  }
                  /**
                   * @dev 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
                      }
                  }
                  /**
                   * @dev Return the log in base 2 of a positive value rounded towards zero.
                   * Returns 0 if given 0.
                   */
                  function log2(uint256 value) internal pure returns (uint256) {
                      uint256 result = 0;
                      uint256 exp;
                      unchecked {
                          exp = 128 * SafeCast.toUint(value > (1 << 128) - 1);
                          value >>= exp;
                          result += exp;
                          exp = 64 * SafeCast.toUint(value > (1 << 64) - 1);
                          value >>= exp;
                          result += exp;
                          exp = 32 * SafeCast.toUint(value > (1 << 32) - 1);
                          value >>= exp;
                          result += exp;
                          exp = 16 * SafeCast.toUint(value > (1 << 16) - 1);
                          value >>= exp;
                          result += exp;
                          exp = 8 * SafeCast.toUint(value > (1 << 8) - 1);
                          value >>= exp;
                          result += exp;
                          exp = 4 * SafeCast.toUint(value > (1 << 4) - 1);
                          value >>= exp;
                          result += exp;
                          exp = 2 * SafeCast.toUint(value > (1 << 2) - 1);
                          value >>= exp;
                          result += exp;
                          result += SafeCast.toUint(value > 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
                      }
                  }
                  /**
                   * @dev Return the log in base 10 of a positive value rounded towards zero.
                   * 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
                      }
                  }
                  /**
                   * @dev Return the log in base 256 of a positive value rounded towards zero.
                   * 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;
                      uint256 isGt;
                      unchecked {
                          isGt = SafeCast.toUint(value > (1 << 128) - 1);
                          value >>= isGt * 128;
                          result += isGt * 16;
                          isGt = SafeCast.toUint(value > (1 << 64) - 1);
                          value >>= isGt * 64;
                          result += isGt * 8;
                          isGt = SafeCast.toUint(value > (1 << 32) - 1);
                          value >>= isGt * 32;
                          result += isGt * 4;
                          isGt = SafeCast.toUint(value > (1 << 16) - 1);
                          value >>= isGt * 16;
                          result += isGt * 2;
                          result += SafeCast.toUint(value > (1 << 8) - 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
                      }
                  }
                  /**
                   * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
                   */
                  function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
                      return uint8(rounding) % 2 == 1;
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
              // This file was procedurally generated from scripts/generate/templates/SafeCast.js.
              pragma solidity ^0.8.20;
              /**
               * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
               * checks.
               *
               * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
               * easily result in undesired exploitation or bugs, since developers usually
               * assume that overflows raise errors. `SafeCast` restores this intuition by
               * reverting the transaction when such an operation overflows.
               *
               * Using this library instead of the unchecked operations eliminates an entire
               * class of bugs, so it's recommended to use it always.
               */
              library SafeCast {
                  /**
                   * @dev Value doesn't fit in an uint of `bits` size.
                   */
                  error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
                  /**
                   * @dev An int value doesn't fit in an uint of `bits` size.
                   */
                  error SafeCastOverflowedIntToUint(int256 value);
                  /**
                   * @dev Value doesn't fit in an int of `bits` size.
                   */
                  error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
                  /**
                   * @dev An uint value doesn't fit in an int of `bits` size.
                   */
                  error SafeCastOverflowedUintToInt(uint256 value);
                  /**
                   * @dev Returns the downcasted uint248 from uint256, reverting on
                   * overflow (when the input is greater than largest uint248).
                   *
                   * Counterpart to Solidity's `uint248` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 248 bits
                   */
                  function toUint248(uint256 value) internal pure returns (uint248) {
                      if (value > type(uint248).max) {
                          revert SafeCastOverflowedUintDowncast(248, value);
                      }
                      return uint248(value);
                  }
                  /**
                   * @dev Returns the downcasted uint240 from uint256, reverting on
                   * overflow (when the input is greater than largest uint240).
                   *
                   * Counterpart to Solidity's `uint240` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 240 bits
                   */
                  function toUint240(uint256 value) internal pure returns (uint240) {
                      if (value > type(uint240).max) {
                          revert SafeCastOverflowedUintDowncast(240, value);
                      }
                      return uint240(value);
                  }
                  /**
                   * @dev Returns the downcasted uint232 from uint256, reverting on
                   * overflow (when the input is greater than largest uint232).
                   *
                   * Counterpart to Solidity's `uint232` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 232 bits
                   */
                  function toUint232(uint256 value) internal pure returns (uint232) {
                      if (value > type(uint232).max) {
                          revert SafeCastOverflowedUintDowncast(232, value);
                      }
                      return uint232(value);
                  }
                  /**
                   * @dev Returns the downcasted uint224 from uint256, reverting on
                   * overflow (when the input is greater than largest uint224).
                   *
                   * Counterpart to Solidity's `uint224` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 224 bits
                   */
                  function toUint224(uint256 value) internal pure returns (uint224) {
                      if (value > type(uint224).max) {
                          revert SafeCastOverflowedUintDowncast(224, value);
                      }
                      return uint224(value);
                  }
                  /**
                   * @dev Returns the downcasted uint216 from uint256, reverting on
                   * overflow (when the input is greater than largest uint216).
                   *
                   * Counterpart to Solidity's `uint216` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 216 bits
                   */
                  function toUint216(uint256 value) internal pure returns (uint216) {
                      if (value > type(uint216).max) {
                          revert SafeCastOverflowedUintDowncast(216, value);
                      }
                      return uint216(value);
                  }
                  /**
                   * @dev Returns the downcasted uint208 from uint256, reverting on
                   * overflow (when the input is greater than largest uint208).
                   *
                   * Counterpart to Solidity's `uint208` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 208 bits
                   */
                  function toUint208(uint256 value) internal pure returns (uint208) {
                      if (value > type(uint208).max) {
                          revert SafeCastOverflowedUintDowncast(208, value);
                      }
                      return uint208(value);
                  }
                  /**
                   * @dev Returns the downcasted uint200 from uint256, reverting on
                   * overflow (when the input is greater than largest uint200).
                   *
                   * Counterpart to Solidity's `uint200` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 200 bits
                   */
                  function toUint200(uint256 value) internal pure returns (uint200) {
                      if (value > type(uint200).max) {
                          revert SafeCastOverflowedUintDowncast(200, value);
                      }
                      return uint200(value);
                  }
                  /**
                   * @dev Returns the downcasted uint192 from uint256, reverting on
                   * overflow (when the input is greater than largest uint192).
                   *
                   * Counterpart to Solidity's `uint192` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 192 bits
                   */
                  function toUint192(uint256 value) internal pure returns (uint192) {
                      if (value > type(uint192).max) {
                          revert SafeCastOverflowedUintDowncast(192, value);
                      }
                      return uint192(value);
                  }
                  /**
                   * @dev Returns the downcasted uint184 from uint256, reverting on
                   * overflow (when the input is greater than largest uint184).
                   *
                   * Counterpart to Solidity's `uint184` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 184 bits
                   */
                  function toUint184(uint256 value) internal pure returns (uint184) {
                      if (value > type(uint184).max) {
                          revert SafeCastOverflowedUintDowncast(184, value);
                      }
                      return uint184(value);
                  }
                  /**
                   * @dev Returns the downcasted uint176 from uint256, reverting on
                   * overflow (when the input is greater than largest uint176).
                   *
                   * Counterpart to Solidity's `uint176` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 176 bits
                   */
                  function toUint176(uint256 value) internal pure returns (uint176) {
                      if (value > type(uint176).max) {
                          revert SafeCastOverflowedUintDowncast(176, value);
                      }
                      return uint176(value);
                  }
                  /**
                   * @dev Returns the downcasted uint168 from uint256, reverting on
                   * overflow (when the input is greater than largest uint168).
                   *
                   * Counterpart to Solidity's `uint168` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 168 bits
                   */
                  function toUint168(uint256 value) internal pure returns (uint168) {
                      if (value > type(uint168).max) {
                          revert SafeCastOverflowedUintDowncast(168, value);
                      }
                      return uint168(value);
                  }
                  /**
                   * @dev Returns the downcasted uint160 from uint256, reverting on
                   * overflow (when the input is greater than largest uint160).
                   *
                   * Counterpart to Solidity's `uint160` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 160 bits
                   */
                  function toUint160(uint256 value) internal pure returns (uint160) {
                      if (value > type(uint160).max) {
                          revert SafeCastOverflowedUintDowncast(160, value);
                      }
                      return uint160(value);
                  }
                  /**
                   * @dev Returns the downcasted uint152 from uint256, reverting on
                   * overflow (when the input is greater than largest uint152).
                   *
                   * Counterpart to Solidity's `uint152` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 152 bits
                   */
                  function toUint152(uint256 value) internal pure returns (uint152) {
                      if (value > type(uint152).max) {
                          revert SafeCastOverflowedUintDowncast(152, value);
                      }
                      return uint152(value);
                  }
                  /**
                   * @dev Returns the downcasted uint144 from uint256, reverting on
                   * overflow (when the input is greater than largest uint144).
                   *
                   * Counterpart to Solidity's `uint144` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 144 bits
                   */
                  function toUint144(uint256 value) internal pure returns (uint144) {
                      if (value > type(uint144).max) {
                          revert SafeCastOverflowedUintDowncast(144, value);
                      }
                      return uint144(value);
                  }
                  /**
                   * @dev Returns the downcasted uint136 from uint256, reverting on
                   * overflow (when the input is greater than largest uint136).
                   *
                   * Counterpart to Solidity's `uint136` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 136 bits
                   */
                  function toUint136(uint256 value) internal pure returns (uint136) {
                      if (value > type(uint136).max) {
                          revert SafeCastOverflowedUintDowncast(136, value);
                      }
                      return uint136(value);
                  }
                  /**
                   * @dev Returns the downcasted uint128 from uint256, reverting on
                   * overflow (when the input is greater than largest uint128).
                   *
                   * Counterpart to Solidity's `uint128` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 128 bits
                   */
                  function toUint128(uint256 value) internal pure returns (uint128) {
                      if (value > type(uint128).max) {
                          revert SafeCastOverflowedUintDowncast(128, value);
                      }
                      return uint128(value);
                  }
                  /**
                   * @dev Returns the downcasted uint120 from uint256, reverting on
                   * overflow (when the input is greater than largest uint120).
                   *
                   * Counterpart to Solidity's `uint120` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 120 bits
                   */
                  function toUint120(uint256 value) internal pure returns (uint120) {
                      if (value > type(uint120).max) {
                          revert SafeCastOverflowedUintDowncast(120, value);
                      }
                      return uint120(value);
                  }
                  /**
                   * @dev Returns the downcasted uint112 from uint256, reverting on
                   * overflow (when the input is greater than largest uint112).
                   *
                   * Counterpart to Solidity's `uint112` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 112 bits
                   */
                  function toUint112(uint256 value) internal pure returns (uint112) {
                      if (value > type(uint112).max) {
                          revert SafeCastOverflowedUintDowncast(112, value);
                      }
                      return uint112(value);
                  }
                  /**
                   * @dev Returns the downcasted uint104 from uint256, reverting on
                   * overflow (when the input is greater than largest uint104).
                   *
                   * Counterpart to Solidity's `uint104` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 104 bits
                   */
                  function toUint104(uint256 value) internal pure returns (uint104) {
                      if (value > type(uint104).max) {
                          revert SafeCastOverflowedUintDowncast(104, value);
                      }
                      return uint104(value);
                  }
                  /**
                   * @dev Returns the downcasted uint96 from uint256, reverting on
                   * overflow (when the input is greater than largest uint96).
                   *
                   * Counterpart to Solidity's `uint96` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 96 bits
                   */
                  function toUint96(uint256 value) internal pure returns (uint96) {
                      if (value > type(uint96).max) {
                          revert SafeCastOverflowedUintDowncast(96, value);
                      }
                      return uint96(value);
                  }
                  /**
                   * @dev Returns the downcasted uint88 from uint256, reverting on
                   * overflow (when the input is greater than largest uint88).
                   *
                   * Counterpart to Solidity's `uint88` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 88 bits
                   */
                  function toUint88(uint256 value) internal pure returns (uint88) {
                      if (value > type(uint88).max) {
                          revert SafeCastOverflowedUintDowncast(88, value);
                      }
                      return uint88(value);
                  }
                  /**
                   * @dev Returns the downcasted uint80 from uint256, reverting on
                   * overflow (when the input is greater than largest uint80).
                   *
                   * Counterpart to Solidity's `uint80` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 80 bits
                   */
                  function toUint80(uint256 value) internal pure returns (uint80) {
                      if (value > type(uint80).max) {
                          revert SafeCastOverflowedUintDowncast(80, value);
                      }
                      return uint80(value);
                  }
                  /**
                   * @dev Returns the downcasted uint72 from uint256, reverting on
                   * overflow (when the input is greater than largest uint72).
                   *
                   * Counterpart to Solidity's `uint72` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 72 bits
                   */
                  function toUint72(uint256 value) internal pure returns (uint72) {
                      if (value > type(uint72).max) {
                          revert SafeCastOverflowedUintDowncast(72, value);
                      }
                      return uint72(value);
                  }
                  /**
                   * @dev Returns the downcasted uint64 from uint256, reverting on
                   * overflow (when the input is greater than largest uint64).
                   *
                   * Counterpart to Solidity's `uint64` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 64 bits
                   */
                  function toUint64(uint256 value) internal pure returns (uint64) {
                      if (value > type(uint64).max) {
                          revert SafeCastOverflowedUintDowncast(64, value);
                      }
                      return uint64(value);
                  }
                  /**
                   * @dev Returns the downcasted uint56 from uint256, reverting on
                   * overflow (when the input is greater than largest uint56).
                   *
                   * Counterpart to Solidity's `uint56` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 56 bits
                   */
                  function toUint56(uint256 value) internal pure returns (uint56) {
                      if (value > type(uint56).max) {
                          revert SafeCastOverflowedUintDowncast(56, value);
                      }
                      return uint56(value);
                  }
                  /**
                   * @dev Returns the downcasted uint48 from uint256, reverting on
                   * overflow (when the input is greater than largest uint48).
                   *
                   * Counterpart to Solidity's `uint48` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 48 bits
                   */
                  function toUint48(uint256 value) internal pure returns (uint48) {
                      if (value > type(uint48).max) {
                          revert SafeCastOverflowedUintDowncast(48, value);
                      }
                      return uint48(value);
                  }
                  /**
                   * @dev Returns the downcasted uint40 from uint256, reverting on
                   * overflow (when the input is greater than largest uint40).
                   *
                   * Counterpart to Solidity's `uint40` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 40 bits
                   */
                  function toUint40(uint256 value) internal pure returns (uint40) {
                      if (value > type(uint40).max) {
                          revert SafeCastOverflowedUintDowncast(40, value);
                      }
                      return uint40(value);
                  }
                  /**
                   * @dev Returns the downcasted uint32 from uint256, reverting on
                   * overflow (when the input is greater than largest uint32).
                   *
                   * Counterpart to Solidity's `uint32` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 32 bits
                   */
                  function toUint32(uint256 value) internal pure returns (uint32) {
                      if (value > type(uint32).max) {
                          revert SafeCastOverflowedUintDowncast(32, value);
                      }
                      return uint32(value);
                  }
                  /**
                   * @dev Returns the downcasted uint24 from uint256, reverting on
                   * overflow (when the input is greater than largest uint24).
                   *
                   * Counterpart to Solidity's `uint24` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 24 bits
                   */
                  function toUint24(uint256 value) internal pure returns (uint24) {
                      if (value > type(uint24).max) {
                          revert SafeCastOverflowedUintDowncast(24, value);
                      }
                      return uint24(value);
                  }
                  /**
                   * @dev Returns the downcasted uint16 from uint256, reverting on
                   * overflow (when the input is greater than largest uint16).
                   *
                   * Counterpart to Solidity's `uint16` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 16 bits
                   */
                  function toUint16(uint256 value) internal pure returns (uint16) {
                      if (value > type(uint16).max) {
                          revert SafeCastOverflowedUintDowncast(16, value);
                      }
                      return uint16(value);
                  }
                  /**
                   * @dev Returns the downcasted uint8 from uint256, reverting on
                   * overflow (when the input is greater than largest uint8).
                   *
                   * Counterpart to Solidity's `uint8` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 8 bits
                   */
                  function toUint8(uint256 value) internal pure returns (uint8) {
                      if (value > type(uint8).max) {
                          revert SafeCastOverflowedUintDowncast(8, value);
                      }
                      return uint8(value);
                  }
                  /**
                   * @dev Converts a signed int256 into an unsigned uint256.
                   *
                   * Requirements:
                   *
                   * - input must be greater than or equal to 0.
                   */
                  function toUint256(int256 value) internal pure returns (uint256) {
                      if (value < 0) {
                          revert SafeCastOverflowedIntToUint(value);
                      }
                      return uint256(value);
                  }
                  /**
                   * @dev Returns the downcasted int248 from int256, reverting on
                   * overflow (when the input is less than smallest int248 or
                   * greater than largest int248).
                   *
                   * Counterpart to Solidity's `int248` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 248 bits
                   */
                  function toInt248(int256 value) internal pure returns (int248 downcasted) {
                      downcasted = int248(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(248, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int240 from int256, reverting on
                   * overflow (when the input is less than smallest int240 or
                   * greater than largest int240).
                   *
                   * Counterpart to Solidity's `int240` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 240 bits
                   */
                  function toInt240(int256 value) internal pure returns (int240 downcasted) {
                      downcasted = int240(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(240, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int232 from int256, reverting on
                   * overflow (when the input is less than smallest int232 or
                   * greater than largest int232).
                   *
                   * Counterpart to Solidity's `int232` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 232 bits
                   */
                  function toInt232(int256 value) internal pure returns (int232 downcasted) {
                      downcasted = int232(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(232, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int224 from int256, reverting on
                   * overflow (when the input is less than smallest int224 or
                   * greater than largest int224).
                   *
                   * Counterpart to Solidity's `int224` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 224 bits
                   */
                  function toInt224(int256 value) internal pure returns (int224 downcasted) {
                      downcasted = int224(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(224, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int216 from int256, reverting on
                   * overflow (when the input is less than smallest int216 or
                   * greater than largest int216).
                   *
                   * Counterpart to Solidity's `int216` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 216 bits
                   */
                  function toInt216(int256 value) internal pure returns (int216 downcasted) {
                      downcasted = int216(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(216, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int208 from int256, reverting on
                   * overflow (when the input is less than smallest int208 or
                   * greater than largest int208).
                   *
                   * Counterpart to Solidity's `int208` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 208 bits
                   */
                  function toInt208(int256 value) internal pure returns (int208 downcasted) {
                      downcasted = int208(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(208, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int200 from int256, reverting on
                   * overflow (when the input is less than smallest int200 or
                   * greater than largest int200).
                   *
                   * Counterpart to Solidity's `int200` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 200 bits
                   */
                  function toInt200(int256 value) internal pure returns (int200 downcasted) {
                      downcasted = int200(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(200, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int192 from int256, reverting on
                   * overflow (when the input is less than smallest int192 or
                   * greater than largest int192).
                   *
                   * Counterpart to Solidity's `int192` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 192 bits
                   */
                  function toInt192(int256 value) internal pure returns (int192 downcasted) {
                      downcasted = int192(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(192, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int184 from int256, reverting on
                   * overflow (when the input is less than smallest int184 or
                   * greater than largest int184).
                   *
                   * Counterpart to Solidity's `int184` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 184 bits
                   */
                  function toInt184(int256 value) internal pure returns (int184 downcasted) {
                      downcasted = int184(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(184, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int176 from int256, reverting on
                   * overflow (when the input is less than smallest int176 or
                   * greater than largest int176).
                   *
                   * Counterpart to Solidity's `int176` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 176 bits
                   */
                  function toInt176(int256 value) internal pure returns (int176 downcasted) {
                      downcasted = int176(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(176, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int168 from int256, reverting on
                   * overflow (when the input is less than smallest int168 or
                   * greater than largest int168).
                   *
                   * Counterpart to Solidity's `int168` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 168 bits
                   */
                  function toInt168(int256 value) internal pure returns (int168 downcasted) {
                      downcasted = int168(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(168, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int160 from int256, reverting on
                   * overflow (when the input is less than smallest int160 or
                   * greater than largest int160).
                   *
                   * Counterpart to Solidity's `int160` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 160 bits
                   */
                  function toInt160(int256 value) internal pure returns (int160 downcasted) {
                      downcasted = int160(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(160, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int152 from int256, reverting on
                   * overflow (when the input is less than smallest int152 or
                   * greater than largest int152).
                   *
                   * Counterpart to Solidity's `int152` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 152 bits
                   */
                  function toInt152(int256 value) internal pure returns (int152 downcasted) {
                      downcasted = int152(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(152, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int144 from int256, reverting on
                   * overflow (when the input is less than smallest int144 or
                   * greater than largest int144).
                   *
                   * Counterpart to Solidity's `int144` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 144 bits
                   */
                  function toInt144(int256 value) internal pure returns (int144 downcasted) {
                      downcasted = int144(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(144, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int136 from int256, reverting on
                   * overflow (when the input is less than smallest int136 or
                   * greater than largest int136).
                   *
                   * Counterpart to Solidity's `int136` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 136 bits
                   */
                  function toInt136(int256 value) internal pure returns (int136 downcasted) {
                      downcasted = int136(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(136, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int128 from int256, reverting on
                   * overflow (when the input is less than smallest int128 or
                   * greater than largest int128).
                   *
                   * Counterpart to Solidity's `int128` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 128 bits
                   */
                  function toInt128(int256 value) internal pure returns (int128 downcasted) {
                      downcasted = int128(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(128, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int120 from int256, reverting on
                   * overflow (when the input is less than smallest int120 or
                   * greater than largest int120).
                   *
                   * Counterpart to Solidity's `int120` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 120 bits
                   */
                  function toInt120(int256 value) internal pure returns (int120 downcasted) {
                      downcasted = int120(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(120, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int112 from int256, reverting on
                   * overflow (when the input is less than smallest int112 or
                   * greater than largest int112).
                   *
                   * Counterpart to Solidity's `int112` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 112 bits
                   */
                  function toInt112(int256 value) internal pure returns (int112 downcasted) {
                      downcasted = int112(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(112, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int104 from int256, reverting on
                   * overflow (when the input is less than smallest int104 or
                   * greater than largest int104).
                   *
                   * Counterpart to Solidity's `int104` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 104 bits
                   */
                  function toInt104(int256 value) internal pure returns (int104 downcasted) {
                      downcasted = int104(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(104, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int96 from int256, reverting on
                   * overflow (when the input is less than smallest int96 or
                   * greater than largest int96).
                   *
                   * Counterpart to Solidity's `int96` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 96 bits
                   */
                  function toInt96(int256 value) internal pure returns (int96 downcasted) {
                      downcasted = int96(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(96, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int88 from int256, reverting on
                   * overflow (when the input is less than smallest int88 or
                   * greater than largest int88).
                   *
                   * Counterpart to Solidity's `int88` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 88 bits
                   */
                  function toInt88(int256 value) internal pure returns (int88 downcasted) {
                      downcasted = int88(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(88, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int80 from int256, reverting on
                   * overflow (when the input is less than smallest int80 or
                   * greater than largest int80).
                   *
                   * Counterpart to Solidity's `int80` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 80 bits
                   */
                  function toInt80(int256 value) internal pure returns (int80 downcasted) {
                      downcasted = int80(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(80, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int72 from int256, reverting on
                   * overflow (when the input is less than smallest int72 or
                   * greater than largest int72).
                   *
                   * Counterpart to Solidity's `int72` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 72 bits
                   */
                  function toInt72(int256 value) internal pure returns (int72 downcasted) {
                      downcasted = int72(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(72, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int64 from int256, reverting on
                   * overflow (when the input is less than smallest int64 or
                   * greater than largest int64).
                   *
                   * Counterpart to Solidity's `int64` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 64 bits
                   */
                  function toInt64(int256 value) internal pure returns (int64 downcasted) {
                      downcasted = int64(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(64, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int56 from int256, reverting on
                   * overflow (when the input is less than smallest int56 or
                   * greater than largest int56).
                   *
                   * Counterpart to Solidity's `int56` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 56 bits
                   */
                  function toInt56(int256 value) internal pure returns (int56 downcasted) {
                      downcasted = int56(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(56, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int48 from int256, reverting on
                   * overflow (when the input is less than smallest int48 or
                   * greater than largest int48).
                   *
                   * Counterpart to Solidity's `int48` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 48 bits
                   */
                  function toInt48(int256 value) internal pure returns (int48 downcasted) {
                      downcasted = int48(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(48, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int40 from int256, reverting on
                   * overflow (when the input is less than smallest int40 or
                   * greater than largest int40).
                   *
                   * Counterpart to Solidity's `int40` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 40 bits
                   */
                  function toInt40(int256 value) internal pure returns (int40 downcasted) {
                      downcasted = int40(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(40, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int32 from int256, reverting on
                   * overflow (when the input is less than smallest int32 or
                   * greater than largest int32).
                   *
                   * Counterpart to Solidity's `int32` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 32 bits
                   */
                  function toInt32(int256 value) internal pure returns (int32 downcasted) {
                      downcasted = int32(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(32, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int24 from int256, reverting on
                   * overflow (when the input is less than smallest int24 or
                   * greater than largest int24).
                   *
                   * Counterpart to Solidity's `int24` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 24 bits
                   */
                  function toInt24(int256 value) internal pure returns (int24 downcasted) {
                      downcasted = int24(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(24, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int16 from int256, reverting on
                   * overflow (when the input is less than smallest int16 or
                   * greater than largest int16).
                   *
                   * Counterpart to Solidity's `int16` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 16 bits
                   */
                  function toInt16(int256 value) internal pure returns (int16 downcasted) {
                      downcasted = int16(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(16, value);
                      }
                  }
                  /**
                   * @dev Returns the downcasted int8 from int256, reverting on
                   * overflow (when the input is less than smallest int8 or
                   * greater than largest int8).
                   *
                   * Counterpart to Solidity's `int8` operator.
                   *
                   * Requirements:
                   *
                   * - input must fit into 8 bits
                   */
                  function toInt8(int256 value) internal pure returns (int8 downcasted) {
                      downcasted = int8(value);
                      if (downcasted != value) {
                          revert SafeCastOverflowedIntDowncast(8, value);
                      }
                  }
                  /**
                   * @dev Converts an unsigned uint256 into a signed int256.
                   *
                   * Requirements:
                   *
                   * - input must be less than or equal to maxInt256.
                   */
                  function toInt256(uint256 value) internal pure returns (int256) {
                      // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
                      if (value > uint256(type(int256).max)) {
                          revert SafeCastOverflowedUintToInt(value);
                      }
                      return int256(value);
                  }
                  /**
                   * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
                   */
                  function toUint(bool b) internal pure returns (uint256 u) {
                      assembly ("memory-safe") {
                          u := iszero(iszero(b))
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol)
              pragma solidity ^0.8.20;
              import {SafeCast} from "./SafeCast.sol";
              /**
               * @dev Standard signed math utilities missing in the Solidity language.
               */
              library SignedMath {
                  /**
                   * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
                   *
                   * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
                   * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
                   * one branch when needed, making this function more expensive.
                   */
                  function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) {
                      unchecked {
                          // branchless ternary works because:
                          // b ^ (a ^ b) == a
                          // b ^ 0 == b
                          return b ^ ((a ^ b) * int256(SafeCast.toUint(condition)));
                      }
                  }
                  /**
                   * @dev Returns the largest of two signed numbers.
                   */
                  function max(int256 a, int256 b) internal pure returns (int256) {
                      return ternary(a > b, a, b);
                  }
                  /**
                   * @dev Returns the smallest of two signed numbers.
                   */
                  function min(int256 a, int256 b) internal pure returns (int256) {
                      return ternary(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 {
                          // Formula from the "Bit Twiddling Hacks" by Sean Eron Anderson.
                          // Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift,
                          // taking advantage of the most significant (or "sign" bit) in two's complement representation.
                          // This opcode adds new most significant bits set to the value of the previous most significant bit. As a result,
                          // the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative).
                          int256 mask = n >> 255;
                          // A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it.
                          return uint256((n + mask) ^ mask);
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)
              pragma solidity ^0.8.20;
              /**
               * @dev Helper library for emitting standardized panic codes.
               *
               * ```solidity
               * contract Example {
               *      using Panic for uint256;
               *
               *      // Use any of the declared internal constants
               *      function foo() { Panic.GENERIC.panic(); }
               *
               *      // Alternatively
               *      function foo() { Panic.panic(Panic.GENERIC); }
               * }
               * ```
               *
               * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
               *
               * _Available since v5.1._
               */
              // slither-disable-next-line unused-state
              library Panic {
                  /// @dev generic / unspecified error
                  uint256 internal constant GENERIC = 0x00;
                  /// @dev used by the assert() builtin
                  uint256 internal constant ASSERT = 0x01;
                  /// @dev arithmetic underflow or overflow
                  uint256 internal constant UNDER_OVERFLOW = 0x11;
                  /// @dev division or modulo by zero
                  uint256 internal constant DIVISION_BY_ZERO = 0x12;
                  /// @dev enum conversion error
                  uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
                  /// @dev invalid encoding in storage
                  uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
                  /// @dev empty array pop
                  uint256 internal constant EMPTY_ARRAY_POP = 0x31;
                  /// @dev array out of bounds access
                  uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
                  /// @dev resource error (too large allocation or too large array)
                  uint256 internal constant RESOURCE_ERROR = 0x41;
                  /// @dev calling invalid internal function
                  uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;
                  /// @dev Reverts with a panic code. Recommended to use with
                  /// the internal constants with predefined codes.
                  function panic(uint256 code) internal pure {
                      assembly ("memory-safe") {
                          mstore(0x00, 0x4e487b71)
                          mstore(0x20, code)
                          revert(0x1c, 0x24)
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
              // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
              pragma solidity ^0.8.20;
              /**
               * @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 ERC-1967 implementation slot:
               * ```solidity
               * contract ERC1967 {
               *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
               *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
               *
               *     function _getImplementation() internal view returns (address) {
               *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
               *     }
               *
               *     function _setImplementation(address newImplementation) internal {
               *         require(newImplementation.code.length > 0);
               *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
               *     }
               * }
               * ```
               *
               * TIP: Consider using this library along with {SlotDerivation}.
               */
              library StorageSlot {
                  struct AddressSlot {
                      address value;
                  }
                  struct BooleanSlot {
                      bool value;
                  }
                  struct Bytes32Slot {
                      bytes32 value;
                  }
                  struct Uint256Slot {
                      uint256 value;
                  }
                  struct Int256Slot {
                      int256 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) {
                      assembly ("memory-safe") {
                          r.slot := slot
                      }
                  }
                  /**
                   * @dev Returns a `BooleanSlot` with member `value` located at `slot`.
                   */
                  function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                      assembly ("memory-safe") {
                          r.slot := slot
                      }
                  }
                  /**
                   * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
                   */
                  function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                      assembly ("memory-safe") {
                          r.slot := slot
                      }
                  }
                  /**
                   * @dev Returns a `Uint256Slot` with member `value` located at `slot`.
                   */
                  function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                      assembly ("memory-safe") {
                          r.slot := slot
                      }
                  }
                  /**
                   * @dev Returns a `Int256Slot` with member `value` located at `slot`.
                   */
                  function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
                      assembly ("memory-safe") {
                          r.slot := slot
                      }
                  }
                  /**
                   * @dev Returns a `StringSlot` with member `value` located at `slot`.
                   */
                  function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                      assembly ("memory-safe") {
                          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) {
                      assembly ("memory-safe") {
                          r.slot := store.slot
                      }
                  }
                  /**
                   * @dev Returns a `BytesSlot` with member `value` located at `slot`.
                   */
                  function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                      assembly ("memory-safe") {
                          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) {
                      assembly ("memory-safe") {
                          r.slot := store.slot
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v5.2.0) (utils/Strings.sol)
              pragma solidity ^0.8.20;
              import {Math} from "./math/Math.sol";
              import {SafeCast} from "./math/SafeCast.sol";
              import {SignedMath} from "./math/SignedMath.sol";
              /**
               * @dev String operations.
               */
              library Strings {
                  using SafeCast for *;
                  bytes16 private constant HEX_DIGITS = "0123456789abcdef";
                  uint8 private constant ADDRESS_LENGTH = 20;
                  /**
                   * @dev The `value` string doesn't fit in the specified `length`.
                   */
                  error StringsInsufficientHexLength(uint256 value, uint256 length);
                  /**
                   * @dev The string being parsed contains characters that are not in scope of the given base.
                   */
                  error StringsInvalidChar();
                  /**
                   * @dev The string being parsed is not a properly formatted address.
                   */
                  error StringsInvalidAddressFormat();
                  /**
                   * @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;
                          assembly ("memory-safe") {
                              ptr := add(buffer, add(32, length))
                          }
                          while (true) {
                              ptr--;
                              assembly ("memory-safe") {
                                  mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                              }
                              value /= 10;
                              if (value == 0) break;
                          }
                          return buffer;
                      }
                  }
                  /**
                   * @dev Converts a `int256` to its ASCII `string` decimal representation.
                   */
                  function toStringSigned(int256 value) internal pure returns (string memory) {
                      return string.concat(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) {
                      uint256 localValue = value;
                      bytes memory buffer = new bytes(2 * length + 2);
                      buffer[0] = "0";
                      buffer[1] = "x";
                      for (uint256 i = 2 * length + 1; i > 1; --i) {
                          buffer[i] = HEX_DIGITS[localValue & 0xf];
                          localValue >>= 4;
                      }
                      if (localValue != 0) {
                          revert StringsInsufficientHexLength(value, length);
                      }
                      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 Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal
                   * representation, according to EIP-55.
                   */
                  function toChecksumHexString(address addr) internal pure returns (string memory) {
                      bytes memory buffer = bytes(toHexString(addr));
                      // hash the hex part of buffer (skip length + 2 bytes, length 40)
                      uint256 hashValue;
                      assembly ("memory-safe") {
                          hashValue := shr(96, keccak256(add(buffer, 0x22), 40))
                      }
                      for (uint256 i = 41; i > 1; --i) {
                          // possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f)
                          if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) {
                              // case shift by xoring with 0x20
                              buffer[i] ^= 0x20;
                          }
                          hashValue >>= 4;
                      }
                      return string(buffer);
                  }
                  /**
                   * @dev Returns true if the two strings are equal.
                   */
                  function equal(string memory a, string memory b) internal pure returns (bool) {
                      return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
                  }
                  /**
                   * @dev Parse a decimal string and returns the value as a `uint256`.
                   *
                   * Requirements:
                   * - The string must be formatted as `[0-9]*`
                   * - The result must fit into an `uint256` type
                   */
                  function parseUint(string memory input) internal pure returns (uint256) {
                      return parseUint(input, 0, bytes(input).length);
                  }
                  /**
                   * @dev Variant of {parseUint} that parses a substring of `input` located between position `begin` (included) and
                   * `end` (excluded).
                   *
                   * Requirements:
                   * - The substring must be formatted as `[0-9]*`
                   * - The result must fit into an `uint256` type
                   */
                  function parseUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {
                      (bool success, uint256 value) = tryParseUint(input, begin, end);
                      if (!success) revert StringsInvalidChar();
                      return value;
                  }
                  /**
                   * @dev Variant of {parseUint-string} that returns false if the parsing fails because of an invalid character.
                   *
                   * NOTE: This function will revert if the result does not fit in a `uint256`.
                   */
                  function tryParseUint(string memory input) internal pure returns (bool success, uint256 value) {
                      return _tryParseUintUncheckedBounds(input, 0, bytes(input).length);
                  }
                  /**
                   * @dev Variant of {parseUint-string-uint256-uint256} that returns false if the parsing fails because of an invalid
                   * character.
                   *
                   * NOTE: This function will revert if the result does not fit in a `uint256`.
                   */
                  function tryParseUint(
                      string memory input,
                      uint256 begin,
                      uint256 end
                  ) internal pure returns (bool success, uint256 value) {
                      if (end > bytes(input).length || begin > end) return (false, 0);
                      return _tryParseUintUncheckedBounds(input, begin, end);
                  }
                  /**
                   * @dev Implementation of {tryParseUint} that does not check bounds. Caller should make sure that
                   * `begin <= end <= input.length`. Other inputs would result in undefined behavior.
                   */
                  function _tryParseUintUncheckedBounds(
                      string memory input,
                      uint256 begin,
                      uint256 end
                  ) private pure returns (bool success, uint256 value) {
                      bytes memory buffer = bytes(input);
                      uint256 result = 0;
                      for (uint256 i = begin; i < end; ++i) {
                          uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));
                          if (chr > 9) return (false, 0);
                          result *= 10;
                          result += chr;
                      }
                      return (true, result);
                  }
                  /**
                   * @dev Parse a decimal string and returns the value as a `int256`.
                   *
                   * Requirements:
                   * - The string must be formatted as `[-+]?[0-9]*`
                   * - The result must fit in an `int256` type.
                   */
                  function parseInt(string memory input) internal pure returns (int256) {
                      return parseInt(input, 0, bytes(input).length);
                  }
                  /**
                   * @dev Variant of {parseInt-string} that parses a substring of `input` located between position `begin` (included) and
                   * `end` (excluded).
                   *
                   * Requirements:
                   * - The substring must be formatted as `[-+]?[0-9]*`
                   * - The result must fit in an `int256` type.
                   */
                  function parseInt(string memory input, uint256 begin, uint256 end) internal pure returns (int256) {
                      (bool success, int256 value) = tryParseInt(input, begin, end);
                      if (!success) revert StringsInvalidChar();
                      return value;
                  }
                  /**
                   * @dev Variant of {parseInt-string} that returns false if the parsing fails because of an invalid character or if
                   * the result does not fit in a `int256`.
                   *
                   * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.
                   */
                  function tryParseInt(string memory input) internal pure returns (bool success, int256 value) {
                      return _tryParseIntUncheckedBounds(input, 0, bytes(input).length);
                  }
                  uint256 private constant ABS_MIN_INT256 = 2 ** 255;
                  /**
                   * @dev Variant of {parseInt-string-uint256-uint256} that returns false if the parsing fails because of an invalid
                   * character or if the result does not fit in a `int256`.
                   *
                   * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.
                   */
                  function tryParseInt(
                      string memory input,
                      uint256 begin,
                      uint256 end
                  ) internal pure returns (bool success, int256 value) {
                      if (end > bytes(input).length || begin > end) return (false, 0);
                      return _tryParseIntUncheckedBounds(input, begin, end);
                  }
                  /**
                   * @dev Implementation of {tryParseInt} that does not check bounds. Caller should make sure that
                   * `begin <= end <= input.length`. Other inputs would result in undefined behavior.
                   */
                  function _tryParseIntUncheckedBounds(
                      string memory input,
                      uint256 begin,
                      uint256 end
                  ) private pure returns (bool success, int256 value) {
                      bytes memory buffer = bytes(input);
                      // Check presence of a negative sign.
                      bytes1 sign = begin == end ? bytes1(0) : bytes1(_unsafeReadBytesOffset(buffer, begin)); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
                      bool positiveSign = sign == bytes1("+");
                      bool negativeSign = sign == bytes1("-");
                      uint256 offset = (positiveSign || negativeSign).toUint();
                      (bool absSuccess, uint256 absValue) = tryParseUint(input, begin + offset, end);
                      if (absSuccess && absValue < ABS_MIN_INT256) {
                          return (true, negativeSign ? -int256(absValue) : int256(absValue));
                      } else if (absSuccess && negativeSign && absValue == ABS_MIN_INT256) {
                          return (true, type(int256).min);
                      } else return (false, 0);
                  }
                  /**
                   * @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as a `uint256`.
                   *
                   * Requirements:
                   * - The string must be formatted as `(0x)?[0-9a-fA-F]*`
                   * - The result must fit in an `uint256` type.
                   */
                  function parseHexUint(string memory input) internal pure returns (uint256) {
                      return parseHexUint(input, 0, bytes(input).length);
                  }
                  /**
                   * @dev Variant of {parseHexUint} that parses a substring of `input` located between position `begin` (included) and
                   * `end` (excluded).
                   *
                   * Requirements:
                   * - The substring must be formatted as `(0x)?[0-9a-fA-F]*`
                   * - The result must fit in an `uint256` type.
                   */
                  function parseHexUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {
                      (bool success, uint256 value) = tryParseHexUint(input, begin, end);
                      if (!success) revert StringsInvalidChar();
                      return value;
                  }
                  /**
                   * @dev Variant of {parseHexUint-string} that returns false if the parsing fails because of an invalid character.
                   *
                   * NOTE: This function will revert if the result does not fit in a `uint256`.
                   */
                  function tryParseHexUint(string memory input) internal pure returns (bool success, uint256 value) {
                      return _tryParseHexUintUncheckedBounds(input, 0, bytes(input).length);
                  }
                  /**
                   * @dev Variant of {parseHexUint-string-uint256-uint256} that returns false if the parsing fails because of an
                   * invalid character.
                   *
                   * NOTE: This function will revert if the result does not fit in a `uint256`.
                   */
                  function tryParseHexUint(
                      string memory input,
                      uint256 begin,
                      uint256 end
                  ) internal pure returns (bool success, uint256 value) {
                      if (end > bytes(input).length || begin > end) return (false, 0);
                      return _tryParseHexUintUncheckedBounds(input, begin, end);
                  }
                  /**
                   * @dev Implementation of {tryParseHexUint} that does not check bounds. Caller should make sure that
                   * `begin <= end <= input.length`. Other inputs would result in undefined behavior.
                   */
                  function _tryParseHexUintUncheckedBounds(
                      string memory input,
                      uint256 begin,
                      uint256 end
                  ) private pure returns (bool success, uint256 value) {
                      bytes memory buffer = bytes(input);
                      // skip 0x prefix if present
                      bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(buffer, begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
                      uint256 offset = hasPrefix.toUint() * 2;
                      uint256 result = 0;
                      for (uint256 i = begin + offset; i < end; ++i) {
                          uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));
                          if (chr > 15) return (false, 0);
                          result *= 16;
                          unchecked {
                              // Multiplying by 16 is equivalent to a shift of 4 bits (with additional overflow check).
                              // This guaratees that adding a value < 16 will not cause an overflow, hence the unchecked.
                              result += chr;
                          }
                      }
                      return (true, result);
                  }
                  /**
                   * @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as an `address`.
                   *
                   * Requirements:
                   * - The string must be formatted as `(0x)?[0-9a-fA-F]{40}`
                   */
                  function parseAddress(string memory input) internal pure returns (address) {
                      return parseAddress(input, 0, bytes(input).length);
                  }
                  /**
                   * @dev Variant of {parseAddress} that parses a substring of `input` located between position `begin` (included) and
                   * `end` (excluded).
                   *
                   * Requirements:
                   * - The substring must be formatted as `(0x)?[0-9a-fA-F]{40}`
                   */
                  function parseAddress(string memory input, uint256 begin, uint256 end) internal pure returns (address) {
                      (bool success, address value) = tryParseAddress(input, begin, end);
                      if (!success) revert StringsInvalidAddressFormat();
                      return value;
                  }
                  /**
                   * @dev Variant of {parseAddress-string} that returns false if the parsing fails because the input is not a properly
                   * formatted address. See {parseAddress} requirements.
                   */
                  function tryParseAddress(string memory input) internal pure returns (bool success, address value) {
                      return tryParseAddress(input, 0, bytes(input).length);
                  }
                  /**
                   * @dev Variant of {parseAddress-string-uint256-uint256} that returns false if the parsing fails because input is not a properly
                   * formatted address. See {parseAddress} requirements.
                   */
                  function tryParseAddress(
                      string memory input,
                      uint256 begin,
                      uint256 end
                  ) internal pure returns (bool success, address value) {
                      if (end > bytes(input).length || begin > end) return (false, address(0));
                      bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(bytes(input), begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
                      uint256 expectedLength = 40 + hasPrefix.toUint() * 2;
                      // check that input is the correct length
                      if (end - begin == expectedLength) {
                          // length guarantees that this does not overflow, and value is at most type(uint160).max
                          (bool s, uint256 v) = _tryParseHexUintUncheckedBounds(input, begin, end);
                          return (s, address(uint160(v)));
                      } else {
                          return (false, address(0));
                      }
                  }
                  function _tryParseChr(bytes1 chr) private pure returns (uint8) {
                      uint8 value = uint8(chr);
                      // Try to parse `chr`:
                      // - Case 1: [0-9]
                      // - Case 2: [a-f]
                      // - Case 3: [A-F]
                      // - otherwise not supported
                      unchecked {
                          if (value > 47 && value < 58) value -= 48;
                          else if (value > 96 && value < 103) value -= 87;
                          else if (value > 64 && value < 71) value -= 55;
                          else return type(uint8).max;
                      }
                      return value;
                  }
                  /**
                   * @dev Reads a bytes32 from a bytes array without bounds checking.
                   *
                   * NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the
                   * assembly block as such would prevent some optimizations.
                   */
                  function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) {
                      // This is not memory safe in the general case, but all calls to this private function are within bounds.
                      assembly ("memory-safe") {
                          value := mload(add(buffer, add(0x20, offset)))
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity ^0.8.22;
              import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
              import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
              import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";
              import {ERC20PermitUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol";
              import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
              import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
              contract CustomTokenFinal is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, AccessControlUpgradeable, ERC20PermitUpgradeable, UUPSUpgradeable {
                  uint256 private _cap;
                  bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
                  /// @custom:oz-upgrades-unsafe-allow constructor
                  constructor() {
                      _disableInitializers();
                  }
                  function initialize(
                      string memory name,
                      string memory symbol,
                      uint256 cap_,
                      address defaultAdmin,
                      address[] memory minters
                  ) initializer public
                  {
                      require(cap_ > 0, "Cap must be greater than 0");
                      _cap = cap_;
                      __ERC20_init(name, symbol);
                      __ERC20Burnable_init();
                      __AccessControl_init();
                      __ERC20Permit_init(name);
                      __UUPSUpgradeable_init();
                      _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);
                      for(uint i = 0; i < minters.length; i++) {
                          _grantRole(MINTER_ROLE, minters[i]);
                      }
                  }
                  function supplyCap() public view returns (uint256) {
                      return _cap;
                  }
                  function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {
                      require(totalSupply() + amount <= supplyCap(), "ERC20: cap exceeded");
                      _mint(to, amount);
                  }
                  function _authorizeUpgrade(address newImplementation)
                      internal
                      onlyRole(DEFAULT_ADMIN_ROLE)
                      override
                  {
                      revert("Upgrades disabled");
                  }
              }