ETH Price: $2,151.58 (+1.36%)

Transaction Decoder

Block:
24701458 at Mar-20-2026 09:39:23 PM +UTC
Transaction Fee:
0.000012973759109756 ETH $0.03
Gas Used:
116,629 Gas / 0.111239564 Gwei

Emitted Events:

574 EntryPoint.Deposited( account=0xfd723b24ee639d12ac1d612f6f04a0c634835354, totalDeposit=26221813596626 )
575 EntryPoint.BeforeExecution( )
576 Ondo.Approval( owner=0xfd723b24ee639d12ac1d612f6f04a0c634835354, spender=0x69460570...25f0Ca22d, amount=404428195392591647006 )
577 EntryPoint.UserOperationEvent( userOpHash=11F9629AA814F0B48A0A591C42880507144F28961F23D53A341C27E89752C2A4, sender=0xfd723b24ee639d12ac1d612f6f04a0c634835354, paymaster=0x00000000...000000000, nonce=1, success=True, actualGasCost=14414293003524, actualGasUsed=118891 )

Account State Difference:

  Address   Before After State Difference Code
0x00000000...6f37da032
(Entry Point 0.7.0)
81.724616694345584847 Eth81.724617799693843768 Eth0.000001105348258921
0x3f5EADFD...9C66E9F5D
(Bundler: 0x3f5...f5d)
1.561843805055057038 Eth
Nonce: 15316
1.561845245588950806 Eth
Nonce: 15317
0.000001440533893768
(Titan Builder)
16.312276294513112236 Eth16.312282125963112236 Eth0.00000583145
0xfAbA6f8e...577269BE3
0xfD723b24...634835354 0.137655827990928768 Eth0.137640308349666323 Eth0.000015519641262445

