@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
JavaScript
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
};