From f3129de0284e68c87e95d210027529e70270a753 Mon Sep 17 00:00:00 2001 From: Nicholas Rodrigues Lordello Date: Tue, 5 Mar 2024 11:13:17 +0100 Subject: [PATCH] Fix E2E Tests For ERC-4337 v0.7 Bundler (#300) Fixes #227 This PR updates the E2E tests to work with the latest bundler for the EntryPoint contract v0.7. Note that there was a notable change in that the `PackedUserOperation` struct is only used on-chain, and the bundler RPC uses a different `UserOperation` type that is completely unpacked. This required some additional helper methods as well as some adjustments to tests to distinguish between the packed and unpacked versions of user operations. Also, unfortunately the reference bundler repository is not tagged yet - so we are using a commit hash that corresponds to the latest version. I asked the 4337 team to create a new tag, at which point, I will update the docker file. Additionally, the latest bundler version uses submodules, so some dockerfile tweaking was required. Note that the broken CI is expected until #270 is fixed. --- modules/4337/docker/bundler/Dockerfile | 4 +- modules/4337/scripts/runOp.ts | 23 ++--- modules/4337/src/utils/safe.ts | 33 ++++++- modules/4337/src/utils/userOp.ts | 95 +++++++++++++++++-- modules/4337/test/e2e/4337NestedSafe.spec.ts | 9 +- modules/4337/test/e2e/LocalBundler.spec.ts | 6 +- .../4337/test/e2e/SingletonSigners.spec.ts | 10 +- modules/4337/test/e2e/UniqueSigner.spec.ts | 9 +- modules/4337/test/e2e/WebAuthnSigner.spec.ts | 9 +- .../test/e2e/WebAuthnSingletonSigner.spec.ts | 10 +- .../erc4337/ERC4337ModuleExisting.spec.ts | 20 ++-- .../test/erc4337/ERC4337ModuleNew.spec.ts | 16 ++-- .../4337/test/erc4337/ERC4337WebAuthn.spec.ts | 4 +- .../test/erc4337/ReferenceEntryPoint.spec.ts | 8 +- .../4337/test/erc4337/Safe4337Mock.spec.ts | 8 +- .../4337/test/erc4337/Safe4337Module.spec.ts | 12 +-- modules/4337/test/gas/Gas.spec.ts | 16 ++-- 17 files changed, 209 insertions(+), 83 deletions(-) diff --git a/modules/4337/docker/bundler/Dockerfile b/modules/4337/docker/bundler/Dockerfile index a011d0e7..86b79b9f 100644 --- a/modules/4337/docker/bundler/Dockerfile +++ b/modules/4337/docker/bundler/Dockerfile @@ -1,9 +1,11 @@ FROM docker.io/library/node:18 -ARG TAG=v0.6.1 +# v0.7.0 +ARG TAG=26e4f4c RUN git clone https://github.com/eth-infinitism/bundler /src/bundler WORKDIR /src/bundler RUN git checkout ${TAG} +RUN git submodule init && git submodule update RUN yarn && yarn preprocess ENTRYPOINT ["yarn", "bundler"] diff --git a/modules/4337/scripts/runOp.ts b/modules/4337/scripts/runOp.ts index fc426a97..af0bab80 100644 --- a/modules/4337/scripts/runOp.ts +++ b/modules/4337/scripts/runOp.ts @@ -1,7 +1,7 @@ import { Result } from 'ethers' import { ethers } from 'hardhat' -import { UserOperation, getRequiredPrefund, getSupportedEntryPoints } from '../src/utils/userOp' +import { getRequiredPrefund, getSupportedEntryPoints } from '../src/utils/userOp' import { chainId } from '../test/utils/encoding' import { getSafe4337Module } from '../test/utils/setup' import { GlobalConfig, MultiProvider4337, Safe4337 } from '../src/utils/safe' @@ -108,6 +108,7 @@ const runOp = async () => { ]), ) + const packedUserOp = await operation.packedUserOperation() console.log( 'validateUserOp', await ethers.provider.send('eth_call', [ @@ -116,18 +117,18 @@ const runOp = async () => { to: safe.address, data: buildData('validateUserOp((address,uint256,bytes,bytes,bytes32,uint256,bytes32,bytes,bytes),bytes32,uint256)', [ [ - userOp.sender, - userOp.nonce, - userOp.initCode, - userOp.callData, - userOp.accountGasLimits, - userOp.preVerificationGas, - userOp.gasFees, - userOp.paymasterAndData, - userOp.signature, + packedUserOp.sender, + packedUserOp.nonce, + packedUserOp.initCode, + packedUserOp.callData, + packedUserOp.accountGasLimits, + packedUserOp.preVerificationGas, + packedUserOp.gasFees, + packedUserOp.paymasterAndData, + packedUserOp.signature, ], '0x0000000000000000000000000000000000000000000000000000000000000000', - getRequiredPrefund(userOp), + getRequiredPrefund(packedUserOp), ]), }, 'latest', diff --git a/modules/4337/src/utils/safe.ts b/modules/4337/src/utils/safe.ts index 60498683..b6d0fed1 100644 --- a/modules/4337/src/utils/safe.ts +++ b/modules/4337/src/utils/safe.ts @@ -2,7 +2,7 @@ import { AddressLike, JsonRpcProvider, Provider, Signer, ethers } from 'ethers' // Import from Safe contracts repo once it is upgraded to ethers v6 and can be installed via npm import { MetaTransaction, SafeSignature, SignedSafeTransaction, buildSignatureBytes } from './execution' -import { UserOperation, EIP712_SAFE_OPERATION_TYPE, packGasParameters } from './userOp' +import { PackedUserOperation, UserOperation, EIP712_SAFE_OPERATION_TYPE, packGasParameters, unpackUserOperation } from './userOp' const AddressOne = '0x0000000000000000000000000000000000000001' @@ -31,7 +31,6 @@ export interface OperationParams { preVerificationGas: bigint maxPriorityFeePerGas: bigint maxFeePerGas: bigint - paymasterAndData: string validAfter: bigint validUntil: bigint } @@ -122,7 +121,28 @@ export class MultiProvider4337 extends JsonRpcProvider { } public async sendUserOperation(userOp: UserOperation, entryPoint: AddressLike): Promise { - return await super.send('eth_sendUserOperation', [userOp, await ethers.resolveAddress(entryPoint, this)]) + const jsonUserOp = { + sender: ethers.getAddress(userOp.sender), + nonce: ethers.toBeHex(userOp.nonce), + callData: ethers.hexlify(userOp.callData), + callGasLimit: ethers.toBeHex(userOp.callGasLimit), + verificationGasLimit: ethers.toBeHex(userOp.verificationGasLimit), + preVerificationGas: ethers.toBeHex(userOp.preVerificationGas), + maxFeePerGas: ethers.toBeHex(userOp.maxFeePerGas), + maxPriorityFeePerGas: ethers.toBeHex(userOp.maxPriorityFeePerGas), + signature: ethers.hexlify(userOp.signature), + } as Record + if (userOp.factory) { + jsonUserOp.factory = ethers.getAddress(userOp.factory) + jsonUserOp.factoryData = ethers.hexlify(userOp.factoryData!) + } + if (userOp.paymaster) { + jsonUserOp.paymaster = ethers.getAddress(userOp.paymaster) + jsonUserOp.paymasterVerificationGasLimit = ethers.toBeHex(userOp.paymasterVerificationGasLimit!) + jsonUserOp.paymasterPostOpGasLimit = ethers.toBeHex(userOp.paymasterPostOpGasLimit!) + jsonUserOp.paymasterData = ethers.hexlify(userOp.paymasterData!) + } + return await super.send('eth_sendUserOperation', [jsonUserOp, await ethers.resolveAddress(entryPoint, this)]) } } @@ -157,7 +177,7 @@ export class Safe4337Operation { return buildSignatureBytes(this.signatures) } - async userOperation(paymasterAndData = '0x'): Promise { + async packedUserOperation(paymasterAndData = '0x'): Promise { const { accountGasLimits, gasFees } = packGasParameters(this.params) return { nonce: ethers.toBeHex(this.params.nonce), @@ -175,6 +195,10 @@ export class Safe4337Operation { } } + async userOperation(paymasterAndData = '0x'): Promise { + return await unpackUserOperation(await this.packedUserOperation(paymasterAndData)) + } + async authorize(signer: ethers.Signer) { const validSigners = await this.safe.getSigners() const signerAddress = await signer.getAddress() @@ -243,7 +267,6 @@ export class Safe4337Operation { callGasLimit: (BigInt(estimates.callGasLimit) * 12n) / 10n, validAfter: 0n, validUntil: 0n, - paymasterAndData: '0x', } return new Safe4337Operation(safe, action, params, globalConfig) } diff --git a/modules/4337/src/utils/userOp.ts b/modules/4337/src/utils/userOp.ts index 76dae91d..d2c7f1cf 100644 --- a/modules/4337/src/utils/userOp.ts +++ b/modules/4337/src/utils/userOp.ts @@ -1,8 +1,8 @@ import { BigNumberish, BytesLike, Contract, Signer, ethers } from 'ethers' -import { PackedUserOperationStruct as UserOperation } from '../../typechain-types/contracts/Safe4337Module' +import { PackedUserOperationStruct as PackedUserOperation } from '../../typechain-types/contracts/Safe4337Module' import { SafeSignature } from './execution' -export { UserOperation } +export { PackedUserOperation } type OptionalExceptFor = Partial>> & Required> @@ -13,7 +13,25 @@ export type SafeUserOperation = { validAfter: BigNumberish validUntil: BigNumberish } & GasParameters & - Omit + Omit + +export type UserOperation = { + sender: string + nonce: BigNumberish + factory?: string + factoryData?: BytesLike + callData: BytesLike + callGasLimit: BigNumberish + verificationGasLimit: BigNumberish + preVerificationGas: BigNumberish + maxFeePerGas: BigNumberish + maxPriorityFeePerGas: BigNumberish + paymaster?: string + paymasterVerificationGasLimit?: BigNumberish + paymasterPostOpGasLimit?: BigNumberish + paymasterData?: BytesLike + signature: BytesLike +} export const EIP712_SAFE_OPERATION_TYPE = { SafeOp: [ @@ -135,13 +153,13 @@ export const buildSafeUserOpContractCall = async ( ) } -export const buildUserOperationFromSafeUserOperation = ({ +export const buildPackedUserOperationFromSafeUserOperation = ({ safeOp, signature, }: { safeOp: SafeUserOperation signature: string -}): UserOperation => { +}): PackedUserOperation => { return { sender: safeOp.safe, nonce: ethers.toBeHex(safeOp.nonce), @@ -154,7 +172,14 @@ export const buildUserOperationFromSafeUserOperation = ({ } } -export const getRequiredGas = (userOp: UserOperation): string => { +export const buildRpcUserOperationFromSafeUserOperation = (op: { + safeOp: SafeUserOperation + signature: string +}): Promise => { + return unpackUserOperation(buildPackedUserOperationFromSafeUserOperation(op)) +} + +export const getRequiredGas = (userOp: PackedUserOperation): string => { let multiplier = 3n if (userOp.paymasterAndData === '0x') { multiplier = 1n @@ -164,7 +189,7 @@ export const getRequiredGas = (userOp: UserOperation): string => { return (BigInt(callGasLimit) + BigInt(verificationGasLimit) * multiplier + BigInt(userOp.preVerificationGas)).toString() } -export const getRequiredPrefund = (userOp: UserOperation): string => { +export const getRequiredPrefund = (userOp: PackedUserOperation): string => { const requiredGas = getRequiredGas(userOp) const { maxFeePerGas } = unpackGasParameters(userOp) const requiredPrefund = (BigInt(requiredGas) * BigInt(maxFeePerGas)).toString() @@ -242,3 +267,59 @@ export const unpackGasParameters = (packed: PackedGasParameters): GasParameters return { verificationGasLimit, callGasLimit, maxPriorityFeePerGas, maxFeePerGas } } + +/** + * Unpacks a user operation. + * + * @param packedUserOp - The packed user operation. + * @returns The unpacked user operation. + */ +export const unpackUserOperation = async (packedUserOp: PackedUserOperation): Promise => { + return { + sender: await ethers.resolveAddress(packedUserOp.sender), + nonce: packedUserOp.nonce, + ...unpackInitCode(packedUserOp), + callData: packedUserOp.callData, + ...unpackGasParameters(packedUserOp), + preVerificationGas: packedUserOp.preVerificationGas, + ...unpackPaymasterAndData(packedUserOp), + signature: packedUserOp.signature, + } +} + +/** + * Unpacks a user operation's `initCode` field into a factory address and its data. + * + * @param _ - The packed user operation. + * @returns The unpacked `initCode`. + */ +export const unpackInitCode = ({ initCode }: Pick): Pick => { + return ethers.dataLength(initCode) > 0 + ? { + factory: ethers.getAddress(ethers.dataSlice(initCode, 0, 20)), + factoryData: ethers.dataSlice(initCode, 20), + } + : {} +} + +/** + * Unpacks a user operation's `paymasterAndData` field into a the paymaster options. + * + * @param _ - The packed user operation. + * @returns The unpacked `paymasterAndData`. + */ +export const unpackPaymasterAndData = ({ + paymasterAndData, +}: Pick): Pick< + UserOperation, + 'paymaster' | 'paymasterVerificationGasLimit' | 'paymasterPostOpGasLimit' | 'paymasterData' +> => { + return ethers.dataLength(paymasterAndData) > 0 + ? { + paymaster: ethers.getAddress(ethers.dataSlice(paymasterAndData, 0, 20)), + paymasterVerificationGasLimit: BigInt(ethers.dataSlice(paymasterAndData, 20, 36)), + paymasterPostOpGasLimit: BigInt(ethers.dataSlice(paymasterAndData, 36, 52)), + paymasterData: ethers.dataSlice(paymasterAndData, 52), + } + : {} +} diff --git a/modules/4337/test/e2e/4337NestedSafe.spec.ts b/modules/4337/test/e2e/4337NestedSafe.spec.ts index 87c69263..6059fdeb 100644 --- a/modules/4337/test/e2e/4337NestedSafe.spec.ts +++ b/modules/4337/test/e2e/4337NestedSafe.spec.ts @@ -12,7 +12,12 @@ import { preimageSafeTransactionHash, signHash, } from '../../src/utils/execution' -import { buildUserOperationFromSafeUserOperation, buildSafeUserOpTransaction, signSafeOp, SafeUserOperation } from '../../src/utils/userOp' +import { + buildRpcUserOperationFromSafeUserOperation, + buildSafeUserOpTransaction, + signSafeOp, + SafeUserOperation, +} from '../../src/utils/userOp' import { chainId } from '../utils/encoding' import { Safe4337 } from '../../src/utils/safe' import { BUNDLER_MNEMONIC, bundlerRpc, prepareAccounts, waitForUserOp } from '../utils/e2e' @@ -403,7 +408,7 @@ describe('E2E - Nested Safes With An Execution Initiated by a Leaf 4337 Safe', ( const executorSigner = executor.owners[0].value as Signer const safeOp = await buildNestedSafeOp(safeTransaction, tree.root, executionPath, await entryPoint.getAddress()) const signature = buildSignatureBytes([await signSafeOp(executorSigner, await validator.getAddress(), safeOp, await chainId())]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = await buildRpcUserOperationFromSafeUserOperation({ safeOp, signature, }) diff --git a/modules/4337/test/e2e/LocalBundler.spec.ts b/modules/4337/test/e2e/LocalBundler.spec.ts index 171a05e0..fef9561d 100644 --- a/modules/4337/test/e2e/LocalBundler.spec.ts +++ b/modules/4337/test/e2e/LocalBundler.spec.ts @@ -1,7 +1,7 @@ import { expect } from 'chai' import { deployments, ethers, network } from 'hardhat' import { buildSignatureBytes } from '../../src/utils/execution' -import { buildUserOperationFromSafeUserOperation, buildSafeUserOpTransaction, signSafeOp } from '../../src/utils/userOp' +import { buildRpcUserOperationFromSafeUserOperation, buildSafeUserOpTransaction, signSafeOp } from '../../src/utils/userOp' import { chainId, timestamp } from '../utils/encoding' import { Safe4337 } from '../../src/utils/safe' import { bundlerRpc, prepareAccounts, waitForUserOp } from '../utils/e2e' @@ -71,7 +71,7 @@ describe('E2E - Local Bundler', () => { }, ) const signature = buildSignatureBytes([await signSafeOp(user, await validator.getAddress(), safeOp, await chainId())]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = await buildRpcUserOperationFromSafeUserOperation({ safeOp, signature, }) @@ -103,7 +103,7 @@ describe('E2E - Local Bundler', () => { await entryPoint.getAddress(), ) const signature = buildSignatureBytes([await signSafeOp(user, await validator.getAddress(), safeOp, await chainId())]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = await buildRpcUserOperationFromSafeUserOperation({ safeOp, signature, }) diff --git a/modules/4337/test/e2e/SingletonSigners.spec.ts b/modules/4337/test/e2e/SingletonSigners.spec.ts index 8bdaf2e8..134cb76e 100644 --- a/modules/4337/test/e2e/SingletonSigners.spec.ts +++ b/modules/4337/test/e2e/SingletonSigners.spec.ts @@ -1,7 +1,11 @@ import { expect } from 'chai' import { deployments, ethers, network } from 'hardhat' import { buildSignatureBytes } from '../../src/utils/execution' -import { buildUserOperationFromSafeUserOperation, buildSafeUserOpTransaction } from '../../src/utils/userOp' +import { + buildPackedUserOperationFromSafeUserOperation, + buildRpcUserOperationFromSafeUserOperation, + buildSafeUserOpTransaction, +} from '../../src/utils/userOp' import { bundlerRpc, encodeMultiSendTransactions, prepareAccounts, waitForUserOp } from '../utils/e2e' describe('E2E - Singleton Signers', () => { @@ -105,7 +109,7 @@ describe('E2E - Singleton Signers', () => { { initCode }, ) const opHash = await validator.getOperationHash( - buildUserOperationFromSafeUserOperation({ + buildPackedUserOperationFromSafeUserOperation({ safeOp, signature: '0x', }), @@ -117,7 +121,7 @@ describe('E2E - Singleton Signers', () => { dynamic: true, })), ) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = await buildRpcUserOperationFromSafeUserOperation({ safeOp, signature, }) diff --git a/modules/4337/test/e2e/UniqueSigner.spec.ts b/modules/4337/test/e2e/UniqueSigner.spec.ts index 2f3a47b1..16a10083 100644 --- a/modules/4337/test/e2e/UniqueSigner.spec.ts +++ b/modules/4337/test/e2e/UniqueSigner.spec.ts @@ -2,7 +2,7 @@ import { expect } from 'chai' import { deployments, ethers, network } from 'hardhat' import { bundlerRpc, prepareAccounts, waitForUserOp } from '../utils/e2e' import { chainId } from '../utils/encoding' -import { packGasParameters } from '../../src/utils/userOp' +import { packGasParameters, unpackUserOperation } from '../../src/utils/userOp' describe('E2E - Unique Signers', () => { before(function () { @@ -92,7 +92,7 @@ describe('E2E - Unique Signers', () => { const safeSalt = Date.now() const safe = await proxyFactory.createProxyWithNonce.staticCall(signerLaunchpad.target, launchpadInitializer, safeSalt) - const userOp = { + const packedUserOp = { sender: safe, nonce: ethers.toBeHex(await entryPoint.getNonce(safe, 0)), initCode: ethers.solidityPacked( @@ -122,7 +122,7 @@ describe('E2E - Unique Signers', () => { } const safeInitOp = { - userOpHash: await entryPoint.getUserOpHash({ ...userOp, signature: '0x' }), + userOpHash: await entryPoint.getUserOpHash({ ...packedUserOp, signature: '0x' }), validAfter: 0, validUntil: 0, entryPoint: entryPoint.target, @@ -149,7 +149,8 @@ describe('E2E - Unique Signers', () => { expect(await ethers.provider.getBalance(safe)).to.equal(ethers.parseEther('1')) expect(await ethers.provider.getCode(safe)).to.equal('0x') - await bundler.sendUserOperation({ ...userOp, signature }, await entryPoint.getAddress()) + const userOp = await unpackUserOperation({ ...packedUserOp, signature }) + await bundler.sendUserOperation(userOp, await entryPoint.getAddress()) await waitForUserOp(userOp) expect(await ethers.provider.getBalance(safe)).to.be.lessThanOrEqual(ethers.parseEther('0.5')) diff --git a/modules/4337/test/e2e/WebAuthnSigner.spec.ts b/modules/4337/test/e2e/WebAuthnSigner.spec.ts index a9954f1c..5f8f3165 100644 --- a/modules/4337/test/e2e/WebAuthnSigner.spec.ts +++ b/modules/4337/test/e2e/WebAuthnSigner.spec.ts @@ -9,7 +9,7 @@ import { extractPublicKey, extractSignature, } from '../utils/webauthn' -import { packGasParameters } from '../../src/utils/userOp' +import { packGasParameters, unpackUserOperation } from '../../src/utils/userOp' describe('E2E - WebAuthn Signers', () => { before(function () { @@ -134,7 +134,7 @@ describe('E2E - WebAuthn Signers', () => { const safeSalt = Date.now() const safe = await proxyFactory.createProxyWithNonce.staticCall(signerLaunchpad.target, launchpadInitializer, safeSalt) - const userOp = { + const packedUserOp = { sender: safe, nonce: ethers.toBeHex(await entryPoint.getNonce(safe, 0)), initCode: ethers.solidityPacked( @@ -164,7 +164,7 @@ describe('E2E - WebAuthn Signers', () => { } const safeInitOp = { - userOpHash: await entryPoint.getUserOpHash({ ...userOp, signature: '0x' }), + userOpHash: await entryPoint.getUserOpHash({ ...packedUserOp, signature: '0x' }), validAfter: 0, validUntil: 0, entryPoint: entryPoint.target, @@ -211,7 +211,8 @@ describe('E2E - WebAuthn Signers', () => { expect(await ethers.provider.getCode(safe)).to.equal('0x') expect(await ethers.provider.getCode(signerAddress)).to.equal('0x') - await bundler.sendUserOperation({ ...userOp, signature }, await entryPoint.getAddress()) + const userOp = await unpackUserOperation({ ...packedUserOp, signature }) + await bundler.sendUserOperation(userOp, await entryPoint.getAddress()) await waitForUserOp(userOp) expect(await ethers.provider.getBalance(safe)).to.be.lessThanOrEqual(ethers.parseEther('0.5')) diff --git a/modules/4337/test/e2e/WebAuthnSingletonSigner.spec.ts b/modules/4337/test/e2e/WebAuthnSingletonSigner.spec.ts index b73f4d4b..e61ad22f 100644 --- a/modules/4337/test/e2e/WebAuthnSingletonSigner.spec.ts +++ b/modules/4337/test/e2e/WebAuthnSingletonSigner.spec.ts @@ -8,7 +8,11 @@ import { extractPublicKey, extractSignature, } from '../utils/webauthn' -import { buildSafeUserOpTransaction, buildUserOperationFromSafeUserOperation } from '../../src/utils/userOp' +import { + buildSafeUserOpTransaction, + buildPackedUserOperationFromSafeUserOperation, + buildRpcUserOperationFromSafeUserOperation, +} from '../../src/utils/userOp' import { buildSignatureBytes } from '../../src/utils/execution' describe('E2E - WebAuthn Singleton Signers', () => { @@ -139,7 +143,7 @@ describe('E2E - WebAuthn Singleton Signers', () => { }, ) const opHash = await module.getOperationHash( - buildUserOperationFromSafeUserOperation({ + buildPackedUserOperationFromSafeUserOperation({ safeOp, signature: '0x', }), @@ -166,7 +170,7 @@ describe('E2E - WebAuthn Singleton Signers', () => { dynamic: true, }, ]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = await buildRpcUserOperationFromSafeUserOperation({ safeOp, signature, }) diff --git a/modules/4337/test/erc4337/ERC4337ModuleExisting.spec.ts b/modules/4337/test/erc4337/ERC4337ModuleExisting.spec.ts index 869a0cf3..05511a42 100644 --- a/modules/4337/test/erc4337/ERC4337ModuleExisting.spec.ts +++ b/modules/4337/test/erc4337/ERC4337ModuleExisting.spec.ts @@ -2,7 +2,11 @@ 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 { calculateSafeOperationHash, buildUserOperationFromSafeUserOperation, buildSafeUserOpTransaction } from '../../src/utils/userOp' +import { + calculateSafeOperationHash, + buildPackedUserOperationFromSafeUserOperation, + buildSafeUserOpTransaction, +} from '../../src/utils/userOp' import { chainId } from '../utils/encoding' describe('Safe4337Module - Existing Safe', () => { @@ -38,7 +42,7 @@ describe('Safe4337Module - Existing Safe', () => { await entryPoint.getAddress(), ) const signature = buildSignatureBytes([await signHash(user1, ethers.keccak256('0xbaddad42'))]) - const userOp = buildUserOperationFromSafeUserOperation({ safeOp, signature }) + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature }) await expect(entryPoint.handleOps([userOp], user1.address)) .to.be.revertedWithCustomError(entryPoint, 'FailedOp') .withArgs(0, 'AA24 signature error') @@ -64,7 +68,7 @@ describe('Safe4337Module - Existing Safe', () => { ) const safeOpHash = calculateSafeOperationHash(await validator.getAddress(), safeOp, await chainId()) const signature = buildSignatureBytes([await signHash(user1, safeOpHash)]) - const userOp = buildUserOperationFromSafeUserOperation({ safeOp, signature }) + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature }) await logGas('Execute UserOp without a prefund payment', entryPoint.handleOps([userOp], relayer)) expect(await ethers.provider.getBalance(await safe.getAddress())).to.be.eq(ethers.parseEther('0')) }) @@ -85,7 +89,7 @@ describe('Safe4337Module - Existing Safe', () => { ) const safeOpHash = calculateSafeOperationHash(await validator.getAddress(), safeOp, await chainId()) const signature = buildSignatureBytes([await signHash(user1, safeOpHash)]) - const userOp = buildUserOperationFromSafeUserOperation({ safeOp, signature }) + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature }) await entryPoint.handleOps([userOp], user1.address) expect(await ethers.provider.getBalance(receiver)).to.be.eq(ethers.parseEther('0.5')) await expect(entryPoint.handleOps([userOp], user1.address)) @@ -111,7 +115,7 @@ describe('Safe4337Module - Existing Safe', () => { ) const safeOpHash = calculateSafeOperationHash(await validator.getAddress(), safeOp, await chainId()) const signature = buildSignatureBytes([await signHash(user1, safeOpHash)]) - const userOp = buildUserOperationFromSafeUserOperation({ safeOp, signature }) + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature }) await logGas('Execute UserOp with fee payment', entryPoint.handleOps([userOp], feeBeneficiary)) // checking that the fee was paid @@ -135,7 +139,7 @@ describe('Safe4337Module - Existing Safe', () => { ) const safeOpHash = calculateSafeOperationHash(await validator.getAddress(), safeOp, await chainId()) const signature = buildSignatureBytes([await signHash(user1, safeOpHash)]) - const userOp = buildUserOperationFromSafeUserOperation({ safeOp, signature }) + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature }) const userOpHash = await entryPoint.getUserOpHash(userOp) const expectedReturnData = validator.interface.encodeErrorResult('ExecutionFailed()', []) @@ -164,7 +168,7 @@ describe('Safe4337Module - Existing Safe', () => { ) const safeOpHash = calculateSafeOperationHash(await validator.getAddress(), safeOp, await chainId()) const signature = buildSignatureBytes([await signHash(user1, safeOpHash)]) - const userOp = buildUserOperationFromSafeUserOperation({ safeOp, signature }) + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature }) await logGas('Execute UserOp without fee payment and bubble up error string', entryPoint.handleOps([userOp], relayer)) expect(await ethers.provider.getBalance(await safe.getAddress())).to.be.eq(ethers.parseEther('0.5')) }) @@ -188,7 +192,7 @@ describe('Safe4337Module - Existing Safe', () => { ) const safeOpHash = calculateSafeOperationHash(await validator.getAddress(), safeOp, await chainId()) const signature = buildSignatureBytes([await signHash(user1, safeOpHash)]) - const userOp = buildUserOperationFromSafeUserOperation({ safeOp, signature }) + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature }) const expectedRevertReason = validator.interface.encodeErrorResult('Error(string)', ['You called a function that always reverts']) diff --git a/modules/4337/test/erc4337/ERC4337ModuleNew.spec.ts b/modules/4337/test/erc4337/ERC4337ModuleNew.spec.ts index 748d14aa..6114a9fd 100644 --- a/modules/4337/test/erc4337/ERC4337ModuleNew.spec.ts +++ b/modules/4337/test/erc4337/ERC4337ModuleNew.spec.ts @@ -2,7 +2,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 { buildUserOperationFromSafeUserOperation, buildSafeUserOpTransaction, signSafeOp } from '../../src/utils/userOp' +import { buildPackedUserOperationFromSafeUserOperation, buildSafeUserOpTransaction, signSafeOp } from '../../src/utils/userOp' import { chainId } from '../utils/encoding' import { Safe4337 } from '../../src/utils/safe' @@ -58,7 +58,7 @@ describe('Safe4337Module - Newly deployed safe', () => { }, ) const signature = buildSignatureBytes([await signSafeOp(user1, user1.address, safeOp, await chainId())]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) @@ -90,7 +90,7 @@ describe('Safe4337Module - Newly deployed safe', () => { ) const signature = buildSignatureBytes([await signSafeOp(user1, await validator.getAddress(), safeOp, await chainId())]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) @@ -114,7 +114,7 @@ describe('Safe4337Module - Newly deployed safe', () => { await entryPoint.getAddress(), ) const signature = buildSignatureBytes([await signSafeOp(user1, await validator.getAddress(), safeOp, await chainId())]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) @@ -143,7 +143,7 @@ describe('Safe4337Module - Newly deployed safe', () => { }, ) const signature = buildSignatureBytes([await signSafeOp(user1, await validator.getAddress(), safeOp, await chainId())]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) @@ -175,7 +175,7 @@ describe('Safe4337Module - Newly deployed safe', () => { }, ) const signature = buildSignatureBytes([await signSafeOp(user1, await validator.getAddress(), safeOp, await chainId())]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) @@ -207,7 +207,7 @@ describe('Safe4337Module - Newly deployed safe', () => { }, ) const signature = buildSignatureBytes([await signSafeOp(user1, await validator.getAddress(), safeOp, await chainId())]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) @@ -237,7 +237,7 @@ describe('Safe4337Module - Newly deployed safe', () => { }, ) const signature = buildSignatureBytes([await signSafeOp(user1, await validator.getAddress(), safeOp, await chainId())]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) diff --git a/modules/4337/test/erc4337/ERC4337WebAuthn.spec.ts b/modules/4337/test/erc4337/ERC4337WebAuthn.spec.ts index 01b41113..6245bec5 100644 --- a/modules/4337/test/erc4337/ERC4337WebAuthn.spec.ts +++ b/modules/4337/test/erc4337/ERC4337WebAuthn.spec.ts @@ -4,7 +4,7 @@ import { getEntryPoint } from '../utils/setup' import { buildSignatureBytes, logGas } from '../../src/utils/execution' import { buildSafeUserOpTransaction, - buildUserOperationFromSafeUserOperation, + buildPackedUserOperationFromSafeUserOperation, calculateSafeOperationHash, packGasParameters, } from '../../src/utils/userOp' @@ -299,7 +299,7 @@ describe('Safe4337Module - WebAuthn Owner', () => { await user.sendTransaction({ to: safe.address, value: ethers.parseEther('1') }).then((tx) => tx.wait()) expect(await ethers.provider.getBalance(safe.address)).to.equal(ethers.parseEther('1')) - const userOp = buildUserOperationFromSafeUserOperation({ safeOp, signature }) + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature }) await logGas('WebAuthn signer Safe operation', entryPoint.handleOps([userOp], user.address)) expect(await ethers.provider.getBalance(safe.address)).to.be.lessThanOrEqual(ethers.parseEther('0.5')) diff --git a/modules/4337/test/erc4337/ReferenceEntryPoint.spec.ts b/modules/4337/test/erc4337/ReferenceEntryPoint.spec.ts index afc9af4a..0efe5a51 100644 --- a/modules/4337/test/erc4337/ReferenceEntryPoint.spec.ts +++ b/modules/4337/test/erc4337/ReferenceEntryPoint.spec.ts @@ -6,7 +6,7 @@ import { getEntryPoint, getFactory, getSafeModuleSetup } from '../utils/setup' import { buildSignatureBytes, logGas } from '../../src/utils/execution' import { buildSafeUserOpTransaction, - buildUserOperationFromSafeUserOperation, + buildPackedUserOperationFromSafeUserOperation, calculateSafeOperationData, signSafeOp, } from '../../src/utils/userOp' @@ -71,7 +71,7 @@ describe('Safe4337Module - Reference EntryPoint', () => { }, ) const signature = buildSignatureBytes([await signSafeOp(user, await validator.getAddress(), safeOp, await chainId())]) - return buildUserOperationFromSafeUserOperation({ + return buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) @@ -120,7 +120,7 @@ describe('Safe4337Module - Reference EntryPoint', () => { }, ) const signature = buildSignatureBytes([await signSafeOp(user, await validator.getAddress(), safeOp, await chainId())]) - return buildUserOperationFromSafeUserOperation({ + return buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) @@ -186,7 +186,7 @@ describe('Safe4337Module - Reference EntryPoint', () => { dynamic: true, }, ]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) diff --git a/modules/4337/test/erc4337/Safe4337Mock.spec.ts b/modules/4337/test/erc4337/Safe4337Mock.spec.ts index 37b50a1b..23883b86 100644 --- a/modules/4337/test/erc4337/Safe4337Mock.spec.ts +++ b/modules/4337/test/erc4337/Safe4337Mock.spec.ts @@ -5,7 +5,7 @@ import { buildSignatureBytes, signHash, logGas } from '../../src/utils/execution import { buildSafeUserOp, buildSafeUserOpTransaction, - buildUserOperationFromSafeUserOperation, + buildPackedUserOperationFromSafeUserOperation, calculateSafeOperationHash, } from '../../src/utils/userOp' import { chainId, timestamp } from '../utils/encoding' @@ -48,7 +48,7 @@ describe('Safe4337Mock', () => { ) const safeOpHash = calculateSafeOperationHash(await validator.getAddress(), safeOp, await chainId()) const signature = buildSignatureBytes([await signHash(user1, safeOpHash)]) - const userOp = buildUserOperationFromSafeUserOperation({ safeOp, signature }) + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature }) await logGas('Execute UserOp without fee payment', entryPoint.handleOps([userOp], user1.address)) expect(await ethers.provider.getBalance(await safe.getAddress())).to.be.eq(ethers.parseEther('0.5')) }) @@ -71,7 +71,7 @@ describe('Safe4337Mock', () => { ) const safeOpHash = calculateSafeOperationHash(await validator.getAddress(), safeOp, await chainId()) const signature = buildSignatureBytes([await signHash(user1, safeOpHash)]) - const userOp = buildUserOperationFromSafeUserOperation({ safeOp, signature }) + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature }) await logGas('Execute UserOp with fee payment', entryPoint.handleOps([userOp], feeBeneficiary)) // checking that the fee was paid @@ -111,7 +111,7 @@ describe('Safe4337Mock', () => { validAfter, validUntil, }) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature: '0x', }) diff --git a/modules/4337/test/erc4337/Safe4337Module.spec.ts b/modules/4337/test/erc4337/Safe4337Module.spec.ts index f647097d..bb9cf035 100644 --- a/modules/4337/test/erc4337/Safe4337Module.spec.ts +++ b/modules/4337/test/erc4337/Safe4337Module.spec.ts @@ -7,7 +7,7 @@ import { GasParameters, buildSafeUserOp, buildSafeUserOpTransaction, - buildUserOperationFromSafeUserOperation, + buildPackedUserOperationFromSafeUserOperation, calculateSafeOperationHash, packGasParameters, packValidationData, @@ -160,7 +160,7 @@ describe('Safe4337Module', () => { validAfter, validUntil, }) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature: '0x', }) @@ -178,7 +178,7 @@ describe('Safe4337Module', () => { const safeOp = buildSafeUserOpTransaction(await safeModule.getAddress(), user.address, 0, '0x', '0', await entryPoint.getAddress()) const safeOpHash = calculateSafeOperationHash(await validator.getAddress(), safeOp, await chainId()) const signature = buildSignatureBytes([await signHash(user, safeOpHash)]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) @@ -207,7 +207,7 @@ describe('Safe4337Module', () => { }) const safeOpHash = calculateSafeOperationHash(await validator.getAddress(), safeOp, await chainId()) const signature = buildSignatureBytes([await signHash(user, safeOpHash)]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) @@ -224,7 +224,7 @@ describe('Safe4337Module', () => { const safeOp = buildSafeUserOpTransaction(await safeModule.getAddress(), user.address, 0, '0x', '0', await entryPoint.getAddress()) const safeOpHash = calculateSafeOperationHash(await validator.getAddress(), safeOp, await chainId()) const signature = buildSignatureBytes([await signHash(user, safeOpHash)]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) @@ -258,7 +258,7 @@ describe('Safe4337Module', () => { const safeOpHash = calculateSafeOperationHash(await validator.getAddress(), safeOp, await chainId()) const signature = buildSignatureBytes([await signHash(user, safeOpHash)]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) diff --git a/modules/4337/test/gas/Gas.spec.ts b/modules/4337/test/gas/Gas.spec.ts index 02edbeb4..75db51b0 100644 --- a/modules/4337/test/gas/Gas.spec.ts +++ b/modules/4337/test/gas/Gas.spec.ts @@ -2,7 +2,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 { buildUserOperationFromSafeUserOperation, buildSafeUserOpTransaction, signSafeOp } from '../../src/utils/userOp' +import { buildPackedUserOperationFromSafeUserOperation, buildSafeUserOpTransaction, signSafeOp } from '../../src/utils/userOp' import { chainId } from '../utils/encoding' import { Safe4337 } from '../../src/utils/safe' @@ -64,7 +64,7 @@ describe('Gas Metering', () => { const signature = buildSignatureBytes([await signSafeOp(user, await validator.getAddress(), safeOp, await chainId())]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) @@ -103,7 +103,7 @@ describe('Gas Metering', () => { const signature = buildSignatureBytes([await signSafeOp(user, await validator.getAddress(), safeOp, await chainId())]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) @@ -138,7 +138,7 @@ describe('Gas Metering', () => { false, ) const signature = buildSignatureBytes([await signSafeOp(user, await validator.getAddress(), safeOp, await chainId())]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) @@ -177,7 +177,7 @@ describe('Gas Metering', () => { const signature = buildSignatureBytes([await signSafeOp(user, await validator.getAddress(), safeOp, await chainId())]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) @@ -209,7 +209,7 @@ describe('Gas Metering', () => { }, ) const signature = buildSignatureBytes([await signSafeOp(user, await validator.getAddress(), safeOp, await chainId())]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) @@ -249,7 +249,7 @@ describe('Gas Metering', () => { false, ) const signature = buildSignatureBytes([await signSafeOp(user, await validator.getAddress(), safeOp, await chainId())]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, }) @@ -283,7 +283,7 @@ describe('Gas Metering', () => { false, ) const signature = buildSignatureBytes([await signSafeOp(user, await validator.getAddress(), safeOp, await chainId())]) - const userOp = buildUserOperationFromSafeUserOperation({ + const userOp = buildPackedUserOperationFromSafeUserOperation({ safeOp, signature, })