ETH Price: $1,975.26 (+0.07%)

Transaction Decoder

Block:
24509025 at Feb-22-2026 01:08:47 AM +UTC
Transaction Fee:
0.000009962378139398 ETH $0.02
Gas Used:
122,662 Gas / 0.081218129 Gwei

Emitted Events:

203 EntryPoint.BeforeExecution( )
204 EntryPoint.UserOperationEvent( userOpHash=91E0E43C3285F1B2547FC35F59B52826AAB14423325C1566958CCDE3AE9312FA, sender=0x66a17bfddf3e35166728a3c67a7982ed2a4500b9, paymaster=0x4fd9098af9ddcb41da48a1d78f91f1398965addc, nonce=32682511990017020104572338700288, success=True, actualGasCost=11363885450024, actualGasUsed=121256 )

Account State Difference:

  Address   Before After State Difference Code
0x5FF137D4...a026d2789
(Entry Point 0.6.0)
319.70359326322569419 Eth319.703581899340244166 Eth0.000011363885450024
0xb3D34cAF...6fdEe90da
(Bundler: 0xb3d...0da)
0.23899153442206799 Eth
Nonce: 9822
0.238992935929378616 Eth
Nonce: 9823
0.000001401507310626
(BuilderNet)
132.873197569861129369 Eth132.873203702961129369 Eth0.0000061331

Execution Trace

