diff --git a/contracts/core/EntryPoint.sol b/contracts/core/EntryPoint.sol index 685ff3d5..f619874b 100644 --- a/contracts/core/EntryPoint.sol +++ b/contracts/core/EntryPoint.sol @@ -753,4 +753,10 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard, data := offset } } + + /// @inheritdoc IEntryPoint + function delegateAndRevert(address target, bytes calldata data) external { + (bool success, bytes memory ret) = target.delegatecall(data); + revert DelegateAndRevert(success, ret); + } } diff --git a/contracts/interfaces/IEntryPoint.sol b/contracts/interfaces/IEntryPoint.sol index 40df5c03..c815a264 100644 --- a/contracts/interfaces/IEntryPoint.sol +++ b/contracts/interfaces/IEntryPoint.sol @@ -198,4 +198,13 @@ interface IEntryPoint is IStakeManager, INonceManager { */ function getSenderAddress(bytes memory initCode) external; + error DelegateAndRevert(bool success, bytes ret); + + /** + * Helper method for dry-run testing. + * @dev calling this method, the EntryPoint will make a delegatecall to the given data, and report (via revert) the result. + * The method always revert, so is only useful off-chain for dry run calls, in cases where state-override to replace + * actual EntryPoint code is less convenient. + */ + function delegateAndRevert(address target, bytes calldata data) external; } diff --git a/reports/gas-checker.txt b/reports/gas-checker.txt index 1a8be462..25d1dcea 100644 --- a/reports/gas-checker.txt +++ b/reports/gas-checker.txt @@ -16,24 +16,24 @@ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ ║ simple - diff from previous │ 2 │ │ 44187 │ 15173 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple │ 10 │ 479694 │ │ ║ +║ simple │ 10 │ 479742 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ ║ simple - diff from previous │ 11 │ │ 44247 │ 15233 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ ║ simple paymaster │ 1 │ 88187 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple paymaster with diff │ 2 │ │ 43138 │ 14124 ║ +║ simple paymaster with diff │ 2 │ │ 43114 │ 14100 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple paymaster │ 10 │ 476718 │ │ ║ +║ simple paymaster │ 10 │ 476706 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple paymaster with diff │ 11 │ │ 43185 │ 14171 ║ +║ simple paymaster with diff │ 11 │ │ 43173 │ 14159 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ ║ big tx 5k │ 1 │ 182987 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ ║ big tx - diff from previous │ 2 │ │ 144698 │ 19438 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx 5k │ 10 │ 1485290 │ │ ║ +║ big tx 5k │ 10 │ 1485386 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx - diff from previous │ 11 │ │ 144699 │ 19439 ║ +║ big tx - diff from previous │ 11 │ │ 144759 │ 19499 ║ ╚════════════════════════════════╧═══════╧═══════════════╧════════════════╧═════════════════════╝ diff --git a/test/entrypoint.test.ts b/test/entrypoint.test.ts index 6485e0fe..dc235517 100644 --- a/test/entrypoint.test.ts +++ b/test/entrypoint.test.ts @@ -25,7 +25,6 @@ import { SimpleAccountFactory__factory, IStakeManager__factory, INonceManager__factory, - EntryPoint__factory, EntryPoint } from '../typechain' import { @@ -1310,19 +1309,13 @@ describe('EntryPoint', function () { }) it('should return true for pure EntryPoint, IStakeManager and INonceManager interface IDs', async function () { - const epInterface = EntryPoint__factory.createInterface() + const epInterface = IEntryPoint__factory.createInterface() const smInterface = IStakeManager__factory.createInterface() const nmInterface = INonceManager__factory.createInterface() // note: manually generating "pure", solidity-like "type(IEntryPoint).interfaceId" without inherited methods + const inheritedMethods = new Set([...smInterface.fragments, ...nmInterface.fragments].map(f => f.name)) const epPureInterfaceFunctions = [ - ...epInterface.fragments.filter(it => [ - 'handleOps', - 'handleAggregatedOps', - 'getUserOpHash', - 'getSenderAddress', - 'simulateValidation', - 'simulateHandleOp' - ].includes(it.name)) + ...epInterface.fragments.filter(it => !inheritedMethods.has(it.name) && it.type === 'function') ] const epPureInterfaceID = getERC165InterfaceID(epPureInterfaceFunctions) const smInterfaceID = getERC165InterfaceID([...smInterface.fragments])