@ensuro/cash-flow-lender
Version:
Contract to track the debt with partners that pay on a monthly basis, used by the Ensuro Protocol
1 lines • 12.2 MB
JSON
{"id":"76cbba6822de023abaa80dde8b4be240","_format":"hh-sol-build-info-1","solcVersion":"0.8.28","solcLongVersion":"0.8.28+commit.7893614a","input":{"language":"Solidity","sources":{"@account-abstraction/contracts/core/BaseAccount.sol":{"content":"// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.23;\n\n/* solhint-disable avoid-low-level-calls */\n/* solhint-disable no-empty-blocks */\n\nimport \"../interfaces/IAccount.sol\";\nimport \"../interfaces/IEntryPoint.sol\";\nimport \"./UserOperationLib.sol\";\n\n/**\n * Basic account implementation.\n * This contract provides the basic logic for implementing the IAccount interface - validateUserOp\n * Specific account implementation should inherit it and provide the account-specific logic.\n */\nabstract contract BaseAccount is IAccount {\n using UserOperationLib for PackedUserOperation;\n\n /**\n * Return the account nonce.\n * This method returns the next sequential nonce.\n * For a nonce of a specific key, use `entrypoint.getNonce(account, key)`\n */\n function getNonce() public view virtual returns (uint256) {\n return entryPoint().getNonce(address(this), 0);\n }\n\n /**\n * Return the entryPoint used by this account.\n * Subclass should return the current entryPoint used by this account.\n */\n function entryPoint() public view virtual returns (IEntryPoint);\n\n /// @inheritdoc IAccount\n function validateUserOp(\n PackedUserOperation calldata userOp,\n bytes32 userOpHash,\n uint256 missingAccountFunds\n ) external virtual override returns (uint256 validationData) {\n _requireFromEntryPoint();\n validationData = _validateSignature(userOp, userOpHash);\n _validateNonce(userOp.nonce);\n _payPrefund(missingAccountFunds);\n }\n\n /**\n * Ensure the request comes from the known entrypoint.\n */\n function _requireFromEntryPoint() internal view virtual {\n require(\n msg.sender == address(entryPoint()),\n \"account: not from EntryPoint\"\n );\n }\n\n /**\n * Validate the signature is valid for this message.\n * @param userOp - Validate the userOp.signature field.\n * @param userOpHash - Convenient field: the hash of the request, to check the signature against.\n * (also hashes the entrypoint and chain id)\n * @return validationData - Signature and time-range of this operation.\n * <20-byte> aggregatorOrSigFail - 0 for valid signature, 1 to mark signature failure,\n * otherwise, an address of an aggregator contract.\n * <6-byte> validUntil - last timestamp this operation is valid. 0 for \"indefinite\"\n * <6-byte> validAfter - first timestamp this operation is valid\n * If the account doesn't use time-range, it is enough to return\n * SIG_VALIDATION_FAILED value (1) for signature failure.\n * Note that the validation code cannot use block.timestamp (or block.number) directly.\n */\n function _validateSignature(\n PackedUserOperation calldata userOp,\n bytes32 userOpHash\n ) internal virtual returns (uint256 validationData);\n\n /**\n * Validate the nonce of the UserOperation.\n * This method may validate the nonce requirement of this account.\n * e.g.\n * To limit the nonce to use sequenced UserOps only (no \"out of order\" UserOps):\n * `require(nonce < type(uint64).max)`\n * For a hypothetical account that *requires* the nonce to be out-of-order:\n * `require(nonce & type(uint64).max == 0)`\n *\n * The actual nonce uniqueness is managed by the EntryPoint, and thus no other\n * action is needed by the account itself.\n *\n * @param nonce to validate\n *\n * solhint-disable-next-line no-empty-blocks\n */\n function _validateNonce(uint256 nonce) internal view virtual {\n }\n\n /**\n * Sends to the entrypoint (msg.sender) the missing funds for this transaction.\n * SubClass MAY override this method for better funds management\n * (e.g. send to the entryPoint more than the minimum required, so that in future transactions\n * it will not be required to send again).\n * @param missingAccountFunds - The minimum value this method should send the entrypoint.\n * This value MAY be zero, in case there is enough deposit,\n * or the userOp has a paymaster.\n */\n function _payPrefund(uint256 missingAccountFunds) internal virtual {\n if (missingAccountFunds != 0) {\n (bool success, ) = payable(msg.sender).call{\n value: missingAccountFunds,\n gas: type(uint256).max\n }(\"\");\n (success);\n //ignore failure (its EntryPoint's job to verify, not account.)\n }\n }\n}\n"},"@account-abstraction/contracts/core/EntryPoint.sol":{"content":"// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.23;\n/* solhint-disable avoid-low-level-calls */\n/* solhint-disable no-inline-assembly */\n\nimport \"../interfaces/IAccount.sol\";\nimport \"../interfaces/IAccountExecute.sol\";\nimport \"../interfaces/IPaymaster.sol\";\nimport \"../interfaces/IEntryPoint.sol\";\n\nimport \"../utils/Exec.sol\";\nimport \"./StakeManager.sol\";\nimport \"./SenderCreator.sol\";\nimport \"./Helpers.sol\";\nimport \"./NonceManager.sol\";\nimport \"./UserOperationLib.sol\";\n\nimport \"@openzeppelin/contracts/utils/introspection/ERC165.sol\";\nimport \"@openzeppelin/contracts/utils/ReentrancyGuard.sol\";\n\n/*\n * Account-Abstraction (EIP-4337) singleton EntryPoint implementation.\n * Only one instance required on each chain.\n */\n\n/// @custom:security-contact https://bounty.ethereum.org\ncontract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard, ERC165 {\n\n using UserOperationLib for PackedUserOperation;\n\n SenderCreator private immutable _senderCreator = new SenderCreator();\n\n function senderCreator() internal view virtual returns (SenderCreator) {\n return _senderCreator;\n }\n\n //compensate for innerHandleOps' emit message and deposit refund.\n // allow some slack for future gas price changes.\n uint256 private constant INNER_GAS_OVERHEAD = 10000;\n\n // Marker for inner call revert on out of gas\n bytes32 private constant INNER_OUT_OF_GAS = hex\"deaddead\";\n bytes32 private constant INNER_REVERT_LOW_PREFUND = hex\"deadaa51\";\n\n uint256 private constant REVERT_REASON_MAX_LEN = 2048;\n uint256 private constant PENALTY_PERCENT = 10;\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n // note: solidity \"type(IEntryPoint).interfaceId\" is without inherited methods but we want to check everything\n return interfaceId == (type(IEntryPoint).interfaceId ^ type(IStakeManager).interfaceId ^ type(INonceManager).interfaceId) ||\n interfaceId == type(IEntryPoint).interfaceId ||\n interfaceId == type(IStakeManager).interfaceId ||\n interfaceId == type(INonceManager).interfaceId ||\n super.supportsInterface(interfaceId);\n }\n\n /**\n * Compensate the caller's beneficiary address with the collected fees of all UserOperations.\n * @param beneficiary - The address to receive the fees.\n * @param amount - Amount to transfer.\n */\n function _compensate(address payable beneficiary, uint256 amount) internal {\n require(beneficiary != address(0), \"AA90 invalid beneficiary\");\n (bool success, ) = beneficiary.call{value: amount}(\"\");\n require(success, \"AA91 failed send to beneficiary\");\n }\n\n /**\n * Execute a user operation.\n * @param opIndex - Index into the opInfo array.\n * @param userOp - The userOp to execute.\n * @param opInfo - The opInfo filled by validatePrepayment for this userOp.\n * @return collected - The total amount this userOp paid.\n */\n function _executeUserOp(\n uint256 opIndex,\n PackedUserOperation calldata userOp,\n UserOpInfo memory opInfo\n )\n internal\n returns\n (uint256 collected) {\n uint256 preGas = gasleft();\n bytes memory context = getMemoryBytesFromOffset(opInfo.contextOffset);\n bool success;\n {\n uint256 saveFreePtr;\n assembly (\"memory-safe\") {\n saveFreePtr := mload(0x40)\n }\n bytes calldata callData = userOp.callData;\n bytes memory innerCall;\n bytes4 methodSig;\n assembly {\n let len := callData.length\n if gt(len, 3) {\n methodSig := calldataload(callData.offset)\n }\n }\n if (methodSig == IAccountExecute.executeUserOp.selector) {\n bytes memory executeUserOp = abi.encodeCall(IAccountExecute.executeUserOp, (userOp, opInfo.userOpHash));\n innerCall = abi.encodeCall(this.innerHandleOp, (executeUserOp, opInfo, context));\n } else\n {\n innerCall = abi.encodeCall(this.innerHandleOp, (callData, opInfo, context));\n }\n assembly (\"memory-safe\") {\n success := call(gas(), address(), 0, add(innerCall, 0x20), mload(innerCall), 0, 32)\n collected := mload(0)\n mstore(0x40, saveFreePtr)\n }\n }\n if (!success) {\n bytes32 innerRevertCode;\n assembly (\"memory-safe\") {\n let len := returndatasize()\n if eq(32,len) {\n returndatacopy(0, 0, 32)\n innerRevertCode := mload(0)\n }\n }\n if (innerRevertCode == INNER_OUT_OF_GAS) {\n // handleOps was called with gas limit too low. abort entire bundle.\n //can only be caused by bundler (leaving not enough gas for inner call)\n revert FailedOp(opIndex, \"AA95 out of gas\");\n } else if (innerRevertCode == INNER_REVERT_LOW_PREFUND) {\n // innerCall reverted on prefund too low. treat entire prefund as \"gas cost\"\n uint256 actualGas = preGas - gasleft() + opInfo.preOpGas;\n uint256 actualGasCost = opInfo.prefund;\n emitPrefundTooLow(opInfo);\n emitUserOperationEvent(opInfo, false, actualGasCost, actualGas);\n collected = actualGasCost;\n } else {\n emit PostOpRevertReason(\n opInfo.userOpHash,\n opInfo.mUserOp.sender,\n opInfo.mUserOp.nonce,\n Exec.getReturnData(REVERT_REASON_MAX_LEN)\n );\n\n uint256 actualGas = preGas - gasleft() + opInfo.preOpGas;\n collected = _postExecution(\n IPaymaster.PostOpMode.postOpReverted,\n opInfo,\n context,\n actualGas\n );\n }\n }\n }\n\n function emitUserOperationEvent(UserOpInfo memory opInfo, bool success, uint256 actualGasCost, uint256 actualGas) internal virtual {\n emit UserOperationEvent(\n opInfo.userOpHash,\n opInfo.mUserOp.sender,\n opInfo.mUserOp.paymaster,\n opInfo.mUserOp.nonce,\n success,\n actualGasCost,\n actualGas\n );\n }\n\n function emitPrefundTooLow(UserOpInfo memory opInfo) internal virtual {\n emit UserOperationPrefundTooLow(\n opInfo.userOpHash,\n opInfo.mUserOp.sender,\n opInfo.mUserOp.nonce\n );\n }\n\n /// @inheritdoc IEntryPoint\n function handleOps(\n PackedUserOperation[] calldata ops,\n address payable beneficiary\n ) public nonReentrant {\n uint256 opslen = ops.length;\n UserOpInfo[] memory opInfos = new UserOpInfo[](opslen);\n\n unchecked {\n for (uint256 i = 0; i < opslen; i++) {\n UserOpInfo memory opInfo = opInfos[i];\n (\n uint256 validationData,\n uint256 pmValidationData\n ) = _validatePrepayment(i, ops[i], opInfo);\n _validateAccountAndPaymasterValidationData(\n i,\n validationData,\n pmValidationData,\n address(0)\n );\n }\n\n uint256 collected = 0;\n emit BeforeExecution();\n\n for (uint256 i = 0; i < opslen; i++) {\n collected += _executeUserOp(i, ops[i], opInfos[i]);\n }\n\n _compensate(beneficiary, collected);\n }\n }\n\n /// @inheritdoc IEntryPoint\n function handleAggregatedOps(\n UserOpsPerAggregator[] calldata opsPerAggregator,\n address payable beneficiary\n ) public nonReentrant {\n\n uint256 opasLen = opsPerAggregator.length;\n uint256 totalOps = 0;\n for (uint256 i = 0; i < opasLen; i++) {\n UserOpsPerAggregator calldata opa = opsPerAggregator[i];\n PackedUserOperation[] calldata ops = opa.userOps;\n IAggregator aggregator = opa.aggregator;\n\n //address(1) is special marker of \"signature error\"\n require(\n address(aggregator) != address(1),\n \"AA96 invalid aggregator\"\n );\n\n if (address(aggregator) != address(0)) {\n // solhint-disable-next-line no-empty-blocks\n try aggregator.validateSignatures(ops, opa.signature) {} catch {\n revert SignatureValidationFailed(address(aggregator));\n }\n }\n\n totalOps += ops.length;\n }\n\n UserOpInfo[] memory opInfos = new UserOpInfo[](totalOps);\n\n uint256 opIndex = 0;\n for (uint256 a = 0; a < opasLen; a++) {\n UserOpsPerAggregator calldata opa = opsPerAggregator[a];\n PackedUserOperation[] calldata ops = opa.userOps;\n IAggregator aggregator = opa.aggregator;\n\n uint256 opslen = ops.length;\n for (uint256 i = 0; i < opslen; i++) {\n UserOpInfo memory opInfo = opInfos[opIndex];\n (\n uint256 validationData,\n uint256 paymasterValidationData\n ) = _validatePrepayment(opIndex, ops[i], opInfo);\n _validateAccountAndPaymasterValidationData(\n i,\n validationData,\n paymasterValidationData,\n address(aggregator)\n );\n opIndex++;\n }\n }\n\n emit BeforeExecution();\n\n uint256 collected = 0;\n opIndex = 0;\n for (uint256 a = 0; a < opasLen; a++) {\n UserOpsPerAggregator calldata opa = opsPerAggregator[a];\n emit SignatureAggregatorChanged(address(opa.aggregator));\n PackedUserOperation[] calldata ops = opa.userOps;\n uint256 opslen = ops.length;\n\n for (uint256 i = 0; i < opslen; i++) {\n collected += _executeUserOp(opIndex, ops[i], opInfos[opIndex]);\n opIndex++;\n }\n }\n emit SignatureAggregatorChanged(address(0));\n\n _compensate(beneficiary, collected);\n }\n\n /**\n * A memory copy of UserOp static fields only.\n * Excluding: callData, initCode and signature. Replacing paymasterAndData with paymaster.\n */\n struct MemoryUserOp {\n address sender;\n uint256 nonce;\n uint256 verificationGasLimit;\n uint256 callGasLimit;\n uint256 paymasterVerificationGasLimit;\n uint256 paymasterPostOpGasLimit;\n uint256 preVerificationGas;\n address paymaster;\n uint256 maxFeePerGas;\n uint256 maxPriorityFeePerGas;\n }\n\n struct UserOpInfo {\n MemoryUserOp mUserOp;\n bytes32 userOpHash;\n uint256 prefund;\n uint256 contextOffset;\n uint256 preOpGas;\n }\n\n /**\n * Inner function to handle a UserOperation.\n * Must be declared \"external\" to open a call context, but it can only be called by handleOps.\n * @param callData - The callData to execute.\n * @param opInfo - The UserOpInfo struct.\n * @param context - The context bytes.\n * @return actualGasCost - the actual cost in eth this UserOperation paid for gas\n */\n function innerHandleOp(\n bytes memory callData,\n UserOpInfo memory opInfo,\n bytes calldata context\n ) external returns (uint256 actualGasCost) {\n uint256 preGas = gasleft();\n require(msg.sender == address(this), \"AA92 internal call only\");\n MemoryUserOp memory mUserOp = opInfo.mUserOp;\n\n uint256 callGasLimit = mUserOp.callGasLimit;\n unchecked {\n // handleOps was called with gas limit too low. abort entire bundle.\n if (\n gasleft() * 63 / 64 <\n callGasLimit +\n mUserOp.paymasterPostOpGasLimit +\n INNER_GAS_OVERHEAD\n ) {\n assembly (\"memory-safe\") {\n mstore(0, INNER_OUT_OF_GAS)\n revert(0, 32)\n }\n }\n }\n\n IPaymaster.PostOpMode mode = IPaymaster.PostOpMode.opSucceeded;\n if (callData.length > 0) {\n bool success = Exec.call(mUserOp.sender, 0, callData, callGasLimit);\n if (!success) {\n bytes memory result = Exec.getReturnData(REVERT_REASON_MAX_LEN);\n if (result.length > 0) {\n emit UserOperationRevertReason(\n opInfo.userOpHash,\n mUserOp.sender,\n mUserOp.nonce,\n result\n );\n }\n mode = IPaymaster.PostOpMode.opReverted;\n }\n }\n\n unchecked {\n uint256 actualGas = preGas - gasleft() + opInfo.preOpGas;\n return _postExecution(mode, opInfo, context, actualGas);\n }\n }\n\n /// @inheritdoc IEntryPoint\n function getUserOpHash(\n PackedUserOperation calldata userOp\n ) public view returns (bytes32) {\n return\n keccak256(abi.encode(userOp.hash(), address(this), block.chainid));\n }\n\n /**\n * Copy general fields from userOp into the memory opInfo structure.\n * @param userOp - The user operation.\n * @param mUserOp - The memory user operation.\n */\n function _copyUserOpToMemory(\n PackedUserOperation calldata userOp,\n MemoryUserOp memory mUserOp\n ) internal pure {\n mUserOp.sender = userOp.sender;\n mUserOp.nonce = userOp.nonce;\n (mUserOp.verificationGasLimit, mUserOp.callGasLimit) = UserOperationLib.unpackUints(userOp.accountGasLimits);\n mUserOp.preVerificationGas = userOp.preVerificationGas;\n (mUserOp.maxPriorityFeePerGas, mUserOp.maxFeePerGas) = UserOperationLib.unpackUints(userOp.gasFees);\n bytes calldata paymasterAndData = userOp.paymasterAndData;\n if (paymasterAndData.length > 0) {\n require(\n paymasterAndData.length >= UserOperationLib.PAYMASTER_DATA_OFFSET,\n \"AA93 invalid paymasterAndData\"\n );\n (mUserOp.paymaster, mUserOp.paymasterVerificationGasLimit, mUserOp.paymasterPostOpGasLimit) = UserOperationLib.unpackPaymasterStaticFields(paymasterAndData);\n } else {\n mUserOp.paymaster = address(0);\n mUserOp.paymasterVerificationGasLimit = 0;\n mUserOp.paymasterPostOpGasLimit = 0;\n }\n }\n\n /**\n * Get the required prefunded gas fee amount for an operation.\n * @param mUserOp - The user operation in memory.\n */\n function _getRequiredPrefund(\n MemoryUserOp memory mUserOp\n ) internal pure returns (uint256 requiredPrefund) {\n unchecked {\n uint256 requiredGas = mUserOp.verificationGasLimit +\n mUserOp.callGasLimit +\n mUserOp.paymasterVerificationGasLimit +\n mUserOp.paymasterPostOpGasLimit +\n mUserOp.preVerificationGas;\n\n requiredPrefund = requiredGas * mUserOp.maxFeePerGas;\n }\n }\n\n /**\n * Create sender smart contract account if init code is provided.\n * @param opIndex - The operation index.\n * @param opInfo - The operation info.\n * @param initCode - The init code for the smart contract account.\n */\n function _createSenderIfNeeded(\n uint256 opIndex,\n UserOpInfo memory opInfo,\n bytes calldata initCode\n ) internal {\n if (initCode.length != 0) {\n address sender = opInfo.mUserOp.sender;\n if (sender.code.length != 0)\n revert FailedOp(opIndex, \"AA10 sender already constructed\");\n address sender1 = senderCreator().createSender{\n gas: opInfo.mUserOp.verificationGasLimit\n }(initCode);\n if (sender1 == address(0))\n revert FailedOp(opIndex, \"AA13 initCode failed or OOG\");\n if (sender1 != sender)\n revert FailedOp(opIndex, \"AA14 initCode must return sender\");\n if (sender1.code.length == 0)\n revert FailedOp(opIndex, \"AA15 initCode must create sender\");\n address factory = address(bytes20(initCode[0:20]));\n emit AccountDeployed(\n opInfo.userOpHash,\n sender,\n factory,\n opInfo.mUserOp.paymaster\n );\n }\n }\n\n /// @inheritdoc IEntryPoint\n function getSenderAddress(bytes calldata initCode) public {\n address sender = senderCreator().createSender(initCode);\n revert SenderAddressResult(sender);\n }\n\n /**\n * Call account.validateUserOp.\n * Revert (with FailedOp) in case validateUserOp reverts, or account didn't send required prefund.\n * Decrement account's deposit if needed.\n * @param opIndex - The operation index.\n * @param op - The user operation.\n * @param opInfo - The operation info.\n * @param requiredPrefund - The required prefund amount.\n */\n function _validateAccountPrepayment(\n uint256 opIndex,\n PackedUserOperation calldata op,\n UserOpInfo memory opInfo,\n uint256 requiredPrefund,\n uint256 verificationGasLimit\n )\n internal\n returns (\n uint256 validationData\n )\n {\n unchecked {\n MemoryUserOp memory mUserOp = opInfo.mUserOp;\n address sender = mUserOp.sender;\n _createSenderIfNeeded(opIndex, opInfo, op.initCode);\n address paymaster = mUserOp.paymaster;\n uint256 missingAccountFunds = 0;\n if (paymaster == address(0)) {\n uint256 bal = balanceOf(sender);\n missingAccountFunds = bal > requiredPrefund\n ? 0\n : requiredPrefund - bal;\n }\n try\n IAccount(sender).validateUserOp{\n gas: verificationGasLimit\n }(op, opInfo.userOpHash, missingAccountFunds)\n returns (uint256 _validationData) {\n validationData = _validationData;\n } catch {\n revert FailedOpWithRevert(opIndex, \"AA23 reverted\", Exec.getReturnData(REVERT_REASON_MAX_LEN));\n }\n if (paymaster == address(0)) {\n DepositInfo storage senderInfo = deposits[sender];\n uint256 deposit = senderInfo.deposit;\n if (requiredPrefund > deposit) {\n revert FailedOp(opIndex, \"AA21 didn't pay prefund\");\n }\n senderInfo.deposit = deposit - requiredPrefund;\n }\n }\n }\n\n /**\n * In case the request has a paymaster:\n * - Validate paymaster has enough deposit.\n * - Call paymaster.validatePaymasterUserOp.\n * - Revert with proper FailedOp in case paymaster reverts.\n * - Decrement paymaster's deposit.\n * @param opIndex - The operation index.\n * @param op - The user operation.\n * @param opInfo - The operation info.\n * @param requiredPreFund - The required prefund amount.\n */\n function _validatePaymasterPrepayment(\n uint256 opIndex,\n PackedUserOperation calldata op,\n UserOpInfo memory opInfo,\n uint256 requiredPreFund\n ) internal returns (bytes memory context, uint256 validationData) {\n unchecked {\n uint256 preGas = gasleft();\n MemoryUserOp memory mUserOp = opInfo.mUserOp;\n address paymaster = mUserOp.paymaster;\n DepositInfo storage paymasterInfo = deposits[paymaster];\n uint256 deposit = paymasterInfo.deposit;\n if (deposit < requiredPreFund) {\n revert FailedOp(opIndex, \"AA31 paymaster deposit too low\");\n }\n paymasterInfo.deposit = deposit - requiredPreFund;\n uint256 pmVerificationGasLimit = mUserOp.paymasterVerificationGasLimit;\n try\n IPaymaster(paymaster).validatePaymasterUserOp{gas: pmVerificationGasLimit}(\n op,\n opInfo.userOpHash,\n requiredPreFund\n )\n returns (bytes memory _context, uint256 _validationData) {\n context = _context;\n validationData = _validationData;\n } catch {\n revert FailedOpWithRevert(opIndex, \"AA33 reverted\", Exec.getReturnData(REVERT_REASON_MAX_LEN));\n }\n if (preGas - gasleft() > pmVerificationGasLimit) {\n revert FailedOp(opIndex, \"AA36 over paymasterVerificationGasLimit\");\n }\n }\n }\n\n /**\n * Revert if either account validationData or paymaster validationData is expired.\n * @param opIndex - The operation index.\n * @param validationData - The account validationData.\n * @param paymasterValidationData - The paymaster validationData.\n * @param expectedAggregator - The expected aggregator.\n */\n function _validateAccountAndPaymasterValidationData(\n uint256 opIndex,\n uint256 validationData,\n uint256 paymasterValidationData,\n address expectedAggregator\n ) internal view {\n (address aggregator, bool outOfTimeRange) = _getValidationData(\n validationData\n );\n if (expectedAggregator != aggregator) {\n revert FailedOp(opIndex, \"AA24 signature error\");\n }\n if (outOfTimeRange) {\n revert FailedOp(opIndex, \"AA22 expired or not due\");\n }\n // pmAggregator is not a real signature aggregator: we don't have logic to handle it as address.\n // Non-zero address means that the paymaster fails due to some signature check (which is ok only during estimation).\n address pmAggregator;\n (pmAggregator, outOfTimeRange) = _getValidationData(\n paymasterValidationData\n );\n if (pmAggregator != address(0)) {\n revert FailedOp(opIndex, \"AA34 signature error\");\n }\n if (outOfTimeRange) {\n revert FailedOp(opIndex, \"AA32 paymaster expired or not due\");\n }\n }\n\n /**\n * Parse validationData into its components.\n * @param validationData - The packed validation data (sigFailed, validAfter, validUntil).\n * @return aggregator the aggregator of the validationData\n * @return outOfTimeRange true if current time is outside the time range of this validationData.\n */\n function _getValidationData(\n uint256 validationData\n ) internal view returns (address aggregator, bool outOfTimeRange) {\n if (validationData == 0) {\n return (address(0), false);\n }\n ValidationData memory data = _parseValidationData(validationData);\n // solhint-disable-next-line not-rely-on-time\n outOfTimeRange = block.timestamp > data.validUntil || block.timestamp < data.validAfter;\n aggregator = data.aggregator;\n }\n\n /**\n * Validate account and paymaster (if defined) and\n * also make sure total validation doesn't exceed verificationGasLimit.\n * This method is called off-chain (simulateValidation()) and on-chain (from handleOps)\n * @param opIndex - The index of this userOp into the \"opInfos\" array.\n * @param userOp - The userOp to validate.\n */\n function _validatePrepayment(\n uint256 opIndex,\n PackedUserOperation calldata userOp,\n UserOpInfo memory outOpInfo\n )\n internal\n returns (uint256 validationData, uint256 paymasterValidationData)\n {\n uint256 preGas = gasleft();\n MemoryUserOp memory mUserOp = outOpInfo.mUserOp;\n _copyUserOpToMemory(userOp, mUserOp);\n outOpInfo.userOpHash = getUserOpHash(userOp);\n\n // Validate all numeric values in userOp are well below 128 bit, so they can safely be added\n // and multiplied without causing overflow.\n uint256 verificationGasLimit = mUserOp.verificationGasLimit;\n uint256 maxGasValues = mUserOp.preVerificationGas |\n verificationGasLimit |\n mUserOp.callGasLimit |\n mUserOp.paymasterVerificationGasLimit |\n mUserOp.paymasterPostOpGasLimit |\n mUserOp.maxFeePerGas |\n mUserOp.maxPriorityFeePerGas;\n require(maxGasValues <= type(uint120).max, \"AA94 gas values overflow\");\n\n uint256 requiredPreFund = _getRequiredPrefund(mUserOp);\n validationData = _validateAccountPrepayment(\n opIndex,\n userOp,\n outOpInfo,\n requiredPreFund,\n verificationGasLimit\n );\n\n if (!_validateAndUpdateNonce(mUserOp.sender, mUserOp.nonce)) {\n revert FailedOp(opIndex, \"AA25 invalid account nonce\");\n }\n\n unchecked {\n if (preGas - gasleft() > verificationGasLimit) {\n revert FailedOp(opIndex, \"AA26 over verificationGasLimit\");\n }\n }\n\n bytes memory context;\n if (mUserOp.paymaster != address(0)) {\n (context, paymasterValidationData) = _validatePaymasterPrepayment(\n opIndex,\n userOp,\n outOpInfo,\n requiredPreFund\n );\n }\n unchecked {\n outOpInfo.prefund = requiredPreFund;\n outOpInfo.contextOffset = getOffsetOfMemoryBytes(context);\n outOpInfo.preOpGas = preGas - gasleft() + userOp.preVerificationGas;\n }\n }\n\n /**\n * Process post-operation, called just after the callData is executed.\n * If a paymaster is defined and its validation returned a non-empty context, its postOp is called.\n * The excess amount is refunded to the account (or paymaster - if it was used in the request).\n * @param mode - Whether is called from innerHandleOp, or outside (postOpReverted).\n * @param opInfo - UserOp fields and info collected during validation.\n * @param context - The context returned in validatePaymasterUserOp.\n * @param actualGas - The gas used so far by this user operation.\n */\n function _postExecution(\n IPaymaster.PostOpMode mode,\n UserOpInfo memory opInfo,\n bytes memory context,\n uint256 actualGas\n ) private returns (uint256 actualGasCost) {\n uint256 preGas = gasleft();\n unchecked {\n address refundAddress;\n MemoryUserOp memory mUserOp = opInfo.mUserOp;\n uint256 gasPrice = getUserOpGasPrice(mUserOp);\n\n address paymaster = mUserOp.paymaster;\n if (paymaster == address(0)) {\n refundAddress = mUserOp.sender;\n } else {\n refundAddress = paymaster;\n if (context.length > 0) {\n actualGasCost = actualGas * gasPrice;\n if (mode != IPaymaster.PostOpMode.postOpReverted) {\n try IPaymaster(paymaster).postOp{\n gas: mUserOp.paymasterPostOpGasLimit\n }(mode, context, actualGasCost, gasPrice)\n // solhint-disable-next-line no-empty-blocks\n {} catch {\n bytes memory reason = Exec.getReturnData(REVERT_REASON_MAX_LEN);\n revert PostOpReverted(reason);\n }\n }\n }\n }\n actualGas += preGas - gasleft();\n\n // Calculating a penalty for unused execution gas\n {\n uint256 executionGasLimit = mUserOp.callGasLimit + mUserOp.paymasterPostOpGasLimit;\n uint256 executionGasUsed = actualGas - opInfo.preOpGas;\n // this check is required for the gas used within EntryPoint and not covered by explicit gas limits\n if (executionGasLimit > executionGasUsed) {\n uint256 unusedGas = executionGasLimit - executionGasUsed;\n uint256 unusedGasPenalty = (unusedGas * PENALTY_PERCENT) / 100;\n actualGas += unusedGasPenalty;\n }\n }\n\n actualGasCost = actualGas * gasPrice;\n uint256 prefund = opInfo.prefund;\n if (prefund < actualGasCost) {\n if (mode == IPaymaster.PostOpMode.postOpReverted) {\n actualGasCost = prefund;\n emitPrefundTooLow(opInfo);\n emitUserOperationEvent(opInfo, false, actualGasCost, actualGas);\n } else {\n assembly (\"memory-safe\") {\n mstore(0, INNER_REVERT_LOW_PREFUND)\n revert(0, 32)\n }\n }\n } else {\n uint256 refund = prefund - actualGasCost;\n _incrementDeposit(refundAddress, refund);\n bool success = mode == IPaymaster.PostOpMode.opSucceeded;\n emitUserOperationEvent(opInfo, success, actualGasCost, actualGas);\n }\n } // unchecked\n }\n\n /**\n * The gas price this UserOp agrees to pay.\n * Relayer/block builder might submit the TX with higher priorityFee, but the user should not.\n * @param mUserOp - The userOp to get the gas price from.\n */\n function getUserOpGasPrice(\n MemoryUserOp memory mUserOp\n ) internal view returns (uint256) {\n unchecked {\n uint256 maxFeePerGas = mUserOp.maxFeePerGas;\n uint256 maxPriorityFeePerGas = mUserOp.maxPriorityFeePerGas;\n if (maxFeePerGas == maxPriorityFeePerGas) {\n //legacy mode (for networks that don't support basefee opcode)\n return maxFeePerGas;\n }\n return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee);\n }\n }\n\n /**\n * The offset of the given bytes in memory.\n * @param data - The bytes to get the offset of.\n */\n function getOffsetOfMemoryBytes(\n bytes memory data\n ) internal pure returns (uint256 offset) {\n assembly {\n offset := data\n }\n }\n\n /**\n * The bytes in memory at the given offset.\n * @param offset - The offset to get the bytes from.\n */\n function getMemoryBytesFromOffset(\n uint256 offset\n ) internal pure returns (bytes memory data) {\n assembly (\"memory-safe\") {\n data := offset\n }\n }\n\n /// @inheritdoc IEntryPoint\n function delegateAndRevert(address target, bytes calldata data) external {\n (bool success, bytes memory ret) = target.delegatecall(data);\n revert DelegateAndRevert(success, ret);\n }\n}\n"},"@account-abstraction/contracts/core/Helpers.sol":{"content":"// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.23;\n\n/* solhint-disable no-inline-assembly */\n\n\n /*\n * For simulation purposes, validateUserOp (and validatePaymasterUserOp)\n * must return this value in case of signature failure, instead of revert.\n */\nuint256 constant SIG_VALIDATION_FAILED = 1;\n\n\n/*\n * For simulation purposes, validateUserOp (and validatePaymasterUserOp)\n * return this value on success.\n */\nuint256 constant SIG_VALIDATION_SUCCESS = 0;\n\n\n/**\n * Returned data from validateUserOp.\n * validateUserOp returns a uint256, which is created by `_packedValidationData` and\n * parsed by `_parseValidationData`.\n * @param aggregator - address(0) - The account validated the signature by itself.\n * address(1) - The account failed to validate the signature.\n * otherwise - This is an address of a signature aggregator that must\n * be used to validate the signature.\n * @param validAfter - This UserOp is valid only after this timestamp.\n * @param validaUntil - This UserOp is valid only up to this timestamp.\n */\nstruct ValidationData {\n address aggregator;\n uint48 validAfter;\n uint48 validUntil;\n}\n\n/**\n * Extract sigFailed, validAfter, validUntil.\n * Also convert zero validUntil to type(uint48).max.\n * @param validationData - The packed validation data.\n */\nfunction _parseValidationData(\n uint256 validationData\n) pure returns (ValidationData memory data) {\n address aggregator = address(uint160(validationData));\n uint48 validUntil = uint48(validationData >> 160);\n if (validUntil == 0) {\n validUntil = type(uint48).max;\n }\n uint48 validAfter = uint48(validationData >> (48 + 160));\n return ValidationData(aggregator, validAfter, validUntil);\n}\n\n/**\n * Helper to pack the return value for validateUserOp.\n * @param data - The ValidationData to pack.\n */\nfunction _packValidationData(\n ValidationData memory data\n) pure returns (uint256) {\n return\n uint160(data.aggregator) |\n (uint256(data.validUntil) << 160) |\n (uint256(data.validAfter) << (160 + 48));\n}\n\n/**\n * Helper to pack the return value for validateUserOp, when not using an aggregator.\n * @param sigFailed - True for signature failure, false for success.\n * @param validUntil - Last timestamp this UserOperation is valid (or zero for infinite).\n * @param validAfter - First timestamp this UserOperation is valid.\n */\nfunction _packValidationData(\n bool sigFailed,\n uint48 validUntil,\n uint48 validAfter\n) pure returns (uint256) {\n return\n (sigFailed ? 1 : 0) |\n (uint256(validUntil) << 160) |\n (uint256(validAfter) << (160 + 48));\n}\n\n/**\n * keccak function over calldata.\n * @dev copy calldata into memory, do keccak and drop allocated memory. Strangely, this is more efficient than letting solidity do it.\n */\n function calldataKeccak(bytes calldata data) pure returns (bytes32 ret) {\n assembly (\"memory-safe\") {\n let mem := mload(0x40)\n let len := data.length\n calldatacopy(mem, data.offset, len)\n ret := keccak256(mem, len)\n }\n }\n\n\n/**\n * The minimum of two numbers.\n * @param a - First number.\n * @param b - Second number.\n */\n function min(uint256 a, uint256 b) pure returns (uint256) {\n return a < b ? a : b;\n }\n"},"@account-abstraction/contracts/core/NonceManager.sol":{"content":"// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.23;\n\nimport \"../interfaces/INonceManager.sol\";\n\n/**\n * nonce management functionality\n */\nabstract contract NonceManager is INonceManager {\n\n /**\n * The next valid sequence number for a given nonce key.\n */\n mapping(address => mapping(uint192 => uint256)) public nonceSequenceNumber;\n\n /// @inheritdoc INonceManager\n function getNonce(address sender, uint192 key)\n public view override returns (uint256 nonce) {\n return nonceSequenceNumber[sender][key] | (uint256(key) << 64);\n }\n\n // allow an account to manually increment its own nonce.\n // (mainly so that during construction nonce can be made non-zero,\n // to \"absorb\" the gas cost of first nonce increment to 1st transaction (construction),\n // not to 2nd transaction)\n function incrementNonce(uint192 key) public override {\n nonceSequenceNumber[msg.sender][key]++;\n }\n\n /**\n * validate nonce uniqueness for this account.\n * called just after validateUserOp()\n * @return true if the nonce was incremented successfully.\n * false if the current nonce doesn't match the given one.\n */\n function _validateAndUpdateNonce(address sender, uint256 nonce) internal returns (bool) {\n\n uint192 key = uint192(nonce >> 64);\n uint64 seq = uint64(nonce);\n return nonceSequenceNumber[sender][key]++ == seq;\n }\n\n}\n"},"@account-abstraction/contracts/core/SenderCreator.sol":{"content":"// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.23;\n\n/**\n * Helper contract for EntryPoint, to call userOp.initCode from a \"neutral\" address,\n * which is explicitly not the entryPoint itself.\n */\ncontract SenderCreator {\n /**\n * Call the \"initCode\" factory to create and return the sender account address.\n * @param initCode - The initCode value from a UserOp. contains 20 bytes of factory address,\n * followed by calldata.\n * @return sender - The returned address of the created account, or zero address on failure.\n */\n function createSender(\n bytes calldata initCode\n ) external returns (address sender) {\n address factory = address(bytes20(initCode[0:20]));\n bytes memory initCallData = initCode[20:];\n bool success;\n /* solhint-disable no-inline-assembly */\n assembly (\"memory-safe\") {\n success := call(\n gas(),\n factory,\n 0,\n add(initCallData, 0x20),\n mload(initCallData),\n 0,\n 32\n )\n sender := mload(0)\n }\n if (!success) {\n sender = address(0);\n }\n }\n}\n"},"@account-abstraction/contracts/core/StakeManager.sol":{"content":"// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.23;\n\nimport \"../interfaces/IStakeManager.sol\";\n\n/* solhint-disable avoid-low-level-calls */\n/* solhint-disable not-rely-on-time */\n\n/**\n * Manage deposits and stakes.\n * Deposit is just a balance used to pay for UserOperations (either by a paymaster or an account).\n * Stake is value locked for at least \"unstakeDelay\" by a paymaster.\n */\nabstract contract StakeManager is IStakeManager {\n /// maps paymaster to their deposits and stakes\n mapping(address => DepositInfo) public deposits;\n\n /// @inheritdoc IStakeManager\n function getDepositInfo(\n address account\n ) public view returns (DepositInfo memory info) {\n return deposits[account];\n }\n\n /**\n * Internal method to return just the stake info.\n * @param addr - The account to query.\n */\n function _getStakeInfo(\n address addr\n ) internal view returns (StakeInfo memory info) {\n DepositInfo storage depositInfo = deposits[addr];\n info.stake = depositInfo.stake;\n info.unstakeDelaySec = depositInfo.unstakeDelaySec;\n }\n\n /// @inheritdoc IStakeManager\n function balanceOf(address account) public view returns (uint256) {\n return deposits[account].deposit;\n }\n\n receive() external payable {\n depositTo(msg.sender);\n }\n\n /**\n * Increments an account's deposit.\n * @param account - The account to increment.\n * @param amount - The amount to increment by.\n * @return the updated deposit of this account\n */\n function _incrementDeposit(address account, uint256 amount) internal returns (uint256) {\n DepositInfo storage info = deposits[account];\n uint256 newAmount = info.deposit + amount;\n info.deposit = newAmount;\n return newAmount;\n }\n\n /**\n * Add to the deposit of the given account.\n * @param account - The account to add to.\n */\n function depositTo(address account) public virtual payable {\n uint256 newDeposit = _incrementDeposit(account, msg.value);\n emit Deposited(account, newDeposit);\n }\n\n /**\n * Add to the account's stake - amount and delay\n * any pending unstake is first cancelled.\n * @param unstakeDelaySec The new lock duration before the deposit can be withdrawn.\n */\n function addStake(uint32 unstakeDelaySec) public payable {\n DepositInfo storage info = deposits[msg.sender];\n require(unstakeDelaySec > 0, \"must specify unstake delay\");\n require(\n unstakeDelaySec >= info.unstakeDelaySec,\n \"cannot decrease unstake time\"\n );\n uint256 stake = info.stake + msg.value;\n require(stake > 0, \"no stake specified\");\n require(stake <= type(uint112).max, \"stake overflow\");\n deposits[msg.sender] = DepositInfo(\n info.deposit,\n true,\n uint112(stake),\n unstakeDelaySec,\n 0\n );\n emit StakeLocked(msg.sender, stake, unstakeDelaySec);\n }\n\n /**\n * Attempt to unlock the stake.\n * The value can be withdrawn (using withdrawStake) after the unstake delay.\n */\n function unlockStake() external {\n DepositInfo storage info = deposits[msg.sender];\n require(info.unstakeDelaySec != 0, \"not staked\");\n require(info.staked, \"already unstaking\");\n uint48 withdrawTime = uint48(block.timestamp) + info.unstakeDelaySec;\n info.withdrawTime = withdrawTime;\n info.staked = false;\n emit StakeUnlocked(msg.sender, withdrawTime);\n }\n\n /**\n * Withdraw from the (unlocked) stake.\n * Must first call unlockStake and wait for the unstakeDelay to pass.\n * @param withdrawAddress - The address to send withdrawn value.\n */\n function withdrawStake(address payable withdrawAddress) external {\n DepositInfo storage info = deposits[msg.sender];\n uint256 stake = info.stake;\n require(stake > 0, \"No stake to withdraw\");\n require(info.withdrawTime > 0, \"must call unlockStake() first\");\n require(\n info.withdrawTime <= block.timestamp,\n \"Stake withdrawal is not due\"\n );\n info.unstakeDelaySec = 0;\n info.withdrawTime = 0;\n info.stake = 0;\n emit StakeWithdrawn(msg.sender, withdrawAddress, stake);\n (bool success,) = withdrawAddress.call{value: stake}(\"\");\n require(success, \"failed to withdraw stake\");\n }\n\n /**\n * Withdraw from the deposit.\n * @param withdrawAddress - The address to send withdrawn value.\n * @param withdrawAmount - The amount to withdraw.\n */\n function withdrawTo(\n address payable withdrawAddress,\n uint256 withdrawAmount\n ) external {\n DepositInfo storage info = deposits[msg.sender];\n require(withdrawAmount <= info.deposit, \"Withdraw amount too large\");\n info.deposit = info.deposit - withdrawAmount;\n emit Withdrawn(msg.sender, withdrawAddress, withdrawAmount);\n (bool success,) = withdrawAddress.call{value: withdrawAmount}(\"\");\n require(success, \"failed to withdraw\");\n }\n}\n"},"@account-abstraction/contracts/core/UserOperationLib.sol":{"content":"// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.23;\n\n/* solhint-disable no-inline-assembly */\n\nimport \"../interfaces/PackedUserOperation.sol\";\nimport {calldataKeccak, min} from \"./Helpers.sol\";\n\n/**\n * Utility functions helpful when working with UserOperation structs.\n */\nlibrary UserOperationLib {\n\n uint256 public constant PAYMASTER_VALIDATION_GAS_OFFSET = 20;\n uint256 public constant PAYMASTER_POSTOP_GAS_OFFSET = 36;\n uint256 public constant PAYMASTER_DATA_OFFSET = 52;\n /**\n * Get sender from user operation data.\n * @param userOp - The user operation data.\n */\n function getSender(\n PackedUserOperation calldata userOp\n ) internal pure returns (address) {\n address data;\n //read sender from userOp, which is first userOp member (saves 800 gas...)\n assembly {\n data := calldatalo