-
Notifications
You must be signed in to change notification settings - Fork 226
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WIP: Rewrite the ERC-7562 parser in a modular configurable way
- Loading branch information
Showing
4 changed files
with
167 additions
and
0 deletions.
There are no files selected for viewing
11 changes: 11 additions & 0 deletions
11
packages/validation-manager/src/AccountAbstractionEntity.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
export const enum AccountAbstractionEntity { | ||
sender = 'Sender', | ||
paymaster = 'Paymaster', | ||
factory = 'Factory', | ||
aggregator = 'Aggregator', | ||
senderCreator = 'SenderCreator', | ||
entryPoint = 'EntryPoint', | ||
// TODO: leaving 'fixme' entity for future refactor | ||
// (some rules are checked in a way that makes it hard to find entity) | ||
fixme = 'fixme' | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
export const enum ERC7562Rule { | ||
op011 = 'OP-011', | ||
op012 = 'OP-012', | ||
op013 = 'OP-013', | ||
op020 = 'OP-020', | ||
op031 = 'OP-031', | ||
op041 = 'OP-041', | ||
op042 = 'OP-042', | ||
op051 = 'OP-051', | ||
op052 = 'OP-052', | ||
op053 = 'OP-053', | ||
op054 = 'OP-054', | ||
op061 = 'OP-061', | ||
op062 = 'OP-062', | ||
op070 = 'OP-070', | ||
op080 = 'OP-080', | ||
cod010 = 'COD-010', | ||
sto010 = 'STO-010', | ||
sto021 = 'STO-021', | ||
sto022 = 'STO-022', | ||
sto031 = 'STO-031', | ||
sto032 = 'STO-032', | ||
sto033 = 'STO-033', | ||
sto040 = 'STO-040', | ||
sto041 = 'STO-041', | ||
grep010 = 'GREP-010', | ||
grep020 = 'GREP-020', | ||
grep040 = 'GREP-040', | ||
grep050 = 'GREP-050', | ||
srep010 = 'SREP-010', | ||
srep040 = 'SREP-040', | ||
erep010 = 'EREP-010', | ||
erep015 = 'EREP-015', | ||
erep020 = 'EREP-020', | ||
erep030 = 'EREP-030', | ||
erep040 = 'EREP-040' | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { ValidationErrors } from '@account-abstraction/utils' | ||
|
||
import { ERC7562Rule } from './ERC7562Rule' | ||
import { AccountAbstractionEntity } from './AccountAbstractionEntity' | ||
|
||
export interface ERC7562RuleViolation { | ||
rule: ERC7562Rule | ||
depth: number | ||
entity: AccountAbstractionEntity | ||
address: string | ||
errorCode: ValidationErrors | ||
description: string | ||
conflict?: string | ||
opcode?: string | ||
value?: string | ||
slot?: string | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import { ERC7562RuleViolation } from './ERC7562RuleViolation' | ||
import { OperationBase, ValidationErrors } from '@account-abstraction/utils' | ||
import { BundlerTracerResult, MethodInfo } from './BundlerCollectorTracer' | ||
import { ERC7562Rule } from './ERC7562Rule' | ||
import { AltMempoolConfig } from '@account-abstraction/utils/dist/src/altmempool/AltMempoolConfig' | ||
import { AccountAbstractionEntity } from './AccountAbstractionEntity' | ||
import { BigNumber } from 'ethers' | ||
|
||
export class ERC7562TracerParser { | ||
constructor ( | ||
readonly mempoolConfig: AltMempoolConfig, | ||
readonly entryPointAddress: string | ||
) { | ||
|
||
} | ||
|
||
private _isCallToEntryPoint (call: MethodInfo): boolean { | ||
return call.to?.toLowerCase() === this.entryPointAddress?.toLowerCase() && | ||
call.from?.toLowerCase() !== this.entryPointAddress?.toLowerCase() | ||
} | ||
|
||
/** | ||
* Validates the UserOperation and throws an exception in case current mempool configuration rules were violated. | ||
*/ | ||
requireCompliance ( | ||
userOp: OperationBase, | ||
tracerResults: BundlerTracerResult | ||
): void { | ||
const violations = this.parseResults(userOp, tracerResults) | ||
if (violations.length > 0) { | ||
// TODO: human-readable description of which rules were violated. | ||
throw new Error('Rules Violated') | ||
} | ||
} | ||
|
||
parseResults ( | ||
userOp: OperationBase, | ||
tracerResults: BundlerTracerResult | ||
): ERC7562RuleViolation[] { | ||
return [] | ||
} | ||
|
||
checkSanity (tracerResults: BundlerTracerResult): void { | ||
if (Object.values(tracerResults.callsFromEntryPoint).length < 1) { | ||
throw new Error('Unexpected traceCall result: no calls from entrypoint.') | ||
} | ||
} | ||
|
||
/** | ||
* OP-052: May call `depositTo(sender)` with any value from either the `sender` or `factory`. | ||
* OP-053: May call the fallback function from the `sender` with any value. | ||
* OP-054: Any other access to the EntryPoint is forbidden. | ||
*/ | ||
checkOp054 (tracerResults: BundlerTracerResult): ERC7562RuleViolation[] { | ||
const callStack = tracerResults.calls.filter((call: any) => call.topLevelTargetAddress == null) as MethodInfo[] | ||
const callInfoEntryPoint = callStack.filter(call => { | ||
const isCallToEntryPoint = this._isCallToEntryPoint(call) | ||
const isEntryPointCallAllowedOP052 = call.method === 'depositTo' | ||
const isEntryPointCallAllowedOP053 = call.method === '0x' | ||
const isEntryPointCallAllowed = isEntryPointCallAllowedOP052 || isEntryPointCallAllowedOP053 | ||
return isCallToEntryPoint && !isEntryPointCallAllowed | ||
}) | ||
return callInfoEntryPoint.map((it: MethodInfo): ERC7562RuleViolation => { | ||
return { | ||
rule: ERC7562Rule.op054, | ||
// TODO: fill in depth, entity | ||
depth: -1, | ||
entity: AccountAbstractionEntity.fixme, | ||
address: it.from, | ||
opcode: it.type, | ||
value: it.value, | ||
errorCode: ValidationErrors.OpcodeValidation, | ||
description: `illegal call into EntryPoint during validation ${it?.method}` | ||
} | ||
}) | ||
} | ||
|
||
/** | ||
* OP-061: CALL with value is forbidden. The only exception is a call to the EntryPoint. | ||
*/ | ||
checkOp061 (tracerResults: BundlerTracerResult): ERC7562RuleViolation[] { | ||
const callStack = tracerResults.calls.filter((call: any) => call.topLevelTargetAddress == null) as MethodInfo[] | ||
const illegalNonZeroValueCall = callStack.filter( | ||
call => | ||
!this._isCallToEntryPoint(call) && | ||
!BigNumber.from(call.value ?? 0).eq(0) | ||
) | ||
return illegalNonZeroValueCall.map((it: MethodInfo): ERC7562RuleViolation => { | ||
return { | ||
rule: ERC7562Rule.op061, | ||
// TODO: fill in depth, entity | ||
depth: -1, | ||
entity: AccountAbstractionEntity.fixme, | ||
address: it.from, | ||
opcode: it.type, | ||
value: it.value, | ||
errorCode: ValidationErrors.OpcodeValidation, | ||
description: 'May not may CALL with value' | ||
} | ||
}) | ||
} | ||
} |