From 973ccfbfb6251ffe81d29db9b2d3126e71e2a62f Mon Sep 17 00:00:00 2001 From: Alex Forshtat Date: Sun, 20 Aug 2023 19:30:47 +0300 Subject: [PATCH 1/7] AA-176: Add ERC-165 "supportsInterface" to the EntryPoint Note: due to 'StakeManager', 'NonceManager' being 'abstract' and only parts of the EntryPoint, and due to IEntryPoint inheriting from all interfaces, the implementation looks a little weird. I this this is fine, though. --- contracts/core/EntryPoint.sol | 11 ++++++- contracts/interfaces/IEntryPoint.sol | 5 +++- src/Utils.ts | 17 +++++++++++ test/entrypoint.test.ts | 43 ++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 src/Utils.ts diff --git a/contracts/core/EntryPoint.sol b/contracts/core/EntryPoint.sol index a5f6f274..759ad36e 100644 --- a/contracts/core/EntryPoint.sol +++ b/contracts/core/EntryPoint.sol @@ -19,7 +19,7 @@ import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; * Account-Abstraction (EIP-4337) singleton EntryPoint implementation. * Only one instance required on each chain. */ -contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard { +contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard, OpenZeppelin.ERC165 { using UserOperationLib for UserOperation; @@ -39,6 +39,15 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard */ uint256 public constant SIG_VALIDATION_FAILED = 1; + /// @inheritdoc OpenZeppelin.IERC165 + function supportsInterface(bytes4 interfaceId) public view virtual override(OpenZeppelin.ERC165, OpenZeppelin.IERC165) returns (bool) { + return interfaceId == (type(IEntryPoint).interfaceId ^ type(IStakeManager).interfaceId ^ type(INonceManager).interfaceId) || + interfaceId == type(IEntryPoint).interfaceId || + interfaceId == type(IStakeManager).interfaceId || + interfaceId == type(INonceManager).interfaceId || + super.supportsInterface(interfaceId); + } + /** * Compensate the caller's beneficiary address with the collected fees of all UserOperations. * @param beneficiary - The address to receive the fees. diff --git a/contracts/interfaces/IEntryPoint.sol b/contracts/interfaces/IEntryPoint.sol index ddb2693d..2a2f34b8 100644 --- a/contracts/interfaces/IEntryPoint.sol +++ b/contracts/interfaces/IEntryPoint.sol @@ -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 { /*** * An event emitted after each successful request. * @param userOpHash - Unique identifier for the request (hash its entire content, except signature). diff --git a/src/Utils.ts b/src/Utils.ts new file mode 100644 index 00000000..541529d5 --- /dev/null +++ b/src/Utils.ts @@ -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 + .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') +} diff --git a/test/entrypoint.test.ts b/test/entrypoint.test.ts index 082badb6..61bbbbaf 100644 --- a/test/entrypoint.test.ts +++ b/test/entrypoint.test.ts @@ -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() + 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) + 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) + }) + }) }) From 5b1fd761b4e08f49cf9f2f1a32cb3a7e32706086 Mon Sep 17 00:00:00 2001 From: Alex Forshtat Date: Sun, 20 Aug 2023 19:37:54 +0300 Subject: [PATCH 2/7] Update 'gas-checker.txt' --- reports/gas-checker.txt | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/reports/gas-checker.txt b/reports/gas-checker.txt index a1f07868..9243f380 100644 --- a/reports/gas-checker.txt +++ b/reports/gas-checker.txt @@ -12,28 +12,28 @@ ║ │ │ │ (delta for │ (compared to ║ ║ │ │ │ one UserOp) │ account.exec()) ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple │ 1 │ 81899 │ │ ║ +║ simple │ 1 │ 81943 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple - diff from previous │ 2 │ │ 44186 │ 15172 ║ +║ simple - diff from previous │ 2 │ │ 44196 │ 15182 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple │ 10 │ 479702 │ │ ║ +║ simple │ 10 │ 479980 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple - diff from previous │ 11 │ │ 44222 │ 15208 ║ +║ simple - diff from previous │ 11 │ │ 44232 │ 15218 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple paymaster │ 1 │ 88182 │ │ ║ +║ simple paymaster │ 1 │ 88226 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple paymaster with diff │ 2 │ │ 43175 │ 14161 ║ +║ simple paymaster with diff │ 2 │ │ 43197 │ 14183 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple paymaster │ 10 │ 476938 │ │ ║ +║ simple paymaster │ 10 │ 477156 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple paymaster with diff │ 11 │ │ 43234 │ 14220 ║ +║ simple paymaster with diff │ 11 │ │ 43280 │ 14266 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx 5k │ 1 │ 182932 │ │ ║ +║ big tx 5k │ 1 │ 182988 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx - diff from previous │ 2 │ │ 144721 │ 19461 ║ +║ big tx - diff from previous │ 2 │ │ 144731 │ 19471 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx 5k │ 10 │ 1485370 │ │ ║ +║ big tx 5k │ 10 │ 1485552 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx - diff from previous │ 11 │ │ 144710 │ 19450 ║ +║ big tx - diff from previous │ 11 │ │ 144756 │ 19496 ║ ╚════════════════════════════════╧═══════╧═══════════════╧════════════════╧═════════════════════╝ From 9783ff08e3a09d45c3e66e08fa3cc471783161ed Mon Sep 17 00:00:00 2001 From: Alex Forshtat Date: Sun, 20 Aug 2023 19:47:39 +0300 Subject: [PATCH 3/7] WTF --- reports/gas-checker.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/reports/gas-checker.txt b/reports/gas-checker.txt index 9243f380..294064d0 100644 --- a/reports/gas-checker.txt +++ b/reports/gas-checker.txt @@ -4,7 +4,7 @@ ╔══════════════════════════╤════════╗ ║ gas estimate "simple" │ 29014 ║ ╟──────────────────────────┼────────╢ -║ gas estimate "big tx 5k" │ 125260 ║ +║ gas estimate "big tx 5k" │ 125248 ║ ╚══════════════════════════╧════════╝ ╔════════════════════════════════╤═══════╤═══════════════╤════════════════╤═════════════════════╗ @@ -14,26 +14,26 @@ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ ║ simple │ 1 │ 81943 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple - diff from previous │ 2 │ │ 44196 │ 15182 ║ +║ simple - diff from previous │ 2 │ │ 44208 │ 15194 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple │ 10 │ 479980 │ │ ║ +║ simple │ 10 │ 479944 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple - diff from previous │ 11 │ │ 44232 │ 15218 ║ +║ simple - diff from previous │ 11 │ │ 44280 │ 15266 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple paymaster │ 1 │ 88226 │ │ ║ +║ simple paymaster │ 1 │ 88202 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ ║ simple paymaster with diff │ 2 │ │ 43197 │ 14183 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple paymaster │ 10 │ 477156 │ │ ║ +║ simple paymaster │ 10 │ 477132 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple paymaster with diff │ 11 │ │ 43280 │ 14266 ║ +║ simple paymaster with diff │ 11 │ │ 43208 │ 14194 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx 5k │ 1 │ 182988 │ │ ║ +║ big tx 5k │ 1 │ 182976 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx - diff from previous │ 2 │ │ 144731 │ 19471 ║ +║ big tx - diff from previous │ 2 │ │ 144707 │ 19459 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ ║ big tx 5k │ 10 │ 1485552 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx - diff from previous │ 11 │ │ 144756 │ 19496 ║ +║ big tx - diff from previous │ 11 │ │ 144744 │ 19496 ║ ╚════════════════════════════════╧═══════╧═══════════════╧════════════════╧═════════════════════╝ From 3a5c478460061cb68fbd72927a21669f526b0a95 Mon Sep 17 00:00:00 2001 From: Alex Forshtat Date: Mon, 21 Aug 2023 14:14:08 +0300 Subject: [PATCH 4/7] Separate main test and other tests --- test/entrypoint.test.ts | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/test/entrypoint.test.ts b/test/entrypoint.test.ts index 61bbbbaf..281288ce 100644 --- a/test/entrypoint.test.ts +++ b/test/entrypoint.test.ts @@ -25,6 +25,7 @@ import { SimpleAccountFactory__factory, IStakeManager__factory, INonceManager__factory, + EntryPoint__factory, TestPaymasterRevertCustomError__factory } from '../typechain' import { @@ -1369,12 +1370,18 @@ describe('EntryPoint', function () { }) describe('ERC-165', function () { - it('should return true for EntryPoint interface IDs', async function () { - const epInterface = IEntryPoint__factory.createInterface() + it('should return true for IEntryPoint interface ID', async function () { + const iepInterface = IEntryPoint__factory.createInterface() + const iepInterfaceID = getERC165InterfaceID([...iepInterface.fragments]) + expect(await entryPoint.supportsInterface(iepInterfaceID)).to.equal(true) + }) + + it('should return true for pure EntryPoint, IStakeManager and INonceManager interface IDs', async function () { + const epInterface = EntryPoint__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 epPureInterfaceID = getERC165InterfaceID([ + const epPureInterfaceFunctions = [ ...epInterface.fragments.filter(it => [ 'handleOps', 'handleAggregatedOps', @@ -1383,26 +1390,19 @@ describe('EntryPoint', function () { 'simulateValidation', 'simulateHandleOp' ].includes(it.name)) - ]) - const epInterfaceID = getERC165InterfaceID([...epInterface.fragments]) + ] + const epPureInterfaceID = getERC165InterfaceID(epPureInterfaceFunctions) 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) - expect(res1).to.equal(true) - expect(res2).to.equal(true) - expect(res3).to.equal(true) - expect(res4).to.equal(true) + expect(await entryPoint.supportsInterface(smInterfaceID)).to.equal(true) + expect(await entryPoint.supportsInterface(nmInterfaceID)).to.equal(true) + expect(await entryPoint.supportsInterface(epPureInterfaceID)).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) + expect(await entryPoint.supportsInterface(entryPointInterfaceID)).to.equal(false) }) }) }) From c7772ff85a54722866478d2dc99fa92e8b7410b0 Mon Sep 17 00:00:00 2001 From: Alex Forshtat Date: Mon, 21 Aug 2023 14:33:22 +0300 Subject: [PATCH 5/7] Remove 'IERC165' from 'IEntryPoint' inheritance --- contracts/core/EntryPoint.sol | 5 ++++- contracts/interfaces/IEntryPoint.sol | 5 +---- src/Utils.ts | 1 - 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/contracts/core/EntryPoint.sol b/contracts/core/EntryPoint.sol index 759ad36e..bf0d1cbe 100644 --- a/contracts/core/EntryPoint.sol +++ b/contracts/core/EntryPoint.sol @@ -13,6 +13,9 @@ import "./StakeManager.sol"; import "./SenderCreator.sol"; import "./Helpers.sol"; import "./NonceManager.sol"; + +// 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 "@openzeppelin/contracts/security/ReentrancyGuard.sol"; /* @@ -40,7 +43,7 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard, uint256 public constant SIG_VALIDATION_FAILED = 1; /// @inheritdoc OpenZeppelin.IERC165 - function supportsInterface(bytes4 interfaceId) public view virtual override(OpenZeppelin.ERC165, OpenZeppelin.IERC165) returns (bool) { + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == (type(IEntryPoint).interfaceId ^ type(IStakeManager).interfaceId ^ type(INonceManager).interfaceId) || interfaceId == type(IEntryPoint).interfaceId || interfaceId == type(IStakeManager).interfaceId || diff --git a/contracts/interfaces/IEntryPoint.sol b/contracts/interfaces/IEntryPoint.sol index 2a2f34b8..ddb2693d 100644 --- a/contracts/interfaces/IEntryPoint.sol +++ b/contracts/interfaces/IEntryPoint.sol @@ -9,15 +9,12 @@ 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, OpenZeppelin.IERC165 { +interface IEntryPoint is IStakeManager, INonceManager { /*** * An event emitted after each successful request. * @param userOpHash - Unique identifier for the request (hash its entire content, except signature). diff --git a/src/Utils.ts b/src/Utils.ts index 541529d5..8b520578 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -9,7 +9,6 @@ export function getERC165InterfaceID (abi: JsonFragment[]): string { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return iface.getSighash(it.name!) }) - .filter(it => it !== '0x01ffc9a7') // remove the IERC165 method itself .map((x) => parseInt(x, 16)) .reduce((x, y) => x ^ y) interfaceId = interfaceId > 0 ? interfaceId : 0xFFFFFFFF + interfaceId + 1 From e4ef73a3873372b5753dccc5d7f67a5cbc3d9309 Mon Sep 17 00:00:00 2001 From: Alex Forshtat Date: Mon, 21 Aug 2023 14:35:34 +0300 Subject: [PATCH 6/7] Add comment --- contracts/core/EntryPoint.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/core/EntryPoint.sol b/contracts/core/EntryPoint.sol index bf0d1cbe..af9fcbf4 100644 --- a/contracts/core/EntryPoint.sol +++ b/contracts/core/EntryPoint.sol @@ -44,6 +44,7 @@ contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard, /// @inheritdoc OpenZeppelin.IERC165 function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + // note: solidity "type(IEntryPoint).interfaceId" is without inherited methods but we want to check everything return interfaceId == (type(IEntryPoint).interfaceId ^ type(IStakeManager).interfaceId ^ type(INonceManager).interfaceId) || interfaceId == type(IEntryPoint).interfaceId || interfaceId == type(IStakeManager).interfaceId || From 9df75e19aa3721c7045e2fb5e51870011ff094db Mon Sep 17 00:00:00 2001 From: Alex Forshtat Date: Mon, 21 Aug 2023 14:40:25 +0300 Subject: [PATCH 7/7] Update 'gas-checker.txt' --- reports/gas-checker.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/reports/gas-checker.txt b/reports/gas-checker.txt index 294064d0..9fd84fa8 100644 --- a/reports/gas-checker.txt +++ b/reports/gas-checker.txt @@ -4,7 +4,7 @@ ╔══════════════════════════╤════════╗ ║ gas estimate "simple" │ 29014 ║ ╟──────────────────────────┼────────╢ -║ gas estimate "big tx 5k" │ 125248 ║ +║ gas estimate "big tx 5k" │ 125260 ║ ╚══════════════════════════╧════════╝ ╔════════════════════════════════╤═══════╤═══════════════╤════════════════╤═════════════════════╗ @@ -16,7 +16,7 @@ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ ║ simple - diff from previous │ 2 │ │ 44208 │ 15194 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple │ 10 │ 479944 │ │ ║ +║ simple │ 10 │ 479920 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ ║ simple - diff from previous │ 11 │ │ 44280 │ 15266 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ @@ -24,16 +24,16 @@ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ ║ simple paymaster with diff │ 2 │ │ 43197 │ 14183 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple paymaster │ 10 │ 477132 │ │ ║ +║ simple paymaster │ 10 │ 477156 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ simple paymaster with diff │ 11 │ │ 43208 │ 14194 ║ +║ simple paymaster with diff │ 11 │ │ 43184 │ 14170 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx 5k │ 1 │ 182976 │ │ ║ +║ big tx 5k │ 1 │ 183000 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx - diff from previous │ 2 │ │ 144707 │ 19459 ║ +║ big tx - diff from previous │ 2 │ │ 144719 │ 19459 ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx 5k │ 10 │ 1485552 │ │ ║ +║ big tx 5k │ 10 │ 1485612 │ │ ║ ╟────────────────────────────────┼───────┼───────────────┼────────────────┼─────────────────────╢ -║ big tx - diff from previous │ 11 │ │ 144744 │ 19496 ║ +║ big tx - diff from previous │ 11 │ │ 144720 │ 19460 ║ ╚════════════════════════════════╧═══════╧═══════════════╧════════════════╧═════════════════════╝