-
Notifications
You must be signed in to change notification settings - Fork 670
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AA-176: Add ERC-165 "supportsInterface" to the EntryPoint #331
Changes from 3 commits
973ccfb
5b1fd76
9783ff0
3a5c478
c7772ff
e4ef73a
9df75e1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,12 +9,15 @@ pragma solidity ^0.8.12; | |
/* solhint-disable no-inline-assembly */ | ||
/* solhint-disable reason-string */ | ||
|
||
// we also require '@gnosis.pm/safe-contracts' and both libraries have 'IERC165.sol', leading to conflicts | ||
import "@openzeppelin/contracts/utils/introspection/ERC165.sol" as OpenZeppelin; | ||
|
||
import "./UserOperation.sol"; | ||
import "./IStakeManager.sol"; | ||
import "./IAggregator.sol"; | ||
import "./INonceManager.sol"; | ||
|
||
interface IEntryPoint is IStakeManager, INonceManager { | ||
interface IEntryPoint is IStakeManager, INonceManager, OpenZeppelin.IERC165 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why should the IEntryPoint inherit from ERC165 ? (you later manually remove it, so maybe it should not be in the interface itself... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. actually, maybe its good, so a bundler can work only with IEntryPoint, not with EntryPoint contract itself. |
||
/*** | ||
* An event emitted after each successful request. | ||
* @param userOpHash - Unique identifier for the request (hash its entire content, except signature). | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,36 +4,36 @@ | |
╔══════════════════════════╤════════╗ | ||
║ gas estimate "simple" │ 29014 ║ | ||
╟──────────────────────────┼────────╢ | ||
║ gas estimate "big tx 5k" │ 125260 ║ | ||
║ gas estimate "big tx 5k" │ 125248 ║ | ||
╚══════════════════════════╧════════╝ | ||
|
||
╔════════════════════════════════╤═══════╤═══════════════╤════════════════╤═════════════════════╗ | ||
║ handleOps description │ count │ total gasUsed │ per UserOp gas │ per UserOp overhead ║ | ||
║ │ │ │ (delta for │ (compared to ║ | ||
║ │ │ │ one UserOp) │ account.exec()) ║ | ||
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ | ||
║ simple │ 1 │ 81899 │ │ ║ | ||
║ simple │ 1 │ 81943 │ │ ║ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cost 40 per op? 250 per 10 ? |
||
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ | ||
║ simple - diff from previous │ 2 │ │ 44186 │ 15172 ║ | ||
║ simple - diff from previous │ 2 │ │ 44208 │ 15194 ║ | ||
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ | ||
║ simple │ 10 │ 479702 │ │ ║ | ||
║ simple │ 10 │ 479944 │ │ ║ | ||
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ | ||
║ simple - diff from previous │ 11 │ │ 44222 │ 15208 ║ | ||
║ simple - diff from previous │ 11 │ │ 44280 │ 15266 ║ | ||
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ | ||
║ simple paymaster │ 1 │ 88182 │ │ ║ | ||
║ simple paymaster │ 1 │ 88202 │ │ ║ | ||
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ | ||
║ simple paymaster with diff │ 2 │ │ 43175 │ 14161 ║ | ||
║ simple paymaster with diff │ 2 │ │ 43197 │ 14183 ║ | ||
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ | ||
║ simple paymaster │ 10 │ 476938 │ │ ║ | ||
║ simple paymaster │ 10 │ 477132 │ │ ║ | ||
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ | ||
║ simple paymaster with diff │ 11 │ │ 43234 │ 14220 ║ | ||
║ simple paymaster with diff │ 11 │ │ 43208 │ 14194 ║ | ||
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ | ||
║ big tx 5k │ 1 │ 182932 │ │ ║ | ||
║ big tx 5k │ 1 │ 182976 │ │ ║ | ||
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ | ||
║ big tx - diff from previous │ 2 │ │ 144721 │ 19461 ║ | ||
║ big tx - diff from previous │ 2 │ │ 144707 │ 19459 ║ | ||
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ | ||
║ big tx 5k │ 10 │ 1485370 │ │ ║ | ||
║ big tx 5k │ 10 │ 1485552 │ │ ║ | ||
╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ | ||
║ big tx - diff from previous │ 11 │ │ 144710 │ 19450 ║ | ||
║ big tx - diff from previous │ 11 │ │ 144744 │ 19496 ║ | ||
╚════════════════════════════════╧═══════╧═══════════════╧════════════════╧═════════════════════╝ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { Interface, JsonFragment } from '@ethersproject/abi' | ||
|
||
export function getERC165InterfaceID (abi: JsonFragment[]): string { | ||
let interfaceId = | ||
abi | ||
.filter(it => it.type === 'function' && it.name != null) | ||
.map(it => { | ||
const iface = new Interface([it]) | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
return iface.getSighash(it.name!) | ||
}) | ||
.filter(it => it !== '0x01ffc9a7') // remove the IERC165 method itself | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why do you exclude it? see comment in the contract. |
||
.map((x) => parseInt(x, 16)) | ||
.reduce((x, y) => x ^ y) | ||
interfaceId = interfaceId > 0 ? interfaceId : 0xFFFFFFFF + interfaceId + 1 | ||
return '0x' + interfaceId.toString(16).padStart(8, '0') | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,10 @@ import { | |
TestSignatureAggregator__factory, | ||
MaliciousAccount__factory, | ||
TestWarmColdAccount__factory, | ||
IEntryPoint__factory, | ||
SimpleAccountFactory__factory, | ||
IStakeManager__factory, | ||
INonceManager__factory, | ||
TestPaymasterRevertCustomError__factory | ||
} from '../typechain' | ||
import { | ||
|
@@ -53,6 +57,7 @@ import { arrayify, defaultAbiCoder, hexConcat, hexZeroPad, parseEther } from 'et | |
import { debugTransaction } from './debugTx' | ||
import { BytesLike } from '@ethersproject/bytes' | ||
import { toChecksumAddress } from 'ethereumjs-util' | ||
import { getERC165InterfaceID } from '../src/Utils' | ||
|
||
describe('EntryPoint', function () { | ||
let entryPoint: EntryPoint | ||
|
@@ -1362,4 +1367,42 @@ describe('EntryPoint', function () { | |
}) | ||
}) | ||
}) | ||
|
||
describe('ERC-165', function () { | ||
it('should return true for EntryPoint interface IDs', async function () { | ||
const epInterface = IEntryPoint__factory.createInterface() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I miss a sample for: how a bundler can check the current entryPoint adddress it has is OK ? |
||
const smInterface = IStakeManager__factory.createInterface() | ||
const nmInterface = INonceManager__factory.createInterface() | ||
// note: manually generating "pure", solidity-like "type(IEntryPoint).interfaceId" without inherited methods | ||
const epPureInterfaceID = getERC165InterfaceID([ | ||
...epInterface.fragments.filter(it => [ | ||
'handleOps', | ||
'handleAggregatedOps', | ||
'getUserOpHash', | ||
'getSenderAddress', | ||
'simulateValidation', | ||
'simulateHandleOp' | ||
].includes(it.name)) | ||
]) | ||
const epInterfaceID = getERC165InterfaceID([...epInterface.fragments]) | ||
const smInterfaceID = getERC165InterfaceID([...smInterface.fragments]) | ||
const nmInterfaceID = getERC165InterfaceID([...nmInterface.fragments]) | ||
const res1 = await entryPoint.supportsInterface(epInterfaceID) | ||
const res2 = await entryPoint.supportsInterface(smInterfaceID) | ||
const res3 = await entryPoint.supportsInterface(nmInterfaceID) | ||
const res4 = await entryPoint.supportsInterface(epPureInterfaceID) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. better: expect(await entryPoint.supoprtsInterface). to.be.true |
||
expect(res1).to.equal(true) | ||
expect(res2).to.equal(true) | ||
expect(res3).to.equal(true) | ||
expect(res4).to.equal(true) | ||
}) | ||
|
||
it('should return false for a wrong interface', async function () { | ||
const saInterface = SimpleAccountFactory__factory.createInterface() | ||
const entryPointInterfaceID = getERC165InterfaceID([...saInterface.fragments]) | ||
const res = await entryPoint.supportsInterface(entryPointInterfaceID) | ||
expect(res) | ||
.to.equal(false) | ||
}) | ||
}) | ||
}) |
This comment was marked as resolved.
Sorry, something went wrong.