From 323dfb63845a9fe7916d67555810dc29adfdbd07 Mon Sep 17 00:00:00 2001 From: Andrew Morris Date: Mon, 18 Sep 2023 16:56:58 +1000 Subject: [PATCH 1/4] Fix unnecessary 5s delays in SafeECDSAPlugin test --- .../integration/SafeECDSAPlugin.test.ts | 27 ++++++-------- .../test/hardhat/utils/sendUserOpAndWait.ts | 36 +++++++++++++++++++ 2 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 account-integrations/safe/test/hardhat/utils/sendUserOpAndWait.ts diff --git a/account-integrations/safe/test/hardhat/integration/SafeECDSAPlugin.test.ts b/account-integrations/safe/test/hardhat/integration/SafeECDSAPlugin.test.ts index 155e4076..5a5f730c 100644 --- a/account-integrations/safe/test/hardhat/integration/SafeECDSAPlugin.test.ts +++ b/account-integrations/safe/test/hardhat/integration/SafeECDSAPlugin.test.ts @@ -2,7 +2,6 @@ import hre from "hardhat"; import { expect } from "chai"; import { AddressZero } from "@ethersproject/constants"; import { getBytes, concat, resolveProperties, ethers } from "ethers"; -import { ethers as ethersV5 } from "ethers-v5"; import { UserOperationStruct } from "@account-abstraction/contracts"; import { getUserOpHash } from "@account-abstraction/utils"; import { calculateProxyAddress } from "../utils/calculateProxyAddress"; @@ -10,7 +9,7 @@ import { SafeProxyFactory__factory, Safe__factory, } from "../../../typechain-types"; -import sleep from "../utils/sleep"; +import sendUserOpAndWait from "../utils/sendUserOpAndWait"; const ERC4337_TEST_ENV_VARIABLES_DEFINED = typeof process.env.ERC4337_TEST_BUNDLER_URL !== "undefined" && @@ -28,7 +27,7 @@ const MNEMONIC = process.env.MNEMONIC; describe("SafeECDSAPlugin", () => { const setupTests = async () => { - const bundlerProvider = new ethersV5.providers.JsonRpcProvider(BUNDLER_URL); + const bundlerProvider = new ethers.JsonRpcProvider(BUNDLER_URL); const provider = new ethers.JsonRpcProvider(NODE_URL); const userWallet = ethers.Wallet.fromPhrase(MNEMONIC!).connect(provider); @@ -87,8 +86,7 @@ describe("SafeECDSAPlugin", () => { userWallet.address, { gasLimit: 1_000_000 }, ); - // The bundler uses a different node, so we need to allow it sometime to sync - await sleep(5000); + await safeECDSAPlugin.deploymentTransaction()?.wait(); const feeData = await provider.getFeeData(); if (!feeData.maxFeePerGas || !feeData.maxPriorityFeePerGas) { @@ -147,12 +145,12 @@ describe("SafeECDSAPlugin", () => { ); // Native tokens for the pre-fund 💸 - await userWallet.sendTransaction({ - to: deployedAddress, - value: ethers.parseEther("100"), - }); - // The bundler uses a different node, so we need to allow it sometime to sync - await sleep(5000); + await ( + await userWallet.sendTransaction({ + to: deployedAddress, + value: ethers.parseEther("100"), + }) + ).wait(); const unsignedUserOperation: UserOperationStruct = { sender: deployedAddress, @@ -193,12 +191,7 @@ describe("SafeECDSAPlugin", () => { const recipientBalanceBefore = await provider.getBalance(recipientAddress); - await bundlerProvider.send("eth_sendUserOperation", [ - userOperation, - ENTRYPOINT_ADDRESS, - ]); - // The bundler uses a different node, so we need to allow it sometime to sync - await sleep(5000); + await sendUserOpAndWait(userOperation, ENTRYPOINT_ADDRESS, bundlerProvider); const recipientBalanceAfter = await provider.getBalance(recipientAddress); diff --git a/account-integrations/safe/test/hardhat/utils/sendUserOpAndWait.ts b/account-integrations/safe/test/hardhat/utils/sendUserOpAndWait.ts new file mode 100644 index 00000000..1d70b18b --- /dev/null +++ b/account-integrations/safe/test/hardhat/utils/sendUserOpAndWait.ts @@ -0,0 +1,36 @@ +import { UserOperationStruct } from "@account-abstraction/contracts"; +import { ethers } from "ethers"; +import sleep from "./sleep"; + +export default async function sendUserOpAndWait( + userOp: UserOperationStruct, + entryPoint: string, + bundlerProvider: ethers.JsonRpcProvider, + pollingDelay = 100, + maxAttempts = 200, +) { + const userOpHash = (await bundlerProvider.send("eth_sendUserOperation", [ + userOp, + entryPoint, + ])) as string; + + let receipt: { success: boolean } | null = null; + + let attempts = 0; + + while (attempts < maxAttempts && receipt === null) { + await sleep(pollingDelay); + + receipt = (await bundlerProvider.send("eth_getUserOperationReceipt", [ + userOpHash, + ])) as { success: boolean } | null; + + attempts++; + } + + if (receipt === null) { + throw new Error(`Could not get receipt after ${maxAttempts} attempts`); + } + + return receipt; +} From 591c6afd3bd6d51b899cae921bb293ea6a8206cf Mon Sep 17 00:00:00 2001 From: Andrew Morris Date: Mon, 18 Sep 2023 16:57:09 +1000 Subject: [PATCH 2/4] Fix unnecessary 5s delays in SafeWebAuthnPlugin test --- .../integration/SafeWebAuthnPlugin.test.ts | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/account-integrations/safe/test/hardhat/integration/SafeWebAuthnPlugin.test.ts b/account-integrations/safe/test/hardhat/integration/SafeWebAuthnPlugin.test.ts index 15a6521d..958db89d 100644 --- a/account-integrations/safe/test/hardhat/integration/SafeWebAuthnPlugin.test.ts +++ b/account-integrations/safe/test/hardhat/integration/SafeWebAuthnPlugin.test.ts @@ -2,14 +2,13 @@ import hre from "hardhat"; import { expect } from "chai"; import { AddressZero } from "@ethersproject/constants"; import { concat, ethers, BigNumberish } from "ethers"; -import { ethers as ethersV5 } from "ethers-v5"; import { UserOperationStruct } from "@account-abstraction/contracts"; import { calculateProxyAddress } from "../utils/calculateProxyAddress"; import { SafeProxyFactory__factory, Safe__factory, } from "../../../typechain-types"; -import sleep from "../utils/sleep"; +import sendUserOpAndWait from "../utils/sendUserOpAndWait"; const ERC4337_TEST_ENV_VARIABLES_DEFINED = typeof process.env.ERC4337_TEST_BUNDLER_URL !== "undefined" && @@ -27,7 +26,7 @@ const MNEMONIC = process.env.MNEMONIC; describe("SafeWebAuthnPlugin", () => { const setupTests = async () => { - const bundlerProvider = new ethersV5.providers.JsonRpcProvider(BUNDLER_URL); + const bundlerProvider = new ethers.JsonRpcProvider(BUNDLER_URL); const provider = new ethers.JsonRpcProvider(NODE_URL); const userWallet = ethers.Wallet.fromPhrase(MNEMONIC!).connect(provider); @@ -128,8 +127,7 @@ describe("SafeWebAuthnPlugin", () => { publicKey, { gasLimit: 2_000_000 }, ); - // The bundler uses a different node, so we need to allow it sometime to sync - await sleep(5000); + await safeWebAuthnPlugin.deploymentTransaction()?.wait(); const feeData = await provider.getFeeData(); if (!feeData.maxFeePerGas || !feeData.maxPriorityFeePerGas) { @@ -188,12 +186,12 @@ describe("SafeWebAuthnPlugin", () => { ); // Native tokens for the pre-fund 💸 - await userWallet.sendTransaction({ - to: deployedAddress, - value: ethers.parseEther("100"), - }); - // The bundler uses a different node, so we need to allow it sometime to sync - await sleep(5000); + await ( + await userWallet.sendTransaction({ + to: deployedAddress, + value: ethers.parseEther("100"), + }) + ).wait(); const userOperationWithoutGasFields = { sender: deployedAddress, @@ -248,12 +246,7 @@ describe("SafeWebAuthnPlugin", () => { const recipientBalanceBefore = await provider.getBalance(recipientAddress); - await bundlerProvider.send("eth_sendUserOperation", [ - userOperation, - ENTRYPOINT_ADDRESS, - ]); - // The bundler uses a different node, so we need to allow it sometime to sync - await sleep(5000); + await sendUserOpAndWait(userOperation, ENTRYPOINT_ADDRESS, bundlerProvider); const recipientBalanceAfter = await provider.getBalance(recipientAddress); From f2c583a26418bfe7eed5bbe5a4eae041d05bf12d Mon Sep 17 00:00:00 2001 From: Andrew Morris Date: Mon, 18 Sep 2023 16:58:34 +1000 Subject: [PATCH 3/4] Remove ethers-v5 --- account-integrations/safe/package.json | 1 - account-integrations/safe/yarn.lock | 32 +++++++++++++------------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/account-integrations/safe/package.json b/account-integrations/safe/package.json index 0784dfba..d8e4a4b8 100644 --- a/account-integrations/safe/package.json +++ b/account-integrations/safe/package.json @@ -33,7 +33,6 @@ "eslint-plugin-import": "^2.28.1", "eslint-plugin-prettier": "^5.0.0", "ethers": "^6.4.0", - "ethers-v5": "npm:ethers@5.7.2", "hardhat": "^2.17.1", "hardhat-gas-reporter": "^1.0.8", "hardhat-preprocessor": "^0.1.5", diff --git a/account-integrations/safe/yarn.lock b/account-integrations/safe/yarn.lock index 528c8beb..51b45455 100644 --- a/account-integrations/safe/yarn.lock +++ b/account-integrations/safe/yarn.lock @@ -2627,7 +2627,22 @@ ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.4: ethereum-cryptography "^0.1.3" rlp "^2.2.4" -"ethers-v5@npm:ethers@5.7.2", ethers@^5.5.3, ethers@^5.7.0, ethers@^5.7.1: +ethers@^4.0.40: + version "4.0.49" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.49.tgz#0eb0e9161a0c8b4761be547396bbe2fb121a8894" + integrity sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg== + dependencies: + aes-js "3.0.0" + bn.js "^4.11.9" + elliptic "6.5.4" + hash.js "1.1.3" + js-sha3 "0.5.7" + scrypt-js "2.0.4" + setimmediate "1.0.4" + uuid "2.0.1" + xmlhttprequest "1.8.0" + +ethers@^5.5.3, ethers@^5.7.0, ethers@^5.7.1: version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== @@ -2663,21 +2678,6 @@ ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.4: "@ethersproject/web" "5.7.1" "@ethersproject/wordlists" "5.7.0" -ethers@^4.0.40: - version "4.0.49" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.49.tgz#0eb0e9161a0c8b4761be547396bbe2fb121a8894" - integrity sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg== - dependencies: - aes-js "3.0.0" - bn.js "^4.11.9" - elliptic "6.5.4" - hash.js "1.1.3" - js-sha3 "0.5.7" - scrypt-js "2.0.4" - setimmediate "1.0.4" - uuid "2.0.1" - xmlhttprequest "1.8.0" - ethers@^6.4.0: version "6.6.7" resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.6.7.tgz#9cf773bcbc0ca56d783d4774e9b73b4d1aff9962" From fc2704e6fbc86adae5a637c5b012b7c5f250ae04 Mon Sep 17 00:00:00 2001 From: Andrew Morris Date: Mon, 18 Sep 2023 17:05:35 +1000 Subject: [PATCH 4/4] Avoid double await with receiptOf --- .../test/hardhat/integration/SafeECDSAPlugin.test.ts | 9 +++++---- .../hardhat/integration/SafeWebAuthnPlugin.test.ts | 9 +++++---- .../safe/test/hardhat/utils/receiptOf.ts | 10 ++++++++++ 3 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 account-integrations/safe/test/hardhat/utils/receiptOf.ts diff --git a/account-integrations/safe/test/hardhat/integration/SafeECDSAPlugin.test.ts b/account-integrations/safe/test/hardhat/integration/SafeECDSAPlugin.test.ts index 5a5f730c..47e5c29e 100644 --- a/account-integrations/safe/test/hardhat/integration/SafeECDSAPlugin.test.ts +++ b/account-integrations/safe/test/hardhat/integration/SafeECDSAPlugin.test.ts @@ -10,6 +10,7 @@ import { Safe__factory, } from "../../../typechain-types"; import sendUserOpAndWait from "../utils/sendUserOpAndWait"; +import receiptOf from "../utils/receiptOf"; const ERC4337_TEST_ENV_VARIABLES_DEFINED = typeof process.env.ERC4337_TEST_BUNDLER_URL !== "undefined" && @@ -145,12 +146,12 @@ describe("SafeECDSAPlugin", () => { ); // Native tokens for the pre-fund 💸 - await ( - await userWallet.sendTransaction({ + await receiptOf( + userWallet.sendTransaction({ to: deployedAddress, value: ethers.parseEther("100"), - }) - ).wait(); + }), + ); const unsignedUserOperation: UserOperationStruct = { sender: deployedAddress, diff --git a/account-integrations/safe/test/hardhat/integration/SafeWebAuthnPlugin.test.ts b/account-integrations/safe/test/hardhat/integration/SafeWebAuthnPlugin.test.ts index 958db89d..67d4ee47 100644 --- a/account-integrations/safe/test/hardhat/integration/SafeWebAuthnPlugin.test.ts +++ b/account-integrations/safe/test/hardhat/integration/SafeWebAuthnPlugin.test.ts @@ -9,6 +9,7 @@ import { Safe__factory, } from "../../../typechain-types"; import sendUserOpAndWait from "../utils/sendUserOpAndWait"; +import receiptOf from "../utils/receiptOf"; const ERC4337_TEST_ENV_VARIABLES_DEFINED = typeof process.env.ERC4337_TEST_BUNDLER_URL !== "undefined" && @@ -186,12 +187,12 @@ describe("SafeWebAuthnPlugin", () => { ); // Native tokens for the pre-fund 💸 - await ( - await userWallet.sendTransaction({ + await receiptOf( + userWallet.sendTransaction({ to: deployedAddress, value: ethers.parseEther("100"), - }) - ).wait(); + }), + ); const userOperationWithoutGasFields = { sender: deployedAddress, diff --git a/account-integrations/safe/test/hardhat/utils/receiptOf.ts b/account-integrations/safe/test/hardhat/utils/receiptOf.ts new file mode 100644 index 00000000..f0432aab --- /dev/null +++ b/account-integrations/safe/test/hardhat/utils/receiptOf.ts @@ -0,0 +1,10 @@ +import { ethers } from "ethers"; + +export default async function receiptOf( + txResponseOrPromise: + | ethers.TransactionResponse + | Promise, +) { + const txResponse = await txResponseOrPromise; + return await txResponse.wait(); +}