diff --git a/packages/boba/account-abstraction/contracts/bundler/EntryPointWrapper.sol b/packages/boba/account-abstraction/contracts/bundler/EntryPointWrapper.sol index bf9028e29e..22413acc9a 100644 --- a/packages/boba/account-abstraction/contracts/bundler/EntryPointWrapper.sol +++ b/packages/boba/account-abstraction/contracts/bundler/EntryPointWrapper.sol @@ -39,19 +39,22 @@ contract EntryPointWrapper { StakeInfo stakeInfo; } - /** - * returned aggregated signature info. - * the aggregator returned by the account, and its current stake. - */ - struct SelectorType { - string validator; + struct FailedOpStatus { + bool status; + uint256 opIndex; + string reason; } + struct Response { + string selectorType; + ReturnInfo returnInfo; + StakeInfo senderInfo; + StakeInfo factoryInfo; + StakeInfo paymasterInfo; + AggregatorStakeInfo aggregatorInfo; + } - event ReturnedData(bytes revertData); - // event SelectorType(string); - /** * a custom revert error of handleOps, to identify the offending op. * NOTE: if simulateValidation passes successfully, there should be no reason for handleOps to fail on it. @@ -89,27 +92,30 @@ contract EntryPointWrapper { IEntryPoint public entryPoint; + StakeInfo private emptyStakeInfo = StakeInfo(0, 0); + AggregatorStakeInfo private emptyAggregatorInfo = AggregatorStakeInfo(address(0), emptyStakeInfo); + ReturnInfo private emptyReturnInfo = ReturnInfo(0, 0, false, 0, 0, new bytes(0)); + Response private emptyResponse = Response("", emptyReturnInfo, emptyStakeInfo, emptyStakeInfo, emptyStakeInfo, emptyAggregatorInfo); + FailedOpStatus private emptyFailedOp = FailedOpStatus(false, 0, ""); + constructor(IEntryPoint _entryPoint) { entryPoint = _entryPoint; } - function simulateValidation(UserOperation calldata userOp) external returns (SelectorType memory, ReturnInfo memory, StakeInfo memory, StakeInfo memory, StakeInfo memory, AggregatorStakeInfo memory) { + function simulateValidation(UserOperation calldata userOp) external returns (FailedOpStatus memory, Response memory) { try entryPoint.simulateValidation(userOp) {} catch (bytes memory revertData) { bytes4 receivedSelector = bytes4(revertData); if (receivedSelector == ValidationResult.selector) { (ReturnInfo memory returnInfo, StakeInfo memory senderInfo, StakeInfo memory factoryInfo, StakeInfo memory paymasterInfo) = abi.decode(slice(revertData, 4, revertData.length - 4), (ReturnInfo, StakeInfo, StakeInfo, StakeInfo)); - StakeInfo memory emptyStakeInfo = StakeInfo(0, 0); - AggregatorStakeInfo memory emptyAggregatorInfo = AggregatorStakeInfo(address(0), emptyStakeInfo); - SelectorType memory selector = SelectorType('ValidationResult'); - return (selector, returnInfo, senderInfo, factoryInfo, paymasterInfo, emptyAggregatorInfo); + return (emptyFailedOp, Response('ValidationResult', returnInfo, senderInfo, factoryInfo, paymasterInfo, emptyAggregatorInfo)); } else if (receivedSelector == ValidationResultWithAggregation.selector) { (ReturnInfo memory returnInfo, StakeInfo memory senderInfo, StakeInfo memory factoryInfo, StakeInfo memory paymasterInfo, AggregatorStakeInfo memory aggregatorInfo) = abi.decode(slice(revertData, 4, revertData.length - 4), (ReturnInfo, StakeInfo, StakeInfo, StakeInfo, AggregatorStakeInfo)); - SelectorType memory selector = SelectorType('ValidationResultWithAggregation'); - return (selector, returnInfo, senderInfo, factoryInfo, paymasterInfo, aggregatorInfo); + return (emptyFailedOp, Response('ValidationResultWithAggregation', returnInfo, senderInfo, factoryInfo, paymasterInfo, aggregatorInfo)); } else if (receivedSelector == FailedOp.selector){ - emit ReturnedData(revertData); + (uint256 opIndex, string memory reason) = abi.decode(slice(revertData, 4, revertData.length - 4), (uint256, string)); + return (FailedOpStatus(true, opIndex, reason), emptyResponse); } } } diff --git a/packages/boba/bundler/src/modules/ValidationManager.ts b/packages/boba/bundler/src/modules/ValidationManager.ts index 89f40f0251..10fc9a03da 100644 --- a/packages/boba/bundler/src/modules/ValidationManager.ts +++ b/packages/boba/bundler/src/modules/ValidationManager.ts @@ -68,22 +68,14 @@ export class ValidationManager { simulateValidation: any ): ValidationResult { - let selectorType: EntryPointWrapper.SelectorTypeStructOutput - let returnInfo: EntryPointWrapper.ReturnInfoStructOutput - let senderInfo: EntryPointWrapper.StakeInfoStructOutput - let factoryInfo: EntryPointWrapper.StakeInfoStructOutput - let paymasterInfo: EntryPointWrapper.StakeInfoStructOutput - let aggregatorInfo: EntryPointWrapper.AggregatorStakeInfoStructOutput + let failedOpStatus: EntryPointWrapper.FailedOpStatusStructOutput + let response: EntryPointWrapper.ResponseStructOutput ;[ - selectorType, - returnInfo, - senderInfo, - factoryInfo, - paymasterInfo, - aggregatorInfo, + failedOpStatus, + response, ] = simulateValidation - if (!selectorType.validator.startsWith('ValidationResult')) { + if (!response.selectorType.startsWith('ValidationResult')) { // parse it as FailedOp // if its FailedOp, then we have the paymaster param... otherwise its an Error(string) let paymaster = hexlify(userOp.paymasterAndData)?.slice(0, 42) @@ -93,12 +85,12 @@ export class ValidationManager { if (paymaster == null) { throw new RpcError( - `account validation failed: ${selectorType}`, + `account validation failed: ${failedOpStatus}`, ValidationErrors.SimulateValidation ) } else { throw new RpcError( - `paymaster validation failed: ${selectorType}`, + `paymaster validation failed: ${failedOpStatus}`, ValidationErrors.SimulatePaymasterValidation, { paymaster } ) @@ -122,16 +114,16 @@ export class ValidationManager { } return { - returnInfo, + returnInfo: response.returnInfo, senderInfo: { - ...senderInfo, + ...response.senderInfo, addr: userOp.sender, }, - factoryInfo: fillEntity(userOp.initCode, factoryInfo), - paymasterInfo: fillEntity(userOp.paymasterAndData, paymasterInfo), + factoryInfo: fillEntity(userOp.initCode, response.factoryInfo), + paymasterInfo: fillEntity(userOp.paymasterAndData, response.paymasterInfo), aggregatorInfo: fillEntity( - aggregatorInfo?.aggregator, - aggregatorInfo?.stakeInfo + response.aggregatorInfo?.aggregator, + response.aggregatorInfo?.stakeInfo ), } }