Execution Trace

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

          File 2 of 3: Ondo
          // SPDX-License-Identifier: AGPL-3.0
          pragma solidity 0.8.3;
          /*
           * @dev Provides information about the current execution context, including the
           * sender of the transaction and its data. While these are generally available
           * via msg.sender and msg.data, they should not be accessed in such a direct
           * manner, since when dealing with meta-transactions the account sending and
           * paying for execution may not be the actual sender (as far as an application
           * is concerned).
           *
           * This contract is only required for intermediate, library-like contracts.
           */
          abstract contract Context {
            function _msgSender() internal view virtual returns (address) {
              return msg.sender;
            }
            function _msgData() internal view virtual returns (bytes calldata) {
              this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
              return msg.data;
            }
          }
          /**
           * @dev Interface of the ERC165 standard, as defined in the
           * https://eips.ethereum.org/EIPS/eip-165[EIP].
           *
           * Implementers can declare support of contract interfaces, which can then be
           * queried by others ({ERC165Checker}).
           *
           * For an implementation, see {ERC165}.
           */
          interface IERC165 {
            /**
             * @dev Returns true if this contract implements the interface defined by
             * `interfaceId`. See the corresponding
             * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
             * to learn more about how these ids are created.
             *
             * This function call must use less than 30 000 gas.
             */
            function supportsInterface(bytes4 interfaceId) external view returns (bool);
          }
          /**
           * @dev Implementation of the {IERC165} interface.
           *
           * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
           * for the additional interface id that will be supported. For example:
           *
           * ```solidity
           * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
           *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
           * }
           * ```
           *
           * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
           */
          abstract contract ERC165 is IERC165 {
            /**
             * @dev See {IERC165-supportsInterface}.
             */
            function supportsInterface(bytes4 interfaceId)
              public
              view
              virtual
              override
              returns (bool)
            {
              return interfaceId == type(IERC165).interfaceId;
            }
          }
          /**
           * @dev External interface of AccessControl declared to support ERC165 detection.
           */
          interface IAccessControl {
            function hasRole(bytes32 role, address account) external view returns (bool);
            function getRoleAdmin(bytes32 role) external view returns (bytes32);
            function grantRole(bytes32 role, address account) external;
            function revokeRole(bytes32 role, address account) external;
            function renounceRole(bytes32 role, address account) external;
          }
          /**
           * @dev Contract module that allows children to implement role-based access
           * control mechanisms. This is a lightweight version that doesn't allow enumerating role
           * members except through off-chain means by accessing the contract event logs. Some
           * applications may benefit from on-chain enumerability, for those cases see
           * {AccessControlEnumerable}.
           *
           * Roles are referred to by their `bytes32` identifier. These should be exposed
           * in the external API and be unique. The best way to achieve this is by
           * using `public constant` hash digests:
           *
           * ```
           * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
           * ```
           *
           * Roles can be used to represent a set of permissions. To restrict access to a
           * function call, use {hasRole}:
           *
           * ```
           * function foo() public {
           *     require(hasRole(MY_ROLE, msg.sender));
           *     ...
           * }
           * ```
           *
           * Roles can be granted and revoked dynamically via the {grantRole} and
           * {revokeRole} functions. Each role has an associated admin role, and only
           * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
           *
           * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
           * that only accounts with this role will be able to grant or revoke other
           * roles. More complex role relationships can be created by using
           * {_setRoleAdmin}.
           *
           * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
           * grant and revoke this role. Extra precautions should be taken to secure
           * accounts that have been granted it.
           */
          abstract contract AccessControl is Context, IAccessControl, ERC165 {
            struct RoleData {
              mapping(address => bool) members;
              bytes32 adminRole;
            }
            mapping(bytes32 => RoleData) private _roles;
            bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
            /**
             * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
             *
             * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
             * {RoleAdminChanged} not being emitted signaling this.
             *
             * _Available since v3.1._
             */
            event RoleAdminChanged(
              bytes32 indexed role,
              bytes32 indexed previousAdminRole,
              bytes32 indexed newAdminRole
            );
            /**
             * @dev Emitted when `account` is granted `role`.
             *
             * `sender` is the account that originated the contract call, an admin role
             * bearer except when using {_setupRole}.
             */
            event RoleGranted(
              bytes32 indexed role,
              address indexed account,
              address indexed sender
            );
            /**
             * @dev Emitted when `account` is revoked `role`.
             *
             * `sender` is the account that originated the contract call:
             *   - if using `revokeRole`, it is the admin role bearer
             *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
             */
            event RoleRevoked(
              bytes32 indexed role,
              address indexed account,
              address indexed sender
            );
            /**
             * @dev See {IERC165-supportsInterface}.
             */
            function supportsInterface(bytes4 interfaceId)
              public
              view
              virtual
              override
              returns (bool)
            {
              return
                interfaceId == type(IAccessControl).interfaceId ||
                super.supportsInterface(interfaceId);
            }
            /**
             * @dev Returns `true` if `account` has been granted `role`.
             */
            function hasRole(bytes32 role, address account)
              public
              view
              override
              returns (bool)
            {
              return _roles[role].members[account];
            }
            /**
             * @dev Returns the admin role that controls `role`. See {grantRole} and
             * {revokeRole}.
             *
             * To change a role's admin, use {_setRoleAdmin}.
             */
            function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
              return _roles[role].adminRole;
            }
            /**
             * @dev Grants `role` to `account`.
             *
             * If `account` had not been already granted `role`, emits a {RoleGranted}
             * event.
             *
             * Requirements:
             *
             * - the caller must have ``role``'s admin role.
             */
            function grantRole(bytes32 role, address account) public virtual override {
              require(
                hasRole(getRoleAdmin(role), _msgSender()),
                "AccessControl: sender must be an admin to grant"
              );
              _grantRole(role, account);
            }
            /**
             * @dev Revokes `role` from `account`.
             *
             * If `account` had been granted `role`, emits a {RoleRevoked} event.
             *
             * Requirements:
             *
             * - the caller must have ``role``'s admin role.
             */
            function revokeRole(bytes32 role, address account) public virtual override {
              require(
                hasRole(getRoleAdmin(role), _msgSender()),
                "AccessControl: sender must be an admin to revoke"
              );
              _revokeRole(role, account);
            }
            /**
             * @dev Revokes `role` from the calling account.
             *
             * Roles are often managed via {grantRole} and {revokeRole}: this function's
             * purpose is to provide a mechanism for accounts to lose their privileges
             * if they are compromised (such as when a trusted device is misplaced).
             *
             * If the calling account had been granted `role`, emits a {RoleRevoked}
             * event.
             *
             * Requirements:
             *
             * - the caller must be `account`.
             */
            function renounceRole(bytes32 role, address account) public virtual override {
              require(
                account == _msgSender(),
                "AccessControl: can only renounce roles for self"
              );
              _revokeRole(role, account);
            }
            /**
             * @dev Grants `role` to `account`.
             *
             * If `account` had not been already granted `role`, emits a {RoleGranted}
             * event. Note that unlike {grantRole}, this function doesn't perform any
             * checks on the calling account.
             *
             * [WARNING]
             * ====
             * This function should only be called from the constructor when setting
             * up the initial roles for the system.
             *
             * Using this function in any other way is effectively circumventing the admin
             * system imposed by {AccessControl}.
             * ====
             */
            function _setupRole(bytes32 role, address account) internal virtual {
              _grantRole(role, account);
            }
            /**
             * @dev Sets `adminRole` as ``role``'s admin role.
             *
             * Emits a {RoleAdminChanged} event.
             */
            function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
              emit RoleAdminChanged(role, getRoleAdmin(role), adminRole);
              _roles[role].adminRole = adminRole;
            }
            function _grantRole(bytes32 role, address account) private {
              if (!hasRole(role, account)) {
                _roles[role].members[account] = true;
                emit RoleGranted(role, account, _msgSender());
              }
            }
            function _revokeRole(bytes32 role, address account) private {
              if (hasRole(role, account)) {
                _roles[role].members[account] = false;
                emit RoleRevoked(role, account, _msgSender());
              }
            }
          }
          interface IOndo {
            enum InvestorType {CoinlistTranche1, CoinlistTranche2, SeedTranche}
            // ----------- State changing api -----------
            /// @notice Called by timelock contract to initialize locked balance of coinlist/seed investor
            function updateTrancheBalance(
              address beneficiary,
              uint256 rawAmount,
              InvestorType tranche
            ) external;
            // ----------- Getters -----------
            /// @notice Gets the TOTAL amount of Ondo available for an address
            function getFreedBalance(address account) external view returns (uint96);
            /// @notice Gets the initial locked balance and unlocked Ondo for an address
            function getVestedBalance(address account)
              external
              view
              returns (uint96, uint96);
          }
          abstract contract LinearTimelock {
            struct InvestorParam {
              IOndo.InvestorType investorType;
              uint96 initialBalance;
            }
            /// @notice the timestamp at which releasing is allowed
            uint256 public cliffTimestamp;
            /// @notice the linear vesting period for the first tranche
            uint256 public immutable tranche1VestingPeriod;
            /// @notice the linear vesting period for the second tranche
            uint256 public immutable tranche2VestingPeriod;
            /// @notice the linear vesting period for the Seed/Series A Tranche
            uint256 public immutable seedVestingPeriod;
            /// @dev mapping of balances for each investor
            mapping(address => InvestorParam) internal investorBalances;
            /// @notice role that allows updating of tranche balances - granted to Merkle airdrop contract
            bytes32 public constant TIMELOCK_UPDATE_ROLE =
              keccak256("TIMELOCK_UPDATE_ROLE");
            constructor(
              uint256 _cliffTimestamp,
              uint256 _tranche1VestingPeriod,
              uint256 _tranche2VestingPeriod,
              uint256 _seedVestingPeriod
            ) {
              cliffTimestamp = _cliffTimestamp;
              tranche1VestingPeriod = _tranche1VestingPeriod;
              tranche2VestingPeriod = _tranche2VestingPeriod;
              seedVestingPeriod = _seedVestingPeriod;
            }
            function passedCliff() public view returns (bool) {
              return block.timestamp > cliffTimestamp;
            }
            /// @dev the seedVestingPeriod is the longest vesting period
            function passedAllVestingPeriods() public view returns (bool) {
              return block.timestamp > cliffTimestamp + seedVestingPeriod;
            }
            /**
              @notice View function to get the user's initial balance and current amount of freed balance
             */
            function getVestedBalance(address account)
              external
              view
              returns (uint256, uint256)
            {
              if (investorBalances[account].initialBalance == 0) {
                return (0, 0);
              }
              InvestorParam memory investorParam = investorBalances[account];
              uint96 amountAvailable;
              if (passedAllVestingPeriods()) {
                amountAvailable = investorParam.initialBalance;
              } else if (passedCliff()) {
                (uint256 vestingPeriod, uint256 elapsed) =
                  _getTrancheInfo(investorParam.investorType);
                amountAvailable = _proportionAvailable(
                  elapsed,
                  vestingPeriod,
                  investorParam
                );
              } else {
                amountAvailable = 0;
              }
              return (investorParam.initialBalance, amountAvailable);
            }
            function _getTrancheInfo(IOndo.InvestorType investorType)
              internal
              view
              returns (uint256 vestingPeriod, uint256 elapsed)
            {
              elapsed = block.timestamp - cliffTimestamp;
              if (investorType == IOndo.InvestorType.CoinlistTranche1) {
                elapsed = elapsed > tranche1VestingPeriod
                  ? tranche1VestingPeriod
                  : elapsed;
                vestingPeriod = tranche1VestingPeriod;
              } else if (investorType == IOndo.InvestorType.CoinlistTranche2) {
                elapsed = elapsed > tranche2VestingPeriod
                  ? tranche2VestingPeriod
                  : elapsed;
                vestingPeriod = tranche2VestingPeriod;
              } else if (investorType == IOndo.InvestorType.SeedTranche) {
                elapsed = elapsed > seedVestingPeriod ? seedVestingPeriod : elapsed;
                vestingPeriod = seedVestingPeriod;
              }
            }
            function _proportionAvailable(
              uint256 elapsed,
              uint256 vestingPeriod,
              InvestorParam memory investorParam
            ) internal pure returns (uint96) {
              if (investorParam.investorType == IOndo.InvestorType.SeedTranche) {
                // Seed/Series A Tranche Balance = proportionAvail*2/3 + x/3, where x = Balance. This allows 1/3 of the series A balance to be unlocked at cliff
                uint96 vestedAmount =
                  safe96(
                    (((investorParam.initialBalance * elapsed) / vestingPeriod) * 2) / 3,
                    "Ondo::_proportionAvailable: amount exceeds 96 bits"
                  );
                return
                  add96(
                    vestedAmount,
                    investorParam.initialBalance / 3,
                    "Ondo::_proportionAvailable: overflow"
                  );
              } else {
                return
                  safe96(
                    (investorParam.initialBalance * elapsed) / vestingPeriod,
                    "Ondo::_proportionAvailable: amount exceeds 96 bits"
                  );
              }
            }
            function safe32(uint256 n, string memory errorMessage)
              internal
              pure
              returns (uint32)
            {
              require(n < 2**32, errorMessage);
              return uint32(n);
            }
            function safe96(uint256 n, string memory errorMessage)
              internal
              pure
              returns (uint96)
            {
              require(n < 2**96, errorMessage);
              return uint96(n);
            }
            function add96(
              uint96 a,
              uint96 b,
              string memory errorMessage
            ) internal pure returns (uint96) {
              uint96 c = a + b;
              require(c >= a, errorMessage);
              return c;
            }
            function sub96(
              uint96 a,
              uint96 b,
              string memory errorMessage
            ) internal pure returns (uint96) {
              require(b <= a, errorMessage);
              return a - b;
            }
          }
          contract Ondo is AccessControl, LinearTimelock {
            /// @notice EIP-20 token name for this token
            string public constant name = "Ondo";
            /// @notice EIP-20 token symbol for this token
            string public constant symbol = "ONDO";
            /// @notice EIP-20 token decimals for this token
            uint8 public constant decimals = 18;
            // whether token transfers are allowed
            bool public transferAllowed; // false by default
            /// @notice Total number of tokens in circulation
            uint256 public totalSupply = 10_000_000_000e18; // 10 billion Ondo
            // Allowance amounts on behalf of others
            mapping(address => mapping(address => uint96)) internal allowances;
            // Official record of token balances for each account
            mapping(address => uint96) internal balances;
            /// @notice A record of each accounts delegate
            mapping(address => address) public delegates;
            /// @notice A checkpoint for marking number of votes from a given block
            struct Checkpoint {
              uint32 fromBlock;
              uint96 votes;
            }
            /// @notice A record of votes checkpoints for each account, by index
            mapping(address => mapping(uint32 => Checkpoint)) public checkpoints;
            /// @notice The number of checkpoints for each account
            mapping(address => uint32) public numCheckpoints;
            /// @notice The EIP-712 typehash for the contract's domain
            bytes32 public constant DOMAIN_TYPEHASH =
              keccak256(
                "EIP712Domain(string name,uint256 chainId,address verifyingContract)"
              );
            /// @notice The EIP-712 typehash for the delegation struct used by the contract
            bytes32 public constant DELEGATION_TYPEHASH =
              keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
            /// @notice The identifier of the role which allows special transfer privileges.
            bytes32 public constant TRANSFER_ROLE = keccak256("TRANSFER_ROLE");
            bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
            /// @notice A record of states for signing / validating signatures
            mapping(address => uint256) public nonces;
            /// @notice An event thats emitted when an account changes its delegate
            event DelegateChanged(
              address indexed delegator,
              address indexed fromDelegate,
              address indexed toDelegate
            );
            /// @notice An event thats emitted when a delegate account's vote balance changes
            event DelegateVotesChanged(
              address indexed delegate,
              uint256 previousBalance,
              uint256 newBalance
            );
            /// @notice The standard EIP-20 transfer event
            event Transfer(address indexed from, address indexed to, uint256 amount);
            /// @notice The standard EIP-20 approval event
            event Approval(
              address indexed owner,
              address indexed spender,
              uint256 amount
            );
            event CliffTimestampUpdate(uint256 newTimestamp);
            /**
             * @dev Emitted when the transfer is enabled triggered by `account`.
             */
            event TransferEnabled(address account);
            /// @notice a modifier which checks if transfers are allowed
            modifier whenTransferAllowed() {
              require(
                transferAllowed || hasRole(TRANSFER_ROLE, msg.sender),
                "OndoToken: Transfers not allowed or not right privillege"
              );
              _;
            }
            /**
             * @notice Construct a new Ondo token
             * @param _governance The initial account to grant owner permission and all the tokens
             */
            constructor(
              address _governance,
              uint256 _cliffTimestamp,
              uint256 _tranche1VestingPeriod,
              uint256 _tranche2VestingPeriod,
              uint256 _seedVestingPeriod
            )
              LinearTimelock(
                _cliffTimestamp,
                _tranche1VestingPeriod,
                _tranche2VestingPeriod,
                _seedVestingPeriod
              )
            {
              balances[_governance] = uint96(totalSupply);
              _setupRole(DEFAULT_ADMIN_ROLE, _governance);
              _setupRole(TRANSFER_ROLE, _governance);
              _setupRole(MINTER_ROLE, _governance);
              emit Transfer(address(0), _governance, totalSupply);
            }
            /**
             * @notice Get the number of tokens `spender` is approved to spend on behalf of `account`
             * @param account The address of the account holding the funds
             * @param spender The address of the account spending the funds
             * @return The number of tokens approved
             */
            function allowance(address account, address spender)
              external
              view
              returns (uint256)
            {
              return allowances[account][spender];
            }
            /**
             * @notice Approve `spender` to transfer up to `amount` from `src`
             * @dev This will overwrite the approval amount for `spender`
             *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
             * @param spender The address of the account which may transfer tokens
             * @param rawAmount The number of tokens that are approved (2^256-1 means infinite)
             * @return Whether or not the approval succeeded
             */
            function approve(address spender, uint256 rawAmount) external returns (bool) {
              uint96 amount;
              if (rawAmount == type(uint256).max) {
                amount = type(uint96).max;
              } else {
                amount = safe96(rawAmount, "Ondo::approve: amount exceeds 96 bits");
              }
              allowances[msg.sender][spender] = amount;
              emit Approval(msg.sender, spender, amount);
              return true;
            }
            /**
             * @notice Get the number of tokens held by the `account`
             * @param account The address of the account to get the balance of
             * @return The number of tokens held
             */
            function balanceOf(address account) external view returns (uint256) {
              return balances[account];
            }
            /**
             * @notice Get the total number of UNLOCKED tokens held by the `account`
             * @param account The address of the account to get the unlocked balance of
             * @return The number of unlocked tokens held.
             */
            function getFreedBalance(address account) external view returns (uint256) {
              if (investorBalances[account].initialBalance > 0) {
                return _getFreedBalance(account);
              } else {
                return balances[account];
              }
            }
            /**
             * @notice Transfer `amount` tokens from `msg.sender` to `dst`
             * @param dst The address of the destination account
             * @param rawAmount The number of tokens to transfer
             * @return Whether or not the transfer succeeded
             */
            function transfer(address dst, uint256 rawAmount) external returns (bool) {
              uint96 amount = safe96(rawAmount, "Ondo::transfer: amount exceeds 96 bits");
              _transferTokens(msg.sender, dst, amount);
              return true;
            }
            /**
             * @notice Transfer `amount` tokens from `src` to `dst`
             * @param src The address of the source account
             * @param dst The address of the destination account
             * @param rawAmount The number of tokens to transfer
             * @return Whether or not the transfer succeeded
             */
            function transferFrom(
              address src,
              address dst,
              uint256 rawAmount
            ) external returns (bool) {
              address spender = msg.sender;
              uint96 spenderAllowance = allowances[src][spender];
              uint96 amount = safe96(rawAmount, "Ondo::approve: amount exceeds 96 bits");
              if (spender != src && spenderAllowance != type(uint96).max) {
                uint96 newAllowance =
                  sub96(
                    spenderAllowance,
                    amount,
                    "Ondo::transferFrom: transfer amount exceeds spender allowance"
                  );
                allowances[src][spender] = newAllowance;
                emit Approval(src, spender, newAllowance);
              }
              _transferTokens(src, dst, amount);
              return true;
            }
            /**
             * @notice Delegate votes from `msg.sender` to `delegatee`
             * @param delegatee The address to delegate votes to
             */
            function delegate(address delegatee) public {
              return _delegate(msg.sender, delegatee);
            }
            /**
             * @notice Delegates votes from signatory to `delegatee`
             * @param delegatee The address to delegate votes to
             * @param nonce The contract state required to match the signature
             * @param expiry The time at which to expire the signature
             * @param v The recovery byte of the signature
             * @param r Half of the ECDSA signature pair
             * @param s Half of the ECDSA signature pair
             */
            function delegateBySig(
              address delegatee,
              uint256 nonce,
              uint256 expiry,
              uint8 v,
              bytes32 r,
              bytes32 s
            ) public {
              bytes32 domainSeparator =
                keccak256(
                  abi.encode(
                    DOMAIN_TYPEHASH,
                    keccak256(bytes(name)),
                    getChainId(),
                    address(this)
                  )
                );
              bytes32 structHash =
                keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry));
              bytes32 digest =
                keccak256(abi.encodePacked("\\x19\\x01", domainSeparator, structHash));
              address signatory = ecrecover(digest, v, r, s);
              require(signatory != address(0), "Ondo::delegateBySig: invalid signature");
              require(nonce == nonces[signatory]++, "Ondo::delegateBySig: invalid nonce");
              require(
                block.timestamp <= expiry,
                "Ondo::delegateBySig: signature expired"
              );
              return _delegate(signatory, delegatee);
            }
            /**
             * @notice Gets the current votes balance for `account`
             * @param account The address to get votes balance
             * @return The number of current votes for `account`
             */
            function getCurrentVotes(address account) external view returns (uint96) {
              uint32 nCheckpoints = numCheckpoints[account];
              return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;
            }
            /**
             * @notice Determine the prior number of votes for an account as of a block number
             * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
             * @param account The address of the account to check
             * @param blockNumber The block number to get the vote balance at
             * @return The number of votes the account had as of the given block
             */
            function getPriorVotes(address account, uint256 blockNumber)
              public
              view
              returns (uint96)
            {
              require(
                blockNumber < block.number,
                "Ondo::getPriorVotes: not yet determined"
              );
              uint32 nCheckpoints = numCheckpoints[account];
              if (nCheckpoints == 0) {
                return 0;
              }
              // First check most recent balance
              if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
                return checkpoints[account][nCheckpoints - 1].votes;
              }
              // Next check implicit zero balance
              if (checkpoints[account][0].fromBlock > blockNumber) {
                return 0;
              }
              uint32 lower = 0;
              uint32 upper = nCheckpoints - 1;
              while (upper > lower) {
                uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
                Checkpoint memory cp = checkpoints[account][center];
                if (cp.fromBlock == blockNumber) {
                  return cp.votes;
                } else if (cp.fromBlock < blockNumber) {
                  lower = center;
                } else {
                  upper = center - 1;
                }
              }
              return checkpoints[account][lower].votes;
            }
            /**
             * @notice Create `rawAmount` new tokens and assign them to `account`.
             * @param account The address to give newly minted tokens to
             * @param rawAmount Number of new tokens to mint.
             * @dev Even though total token supply is uint96, we use uint256 for the amount for consistency with other external interfaces.
             */
            function mint(address account, uint256 rawAmount) external {
              require(hasRole(MINTER_ROLE, msg.sender), "Ondo::mint: not authorized");
              require(account != address(0), "cannot mint to the zero address");
              uint96 amount = safe96(rawAmount, "Ondo::mint: amount exceeds 96 bits");
              uint96 supply =
                safe96(totalSupply, "Ondo::mint: totalSupply exceeds 96 bits");
              totalSupply = add96(supply, amount, "Ondo::mint: token supply overflow");
              balances[account] = add96(
                balances[account],
                amount,
                "Ondo::mint: balance overflow"
              );
              emit Transfer(address(0), account, amount);
            }
            function _delegate(address delegator, address delegatee) internal {
              address currentDelegate = delegates[delegator];
              uint96 delegatorBalance = balances[delegator];
              delegates[delegator] = delegatee;
              emit DelegateChanged(delegator, currentDelegate, delegatee);
              _moveDelegates(currentDelegate, delegatee, delegatorBalance);
            }
            function _transferTokens(
              address src,
              address dst,
              uint96 amount
            ) internal whenTransferAllowed {
              require(
                src != address(0),
                "Ondo::_transferTokens: cannot transfer from the zero address"
              );
              require(
                dst != address(0),
                "Ondo::_transferTokens: cannot transfer to the zero address"
              );
              if (investorBalances[src].initialBalance > 0) {
                require(
                  amount <= _getFreedBalance(src),
                  "Ondo::_transferTokens: not enough unlocked balance"
                );
              }
              balances[src] = sub96(
                balances[src],
                amount,
                "Ondo::_transferTokens: transfer amount exceeds balance"
              );
              balances[dst] = add96(
                balances[dst],
                amount,
                "Ondo::_transferTokens: transfer amount overflows"
              );
              emit Transfer(src, dst, amount);
              _moveDelegates(delegates[src], delegates[dst], amount);
            }
            function _moveDelegates(
              address srcRep,
              address dstRep,
              uint96 amount
            ) internal {
              if (srcRep != dstRep && amount > 0) {
                if (srcRep != address(0)) {
                  uint32 srcRepNum = numCheckpoints[srcRep];
                  uint96 srcRepOld =
                    srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;
                  uint96 srcRepNew =
                    sub96(srcRepOld, amount, "Ondo::_moveVotes: vote amount underflows");
                  _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
                }
                if (dstRep != address(0)) {
                  uint32 dstRepNum = numCheckpoints[dstRep];
                  uint96 dstRepOld =
                    dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;
                  uint96 dstRepNew =
                    add96(dstRepOld, amount, "Ondo::_moveVotes: vote amount overflows");
                  _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
                }
              }
            }
            function _writeCheckpoint(
              address delegatee,
              uint32 nCheckpoints,
              uint96 oldVotes,
              uint96 newVotes
            ) internal {
              uint32 blockNumber =
                safe32(
                  block.number,
                  "Ondo::_writeCheckpoint: block number exceeds 32 bits"
                );
              if (
                nCheckpoints > 0 &&
                checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber
              ) {
                checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;
              } else {
                checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);
                numCheckpoints[delegatee] = nCheckpoints + 1;
              }
              emit DelegateVotesChanged(delegatee, oldVotes, newVotes);
            }
            function getChainId() internal view returns (uint256) {
              uint256 chainId;
              assembly {
                chainId := chainid()
              }
              return chainId;
            }
            /**
             * @notice Turn on _transferAllowed variable. Transfers are enabled
             */
            function enableTransfer() external {
              require(
                hasRole(DEFAULT_ADMIN_ROLE, msg.sender),
                "Ondo::enableTransfer: not authorized"
              );
              transferAllowed = true;
              emit TransferEnabled(msg.sender);
            }
            /**
             * @notice Called by merkle airdrop contract to initialize locked balances
             */
            function updateTrancheBalance(
              address beneficiary,
              uint256 rawAmount,
              IOndo.InvestorType investorType
            ) external {
              require(hasRole(TIMELOCK_UPDATE_ROLE, msg.sender));
              require(rawAmount > 0, "Ondo::updateTrancheBalance: amount must be > 0");
              require(
                investorBalances[beneficiary].initialBalance == 0,
                "Ondo::updateTrancheBalance: already has timelocked Ondo"
              ); //Prevents users from being in more than 1 tranche
              uint96 amount =
                safe96(rawAmount, "Ondo::updateTrancheBalance: amount exceeds 96 bits");
              investorBalances[beneficiary] = InvestorParam(investorType, amount);
            }
            /**
             * @notice Internal function the amount of unlocked Ondo for an account that participated in Coinlist/Seed Investments
             */
            function _getFreedBalance(address account) internal view returns (uint96) {
              if (passedAllVestingPeriods()) {
                //all vesting periods are over, just return the total balance
                return balances[account];
              } else {
                InvestorParam memory investorParam = investorBalances[account];
                if (passedCliff()) {
                  //we are in between the cliff timestamp and last vesting period
                  (uint256 vestingPeriod, uint256 elapsed) =
                    _getTrancheInfo(investorParam.investorType);
                  uint96 lockedBalance =
                    sub96(
                      investorParam.initialBalance,
                      _proportionAvailable(elapsed, vestingPeriod, investorParam),
                      "Ondo::getFreedBalance: locked balance underflow"
                    );
                  return
                    sub96(
                      balances[account],
                      lockedBalance,
                      "Ondo::getFreedBalance: total freed balance underflow"
                    );
                } else {
                  //we have not hit the cliff yet, all investor balance is locked
                  return
                    sub96(
                      balances[account],
                      investorParam.initialBalance,
                      "Ondo::getFreedBalance: balance underflow"
                    );
                }
              }
            }
            function updateCliffTimestamp(uint256 newTimestamp) external {
              require(
                hasRole(DEFAULT_ADMIN_ROLE, msg.sender),
                "Ondo::updateCliffTimestamp: not authorized"
              );
              cliffTimestamp = newTimestamp;
              emit CliffTimestampUpdate(newTimestamp);
            }
          }
          

          File 3 of 3: BizGuard
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
          pragma solidity ^0.8.20;
          import {Context} from "../utils/Context.sol";
          /**
           * @dev Contract module which provides a basic access control mechanism, where
           * there is an account (an owner) that can be granted exclusive access to
           * specific functions.
           *
           * The initial owner is set to the address provided by the deployer. This can
           * later be changed with {transferOwnership}.
           *
           * This module is used through inheritance. It will make available the modifier
           * `onlyOwner`, which can be applied to your functions to restrict their use to
           * the owner.
           */
          abstract contract Ownable is Context {
              address private _owner;
              /**
               * @dev The caller account is not authorized to perform an operation.
               */
              error OwnableUnauthorizedAccount(address account);
              /**
               * @dev The owner is not a valid owner account. (eg. `address(0)`)
               */
              error OwnableInvalidOwner(address owner);
              event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
              /**
               * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
               */
              constructor(address initialOwner) {
                  if (initialOwner == address(0)) {
                      revert OwnableInvalidOwner(address(0));
                  }
                  _transferOwnership(initialOwner);
              }
              /**
               * @dev Throws if called by any account other than the owner.
               */
              modifier onlyOwner() {
                  _checkOwner();
                  _;
              }
              /**
               * @dev Returns the address of the current owner.
               */
              function owner() public view virtual returns (address) {
                  return _owner;
              }
              /**
               * @dev Throws if the sender is not the owner.
               */
              function _checkOwner() internal view virtual {
                  if (owner() != _msgSender()) {
                      revert OwnableUnauthorizedAccount(_msgSender());
                  }
              }
              /**
               * @dev Leaves the contract without owner. It will not be possible to call
               * `onlyOwner` functions. Can only be called by the current owner.
               *
               * NOTE: Renouncing ownership will leave the contract without an owner,
               * thereby disabling any functionality that is only available to the owner.
               */
              function renounceOwnership() public virtual onlyOwner {
                  _transferOwnership(address(0));
              }
              /**
               * @dev Transfers ownership of the contract to a new account (`newOwner`).
               * Can only be called by the current owner.
               */
              function transferOwnership(address newOwner) public virtual onlyOwner {
                  if (newOwner == address(0)) {
                      revert OwnableInvalidOwner(address(0));
                  }
                  _transferOwnership(newOwner);
              }
              /**
               * @dev Transfers ownership of the contract to a new account (`newOwner`).
               * Internal function without access restriction.
               */
              function _transferOwnership(address newOwner) internal virtual {
                  address oldOwner = _owner;
                  _owner = newOwner;
                  emit OwnershipTransferred(oldOwner, newOwner);
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.1.0) (access/Ownable2Step.sol)
          pragma solidity ^0.8.20;
          import {Ownable} from "./Ownable.sol";
          /**
           * @dev Contract module which provides access control mechanism, where
           * there is an account (an owner) that can be granted exclusive access to
           * specific functions.
           *
           * This extension of the {Ownable} contract includes a two-step mechanism to transfer
           * ownership, where the new owner must call {acceptOwnership} in order to replace the
           * old one. This can help prevent common mistakes, such as transfers of ownership to
           * incorrect accounts, or to contracts that are unable to interact with the
           * permission system.
           *
           * The initial owner is specified at deployment time in the constructor for `Ownable`. This
           * can later be changed with {transferOwnership} and {acceptOwnership}.
           *
           * This module is used through inheritance. It will make available all functions
           * from parent (Ownable).
           */
          abstract contract Ownable2Step is Ownable {
              address private _pendingOwner;
              event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
              /**
               * @dev Returns the address of the pending owner.
               */
              function pendingOwner() public view virtual returns (address) {
                  return _pendingOwner;
              }
              /**
               * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
               * Can only be called by the current owner.
               *
               * Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer.
               */
              function transferOwnership(address newOwner) public virtual override onlyOwner {
                  _pendingOwner = newOwner;
                  emit OwnershipTransferStarted(owner(), newOwner);
              }
              /**
               * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
               * Internal function without access restriction.
               */
              function _transferOwnership(address newOwner) internal virtual override {
                  delete _pendingOwner;
                  super._transferOwnership(newOwner);
              }
              /**
               * @dev The new owner accepts the ownership transfer.
               */
              function acceptOwnership() public virtual {
                  address sender = _msgSender();
                  if (pendingOwner() != sender) {
                      revert OwnableUnauthorizedAccount(sender);
                  }
                  _transferOwnership(sender);
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
          pragma solidity ^0.8.20;
          /**
           * @dev Provides information about the current execution context, including the
           * sender of the transaction and its data. While these are generally available
           * via msg.sender and msg.data, they should not be accessed in such a direct
           * manner, since when dealing with meta-transactions the account sending and
           * paying for execution may not be the actual sender (as far as an application
           * is concerned).
           *
           * This contract is only required for intermediate, library-like contracts.
           */
          abstract contract Context {
              function _msgSender() internal view virtual returns (address) {
                  return msg.sender;
              }
              function _msgData() internal view virtual returns (bytes calldata) {
                  return msg.data;
              }
              function _contextSuffixLength() internal view virtual returns (uint256) {
                  return 0;
              }
          }
          // SPDX-License-Identifier: Apache-2.0
          pragma solidity 0.8.28;
          import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol";
          /**
           * @title BizGuard - Guard contract for Biz.
           * @dev Most important concepts:
           *      - BizGuard maintains the nonce of all Biz for signature validation.
           *      - BizGuard is an ownable smart contract with 4337 flag to enable/disable ERC-4337 of Biz.
           * @author David Kim - @PowerStream3604
           */
          contract BizGuard is Ownable2Step {
              event FlagSet(bool flag);
              mapping(address => uint256) public accountNonce;
              bool erc4337Flag;
              /**
               * @notice constructor
               * @dev Sets the initial owner of the account.
               * @param owner address.
               */
              constructor(address owner) Ownable(owner) {}
              /**
               * @notice Increment nonce of the msg.sender.
               * @dev Nonce can only increment and not decrement.
               * @return nonce uint256 nonce of the msg.sender.
               */
              function incrementNonce() external returns (uint256 nonce) {
                  nonce = accountNonce[msg.sender];
                  unchecked {
                      ++accountNonce[msg.sender];
                  }
              }
              /**
               * @notice Return if the 4337 flag is enabled.
               * @dev This view function is called by validateUserOp() in all Biz wallet.
               * @return isEnabled bool flag whether 4337 is enabled.
               */
              function is4337Enabled() external view returns (bool isEnabled) {
                  isEnabled = erc4337Flag;
              }
              /**
               * @notice Set function to set 4337 Flag.
               * @dev This function can only be called by the owner.
               * @param flag bool value of the flag.
               */
              function set4337Flag(bool flag) external onlyOwner {
                  erc4337Flag = flag;
                  emit FlagSet(flag);
              }
          }