diff --git a/packages/demos/inpage/demo/config/ConfigType.ts b/packages/demos/inpage/demo/config/ConfigType.ts index 65a13f6..f237b7d 100644 --- a/packages/demos/inpage/demo/config/ConfigType.ts +++ b/packages/demos/inpage/demo/config/ConfigType.ts @@ -7,6 +7,11 @@ type ConfigType = { addFundsEthAmount?: string; deployerSeedPhrase: string; requirePermission?: boolean; + externalContracts?: { + entryPoint: string; + blsSignatureAggregator: string; + addressRegistry: string; + }; }; export default ConfigType; diff --git a/packages/demos/inpage/demo/config/config.template.ts b/packages/demos/inpage/demo/config/config.template.ts index 9ce7369..d720c20 100644 --- a/packages/demos/inpage/demo/config/config.template.ts +++ b/packages/demos/inpage/demo/config/config.template.ts @@ -15,11 +15,24 @@ const config: ConfigType = { rpcUrl: 'http://127.0.0.1:8545', deployerSeedPhrase: 'test test test test test test test test test test test junk', + // Uncomment this with the url of a bundler to enable using an external // bundler (sometimes this is the same as rpcUrl). Otherwise, a bundler will // be simulated inside the library. // bundlerRpcUrl: '', + requirePermission: false, + + // These contracts will be deployed deterministically by default. However, + // if you need to interop with a specific existing deployment, you'll need + // to specify the contracts here: + // externalContracts: { + // entryPoint: '0x...', + // blsSignatureAggregator: '0x...', + // addressRegistry: '0x...', + // } + // (Other contracts will still be deterministically deployed, but they + // shouldn't be required for interop purposes.) }; export default config; diff --git a/packages/demos/inpage/demo/main.tsx b/packages/demos/inpage/demo/main.tsx index b88f20b..583d9db 100644 --- a/packages/demos/inpage/demo/main.tsx +++ b/packages/demos/inpage/demo/main.tsx @@ -13,6 +13,7 @@ WaxInPage.addStylesheet(); const waxInPage = new WaxInPage({ rpcUrl: config.rpcUrl, bundlerRpcUrl: config.bundlerRpcUrl, + externalContracts: config.externalContracts, }); waxInPage.attachGlobals(); diff --git a/packages/demos/inpage/scripts/dev.ts b/packages/demos/inpage/scripts/dev.ts index 1be1d33..dcb0c4f 100755 --- a/packages/demos/inpage/scripts/dev.ts +++ b/packages/demos/inpage/scripts/dev.ts @@ -1,12 +1,34 @@ #!/usr/bin/env tsx +/* eslint-disable no-console */ + import concurrently from 'concurrently'; import config from '../demo/config/config.ts'; const tasks = ['vite']; +let externalNode: boolean; + if (config.rpcUrl === 'http://127.0.0.1:8545') { - tasks.push('yarn --cwd hardhat hardhat node'); + try { + await fetch(config.rpcUrl); + externalNode = true; + } catch (e) { + if ((e as { code: string }).code !== 'ECONNREFUSED') { + throw e; + } + + externalNode = false; + tasks.push('yarn --cwd hardhat hardhat node'); + } +} else { + externalNode = true; +} + +if (externalNode) { + console.log(`Relying on external node: ${config.rpcUrl}`); +} else { + console.log('Starting dev node'); } await concurrently(tasks, { killOthers: 'failure' }).result; diff --git a/packages/demos/inpage/src/Button.tsx b/packages/demos/inpage/src/Button.tsx index 0b870ff..53a618f 100644 --- a/packages/demos/inpage/src/Button.tsx +++ b/packages/demos/inpage/src/Button.tsx @@ -130,6 +130,10 @@ const Button = ({ return; } + if ('key' in e && e.key !== 'Enter' && e.key !== ' ') { + return; + } + runAsync(async () => { try { setLoading(true); diff --git a/packages/demos/inpage/src/EthereumApi.tsx b/packages/demos/inpage/src/EthereumApi.tsx index e5653af..035b20b 100644 --- a/packages/demos/inpage/src/EthereumApi.tsx +++ b/packages/demos/inpage/src/EthereumApi.tsx @@ -13,12 +13,14 @@ import { roundUpPseudoFloat } from './helpers/encodeUtils'; // We need a UserOperation in order to estimate the gas fields of a // UserOperation, so we use these values as placeholders. -const temporaryEstimationGas = '0x012345'; +const temporaryEstimationGas = '0x01234567'; const temporarySignature = [ '0x', '123456fe2807660c417ca1a38760342fa70135fcab89a8c7c879a77da8ce7a0b5a3805735e', '95170906b11c6f30dcc74e463e1e6990c68a3998a7271b728b123456', ].join(''); +const verificationGasLimitBuffer = 2000n; +const preVerificationGasBuffer = 1000n; type StrictUserOperation = { sender: string; @@ -183,9 +185,15 @@ export default class EthereumApi { return { ...userOp, + callGasLimit: roundUpPseudoFloat(userOp.callGasLimit), + verificationGasLimit: `0x${roundUpPseudoFloat( + BigInt(userOp.verificationGasLimit), + ).toString(16)}`, + preVerificationGas: `0x${roundUpPseudoFloat( + BigInt(userOp.preVerificationGas), + ).toString(16)}`, maxFeePerGas: roundUpPseudoFloat(userOp.maxFeePerGas), maxPriorityFeePerGas: roundUpPseudoFloat(userOp.maxPriorityFeePerGas), - callGasLimit: roundUpPseudoFloat(userOp.callGasLimit), }; } @@ -342,7 +350,7 @@ export default class EthereumApi { callData, callGasLimit: actions.map((a) => BigInt(a.gas)).reduce((a, b) => a + b), verificationGasLimit: temporaryEstimationGas, - preVerificationGas: temporaryEstimationGas, + preVerificationGas: '0x0', maxFeePerGas, maxPriorityFeePerGas, paymasterAndData: '0x', @@ -360,8 +368,14 @@ export default class EthereumApi { params: [userOp, await contracts.entryPoint.getAddress()], }); - userOp.verificationGasLimit = verificationGasLimit; - userOp.preVerificationGas = preVerificationGas; + userOp.verificationGasLimit = `0x${( + BigInt(verificationGasLimit) + verificationGasLimitBuffer + ).toString(16)}`; + userOp.preVerificationGas = `0x${( + BigInt(preVerificationGas) + preVerificationGasBuffer + ).toString(16)}`; + + userOp = this.#maybeRoundUpPseudoFloats(userOp); userOpHash = await this.#calculateUserOpHash(userOp); diff --git a/packages/demos/inpage/src/JsonRpcError.ts b/packages/demos/inpage/src/JsonRpcError.ts index 8990d30..cdbe592 100644 --- a/packages/demos/inpage/src/JsonRpcError.ts +++ b/packages/demos/inpage/src/JsonRpcError.ts @@ -1,7 +1,7 @@ import z from 'zod'; class JsonRpcError extends Error { - code: number; + code: number | string; data: unknown; constructor({ code, data, message }: RawJsonRpcError) { @@ -17,7 +17,7 @@ class JsonRpcError extends Error { } const RawJsonRpcError = z.object({ - code: z.number().int(), + code: z.union([z.number().int(), z.string()]), data: z.unknown(), message: z.string(), }); diff --git a/packages/demos/inpage/src/WaxInPage.tsx b/packages/demos/inpage/src/WaxInPage.tsx index 2a3fed1..31cef9f 100644 --- a/packages/demos/inpage/src/WaxInPage.tsx +++ b/packages/demos/inpage/src/WaxInPage.tsx @@ -50,6 +50,7 @@ import measureCalldataGas from './measureCalldataGas'; import DeterministicDeployer, { DeterministicDeploymentViewer, } from '../lib-ts/deterministic-deployer/DeterministicDeployer'; +import ConfigType from '../demo/config/ConfigType'; type Config = { logRequests?: boolean; @@ -58,6 +59,7 @@ type Config = { deployContractsIfNeeded: boolean; ethersPollingInterval?: number; useTopLevelCompression?: boolean; + externalContracts?: ConfigType['externalContracts']; }; const defaultConfig: Config = { @@ -71,6 +73,7 @@ let ethersDefaultPollingInterval = 4000; type ConstructorOptions = { rpcUrl: string; bundlerRpcUrl?: string; + externalContracts?: ConfigType['externalContracts']; storage?: WaxStorage; }; @@ -103,6 +106,7 @@ export default class WaxInPage { constructor({ rpcUrl, bundlerRpcUrl, + externalContracts, storage = makeLocalWaxStorage(), }: ConstructorOptions) { let bundler: IBundler; @@ -113,6 +117,8 @@ export default class WaxInPage { bundler = new NetworkBundler(bundlerRpcUrl); } + this.#config.externalContracts = + externalContracts ?? this.#config.externalContracts; this.ethereum = new EthereumApi(rpcUrl, this, bundler); this.storage = storage; this.ethersProvider = new ethers.BrowserProvider(this.ethereum); @@ -194,15 +200,48 @@ export default class WaxInPage { chainId, ); - const assumedEntryPoint = viewer.connectAssume(EntryPoint__factory, []); - - const assumedAddressRegistry = viewer.connectAssume( - AddressRegistry__factory, - [], - ); + const wallet = await this.requestAdminAccount('deploy-contracts'); const assumedBlsOpen = viewer.connectAssume(BLSOpen__factory, []); + let assumedEntryPoint: EntryPoint; + let assumedAddressRegistry: AddressRegistry; + let assumedBlsSignatureAggregator: BLSSignatureAggregator; + + if (this.#config.externalContracts) { + assumedEntryPoint = EntryPoint__factory.connect( + this.#config.externalContracts.entryPoint, + wallet, + ); + + assumedBlsSignatureAggregator = BLSSignatureAggregator__factory.connect( + this.#config.externalContracts.blsSignatureAggregator, + wallet, + ); + + assumedAddressRegistry = AddressRegistry__factory.connect( + this.#config.externalContracts.addressRegistry, + wallet, + ); + } else { + assumedEntryPoint = viewer.connectAssume(EntryPoint__factory, []); + + assumedAddressRegistry = viewer.connectAssume( + AddressRegistry__factory, + [], + ); + + assumedBlsSignatureAggregator = viewer.connectAssume( + DeterministicDeployer.link(BLSSignatureAggregator__factory, [ + { + 'account-abstraction/contracts/samples/bls/lib/BLSOpen.sol:BLSOpen': + await assumedBlsOpen.getAddress(), + }, + ]), + [], + ); + } + const contracts: Contracts = { greeter: viewer.connectAssume(Greeter__factory, ['']).connect(runner), entryPoint: assumedEntryPoint, @@ -226,15 +265,7 @@ export default class WaxInPage { [], ), testToken: viewer.connectAssume(ERC20Mock__factory, []), - blsSignatureAggregator: viewer.connectAssume( - DeterministicDeployer.link(BLSSignatureAggregator__factory, [ - { - 'account-abstraction/contracts/samples/bls/lib/BLSOpen.sol:BLSOpen': - await assumedBlsOpen.getAddress(), - }, - ]), - [], - ), + blsSignatureAggregator: assumedBlsSignatureAggregator, }; if (this.#contractsDeployed) { @@ -250,19 +281,49 @@ export default class WaxInPage { throw new Error('Contracts not deployed'); } - const wallet = await this.requestAdminAccount('deploy-contracts'); - const factory = await DeterministicDeployer.init(wallet); - const entryPoint = await factory.connectOrDeploy(EntryPoint__factory, []); - - const addressRegistry = await factory.connectOrDeploy( - AddressRegistry__factory, - [], - ); - const blsOpen = await factory.connectOrDeploy(BLSOpen__factory, []); + let entryPoint: EntryPoint; + let blsSignatureAggregator: BLSSignatureAggregator; + let addressRegistry: AddressRegistry; + + if (this.#config.externalContracts) { + entryPoint = assumedEntryPoint; + blsSignatureAggregator = assumedBlsSignatureAggregator; + addressRegistry = assumedAddressRegistry; + + await Promise.all( + [entryPoint, blsSignatureAggregator, addressRegistry].map( + async (contract) => { + if (!(await this.#checkDeployed(await contract.getAddress()))) { + throw new Error( + `External contract not deployed: ${await contract.getAddress()}`, + ); + } + }, + ), + ); + } else { + entryPoint = await factory.connectOrDeploy(EntryPoint__factory, []); + + blsSignatureAggregator = await factory.connectOrDeploy( + DeterministicDeployer.link(BLSSignatureAggregator__factory, [ + { + 'account-abstraction/contracts/samples/bls/lib/BLSOpen.sol:BLSOpen': + await blsOpen.getAddress(), + }, + ]), + [], + ); + + addressRegistry = await factory.connectOrDeploy( + AddressRegistry__factory, + [], + ); + } + const deployments: { [C in keyof Contracts]: () => Promise; } = { @@ -285,16 +346,7 @@ export default class WaxInPage { safeECDSARecoveryPlugin: () => factory.connectOrDeploy(SafeECDSARecoveryPlugin__factory, []), testToken: () => factory.connectOrDeploy(ERC20Mock__factory, []), - blsSignatureAggregator: async () => - factory.connectOrDeploy( - DeterministicDeployer.link(BLSSignatureAggregator__factory, [ - { - 'account-abstraction/contracts/samples/bls/lib/BLSOpen.sol:BLSOpen': - await blsOpen.getAddress(), - }, - ]), - [], - ), + blsSignatureAggregator: () => Promise.resolve(blsSignatureAggregator), }; for (const deployment of Object.values(deployments)) { @@ -306,18 +358,19 @@ export default class WaxInPage { async #checkDeployments(contracts: Contracts): Promise { const deployFlags = await Promise.all( - Object.values(contracts).map(async (contract) => { - const existingCode = await this.ethersProvider.getCode( - contract.getAddress(), - ); - - return existingCode !== '0x'; - }), + Object.values(contracts).map( + async (contract) => + await this.#checkDeployed(await contract.getAddress()), + ), ); return deployFlags.every((flag) => flag); } + async #checkDeployed(address: string): Promise { + return (await this.ethersProvider.getCode(address)) !== '0x'; + } + async requestAdminAccount(purpose: AdminPurpose): Promise { if (this.#adminAccount) { return this.#adminAccount; diff --git a/packages/demos/inpage/src/bundlers/SimulatedBundler.ts b/packages/demos/inpage/src/bundlers/SimulatedBundler.ts index 323c38e..9b0c3bc 100644 --- a/packages/demos/inpage/src/bundlers/SimulatedBundler.ts +++ b/packages/demos/inpage/src/bundlers/SimulatedBundler.ts @@ -23,7 +23,6 @@ import { hexJoin, hexLen, lookupAddress, - roundUpPseudoFloat, } from '../helpers/encodeUtils'; import windowDebug from '../../demo/windowDebug'; import simulateValidation from '../helpers/simulateValidation'; @@ -148,19 +147,13 @@ export default class SimulatedBundler implements IBundler { ], }); - let res = { + return { preVerificationGas: `0x${(basePreVerificationGas + calldataGas).toString( 16, )}`, verificationGasLimit: `0x${verificationGasLimit.toString(16)}`, callGasLimit, }; - - if (this.#waxInPage.getConfig('useTopLevelCompression')) { - res = SimulatedBundler.roundUpGasEstimate(res); - } - - return res; } async eth_getUserOperationReceipt( @@ -513,21 +506,6 @@ export default class SimulatedBundler implements IBundler { parts.push(encodeBytes(calldata)); } } - - static roundUpGasEstimate({ - preVerificationGas, - verificationGasLimit, - callGasLimit, - }: EthereumRpc.UserOperationGasEstimate): EthereumRpc.UserOperationGasEstimate { - const roundUp = (x: string) => - `0x${roundUpPseudoFloat(BigInt(x)).toString(16)}`; - - return { - preVerificationGas: roundUp(preVerificationGas), - verificationGasLimit: roundUp(verificationGasLimit), - callGasLimit: roundUp(callGasLimit), - }; - } } const decompressAndPerformSelector = ethers.FunctionFragment.getSelector( diff --git a/packages/plugins/.gitignore b/packages/plugins/.gitignore index fc296fb..1947bfe 100644 --- a/packages/plugins/.gitignore +++ b/packages/plugins/.gitignore @@ -10,3 +10,5 @@ cache cache_hardhat artifacts +deployedAddresses.backup.json +deployedAddresses.json diff --git a/packages/plugins/hardhat.config.ts b/packages/plugins/hardhat.config.ts index 9a59407..bcbc469 100644 --- a/packages/plugins/hardhat.config.ts +++ b/packages/plugins/hardhat.config.ts @@ -20,7 +20,7 @@ const config: HardhatUserConfig = { settings: { optimizer: { enabled: true, - runs: 200, + runs: 1_000_000, }, }, }, diff --git a/packages/plugins/script/deploy_all.ts b/packages/plugins/script/deploy_all.ts index 4613bf2..d90b5a6 100644 --- a/packages/plugins/script/deploy_all.ts +++ b/packages/plugins/script/deploy_all.ts @@ -1,5 +1,9 @@ +import fs from "fs/promises"; import { ethers } from "ethers"; -import DeterministicDeployer from "../lib-ts/deterministic-deployer/DeterministicDeployer"; +import DeterministicDeployer, { + ContractFactoryConstructor, + DeployParams, +} from "../lib-ts/deterministic-deployer/DeterministicDeployer"; import { SimulateTxAccessor__factory, SafeProxyFactory__factory, @@ -13,11 +17,17 @@ import { EntryPoint__factory, BLSSignatureAggregator__factory, BLSOpen__factory, + HandleOpsCaller__factory, + HandleAggregatedOpsCaller__factory, + AddressRegistry__factory, } from "../typechain-types"; import makeDevFaster from "../test/e2e/utils/makeDevFaster"; import { TokenCallbackHandler__factory } from "../typechain-types/factories/lib/safe-contracts/contracts/handler/TokenCallbackHandler__factory"; import bundlerConfig from "./../config/bundler.config.json"; +// 'test '.repeat(11) + 'absent' +const testAbsentAddress = "0xe8250207B79D7396631bb3aE38a7b457261ae0B6"; + async function deploy() { const { NODE_URL, MNEMONIC } = process.env; const provider = new ethers.JsonRpcProvider(NODE_URL); @@ -25,63 +35,140 @@ async function deploy() { const hdNode = ethers.HDNodeWallet.fromPhrase(MNEMONIC!); const wallet = new ethers.Wallet(hdNode.privateKey, provider); - const deployer = await DeterministicDeployer.init(wallet); + const recordingDeployer = await RecordingDeployer.init(wallet); - const contractFactories = [ - SimulateTxAccessor__factory, - TokenCallbackHandler__factory, - CompatibilityFallbackHandler__factory, - CreateCall__factory, - EntryPoint__factory, - MultiSend__factory, - MultiSendCallOnly__factory, - SignMessageLib__factory, - BLSOpen__factory, - ]; - - for (const contractFactory of contractFactories) { - const contract = await deployer.connectOrDeploy(contractFactory, []); - - const contractName = contractFactory.name.split("_")[0]; - console.log(`deployed ${contractName} to ${await contract.getAddress()}`); - } - - const blsSignatureAggregatorFactory = DeterministicDeployer.link( + const linkedAggregator = DeterministicDeployer.link( BLSSignatureAggregator__factory, [ { "lib/account-abstraction/contracts/samples/bls/lib/BLSOpen.sol:BLSOpen": - deployer.calculateAddress(BLSOpen__factory, []), + recordingDeployer.deployer.calculateAddress(BLSOpen__factory, []), }, ], ); - const blsSignatureAggregator = await deployer.connectOrDeploy( - blsSignatureAggregatorFactory, - [bundlerConfig.entryPoint], - ); - console.log( - `deployed ${ - BLSSignatureAggregator__factory.name.split("_")[0] - } to ${await blsSignatureAggregator.getAddress()}`, + + const deployments = [ + ["SimulateTxAccessor", SimulateTxAccessor__factory], + ["TokenCallbackHandler", TokenCallbackHandler__factory], + ["CompatibilityFallbackHandler", CompatibilityFallbackHandler__factory], + ["CreateCall", CreateCall__factory], + ["EntryPoint", EntryPoint__factory], + ["MultiSend", MultiSend__factory], + ["MultiSendCallOnly", MultiSendCallOnly__factory], + ["SignMessageLib", SignMessageLib__factory], + ["BLSOpen", BLSOpen__factory], + ["BLSSignatureAggregator", linkedAggregator], + ["AddressRegistry", AddressRegistry__factory], + ] as const; + + for (const [name, contractFactory] of deployments) { + await recordingDeployer.deploy(name, contractFactory, []); + } + + const handleOpsCaller = await recordingDeployer.deploy( + "HandleOpsCaller", + HandleOpsCaller__factory, + [ + recordingDeployer.deployer.calculateAddress(EntryPoint__factory, []), + testAbsentAddress, + recordingDeployer.deployer.calculateAddress(AddressRegistry__factory, []), + ], ); - const safeDeployer = await DeterministicDeployer.initSafeVersion(wallet); + const handleAggregatedOpsCaller = await recordingDeployer.deploy( + "HandleAggregatedOpsCaller", + HandleAggregatedOpsCaller__factory, + [ + recordingDeployer.deployer.calculateAddress(EntryPoint__factory, []), + testAbsentAddress, + recordingDeployer.deployer.calculateAddress(linkedAggregator, []), + recordingDeployer.deployer.calculateAddress(AddressRegistry__factory, []), + ], + ); + + void handleOpsCaller; + void handleAggregatedOpsCaller; const safeContractFactories = [ - SafeProxyFactory__factory, - SafeL2__factory, - Safe__factory, - ]; + ["SafeProxyFactory", SafeProxyFactory__factory], + ["SafeL2", SafeL2__factory], + ["Safe", Safe__factory], + ] as const; - for (const contractFactory of safeContractFactories) { - const contract = await safeDeployer.connectOrDeploy(contractFactory, []); - - const contractName = contractFactory.name.split("_")[0]; - console.log(`deployed ${contractName} to ${await contract.getAddress()}`); + for (const [name, contractFactory] of safeContractFactories) { + await recordingDeployer.deployWithSafeDeployer(name, contractFactory, []); } + + await recordingDeployer.finish(); } deploy().catch((error: Error) => { console.error(error); process.exitCode = 1; }); + +class RecordingDeployer { + deployments: Record = {}; + + private constructor( + public deployer: DeterministicDeployer, + public safeDeployer: DeterministicDeployer, + ) {} + + static async init(wallet: ethers.Wallet): Promise { + const deployer = await DeterministicDeployer.init(wallet); + const safeDeployer = await DeterministicDeployer.initSafeVersion(wallet); + + try { + await fs.rename( + "deployedAddresses.json", + "deployedAddresses.backup.json", + ); + } catch (e) { + if ((e as { code: string }).code !== "ENOENT") { + throw e; + } + } + + return new RecordingDeployer(deployer, safeDeployer); + } + + async deploy( + name: string, + factory: CFC, + args: DeployParams, + ) { + return this.deployImpl(name, factory, args, this.deployer); + } + + async deployWithSafeDeployer( + name: string, + factory: CFC, + args: DeployParams, + ) { + return this.deployImpl(name, factory, args, this.safeDeployer); + } + + private async deployImpl( + name: string, + factory: CFC, + args: DeployParams, + deployer: DeterministicDeployer, + ) { + const contract = await deployer.connectOrDeploy(factory, args); + const address = await contract.getAddress(); + console.log(`Deployed ${name} to ${address}`); + this.deployments[name] = address; + + return contract; + } + + async finish() { + await fs.writeFile( + "deployedAddresses.json", + JSON.stringify(this.deployments, null, 2), + ); + + await fs.rm("deployedAddresses.backup.json", { force: true }); + } +} diff --git a/packages/plugins/script/start-hardhat.sh b/packages/plugins/script/start-hardhat.sh index 2b59073..35ba6bd 100755 --- a/packages/plugins/script/start-hardhat.sh +++ b/packages/plugins/script/start-hardhat.sh @@ -17,7 +17,6 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) set -meuo pipefail function cleanup { - docker stop $CONTAINER || true jobs -p | xargs kill } diff --git a/packages/plugins/test/integration/safe/SafeZkEmailRecoveryPluginIntegration.t.sol b/packages/plugins/test/integration/safe/SafeZkEmailRecoveryPluginIntegration.t.sol index 13d0193..8c73888 100644 --- a/packages/plugins/test/integration/safe/SafeZkEmailRecoveryPluginIntegration.t.sol +++ b/packages/plugins/test/integration/safe/SafeZkEmailRecoveryPluginIntegration.t.sol @@ -151,7 +151,7 @@ contract SafeZkEmailRecoveryPlugin_Integration_Test is TestHelper { ); emailProof.timestamp = block.timestamp; emailProof - .maskedSubject = "Accept guardian request for 0x78cA0A67bF6Cbe8Bf2429f0c7934eE5Dd687a32c"; + .maskedSubject = "Accept guardian request for 0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9"; emailProof.emailNullifier = keccak256(abi.encode("nullifier 1")); emailProof.accountSalt = accountSalt; emailProof.isCodeExist = true; @@ -185,7 +185,7 @@ contract SafeZkEmailRecoveryPlugin_Integration_Test is TestHelper { ); emailProof.timestamp = block.timestamp + 1; emailProof - .maskedSubject = "Update owner to 0xDdF4497d39b10cf50Af640942cc15233970dA0c2 on account 0x78cA0A67bF6Cbe8Bf2429f0c7934eE5Dd687a32c"; + .maskedSubject = "Update owner to 0xDdF4497d39b10cf50Af640942cc15233970dA0c2 on account 0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9"; emailProof.emailNullifier = keccak256(abi.encode("nullifier 2")); emailProof.accountSalt = accountSalt; require(