ETH Price: $2,439.62 (+3.87%)

Transaction Decoder

Block:
19023120 at Jan-17-2024 12:46:23 AM +UTC
Transaction Fee:
0.003065371351295355 ETH $7.48
Gas Used:
99,963 Gas / 30.665059585 Gwei

Emitted Events:

234 EntryPoint.BeforeExecution( )
235 EntryPoint.UserOperationEvent( userOpHash=0FF6698293DEB97E4B280B507518511F66788C6810DA3C31BDFF7B46BE1081E5, sender=0x66301c22d10e938514ac77f73403dbc039705243, paymaster=0x00000000...000000000, nonce=32, success=True, actualGasCost=3147921691698175, actualGasUsed=102655 )

Account State Difference:

  Address   Before After State Difference Code
0x45122d64...8c31BAD6E
(OKX Dep: 0x45122d649A629677D41A937534CABDc8c31BAD6E)
0.000147468244116766 Eth0.250147468244116766 Eth0.25
0x5FF137D4...a026d2789
(Entry Point 0.6.0)
42.870939890895022036 Eth42.867791969203323861 Eth0.003147921691698175
0x66301c22...039705243 0.36149370889739097 Eth0.11149370889739097 Eth0.25
0x82e934aF...0a2BE9441
0.468638004071523035 Eth
Nonce: 401
0.468720554411925855 Eth
Nonce: 402
0.00008255034040282
13.421160124976633511 Eth13.421217103886633511 Eth0.00005697891

Execution Trace

