Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
}
}
}
Expand Down
34 changes: 13 additions & 21 deletions packages/boba/bundler/src/modules/ValidationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 }
)
Expand All @@ -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
),
}
}
Expand Down