UNPKG

@owlprotocol/contracts-account-abstraction

Version:

ERC4337 Account Abstraction support for deploying relevant smart contracts and interacting with UserOps.

147 lines (146 loc) 4.46 kB
import { encodeFunctionData, decodeErrorResult, decodeFunctionResult } from "viem"; import { simulateEntryPoint } from "./simulateEntryPoint.js"; import { parseFailedOpWithRevert } from "../../gasestimation/parseFailedOpWithRevert.js"; import { abi as EntryPointV07SimulationsAbi } from "../../artifacts/EntryPointSimulations.js"; import { targetCallResultSchema, ExecutionError, ExecutionErrors, ValidationErrors } from "../../models/index.js"; async function getExecutionResult(client, parameters) { const { packedUserOperation, entryPoint, entryPointSimulationsAddress, stateOverride } = parameters; const error = await simulateHandleOpV07(client, { packedUserOperation, entryPoint, targetAddress: packedUserOperation.sender, targetCallData: packedUserOperation.callData, entryPointSimulationsAddress, stateOverride }); if (error.result === "failed") { throw new ExecutionError( `UserOperation reverted during simulation with reason: ${error.data}`, ExecutionErrors.UserOperationReverted ); } return error; } async function simulateHandleOpV07(client, parameters) { const { packedUserOperation, entryPoint, targetAddress, targetCallData, entryPointSimulationsAddress, stateOverride } = parameters; const entryPointSimulationsSimulateHandleOpCallData = encodeFunctionData({ abi: EntryPointV07SimulationsAbi, functionName: "simulateHandleOp", args: [packedUserOperation] }); const entryPointSimulationsSimulateTargetCallData = encodeFunctionData({ abi: EntryPointV07SimulationsAbi, functionName: "simulateCallData", args: [packedUserOperation, targetAddress, targetCallData] }); const cause = await simulateEntryPoint(client, { entryPoint, entryPointSimulationsCallData: [ entryPointSimulationsSimulateHandleOpCallData, entryPointSimulationsSimulateTargetCallData ], entryPointSimulationsAddress, stateOverride }); try { const executionResult = getSimulateHandleOpResult(cause[0]); if (executionResult.result === "failed") { return executionResult; } const targetCallValidationResult = validateTargetCallDataResult(cause[1]); if (targetCallValidationResult.result === "failed") { return targetCallValidationResult; } return { result: "execution", data: { callDataResult: targetCallValidationResult.data, executionResult: executionResult.data.executionResult } }; } catch (e) { return { result: "failed", data: "Unknown error, could not parse simulate handle op result.", code: ValidationErrors.SimulateValidation }; } } function getSimulateHandleOpResult(data) { try { const decodedError = decodeErrorResult({ abi: EntryPointV07SimulationsAbi, data }); if (decodedError && decodedError.errorName === "FailedOp" && decodedError.args) { return { result: "failed", data: decodedError.args[1], code: ValidationErrors.SimulateValidation }; } if (decodedError && decodedError.errorName === "FailedOpWithRevert" && decodedError.args) { return { result: "failed", data: parseFailedOpWithRevert(decodedError.args?.[2]), code: ValidationErrors.SimulateValidation }; } } catch { const decodedResult = decodeFunctionResult({ abi: EntryPointV07SimulationsAbi, functionName: "simulateHandleOp", data }); return { result: "execution", data: { executionResult: decodedResult } }; } throw new Error("Unexpected error"); } function validateTargetCallDataResult(data) { try { const targetCallResult = decodeFunctionResult({ abi: EntryPointV07SimulationsAbi, functionName: "simulateCallData", data }); const parsedTargetCallResult = targetCallResultSchema.parse(targetCallResult); if (parsedTargetCallResult.success) { return { result: "success", data: parsedTargetCallResult }; } return { result: "failed", data: parsedTargetCallResult.returnData, code: ExecutionErrors.UserOperationReverted }; } catch (_e) { return { result: "failed", data: "Unknown error, could not parse target call data result.", code: ExecutionErrors.UserOperationReverted }; } } export { getExecutionResult, simulateHandleOpV07 };