EntryPoint.handleOps( ops=, beneficiary=0xb3D34cAFEDA3893A6665EB2342Da7E26fdEe90da )
  • 0x66a17bfddf3e35166728a3c67a7982ed2a4500b9.3a871cdd( )
    • LightAccount.validateUserOp( userOp=[{name:sender, type:address, order:1, indexed:false, value:0x66a17bFddF3E35166728A3C67A7982ED2a4500B9, valueString:0x66a17bFddF3E35166728A3C67A7982ED2a4500B9}, {name:nonce, type:uint256, order:2, indexed:false, value:32682511990017020104572338700288, valueString:32682511990017020104572338700288}, {name:initCode, type:bytes, order:3, indexed:false, value:0x, valueString:0x}, {name:callData, type:bytes, order:4, indexed:false, value:0xB61D27F600000000000000000000000066A17BFDDF3E35166728A3C67A7982ED2A4500B9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004D087D28800000000000000000000000000000000000000000000000000000000, valueString:0xB61D27F600000000000000000000000066A17BFDDF3E35166728A3C67A7982ED2A4500B9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004D087D28800000000000000000000000000000000000000000000000000000000}, {name:callGasLimit, type:uint256, order:5, indexed:false, value:10095, valueString:10095}, {name:verificationGasLimit, type:uint256, order:6, indexed:false, value:82522, valueString:82522}, {name:preVerificationGas, type:uint256, order:7, indexed:false, value:46428, valueString:46428}, {name:maxFeePerGas, type:uint256, order:8, indexed:false, value:104125893, valueString:104125893}, {name:maxPriorityFeePerGas, type:uint256, order:9, indexed:false, value:62500000, valueString:62500000}, {name:paymasterAndData, type:bytes, order:10, indexed:false, value:0x4FD9098AF9DDCB41DA48A1D78F91F1398965ADDC0000000000000000699A59750000000000000000000000000000000000000000DDC19385DF64347148E552CDF1AFDD08A74742174EDD672A02AE732D0EB4E114368838AEEDE0C096B815A5D15E42D199B47A77B46101F2ECA6DF4B65BDCDC0DA1B, valueString:0x4FD9098AF9DDCB41DA48A1D78F91F1398965ADDC0000000000000000699A59750000000000000000000000000000000000000000DDC19385DF64347148E552CDF1AFDD08A74742174EDD672A02AE732D0EB4E114368838AEEDE0C096B815A5D15E42D199B47A77B46101F2ECA6DF4B65BDCDC0DA1B}, {name:signature, type:bytes, order:11, indexed:false, value:0xA62CE9B69D1F7097018CF43156935B2CE750D047E0970BA9928DAA4EEB2587245803283189F5F8D0AB663B656AE7AB1DD48D152DCF797C745DB27F944BFF1DE61C, valueString:0xA62CE9B69D1F7097018CF43156935B2CE750D047E0970BA9928DAA4EEB2587245803283189F5F8D0AB663B656AE7AB1DD48D152DCF797C745DB27F944BFF1DE61C}], userOpHash=91E0E43C3285F1B2547FC35F59B52826AAB14423325C1566958CCDE3AE9312FA, missingAccountFunds=0 ) => ( validationData=0 )
      • Null: 0x000...001.48e9096f( )
      • Alchemy: Paymaster 1.f465c77e( )
        • 0x8505d426baabf0ab923801c3e460fad3b3da9c4f.f465c77e( )
          • Null: 0x000...001.5d70fd02( )
          • EntryPoint.innerHandleOp( callData=0xB61D27F600000000000000000000000066A17BFDDF3E35166728A3C67A7982ED2A4500B9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004D087D28800000000000000000000000000000000000000000000000000000000, opInfo=[{name:mUserOp, type:tuple, order:1, indexed:false, value:[{name:sender, type:address, order:1, indexed:false, value:0x66a17bFddF3E35166728A3C67A7982ED2a4500B9, valueString:0x66a17bFddF3E35166728A3C67A7982ED2a4500B9}, {name:nonce, type:uint256, order:2, indexed:false, value:32682511990017020104572338700288, valueString:32682511990017020104572338700288}, {name:callGasLimit, type:uint256, order:3, indexed:false, value:10095, valueString:10095}, {name:verificationGasLimit, type:uint256, order:4, indexed:false, value:82522, valueString:82522}, {name:preVerificationGas, type:uint256, order:5, indexed:false, value:46428, valueString:46428}, {name:paymaster, type:address, order:6, indexed:false, value:0x4Fd9098af9ddcB41DA48A1d78F91F1398965addc, valueString:0x4Fd9098af9ddcB41DA48A1d78F91F1398965addc}, {name:maxFeePerGas, type:uint256, order:7, indexed:false, value:104125893, valueString:104125893}, {name:maxPriorityFeePerGas, type:uint256, order:8, indexed:false, value:62500000, valueString:62500000}], valueString:[{name:sender, type:address, order:1, indexed:false, value:0x66a17bFddF3E35166728A3C67A7982ED2a4500B9, valueString:0x66a17bFddF3E35166728A3C67A7982ED2a4500B9}, {name:nonce, type:uint256, order:2, indexed:false, value:32682511990017020104572338700288, valueString:32682511990017020104572338700288}, {name:callGasLimit, type:uint256, order:3, indexed:false, value:10095, valueString:10095}, {name:verificationGasLimit, type:uint256, order:4, indexed:false, value:82522, valueString:82522}, {name:preVerificationGas, type:uint256, order:5, indexed:false, value:46428, valueString:46428}, {name:paymaster, type:address, order:6, indexed:false, value:0x4Fd9098af9ddcB41DA48A1d78F91F1398965addc, valueString:0x4Fd9098af9ddcB41DA48A1d78F91F1398965addc}, {name:maxFeePerGas, type:uint256, order:7, indexed:false, value:104125893, valueString:104125893}, {name:maxPriorityFeePerGas, type:uint256, order:8, indexed:false, value:62500000, valueString:62500000}]}, {name:userOpHash, type:bytes32, order:2, indexed:false, value:91E0E43C3285F1B2547FC35F59B52826AAB14423325C1566958CCDE3AE9312FA, valueString:91E0E43C3285F1B2547FC35F59B52826AAB14423325C1566958CCDE3AE9312FA}, {name:prefund, type:uint256, order:3, indexed:false, value:31663538676477, valueString:31663538676477}, {name:contextOffset, type:uint256, order:4, indexed:false, value:1216, valueString:1216}, {name:preOpGas, type:uint256, order:5, indexed:false, value:114665, valueString:114665}], context=0x ) => ( actualGasCost=11363885450024 )
            • 0x66a17bfddf3e35166728a3c67a7982ed2a4500b9.b61d27f6( )
              • LightAccount.execute( dest=0x66a17bFddF3E35166728A3C67A7982ED2a4500B9, value=0, func=0xD087D288 )
                • 0x66a17bfddf3e35166728a3c67a7982ed2a4500b9.CALL( )
                  • LightAccount.DELEGATECALL( )
                    • EntryPoint.getNonce( sender=0x66a17bFddF3E35166728A3C67A7982ED2a4500B9, key=0 ) => ( nonce=0 )
                    • ETH 0.000011363885450024 Bundler: 0xb3d...0da.CALL( )
                      handleOps[EntryPoint (ln:137)]
                      File 1 of 2: EntryPoint
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)
                      pragma solidity ^0.8.0;
                      /**
                       * @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;
                          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
                              require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
                              // Any calls to nonReentrant after this point will fail
                              _status = _ENTERED;
                          }
                          function _nonReentrantAfter() private {
                              // By storing the original value once again, a refund is triggered (see
                              // https://eips.ethereum.org/EIPS/eip-2200)
                              _status = _NOT_ENTERED;
                          }
                      }
                      /**
                       ** Account-Abstraction (EIP-4337) singleton EntryPoint implementation.
                       ** Only one instance required on each chain.
                       **/
                      // SPDX-License-Identifier: GPL-3.0
                      pragma solidity ^0.8.12;
                      /* solhint-disable avoid-low-level-calls */
                      /* solhint-disable no-inline-assembly */
                      import "../interfaces/IAccount.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 "@openzeppelin/contracts/security/ReentrancyGuard.sol";
                      contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard {
                          using UserOperationLib for UserOperation;
                          SenderCreator private immutable senderCreator = new SenderCreator();
                          // internal value used during simulation: need to query aggregator.
                          address private constant SIMULATE_FIND_AGGREGATOR = address(1);
                          // marker for inner call revert on out of gas
                          bytes32 private constant INNER_OUT_OF_GAS = hex'deaddead';
                          uint256 private constant REVERT_REASON_MAX_LEN = 2048;
                          /**
                           * for simulation purposes, validateUserOp (and validatePaymasterUserOp) must return this value
                           * in case of signature failure, instead of revert.
                           */
                          uint256 public constant SIG_VALIDATION_FAILED = 1;
                          /**
                           * 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 op
                           * @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, UserOperation calldata userOp, UserOpInfo memory opInfo) private returns (uint256 collected) {
                              uint256 preGas = gasleft();
                              bytes memory context = getMemoryBytesFromOffset(opInfo.contextOffset);
                              try this.innerHandleOp(userOp.callData, opInfo, context) returns (uint256 _actualGasCost) {
                                  collected = _actualGasCost;
                              } catch {
                                  bytes32 innerRevertCode;
                                  assembly {
                                      returndatacopy(0, 0, 32)
                                      innerRevertCode := mload(0)
                                  }
                                  // handleOps was called with gas limit too low. abort entire bundle.
                                  if (innerRevertCode == INNER_OUT_OF_GAS) {
                                      //report paymaster, since if it is not deliberately caused by the bundler,
                                      // it must be a revert caused by paymaster.
                                      revert FailedOp(opIndex, "AA95 out of gas");
                                  }
                                  uint256 actualGas = preGas - gasleft() + opInfo.preOpGas;
                                  collected = _handlePostOp(opIndex, IPaymaster.PostOpMode.postOpReverted, opInfo, context, actualGas);
                              }
                          }
                          /**
                           * 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(UserOperation[] 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);
                          } //unchecked
                          }
                          /**
                           * 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
                          ) public nonReentrant {
                              uint256 opasLen = opsPerAggregator.length;
                              uint256 totalOps = 0;
                              for (uint256 i = 0; i < opasLen; i++) {
                                  UserOpsPerAggregator calldata opa = opsPerAggregator[i];
                                  UserOperation[] 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);
                              emit BeforeExecution();
                              uint256 opIndex = 0;
                              for (uint256 a = 0; a < opasLen; a++) {
                                  UserOpsPerAggregator calldata opa = opsPerAggregator[a];
                                  UserOperation[] 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++;
                                  }
                              }
                              uint256 collected = 0;
                              opIndex = 0;
                              for (uint256 a = 0; a < opasLen; a++) {
                                  UserOpsPerAggregator calldata opa = opsPerAggregator[a];
                                  emit SignatureAggregatorChanged(address(opa.aggregator));
                                  UserOperation[] 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);
                          }
                          /// @inheritdoc IEntryPoint
                          function simulateHandleOp(UserOperation calldata op, address target, bytes calldata targetCallData) external override {
                              UserOpInfo memory opInfo;
                              _simulationOnlyValidations(op);
                              (uint256 validationData, uint256 paymasterValidationData) = _validatePrepayment(0, op, opInfo);
                              ValidationData memory data = _intersectTimeRange(validationData, paymasterValidationData);
                              numberMarker();
                              uint256 paid = _executeUserOp(0, op, opInfo);
                              numberMarker();
                              bool targetSuccess;
                              bytes memory targetResult;
                              if (target != address(0)) {
                                  (targetSuccess, targetResult) = target.call(targetCallData);
                              }
                              revert ExecutionResult(opInfo.preOpGas, paid, data.validAfter, data.validUntil, targetSuccess, targetResult);
                          }
                          // A memory copy of UserOp static fields only.
                          // Excluding: callData, initCode and signature. Replacing paymasterAndData with paymaster.
                          struct MemoryUserOp {
                              address sender;
                              uint256 nonce;
                              uint256 callGasLimit;
                              uint256 verificationGasLimit;
                              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.
                           */
                          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;
                              uint callGasLimit = mUserOp.callGasLimit;
                          unchecked {
                              // handleOps was called with gas limit too low. abort entire bundle.
                              if (gasleft() < callGasLimit + mUserOp.verificationGasLimit + 5000) {
                                  assembly {
                                      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;
                              //note: opIndex is ignored (relevant only if mode==postOpReverted, which is only possible outside of innerHandleOp)
                              return _handlePostOp(0, mode, opInfo, context, actualGas);
                          }
                          }
                          /**
                           * 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.
                           */
                          function getUserOpHash(UserOperation 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.
                           */
                          function _copyUserOpToMemory(UserOperation calldata userOp, MemoryUserOp memory mUserOp) internal pure {
                              mUserOp.sender = userOp.sender;
                              mUserOp.nonce = userOp.nonce;
                              mUserOp.callGasLimit = userOp.callGasLimit;
                              mUserOp.verificationGasLimit = userOp.verificationGasLimit;
                              mUserOp.preVerificationGas = userOp.preVerificationGas;
                              mUserOp.maxFeePerGas = userOp.maxFeePerGas;
                              mUserOp.maxPriorityFeePerGas = userOp.maxPriorityFeePerGas;
                              bytes calldata paymasterAndData = userOp.paymasterAndData;
                              if (paymasterAndData.length > 0) {
                                  require(paymasterAndData.length >= 20, "AA93 invalid paymasterAndData");
                                  mUserOp.paymaster = address(bytes20(paymasterAndData[: 20]));
                              } else {
                                  mUserOp.paymaster = address(0);
                              }
                          }
                          /**
                           * Simulate a call to account.validateUserOp and paymaster.validatePaymasterUserOp.
                           * @dev this method always revert. Successful result is ValidationResult error. other errors are failures.
                           * @dev The node must also verify it doesn't use banned opcodes, and that it doesn't reference storage outside the account's data.
                           * @param userOp the user operation to validate.
                           */
                          function simulateValidation(UserOperation calldata userOp) external {
                              UserOpInfo memory outOpInfo;
                              _simulationOnlyValidations(userOp);
                              (uint256 validationData, uint256 paymasterValidationData) = _validatePrepayment(0, userOp, outOpInfo);
                              StakeInfo memory paymasterInfo = _getStakeInfo(outOpInfo.mUserOp.paymaster);
                              StakeInfo memory senderInfo = _getStakeInfo(outOpInfo.mUserOp.sender);
                              StakeInfo memory factoryInfo;
                              {
                                  bytes calldata initCode = userOp.initCode;
                                  address factory = initCode.length >= 20 ? address(bytes20(initCode[0 : 20])) : address(0);
                                  factoryInfo = _getStakeInfo(factory);
                              }
                              ValidationData memory data = _intersectTimeRange(validationData, paymasterValidationData);
                              address aggregator = data.aggregator;
                              bool sigFailed = aggregator == address(1);
                              ReturnInfo memory returnInfo = ReturnInfo(outOpInfo.preOpGas, outOpInfo.prefund,
                                  sigFailed, data.validAfter, data.validUntil, getMemoryBytesFromOffset(outOpInfo.contextOffset));
                              if (aggregator != address(0) && aggregator != address(1)) {
                                  AggregatorStakeInfo memory aggregatorInfo = AggregatorStakeInfo(aggregator, _getStakeInfo(aggregator));
                                  revert ValidationResultWithAggregation(returnInfo, senderInfo, factoryInfo, paymasterInfo, aggregatorInfo);
                              }
                              revert ValidationResult(returnInfo, senderInfo, factoryInfo, paymasterInfo);
                          }
                          function _getRequiredPrefund(MemoryUserOp memory mUserOp) internal pure returns (uint256 requiredPrefund) {
                          unchecked {
                              //when using a Paymaster, the verificationGasLimit is used also to as a limit for the postOp call.
                              // our security model might call postOp eventually twice
                              uint256 mul = mUserOp.paymaster != address(0) ? 3 : 1;
                              uint256 requiredGas = mUserOp.callGasLimit + mUserOp.verificationGasLimit * mul + mUserOp.preVerificationGas;
                              requiredPrefund = requiredGas * mUserOp.maxFeePerGas;
                          }
                          }
                          // create the sender's contract if needed.
                          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);
                              }
                          }
                          /**
                           * 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 calldata initCode) public {
                              address sender = senderCreator.createSender(initCode);
                              revert SenderAddressResult(sender);
                          }
                          function _simulationOnlyValidations(UserOperation calldata userOp) internal view {
                              // solhint-disable-next-line no-empty-blocks
                              try this._validateSenderAndPaymaster(userOp.initCode, userOp.sender, userOp.paymasterAndData) {}
                              catch Error(string memory revertReason) {
                                  if (bytes(revertReason).length != 0) {
                                      revert FailedOp(0, revertReason);
                                  }
                              }
                          }
                          /**
                          * Called only during simulation.
                          * This function always reverts to prevent warm/cold storage differentiation in simulation vs execution.
                          */
                          function _validateSenderAndPaymaster(bytes calldata initCode, address sender, bytes calldata paymasterAndData) external view {
                              if (initCode.length == 0 && sender.code.length == 0) {
                                  // it would revert anyway. but give a meaningful message
                                  revert("AA20 account not deployed");
                              }
                              if (paymasterAndData.length >= 20) {
                                  address paymaster = address(bytes20(paymasterAndData[0 : 20]));
                                  if (paymaster.code.length == 0) {
                                      // it would revert anyway. but give a meaningful message
                                      revert("AA30 paymaster not deployed");
                                  }
                              }
                              // always revert
                              revert("");
                          }
                          /**
                           * call account.validateUserOp.
                           * revert (with FailedOp) in case validateUserOp reverts, or account didn't send required prefund.
                           * decrement account's deposit if needed
                           */
                          function _validateAccountPrepayment(uint256 opIndex, UserOperation calldata op, UserOpInfo memory opInfo, uint256 requiredPrefund)
                          internal returns (uint256 gasUsedByValidateAccountPrepayment, uint256 validationData) {
                          unchecked {
                              uint256 preGas = gasleft();
                              MemoryUserOp memory mUserOp = opInfo.mUserOp;
                              address sender = mUserOp.sender;
                              _createSenderIfNeeded(opIndex, opInfo, op.initCode);
                              address paymaster = mUserOp.paymaster;
                              numberMarker();
                              uint256 missingAccountFunds = 0;
                              if (paymaster == address(0)) {
                                  uint256 bal = balanceOf(sender);
                                  missingAccountFunds = bal > requiredPrefund ? 0 : requiredPrefund - bal;
                              }
                              try IAccount(sender).validateUserOp{gas : mUserOp.verificationGasLimit}(op, opInfo.userOpHash, missingAccountFunds)
                              returns (uint256 _validationData) {
                                  validationData = _validationData;
                              } catch Error(string memory revertReason) {
                                  revert FailedOp(opIndex, string.concat("AA23 reverted: ", revertReason));
                              } catch {
                                  revert FailedOp(opIndex, "AA23 reverted (or OOG)");
                              }
                              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 = uint112(deposit - requiredPrefund);
                              }
                              gasUsedByValidateAccountPrepayment = preGas - gasleft();
                          }
                          }
                          /**
                           * 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
                           */
                          function _validatePaymasterPrepayment(uint256 opIndex, UserOperation calldata op, UserOpInfo memory opInfo, uint256 requiredPreFund, uint256 gasUsedByValidateAccountPrepayment)
                          internal returns (bytes memory context, uint256 validationData) {
                          unchecked {
                              MemoryUserOp memory mUserOp = opInfo.mUserOp;
                              uint256 verificationGasLimit = mUserOp.verificationGasLimit;
                              require(verificationGasLimit > gasUsedByValidateAccountPrepayment, "AA41 too little verificationGas");
                              uint256 gas = verificationGasLimit - gasUsedByValidateAccountPrepayment;
                              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 = uint112(deposit - requiredPreFund);
                              try IPaymaster(paymaster).validatePaymasterUserOp{gas : gas}(op, opInfo.userOpHash, requiredPreFund) returns (bytes memory _context, uint256 _validationData){
                                  context = _context;
                                  validationData = _validationData;
                              } catch Error(string memory revertReason) {
                                  revert FailedOp(opIndex, string.concat("AA33 reverted: ", revertReason));
                              } catch {
                                  revert FailedOp(opIndex, "AA33 reverted (or OOG)");
                              }
                          }
                          }
                          /**
                           * revert if either account validationData or paymaster validationData is expired
                           */
                          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");
                              }
                          }
                          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).
                           * 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, UserOperation calldata userOp, UserOpInfo memory outOpInfo)
                          private 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 maxGasValues = mUserOp.preVerificationGas | mUserOp.verificationGasLimit | mUserOp.callGasLimit |
                              userOp.maxFeePerGas | userOp.maxPriorityFeePerGas;
                              require(maxGasValues <= type(uint120).max, "AA94 gas values overflow");
                              uint256 gasUsedByValidateAccountPrepayment;
                              (uint256 requiredPreFund) = _getRequiredPrefund(mUserOp);
                              (gasUsedByValidateAccountPrepayment, validationData) = _validateAccountPrepayment(opIndex, userOp, outOpInfo, requiredPreFund);
                              if (!_validateAndUpdateNonce(mUserOp.sender, mUserOp.nonce)) {
                                  revert FailedOp(opIndex, "AA25 invalid account nonce");
                              }
                              //a "marker" where account opcode validation is done and paymaster opcode validation is about to start
                              // (used only by off-chain simulateValidation)
                              numberMarker();
                              bytes memory context;
                              if (mUserOp.paymaster != address(0)) {
                                  (context, paymasterValidationData) = _validatePaymasterPrepayment(opIndex, userOp, outOpInfo, requiredPreFund, gasUsedByValidateAccountPrepayment);
                              }
                          unchecked {
                              uint256 gasUsed = preGas - gasleft();
                              if (userOp.verificationGasLimit < gasUsed) {
                                  revert FailedOp(opIndex, "AA40 over verificationGasLimit");
                              }
                              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 opIndex index in the batch
                           * @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 _handlePostOp(uint256 opIndex, 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) {
                                          IPaymaster(paymaster).postOp{gas : mUserOp.verificationGasLimit}(mode, context, actualGasCost);
                                      } else {
                                          // solhint-disable-next-line no-empty-blocks
                                          try IPaymaster(paymaster).postOp{gas : mUserOp.verificationGasLimit}(mode, context, actualGasCost) {}
                                          catch Error(string memory reason) {
                                              revert FailedOp(opIndex, string.concat("AA50 postOp reverted: ", reason));
                                          }
                                          catch {
                                              revert FailedOp(opIndex, "AA50 postOp revert");
                                          }
                                      }
                                  }
                              }
                              actualGas += preGas - gasleft();
                              actualGasCost = actualGas * gasPrice;
                              if (opInfo.prefund < actualGasCost) {
                                  revert FailedOp(opIndex, "AA51 prefund below actualGasCost");
                              }
                              uint256 refund = opInfo.prefund - actualGasCost;
                              _incrementDeposit(refundAddress, refund);
                              bool success = mode == IPaymaster.PostOpMode.opSucceeded;
                              emit UserOperationEvent(opInfo.userOpHash, mUserOp.sender, mUserOp.paymaster, mUserOp.nonce, 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
                           */
                          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);
                          }
                          }
                          function min(uint256 a, uint256 b) internal pure returns (uint256) {
                              return a < b ? a : b;
                          }
                          function getOffsetOfMemoryBytes(bytes memory data) internal pure returns (uint256 offset) {
                              assembly {offset := data}
                          }
                          function getMemoryBytesFromOffset(uint256 offset) internal pure returns (bytes memory data) {
                              assembly {data := offset}
                          }
                          //place the NUMBER opcode in the code.
                          // this is used as a marker during simulation, as this OP is completely banned from the simulated code of the
                          // account and paymaster.
                          function numberMarker() internal view {
                              assembly {mstore(0, number())}
                          }
                      }
                      // SPDX-License-Identifier: GPL-3.0
                      pragma solidity ^0.8.12;
                      /* solhint-disable no-inline-assembly */
                      /**
                       * returned data from validateUserOp.
                       * validateUserOp returns a uint256, with 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
                          function _parseValidationData(uint 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);
                          }
                      // intersect account and paymaster ranges.
                          function _intersectTimeRange(uint256 validationData, uint256 paymasterValidationData) pure returns (ValidationData memory) {
                              ValidationData memory accountValidationData = _parseValidationData(validationData);
                              ValidationData memory pmValidationData = _parseValidationData(paymasterValidationData);
                              address aggregator = accountValidationData.aggregator;
                              if (aggregator == address(0)) {
                                  aggregator = pmValidationData.aggregator;
                              }
                              uint48 validAfter = accountValidationData.validAfter;
                              uint48 validUntil = accountValidationData.validUntil;
                              uint48 pmValidAfter = pmValidationData.validAfter;
                              uint48 pmValidUntil = pmValidationData.validUntil;
                              if (validAfter < pmValidAfter) validAfter = pmValidAfter;
                              if (validUntil > pmValidUntil) validUntil = pmValidUntil;
                              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 {
                                  let mem := mload(0x40)
                                  let len := data.length
                                  calldatacopy(mem, data.offset, len)
                                  ret := keccak256(mem, len)
                              }
                          }
                      // SPDX-License-Identifier: GPL-3.0
                      pragma solidity ^0.8.12;
                      import "../interfaces/IEntryPoint.sol";
                      /**
                       * nonce management functionality
                       */
                      contract NonceManager is INonceManager {
                          /**
                           * The next valid sequence number for a given nonce key.
                           */
                          mapping(address => mapping(uint192 => uint256)) public nonceSequenceNumber;
                          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()
                           */
                          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.12;
                      /**
                       * 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 {
                                  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.12;
                      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
                          function _getStakeInfo(address addr) internal view returns (StakeInfo memory info) {
                              DepositInfo storage depositInfo = deposits[addr];
                              info.stake = depositInfo.stake;
                              info.unstakeDelaySec = depositInfo.unstakeDelaySec;
                          }
                          /// return the deposit (for gas payment) of the account
                          function balanceOf(address account) public view returns (uint256) {
                              return deposits[account].deposit;
                          }
                          receive() external payable {
                              depositTo(msg.sender);
                          }
                          function _incrementDeposit(address account, uint256 amount) internal {
                              DepositInfo storage info = deposits[account];
                              uint256 newAmount = info.deposit + amount;
                              require(newAmount <= type(uint112).max, "deposit overflow");
                              info.deposit = uint112(newAmount);
                          }
                          /**
                           * add to the deposit of the given account
                           */
                          function depositTo(address account) public payable {
                              _incrementDeposit(account, msg.value);
                              DepositInfo storage info = deposits[account];
                              emit Deposited(account, info.deposit);
                          }
                          /**
                           * 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 = uint112(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.12;
                      import "./UserOperation.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(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
                          external returns (uint256 validationData);
                      }
                      // SPDX-License-Identifier: GPL-3.0
                      pragma solidity ^0.8.12;
                      import "./UserOperation.sol";
                      /**
                       * Aggregated Signatures validator.
                       */
                      interface IAggregator {
                          /**
                           * validate aggregated signature.
                           * revert if the aggregated signature does not match the given list of operations.
                           */
                          function validateSignatures(UserOperation[] calldata userOps, bytes calldata signature) external view;
                          /**
                           * validate signature of a single userOp
                           * This method is should be called by bundler after EntryPoint.simulateValidation() returns (reverts) with ValidationResultWithAggregation
                           * 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(UserOperation 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(UserOperation[] 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.8.12;
                      /* solhint-disable avoid-low-level-calls */
                      /* solhint-disable no-inline-assembly */
                      /* solhint-disable reason-string */
                      import "./UserOperation.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 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.
                           */
                          event SignatureAggregatorChanged(address indexed aggregator);
                          /**
                           * a custom revert error of handleOps, to identify the offending op.
                           *  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.
                           *   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.
                           */
                          error FailedOp(uint256 opIndex, string reason);
                          /**
                           * error case when a signature aggregator fails to verify the aggregated signature it had created.
                           */
                          error SignatureValidationFailed(address aggregator);
                          /**
                           * Successful result from simulateValidation.
                           * @param returnInfo gas and time-range returned values
                           * @param senderInfo stake information about the sender
                           * @param factoryInfo stake information about the factory (if any)
                           * @param paymasterInfo stake information about the paymaster (if any)
                           */
                          error ValidationResult(ReturnInfo returnInfo,
                              StakeInfo senderInfo, StakeInfo factoryInfo, StakeInfo paymasterInfo);
                          /**
                           * Successful result from simulateValidation, if the account returns a signature aggregator
                           * @param returnInfo gas and time-range returned values
                           * @param senderInfo stake information about the sender
                           * @param factoryInfo stake information about the factory (if any)
                           * @param paymasterInfo stake information about the paymaster (if any)
                           * @param aggregatorInfo signature aggregation info (if the account requires signature aggregator)
                           *      bundler MUST use it to verify the signature, or reject the UserOperation
                           */
                          error ValidationResultWithAggregation(ReturnInfo returnInfo,
                              StakeInfo senderInfo, StakeInfo factoryInfo, StakeInfo paymasterInfo,
                              AggregatorStakeInfo aggregatorInfo);
                          /**
                           * return value of getSenderAddress
                           */
                          error SenderAddressResult(address sender);
                          /**
                           * return value of simulateHandleOp
                           */
                          error ExecutionResult(uint256 preOpGas, uint256 paid, uint48 validAfter, uint48 validUntil, bool targetSuccess, bytes targetResult);
                          //UserOps handled, per aggregator
                          struct UserOpsPerAggregator {
                              UserOperation[] userOps;
                              // aggregator address
                              IAggregator aggregator;
                              // aggregated signature
                              bytes signature;
                          }
                          /**
                           * Execute a batch of UserOperation.
                           * 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(UserOperation[] 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.
                           */
                          function getUserOpHash(UserOperation calldata userOp) external view returns (bytes32);
                          /**
                           * Simulate a call to account.validateUserOp and paymaster.validatePaymasterUserOp.
                           * @dev this method always revert. Successful result is ValidationResult error. other errors are failures.
                           * @dev The node must also verify it doesn't use banned opcodes, and that it doesn't reference storage outside the account's data.
                           * @param userOp the user operation to validate.
                           */
                          function simulateValidation(UserOperation calldata userOp) external;
                          /**
                           * gas and return values during simulation
                           * @param preOpGas the gas used for validation (including preValidationGas)
                           * @param prefund the required prefund for this operation
                           * @param sigFailed validateUserOp's (or paymaster's) signature check failed
                           * @param validAfter - first timestamp this UserOp is valid (merging account and paymaster time-range)
                           * @param validUntil - last timestamp this UserOp is valid (merging account and paymaster time-range)
                           * @param paymasterContext returned by validatePaymasterUserOp (to be passed into postOp)
                           */
                          struct ReturnInfo {
                              uint256 preOpGas;
                              uint256 prefund;
                              bool sigFailed;
                              uint48 validAfter;
                              uint48 validUntil;
                              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;
                          /**
                           * simulate full execution of a UserOperation (including both validation and target execution)
                           * this method will always revert with "ExecutionResult".
                           * it performs full validation of the UserOperation, but ignores signature error.
                           * an optional target address is called after the userop succeeds, and its value is returned
                           * (before the entire call is reverted)
                           * Note that in order to collect the the success/failure of the target call, it must be executed
                           * with trace enabled to track the emitted events.
                           * @param op the UserOperation to simulate
                           * @param target if nonzero, a target address to call after userop simulation. If called, the targetSuccess and targetResult
                           *        are set to the return from that call.
                           * @param targetCallData callData to pass to target address
                           */
                          function simulateHandleOp(UserOperation calldata op, address target, bytes calldata targetCallData) external;
                      }
                      // SPDX-License-Identifier: GPL-3.0
                      pragma solidity ^0.8.12;
                      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.8.12;
                      import "./UserOperation.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 {
                              opSucceeded, // user op succeeded
                              opReverted, // user op reverted. still has to pay for gas.
                              postOpReverted //user op succeeded, but caused postOp to revert. Now it's a 2nd call, after user's op was deliberately reverted.
                          }
                          /**
                           * 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,
                           *         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
                           *      Note that the validation code cannot use block.timestamp (or block.number) directly.
                           */
                          function validatePaymasterUserOp(UserOperation 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. still has to pay for gas.
                           *      postOpReverted - user op succeeded, but caused postOp (in mode=opSucceeded) to revert.
                           *                       Now this is the 2nd call, after user's op was deliberately reverted.
                           * @param context - the context value returned by validatePaymasterUserOp
                           * @param actualGasCost - actual gas used so far (without this postOp call).
                           */
                          function postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) external;
                      }
                      // SPDX-License-Identifier: GPL-3.0-only
                      pragma solidity ^0.8.12;
                      /**
                       * 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,staked, stake) fit into one cell (used during handleOps)
                           *    and the rest fit into a 2nd cell.
                           *    112 bit allows for 10^15 eth
                           *    48 bit for full timestamp
                           *    32 bit allows 150 years for unstake delay
                           */
                          struct DepositInfo {
                              uint112 deposit;
                              bool staked;
                              uint112 stake;
                              uint32 unstakeDelaySec;
                              uint48 withdrawTime;
                          }
                          //API struct used by getStakeInfo and simulateValidation
                          struct StakeInfo {
                              uint256 stake;
                              uint256 unstakeDelaySec;
                          }
                          /// @return info - full deposit information of given account
                          function getDepositInfo(address account) external view returns (DepositInfo memory info);
                          /// @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
                           */
                          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.8.12;
                      /* solhint-disable no-inline-assembly */
                      import {calldataKeccak} from "../core/Helpers.sol";
                      /**
                       * 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 callGasLimit the gas limit passed to the callData method call.
                           * @param verificationGasLimit gas used for validateUserOp and validatePaymasterUserOp.
                           * @param preVerificationGas gas not calculated by the handleOps method, but added to the gas paid. Covers batch overhead.
                           * @param maxFeePerGas same as EIP-1559 gas parameter.
                           * @param maxPriorityFeePerGas same as EIP-1559 gas parameter.
                           * @param paymasterAndData if set, this field holds the paymaster address and paymaster-specific 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 UserOperation {
                              address sender;
                              uint256 nonce;
                              bytes initCode;
                              bytes callData;
                              uint256 callGasLimit;
                              uint256 verificationGasLimit;
                              uint256 preVerificationGas;
                              uint256 maxFeePerGas;
                              uint256 maxPriorityFeePerGas;
                              bytes paymasterAndData;
                              bytes signature;
                          }
                      /**
                       * Utility functions helpful when working with UserOperation structs.
                       */
                      library UserOperationLib {
                          function getSender(UserOperation 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.
                          function gasPrice(UserOperation calldata userOp) internal view returns (uint256) {
                          unchecked {
                              uint256 maxFeePerGas = userOp.maxFeePerGas;
                              uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas;
                              if (maxFeePerGas == maxPriorityFeePerGas) {
                                  //legacy mode (for networks that don't support basefee opcode)
                                  return maxFeePerGas;
                              }
                              return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee);
                          }
                          }
                          function pack(UserOperation 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);
                              uint256 callGasLimit = userOp.callGasLimit;
                              uint256 verificationGasLimit = userOp.verificationGasLimit;
                              uint256 preVerificationGas = userOp.preVerificationGas;
                              uint256 maxFeePerGas = userOp.maxFeePerGas;
                              uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas;
                              bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData);
                              return abi.encode(
                                  sender, nonce,
                                  hashInitCode, hashCallData,
                                  callGasLimit, verificationGasLimit, preVerificationGas,
                                  maxFeePerGas, maxPriorityFeePerGas,
                                  hashPaymasterAndData
                              );
                          }
                          function hash(UserOperation calldata userOp) internal pure returns (bytes32) {
                              return keccak256(pack(userOp));
                          }
                          function min(uint256 a, uint256 b) internal pure returns (uint256) {
                              return a < b ? a : b;
                          }
                      }
                      // SPDX-License-Identifier: LGPL-3.0-only
                      pragma solidity >=0.7.5 <0.9.0;
                      // 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 {
                                  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 {
                                  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 {
                                  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 {
                                  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 {
                                  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 2: LightAccount
                      // SPDX-License-Identifier: GPL-3.0
                      pragma solidity ^0.8.21;
                      /* solhint-disable avoid-low-level-calls */
                      /* solhint-disable no-inline-assembly */
                      /* solhint-disable reason-string */
                      import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";
                      import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
                      import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
                      import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
                      import {BaseAccount} from "account-abstraction/core/BaseAccount.sol";
                      import {IEntryPoint} from "account-abstraction/interfaces/IEntryPoint.sol";
                      import {UserOperation} from "account-abstraction/interfaces/UserOperation.sol";
                      import {TokenCallbackHandler} from "account-abstraction/samples/callback/TokenCallbackHandler.sol";
                      import {CustomSlotInitializable} from "./CustomSlotInitializable.sol";
                      /**
                       * @title A simple ERC-4337 compatible smart contract account with a designated owner account
                       * @dev Like eth-infinitism's `SimpleAccount`, but with the following changes:
                       *
                       * 1. Instead of the default storage slots, uses namespaced storage to avoid
                       * clashes when switching implementations.
                       *
                       * 2. Ownership can be transferred via `transferOwnership`, similar to the
                       * behavior of an `Ownable` contract. This is a simple single-step operation,
                       * so care must be taken to ensure that the ownership is being transferred to
                       * the correct address.
                       *
                       * 3. Supports [ERC-1271](https://eips.ethereum.org/EIPS/eip-1271) signature
                       * validation for both validating the signature on user operations and in
                       * exposing its own `isValidSignature` method. This only works when the owner of
                       * `LightAccount` also support ERC-1271.
                       *
                       * ERC-4337's bundler validation rules limit the types of contracts that can be
                       * used as owners to validate user operation signatures. For example, the
                       * contract's `isValidSignature` function may not use any forbidden opcodes
                       * such as `TIMESTAMP` or `NUMBER`, and the contract may not be an ERC-1967
                       * proxy as it accesses a constant implementation slot not associated with
                       * the account, violating storage access rules. This also means that the
                       * owner of a `LightAccount` may not be another `LightAccount` if you want to
                       * send user operations through a bundler.
                       *
                       * 4. Event `SimpleAccountInitialized` renamed to `LightAccountInitialized`.
                       *
                       * 5. Uses custom errors.
                       */
                      contract LightAccount is BaseAccount, TokenCallbackHandler, UUPSUpgradeable, CustomSlotInitializable, IERC1271 {
                          using ECDSA for bytes32;
                          // keccak256(abi.encode(uint256(keccak256("light_account_v1.storage")) - 1)) & ~bytes32(uint256(0xff));
                          bytes32 internal constant _STORAGE_POSITION = 0x691ec1a18226d004c07c9f8e5c4a6ff15a7b38db267cf7e3c945aef8be512200;
                          // keccak256(abi.encode(uint256(keccak256("light_account_v1.initializable")) - 1)) & ~bytes32(uint256(0xff));
                          bytes32 internal constant _INITIALIZABLE_STORAGE_POSITION =
                              0x33e4b41198cc5b8053630ed667ea7c0c4c873f7fc8d9a478b5d7259cec0a4a00;
                          // bytes4(keccak256("isValidSignature(bytes32,bytes)"))
                          bytes4 internal constant _1271_MAGIC_VALUE = 0x1626ba7e;
                          IEntryPoint private immutable _ENTRY_POINT;
                          bytes32 private constant _DOMAIN_SEPARATOR_TYPEHASH =
                              keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
                          bytes32 private constant _LA_MSG_TYPEHASH = keccak256("LightAccountMessage(bytes message)");
                          bytes32 private constant _NAME_HASH = keccak256("LightAccount");
                          bytes32 private constant _VERSION_HASH = keccak256("1");
                          struct LightAccountStorage {
                              address owner;
                          }
                          /**
                           * @notice Emitted when this account is first initialized
                           * @param entryPoint The entry point
                           * @param owner The initial owner
                           */
                          event LightAccountInitialized(IEntryPoint indexed entryPoint, address indexed owner);
                          /**
                           * @notice Emitted when this account's owner changes. Also emitted once at
                           * initialization, with a `previousOwner` of 0.
                           * @param previousOwner The previous owner
                           * @param newOwner The new owner
                           */
                          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                          /**
                           * @dev The length of the array does not match the expected length.
                           */
                          error ArrayLengthMismatch();
                          /**
                           * @dev The new owner is not a valid owner (e.g., `address(0)`, the
                           * account itself, or the current owner).
                           */
                          error InvalidOwner(address owner);
                          /**
                           * @dev The caller is not authorized.
                           */
                          error NotAuthorized(address caller);
                          modifier onlyOwner() {
                              _onlyOwner();
                              _;
                          }
                          constructor(IEntryPoint anEntryPoint) CustomSlotInitializable(_INITIALIZABLE_STORAGE_POSITION) {
                              _ENTRY_POINT = anEntryPoint;
                              _disableInitializers();
                          }
                          // solhint-disable-next-line no-empty-blocks
                          receive() external payable {}
                          /**
                           * @notice Execute a transaction. This may only be called directly by the
                           * owner or by the entry point via a user operation signed by the owner.
                           * @param dest The target of the transaction
                           * @param value The amount of wei sent in the transaction
                           * @param func The transaction's calldata
                           */
                          function execute(address dest, uint256 value, bytes calldata func) external {
                              _requireFromEntryPointOrOwner();
                              _call(dest, value, func);
                          }
                          /**
                           * @notice Execute a sequence of transactions
                           * @param dest An array of the targets for each transaction in the sequence
                           * @param func An array of calldata for each transaction in the sequence.
                           * Must be the same length as dest, with corresponding elements representing
                           * the parameters for each transaction.
                           */
                          function executeBatch(address[] calldata dest, bytes[] calldata func) external {
                              _requireFromEntryPointOrOwner();
                              if (dest.length != func.length) {
                                  revert ArrayLengthMismatch();
                              }
                              uint256 length = dest.length;
                              for (uint256 i = 0; i < length;) {
                                  _call(dest[i], 0, func[i]);
                                  unchecked {
                                      ++i;
                                  }
                              }
                          }
                          /**
                           * @notice Execute a sequence of transactions
                           * @param dest An array of the targets for each transaction in the sequence
                           * @param value An array of value for each transaction in the sequence
                           * @param func An array of calldata for each transaction in the sequence.
                           * Must be the same length as dest, with corresponding elements representing
                           * the parameters for each transaction.
                           */
                          function executeBatch(address[] calldata dest, uint256[] calldata value, bytes[] calldata func) external {
                              _requireFromEntryPointOrOwner();
                              if (dest.length != func.length || dest.length != value.length) {
                                  revert ArrayLengthMismatch();
                              }
                              uint256 length = dest.length;
                              for (uint256 i = 0; i < length;) {
                                  _call(dest[i], value[i], func[i]);
                                  unchecked {
                                      ++i;
                                  }
                              }
                          }
                          /**
                           * @notice Transfers ownership of the contract to a new account (`newOwner`).
                           * Can only be called by the current owner or from the entry point via a
                           * user operation signed by the current owner.
                           * @param newOwner The new owner
                           */
                          function transferOwnership(address newOwner) external virtual onlyOwner {
                              if (newOwner == address(0) || newOwner == address(this)) {
                                  revert InvalidOwner(newOwner);
                              }
                              _transferOwnership(newOwner);
                          }
                          /**
                           * @notice Called once as part of initialization, either during initial deployment or when first upgrading to
                           * this contract.
                           * @dev The _ENTRY_POINT member is immutable, to reduce gas consumption.  To upgrade EntryPoint,
                           * a new implementation of LightAccount must be deployed with the new EntryPoint address, then upgrading
                           * the implementation by calling `upgradeTo()`
                           * @param anOwner The initial owner of the account
                           */
                          function initialize(address anOwner) public virtual initializer {
                              _initialize(anOwner);
                          }
                          /**
                           * @notice Deposit more funds for this account in the entryPoint
                           */
                          function addDeposit() public payable {
                              entryPoint().depositTo{value: msg.value}(address(this));
                          }
                          /**
                           * @notice Withdraw value from the account's deposit
                           * @param withdrawAddress Target to send to
                           * @param amount Amount to withdraw
                           */
                          function withdrawDepositTo(address payable withdrawAddress, uint256 amount) public onlyOwner {
                              entryPoint().withdrawTo(withdrawAddress, amount);
                          }
                          /// @inheritdoc BaseAccount
                          function entryPoint() public view virtual override returns (IEntryPoint) {
                              return _ENTRY_POINT;
                          }
                          /**
                           * @notice Return the current owner of this account
                           * @return The current owner
                           */
                          function owner() public view returns (address) {
                              return _getStorage().owner;
                          }
                          /**
                           * @notice Check current account deposit in the entryPoint
                           * @return The current account deposit
                           */
                          function getDeposit() public view returns (uint256) {
                              return entryPoint().balanceOf(address(this));
                          }
                          /**
                           * @notice Returns the domain separator for this contract, as defined in the EIP-712 standard.
                           * @return bytes32 The domain separator hash.
                           */
                          function domainSeparator() public view returns (bytes32) {
                              return keccak256(
                                  abi.encode(
                                      _DOMAIN_SEPARATOR_TYPEHASH,
                                      _NAME_HASH, // name
                                      _VERSION_HASH, // version
                                      block.chainid, // chainId
                                      address(this) // verifying contract
                                  )
                              );
                          }
                          /**
                           * @notice Returns the pre-image of the message hash
                           * @param message Message that should be encoded.
                           * @return Encoded message.
                           */
                          function encodeMessageData(bytes memory message) public view returns (bytes memory) {
                              bytes32 messageHash = keccak256(abi.encode(_LA_MSG_TYPEHASH, keccak256(message)));
                              return abi.encodePacked("\\x19\\x01", domainSeparator(), messageHash);
                          }
                          /**
                           * @notice Returns hash of a message that can be signed by owners.
                           * @param message Message that should be hashed.
                           * @return Message hash.
                           */
                          function getMessageHash(bytes memory message) public view returns (bytes32) {
                              return keccak256(encodeMessageData(message));
                          }
                          /**
                           * @dev The signature is valid if it is signed by the owner's private key
                           * (if the owner is an EOA) or if it is a valid ERC-1271 signature from the
                           * owner (if the owner is a contract). Note that unlike the signature
                           * validation used in `validateUserOp`, this does **not** wrap the digest in
                           * an "Ethereum Signed Message" envelope before checking the signature in
                           * the EOA-owner case.
                           * @inheritdoc IERC1271
                           */
                          function isValidSignature(bytes32 digest, bytes memory signature) public view override returns (bytes4) {
                              bytes32 messageHash = getMessageHash(abi.encode(digest));
                              if (SignatureChecker.isValidSignatureNow(owner(), messageHash, signature)) {
                                  return _1271_MAGIC_VALUE;
                              }
                              return 0xffffffff;
                          }
                          function _initialize(address anOwner) internal virtual {
                              if (anOwner == address(0)) {
                                  revert InvalidOwner(address(0));
                              }
                              _getStorage().owner = anOwner;
                              emit LightAccountInitialized(_ENTRY_POINT, anOwner);
                              emit OwnershipTransferred(address(0), anOwner);
                          }
                          /**
                           * @dev Transfers ownership of the contract to a new account (`newOwner`).
                           * Internal function without access restriction.
                           */
                          function _transferOwnership(address newOwner) internal virtual {
                              LightAccountStorage storage _storage = _getStorage();
                              address oldOwner = _storage.owner;
                              if (newOwner == oldOwner) {
                                  revert InvalidOwner(newOwner);
                              }
                              _storage.owner = newOwner;
                              emit OwnershipTransferred(oldOwner, newOwner);
                          }
                          /*
                           * Implement template method of BaseAccount.
                           *
                           * Uses a modified version of `SignatureChecker.isValidSignatureNow` in
                           * which the digest is wrapped with an "Ethereum Signed Message" envelope
                           * for the EOA-owner case but not in the ERC-1271 contract-owner case.
                           */
                          function _validateSignature(UserOperation calldata userOp, bytes32 userOpHash)
                              internal
                              virtual
                              override
                              returns (uint256 validationData)
                          {
                              address _owner = owner();
                              bytes32 signedHash = userOpHash.toEthSignedMessageHash();
                              bytes memory signature = userOp.signature;
                              (address recovered, ECDSA.RecoverError error) = signedHash.tryRecover(signature);
                              if (
                                  (error == ECDSA.RecoverError.NoError && recovered == _owner)
                                      || SignatureChecker.isValidERC1271SignatureNow(_owner, userOpHash, signature)
                              ) {
                                  return 0;
                              }
                              return SIG_VALIDATION_FAILED;
                          }
                          function _onlyOwner() internal view {
                              //directly from EOA owner, or through the account itself (which gets redirected through execute())
                              if (msg.sender != address(this) && msg.sender != owner()) {
                                  revert NotAuthorized(msg.sender);
                              }
                          }
                          // Require the function call went through EntryPoint or owner
                          function _requireFromEntryPointOrOwner() internal view {
                              if (msg.sender != address(entryPoint()) && msg.sender != owner()) {
                                  revert NotAuthorized(msg.sender);
                              }
                          }
                          function _call(address target, uint256 value, bytes memory data) internal {
                              (bool success, bytes memory result) = target.call{value: value}(data);
                              if (!success) {
                                  assembly {
                                      revert(add(result, 32), mload(result))
                                  }
                              }
                          }
                          function _authorizeUpgrade(address newImplementation) internal view override {
                              (newImplementation);
                              _onlyOwner();
                          }
                          function _getStorage() internal pure returns (LightAccountStorage storage storageStruct) {
                              bytes32 position = _STORAGE_POSITION;
                              assembly {
                                  storageStruct.slot := position
                              }
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol)
                      pragma solidity ^0.8.0;
                      /**
                       * @dev Interface of the ERC1271 standard signature validation method for
                       * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
                       *
                       * _Available since v4.1._
                       */
                      interface IERC1271 {
                          /**
                           * @dev Should return whether the signature provided is valid for the provided data
                           * @param hash      Hash of the data to be signed
                           * @param signature Signature byte array associated with _data
                           */
                          function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol)
                      pragma solidity ^0.8.0;
                      import "../../interfaces/draft-IERC1822.sol";
                      import "../ERC1967/ERC1967Upgrade.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.
                       *
                       * _Available since v4.1._
                       */
                      abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade {
                          /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
                          address private immutable __self = address(this);
                          /**
                           * @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 ERC1967) 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 ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
                           * fail.
                           */
                          modifier onlyProxy() {
                              require(address(this) != __self, "Function must be called through delegatecall");
                              require(_getImplementation() == __self, "Function must be called through active proxy");
                              _;
                          }
                          /**
                           * @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() {
                              require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
                              _;
                          }
                          /**
                           * @dev Implementation of the ERC1822 {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 override notDelegated returns (bytes32) {
                              return _IMPLEMENTATION_SLOT;
                          }
                          /**
                           * @dev Upgrade the implementation of the proxy to `newImplementation`.
                           *
                           * Calls {_authorizeUpgrade}.
                           *
                           * Emits an {Upgraded} event.
                           *
                           * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
                           */
                          function upgradeTo(address newImplementation) public virtual onlyProxy {
                              _authorizeUpgrade(newImplementation);
                              _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
                          }
                          /**
                           * @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, true);
                          }
                          /**
                           * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
                           * {upgradeTo} and {upgradeToAndCall}.
                           *
                           * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
                           *
                           * ```solidity
                           * function _authorizeUpgrade(address) internal override onlyOwner {}
                           * ```
                           */
                          function _authorizeUpgrade(address newImplementation) internal virtual;
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)
                      pragma solidity ^0.8.0;
                      import "../Strings.sol";
                      /**
                       * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
                       *
                       * These functions can be used to verify that a message was signed by the holder
                       * of the private keys of a given address.
                       */
                      library ECDSA {
                          enum RecoverError {
                              NoError,
                              InvalidSignature,
                              InvalidSignatureLength,
                              InvalidSignatureS,
                              InvalidSignatureV // Deprecated in v4.8
                          }
                          function _throwError(RecoverError error) private pure {
                              if (error == RecoverError.NoError) {
                                  return; // no error: do nothing
                              } else if (error == RecoverError.InvalidSignature) {
                                  revert("ECDSA: invalid signature");
                              } else if (error == RecoverError.InvalidSignatureLength) {
                                  revert("ECDSA: invalid signature length");
                              } else if (error == RecoverError.InvalidSignatureS) {
                                  revert("ECDSA: invalid signature 's' value");
                              }
                          }
                          /**
                           * @dev Returns the address that signed a hashed message (`hash`) with
                           * `signature` or error string. This address can then be used for verification purposes.
                           *
                           * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
                           * this function rejects them by requiring the `s` value to be in the lower
                           * half order, and the `v` value to be either 27 or 28.
                           *
                           * IMPORTANT: `hash` _must_ be the result of a hash operation for the
                           * verification to be secure: it is possible to craft signatures that
                           * recover to arbitrary addresses for non-hashed data. A safe way to ensure
                           * this is by receiving a hash of the original message (which may otherwise
                           * be too long), and then calling {toEthSignedMessageHash} on it.
                           *
                           * Documentation for signature generation:
                           * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
                           * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
                           *
                           * _Available since v4.3._
                           */
                          function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
                              if (signature.length == 65) {
                                  bytes32 r;
                                  bytes32 s;
                                  uint8 v;
                                  // ecrecover takes the signature parameters, and the only way to get them
                                  // currently is to use assembly.
                                  /// @solidity memory-safe-assembly
                                  assembly {
                                      r := mload(add(signature, 0x20))
                                      s := mload(add(signature, 0x40))
                                      v := byte(0, mload(add(signature, 0x60)))
                                  }
                                  return tryRecover(hash, v, r, s);
                              } else {
                                  return (address(0), RecoverError.InvalidSignatureLength);
                              }
                          }
                          /**
                           * @dev Returns the address that signed a hashed message (`hash`) with
                           * `signature`. This address can then be used for verification purposes.
                           *
                           * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
                           * this function rejects them by requiring the `s` value to be in the lower
                           * half order, and the `v` value to be either 27 or 28.
                           *
                           * IMPORTANT: `hash` _must_ be the result of a hash operation for the
                           * verification to be secure: it is possible to craft signatures that
                           * recover to arbitrary addresses for non-hashed data. A safe way to ensure
                           * this is by receiving a hash of the original message (which may otherwise
                           * be too long), and then calling {toEthSignedMessageHash} on it.
                           */
                          function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
                              (address recovered, RecoverError error) = tryRecover(hash, signature);
                              _throwError(error);
                              return recovered;
                          }
                          /**
                           * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
                           *
                           * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
                           *
                           * _Available since v4.3._
                           */
                          function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
                              bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
                              uint8 v = uint8((uint256(vs) >> 255) + 27);
                              return tryRecover(hash, v, r, s);
                          }
                          /**
                           * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
                           *
                           * _Available since v4.2._
                           */
                          function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
                              (address recovered, RecoverError error) = tryRecover(hash, r, vs);
                              _throwError(error);
                              return recovered;
                          }
                          /**
                           * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
                           * `r` and `s` signature fields separately.
                           *
                           * _Available since v4.3._
                           */
                          function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
                              // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
                              // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
                              // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
                              // signatures from current libraries generate a unique signature with an s-value in the lower half order.
                              //
                              // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
                              // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
                              // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
                              // these malleable signatures as well.
                              if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
                                  return (address(0), RecoverError.InvalidSignatureS);
                              }
                              // If the signature is valid (and not malleable), return the signer address
                              address signer = ecrecover(hash, v, r, s);
                              if (signer == address(0)) {
                                  return (address(0), RecoverError.InvalidSignature);
                              }
                              return (signer, RecoverError.NoError);
                          }
                          /**
                           * @dev Overload of {ECDSA-recover} that receives the `v`,
                           * `r` and `s` signature fields separately.
                           */
                          function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
                              (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
                              _throwError(error);
                              return recovered;
                          }
                          /**
                           * @dev Returns an Ethereum Signed Message, created from a `hash`. This
                           * produces hash corresponding to the one signed with the
                           * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
                           * JSON-RPC method as part of EIP-191.
                           *
                           * See {recover}.
                           */
                          function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
                              // 32 is the length in bytes of hash,
                              // enforced by the type signature above
                              /// @solidity memory-safe-assembly
                              assembly {
                                  mstore(0x00, "\\x19Ethereum Signed Message:\
                      32")
                                  mstore(0x1c, hash)
                                  message := keccak256(0x00, 0x3c)
                              }
                          }
                          /**
                           * @dev Returns an Ethereum Signed Message, created from `s`. This
                           * produces hash corresponding to the one signed with the
                           * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
                           * JSON-RPC method as part of EIP-191.
                           *
                           * See {recover}.
                           */
                          function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
                              return keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\
                      ", Strings.toString(s.length), s));
                          }
                          /**
                           * @dev Returns an Ethereum Signed Typed Data, created from a
                           * `domainSeparator` and a `structHash`. This produces hash corresponding
                           * to the one signed with the
                           * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
                           * JSON-RPC method as part of EIP-712.
                           *
                           * See {recover}.
                           */
                          function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
                              /// @solidity memory-safe-assembly
                              assembly {
                                  let ptr := mload(0x40)
                                  mstore(ptr, "\\x19\\x01")
                                  mstore(add(ptr, 0x02), domainSeparator)
                                  mstore(add(ptr, 0x22), structHash)
                                  data := keccak256(ptr, 0x42)
                              }
                          }
                          /**
                           * @dev Returns an Ethereum Signed Data with intended validator, created from a
                           * `validator` and `data` according to the version 0 of EIP-191.
                           *
                           * See {recover}.
                           */
                          function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
                              return keccak256(abi.encodePacked("\\x19\\x00", validator, data));
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/SignatureChecker.sol)
                      pragma solidity ^0.8.0;
                      import "./ECDSA.sol";
                      import "../../interfaces/IERC1271.sol";
                      /**
                       * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
                       * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
                       * Argent and Gnosis Safe.
                       *
                       * _Available since v4.1._
                       */
                      library SignatureChecker {
                          /**
                           * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
                           * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
                           *
                           * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
                           * change through time. It could return true at block N and false at block N+1 (or the opposite).
                           */
                          function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
                              (address recovered, ECDSA.RecoverError error) = ECDSA.tryRecover(hash, signature);
                              return
                                  (error == ECDSA.RecoverError.NoError && recovered == signer) ||
                                  isValidERC1271SignatureNow(signer, hash, signature);
                          }
                          /**
                           * @dev Checks if a signature is valid for a given signer and data hash. The signature is validated
                           * against the signer smart contract using ERC1271.
                           *
                           * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
                           * change through time. It could return true at block N and false at block N+1 (or the opposite).
                           */
                          function isValidERC1271SignatureNow(
                              address signer,
                              bytes32 hash,
                              bytes memory signature
                          ) internal view returns (bool) {
                              (bool success, bytes memory result) = signer.staticcall(
                                  abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature)
                              );
                              return (success &&
                                  result.length >= 32 &&
                                  abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
                          }
                      }
                      // SPDX-License-Identifier: GPL-3.0
                      pragma solidity ^0.8.12;
                      /* solhint-disable avoid-low-level-calls */
                      /* solhint-disable no-empty-blocks */
                      import "../interfaces/IAccount.sol";
                      import "../interfaces/IEntryPoint.sol";
                      import "./Helpers.sol";
                      /**
                       * Basic account implementation.
                       * this contract provides the basic logic for implementing the IAccount interface  - validateUserOp
                       * specific account implementation should inherit it and provide the account-specific logic
                       */
                      abstract contract BaseAccount is IAccount {
                          using UserOperationLib for UserOperation;
                          //return value in case of signature failure, with no time-range.
                          // equivalent to _packValidationData(true,0,0);
                          uint256 constant internal SIG_VALIDATION_FAILED = 1;
                          /**
                           * Return the account nonce.
                           * This method returns the next sequential nonce.
                           * For a nonce of a specific key, use `entrypoint.getNonce(account, key)`
                           */
                          function getNonce() public view virtual returns (uint256) {
                              return entryPoint().getNonce(address(this), 0);
                          }
                          /**
                           * return the entryPoint used by this account.
                           * subclass should return the current entryPoint used by this account.
                           */
                          function entryPoint() public view virtual returns (IEntryPoint);
                          /**
                           * Validate user's signature and nonce.
                           * subclass doesn't need to override this method. Instead, it should override the specific internal validation methods.
                           */
                          function validateUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
                          external override virtual returns (uint256 validationData) {
                              _requireFromEntryPoint();
                              validationData = _validateSignature(userOp, userOpHash);
                              _validateNonce(userOp.nonce);
                              _payPrefund(missingAccountFunds);
                          }
                          /**
                           * ensure the request comes from the known entrypoint.
                           */
                          function _requireFromEntryPoint() internal virtual view {
                              require(msg.sender == address(entryPoint()), "account: not from EntryPoint");
                          }
                          /**
                           * validate the signature is valid for this message.
                           * @param userOp validate the userOp.signature field
                           * @param userOpHash convenient field: the hash of the request, to check the signature against
                           *          (also hashes the entrypoint and chain id)
                           * @return validationData signature and time-range of this operation
                           *      <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 the 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 _validateSignature(UserOperation calldata userOp, bytes32 userOpHash)
                          internal virtual returns (uint256 validationData);
                          /**
                           * Validate the nonce of the UserOperation.
                           * This method may validate the nonce requirement of this account.
                           * e.g.
                           * To limit the nonce to use sequenced UserOps only (no "out of order" UserOps):
                           *      `require(nonce < type(uint64).max)`
                           * For a hypothetical account that *requires* the nonce to be out-of-order:
                           *      `require(nonce & type(uint64).max == 0)`
                           *
                           * The actual nonce uniqueness is managed by the EntryPoint, and thus no other
                           * action is needed by the account itself.
                           *
                           * @param nonce to validate
                           *
                           * solhint-disable-next-line no-empty-blocks
                           */
                          function _validateNonce(uint256 nonce) internal view virtual {
                          }
                          /**
                           * sends to the entrypoint (msg.sender) the missing funds for this transaction.
                           * subclass MAY override this method for better funds management
                           * (e.g. send to the entryPoint more than the minimum required, so that in future transactions
                           * it will not be required to send again)
                           * @param missingAccountFunds the minimum value this method should send the entrypoint.
                           *  this value MAY be zero, in case there is enough deposit, or the userOp has a paymaster.
                           */
                          function _payPrefund(uint256 missingAccountFunds) internal virtual {
                              if (missingAccountFunds != 0) {
                                  (bool success,) = payable(msg.sender).call{value : missingAccountFunds, gas : type(uint256).max}("");
                                  (success);
                                  //ignore failure (its EntryPoint's job to verify, not account.)
                              }
                          }
                      }
                      /**
                       ** Account-Abstraction (EIP-4337) singleton EntryPoint implementation.
                       ** Only one instance required on each chain.
                       **/
                      // SPDX-License-Identifier: GPL-3.0
                      pragma solidity ^0.8.12;
                      /* solhint-disable avoid-low-level-calls */
                      /* solhint-disable no-inline-assembly */
                      /* solhint-disable reason-string */
                      import "./UserOperation.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 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.
                           */
                          event SignatureAggregatorChanged(address indexed aggregator);
                          /**
                           * a custom revert error of handleOps, to identify the offending op.
                           *  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.
                           *   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.
                           */
                          error FailedOp(uint256 opIndex, string reason);
                          /**
                           * error case when a signature aggregator fails to verify the aggregated signature it had created.
                           */
                          error SignatureValidationFailed(address aggregator);
                          /**
                           * Successful result from simulateValidation.
                           * @param returnInfo gas and time-range returned values
                           * @param senderInfo stake information about the sender
                           * @param factoryInfo stake information about the factory (if any)
                           * @param paymasterInfo stake information about the paymaster (if any)
                           */
                          error ValidationResult(ReturnInfo returnInfo,
                              StakeInfo senderInfo, StakeInfo factoryInfo, StakeInfo paymasterInfo);
                          /**
                           * Successful result from simulateValidation, if the account returns a signature aggregator
                           * @param returnInfo gas and time-range returned values
                           * @param senderInfo stake information about the sender
                           * @param factoryInfo stake information about the factory (if any)
                           * @param paymasterInfo stake information about the paymaster (if any)
                           * @param aggregatorInfo signature aggregation info (if the account requires signature aggregator)
                           *      bundler MUST use it to verify the signature, or reject the UserOperation
                           */
                          error ValidationResultWithAggregation(ReturnInfo returnInfo,
                              StakeInfo senderInfo, StakeInfo factoryInfo, StakeInfo paymasterInfo,
                              AggregatorStakeInfo aggregatorInfo);
                          /**
                           * return value of getSenderAddress
                           */
                          error SenderAddressResult(address sender);
                          /**
                           * return value of simulateHandleOp
                           */
                          error ExecutionResult(uint256 preOpGas, uint256 paid, uint48 validAfter, uint48 validUntil, bool targetSuccess, bytes targetResult);
                          //UserOps handled, per aggregator
                          struct UserOpsPerAggregator {
                              UserOperation[] userOps;
                              // aggregator address
                              IAggregator aggregator;
                              // aggregated signature
                              bytes signature;
                          }
                          /**
                           * Execute a batch of UserOperation.
                           * 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(UserOperation[] 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.
                           */
                          function getUserOpHash(UserOperation calldata userOp) external view returns (bytes32);
                          /**
                           * Simulate a call to account.validateUserOp and paymaster.validatePaymasterUserOp.
                           * @dev this method always revert. Successful result is ValidationResult error. other errors are failures.
                           * @dev The node must also verify it doesn't use banned opcodes, and that it doesn't reference storage outside the account's data.
                           * @param userOp the user operation to validate.
                           */
                          function simulateValidation(UserOperation calldata userOp) external;
                          /**
                           * gas and return values during simulation
                           * @param preOpGas the gas used for validation (including preValidationGas)
                           * @param prefund the required prefund for this operation
                           * @param sigFailed validateUserOp's (or paymaster's) signature check failed
                           * @param validAfter - first timestamp this UserOp is valid (merging account and paymaster time-range)
                           * @param validUntil - last timestamp this UserOp is valid (merging account and paymaster time-range)
                           * @param paymasterContext returned by validatePaymasterUserOp (to be passed into postOp)
                           */
                          struct ReturnInfo {
                              uint256 preOpGas;
                              uint256 prefund;
                              bool sigFailed;
                              uint48 validAfter;
                              uint48 validUntil;
                              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;
                          /**
                           * simulate full execution of a UserOperation (including both validation and target execution)
                           * this method will always revert with "ExecutionResult".
                           * it performs full validation of the UserOperation, but ignores signature error.
                           * an optional target address is called after the userop succeeds, and its value is returned
                           * (before the entire call is reverted)
                           * Note that in order to collect the the success/failure of the target call, it must be executed
                           * with trace enabled to track the emitted events.
                           * @param op the UserOperation to simulate
                           * @param target if nonzero, a target address to call after userop simulation. If called, the targetSuccess and targetResult
                           *        are set to the return from that call.
                           * @param targetCallData callData to pass to target address
                           */
                          function simulateHandleOp(UserOperation calldata op, address target, bytes calldata targetCallData) external;
                      }
                      // SPDX-License-Identifier: GPL-3.0
                      pragma solidity ^0.8.12;
                      /* solhint-disable no-inline-assembly */
                      import {calldataKeccak} from "../core/Helpers.sol";
                      /**
                       * 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 callGasLimit the gas limit passed to the callData method call.
                           * @param verificationGasLimit gas used for validateUserOp and validatePaymasterUserOp.
                           * @param preVerificationGas gas not calculated by the handleOps method, but added to the gas paid. Covers batch overhead.
                           * @param maxFeePerGas same as EIP-1559 gas parameter.
                           * @param maxPriorityFeePerGas same as EIP-1559 gas parameter.
                           * @param paymasterAndData if set, this field holds the paymaster address and paymaster-specific 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 UserOperation {
                              address sender;
                              uint256 nonce;
                              bytes initCode;
                              bytes callData;
                              uint256 callGasLimit;
                              uint256 verificationGasLimit;
                              uint256 preVerificationGas;
                              uint256 maxFeePerGas;
                              uint256 maxPriorityFeePerGas;
                              bytes paymasterAndData;
                              bytes signature;
                          }
                      /**
                       * Utility functions helpful when working with UserOperation structs.
                       */
                      library UserOperationLib {
                          function getSender(UserOperation 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.
                          function gasPrice(UserOperation calldata userOp) internal view returns (uint256) {
                          unchecked {
                              uint256 maxFeePerGas = userOp.maxFeePerGas;
                              uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas;
                              if (maxFeePerGas == maxPriorityFeePerGas) {
                                  //legacy mode (for networks that don't support basefee opcode)
                                  return maxFeePerGas;
                              }
                              return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee);
                          }
                          }
                          function pack(UserOperation 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);
                              uint256 callGasLimit = userOp.callGasLimit;
                              uint256 verificationGasLimit = userOp.verificationGasLimit;
                              uint256 preVerificationGas = userOp.preVerificationGas;
                              uint256 maxFeePerGas = userOp.maxFeePerGas;
                              uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas;
                              bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData);
                              return abi.encode(
                                  sender, nonce,
                                  hashInitCode, hashCallData,
                                  callGasLimit, verificationGasLimit, preVerificationGas,
                                  maxFeePerGas, maxPriorityFeePerGas,
                                  hashPaymasterAndData
                              );
                          }
                          function hash(UserOperation calldata userOp) internal pure returns (bytes32) {
                              return keccak256(pack(userOp));
                          }
                          function min(uint256 a, uint256 b) internal pure returns (uint256) {
                              return a < b ? a : b;
                          }
                      }
                      // SPDX-License-Identifier: GPL-3.0
                      pragma solidity ^0.8.12;
                      /* solhint-disable no-empty-blocks */
                      import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
                      import "@openzeppelin/contracts/token/ERC777/IERC777Recipient.sol";
                      import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
                      import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
                      /**
                       * Token callback handler.
                       *   Handles supported tokens' callbacks, allowing account receiving these tokens.
                       */
                      contract TokenCallbackHandler is IERC777Recipient, IERC721Receiver, IERC1155Receiver {
                          function tokensReceived(
                              address,
                              address,
                              address,
                              uint256,
                              bytes calldata,
                              bytes calldata
                          ) external pure override {
                          }
                          function onERC721Received(
                              address,
                              address,
                              uint256,
                              bytes calldata
                          ) external pure override returns (bytes4) {
                              return IERC721Receiver.onERC721Received.selector;
                          }
                          function onERC1155Received(
                              address,
                              address,
                              uint256,
                              uint256,
                              bytes calldata
                          ) external pure override returns (bytes4) {
                              return IERC1155Receiver.onERC1155Received.selector;
                          }
                          function onERC1155BatchReceived(
                              address,
                              address,
                              uint256[] calldata,
                              uint256[] calldata,
                              bytes calldata
                          ) external pure override returns (bytes4) {
                              return IERC1155Receiver.onERC1155BatchReceived.selector;
                          }
                          function supportsInterface(bytes4 interfaceId) external view virtual override returns (bool) {
                              return
                                  interfaceId == type(IERC721Receiver).interfaceId ||
                                  interfaceId == type(IERC1155Receiver).interfaceId ||
                                  interfaceId == type(IERC165).interfaceId;
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
                      pragma solidity ^0.8.21;
                      /**
                       * @dev Identical to OpenZeppelin's `Initializable`, except that its state variables are kept at a custom storage slot
                       * instead of at the start of storage.
                       *
                       * 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 CustomSlotInitializable {
                          bytes32 internal immutable _storagePosition;
                          struct CustomSlotInitializableStorage {
                              /**
                               * @dev Indicates that the contract has been initialized.
                               * @custom:oz-retyped-from bool
                               */
                              uint64 initialized;
                              /**
                               * @dev Indicates that the contract is in the process of being initialized.
                               */
                              bool initializing;
                          }
                          /**
                           * @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);
                          constructor(bytes32 storagePosition) {
                              _storagePosition = storagePosition;
                          }
                          /**
                           * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
                           * `onlyInitializing` functions can be used to initialize parent contracts.
                           *
                           * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
                           * constructor.
                           *
                           * Emits an {Initialized} event.
                           */
                          modifier initializer() {
                              CustomSlotInitializableStorage storage _storage = _getInitializableStorage();
                              // Cache values to avoid duplicated sloads
                              bool isTopLevelCall = !_storage.initializing;
                              uint64 initialized = _storage.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();
                              }
                              _storage.initialized = 1;
                              if (isTopLevelCall) {
                                  _storage.initializing = true;
                              }
                              _;
                              if (isTopLevelCall) {
                                  _storage.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 type(uint64).max will prevent any future reinitialization.
                           *
                           * Emits an {Initialized} event.
                           */
                          modifier reinitializer(uint64 version) {
                              CustomSlotInitializableStorage storage _storage = _getInitializableStorage();
                              if (_storage.initializing || _storage.initialized >= version) {
                                  revert InvalidInitialization();
                              }
                              _storage.initialized = version;
                              _storage.initializing = true;
                              _;
                              _storage.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() {
                              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 {
                              CustomSlotInitializableStorage storage _storage = _getInitializableStorage();
                              if (_storage.initializing) {
                                  revert InvalidInitialization();
                              }
                              if (_storage.initialized != type(uint64).max) {
                                  _storage.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;
                          }
                          function _getInitializableStorage() private view returns (CustomSlotInitializableStorage storage _storage) {
                              bytes32 position = _storagePosition;
                              assembly {
                                  _storage.slot := position
                              }
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
                      pragma solidity ^0.8.0;
                      /**
                       * @dev ERC1822: 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 v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
                      pragma solidity ^0.8.2;
                      import "../beacon/IBeacon.sol";
                      import "../../interfaces/IERC1967.sol";
                      import "../../interfaces/draft-IERC1822.sol";
                      import "../../utils/Address.sol";
                      import "../../utils/StorageSlot.sol";
                      /**
                       * @dev This abstract contract provides getters and event emitting update functions for
                       * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
                       *
                       * _Available since v4.1._
                       */
                      abstract contract ERC1967Upgrade is IERC1967 {
                          // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                          bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                          /**
                           * @dev Storage slot with the address of the current implementation.
                           * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                           * validated in the constructor.
                           */
                          bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                          /**
                           * @dev Returns the current implementation address.
                           */
                          function _getImplementation() internal view returns (address) {
                              return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                          }
                          /**
                           * @dev Stores a new address in the EIP1967 implementation slot.
                           */
                          function _setImplementation(address newImplementation) private {
                              require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                              StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                          }
                          /**
                           * @dev Perform implementation upgrade
                           *
                           * Emits an {Upgraded} event.
                           */
                          function _upgradeTo(address newImplementation) internal {
                              _setImplementation(newImplementation);
                              emit Upgraded(newImplementation);
                          }
                          /**
                           * @dev Perform implementation upgrade with additional setup call.
                           *
                           * Emits an {Upgraded} event.
                           */
                          function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
                              _upgradeTo(newImplementation);
                              if (data.length > 0 || forceCall) {
                                  Address.functionDelegateCall(newImplementation, data);
                              }
                          }
                          /**
                           * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                           *
                           * Emits an {Upgraded} event.
                           */
                          function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
                              // Upgrades from old implementations will perform a rollback test. This test requires the new
                              // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
                              // this special case will break upgrade paths from old UUPS implementation to new ones.
                              if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
                                  _setImplementation(newImplementation);
                              } else {
                                  try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                                      require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
                                  } catch {
                                      revert("ERC1967Upgrade: new implementation is not UUPS");
                                  }
                                  _upgradeToAndCall(newImplementation, data, forceCall);
                              }
                          }
                          /**
                           * @dev Storage slot with the admin of the contract.
                           * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                           * validated in the constructor.
                           */
                          bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                          /**
                           * @dev Returns the current admin.
                           */
                          function _getAdmin() internal view returns (address) {
                              return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
                          }
                          /**
                           * @dev Stores a new address in the EIP1967 admin slot.
                           */
                          function _setAdmin(address newAdmin) private {
                              require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                              StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                          }
                          /**
                           * @dev Changes the admin of the proxy.
                           *
                           * Emits an {AdminChanged} event.
                           */
                          function _changeAdmin(address newAdmin) internal {
                              emit AdminChanged(_getAdmin(), newAdmin);
                              _setAdmin(newAdmin);
                          }
                          /**
                           * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                           * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                           */
                          bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                          /**
                           * @dev Returns the current beacon.
                           */
                          function _getBeacon() internal view returns (address) {
                              return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
                          }
                          /**
                           * @dev Stores a new beacon in the EIP1967 beacon slot.
                           */
                          function _setBeacon(address newBeacon) private {
                              require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
                              require(
                                  Address.isContract(IBeacon(newBeacon).implementation()),
                                  "ERC1967: beacon implementation is not a contract"
                              );
                              StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                          }
                          /**
                           * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                           * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                           *
                           * Emits a {BeaconUpgraded} event.
                           */
                          function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
                              _setBeacon(newBeacon);
                              emit BeaconUpgraded(newBeacon);
                              if (data.length > 0 || forceCall) {
                                  Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                              }
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
                      pragma solidity ^0.8.0;
                      import "./math/Math.sol";
                      import "./math/SignedMath.sol";
                      /**
                       * @dev String operations.
                       */
                      library Strings {
                          bytes16 private constant _SYMBOLS = "0123456789abcdef";
                          uint8 private constant _ADDRESS_LENGTH = 20;
                          /**
                           * @dev Converts a `uint256` to its ASCII `string` decimal representation.
                           */
                          function toString(uint256 value) internal pure returns (string memory) {
                              unchecked {
                                  uint256 length = Math.log10(value) + 1;
                                  string memory buffer = new string(length);
                                  uint256 ptr;
                                  /// @solidity memory-safe-assembly
                                  assembly {
                                      ptr := add(buffer, add(32, length))
                                  }
                                  while (true) {
                                      ptr--;
                                      /// @solidity memory-safe-assembly
                                      assembly {
                                          mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                                      }
                                      value /= 10;
                                      if (value == 0) break;
                                  }
                                  return buffer;
                              }
                          }
                          /**
                           * @dev Converts a `int256` to its ASCII `string` decimal representation.
                           */
                          function toString(int256 value) internal pure returns (string memory) {
                              return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
                          }
                          /**
                           * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
                           */
                          function toHexString(uint256 value) internal pure returns (string memory) {
                              unchecked {
                                  return toHexString(value, Math.log256(value) + 1);
                              }
                          }
                          /**
                           * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
                           */
                          function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
                              bytes memory buffer = new bytes(2 * length + 2);
                              buffer[0] = "0";
                              buffer[1] = "x";
                              for (uint256 i = 2 * length + 1; i > 1; --i) {
                                  buffer[i] = _SYMBOLS[value & 0xf];
                                  value >>= 4;
                              }
                              require(value == 0, "Strings: hex length insufficient");
                              return string(buffer);
                          }
                          /**
                           * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
                           */
                          function toHexString(address addr) internal pure returns (string memory) {
                              return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
                          }
                          /**
                           * @dev Returns true if the two strings are equal.
                           */
                          function equal(string memory a, string memory b) internal pure returns (bool) {
                              return keccak256(bytes(a)) == keccak256(bytes(b));
                          }
                      }
                      // SPDX-License-Identifier: GPL-3.0
                      pragma solidity ^0.8.12;
                      import "./UserOperation.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(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
                          external returns (uint256 validationData);
                      }
                      // SPDX-License-Identifier: GPL-3.0
                      pragma solidity ^0.8.12;
                      /* solhint-disable no-inline-assembly */
                      /**
                       * returned data from validateUserOp.
                       * validateUserOp returns a uint256, with 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
                          function _parseValidationData(uint 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);
                          }
                      // intersect account and paymaster ranges.
                          function _intersectTimeRange(uint256 validationData, uint256 paymasterValidationData) pure returns (ValidationData memory) {
                              ValidationData memory accountValidationData = _parseValidationData(validationData);
                              ValidationData memory pmValidationData = _parseValidationData(paymasterValidationData);
                              address aggregator = accountValidationData.aggregator;
                              if (aggregator == address(0)) {
                                  aggregator = pmValidationData.aggregator;
                              }
                              uint48 validAfter = accountValidationData.validAfter;
                              uint48 validUntil = accountValidationData.validUntil;
                              uint48 pmValidAfter = pmValidationData.validAfter;
                              uint48 pmValidUntil = pmValidationData.validUntil;
                              if (validAfter < pmValidAfter) validAfter = pmValidAfter;
                              if (validUntil > pmValidUntil) validUntil = pmValidUntil;
                              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 {
                                  let mem := mload(0x40)
                                  let len := data.length
                                  calldatacopy(mem, data.offset, len)
                                  ret := keccak256(mem, len)
                              }
                          }
                      // SPDX-License-Identifier: GPL-3.0-only
                      pragma solidity ^0.8.12;
                      /**
                       * 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,staked, stake) fit into one cell (used during handleOps)
                           *    and the rest fit into a 2nd cell.
                           *    112 bit allows for 10^15 eth
                           *    48 bit for full timestamp
                           *    32 bit allows 150 years for unstake delay
                           */
                          struct DepositInfo {
                              uint112 deposit;
                              bool staked;
                              uint112 stake;
                              uint32 unstakeDelaySec;
                              uint48 withdrawTime;
                          }
                          //API struct used by getStakeInfo and simulateValidation
                          struct StakeInfo {
                              uint256 stake;
                              uint256 unstakeDelaySec;
                          }
                          /// @return info - full deposit information of given account
                          function getDepositInfo(address account) external view returns (DepositInfo memory info);
                          /// @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
                           */
                          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.8.12;
                      import "./UserOperation.sol";
                      /**
                       * Aggregated Signatures validator.
                       */
                      interface IAggregator {
                          /**
                           * validate aggregated signature.
                           * revert if the aggregated signature does not match the given list of operations.
                           */
                          function validateSignatures(UserOperation[] calldata userOps, bytes calldata signature) external view;
                          /**
                           * validate signature of a single userOp
                           * This method is should be called by bundler after EntryPoint.simulateValidation() returns (reverts) with ValidationResultWithAggregation
                           * 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(UserOperation 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(UserOperation[] calldata userOps) external view returns (bytes memory aggregatedSignature);
                      }
                      // SPDX-License-Identifier: GPL-3.0
                      pragma solidity ^0.8.12;
                      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: MIT
                      // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
                      pragma solidity ^0.8.0;
                      /**
                       * @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 v4.4.1 (token/ERC777/IERC777Recipient.sol)
                      pragma solidity ^0.8.0;
                      /**
                       * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP.
                       *
                       * Accounts can be notified of {IERC777} tokens being sent to them by having a
                       * contract implement this interface (contract holders can be their own
                       * implementer) and registering it on the
                       * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].
                       *
                       * See {IERC1820Registry} and {ERC1820Implementer}.
                       */
                      interface IERC777Recipient {
                          /**
                           * @dev Called by an {IERC777} token contract whenever tokens are being
                           * moved or created into a registered account (`to`). The type of operation
                           * is conveyed by `from` being the zero address or not.
                           *
                           * This call occurs _after_ the token contract's state is updated, so
                           * {IERC777-balanceOf}, etc., can be used to query the post-operation state.
                           *
                           * This function may revert to prevent the operation from being executed.
                           */
                          function tokensReceived(
                              address operator,
                              address from,
                              address to,
                              uint256 amount,
                              bytes calldata userData,
                              bytes calldata operatorData
                          ) external;
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
                      pragma solidity ^0.8.0;
                      /**
                       * @title ERC721 token receiver interface
                       * @dev Interface for any contract that wants to support safeTransfers
                       * from ERC721 asset contracts.
                       */
                      interface IERC721Receiver {
                          /**
                           * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
                           * by `operator` from `from`, this function is called.
                           *
                           * It must return its Solidity selector to confirm the token transfer.
                           * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
                           *
                           * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
                           */
                          function onERC721Received(
                              address operator,
                              address from,
                              uint256 tokenId,
                              bytes calldata data
                          ) external returns (bytes4);
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)
                      pragma solidity ^0.8.0;
                      import "../../utils/introspection/IERC165.sol";
                      /**
                       * @dev _Available since v3.1._
                       */
                      interface IERC1155Receiver is IERC165 {
                          /**
                           * @dev Handles the receipt of a single ERC1155 token type. This function is
                           * called at the end of a `safeTransferFrom` after the balance has been updated.
                           *
                           * NOTE: To accept the transfer, this must return
                           * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
                           * (i.e. 0xf23a6e61, or its own function selector).
                           *
                           * @param operator The address which initiated the transfer (i.e. msg.sender)
                           * @param from The address which previously owned the token
                           * @param id The ID of the token being transferred
                           * @param value The amount of tokens being transferred
                           * @param data Additional data with no specified format
                           * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
                           */
                          function onERC1155Received(
                              address operator,
                              address from,
                              uint256 id,
                              uint256 value,
                              bytes calldata data
                          ) external returns (bytes4);
                          /**
                           * @dev Handles the receipt of a multiple ERC1155 token types. This function
                           * is called at the end of a `safeBatchTransferFrom` after the balances have
                           * been updated.
                           *
                           * NOTE: To accept the transfer(s), this must return
                           * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
                           * (i.e. 0xbc197c81, or its own function selector).
                           *
                           * @param operator The address which initiated the batch transfer (i.e. msg.sender)
                           * @param from The address which previously owned the token
                           * @param ids An array containing ids of each token being transferred (order and length must match values array)
                           * @param values An array containing amounts of each token being transferred (order and length must match ids array)
                           * @param data Additional data with no specified format
                           * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
                           */
                          function onERC1155BatchReceived(
                              address operator,
                              address from,
                              uint256[] calldata ids,
                              uint256[] calldata values,
                              bytes calldata data
                          ) external returns (bytes4);
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
                      pragma solidity ^0.8.0;
                      /**
                       * @dev This is the interface that {BeaconProxy} expects of its beacon.
                       */
                      interface IBeacon {
                          /**
                           * @dev Must return an address that can be used as a delegate call target.
                           *
                           * {BeaconProxy} will check that this address is a contract.
                           */
                          function implementation() external view returns (address);
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)
                      pragma solidity ^0.8.0;
                      /**
                       * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
                       *
                       * _Available since v4.8.3._
                       */
                      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 v4.9.0) (utils/Address.sol)
                      pragma solidity ^0.8.1;
                      /**
                       * @dev Collection of functions related to the address type
                       */
                      library Address {
                          /**
                           * @dev Returns true if `account` is a contract.
                           *
                           * [IMPORTANT]
                           * ====
                           * It is unsafe to assume that an address for which this function returns
                           * false is an externally-owned account (EOA) and not a contract.
                           *
                           * Among others, `isContract` will return false for the following
                           * types of addresses:
                           *
                           *  - an externally-owned account
                           *  - a contract in construction
                           *  - an address where a contract will be created
                           *  - an address where a contract lived, but was destroyed
                           *
                           * Furthermore, `isContract` will also return true if the target contract within
                           * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
                           * which only has an effect at the end of a transaction.
                           * ====
                           *
                           * [IMPORTANT]
                           * ====
                           * You shouldn't rely on `isContract` to protect against flash loan attacks!
                           *
                           * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                           * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                           * constructor.
                           * ====
                           */
                          function isContract(address account) internal view returns (bool) {
                              // This method relies on extcodesize/address.code.length, which returns 0
                              // for contracts in construction, since the code is only stored at the end
                              // of the constructor execution.
                              return account.code.length > 0;
                          }
                          /**
                           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                           * `recipient`, forwarding all available gas and reverting on errors.
                           *
                           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                           * of certain opcodes, possibly making contracts go over the 2300 gas limit
                           * imposed by `transfer`, making them unable to receive funds via
                           * `transfer`. {sendValue} removes this limitation.
                           *
                           * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                           *
                           * IMPORTANT: because control is transferred to `recipient`, care must be
                           * taken to not create reentrancy vulnerabilities. Consider using
                           * {ReentrancyGuard} or the
                           * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                           */
                          function sendValue(address payable recipient, uint256 amount) internal {
                              require(address(this).balance >= amount, "Address: insufficient balance");
                              (bool success, ) = recipient.call{value: amount}("");
                              require(success, "Address: unable to send value, recipient may have reverted");
                          }
                          /**
                           * @dev Performs a Solidity function call using a low level `call`. A
                           * plain `call` is an unsafe replacement for a function call: use this
                           * function instead.
                           *
                           * If `target` reverts with a revert reason, it is bubbled up by this
                           * function (like regular Solidity function calls).
                           *
                           * Returns the raw returned data. To convert to the expected return value,
                           * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                           *
                           * Requirements:
                           *
                           * - `target` must be a contract.
                           * - calling `target` with `data` must not revert.
                           *
                           * _Available since v3.1._
                           */
                          function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                              return functionCallWithValue(target, data, 0, "Address: low-level call failed");
                          }
                          /**
                           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                           * `errorMessage` as a fallback revert reason when `target` reverts.
                           *
                           * _Available since v3.1._
                           */
                          function functionCall(
                              address target,
                              bytes memory data,
                              string memory errorMessage
                          ) internal returns (bytes memory) {
                              return functionCallWithValue(target, data, 0, errorMessage);
                          }
                          /**
                           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                           * but also transferring `value` wei to `target`.
                           *
                           * Requirements:
                           *
                           * - the calling contract must have an ETH balance of at least `value`.
                           * - the called Solidity function must be `payable`.
                           *
                           * _Available since v3.1._
                           */
                          function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                              return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                          }
                          /**
                           * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                           * with `errorMessage` as a fallback revert reason when `target` reverts.
                           *
                           * _Available since v3.1._
                           */
                          function functionCallWithValue(
                              address target,
                              bytes memory data,
                              uint256 value,
                              string memory errorMessage
                          ) internal returns (bytes memory) {
                              require(address(this).balance >= value, "Address: insufficient balance for call");
                              (bool success, bytes memory returndata) = target.call{value: value}(data);
                              return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                          }
                          /**
                           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                           * but performing a static call.
                           *
                           * _Available since v3.3._
                           */
                          function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                              return functionStaticCall(target, data, "Address: low-level static call failed");
                          }
                          /**
                           * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                           * but performing a static call.
                           *
                           * _Available since v3.3._
                           */
                          function functionStaticCall(
                              address target,
                              bytes memory data,
                              string memory errorMessage
                          ) internal view returns (bytes memory) {
                              (bool success, bytes memory returndata) = target.staticcall(data);
                              return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                          }
                          /**
                           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                           * but performing a delegate call.
                           *
                           * _Available since v3.4._
                           */
                          function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                              return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                          }
                          /**
                           * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                           * but performing a delegate call.
                           *
                           * _Available since v3.4._
                           */
                          function functionDelegateCall(
                              address target,
                              bytes memory data,
                              string memory errorMessage
                          ) internal returns (bytes memory) {
                              (bool success, bytes memory returndata) = target.delegatecall(data);
                              return verifyCallResultFromTarget(target, success, returndata, errorMessage);
                          }
                          /**
                           * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
                           * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
                           *
                           * _Available since v4.8._
                           */
                          function verifyCallResultFromTarget(
                              address target,
                              bool success,
                              bytes memory returndata,
                              string memory errorMessage
                          ) internal view returns (bytes memory) {
                              if (success) {
                                  if (returndata.length == 0) {
                                      // only check isContract if the call was successful and the return data is empty
                                      // otherwise we already know that it was a contract
                                      require(isContract(target), "Address: call to non-contract");
                                  }
                                  return returndata;
                              } else {
                                  _revert(returndata, errorMessage);
                              }
                          }
                          /**
                           * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
                           * revert reason or using the provided one.
                           *
                           * _Available since v4.3._
                           */
                          function verifyCallResult(
                              bool success,
                              bytes memory returndata,
                              string memory errorMessage
                          ) internal pure returns (bytes memory) {
                              if (success) {
                                  return returndata;
                              } else {
                                  _revert(returndata, errorMessage);
                              }
                          }
                          function _revert(bytes memory returndata, string memory errorMessage) private pure {
                              // Look for revert reason and bubble it up if present
                              if (returndata.length > 0) {
                                  // The easiest way to bubble the revert reason is using memory via assembly
                                  /// @solidity memory-safe-assembly
                                  assembly {
                                      let returndata_size := mload(returndata)
                                      revert(add(32, returndata), returndata_size)
                                  }
                              } else {
                                  revert(errorMessage);
                              }
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
                      // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
                      pragma solidity ^0.8.0;
                      /**
                       * @dev Library for reading and writing primitive types to specific storage slots.
                       *
                       * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
                       * This library helps with reading and writing to such slots without the need for inline assembly.
                       *
                       * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
                       *
                       * Example usage to set ERC1967 implementation slot:
                       * ```solidity
                       * contract ERC1967 {
                       *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                       *
                       *     function _getImplementation() internal view returns (address) {
                       *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                       *     }
                       *
                       *     function _setImplementation(address newImplementation) internal {
                       *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                       *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                       *     }
                       * }
                       * ```
                       *
                       * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
                       * _Available since v4.9 for `string`, `bytes`._
                       */
                      library StorageSlot {
                          struct AddressSlot {
                              address value;
                          }
                          struct BooleanSlot {
                              bool value;
                          }
                          struct Bytes32Slot {
                              bytes32 value;
                          }
                          struct Uint256Slot {
                              uint256 value;
                          }
                          struct StringSlot {
                              string value;
                          }
                          struct BytesSlot {
                              bytes value;
                          }
                          /**
                           * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                           */
                          function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                              /// @solidity memory-safe-assembly
                              assembly {
                                  r.slot := slot
                              }
                          }
                          /**
                           * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                           */
                          function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                              /// @solidity memory-safe-assembly
                              assembly {
                                  r.slot := slot
                              }
                          }
                          /**
                           * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                           */
                          function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                              /// @solidity memory-safe-assembly
                              assembly {
                                  r.slot := slot
                              }
                          }
                          /**
                           * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                           */
                          function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                              /// @solidity memory-safe-assembly
                              assembly {
                                  r.slot := slot
                              }
                          }
                          /**
                           * @dev Returns an `StringSlot` with member `value` located at `slot`.
                           */
                          function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                              /// @solidity memory-safe-assembly
                              assembly {
                                  r.slot := slot
                              }
                          }
                          /**
                           * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
                           */
                          function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                              /// @solidity memory-safe-assembly
                              assembly {
                                  r.slot := store.slot
                              }
                          }
                          /**
                           * @dev Returns an `BytesSlot` with member `value` located at `slot`.
                           */
                          function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                              /// @solidity memory-safe-assembly
                              assembly {
                                  r.slot := slot
                              }
                          }
                          /**
                           * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
                           */
                          function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                              /// @solidity memory-safe-assembly
                              assembly {
                                  r.slot := store.slot
                              }
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
                      pragma solidity ^0.8.0;
                      /**
                       * @dev Standard math utilities missing in the Solidity language.
                       */
                      library Math {
                          enum Rounding {
                              Down, // Toward negative infinity
                              Up, // Toward infinity
                              Zero // Toward zero
                          }
                          /**
                           * @dev Returns the largest of two numbers.
                           */
                          function max(uint256 a, uint256 b) internal pure returns (uint256) {
                              return a > b ? a : b;
                          }
                          /**
                           * @dev Returns the smallest of two numbers.
                           */
                          function min(uint256 a, uint256 b) internal pure returns (uint256) {
                              return a < b ? a : b;
                          }
                          /**
                           * @dev Returns the average of two numbers. The result is rounded towards
                           * zero.
                           */
                          function average(uint256 a, uint256 b) internal pure returns (uint256) {
                              // (a + b) / 2 can overflow.
                              return (a & b) + (a ^ b) / 2;
                          }
                          /**
                           * @dev Returns the ceiling of the division of two numbers.
                           *
                           * This differs from standard division with `/` in that it rounds up instead
                           * of rounding down.
                           */
                          function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
                              // (a + b - 1) / b can overflow on addition, so we distribute.
                              return a == 0 ? 0 : (a - 1) / b + 1;
                          }
                          /**
                           * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
                           * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
                           * with further edits by Uniswap Labs also under MIT license.
                           */
                          function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
                              unchecked {
                                  // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
                                  // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
                                  // variables such that product = prod1 * 2^256 + prod0.
                                  uint256 prod0; // Least significant 256 bits of the product
                                  uint256 prod1; // Most significant 256 bits of the product
                                  assembly {
                                      let mm := mulmod(x, y, not(0))
                                      prod0 := mul(x, y)
                                      prod1 := sub(sub(mm, prod0), lt(mm, prod0))
                                  }
                                  // Handle non-overflow cases, 256 by 256 division.
                                  if (prod1 == 0) {
                                      // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                                      // The surrounding unchecked block does not change this fact.
                                      // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                                      return prod0 / denominator;
                                  }
                                  // Make sure the result is less than 2^256. Also prevents denominator == 0.
                                  require(denominator > prod1, "Math: mulDiv overflow");
                                  ///////////////////////////////////////////////
                                  // 512 by 256 division.
                                  ///////////////////////////////////////////////
                                  // Make division exact by subtracting the remainder from [prod1 prod0].
                                  uint256 remainder;
                                  assembly {
                                      // Compute remainder using mulmod.
                                      remainder := mulmod(x, y, denominator)
                                      // Subtract 256 bit number from 512 bit number.
                                      prod1 := sub(prod1, gt(remainder, prod0))
                                      prod0 := sub(prod0, remainder)
                                  }
                                  // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
                                  // See https://cs.stackexchange.com/q/138556/92363.
                                  // Does not overflow because the denominator cannot be zero at this stage in the function.
                                  uint256 twos = denominator & (~denominator + 1);
                                  assembly {
                                      // Divide denominator by twos.
                                      denominator := div(denominator, twos)
                                      // Divide [prod1 prod0] by twos.
                                      prod0 := div(prod0, twos)
                                      // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                                      twos := add(div(sub(0, twos), twos), 1)
                                  }
                                  // Shift in bits from prod1 into prod0.
                                  prod0 |= prod1 * twos;
                                  // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
                                  // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
                                  // four bits. That is, denominator * inv = 1 mod 2^4.
                                  uint256 inverse = (3 * denominator) ^ 2;
                                  // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
                                  // in modular arithmetic, doubling the correct bits in each step.
                                  inverse *= 2 - denominator * inverse; // inverse mod 2^8
                                  inverse *= 2 - denominator * inverse; // inverse mod 2^16
                                  inverse *= 2 - denominator * inverse; // inverse mod 2^32
                                  inverse *= 2 - denominator * inverse; // inverse mod 2^64
                                  inverse *= 2 - denominator * inverse; // inverse mod 2^128
                                  inverse *= 2 - denominator * inverse; // inverse mod 2^256
                                  // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
                                  // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
                                  // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
                                  // is no longer required.
                                  result = prod0 * inverse;
                                  return result;
                              }
                          }
                          /**
                           * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
                           */
                          function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
                              uint256 result = mulDiv(x, y, denominator);
                              if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
                                  result += 1;
                              }
                              return result;
                          }
                          /**
                           * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
                           *
                           * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
                           */
                          function sqrt(uint256 a) internal pure returns (uint256) {
                              if (a == 0) {
                                  return 0;
                              }
                              // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
                              //
                              // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
                              // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
                              //
                              // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
                              // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
                              // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
                              //
                              // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
                              uint256 result = 1 << (log2(a) >> 1);
                              // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
                              // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
                              // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
                              // into the expected uint128 result.
                              unchecked {
                                  result = (result + a / result) >> 1;
                                  result = (result + a / result) >> 1;
                                  result = (result + a / result) >> 1;
                                  result = (result + a / result) >> 1;
                                  result = (result + a / result) >> 1;
                                  result = (result + a / result) >> 1;
                                  result = (result + a / result) >> 1;
                                  return min(result, a / result);
                              }
                          }
                          /**
                           * @notice Calculates sqrt(a), following the selected rounding direction.
                           */
                          function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
                              unchecked {
                                  uint256 result = sqrt(a);
                                  return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
                              }
                          }
                          /**
                           * @dev Return the log in base 2, rounded down, of a positive value.
                           * Returns 0 if given 0.
                           */
                          function log2(uint256 value) internal pure returns (uint256) {
                              uint256 result = 0;
                              unchecked {
                                  if (value >> 128 > 0) {
                                      value >>= 128;
                                      result += 128;
                                  }
                                  if (value >> 64 > 0) {
                                      value >>= 64;
                                      result += 64;
                                  }
                                  if (value >> 32 > 0) {
                                      value >>= 32;
                                      result += 32;
                                  }
                                  if (value >> 16 > 0) {
                                      value >>= 16;
                                      result += 16;
                                  }
                                  if (value >> 8 > 0) {
                                      value >>= 8;
                                      result += 8;
                                  }
                                  if (value >> 4 > 0) {
                                      value >>= 4;
                                      result += 4;
                                  }
                                  if (value >> 2 > 0) {
                                      value >>= 2;
                                      result += 2;
                                  }
                                  if (value >> 1 > 0) {
                                      result += 1;
                                  }
                              }
                              return result;
                          }
                          /**
                           * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
                           * Returns 0 if given 0.
                           */
                          function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
                              unchecked {
                                  uint256 result = log2(value);
                                  return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
                              }
                          }
                          /**
                           * @dev Return the log in base 10, rounded down, of a positive value.
                           * Returns 0 if given 0.
                           */
                          function log10(uint256 value) internal pure returns (uint256) {
                              uint256 result = 0;
                              unchecked {
                                  if (value >= 10 ** 64) {
                                      value /= 10 ** 64;
                                      result += 64;
                                  }
                                  if (value >= 10 ** 32) {
                                      value /= 10 ** 32;
                                      result += 32;
                                  }
                                  if (value >= 10 ** 16) {
                                      value /= 10 ** 16;
                                      result += 16;
                                  }
                                  if (value >= 10 ** 8) {
                                      value /= 10 ** 8;
                                      result += 8;
                                  }
                                  if (value >= 10 ** 4) {
                                      value /= 10 ** 4;
                                      result += 4;
                                  }
                                  if (value >= 10 ** 2) {
                                      value /= 10 ** 2;
                                      result += 2;
                                  }
                                  if (value >= 10 ** 1) {
                                      result += 1;
                                  }
                              }
                              return result;
                          }
                          /**
                           * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
                           * Returns 0 if given 0.
                           */
                          function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
                              unchecked {
                                  uint256 result = log10(value);
                                  return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
                              }
                          }
                          /**
                           * @dev Return the log in base 256, rounded down, of a positive value.
                           * Returns 0 if given 0.
                           *
                           * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
                           */
                          function log256(uint256 value) internal pure returns (uint256) {
                              uint256 result = 0;
                              unchecked {
                                  if (value >> 128 > 0) {
                                      value >>= 128;
                                      result += 16;
                                  }
                                  if (value >> 64 > 0) {
                                      value >>= 64;
                                      result += 8;
                                  }
                                  if (value >> 32 > 0) {
                                      value >>= 32;
                                      result += 4;
                                  }
                                  if (value >> 16 > 0) {
                                      value >>= 16;
                                      result += 2;
                                  }
                                  if (value >> 8 > 0) {
                                      result += 1;
                                  }
                              }
                              return result;
                          }
                          /**
                           * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
                           * Returns 0 if given 0.
                           */
                          function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
                              unchecked {
                                  uint256 result = log256(value);
                                  return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
                              }
                          }
                      }
                      // SPDX-License-Identifier: MIT
                      // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
                      pragma solidity ^0.8.0;
                      /**
                       * @dev Standard signed math utilities missing in the Solidity language.
                       */
                      library SignedMath {
                          /**
                           * @dev Returns the largest of two signed numbers.
                           */
                          function max(int256 a, int256 b) internal pure returns (int256) {
                              return a > b ? a : b;
                          }
                          /**
                           * @dev Returns the smallest of two signed numbers.
                           */
                          function min(int256 a, int256 b) internal pure returns (int256) {
                              return a < b ? a : b;
                          }
                          /**
                           * @dev Returns the average of two signed numbers without overflow.
                           * The result is rounded towards zero.
                           */
                          function average(int256 a, int256 b) internal pure returns (int256) {
                              // Formula from the book "Hacker's Delight"
                              int256 x = (a & b) + ((a ^ b) >> 1);
                              return x + (int256(uint256(x) >> 255) & (a ^ b));
                          }
                          /**
                           * @dev Returns the absolute unsigned value of a signed value.
                           */
                          function abs(int256 n) internal pure returns (uint256) {
                              unchecked {
                                  // must be unchecked in order to support `n = type(int256).min`
                                  return uint256(n >= 0 ? n : -n);
                              }
                          }
                      }