From 4305341a7601c28bd2ff65b3b3201f4066b1079a Mon Sep 17 00:00:00 2001 From: Mikhail <16622558+mmv08@users.noreply.github.com> Date: Wed, 19 Jun 2024 15:27:08 +0200 Subject: [PATCH] add a new logUserOperationGas function --- modules/4337/src/utils/execution.ts | 27 ++++++++++++++++++ .../erc4337/ERC4337ModuleExisting.spec.ts | 12 +++++--- .../test/erc4337/ERC4337ModuleNew.spec.ts | 12 +++++--- .../test/erc4337/ReferenceEntryPoint.spec.ts | 17 ++++++++--- .../4337/test/erc4337/Safe4337Mock.spec.ts | 6 ++-- modules/4337/test/gas/Gas.spec.ts | 28 +++++++++++++------ 6 files changed, 79 insertions(+), 23 deletions(-) diff --git a/modules/4337/src/utils/execution.ts b/modules/4337/src/utils/execution.ts index 945acfc6c..cea88252b 100644 --- a/modules/4337/src/utils/execution.ts +++ b/modules/4337/src/utils/execution.ts @@ -1,4 +1,5 @@ import { BigNumberish, Signer, TransactionResponse, ethers } from 'ethers' +import { IEntryPoint } from '../../typechain-types' export const EIP_DOMAIN = { EIP712Domain: [ @@ -137,9 +138,35 @@ export const buildSignatureBytes = (signatures: SafeSignature[]): string => { export const logGas = async (message: string, tx: Promise, skip?: boolean): Promise => { return tx.then(async (result) => { const receipt = await result.wait() + if (!receipt?.gasUsed) throw new Error('No gas used in receipt') if (!skip) console.log(` Used ${receipt.gasUsed} gas for >${message}<`) return result }) } + +export const logUserOperationGas = async ( + message: string, + entryPoint: IEntryPoint, + tx: Promise, + skip?: boolean, +): Promise => { + return tx.then(async (result) => { + const receipt = await result.wait() + if (!receipt) throw new Error('No receipt') + + const userOperationEvent = await entryPoint.queryFilter(entryPoint.filters.UserOperationEvent(), receipt.blockNumber) + const parsedUserOperationEvent = entryPoint.interface.parseLog(userOperationEvent[0]) + + if (!receipt?.gasUsed) throw new Error('No gas used in receipt') + if (!parsedUserOperationEvent?.args.actualGasUsed) + throw new Error('No gas used in UserOperationEvent or UserOperationEvent not emitted') + + if (!skip) { + console.log(` Used ${parsedUserOperationEvent.args.actualGasUsed} gas (Account or Paymaster) for >${message}<`) + console.log(` Used ${receipt.gasUsed} gas (Transaction) for >${message}<`) + } + return result + }) +} diff --git a/modules/4337/test/erc4337/ERC4337ModuleExisting.spec.ts b/modules/4337/test/erc4337/ERC4337ModuleExisting.spec.ts index 05511a422..5488ea681 100644 --- a/modules/4337/test/erc4337/ERC4337ModuleExisting.spec.ts +++ b/modules/4337/test/erc4337/ERC4337ModuleExisting.spec.ts @@ -1,7 +1,7 @@ import { expect } from 'chai' import { deployments, ethers } from 'hardhat' import { getTestSafe, getSafe4337Module, getEntryPoint } from '../utils/setup' -import { buildSignatureBytes, signHash, logGas } from '../../src/utils/execution' +import { buildSignatureBytes, signHash, logUserOperationGas } from '../../src/utils/execution' import { calculateSafeOperationHash, buildPackedUserOperationFromSafeUserOperation, @@ -69,7 +69,7 @@ describe('Safe4337Module - Existing Safe', () => { const safeOpHash = calculateSafeOperationHash(await validator.getAddress(), safeOp, await chainId()) const signature = buildSignatureBytes([await signHash(user1, safeOpHash)]) const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature }) - await logGas('Execute UserOp without a prefund payment', entryPoint.handleOps([userOp], relayer)) + await logUserOperationGas('Execute UserOp without a prefund payment', entryPoint, entryPoint.handleOps([userOp], relayer)) expect(await ethers.provider.getBalance(await safe.getAddress())).to.be.eq(ethers.parseEther('0')) }) @@ -116,7 +116,7 @@ describe('Safe4337Module - Existing Safe', () => { const safeOpHash = calculateSafeOperationHash(await validator.getAddress(), safeOp, await chainId()) const signature = buildSignatureBytes([await signHash(user1, safeOpHash)]) const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature }) - await logGas('Execute UserOp with fee payment', entryPoint.handleOps([userOp], feeBeneficiary)) + await logUserOperationGas('Execute UserOp with fee payment', entryPoint, entryPoint.handleOps([userOp], feeBeneficiary)) // checking that the fee was paid expect(await ethers.provider.getBalance(feeBeneficiary)).to.be.gt(0) @@ -169,7 +169,11 @@ describe('Safe4337Module - Existing Safe', () => { const safeOpHash = calculateSafeOperationHash(await validator.getAddress(), safeOp, await chainId()) const signature = buildSignatureBytes([await signHash(user1, safeOpHash)]) const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature }) - await logGas('Execute UserOp without fee payment and bubble up error string', entryPoint.handleOps([userOp], relayer)) + await logUserOperationGas( + 'Execute UserOp without fee payment and bubble up error string', + entryPoint, + entryPoint.handleOps([userOp], relayer), + ) expect(await ethers.provider.getBalance(await safe.getAddress())).to.be.eq(ethers.parseEther('0.5')) }) diff --git a/modules/4337/test/erc4337/ERC4337ModuleNew.spec.ts b/modules/4337/test/erc4337/ERC4337ModuleNew.spec.ts index 6114a9fd8..326b84f39 100644 --- a/modules/4337/test/erc4337/ERC4337ModuleNew.spec.ts +++ b/modules/4337/test/erc4337/ERC4337ModuleNew.spec.ts @@ -1,7 +1,7 @@ import { expect } from 'chai' import { deployments, ethers } from 'hardhat' import { getSafe4337Module, getEntryPoint, getFactory, getSafeModuleSetup, getSafeL2Singleton } from '../utils/setup' -import { buildSignatureBytes, logGas } from '../../src/utils/execution' +import { buildSignatureBytes, logUserOperationGas } from '../../src/utils/execution' import { buildPackedUserOperationFromSafeUserOperation, buildSafeUserOpTransaction, signSafeOp } from '../../src/utils/userOp' import { chainId } from '../utils/encoding' import { Safe4337 } from '../../src/utils/safe' @@ -94,7 +94,7 @@ describe('Safe4337Module - Newly deployed safe', () => { safeOp, signature, }) - await logGas('Execute UserOp without fee payment', entryPoint.handleOps([userOp], user1.address)) + await logUserOperationGas('Execute UserOp without fee payment', entryPoint, entryPoint.handleOps([userOp], user1.address)) expect(await ethers.provider.getBalance(safe.address)).to.be.eq(ethers.parseEther('0')) }) @@ -179,7 +179,7 @@ describe('Safe4337Module - Newly deployed safe', () => { safeOp, signature, }) - await logGas('Execute UserOp with fee payment', entryPoint.handleOps([userOp], feeBeneficiary)) + await logUserOperationGas('Execute UserOp with fee payment', entryPoint, entryPoint.handleOps([userOp], feeBeneficiary)) // checking that the fee was paid expect(await ethers.provider.getBalance(feeBeneficiary)).to.be.gt(0) @@ -211,7 +211,11 @@ describe('Safe4337Module - Newly deployed safe', () => { safeOp, signature, }) - await logGas('Execute UserOp with fee payment and bubble up error string', entryPoint.handleOps([userOp], user1.address)) + await logUserOperationGas( + 'Execute UserOp with fee payment and bubble up error string', + entryPoint, + entryPoint.handleOps([userOp], user1.address), + ) expect(await ethers.provider.getBalance(safe.address)).to.be.eq(ethers.parseEther('0.5')) }) diff --git a/modules/4337/test/erc4337/ReferenceEntryPoint.spec.ts b/modules/4337/test/erc4337/ReferenceEntryPoint.spec.ts index 0efe5a518..f0812433c 100644 --- a/modules/4337/test/erc4337/ReferenceEntryPoint.spec.ts +++ b/modules/4337/test/erc4337/ReferenceEntryPoint.spec.ts @@ -3,7 +3,7 @@ import { deployments, ethers } from 'hardhat' import { time } from '@nomicfoundation/hardhat-network-helpers' import { EventLog, Log } from 'ethers' import { getEntryPoint, getFactory, getSafeModuleSetup } from '../utils/setup' -import { buildSignatureBytes, logGas } from '../../src/utils/execution' +import { buildSignatureBytes, logUserOperationGas } from '../../src/utils/execution' import { buildSafeUserOpTransaction, buildPackedUserOperationFromSafeUserOperation, @@ -78,7 +78,11 @@ describe('Safe4337Module - Reference EntryPoint', () => { }), ) - const transaction = await logGas('Execute UserOps with reference EntryPoint', entryPoint.handleOps(userOps, await relayer.getAddress())) + const transaction = await logUserOperationGas( + 'Execute UserOps with reference EntryPoint', + entryPoint, + entryPoint.handleOps(userOps, await relayer.getAddress()), + ) const receipt = await transaction.wait() const transfers = ethers.parseEther('0.1') * BigInt(userOps.length) @@ -132,7 +136,11 @@ describe('Safe4337Module - Reference EntryPoint', () => { .withArgs(0, 'AA22 expired or not due') await time.increaseTo(validAfter + 1) - const transaction = await logGas('Execute UserOps with reference EntryPoint', entryPoint.handleOps(userOps, await relayer.getAddress())) + const transaction = await logUserOperationGas( + 'Execute UserOps with reference EntryPoint', + entryPoint, + entryPoint.handleOps(userOps, await relayer.getAddress()), + ) const receipt = await transaction.wait() const transfers = ethers.parseEther('0.1') * BigInt(userOps.length) @@ -191,8 +199,9 @@ describe('Safe4337Module - Reference EntryPoint', () => { signature, }) - const transaction = await logGas( + const transaction = await logUserOperationGas( 'Execute UserOps with reference EntryPoint', + entryPoint, entryPoint.handleOps([userOp], await relayer.getAddress()), ) const receipt = await transaction.wait() diff --git a/modules/4337/test/erc4337/Safe4337Mock.spec.ts b/modules/4337/test/erc4337/Safe4337Mock.spec.ts index 23883b86a..b1ea34228 100644 --- a/modules/4337/test/erc4337/Safe4337Mock.spec.ts +++ b/modules/4337/test/erc4337/Safe4337Mock.spec.ts @@ -1,7 +1,7 @@ import { expect } from 'chai' import { deployments, ethers } from 'hardhat' import { getEntryPoint, get4337TestSafe } from '../utils/setup' -import { buildSignatureBytes, signHash, logGas } from '../../src/utils/execution' +import { buildSignatureBytes, signHash, logUserOperationGas } from '../../src/utils/execution' import { buildSafeUserOp, buildSafeUserOpTransaction, @@ -49,7 +49,7 @@ describe('Safe4337Mock', () => { const safeOpHash = calculateSafeOperationHash(await validator.getAddress(), safeOp, await chainId()) const signature = buildSignatureBytes([await signHash(user1, safeOpHash)]) const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature }) - await logGas('Execute UserOp without fee payment', entryPoint.handleOps([userOp], user1.address)) + await logUserOperationGas('Execute UserOp without fee payment', entryPoint, entryPoint.handleOps([userOp], user1.address)) expect(await ethers.provider.getBalance(await safe.getAddress())).to.be.eq(ethers.parseEther('0.5')) }) @@ -72,7 +72,7 @@ describe('Safe4337Mock', () => { const safeOpHash = calculateSafeOperationHash(await validator.getAddress(), safeOp, await chainId()) const signature = buildSignatureBytes([await signHash(user1, safeOpHash)]) const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature }) - await logGas('Execute UserOp with fee payment', entryPoint.handleOps([userOp], feeBeneficiary)) + await logUserOperationGas('Execute UserOp with fee payment', entryPoint, entryPoint.handleOps([userOp], feeBeneficiary)) // checking that the fee was paid expect(await ethers.provider.getBalance(feeBeneficiary)).to.be.gt(0) diff --git a/modules/4337/test/gas/Gas.spec.ts b/modules/4337/test/gas/Gas.spec.ts index 75db51b03..ed26e6e92 100644 --- a/modules/4337/test/gas/Gas.spec.ts +++ b/modules/4337/test/gas/Gas.spec.ts @@ -1,7 +1,7 @@ import { expect } from 'chai' import { deployments, ethers } from 'hardhat' import { getSafe4337Module, getEntryPoint, getFactory, getSafeModuleSetup, getSafeL2Singleton } from '../utils/setup' -import { buildSignatureBytes, logGas } from '../../src/utils/execution' +import { buildSignatureBytes, logUserOperationGas } from '../../src/utils/execution' import { buildPackedUserOperationFromSafeUserOperation, buildSafeUserOpTransaction, signSafeOp } from '../../src/utils/userOp' import { chainId } from '../utils/encoding' import { Safe4337 } from '../../src/utils/safe' @@ -69,7 +69,7 @@ describe('Gas Metering', () => { signature, }) - await logGas('Safe with 4337 Module Deployment', entryPoint.handleOps([userOp], user.address)) + await logUserOperationGas('Safe with 4337 Module Deployment', entryPoint, entryPoint.handleOps([userOp], user.address)) expect(ethers.dataLength(await ethers.provider.getCode(safe.address))).to.not.equal(0) }) @@ -108,7 +108,11 @@ describe('Gas Metering', () => { signature, }) - await logGas('Safe with 4337 Module Deployment + Native Transfer', entryPoint.handleOps([userOp], user.address)) + await logUserOperationGas( + 'Safe with 4337 Module Deployment + Native Transfer', + entryPoint, + entryPoint.handleOps([userOp], user.address), + ) const recipientBalAfter = await ethers.provider.getBalance(receiver) expect(ethers.dataLength(await ethers.provider.getCode(safe.address))).to.not.equal(0) @@ -143,7 +147,7 @@ describe('Gas Metering', () => { signature, }) - await logGas('Safe with 4337 Module Native Transfer', entryPoint.handleOps([userOp], user.address)) + await logUserOperationGas('Safe with 4337 Module Native Transfer', entryPoint, entryPoint.handleOps([userOp], user.address)) expect(await ethers.provider.getBalance(receiver)).to.equal(amount) }) @@ -182,7 +186,11 @@ describe('Gas Metering', () => { signature, }) - await logGas('Safe with 4337 Module Deployment + ERC20 Transfer', entryPoint.handleOps([userOp], user.address)) + await logUserOperationGas( + 'Safe with 4337 Module Deployment + ERC20 Transfer', + entryPoint, + entryPoint.handleOps([userOp], user.address), + ) expect(await erc20Token.balanceOf(safe.address)).to.equal(0) expect(ethers.dataLength(await ethers.provider.getCode(safe.address))).to.not.equal(0) }) @@ -215,7 +223,11 @@ describe('Gas Metering', () => { }) expect(await erc721Token.balanceOf(safe.address)).to.equal(0) - await logGas('Safe with 4337 Module Deployment + ERC721 Transfer', entryPoint.handleOps([userOp], user.address)) + await logUserOperationGas( + 'Safe with 4337 Module Deployment + ERC721 Transfer', + entryPoint, + entryPoint.handleOps([userOp], user.address), + ) expect(await erc721Token.balanceOf(safe.address)).to.equal(1) expect(await erc721Token.ownerOf(tokenID)).to.equal(safe.address) expect(ethers.dataLength(await ethers.provider.getCode(safe.address))).to.not.equal(0) @@ -254,7 +266,7 @@ describe('Gas Metering', () => { signature, }) - await logGas('Safe with 4337 Module ERC20 Transfer', entryPoint.handleOps([userOp], user.address)) + await logUserOperationGas('Safe with 4337 Module ERC20 Transfer', entryPoint, entryPoint.handleOps([userOp], user.address)) expect(await erc20Token.balanceOf(safe.address)).to.equal(0) }) @@ -289,7 +301,7 @@ describe('Gas Metering', () => { }) expect(await erc721Token.balanceOf(safe.address)).to.equal(0) - await logGas('Safe with 4337 Module ERC721 Transfer', entryPoint.handleOps([userOp], user.address)) + await logUserOperationGas('Safe with 4337 Module ERC721 Transfer', entryPoint, entryPoint.handleOps([userOp], user.address)) expect(await erc721Token.balanceOf(safe.address)).to.equal(1) expect(await erc721Token.ownerOf(tokenID)).to.equal(safe.address) })