From 0a8dbcd112af60e1e569e1ab2eb09ac5f4334bda Mon Sep 17 00:00:00 2001 From: Dror Tirosh Date: Sun, 29 Oct 2023 20:12:01 +0200 Subject: [PATCH 1/4] delegateAndRevert --- contracts/core/EntryPoint.sol | 6 ++++++ contracts/interfaces/IEntryPoint.sol | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/contracts/core/EntryPoint.sol b/contracts/core/EntryPoint.sol index 74a096bf..05636cf5 100644 --- a/contracts/core/EntryPoint.sol +++ b/contracts/core/EntryPoint.sol @@ -749,4 +749,10 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard, mstore(0, number()) } } + + /// @inheritdoc IEntryPoint + function delegateAndRevert(bytes calldata data) external { + (bool success, bytes memory ret) = address(this).delegatecall(data); + revert DelegateAndRevert(success, ret); + } } diff --git a/contracts/interfaces/IEntryPoint.sol b/contracts/interfaces/IEntryPoint.sol index bace9a64..5367cc4f 100644 --- a/contracts/interfaces/IEntryPoint.sol +++ b/contracts/interfaces/IEntryPoint.sol @@ -173,4 +173,14 @@ 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(bytes calldata data) external; + } From 2f85d36ac594ffd58b159592f5aae048f762dd47 Mon Sep 17 00:00:00 2001 From: Dror Tirosh Date: Wed, 8 Nov 2023 14:07:16 +0200 Subject: [PATCH 2/4] fix test, gascalc --- reports/gas-checker.txt | 18 +++++++++--------- test/entrypoint.test.ts | 12 +++--------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/reports/gas-checker.txt b/reports/gas-checker.txt index b8be925c..9dac2f60 100644 --- a/reports/gas-checker.txt +++ b/reports/gas-checker.txt @@ -14,26 +14,26 @@ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ ║ simple │ 1 │ 81838 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple - diff from previous │ 2 │ │ 44095 │ 15081 ║ +║ simple - diff from previous │ 2 │ │ 44083 │ 15069 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple │ 10 │ 478810 │ │ ║ +║ simple │ 10 │ 478822 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple - diff from previous │ 11 │ │ 44131 │ 15117 ║ +║ simple - diff from previous │ 11 │ │ 44119 │ 15105 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ ║ simple paymaster │ 1 │ 88109 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple paymaster with diff │ 2 │ │ 43096 │ 14082 ║ +║ simple paymaster with diff │ 2 │ │ 43084 │ 14070 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple paymaster │ 10 │ 476022 │ │ ║ +║ simple paymaster │ 10 │ 476070 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple paymaster with diff │ 11 │ │ 43155 │ 14141 ║ +║ simple paymaster with diff │ 11 │ │ 43131 │ 14117 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ ║ big tx 5k │ 1 │ 182895 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx - diff from previous │ 2 │ │ 144594 │ 19334 ║ +║ big tx - diff from previous │ 2 │ │ 144606 │ 19346 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx 5k │ 10 │ 1484454 │ │ ║ +║ big tx 5k │ 10 │ 1484490 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx - diff from previous │ 11 │ │ 144619 │ 19359 ║ +║ big tx - diff from previous │ 11 │ │ 144655 │ 19395 ║ ╚════════════════════════════════╧═══════╧═══════════════╧════════════════╧═════════════════════╝ diff --git a/test/entrypoint.test.ts b/test/entrypoint.test.ts index b1fb051f..3829f91d 100644 --- a/test/entrypoint.test.ts +++ b/test/entrypoint.test.ts @@ -1225,19 +1225,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]) From 306048e830908c33072f2349b342cf42a9409c06 Mon Sep 17 00:00:00 2001 From: Dror Tirosh Date: Tue, 14 Nov 2023 17:40:03 +0200 Subject: [PATCH 3/4] lints --- test/entrypoint.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/entrypoint.test.ts b/test/entrypoint.test.ts index 3829f91d..5e476e77 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 { @@ -1231,7 +1230,7 @@ describe('EntryPoint', function () { // 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 => !inheritedMethods.has(it.name) && it.type == 'function') + ...epInterface.fragments.filter(it => !inheritedMethods.has(it.name) && it.type === 'function') ] const epPureInterfaceID = getERC165InterfaceID(epPureInterfaceFunctions) const smInterfaceID = getERC165InterfaceID([...smInterface.fragments]) From a9f170351c113a0de77430b354a902947b822c8b Mon Sep 17 00:00:00 2001 From: Dror Tirosh Date: Tue, 19 Dec 2023 21:12:23 +0200 Subject: [PATCH 4/4] add target --- contracts/core/EntryPoint.sol | 4 ++-- contracts/interfaces/IEntryPoint.sol | 3 +-- reports/gas-checker.txt | 24 ++++++++++++------------ 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/contracts/core/EntryPoint.sol b/contracts/core/EntryPoint.sol index 3f880b79..f619874b 100644 --- a/contracts/core/EntryPoint.sol +++ b/contracts/core/EntryPoint.sol @@ -755,8 +755,8 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard, } /// @inheritdoc IEntryPoint - function delegateAndRevert(bytes calldata data) external { - (bool success, bytes memory ret) = address(this).delegatecall(data); + 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 2b48ce7e..c815a264 100644 --- a/contracts/interfaces/IEntryPoint.sol +++ b/contracts/interfaces/IEntryPoint.sol @@ -206,6 +206,5 @@ interface IEntryPoint is IStakeManager, INonceManager { * 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(bytes calldata data) external; - + function delegateAndRevert(address target, bytes calldata data) external; } diff --git a/reports/gas-checker.txt b/reports/gas-checker.txt index 0be941e8..25d1dcea 100644 --- a/reports/gas-checker.txt +++ b/reports/gas-checker.txt @@ -2,9 +2,9 @@ the destination is "account.entryPoint()", which is known to be "hot" address used by this account it little higher than EOA call: its an exec from entrypoint (or account owner) into account contract, verifying msg.sender and exec to target) ╔══════════════════════════╤════════╗ -║ gas estimate "simple" │ 29002 ║ +║ gas estimate "simple" │ 29014 ║ ╟──────────────────────────┼────────╢ -║ gas estimate "big tx 5k" │ 125248 ║ +║ gas estimate "big tx 5k" │ 125260 ║ ╚══════════════════════════╧════════╝ ╔════════════════════════════════╤═══════╤═══════════════╤════════════════╤═════════════════════╗ @@ -14,26 +14,26 @@ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ ║ simple │ 1 │ 81930 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple - diff from previous │ 2 │ │ 44187 │ 15185 ║ +║ simple - diff from previous │ 2 │ │ 44187 │ 15173 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple │ 10 │ 479718 │ │ ║ +║ simple │ 10 │ 479742 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple - diff from previous │ 11 │ │ 44223 │ 15221 ║ +║ simple - diff from previous │ 11 │ │ 44247 │ 15233 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ ║ simple paymaster │ 1 │ 88187 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple paymaster with diff │ 2 │ │ 43126 │ 14124 ║ +║ simple paymaster with diff │ 2 │ │ 43114 │ 14100 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple paymaster │ 10 │ 476670 │ │ ║ +║ simple paymaster │ 10 │ 476706 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple paymaster with diff │ 11 │ │ 43173 │ 14171 ║ +║ simple paymaster with diff │ 11 │ │ 43173 │ 14159 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx 5k │ 1 │ 182963 │ │ ║ +║ big tx 5k │ 1 │ 182987 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx - diff from previous │ 2 │ │ 144686 │ 19438 ║ +║ big tx - diff from previous │ 2 │ │ 144698 │ 19438 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx 5k │ 10 │ 1485374 │ │ ║ +║ big tx 5k │ 10 │ 1485386 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx - diff from previous │ 11 │ │ 144759 │ 19511 ║ +║ big tx - diff from previous │ 11 │ │ 144759 │ 19499 ║ ╚════════════════════════════════╧═══════╧═══════════════╧════════════════╧═════════════════════╝