EntryPoint.handleOps( ops=, beneficiary=0x82e934aF5268AA9C3977346C92233E80a2BE9441 )
  • 0x66301c22d10e938514ac77f73403dbc039705243.3a871cdd( )
    • SmartAccountV2.validateUserOp( userOp=[{name:sender, type:address, order:1, indexed:false, value:0x66301c22d10e938514ac77F73403dBC039705243, valueString:0x66301c22d10e938514ac77F73403dBC039705243}, {name:nonce, type:uint256, order:2, indexed:false, value:32, valueString:32}, {name:initCode, type:bytes, order:3, indexed:false, value:0x, valueString:0x}, {name:callData, type:bytes, order:4, indexed:false, value:0x70641A2200000000000000000000000045122D649A629677D41A937534CABDC8C31BAD6E00000000000000000000000000000000000000000000000003782DACE9D9000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000, valueString:0x70641A2200000000000000000000000045122D649A629677D41A937534CABDC8C31BAD6E00000000000000000000000000000000000000000000000003782DACE9D9000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000}, {name:callGasLimit, type:uint256, order:5, indexed:false, value:65814, valueString:65814}, {name:verificationGasLimit, type:uint256, order:6, indexed:false, value:51992, valueString:51992}, {name:preVerificationGas, type:uint256, order:7, indexed:false, value:48973, valueString:48973}, {name:maxFeePerGas, type:uint256, order:8, indexed:false, value:41029500000, valueString:41029500000}, {name:maxPriorityFeePerGas, type:uint256, order:9, indexed:false, value:570000000, valueString:570000000}, {name:paymasterAndData, type:bytes, order:10, indexed:false, value:0x, valueString:0x}, {name:signature, type:bytes, order:11, indexed:false, value:0x000000000000000000000000000000000000000000000000000000000065A724AC1D6B9420AA26817BDFB26505932AEF34E52647BD9196E8A2584ABE1974E1D4375317CCC4679D99E4C270C7F67B12FC19866B630DC8DA0654E3A9576AFC8EE6301C, valueString:0x000000000000000000000000000000000000000000000000000000000065A724AC1D6B9420AA26817BDFB26505932AEF34E52647BD9196E8A2584ABE1974E1D4375317CCC4679D99E4C270C7F67B12FC19866B630DC8DA0654E3A9576AFC8EE6301C}], userOpHash=0FF6698293DEB97E4B280B507518511F66788C6810DA3C31BDFF7B46BE1081E5, missingAccountFunds=0 ) => ( validationData=2492521936824435372582800139163990533296891540931205922816 )
      • 0x228e505d1f21948968fb52794ea823f65053a294.adb66249( )
      • Null: 0x000...001.d59e248a( )
      • EntryPoint.innerHandleOp( callData=0x70641A2200000000000000000000000045122D649A629677D41A937534CABDC8C31BAD6E00000000000000000000000000000000000000000000000003782DACE9D9000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000, opInfo=[{name:mUserOp, type:tuple, order:1, indexed:false, value:[{name:sender, type:address, order:1, indexed:false, value:0x66301c22d10e938514ac77F73403dBC039705243, valueString:0x66301c22d10e938514ac77F73403dBC039705243}, {name:nonce, type:uint256, order:2, indexed:false, value:32, valueString:32}, {name:callGasLimit, type:uint256, order:3, indexed:false, value:65814, valueString:65814}, {name:verificationGasLimit, type:uint256, order:4, indexed:false, value:51992, valueString:51992}, {name:preVerificationGas, type:uint256, order:5, indexed:false, value:48973, valueString:48973}, {name:paymaster, type:address, order:6, indexed:false, value:0x0000000000000000000000000000000000000000, valueString:0x0000000000000000000000000000000000000000}, {name:maxFeePerGas, type:uint256, order:7, indexed:false, value:41029500000, valueString:41029500000}, {name:maxPriorityFeePerGas, type:uint256, order:8, indexed:false, value:570000000, valueString:570000000}], valueString:[{name:sender, type:address, order:1, indexed:false, value:0x66301c22d10e938514ac77F73403dBC039705243, valueString:0x66301c22d10e938514ac77F73403dBC039705243}, {name:nonce, type:uint256, order:2, indexed:false, value:32, valueString:32}, {name:callGasLimit, type:uint256, order:3, indexed:false, value:65814, valueString:65814}, {name:verificationGasLimit, type:uint256, order:4, indexed:false, value:51992, valueString:51992}, {name:preVerificationGas, type:uint256, order:5, indexed:false, value:48973, valueString:48973}, {name:paymaster, type:address, order:6, indexed:false, value:0x0000000000000000000000000000000000000000, valueString:0x0000000000000000000000000000000000000000}, {name:maxFeePerGas, type:uint256, order:7, indexed:false, value:41029500000, valueString:41029500000}, {name:maxPriorityFeePerGas, type:uint256, order:8, indexed:false, value:570000000, valueString:570000000}]}, {name:userOpHash, type:bytes32, order:2, indexed:false, value:0FF6698293DEB97E4B280B507518511F66788C6810DA3C31BDFF7B46BE1081E5, valueString:0FF6698293DEB97E4B280B507518511F66788C6810DA3C31BDFF7B46BE1081E5}, {name:prefund, type:uint256, order:3, indexed:false, value:6842858980500000, valueString:6842858980500000}, {name:contextOffset, type:uint256, order:4, indexed:false, value:96, valueString:96}, {name:preOpGas, type:uint256, order:5, indexed:false, value:88622, valueString:88622}], context=0x ) => ( actualGasCost=3147921691698175 )
        • 0x66301c22d10e938514ac77f73403dbc039705243.70641a22( )
          • SmartAccountV2.execTransactionFromEntrypoint( to=0x45122d649A629677D41A937534CABDc8c31BAD6E, value=250000000000000000, data=0x )
            • ETH 0.25 OKX Dep: 0x45122d649A629677D41A937534CABDc8c31BAD6E.CALL( )
            • ETH 0.003147921691698175 0x82e934af5268aa9c3977346c92233e80a2be9441.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: SmartAccountV2
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
              pragma solidity ^0.8.0;
              /**
               * @dev Interface of the ERC20 standard as defined in the EIP.
               */
              interface IERC20 {
                  /**
                   * @dev Emitted when `value` tokens are moved from one account (`from`) to
                   * another (`to`).
                   *
                   * Note that `value` may be zero.
                   */
                  event Transfer(address indexed from, address indexed to, uint256 value);
                  /**
                   * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                   * a call to {approve}. `value` is the new allowance.
                   */
                  event Approval(address indexed owner, address indexed spender, uint256 value);
                  /**
                   * @dev Returns the amount of tokens in existence.
                   */
                  function totalSupply() external view returns (uint256);
                  /**
                   * @dev Returns the amount of tokens owned by `account`.
                   */
                  function balanceOf(address account) external view returns (uint256);
                  /**
                   * @dev Moves `amount` tokens from the caller's account to `to`.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * Emits a {Transfer} event.
                   */
                  function transfer(address to, uint256 amount) external returns (bool);
                  /**
                   * @dev Returns the remaining number of tokens that `spender` will be
                   * allowed to spend on behalf of `owner` through {transferFrom}. This is
                   * zero by default.
                   *
                   * This value changes when {approve} or {transferFrom} are called.
                   */
                  function allowance(address owner, address spender) external view returns (uint256);
                  /**
                   * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * IMPORTANT: Beware that changing an allowance with this method brings the risk
                   * that someone may use both the old and the new allowance by unfortunate
                   * transaction ordering. One possible solution to mitigate this race
                   * condition is to first reduce the spender's allowance to 0 and set the
                   * desired value afterwards:
                   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                   *
                   * Emits an {Approval} event.
                   */
                  function approve(address spender, uint256 amount) external returns (bool);
                  /**
                   * @dev Moves `amount` tokens from `from` to `to` using the
                   * allowance mechanism. `amount` is then deducted from the caller's
                   * allowance.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * Emits a {Transfer} event.
                   */
                  function transferFrom(address from, address to, uint256 amount) external returns (bool);
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v4.9.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/math/Math.sol)
              pragma solidity ^0.8.0;
              /**
               * @dev Standard math utilities missing in the Solidity language.
               */
              library Math {
                  enum Rounding {
                      Down, // Toward negative infinity
                      Up, // Toward infinity
                      Zero // Toward zero
                  }
                  /**
                   * @dev Returns the largest of two numbers.
                   */
                  function max(uint256 a, uint256 b) internal pure returns (uint256) {
                      return a > b ? a : b;
                  }
                  /**
                   * @dev Returns the smallest of two numbers.
                   */
                  function min(uint256 a, uint256 b) internal pure returns (uint256) {
                      return a < b ? a : b;
                  }
                  /**
                   * @dev Returns the average of two numbers. The result is rounded towards
                   * zero.
                   */
                  function average(uint256 a, uint256 b) internal pure returns (uint256) {
                      // (a + b) / 2 can overflow.
                      return (a & b) + (a ^ b) / 2;
                  }
                  /**
                   * @dev Returns the ceiling of the division of two numbers.
                   *
                   * This differs from standard division with `/` in that it rounds up instead
                   * of rounding down.
                   */
                  function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
                      // (a + b - 1) / b can overflow on addition, so we distribute.
                      return a == 0 ? 0 : (a - 1) / b + 1;
                  }
                  /**
                   * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
                   * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
                   * with further edits by Uniswap Labs also under MIT license.
                   */
                  function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
                      unchecked {
                          // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
                          // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
                          // variables such that product = prod1 * 2^256 + prod0.
                          uint256 prod0; // Least significant 256 bits of the product
                          uint256 prod1; // Most significant 256 bits of the product
                          assembly {
                              let mm := mulmod(x, y, not(0))
                              prod0 := mul(x, y)
                              prod1 := sub(sub(mm, prod0), lt(mm, prod0))
                          }
                          // Handle non-overflow cases, 256 by 256 division.
                          if (prod1 == 0) {
                              // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                              // The surrounding unchecked block does not change this fact.
                              // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                              return prod0 / denominator;
                          }
                          // Make sure the result is less than 2^256. Also prevents denominator == 0.
                          require(denominator > prod1, "Math: mulDiv overflow");
                          ///////////////////////////////////////////////
                          // 512 by 256 division.
                          ///////////////////////////////////////////////
                          // Make division exact by subtracting the remainder from [prod1 prod0].
                          uint256 remainder;
                          assembly {
                              // Compute remainder using mulmod.
                              remainder := mulmod(x, y, denominator)
                              // Subtract 256 bit number from 512 bit number.
                              prod1 := sub(prod1, gt(remainder, prod0))
                              prod0 := sub(prod0, remainder)
                          }
                          // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
                          // See https://cs.stackexchange.com/q/138556/92363.
                          // Does not overflow because the denominator cannot be zero at this stage in the function.
                          uint256 twos = denominator & (~denominator + 1);
                          assembly {
                              // Divide denominator by twos.
                              denominator := div(denominator, twos)
                              // Divide [prod1 prod0] by twos.
                              prod0 := div(prod0, twos)
                              // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                              twos := add(div(sub(0, twos), twos), 1)
                          }
                          // Shift in bits from prod1 into prod0.
                          prod0 |= prod1 * twos;
                          // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
                          // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
                          // four bits. That is, denominator * inv = 1 mod 2^4.
                          uint256 inverse = (3 * denominator) ^ 2;
                          // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
                          // in modular arithmetic, doubling the correct bits in each step.
                          inverse *= 2 - denominator * inverse; // inverse mod 2^8
                          inverse *= 2 - denominator * inverse; // inverse mod 2^16
                          inverse *= 2 - denominator * inverse; // inverse mod 2^32
                          inverse *= 2 - denominator * inverse; // inverse mod 2^64
                          inverse *= 2 - denominator * inverse; // inverse mod 2^128
                          inverse *= 2 - denominator * inverse; // inverse mod 2^256
                          // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
                          // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
                          // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
                          // is no longer required.
                          result = prod0 * inverse;
                          return result;
                      }
                  }
                  /**
                   * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
                   */
                  function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
                      uint256 result = mulDiv(x, y, denominator);
                      if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
                          result += 1;
                      }
                      return result;
                  }
                  /**
                   * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
                   *
                   * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
                   */
                  function sqrt(uint256 a) internal pure returns (uint256) {
                      if (a == 0) {
                          return 0;
                      }
                      // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
                      //
                      // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
                      // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
                      //
                      // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
                      // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
                      // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
                      //
                      // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
                      uint256 result = 1 << (log2(a) >> 1);
                      // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
                      // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
                      // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
                      // into the expected uint128 result.
                      unchecked {
                          result = (result + a / result) >> 1;
                          result = (result + a / result) >> 1;
                          result = (result + a / result) >> 1;
                          result = (result + a / result) >> 1;
                          result = (result + a / result) >> 1;
                          result = (result + a / result) >> 1;
                          result = (result + a / result) >> 1;
                          return min(result, a / result);
                      }
                  }
                  /**
                   * @notice Calculates sqrt(a), following the selected rounding direction.
                   */
                  function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
                      unchecked {
                          uint256 result = sqrt(a);
                          return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
                      }
                  }
                  /**
                   * @dev Return the log in base 2, rounded down, of a positive value.
                   * Returns 0 if given 0.
                   */
                  function log2(uint256 value) internal pure returns (uint256) {
                      uint256 result = 0;
                      unchecked {
                          if (value >> 128 > 0) {
                              value >>= 128;
                              result += 128;
                          }
                          if (value >> 64 > 0) {
                              value >>= 64;
                              result += 64;
                          }
                          if (value >> 32 > 0) {
                              value >>= 32;
                              result += 32;
                          }
                          if (value >> 16 > 0) {
                              value >>= 16;
                              result += 16;
                          }
                          if (value >> 8 > 0) {
                              value >>= 8;
                              result += 8;
                          }
                          if (value >> 4 > 0) {
                              value >>= 4;
                              result += 4;
                          }
                          if (value >> 2 > 0) {
                              value >>= 2;
                              result += 2;
                          }
                          if (value >> 1 > 0) {
                              result += 1;
                          }
                      }
                      return result;
                  }
                  /**
                   * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
                   * Returns 0 if given 0.
                   */
                  function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
                      unchecked {
                          uint256 result = log2(value);
                          return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
                      }
                  }
                  /**
                   * @dev Return the log in base 10, rounded down, of a positive value.
                   * Returns 0 if given 0.
                   */
                  function log10(uint256 value) internal pure returns (uint256) {
                      uint256 result = 0;
                      unchecked {
                          if (value >= 10 ** 64) {
                              value /= 10 ** 64;
                              result += 64;
                          }
                          if (value >= 10 ** 32) {
                              value /= 10 ** 32;
                              result += 32;
                          }
                          if (value >= 10 ** 16) {
                              value /= 10 ** 16;
                              result += 16;
                          }
                          if (value >= 10 ** 8) {
                              value /= 10 ** 8;
                              result += 8;
                          }
                          if (value >= 10 ** 4) {
                              value /= 10 ** 4;
                              result += 4;
                          }
                          if (value >= 10 ** 2) {
                              value /= 10 ** 2;
                              result += 2;
                          }
                          if (value >= 10 ** 1) {
                              result += 1;
                          }
                      }
                      return result;
                  }
                  /**
                   * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
                   * Returns 0 if given 0.
                   */
                  function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
                      unchecked {
                          uint256 result = log10(value);
                          return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
                      }
                  }
                  /**
                   * @dev Return the log in base 256, rounded down, of a positive value.
                   * Returns 0 if given 0.
                   *
                   * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
                   */
                  function log256(uint256 value) internal pure returns (uint256) {
                      uint256 result = 0;
                      unchecked {
                          if (value >> 128 > 0) {
                              value >>= 128;
                              result += 16;
                          }
                          if (value >> 64 > 0) {
                              value >>= 64;
                              result += 8;
                          }
                          if (value >> 32 > 0) {
                              value >>= 32;
                              result += 4;
                          }
                          if (value >> 16 > 0) {
                              value >>= 16;
                              result += 2;
                          }
                          if (value >> 8 > 0) {
                              result += 1;
                          }
                      }
                      return result;
                  }
                  /**
                   * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
                   * Returns 0 if given 0.
                   */
                  function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
                      unchecked {
                          uint256 result = log256(value);
                          return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
              pragma solidity ^0.8.0;
              /**
               * @dev Standard signed math utilities missing in the Solidity language.
               */
              library SignedMath {
                  /**
                   * @dev Returns the largest of two signed numbers.
                   */
                  function max(int256 a, int256 b) internal pure returns (int256) {
                      return a > b ? a : b;
                  }
                  /**
                   * @dev Returns the smallest of two signed numbers.
                   */
                  function min(int256 a, int256 b) internal pure returns (int256) {
                      return a < b ? a : b;
                  }
                  /**
                   * @dev Returns the average of two signed numbers without overflow.
                   * The result is rounded towards zero.
                   */
                  function average(int256 a, int256 b) internal pure returns (int256) {
                      // Formula from the book "Hacker's Delight"
                      int256 x = (a & b) + ((a ^ b) >> 1);
                      return x + (int256(uint256(x) >> 255) & (a ^ b));
                  }
                  /**
                   * @dev Returns the absolute unsigned value of a signed value.
                   */
                  function abs(int256 n) internal pure returns (uint256) {
                      unchecked {
                          // must be unchecked in order to support `n = type(int256).min`
                          return uint256(n >= 0 ? n : -n);
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              // 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;
              /* 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.)
                      }
                  }
              }
              // 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 "./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-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: GPL-3.0
              pragma solidity ^0.8.12;
              interface IValidations {
                  struct bundlerInformation {
                      address bundler;
                      uint256 registeTime;
                  }
                  event UnrestrictedBundlerSet(bool allowed);
                  event UnrestrictedModuleSet(bool allowed);
                  event WalletFactoryWhitelistSet(address walletProxyFactory);
                  event BundlerWhitelistSet(address indexed bundler, bool allowed);
                  event ModuleWhitelistSet(address indexed module, bool allowed);
                  function officialBundlerWhiteList(
                      address bundler
                  ) external view returns (bool);
                  function moduleWhiteList(address module) external view returns (bool);
                  function setUnrestrictedBundler(bool allowed) external;
                  function setUnrestrictedModule(bool allowed) external;
                  function setBundlerOfficialWhitelist(
                      address bundler,
                      bool allowed
                  ) external;
                  function setWalletProxyFactoryWhitelist(address walletFactory) external;
                  function setModuleWhitelist(address module, bool allowed) external;
                  function validateBundlerWhiteList(address bundler) external view;
                  function validateModuleWhitelist(address module) external;
              }
              // SPDX-License-Identifier: LGPL-3.0-only
              pragma solidity ^0.8.12;
              import "../common/Enum.sol";
              /// @title Executor - A contract that can execute transactions
              contract Executor {
                  struct ExecuteParams {
                      bool allowFailed;
                      address to;
                      uint256 value;
                      bytes data;
                      bytes nestedCalls; // ExecuteParams encoded as bytes
                  }
                  event HandleSuccessExternalCalls();
                  event HandleFailedExternalCalls(bytes revertReason);
                  function execute(
                      ExecuteParams memory params,
                      Enum.Operation operation,
                      uint256 txGas
                  ) internal returns (bool success) {
                      bytes memory result;
                      if (operation == Enum.Operation.DelegateCall) {
                          // solhint-disable-next-line no-inline-assembly
                          (success, result) = params.to.delegatecall{gas: txGas}(params.data);
                      } else {
                          // solhint-disable-next-line no-inline-assembly
                          (success, result) = payable(params.to).call{
                              gas: txGas,
                              value: params.value
                          }(params.data);
                      }
                      if (!success) {
                          if (!params.allowFailed) {
                              assembly {
                                  revert(add(result, 32), mload(result))
                              }
                          }
                      }
                  }
              }
              // SPDX-License-Identifier: LGPL-3.0-only
              pragma solidity ^0.8.12;
              import "../common/SelfAuthorized.sol";
              /// @title Fallback Manager - A contract that manages fallback calls made to this contract
              contract FallbackManager is SelfAuthorized {
                  event ChangedFallbackHandler(address handler);
                  // keccak256("fallback_manager.handler.address")
                  bytes32 internal constant FALLBACK_HANDLER_STORAGE_SLOT =
                      0x6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d5;
                  function getFallbackHandler()
                      public
                      view
                      returns (address fallbackHandler)
                  {
                      bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT;
                      // solhint-disable-next-line no-inline-assembly
                      assembly {
                          let encoded := sload(slot)
                          fallbackHandler := shr(96, encoded)
                      }
                  }
                  /// @dev Allows to add a contract to handle fallback calls.
                  ///      Only fallback calls without value and with data will be forwarded.
                  ///      This can only be done via a Safe transaction.
                  /// @param handler contract to handle fallbacks calls.
                  function setFallbackHandler(address handler) external authorized {
                      setFallbackHandler(handler, false);
                      emit ChangedFallbackHandler(handler);
                  }
                  function setFallbackHandler(address handler, bool delegate) internal {
                      require(handler != address(this), "handler illegal");
                      bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT;
                      // solhint-disable-next-line no-inline-assembly
                      assembly {
                          let encoded := or(shl(96, handler), delegate)
                          sstore(slot, encoded)
                      }
                  }
                  function initializeFallbackHandler(address handler) internal {
                      bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT;
                      // solhint-disable-next-line no-inline-assembly
                      assembly {
                          let encoded := shl(96, handler)
                          sstore(slot, encoded)
                      }
                  }
                  // solhint-disable-next-line payable-fallback,no-complex-fallback
                  fallback() external {
                      assembly {
                          // Load handler and delegate flag from storage
                          let encoded := sload(FALLBACK_HANDLER_STORAGE_SLOT)
                          let handler := shr(96, encoded)
                          let delegate := and(encoded, 1)
                          // Copy calldata to memory
                          calldatacopy(0, 0, calldatasize())
                          // If delegate flag is set, delegate the call to the handler
                          switch delegate
                          case 0 {
                              mstore(calldatasize(), shl(96, caller()))
                              let success := call(
                                  gas(),
                                  handler,
                                  0,
                                  0,
                                  add(calldatasize(), 20),
                                  0,
                                  0
                              )
                              returndatacopy(0, 0, returndatasize())
                              if iszero(success) {
                                  revert(0, returndatasize())
                              }
                              return(0, returndatasize())
                          }
                          case 1 {
                              let result := delegatecall(
                                  gas(),
                                  handler,
                                  0,
                                  calldatasize(),
                                  0,
                                  0
                              )
                              returndatacopy(0, 0, returndatasize())
                              switch result
                              case 0 {
                                  revert(0, returndatasize())
                              }
                              default {
                                  return(0, returndatasize())
                              }
                          }
                      }
                  }
              }
              // SPDX-License-Identifier: LGPL-3.0-only
              pragma solidity ^0.8.12;
              import "../common/Enum.sol";
              import "../common/SelfAuthorized.sol";
              import "./Executor.sol";
              interface Guard {
                  function checkTransaction(
                      address to,
                      uint256 value,
                      bytes memory data,
                      Enum.Operation operation
                  ) external;
                  function checkAfterExecution(bool success) external;
              }
              /// @title Fallback Manager - A contract that manages fallback calls made to this contract
              contract GuardManager is SelfAuthorized, Executor {
                  event ChangedGuard(address guard);
                  // keccak256("guard_manager.guard.address")
                  bytes32 internal constant GUARD_STORAGE_SLOT =
                      0x4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c8;
                  function getGuard() public view returns (address guard) {
                      bytes32 slot = GUARD_STORAGE_SLOT;
                      // solhint-disable-next-line no-inline-assembly
                      assembly {
                          guard := sload(slot)
                      }
                  }
                  function setGuard(address guard) external authorized {
                      bytes32 slot = GUARD_STORAGE_SLOT;
                      // solhint-disable-next-line no-inline-assembly
                      assembly {
                          sstore(slot, guard)
                      }
                      emit ChangedGuard(guard);
                  }
                  // execute from this contract
                  function execTransactionBatch(
                      bytes memory executeParamBytes
                  ) external authorized {
                      executeWithGuardBatch(abi.decode(executeParamBytes, (ExecuteParams[])));
                  }
                  function execTransactionRevertOnFail(
                      bytes memory executeParamBytes
                  ) external authorized {
                      execTransactionBatchRevertOnFail(
                          abi.decode(executeParamBytes, (ExecuteParams[]))
                      );
                  }
                  function executeWithGuard(
                      address to,
                      uint256 value,
                      bytes calldata data
                  ) internal {
                      address guard = getGuard();
                      if (guard != address(0)) {
                          Guard(guard).checkTransaction(to, value, data, Enum.Operation.Call);
                          Guard(guard).checkAfterExecution(
                              execute(
                                  ExecuteParams(false, to, value, data, ""),
                                  Enum.Operation.Call,
                                  gasleft()
                              )
                          );
                      } else {
                          execute(
                              ExecuteParams(false, to, value, data, ""),
                              Enum.Operation.Call,
                              gasleft()
                          );
                      }
                  }
                  function execTransactionBatchRevertOnFail(
                      ExecuteParams[] memory _params
                  ) internal {
                      address guard = getGuard();
                      uint256 length = _params.length;
                      if (guard == address(0)) {
                          for (uint256 i = 0; i < length; ) {
                              ExecuteParams memory param = _params[i];
                              execute(param, Enum.Operation.Call, gasleft());
                              if (param.nestedCalls.length > 0) {
                                  try
                                      this.execTransactionRevertOnFail(param.nestedCalls)
                                  {} catch (bytes memory returnData) {
                                      revert(string(returnData));
                                  }
                              }
                              unchecked {
                                  ++i;
                              }
                          }
                      } else {
                          for (uint256 i = 0; i < length; ) {
                              ExecuteParams memory param = _params[i];
                              Guard(guard).checkTransaction(
                                  param.to,
                                  param.value,
                                  param.data,
                                  Enum.Operation.Call
                              );
                              Guard(guard).checkAfterExecution(
                                  execute(param, Enum.Operation.Call, gasleft())
                              );
                              if (param.nestedCalls.length > 0) {
                                  try
                                      this.execTransactionRevertOnFail(param.nestedCalls)
                                  {} catch (bytes memory returnData) {
                                      revert(string(returnData));
                                  }
                              }
                              unchecked {
                                  ++i;
                              }
                          }
                      }
                  }
                  function executeWithGuardBatch(ExecuteParams[] memory _params) internal {
                      address guard = getGuard();
                      uint256 length = _params.length;
                      if (guard == address(0)) {
                          for (uint256 i = 0; i < length; ) {
                              ExecuteParams memory param = _params[i];
                              bool success = execute(param, Enum.Operation.Call, gasleft());
                              if (success) {
                                  emit HandleSuccessExternalCalls();
                              }
                              if (param.nestedCalls.length > 0) {
                                  try this.execTransactionBatch(param.nestedCalls) {} catch (
                                      bytes memory returnData
                                  ) {
                                      emit HandleFailedExternalCalls(returnData);
                                  }
                              }
                              unchecked {
                                  ++i;
                              }
                          }
                      } else {
                          for (uint256 i = 0; i < length; ) {
                              ExecuteParams memory param = _params[i];
                              Guard(guard).checkTransaction(
                                  param.to,
                                  param.value,
                                  param.data,
                                  Enum.Operation.Call
                              );
                              bool success = execute(param, Enum.Operation.Call, gasleft());
                              if (success) {
                                  emit HandleSuccessExternalCalls();
                              }
                              Guard(guard).checkAfterExecution(success);
                              if (param.nestedCalls.length > 0) {
                                  try this.execTransactionBatch(param.nestedCalls) {} catch (
                                      bytes memory returnData
                                  ) {
                                      emit HandleFailedExternalCalls(returnData);
                                  }
                              }
                              unchecked {
                                  ++i;
                              }
                          }
                      }
                  }
              }
              // SPDX-License-Identifier: LGPL-3.0-only
              pragma solidity ^0.8.12;
              import "../common/Enum.sol";
              import "../common/SelfAuthorized.sol";
              import "./Executor.sol";
              /// @title Module Manager - A contract that manages modules that can execute transactions via this contract
              contract ModuleManager is SelfAuthorized, Executor {
                  event EnabledModule(address module);
                  event DisabledModule(address module);
                  event ExecutionFromModuleSuccess(address module);
                  event ExecutionFromModuleFailure(address module);
                  address internal constant SENTINEL_MODULES = address(0x1);
                  mapping(address => address) internal modules;
                  function initializeModules() internal {
                      modules[SENTINEL_MODULES] = SENTINEL_MODULES;
                  }
                  function enableModule(address module) public authorized {
                      // Module address cannot be null or sentinel.
                      require(module != address(0) && module != SENTINEL_MODULES, "GS101");
                      // Module cannot be added twice.
                      require(modules[module] == address(0), "GS102");
                      modules[module] = modules[SENTINEL_MODULES];
                      modules[SENTINEL_MODULES] = module;
                      emit EnabledModule(module);
                  }
                  /// @dev Allows to remove a module from the whitelist.
                  ///      This can only be done via a Safe transaction.
                  /// @notice Disables the module `module` for the Safe.
                  /// @param prevModule Module that pointed to the module to be removed in the linked list
                  /// @param module Module to be removed.
                  function disableModule(
                      address prevModule,
                      address module
                  ) public authorized {
                      // Validate module address and check that it corresponds to module index.
                      require(module != address(0) && module != SENTINEL_MODULES, "GS101");
                      require(modules[prevModule] == module, "GS103");
                      modules[prevModule] = modules[module];
                      modules[module] = address(0);
                      emit DisabledModule(module);
                  }
                  /// @dev Returns if an module is enabled
                  /// @return True if the module is enabled
                  function isModuleEnabled(address module) public view returns (bool) {
                      return SENTINEL_MODULES != module && modules[module] != address(0);
                  }
                  /// @dev Allows a Module to execute a Safe transaction without any further confirmations.
                  /// @param to Destination address of module transaction.
                  /// @param value Ether value of module transaction.
                  /// @param data Data payload of module transaction.
                  /// @param operation Operation type of module transaction.
                  function execTransactionFromModule(
                      address to,
                      uint256 value,
                      bytes calldata data,
                      Enum.Operation operation
                  ) public virtual {
                      // Only whitelisted modules are allowed.
                      require(modules[msg.sender] != address(0), "GS104");
                      // Execute transaction without further confirmations.
                      if (
                          execute(
                              ExecuteParams(false, to, value, data, ""),
                              operation,
                              gasleft()
                          )
                      ) emit ExecutionFromModuleSuccess(msg.sender);
                      else emit ExecutionFromModuleFailure(msg.sender);
                  }
                  /// @dev Allows a Module to execute a Safe transaction without any further confirmations and return data
                  /// @param to Destination address of module transaction.
                  /// @param value Ether value of module transaction.
                  /// @param data Data payload of module transaction.
                  /// @param operation Operation type of module transaction.
                  function execTransactionFromModuleReturnData(
                      address to,
                      uint256 value,
                      bytes calldata data,
                      Enum.Operation operation
                  ) public returns (bytes memory returnData) {
                      execTransactionFromModule(to, value, data, operation);
                      // solhint-disable-next-line no-inline-assembly
                      assembly {
                          // Load free memory location
                          let ptr := mload(0x40)
                          // We allocate memory for the return data by setting the free memory location to
                          // current free memory location + data size + 32 bytes for data size value
                          mstore(0x40, add(ptr, add(returndatasize(), 0x20)))
                          // Store the size
                          mstore(ptr, returndatasize())
                          // Store the data
                          returndatacopy(add(ptr, 0x20), 0, returndatasize())
                          // Point the return data to the correct memory location
                          returnData := ptr
                      }
                  }
              }
              // SPDX-License-Identifier: LGPL-3.0-only
              pragma solidity ^0.8.12;
              contract OwnerManager {
                  event AAOwnerSet(address owner);
                  address internal owner;
                  uint256 private nonce;
                  modifier onlyOwner() {
                      require(isOwner(msg.sender), "not call by owner");
                      _;
                  }
                  function initializeOwners(address _owner) internal {
                      owner = _owner;
                      emit AAOwnerSet(_owner);
                  }
                  function isOwner(address _owner) public view returns (bool) {
                      return owner == _owner;
                  }
                  function getOwner() public view returns (address) {
                      return owner;
                  }
              }
              // SPDX-License-Identifier: GPL-3.0
              pragma solidity ^0.8.12;
              import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
              import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
              import "../../@eth-infinitism-v0.6/core/BaseAccount.sol";
              import "../common/Enum.sol";
              import "../common/SignatureDecoder.sol";
              import "./OwnerManager.sol";
              contract SignatureManager is BaseAccount, Enum, OwnerManager, SignatureDecoder {
                  using UserOperationLib for UserOperation;
                  IEntryPoint internal immutable ENTRYPOINT;
                  bytes32 internal immutable HASH_NAME;
                  bytes32 internal immutable HASH_VERSION;
                  bytes32 internal immutable TYPE_HASH;
                  address internal immutable ADDRESS_THIS;
                  bytes32 internal immutable EIP712_ORDER_STRUCT_SCHEMA_HASH;
                  // keccak256("isValidSignature(bytes32 _hash)")
                  bytes32 public constant ERC1271_TYPE_HASH = 0x0c000213b8f2b5d6b75cba966002ab299d4108f2bf3d1dd73953ad6092f72e75;
                  struct SignMessage {
                      address sender;
                      uint256 nonce;
                      bytes initCode;
                      bytes callData;
                      uint256 callGasLimit;
                      uint256 verificationGasLimit;
                      uint256 preVerificationGas;
                      uint256 maxFeePerGas;
                      uint256 maxPriorityFeePerGas;
                      bytes paymasterAndData;
                      address EntryPoint;
                      uint256 sigTime;
                  }
                  /* solhint-enable var-name-mixedcase */
                  constructor(address entrypoint, string memory name, string memory version) {
                      ENTRYPOINT = IEntryPoint(entrypoint);
                      HASH_NAME = keccak256(bytes(name));
                      HASH_VERSION = keccak256(bytes(version));
                      TYPE_HASH = keccak256(
                          "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                      );
                      ADDRESS_THIS = address(this);
                      EIP712_ORDER_STRUCT_SCHEMA_HASH = keccak256(
                          abi.encodePacked(
                              "SignMessage(",
                              "address sender,",
                              "uint256 nonce,",
                              "bytes initCode,",
                              "bytes callData,",
                              "uint256 callGasLimit,",
                              "uint256 verificationGasLimit,",
                              "uint256 preVerificationGas,",
                              "uint256 maxFeePerGas,",
                              "uint256 maxPriorityFeePerGas,",
                              "bytes paymasterAndData,",
                              "address EntryPoint,",
                              "uint256 sigTime",
                              ")"
                          )
                      );
                  }
                  function getUOPHash(
                      SignatureType sigType,
                      address EntryPoint,
                      UserOperation calldata userOp
                  ) public view returns (bytes32) {
                      return
                          keccak256(
                              abi.encode(
                                  sigType == SignatureType.EIP712Type
                                      ? EIP712_ORDER_STRUCT_SCHEMA_HASH
                                      : bytes32(block.chainid),
                                  userOp.getSender(),
                                  userOp.nonce,
                                  keccak256(userOp.initCode),
                                  keccak256(userOp.callData),
                                  userOp.callGasLimit,
                                  userOp.verificationGasLimit,
                                  userOp.preVerificationGas,
                                  userOp.maxFeePerGas,
                                  userOp.maxPriorityFeePerGas,
                                  keccak256(userOp.paymasterAndData),
                                  EntryPoint,
                                  uint256(bytes32(userOp.signature[1:33]))
                              )
                          );
                  }
                  function getUOPSignedHash(
                      SignatureType sigType,
                      address EntryPoint,
                      UserOperation calldata userOp
                  ) public view returns (bytes32) {
                      return
                          sigType == SignatureType.EIP712Type
                              ? ECDSA.toTypedDataHash(
                                  keccak256(
                                      abi.encode(
                                          TYPE_HASH,
                                          HASH_NAME,
                                          HASH_VERSION,
                                          block.chainid,
                                          ADDRESS_THIS
                                      )
                                  ),
                                  keccak256(
                                      abi.encode(
                                          EIP712_ORDER_STRUCT_SCHEMA_HASH,
                                          userOp.getSender(),
                                          userOp.nonce,
                                          keccak256(userOp.initCode),
                                          keccak256(userOp.callData),
                                          userOp.callGasLimit,
                                          userOp.verificationGasLimit,
                                          userOp.preVerificationGas,
                                          userOp.maxFeePerGas,
                                          userOp.maxPriorityFeePerGas,
                                          keccak256(userOp.paymasterAndData),
                                          EntryPoint,
                                          uint256(bytes32(userOp.signature[1:33]))
                                      )
                                  )
                              )
                              : ECDSA.toEthSignedMessageHash(
                                  keccak256(
                                      abi.encode(
                                          bytes32(block.chainid),
                                          userOp.getSender(),
                                          userOp.nonce,
                                          keccak256(userOp.initCode),
                                          keccak256(userOp.callData),
                                          userOp.callGasLimit,
                                          userOp.verificationGasLimit,
                                          userOp.preVerificationGas,
                                          userOp.maxFeePerGas,
                                          userOp.maxPriorityFeePerGas,
                                          keccak256(userOp.paymasterAndData),
                                          EntryPoint,
                                          uint256(bytes32(userOp.signature[1:33]))
                                      )
                                  )
                              );
                  }
                  function validateUserOp(
                      UserOperation calldata userOp,
                      bytes32,
                      uint256 missingAccountFunds
                  ) public virtual override returns (uint256) {
                      if (missingAccountFunds != 0) {
                          payable(msg.sender).call{
                              value: missingAccountFunds,
                              gas: type(uint256).max
                          }("");
                      }
                      return
                          _validateSignature(
                              userOp,
                              getUOPSignedHash(
                                  SignatureType(uint8(bytes1(userOp.signature[0:1]))),
                                  msg.sender,
                                  userOp
                              )
                          );
                  }
                  function _validateSignature(
                      UserOperation calldata userOp,
                      bytes32 userOpHash
                  ) internal virtual override returns (uint256 validationData) {
                      uint256 sigTime = uint256(bytes32(userOp.signature[1:33]));
                      uint formatSigTime = _formatSigtimeToValidationData(sigTime);
                      if (ECDSA.recover(userOpHash, userOp.signature[33:]) != owner) {
                          return SIG_VALIDATION_FAILED;
                      } else {
                          return formatSigTime;
                      }
                  }
                  /// @dev format sigtime to validationData struct
                  /// @param sigTime: 0x[address 20 bytes][after 6 bytes][until 6 bytes]
                  /// @return data: ValidationData
                  function _formatSigtimeToValidationData(
                      uint256 sigTime
                  ) private pure returns (uint256) {
                      uint48 validUntil = uint48(sigTime);
                      if (validUntil == 0) {
                          validUntil = type(uint48).max;
                      }
                      uint48 validAfter = uint48(sigTime >> 48);
                      address aggregator = address(uint160(sigTime >> (48 + 48)));
                      return
                          _packValidationData(
                              ValidationData(aggregator, validAfter, validUntil)
                          );
                  }
                  function entryPoint() public view virtual override returns (IEntryPoint) {
                      return ENTRYPOINT;
                  }
                  function getERC1271SignInfo() external view returns (bytes32, bytes32, bytes32) {
                      return (HASH_NAME, HASH_VERSION, ERC1271_TYPE_HASH);
                  }
                  function isValidSignature(
                      bytes32 _hash,
                      bytes calldata _signature
                  ) external view returns (bytes4) {
                      bytes32 domainSeparator = keccak256(abi.encode(
                          TYPE_HASH,
                          HASH_NAME,
                          HASH_VERSION,
                          bytes32(block.chainid),
                          address(this)
                      ));
                      bytes32 boundHash = keccak256(abi.encode(
                          ERC1271_TYPE_HASH,
                          _hash
                      ));
                      bytes32 digest = keccak256(abi.encodePacked(
                          "\\x19\\x01",
                          domainSeparator,
                          boundHash
                      ));
                      address signer = ECDSA.recover(digest, _signature);
                      if (isOwner(signer)) {
                          return 0x1626ba7e;
                      } else {
                          return 0xffffffff;
                      }
                  }
              }
              // SPDX-License-Identifier: LGPL-3.0-only
              pragma solidity ^0.8.12;
              /// @title Enum - Collection of enums
              contract Enum {
                  enum Operation {
                      Call,
                      DelegateCall
                  }
                  enum SignatureType {
                      EIP712Type,
                      EIP191Type
                  }
              }
              // SPDX-License-Identifier: LGPL-3.0-only
              pragma solidity ^0.8.12;
              /// @title EtherPaymentFallback - A contract that has a fallback to accept ether payments
              /// @author Richard Meissner - <[email protected]>
              contract EtherPaymentFallback {
                  event SafeReceived(address indexed sender, uint256 value);
                  /// @dev Fallback function accepts Ether transactions.
                  receive() external payable {
                      emit SafeReceived(msg.sender, msg.value);
                  }
              }
              // SPDX-License-Identifier: LGPL-3.0-only
              pragma solidity ^0.8.12;
              /// @title SecuredTokenTransfer - Secure token transfer
              /// @author Richard Meissner - <[email protected]>
              contract SecuredTokenTransfer {
                  /// @dev Transfers a token and returns if it was a success
                  /// @param token Token that should be transferred
                  /// @param receiver Receiver to whom the token should be transferred
                  /// @param amount The amount of tokens that should be transferred
                  function transferToken(
                      address token,
                      address receiver,
                      uint256 amount
                  ) internal returns (bool transferred) {
                      // 0xa9059cbb - keccack("transfer(address,uint256)")
                      bytes memory data = abi.encodeWithSelector(
                          0xa9059cbb,
                          receiver,
                          amount
                      );
                      // solhint-disable-next-line no-inline-assembly
                      assembly {
                          // We write the return value to scratch space.
                          // See https://docs.soliditylang.org/en/v0.7.6/internals/layout_in_memory.html#layout-in-memory
                          let success := call(
                              sub(gas(), 10000),
                              token,
                              0,
                              add(data, 0x20),
                              mload(data),
                              0,
                              0x20
                          )
                          switch returndatasize()
                          case 0 {
                              transferred := success
                          }
                          case 0x20 {
                              transferred := iszero(or(iszero(success), iszero(mload(0))))
                          }
                          default {
                              transferred := 0
                          }
                      }
                  }
              }
              // SPDX-License-Identifier: LGPL-3.0-only
              pragma solidity ^0.8.12;
              /// @title SelfAuthorized - authorizes current contract to perform actions
              /// @author Richard Meissner - <[email protected]>
              contract SelfAuthorized {
                  function requireSelfCall() private view {
                      require(msg.sender == address(this), "GS031");
                  }
                  modifier authorized() {
                      // This is a function call as it minimized the bytecode size
                      requireSelfCall();
                      _;
                  }
              }
              // SPDX-License-Identifier: LGPL-3.0-only
              pragma solidity ^0.8.12;
              /// @title SignatureDecoder - Decodes signatures that a encoded as bytes
              /// @author Richard Meissner - <[email protected]>
              contract SignatureDecoder {
                  /// @dev divides bytes signature into `uint8 v, bytes32 r, bytes32 s`.
                  /// @notice Make sure to peform a bounds check for @param pos, to avoid out of bounds access on @param signatures
                  /// @param pos which signature to read. A prior bounds check of this parameter should be performed, to avoid out of bounds access
                  /// @param signatures concatenated rsv signatures
                  function signatureSplit(
                      bytes memory signatures,
                      uint256 pos
                  ) internal pure returns (uint8 v, bytes32 r, bytes32 s) {
                      // The signature format is a compact form of:
                      //   {bytes32 r}{bytes32 s}{uint8 v}
                      // Compact means, uint8 is not padded to 32 bytes.
                      // solhint-disable-next-line no-inline-assembly
                      assembly {
                          let signaturePos := mul(0x41, pos)
                          r := mload(add(signatures, add(signaturePos, 0x20)))
                          s := mload(add(signatures, add(signaturePos, 0x40)))
                          // Here we are loading the last 32 bytes, including 31 bytes
                          // of 's'. There is no 'mload8' to do this.
                          //
                          // 'byte' is not working due to the Solidity parser, so lets
                          // use the second best option, 'and'
                          v := and(mload(add(signatures, add(signaturePos, 0x41))), 0xff)
                      }
                  }
              }
              // SPDX-License-Identifier: LGPL-3.0-only
              pragma solidity ^0.8.12;
              import "./SelfAuthorized.sol";
              /// @title Singleton - Base for singleton contracts (should always be first super contract)
              ///         This contract is tightly coupled to our proxy contract
              contract Singleton is SelfAuthorized {
                  event ImplementUpdated(address indexed implement);
                  address internal singleton;
                  function updateImplement(address implement) external authorized {
                      singleton = implement;
                      emit ImplementUpdated(implement);
                  }
                  function updateImplementAndCall(
                      address implement,
                      bytes calldata data
                  ) external authorized {
                      singleton = implement;
                      emit ImplementUpdated(implement);
                      (bool success, ) = implement.delegatecall(data);
                      require(success, "Update implementation failed");
                  }
              }
              // SPDX-License-Identifier: LGPL-3.0-only
              pragma solidity ^0.8.12;
              import "../../interfaces/IValidations.sol";
              import "../base/SignatureManager.sol";
              import "../base/ModuleManager.sol";
              import "../base/OwnerManager.sol";
              import "../base/FallbackManager.sol";
              import "../base/GuardManager.sol";
              import "../common/EtherPaymentFallback.sol";
              import "../common/Singleton.sol";
              import "../common/SignatureDecoder.sol";
              import "../common/SecuredTokenTransfer.sol";
              contract SmartAccountV2 is
                  EtherPaymentFallback,
                  Singleton,
                  ModuleManager,
                  OwnerManager,
                  SignatureDecoder,
                  SecuredTokenTransfer,
                  FallbackManager,
                  GuardManager,
                  SignatureManager
              {
                  IValidations public immutable VALIDATIONS;
                  address public immutable FALLBACKHANDLER;
                  constructor(
                      address _entryPoint,
                      address _fallbackHandler,
                      address _validations,
                      string memory _name,
                      string memory _version
                  ) SignatureManager(_entryPoint, _name, _version) {
                      FALLBACKHANDLER = _fallbackHandler;
                      VALIDATIONS = IValidations(_validations);
                  }
                  modifier onlyEntryPoint() {
                      require(msg.sender == address(entryPoint()), "Not from entrypoint");
                      _;
                  }
                  modifier onlyWhiteListedBundler() {
                      VALIDATIONS.validateBundlerWhiteList(tx.origin);
                      _;
                  }
                  modifier onlyWhiteListedModule() {
                      VALIDATIONS.validateModuleWhitelist(msg.sender);
                      _;
                  }
                  function initialize(
                      address creator,
                      bytes memory /* place holder for future */
                  ) external {
                      require(getOwner() == address(0), "account: have set up");
                      // set creator as owner by default.
                      initializeOwners(creator);
                      initializeFallbackHandler(FALLBACKHANDLER);
                      initializeModules();
                  }
                  function nonce() public view virtual returns (uint256) {
                      return ENTRYPOINT.getNonce(address(this), 0);
                  }
                  function validateUserOp(
                      UserOperation calldata userOp,
                      bytes32 userOpHash,
                      uint256 missingAccountFunds
                  )
                      public
                      override
                      onlyEntryPoint
                      onlyWhiteListedBundler
                      returns (uint256 validationData)
                  {
                      validationData = super.validateUserOp(
                          userOp,
                          userOpHash,
                          missingAccountFunds
                      );
                  }
                  function execTransactionFromEntrypoint(
                      address to,
                      uint256 value,
                      bytes calldata data
                  ) public onlyEntryPoint {
                      executeWithGuard(to, value, data);
                  }
                  function execTransactionFromEntrypointBatch(
                      ExecuteParams[] calldata _params
                  ) external onlyEntryPoint {
                      executeWithGuardBatch(_params);
                  }
                  function execTransactionFromEntrypointBatchRevertOnFail(
                      ExecuteParams[] calldata _params
                  ) external onlyEntryPoint {
                      execTransactionBatchRevertOnFail(_params);
                  }
                  function execTransactionFromModule(
                      address to,
                      uint256 value,
                      bytes calldata data,
                      Enum.Operation operation
                  ) public override onlyWhiteListedModule {
                      if (operation == Enum.Operation.Call) {
                          ModuleManager.execTransactionFromModule(to, value, data, operation);
                      } else {
                          address originalFallbackHandler = getFallbackHandler();
                          setFallbackHandler(msg.sender, true);
                          ModuleManager.execTransactionFromModule(to, value, data, operation);
                          setFallbackHandler(originalFallbackHandler, false);
                      }
                  }
              }