From 6aac792c4433ce2daab39f46c1be5ddbecce2ae3 Mon Sep 17 00:00:00 2001 From: JohnGuilding Date: Tue, 11 Jun 2024 22:31:00 +0100 Subject: [PATCH] Use recovery subject handlers --- foundry.toml | 4 +- script/Deploy.s.sol | 14 +- script/DeploySafeRecovery.s.sol | 17 +- src/EmailAccountRecoveryRouter.sol | 67 --- src/EmailRecoveryFactory.sol | 53 ++ ...lRecovery.sol => EmailRecoveryManager.sol} | 91 ++- src/SafeZkEmailRecovery.sol | 100 ---- .../EmailAccountRecoveryNew.sol | 35 +- src/handlers/EmailRecoverySubjectHandler.sol | 110 ++++ src/handlers/SafeRecoverySubjectHandler.sol | 146 +++++ ...Recovery.sol => IEmailRecoveryManager.sol} | 9 +- .../IEmailRecoverySubjectHandler.sol | 24 + src/interfaces/IRecoveryModule.sol | 2 +- src/libraries/BytesLib.sol | 71 +++ src/libraries/HexStrings.sol | 27 +- src/libraries/SubjectCalldataBuilder.sol | 29 - ...veryModule.sol => EmailRecoveryModule.sol} | 86 ++- .../OwnableValidatorRecoveryModule.sol | 128 ----- src/modules/SafeRecoveryModule.sol | 164 ------ .../OwnableValidatorBase.t.sol | 115 ---- .../OwnableValidatorRecovery.t.sol | 154 ++--- .../OwnableValidatorRecoveryBase.t.sol} | 62 +- .../SafeRecovery/SafeIntegrationBase.t.sol | 65 ++- .../SafeRecovery/SafeRecovery.t.sol | 92 +-- .../ValidatorEmailRecoveryModule.t.sol | 111 ---- .../ZkEmailRecovery.integration.t.sol | 544 +++++++++--------- test/unit/EmailRecoveryManagerHarness.sol | 49 ++ test/unit/UnitBase.t.sol | 65 ++- .../unit/ZkEmailRecovery/acceptGuardian.t.sol | 37 +- .../acceptanceSubjectTemplates.t.sol | 34 +- test/unit/ZkEmailRecovery/addGuardian.t.sol | 49 +- .../unit/ZkEmailRecovery/cancelRecovery.t.sol | 42 +- .../ZkEmailRecovery/changeThreshold.t.sol | 41 +- .../ZkEmailRecovery/completeRecovery.t.sol | 80 +-- .../computeRouterAddress.t.sol | 67 --- .../ZkEmailRecovery/configureRecovery.t.sol | 63 +- test/unit/ZkEmailRecovery/constructor.t.sol | 16 +- .../deInitRecoveryFromModule.t.sol | 46 +- .../deployRouterForAccount.t.sol | 39 -- .../ZkEmailRecovery/getAccountForRouter.t.sol | 46 -- test/unit/ZkEmailRecovery/getGuardian.t.sol | 9 +- .../ZkEmailRecovery/getGuardianConfig.t.sol | 9 +- .../ZkEmailRecovery/getRecoveryConfig.t.sol | 9 +- .../ZkEmailRecovery/getRecoveryRequest.t.sol | 9 +- .../ZkEmailRecovery/getRouterForAccount.t.sol | 46 -- .../ZkEmailRecovery/processRecovery.t.sol | 53 +- .../recoverySubjectTemplates.t.sol | 46 +- .../unit/ZkEmailRecovery/removeGuardian.t.sol | 35 +- .../unit/ZkEmailRecovery/setupGuardians.t.sol | 48 +- .../updateGuardianDKIMRegistry.t.sol | 19 +- .../updateGuardianVerifier.t.sol | 19 +- .../updateRecoveryConfig.t.sol | 73 ++- .../upgradeEmailAuthGuardian.t.sol | 19 +- .../validateAcceptanceSubjectTemplates.t.sol | 100 ++-- .../validateRecoverySubjectTemplates.t.sol | 232 ++++---- test/unit/ZkEmailRecoveryHarness.sol | 74 --- 56 files changed, 1612 insertions(+), 2182 deletions(-) delete mode 100644 src/EmailAccountRecoveryRouter.sol create mode 100644 src/EmailRecoveryFactory.sol rename src/{ZkEmailRecovery.sol => EmailRecoveryManager.sol} (92%) delete mode 100644 src/SafeZkEmailRecovery.sol rename src/{ => experimental}/EmailAccountRecoveryNew.sol (90%) create mode 100644 src/handlers/EmailRecoverySubjectHandler.sol create mode 100644 src/handlers/SafeRecoverySubjectHandler.sol rename src/interfaces/{IZkEmailRecovery.sol => IEmailRecoveryManager.sol} (96%) create mode 100644 src/interfaces/IEmailRecoverySubjectHandler.sol create mode 100644 src/libraries/BytesLib.sol delete mode 100644 src/libraries/SubjectCalldataBuilder.sol rename src/modules/{ValidatorEmailRecoveryModule.sol => EmailRecoveryModule.sol} (68%) delete mode 100644 src/modules/OwnableValidatorRecoveryModule.sol delete mode 100644 src/modules/SafeRecoveryModule.sol delete mode 100644 test/integration/OwnableValidatorRecovery/OwnableValidatorBase.t.sol rename test/integration/{ValidatorEmailRecoveryModule/ValidatorEmailRecoveryModuleBase.t.sol => OwnableValidatorRecovery/OwnableValidatorRecoveryBase.t.sol} (67%) delete mode 100644 test/integration/ValidatorEmailRecoveryModule/ValidatorEmailRecoveryModule.t.sol create mode 100644 test/unit/EmailRecoveryManagerHarness.sol delete mode 100644 test/unit/ZkEmailRecovery/computeRouterAddress.t.sol delete mode 100644 test/unit/ZkEmailRecovery/deployRouterForAccount.t.sol delete mode 100644 test/unit/ZkEmailRecovery/getAccountForRouter.t.sol delete mode 100644 test/unit/ZkEmailRecovery/getRouterForAccount.t.sol delete mode 100644 test/unit/ZkEmailRecoveryHarness.sol diff --git a/foundry.toml b/foundry.toml index e51dd6d7..454201ff 100644 --- a/foundry.toml +++ b/foundry.toml @@ -22,10 +22,10 @@ ignored_warnings_from = [ ] [rpc_endpoints] -baseSepolia = "${BASE_SEPOLIA_RPC_URL}" +sepolia = "${BASE_SEPOLIA_RPC_URL}" [etherscan] -baseSepolia = { key = "${BASE_SCAN_API_KEY}" } +sepolia = { key = "${BASE_SCAN_API_KEY}" } [fmt] bracket_spacing = true diff --git a/script/Deploy.s.sol b/script/Deploy.s.sol index 614950b2..ee3a1c8e 100644 --- a/script/Deploy.s.sol +++ b/script/Deploy.s.sol @@ -2,19 +2,27 @@ pragma solidity ^0.8.25; import { Script } from "forge-std/Script.sol"; -import { ZkEmailRecovery } from "src/ZkEmailRecovery.sol"; +import { EmailRecoverySubjectHandler } from "src/handlers/EmailRecoverySubjectHandler.sol"; +import { EmailRecoveryManager } from "src/EmailRecoveryManager.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; contract DeployScript is Script { function run() public { bytes32 salt = bytes32(uint256(0)); address verifier = 0xEdC642bbaD91E21cCE6cd436Fdc6F040FD0fF998; - address ecdsaOwnedDkimRegistry = 0xC83256CCf7B94d310e49edA05077899ca036eb78; + address dkimRegistry = 0xC83256CCf7B94d310e49edA05077899ca036eb78; address emailAuthImpl = 0x1C76Aa365c17B40c7E944DcCdE4dC6e6D2A7b748; vm.startBroadcast(vm.envUint("PRIVATE_KEY")); - new ZkEmailRecovery{ salt: salt }(verifier, ecdsaOwnedDkimRegistry, emailAuthImpl); + EmailRecoverySubjectHandler emailRecoveryHandler = new EmailRecoverySubjectHandler(); + + EmailRecoveryManager emailRecoveryManager = new EmailRecoveryManager{ salt: salt }( + verifier, dkimRegistry, emailAuthImpl, address(emailRecoveryHandler) + ); + + new EmailRecoveryModule(address(emailRecoveryManager)); vm.stopBroadcast(); } diff --git a/script/DeploySafeRecovery.s.sol b/script/DeploySafeRecovery.s.sol index 88375442..2177ebce 100644 --- a/script/DeploySafeRecovery.s.sol +++ b/script/DeploySafeRecovery.s.sol @@ -2,22 +2,27 @@ pragma solidity ^0.8.25; import { Script } from "forge-std/Script.sol"; -import { SafeZkEmailRecovery } from "src/SafeZkEmailRecovery.sol"; -import { SafeRecoveryModule } from "src/modules/SafeRecoveryModule.sol"; +import { SafeRecoverySubjectHandler } from "src/handlers/SafeRecoverySubjectHandler.sol"; +import { EmailRecoveryManager } from "src/EmailRecoveryManager.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; contract DeploySafeRecoveryScript is Script { function run() public { bytes32 salt = bytes32(uint256(0)); address verifier = 0xEdC642bbaD91E21cCE6cd436Fdc6F040FD0fF998; - address ecdsaOwnedDkimRegistry = 0xC83256CCf7B94d310e49edA05077899ca036eb78; + address dkimRegistry = 0xC83256CCf7B94d310e49edA05077899ca036eb78; address emailAuthImpl = 0x1C76Aa365c17B40c7E944DcCdE4dC6e6D2A7b748; vm.startBroadcast(vm.envUint("PRIVATE_KEY")); - SafeZkEmailRecovery safeZkEmailRecovery = - new SafeZkEmailRecovery{ salt: salt }(verifier, ecdsaOwnedDkimRegistry, emailAuthImpl); - new SafeRecoveryModule(address(safeZkEmailRecovery)); + SafeRecoverySubjectHandler emailRecoveryHandler = new SafeRecoverySubjectHandler(); + + EmailRecoveryManager emailRecoveryManager = new EmailRecoveryManager( + verifier, dkimRegistry, emailAuthImpl, address(emailRecoveryHandler) + ); + + new EmailRecoveryModule(address(emailRecoveryManager)); vm.stopBroadcast(); } diff --git a/src/EmailAccountRecoveryRouter.sol b/src/EmailAccountRecoveryRouter.sol deleted file mode 100644 index 145741f7..00000000 --- a/src/EmailAccountRecoveryRouter.sol +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; - -import { EmailAuthMsg } from "ether-email-auth/packages/contracts/src/EmailAuth.sol"; -import { IEmailAccountRecovery } from "./interfaces/IEmailAccountRecovery.sol"; - -/** - * Helper contract that routes relayer calls to correct EmailAccountRecovery implementation - */ -contract EmailAccountRecoveryRouter { - address public immutable EMAIL_ACCOUNT_RECOVERY_IMPL; - - constructor(address _emailAccountRecoveryImpl) { - EMAIL_ACCOUNT_RECOVERY_IMPL = _emailAccountRecoveryImpl; - } - - function verifier() external view returns (address) { - return IEmailAccountRecovery(EMAIL_ACCOUNT_RECOVERY_IMPL).verifier(); - } - - function dkim() external view returns (address) { - return IEmailAccountRecovery(EMAIL_ACCOUNT_RECOVERY_IMPL).dkim(); - } - - function emailAuthImplementation() external view returns (address) { - return IEmailAccountRecovery(EMAIL_ACCOUNT_RECOVERY_IMPL).emailAuthImplementation(); - } - - function acceptanceSubjectTemplates() external view returns (string[][] memory) { - return IEmailAccountRecovery(EMAIL_ACCOUNT_RECOVERY_IMPL).acceptanceSubjectTemplates(); - } - - function recoverySubjectTemplates() external view returns (string[][] memory) { - return IEmailAccountRecovery(EMAIL_ACCOUNT_RECOVERY_IMPL).recoverySubjectTemplates(); - } - - function computeEmailAuthAddress(bytes32 accountSalt) external view returns (address) { - return - IEmailAccountRecovery(EMAIL_ACCOUNT_RECOVERY_IMPL).computeEmailAuthAddress(accountSalt); - } - - function computeAcceptanceTemplateId(uint256 templateIdx) external view returns (uint256) { - return IEmailAccountRecovery(EMAIL_ACCOUNT_RECOVERY_IMPL).computeAcceptanceTemplateId( - templateIdx - ); - } - - function computeRecoveryTemplateId(uint256 templateIdx) external view returns (uint256) { - return IEmailAccountRecovery(EMAIL_ACCOUNT_RECOVERY_IMPL).computeRecoveryTemplateId( - templateIdx - ); - } - - function handleAcceptance(EmailAuthMsg memory emailAuthMsg, uint256 templateIdx) external { - IEmailAccountRecovery(EMAIL_ACCOUNT_RECOVERY_IMPL).handleAcceptance( - emailAuthMsg, templateIdx - ); - } - - function handleRecovery(EmailAuthMsg memory emailAuthMsg, uint256 templateIdx) external { - IEmailAccountRecovery(EMAIL_ACCOUNT_RECOVERY_IMPL).handleRecovery(emailAuthMsg, templateIdx); - } - - function completeRecovery() external { - IEmailAccountRecovery(EMAIL_ACCOUNT_RECOVERY_IMPL).completeRecovery(); - } -} diff --git a/src/EmailRecoveryFactory.sol b/src/EmailRecoveryFactory.sol new file mode 100644 index 00000000..ae231570 --- /dev/null +++ b/src/EmailRecoveryFactory.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import { EmailRecoveryManager } from "./EmailRecoveryManager.sol"; +import { EmailRecoveryModule } from "./modules/EmailRecoveryModule.sol"; +import { EmailRecoverySubjectHandler } from "./handlers/EmailRecoverySubjectHandler.sol"; + +contract EmailRecoveryFactory { + function deployModuleAndManager( + address verifier, + address dkimRegistry, + address emailAuthImpl, + address emailRecoveryHandler + ) + external + returns (address, address) + { + EmailRecoveryManager emailRecoveryManager = + new EmailRecoveryManager(verifier, dkimRegistry, emailAuthImpl, emailRecoveryHandler); + EmailRecoveryModule emailRecoveryModule = + new EmailRecoveryModule(address(emailRecoveryManager)); + + return (address(emailRecoveryManager), address(emailRecoveryModule)); + } + + function deployHandler(address emailRecoveryManager) external returns (address) { + EmailRecoverySubjectHandler emailRecoveryHandler = new EmailRecoverySubjectHandler(); + + return (address(emailRecoveryHandler)); + } + + function deployAll( + address verifier, + address dkimRegistry, + address emailAuthImpl + ) + external + returns (address, address, address) + { + EmailRecoverySubjectHandler emailRecoveryHandler = new EmailRecoverySubjectHandler(); + EmailRecoveryManager emailRecoveryManager = new EmailRecoveryManager( + verifier, dkimRegistry, emailAuthImpl, address(emailRecoveryHandler) + ); + EmailRecoveryModule emailRecoveryModule = + new EmailRecoveryModule(address(emailRecoveryManager)); + + return ( + address(emailRecoveryManager), + address(emailRecoveryModule), + address(emailRecoveryHandler) + ); + } +} diff --git a/src/ZkEmailRecovery.sol b/src/EmailRecoveryManager.sol similarity index 92% rename from src/ZkEmailRecovery.sol rename to src/EmailRecoveryManager.sol index 311b19a7..1e6e31bc 100644 --- a/src/ZkEmailRecovery.sol +++ b/src/EmailRecoveryManager.sol @@ -4,8 +4,9 @@ pragma solidity ^0.8.25; import { Create2 } from "@openzeppelin/contracts/utils/Create2.sol"; import { IModule } from "erc7579/interfaces/IERC7579Module.sol"; -import { EmailAccountRecoveryNew } from "./EmailAccountRecoveryNew.sol"; -import { IZkEmailRecovery } from "./interfaces/IZkEmailRecovery.sol"; +import { EmailAccountRecoveryNew } from "./experimental/EmailAccountRecoveryNew.sol"; +import { IEmailRecoveryManager } from "./interfaces/IEmailRecoveryManager.sol"; +import { IEmailRecoverySubjectHandler } from "./interfaces/IEmailRecoverySubjectHandler.sol"; import { IEmailAuth } from "./interfaces/IEmailAuth.sol"; import { IUUPSUpgradable } from "./interfaces/IUUPSUpgradable.sol"; import { IRecoveryModule } from "./interfaces/IRecoveryModule.sol"; @@ -14,10 +15,9 @@ import { GuardianStorage, GuardianStatus } from "./libraries/EnumerableGuardianMap.sol"; -import { SubjectCalldataBuilder } from "./libraries/SubjectCalldataBuilder.sol"; /** - * @title ZkEmailRecovery + * @title EmailRecoveryManager * @notice Provides a mechanism for account recovery using email guardians * @dev The underlying EmailAccountRecovery contract provides some base logic for deploying * guardian contracts and handling email verification. @@ -26,8 +26,9 @@ import { SubjectCalldataBuilder } from "./libraries/SubjectCalldataBuilder.sol"; * provide the core logic for email based account recovery that can be used across different account * implementations. * - * ZkEmailRecovery relies on a dedicated recovery module to execute a recovery attempt. This - * (ZkEmailRecovery) contract defines "what a valid recovery attempt is for an account", and the + * EmailRecoveryManager relies on a dedicated recovery module to execute a recovery attempt. This + * (EmailRecoveryManager) contract defines "what a valid recovery attempt is for an account", and + * the * recovery module defines “how that recovery attempt is executed on the account”. * * The core functions that must be called in the end-to-end flow for recovery are @@ -38,13 +39,15 @@ import { SubjectCalldataBuilder } from "./libraries/SubjectCalldataBuilder.sol"; * processRecovery in this contract * 4. completeRecovery */ -contract ZkEmailRecovery is EmailAccountRecoveryNew, IZkEmailRecovery { +contract EmailRecoveryManager is EmailAccountRecoveryNew, IEmailRecoveryManager { using EnumerableGuardianMap for EnumerableGuardianMap.AddressToGuardianMap; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS & STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + address public immutable subjectHandler; + /** * Minimum required time window between when a recovery attempt becomes valid and when it * becomes invalid @@ -72,10 +75,16 @@ contract ZkEmailRecovery is EmailAccountRecoveryNew, IZkEmailRecovery { */ mapping(address account => GuardianConfig guardianConfig) internal guardianConfigs; - constructor(address _verifier, address _dkimRegistry, address _emailAuthImpl) { + constructor( + address _verifier, + address _dkimRegistry, + address _emailAuthImpl, + address _subjectHandler + ) { verifierAddr = _verifier; dkimAddr = _dkimRegistry; emailAuthImplementationAddr = _emailAuthImpl; + subjectHandler = _subjectHandler; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ @@ -124,15 +133,11 @@ contract ZkEmailRecovery is EmailAccountRecoveryNew, IZkEmailRecovery { uint256[] memory weights, uint256 threshold, uint256 delay, - uint256 expiry, - string[][] memory acceptanceSubjectTemplate, - string[][] memory recoverySubjectTemplate + uint256 expiry ) external { address account = msg.sender; - acceptanceSubjectTemplates[account] = acceptanceSubjectTemplate; - recoverySubjectTemplates[account] = recoverySubjectTemplate; // setupGuardians contains a check that ensures this function can only be called once setupGuardians(account, guardians, weights, threshold); @@ -264,13 +269,8 @@ contract ZkEmailRecovery is EmailAccountRecoveryNew, IZkEmailRecovery { * @return string[][] A two-dimensional array of strings, where each inner array represents a * set of fixed strings and matchers for a subject template. */ - function getAcceptanceSubjectTemplates(address account) - public - view - override - returns (string[][] memory) - { - return acceptanceSubjectTemplates[account]; + function acceptanceSubjectTemplates() public view override returns (string[][] memory) { + return IEmailRecoverySubjectHandler(subjectHandler).acceptanceSubjectTemplates(); } /** @@ -294,13 +294,8 @@ contract ZkEmailRecovery is EmailAccountRecoveryNew, IZkEmailRecovery { internal override { - if (templateIdx != 0) { - revert InvalidTemplateIndex(); - } - - // TODO: store this somewhere so this can be done dynamically - uint256 accountIndex = 0; - address accountInEmail = abi.decode(subjectParams[accountIndex], (address)); + address accountInEmail = IEmailRecoverySubjectHandler(subjectHandler) + .validateAcceptanceSubject(templateIdx, subjectParams); if (recoveryRequests[accountInEmail].currentWeight > 0) { revert RecoveryInProcess(); @@ -336,13 +331,8 @@ contract ZkEmailRecovery is EmailAccountRecoveryNew, IZkEmailRecovery { * @return string[][] A two-dimensional array of strings, where each inner array represents a * set of fixed strings and matchers for a subject template. */ - function getRecoverySubjectTemplates(address account) - public - view - override - returns (string[][] memory) - { - return recoverySubjectTemplates[account]; + function recoverySubjectTemplates() public view override returns (string[][] memory) { + return IEmailRecoverySubjectHandler(subjectHandler).recoverySubjectTemplates(); } /** @@ -363,37 +353,31 @@ contract ZkEmailRecovery is EmailAccountRecoveryNew, IZkEmailRecovery { internal override { - if (templateIdx != 0) { - revert InvalidTemplateIndex(); - } - - // TODO: store these somewhere so this can be done dynamically - uint256 accountIndex = 0; - - address accountInEmail = abi.decode(subjectParams[accountIndex], (address)); - bytes memory recoveryCalldata = SubjectCalldataBuilder.buildSubjectCalldata(subjectParams); + (address account, bytes32 recoveryCalldataHash) = IEmailRecoverySubjectHandler( + subjectHandler + ).validateRecoverySubject(templateIdx, subjectParams, address(this)); // This check ensures GuardianStatus is correct and also that the // account in email is a valid account - GuardianStorage memory guardianStorage = getGuardian(accountInEmail, guardian); + GuardianStorage memory guardianStorage = getGuardian(account, guardian); if (guardianStorage.status != GuardianStatus.ACCEPTED) { revert InvalidGuardianStatus(guardianStorage.status, GuardianStatus.ACCEPTED); } - RecoveryRequest storage recoveryRequest = recoveryRequests[accountInEmail]; + RecoveryRequest storage recoveryRequest = recoveryRequests[account]; recoveryRequest.currentWeight += guardianStorage.weight; - uint256 threshold = getGuardianConfig(accountInEmail).threshold; + uint256 threshold = getGuardianConfig(account).threshold; if (recoveryRequest.currentWeight >= threshold) { - uint256 executeAfter = block.timestamp + recoveryConfigs[accountInEmail].delay; - uint256 executeBefore = block.timestamp + recoveryConfigs[accountInEmail].expiry; + uint256 executeAfter = block.timestamp + recoveryConfigs[account].delay; + uint256 executeBefore = block.timestamp + recoveryConfigs[account].expiry; recoveryRequest.executeAfter = executeAfter; recoveryRequest.executeBefore = executeBefore; - recoveryRequest.recoveryCalldata = recoveryCalldata; + recoveryRequest.calldataHash = recoveryCalldataHash; - emit RecoveryProcessed(accountInEmail, executeAfter, executeBefore); + emit RecoveryProcessed(account, executeAfter, executeBefore); } } @@ -413,7 +397,7 @@ contract ZkEmailRecovery is EmailAccountRecoveryNew, IZkEmailRecovery { * without having to reconfigure everything * @param account The address of the account for which the recovery is being completed */ - function completeRecovery(address account) public override { + function completeRecovery(address account, bytes memory recoveryCalldata) public override { if (account == address(0)) { revert InvalidAccountAddress(); } @@ -434,10 +418,13 @@ contract ZkEmailRecovery is EmailAccountRecoveryNew, IZkEmailRecovery { delete recoveryRequests[account]; + if (keccak256(recoveryCalldata) != recoveryRequest.calldataHash) { + revert InvalidCalldataHash(); + } address recoveryModule = recoveryConfigs[account].recoveryModule; - IRecoveryModule(recoveryModule).recover(account, recoveryRequest.recoveryCalldata); + IRecoveryModule(recoveryModule).recover(account, recoveryCalldata); emit RecoveryCompleted(account); } diff --git a/src/SafeZkEmailRecovery.sol b/src/SafeZkEmailRecovery.sol deleted file mode 100644 index e6333844..00000000 --- a/src/SafeZkEmailRecovery.sol +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; - -import { ZkEmailRecovery } from "./ZkEmailRecovery.sol"; -import { ISafe } from "./interfaces/ISafe.sol"; - -/** - * @title SafeZkEmailRecovery - * @notice Implements email based recovery for Safe accounts inheriting core logic from ZkEmailRecovery - * @dev The underlying ZkEmailRecovery contract provides some the core logic for recovering an account - */ -contract SafeZkEmailRecovery is ZkEmailRecovery { - error InvalidOldOwner(); - - constructor( - address _verifier, - address _dkimRegistry, - address _emailAuthImpl - ) - ZkEmailRecovery(_verifier, _dkimRegistry, _emailAuthImpl) - { } - - /** - * @notice Returns a two-dimensional array of strings representing the subject templates for - * email recovery. - * @dev This function is overridden from ZkEmailRecovery. It overrides the base implementation - * to provide a template specific to Safe accounts. The template includes placeholders for - * the account address, old owner, new owner, and recovery module. - * in the subject or if the email should be in a language that is not English. - * @return string[][] A two-dimensional array of strings, where each inner array represents a - * set of fixed strings and matchers for a subject template. - */ - function recoverySubjectTemplates() public pure override returns (string[][] memory) { - string[][] memory templates = new string[][](1); - templates[0] = new string[](15); - templates[0][0] = "Recover"; - templates[0][1] = "account"; - templates[0][2] = "{ethAddr}"; - templates[0][3] = "from"; - templates[0][4] = "old"; - templates[0][5] = "owner"; - templates[0][6] = "{ethAddr}"; - templates[0][7] = "to"; - templates[0][8] = "new"; - templates[0][9] = "owner"; - templates[0][10] = "{ethAddr}"; - templates[0][11] = "using"; - templates[0][12] = "recovery"; - templates[0][13] = "module"; - templates[0][14] = "{ethAddr}"; - return templates; - } - - /** - * @notice Validates the recovery subject templates and extracts the account address - * @dev This function is overridden from ZkEmailRecovery. It is re-implemented by - * this contract to support a different subject template for recovering Safe accounts. - * This function reverts if the subject parameters are invalid. The function - * should extract and return the account address as that is required by - * the core recovery logic. - * @param templateIdx The index of the template used for the recovery request - * @param subjectParams An array of bytes containing the subject parameters - * @return accountInEmail The extracted account address from the subject parameters - */ - function validateRecoverySubjectTemplates( - uint256 templateIdx, - bytes[] memory subjectParams - ) - internal - view - override - returns (address) - { - if (templateIdx != 0) { - revert InvalidTemplateIndex(); - } - - if (subjectParams.length != 4) { - revert InvalidSubjectParams(); - } - - address accountInEmail = abi.decode(subjectParams[0], (address)); - address oldOwnerInEmail = abi.decode(subjectParams[1], (address)); - address newOwnerInEmail = abi.decode(subjectParams[2], (address)); - address recoveryModuleInEmail = abi.decode(subjectParams[3], (address)); - - bool isOwner = ISafe(accountInEmail).isOwner(oldOwnerInEmail); - if (!isOwner) { - revert InvalidOldOwner(); - } - if (newOwnerInEmail == address(0)) { - revert InvalidNewOwner(); - } - if (recoveryModuleInEmail == address(0)) { - revert InvalidRecoveryModule(); - } - - return accountInEmail; - } -} diff --git a/src/EmailAccountRecoveryNew.sol b/src/experimental/EmailAccountRecoveryNew.sol similarity index 90% rename from src/EmailAccountRecoveryNew.sol rename to src/experimental/EmailAccountRecoveryNew.sol index f30988a1..ed85031e 100644 --- a/src/EmailAccountRecoveryNew.sol +++ b/src/experimental/EmailAccountRecoveryNew.sol @@ -11,14 +11,11 @@ import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy /// @dev This contract is abstract and requires implementation of several methods for configuring a /// new guardian and recovering a wallet. abstract contract EmailAccountRecoveryNew { - uint8 constant EMAIL_ACCOUNT_RECOVERY_VERSION_ID = 2; + uint8 constant EMAIL_ACCOUNT_RECOVERY_VERSION_ID = 1; address public verifierAddr; address public dkimAddr; address public emailAuthImplementationAddr; - mapping(address account => string[][]) public acceptanceSubjectTemplates; - mapping(address account => string[][]) public recoverySubjectTemplates; - /// @notice Returns the address of the verifier contract. /// @dev This function is virtual and can be overridden by inheriting contracts. /// @return address The address of the verifier contract. @@ -46,11 +43,7 @@ abstract contract EmailAccountRecoveryNew { /// specific acceptance subject templates. /// @return string[][] A two-dimensional array of strings, where each inner array represents a /// set of fixed strings and matchers for a subject template. - function getAcceptanceSubjectTemplates(address account) - public - view - virtual - returns (string[][] memory); + function acceptanceSubjectTemplates() public view virtual returns (string[][] memory); /// @notice Returns a two-dimensional array of strings representing the subject templates for /// email recovery. @@ -58,11 +51,7 @@ abstract contract EmailAccountRecoveryNew { /// specific recovery subject templates. /// @return string[][] A two-dimensional array of strings, where each inner array represents a /// set of fixed strings and matchers for a subject template. - function getRecoverySubjectTemplates(address account) - public - view - virtual - returns (string[][] memory); + function recoverySubjectTemplates() public view virtual returns (string[][] memory); function acceptGuardian( address guardian, @@ -85,7 +74,7 @@ abstract contract EmailAccountRecoveryNew { /// @notice Completes the recovery process. /// @dev This function must be implemented by inheriting contracts to finalize the recovery /// process. - function completeRecovery(address account) external virtual; + function completeRecovery(address account, bytes calldata recoveryCalldata) external virtual; /// @notice Computes the address for email auth contract using the CREATE2 opcode. /// @dev This function utilizes the `Create2` library to compute the address. The computation @@ -141,13 +130,7 @@ abstract contract EmailAccountRecoveryNew { /// @param emailAuthMsg The email auth message for the email send from the guardian. /// @param templateIdx The index of the subject template for acceptance, which should match with /// the subject in the given email auth message. - function handleAcceptance( - address account, - EmailAuthMsg memory emailAuthMsg, - uint256 templateIdx - ) - external - { + function handleAcceptance(EmailAuthMsg memory emailAuthMsg, uint256 templateIdx) external { address guardian = computeEmailAuthAddress(emailAuthMsg.proof.accountSalt); uint256 templateId = computeAcceptanceTemplateId(templateIdx); require(templateId == emailAuthMsg.templateId, "invalid template id"); @@ -170,14 +153,14 @@ abstract contract EmailAccountRecoveryNew { guardianEmailAuth.updateDKIMRegistry(dkim()); guardianEmailAuth.updateVerifier(verifier()); - for (uint256 idx = 0; idx < acceptanceSubjectTemplates[account].length; idx++) { + for (uint256 idx = 0; idx < acceptanceSubjectTemplates().length; idx++) { guardianEmailAuth.insertSubjectTemplate( - computeAcceptanceTemplateId(idx), acceptanceSubjectTemplates[account][idx] + computeAcceptanceTemplateId(idx), acceptanceSubjectTemplates()[idx] ); } - for (uint256 idx = 0; idx < recoverySubjectTemplates[account].length; idx++) { + for (uint256 idx = 0; idx < recoverySubjectTemplates().length; idx++) { guardianEmailAuth.insertSubjectTemplate( - computeRecoveryTemplateId(idx), recoverySubjectTemplates[account][idx] + computeRecoveryTemplateId(idx), recoverySubjectTemplates()[idx] ); } diff --git a/src/handlers/EmailRecoverySubjectHandler.sol b/src/handlers/EmailRecoverySubjectHandler.sol new file mode 100644 index 00000000..34f0303e --- /dev/null +++ b/src/handlers/EmailRecoverySubjectHandler.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import { IEmailRecoverySubjectHandler } from "../interfaces/IEmailRecoverySubjectHandler.sol"; +import { IEmailRecoveryManager } from "../interfaces/IEmailRecoveryManager.sol"; +import { HexStrings } from "../libraries/HexStrings.sol"; + +/** + * Handler contract that defines subject templates and how to validate them + * This is the default subject handler that will work with any validator. + */ +contract EmailRecoverySubjectHandler is IEmailRecoverySubjectHandler { + using HexStrings for string; + + error InvalidTemplateIndex(); + error InvalidSubjectParams(); + error InvalidAccount(); + error InvalidRecoveryModule(); + + constructor() { } + + function acceptanceSubjectTemplates() public pure returns (string[][] memory) { + string[][] memory templates = new string[][](1); + templates[0] = new string[](5); + templates[0][0] = "Accept"; + templates[0][1] = "guardian"; + templates[0][2] = "request"; + templates[0][3] = "for"; + templates[0][4] = "{ethAddr}"; + return templates; + } + + function recoverySubjectTemplates() public pure returns (string[][] memory) { + string[][] memory templates = new string[][](1); + templates[0] = new string[](11); + templates[0][0] = "Recover"; + templates[0][1] = "account"; + templates[0][2] = "{ethAddr}"; + templates[0][3] = "via"; + templates[0][4] = "recovery"; + templates[0][5] = "module"; + templates[0][6] = "{ethAddr}"; + templates[0][7] = "using"; + templates[0][8] = "recovery"; + templates[0][9] = "hash"; + templates[0][10] = "{string}"; + return templates; + } + + function validateAcceptanceSubject( + uint256 templateIdx, + bytes[] memory subjectParams + ) + external + view + returns (address) + { + if (templateIdx != 0) { + revert InvalidTemplateIndex(); + } + + if (subjectParams.length != 1) revert InvalidSubjectParams(); + + // The GuardianStatus check in acceptGuardian implicitly + // validates the account, so no need to re-validate here + address accountInEmail = abi.decode(subjectParams[0], (address)); + + return accountInEmail; + } + + function validateRecoverySubject( + uint256 templateIdx, + bytes[] memory subjectParams, + address recoveryManager + ) + public + view + returns (address, bytes32) + { + if (templateIdx != 0) { + revert InvalidTemplateIndex(); + } + + if (subjectParams.length != 3) { + revert InvalidSubjectParams(); + } + + address accountInEmail = abi.decode(subjectParams[0], (address)); + address recoveryModuleInEmail = abi.decode(subjectParams[1], (address)); + string memory calldataHashInEmail = abi.decode(subjectParams[2], (string)); + + if (accountInEmail == address(0)) { + revert InvalidAccount(); + } + + // Even though someone could use a malicious contract as the recoveryManager argument, it + // does not matter in this case as this is only used as part of recovery in the recovery + // manager. + address expectedRecoveryModule = + IEmailRecoveryManager(recoveryManager).getRecoveryConfig(accountInEmail).recoveryModule; + if (recoveryModuleInEmail == address(0) || recoveryModuleInEmail != expectedRecoveryModule) + { + revert InvalidRecoveryModule(); + } + + bytes32 calldataHash = calldataHashInEmail.fromHexStringtoBytes32(); + + return (accountInEmail, calldataHash); + } +} diff --git a/src/handlers/SafeRecoverySubjectHandler.sol b/src/handlers/SafeRecoverySubjectHandler.sol new file mode 100644 index 00000000..4a06fcb2 --- /dev/null +++ b/src/handlers/SafeRecoverySubjectHandler.sol @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import { IEmailRecoverySubjectHandler } from "../interfaces/IEmailRecoverySubjectHandler.sol"; +import { IEmailRecoveryManager } from "../interfaces/IEmailRecoveryManager.sol"; +import { ISafe } from "../interfaces/ISafe.sol"; + +/** + * Handler contract that defines subject templates and how to validate them + * This is a custom subject handler that will work with Safes and defines custom validation. + */ +contract SafeRecoverySubjectHandler is IEmailRecoverySubjectHandler { + error InvalidTemplateIndex(); + error InvalidSubjectParams(); + error InvalidOldOwner(); + error InvalidNewOwner(); + error InvalidRecoveryModule(); + + constructor() { } + + function acceptanceSubjectTemplates() public pure returns (string[][] memory) { + string[][] memory templates = new string[][](1); + templates[0] = new string[](5); + templates[0][0] = "Accept"; + templates[0][1] = "guardian"; + templates[0][2] = "request"; + templates[0][3] = "for"; + templates[0][4] = "{ethAddr}"; + return templates; + } + + function recoverySubjectTemplates() public pure returns (string[][] memory) { + string[][] memory templates = new string[][](1); + templates[0] = new string[](15); + templates[0][0] = "Recover"; + templates[0][1] = "account"; + templates[0][2] = "{ethAddr}"; + templates[0][3] = "from"; + templates[0][4] = "old"; + templates[0][5] = "owner"; + templates[0][6] = "{ethAddr}"; + templates[0][7] = "to"; + templates[0][8] = "new"; + templates[0][9] = "owner"; + templates[0][10] = "{ethAddr}"; + templates[0][11] = "using"; + templates[0][12] = "recovery"; + templates[0][13] = "module"; + templates[0][14] = "{ethAddr}"; + return templates; + } + + function validateAcceptanceSubject( + uint256 templateIdx, + bytes[] memory subjectParams + ) + external + view + returns (address) + { + if (templateIdx != 0) { + revert InvalidTemplateIndex(); + } + + if (subjectParams.length != 1) revert InvalidSubjectParams(); + + // The GuardianStatus check in acceptGuardian implicitly + // validates the account, so no need to re-validate here + address accountInEmail = abi.decode(subjectParams[0], (address)); + + return accountInEmail; + } + + function validateRecoverySubject( + uint256 templateIdx, + bytes[] memory subjectParams, + address recoveryManager + ) + public + view + returns (address, bytes32) + { + if (templateIdx != 0) { + revert InvalidTemplateIndex(); + } + + if (subjectParams.length != 4) { + revert InvalidSubjectParams(); + } + + address accountInEmail = abi.decode(subjectParams[0], (address)); + address oldOwnerInEmail = abi.decode(subjectParams[1], (address)); + address newOwnerInEmail = abi.decode(subjectParams[2], (address)); + address recoveryModuleInEmail = abi.decode(subjectParams[3], (address)); + + bool isOwner = ISafe(accountInEmail).isOwner(oldOwnerInEmail); + if (!isOwner) { + revert InvalidOldOwner(); + } + + if (newOwnerInEmail == address(0)) { + revert InvalidNewOwner(); + } + + // Even though someone could use a malicious contract as the recoveryManager argument, it + // does not matter in this case as this + address expectedRecoveryModule = + IEmailRecoveryManager(recoveryManager).getRecoveryConfig(accountInEmail).recoveryModule; + if (recoveryModuleInEmail == address(0) || recoveryModuleInEmail != expectedRecoveryModule) + { + revert InvalidRecoveryModule(); + } + + address previousOwnerInLinkedList = + getPreviousOwnerInLinkedList(accountInEmail, oldOwnerInEmail); + string memory functionSignature = "swapOwner(address,address,address)"; + bytes memory recoveryCallData = abi.encodeWithSignature( + functionSignature, previousOwnerInLinkedList, oldOwnerInEmail, newOwnerInEmail + ); + bytes32 calldataHash = keccak256(recoveryCallData); + + return (accountInEmail, calldataHash); + } + + function getPreviousOwnerInLinkedList( + address safe, + address oldOwner + ) + internal + view + returns (address) + { + address[] memory owners = ISafe(safe).getOwners(); + uint256 length = owners.length; + + uint256 oldOwnerIndex; + for (uint256 i; i < length; i++) { + if (owners[i] == oldOwner) { + oldOwnerIndex = i; + break; + } + } + address sentinelOwner = address(0x1); + return oldOwnerIndex == 0 ? sentinelOwner : owners[oldOwnerIndex - 1]; + } +} diff --git a/src/interfaces/IZkEmailRecovery.sol b/src/interfaces/IEmailRecoveryManager.sol similarity index 96% rename from src/interfaces/IZkEmailRecovery.sol rename to src/interfaces/IEmailRecoveryManager.sol index bdd362fb..27d93e0f 100644 --- a/src/interfaces/IZkEmailRecovery.sol +++ b/src/interfaces/IEmailRecoveryManager.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.25; import { GuardianStorage, GuardianStatus } from "../libraries/EnumerableGuardianMap.sol"; -interface IZkEmailRecovery { +interface IEmailRecoveryManager { /*////////////////////////////////////////////////////////////////////////// TYPE DELARATIONS //////////////////////////////////////////////////////////////////////////*/ @@ -33,7 +33,8 @@ interface IZkEmailRecovery { uint256 executeAfter; // the timestamp from which the recovery request can be executed uint256 executeBefore; // the timestamp from which the recovery request becomes invalid uint256 currentWeight; // total weight of all guardian approvals for the recovery request - bytes recoveryCalldata; // the calldata used to execute the recovery attempt + bytes32 calldataHash; // the keccak256 hash of the calldata used to execute the recovery + // attempt } /** @@ -124,9 +125,7 @@ interface IZkEmailRecovery { uint256[] memory weights, uint256 threshold, uint256 delay, - uint256 expiry, - string[][] memory acceptanceSubjectTemplate, - string[][] memory recoverySubjectTemplate + uint256 expiry ) external; diff --git a/src/interfaces/IEmailRecoverySubjectHandler.sol b/src/interfaces/IEmailRecoverySubjectHandler.sol new file mode 100644 index 00000000..70a38f79 --- /dev/null +++ b/src/interfaces/IEmailRecoverySubjectHandler.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +interface IEmailRecoverySubjectHandler { + function acceptanceSubjectTemplates() external pure returns (string[][] memory); + function recoverySubjectTemplates() external pure returns (string[][] memory); + + function validateAcceptanceSubject( + uint256 templateIdx, + bytes[] memory subjectParams + ) + external + view + returns (address); + + function validateRecoverySubject( + uint256 templateIdx, + bytes[] memory subjectParams, + address recoveryManager + ) + external + view + returns (address, bytes32); +} diff --git a/src/interfaces/IRecoveryModule.sol b/src/interfaces/IRecoveryModule.sol index ec55497e..ba65996a 100644 --- a/src/interfaces/IRecoveryModule.sol +++ b/src/interfaces/IRecoveryModule.sol @@ -3,5 +3,5 @@ pragma solidity ^0.8.25; interface IRecoveryModule { function recover(address account, bytes memory recoveryCalldata) external; - function getTrustedContract() external returns (address); + function getTrustedRecoveryManager() external returns (address); } diff --git a/src/libraries/BytesLib.sol b/src/libraries/BytesLib.sol new file mode 100644 index 00000000..1cd66b10 --- /dev/null +++ b/src/libraries/BytesLib.sol @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +library BytesLib { + function slice( + bytes memory _bytes, + uint256 _start, + uint256 _length + ) + internal + pure + returns (bytes memory) + { + require(_length + 31 >= _length, "slice_overflow"); + require(_bytes.length >= _start + _length, "slice_outOfBounds"); + + bytes memory tempBytes; + + assembly { + switch iszero(_length) + case 0 { + // Get a location of some free memory and store it in tempBytes as + // Solidity does for memory variables. + tempBytes := mload(0x40) + + // The first word of the slice result is potentially a partial + // word read from the original array. To read it, we calculate + // the length of that partial word and start copying that many + // bytes into the array. The first word we copy will start with + // data we don't care about, but the last `lengthmod` bytes will + // land at the beginning of the contents of the new array. When + // we're done copying, we overwrite the full first word with + // the actual length of the slice. + let lengthmod := and(_length, 31) + + // The multiplication in the next line is necessary + // because when slicing multiples of 32 bytes (lengthmod == 0) + // the following copy loop was copying the origin's length + // and then ending prematurely not copying everything it should. + let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) + let end := add(mc, _length) + + for { + // The multiplication in the next line has the same exact purpose + // as the one above. + let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) + } lt(mc, end) { + mc := add(mc, 0x20) + cc := add(cc, 0x20) + } { mstore(mc, mload(cc)) } + + mstore(tempBytes, _length) + + //update free-memory pointer + //allocating the array padded to 32 bytes like the compiler does now + mstore(0x40, and(add(mc, 31), not(31))) + } + //if we want a zero-length slice let's just return a zero-length array + default { + tempBytes := mload(0x40) + //zero out the 32 bytes slice we are about to return + //we need to do it because Solidity does not garbage collect + mstore(tempBytes, 0) + + mstore(0x40, add(tempBytes, 0x20)) + } + } + + return tempBytes; + } +} diff --git a/src/libraries/HexStrings.sol b/src/libraries/HexStrings.sol index bea100d8..c529dbe3 100644 --- a/src/libraries/HexStrings.sol +++ b/src/libraries/HexStrings.sol @@ -1,27 +1,32 @@ -// Generated with the help of chat gpt - needed a quick solution to convert string to bytes32 +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + library HexStrings { - function fromHexString(string memory s) internal pure returns (bytes32 result) { + function fromHexStringtoBytes32(string memory s) internal pure returns (bytes32 result) { bytes memory b = bytes(s); require(b.length == 66, "Invalid hex string length"); - require(b[0] == '0' && b[1] == 'x', "Invalid hex prefix"); + require(b[0] == "0" && b[1] == "x", "Invalid hex prefix"); for (uint256 i = 0; i < 32; i++) { result |= bytes32( - (uint256(uint8(fromHexChar(uint8(b[2 + i * 2]))) << 4) | uint256(uint8(fromHexChar(uint8(b[3 + i * 2]))))) + ( + uint256(uint8(fromHexChar(uint8(b[2 + i * 2]))) << 4) + | uint256(uint8(fromHexChar(uint8(b[3 + i * 2])))) + ) ) << (31 - i) * 8; } } function fromHexChar(uint8 c) internal pure returns (uint8) { - if (bytes1(c) >= bytes1('0') && bytes1(c) <= bytes1('9')) { - return c - uint8(bytes1('0')); + if (bytes1(c) >= bytes1("0") && bytes1(c) <= bytes1("9")) { + return c - uint8(bytes1("0")); } - if (bytes1(c) >= bytes1('a') && bytes1(c) <= bytes1('f')) { - return 10 + c - uint8(bytes1('a')); + if (bytes1(c) >= bytes1("a") && bytes1(c) <= bytes1("f")) { + return 10 + c - uint8(bytes1("a")); } - if (bytes1(c) >= bytes1('A') && bytes1(c) <= bytes1('F')) { - return 10 + c - uint8(bytes1('A')); + if (bytes1(c) >= bytes1("A") && bytes1(c) <= bytes1("F")) { + return 10 + c - uint8(bytes1("A")); } revert("Invalid hex character"); } -} \ No newline at end of file +} diff --git a/src/libraries/SubjectCalldataBuilder.sol b/src/libraries/SubjectCalldataBuilder.sol deleted file mode 100644 index e64948ef..00000000 --- a/src/libraries/SubjectCalldataBuilder.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; - -library SubjectCalldataBuilder { - - // subjectParams MUST be abi.encoded otherwise calldata contruction will fail. This is particulary important for dynamic types which have their length encoded - function buildSubjectCalldata(bytes[] memory subjectParams) internal returns (bytes memory) { - // TODO: store this dynamically - bytes4 functionSelector = bytes4(keccak256(bytes("changeOwner(address,address,address)"))); - - if (subjectParamsLength == 1) { - return abi.encodePacked(functionSelector, subjectParams[0]); - } - - if (subjectParamsLength == 2) { - return abi.encodePacked(functionSelector, subjectParams[0], subjectParams[1]); - } - - if (subjectParamsLength == 3) { - return abi.encodePacked(functionSelector, subjectParams[0], subjectParams[1], subjectParams[2]); - } - - if (subjectParamsLength == 4) { - return abi.encodePacked(functionSelector, subjectParams[0], subjectParams[1], subjectParams[2], subjectParams[3]); - } - - revert("TODO: implement more"); - } -} \ No newline at end of file diff --git a/src/modules/ValidatorEmailRecoveryModule.sol b/src/modules/EmailRecoveryModule.sol similarity index 68% rename from src/modules/ValidatorEmailRecoveryModule.sol rename to src/modules/EmailRecoveryModule.sol index b5e893b6..905ce423 100644 --- a/src/modules/ValidatorEmailRecoveryModule.sol +++ b/src/modules/EmailRecoveryModule.sol @@ -8,31 +8,31 @@ import { ExecutionLib } from "erc7579/lib/ExecutionLib.sol"; import { ModeLib } from "erc7579/lib/ModeLib.sol"; import { IRecoveryModule } from "../interfaces/IRecoveryModule.sol"; -import { IZkEmailRecovery } from "../interfaces/IZkEmailRecovery.sol"; +import { IEmailRecoveryManager } from "../interfaces/IEmailRecoveryManager.sol"; import { ISafe } from "../interfaces/ISafe.sol"; +import { BytesLib } from "../libraries/BytesLib.sol"; -contract ValidatorEmailRecoveryModule is ERC7579ExecutorBase, IRecoveryModule { +contract EmailRecoveryModule is ERC7579ExecutorBase, IRecoveryModule { + using BytesLib for bytes; /*////////////////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////////////////*/ - address public immutable zkEmailRecovery; + address public immutable emailRecoveryManager; event NewValidatorRecovery(address indexed validatorModule, bytes4 recoverySelector); - error NotTrustedRecoveryContract(); + error NotTrustedRecoveryManager(); error InvalidSubjectParams(); error InvalidValidator(address validator); error InvalidSelector(bytes4 selector); - mapping(address account => address validator) public validators; mapping(address validatorModule => mapping(address account => bytes4 allowedSelector)) internal - $allowedSelector; - - // mapping(=>) internal validator; + allowedSelectors; + mapping(address account => address validator) internal validators; constructor(address _zkEmailRecovery) { - zkEmailRecovery = _zkEmailRecovery; + emailRecoveryManager = _zkEmailRecovery; } modifier withoutUnsafeSelector(bytes4 recoverySelector) { @@ -62,42 +62,18 @@ contract ValidatorEmailRecoveryModule is ERC7579ExecutorBase, IRecoveryModule { uint256[] memory weights, uint256 threshold, uint256 delay, - uint256 expiry, - string[][] memory acceptanceSubjectTemplate, - string[][] memory recoverySubjectTemplate - ) = abi.decode( - data, - ( - address, - bytes4, - address[], - uint256[], - uint256, - uint256, - uint256, - string[][], - string[][] - ) - ); + uint256 expiry + ) = abi.decode(data, (address, bytes4, address[], uint256[], uint256, uint256, uint256)); allowValidatorRecovery(validator, bytes("0"), selector); validators[msg.sender] = validator; _execute({ - to: zkEmailRecovery, + to: emailRecoveryManager, value: 0, data: abi.encodeCall( - IZkEmailRecovery.configureRecovery, - ( - address(this), - guardians, - weights, - threshold, - delay, - expiry, - acceptanceSubjectTemplate, - recoverySubjectTemplate - ) + IEmailRecoveryManager.configureRecovery, + (address(this), guardians, weights, threshold, delay, expiry) ) }); } @@ -117,7 +93,8 @@ contract ValidatorEmailRecoveryModule is ERC7579ExecutorBase, IRecoveryModule { ) { revert InvalidValidator(validator); } - $allowedSelector[validator][msg.sender] = recoverySelector; + + allowedSelectors[validator][msg.sender] = recoverySelector; emit NewValidatorRecovery({ validatorModule: validator, recoverySelector: recoverySelector }); } @@ -127,7 +104,10 @@ contract ValidatorEmailRecoveryModule is ERC7579ExecutorBase, IRecoveryModule { * @custom:unusedparam data - the data to de-initialize the module with */ function onUninstall(bytes calldata /* data */ ) external { - IZkEmailRecovery(zkEmailRecovery).deInitRecoveryFromModule(msg.sender); + address validator = validators[msg.sender]; + delete allowedSelectors[validator][msg.sender]; + delete validators[msg.sender]; + IEmailRecoveryManager(emailRecoveryManager).deInitRecoveryFromModule(msg.sender); } /** @@ -136,7 +116,8 @@ contract ValidatorEmailRecoveryModule is ERC7579ExecutorBase, IRecoveryModule { * @return true if the module is initialized, false otherwise */ function isInitialized(address smartAccount) external view returns (bool) { - return IZkEmailRecovery(zkEmailRecovery).getGuardianConfig(smartAccount).threshold != 0; + return IEmailRecoveryManager(emailRecoveryManager).getGuardianConfig(smartAccount).threshold + != 0; } /*////////////////////////////////////////////////////////////////////////// @@ -144,22 +125,23 @@ contract ValidatorEmailRecoveryModule is ERC7579ExecutorBase, IRecoveryModule { //////////////////////////////////////////////////////////////////////////*/ function recover(address account, bytes memory recoveryCalldata) external { - if (msg.sender != zkEmailRecovery) { - revert NotTrustedRecoveryContract(); + if (msg.sender != emailRecoveryManager) { + revert NotTrustedRecoveryManager(); } - // TODO: check selector - // bytes4 selector = bytes4(recoveryCalldata.slice({ _start: 0, _length: 4 })); - // bytes4 selector = bytes4(0); - // if ($allowedSelector[validator][account] != selector) { - // revert InvalidSelector(selector); - // } + bytes4 selector = bytes4(recoveryCalldata.slice({ _start: 0, _length: 4 })); + + address validator = validators[account]; + bytes4 allowedSelector = allowedSelectors[validator][account]; + if (allowedSelector != selector) { + revert InvalidSelector(selector); + } _execute({ account: account, to: validators[account], value: 0, data: recoveryCalldata }); } - function getTrustedContract() external view returns (address) { - return zkEmailRecovery; + function getTrustedRecoveryManager() external view returns (address) { + return emailRecoveryManager; } /*////////////////////////////////////////////////////////////////////////// @@ -171,7 +153,7 @@ contract ValidatorEmailRecoveryModule is ERC7579ExecutorBase, IRecoveryModule { * @return name The name of the module */ function name() external pure returns (string memory) { - return "ValidatorEmailRecoveryModule"; + return "EmailRecoveryModule"; } /** diff --git a/src/modules/OwnableValidatorRecoveryModule.sol b/src/modules/OwnableValidatorRecoveryModule.sol deleted file mode 100644 index afe943ba..00000000 --- a/src/modules/OwnableValidatorRecoveryModule.sol +++ /dev/null @@ -1,128 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; - -import { ERC7579ExecutorBase } from "@rhinestone/modulekit/src/Modules.sol"; - -import { IRecoveryModule } from "../interfaces/IRecoveryModule.sol"; -import { IZkEmailRecovery } from "../interfaces/IZkEmailRecovery.sol"; - -contract OwnableValidatorRecoveryModule is ERC7579ExecutorBase, IRecoveryModule { - /*////////////////////////////////////////////////////////////////////////// - CONSTANTS - //////////////////////////////////////////////////////////////////////////*/ - - address public immutable ZK_EMAIL_RECOVERY; - - mapping(address account => address validator) public validators; - - error InvalidNewOwner(); - error NotTrustedRecoveryContract(); - - constructor(address _zkEmailRecovery) { - ZK_EMAIL_RECOVERY = _zkEmailRecovery; - } - - /*////////////////////////////////////////////////////////////////////////// - CONFIG - //////////////////////////////////////////////////////////////////////////*/ - - /** - * Initialize the module with the given data - * @param data The data to initialize the module with - */ - function onInstall(bytes calldata data) external { - ( - address validator, - address[] memory guardians, - uint256[] memory weights, - uint256 threshold, - uint256 delay, - uint256 expiry - ) = abi.decode(data, (address, address[], uint256[], uint256, uint256, uint256)); - - validators[msg.sender] = validator; - - bytes memory encodedCall = abi.encodeWithSignature( - "configureRecovery(address,address[],uint256[],uint256,uint256,uint256)", - address(this), - guardians, - weights, - threshold, - delay, - expiry - ); - - _execute(msg.sender, ZK_EMAIL_RECOVERY, 0, encodedCall); - } - - /** - * De-initialize the module with the given data - * @custom:unusedparam data - the data to de-initialize the module with - */ - function onUninstall(bytes calldata /* data */ ) external { - delete validators[msg.sender]; - IZkEmailRecovery(ZK_EMAIL_RECOVERY).deInitRecoveryFromModule(msg.sender); - } - - /** - * Check if the module is initialized - * @param smartAccount The smart account to check - * @return true if the module is initialized, false otherwise - */ - function isInitialized(address smartAccount) external view returns (bool) { - return validators[smartAccount] != address(0); - } - - /*////////////////////////////////////////////////////////////////////////// - MODULE LOGIC - //////////////////////////////////////////////////////////////////////////*/ - - function recover(address account, bytes[] memory subjectParams) external { - if (msg.sender != ZK_EMAIL_RECOVERY) { - revert NotTrustedRecoveryContract(); - } - - address newOwner = abi.decode(subjectParams[1], (address)); - if (newOwner == address(0)) { - revert InvalidNewOwner(); - } - bytes memory encodedCall = abi.encodeWithSignature( - "changeOwner(address,address,address)", account, address(this), newOwner - ); - - _execute(account, validators[account], 0, encodedCall); - } - - function getTrustedContract() external view returns (address) { - return ZK_EMAIL_RECOVERY; - } - - /*////////////////////////////////////////////////////////////////////////// - METADATA - //////////////////////////////////////////////////////////////////////////*/ - - /** - * The name of the module - * @return name The name of the module - */ - function name() external pure returns (string memory) { - return "OwnableValidatorRecoveryModule"; - } - - /** - * The version of the module - * @return version The version of the module - */ - function version() external pure returns (string memory) { - return "0.0.1"; - } - - /** - * Check if the module is of a certain type - * @param typeID The type ID to check - * @return true if the module is of the given type, false otherwise - */ - function isModuleType(uint256 typeID) external pure returns (bool) { - return typeID == TYPE_EXECUTOR; - } -} diff --git a/src/modules/SafeRecoveryModule.sol b/src/modules/SafeRecoveryModule.sol deleted file mode 100644 index 967b3be8..00000000 --- a/src/modules/SafeRecoveryModule.sol +++ /dev/null @@ -1,164 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; - -import { ERC7579ExecutorBase } from "modulekit/Modules.sol"; - -import { IRecoveryModule } from "../interfaces/IRecoveryModule.sol"; -import { IZkEmailRecovery } from "../interfaces/IZkEmailRecovery.sol"; -import { ISafe } from "../interfaces/ISafe.sol"; - -contract SafeRecoveryModule is ERC7579ExecutorBase, IRecoveryModule { - /*////////////////////////////////////////////////////////////////////////// - CONSTANTS - //////////////////////////////////////////////////////////////////////////*/ - - address public immutable ZK_EMAIL_RECOVERY; - - error NotTrustedRecoveryContract(); - error InvalidSubjectParams(); - error InvalidOldOwner(); - error InvalidNewOwner(); - - constructor(address _zkEmailRecovery) { - ZK_EMAIL_RECOVERY = _zkEmailRecovery; - } - - /*////////////////////////////////////////////////////////////////////////// - CONFIG - //////////////////////////////////////////////////////////////////////////*/ - - /** - * Initialize the module with the given data - * @param data The data to initialize the module with - */ - function onInstall(bytes calldata data) external { - ( - address[] memory guardians, - uint256[] memory weights, - uint256 threshold, - uint256 delay, - uint256 expiry - ) = abi.decode(data, (address[], uint256[], uint256, uint256, uint256)); - - _execute({ - to: ZK_EMAIL_RECOVERY, - value: 0, - data: abi.encodeCall( - IZkEmailRecovery.configureRecovery, - (address(this), guardians, weights, threshold, delay, expiry) - ) - }); - } - - /** - * De-initialize the module with the given data - * @custom:unusedparam data - the data to de-initialize the module with - */ - function onUninstall(bytes calldata /* data */ ) external { - IZkEmailRecovery(ZK_EMAIL_RECOVERY).deInitRecoveryFromModule(msg.sender); - } - - /** - * Check if the module is initialized - * @param smartAccount The smart account to check - * @return true if the module is initialized, false otherwise - */ - function isInitialized(address smartAccount) external view returns (bool) { - return IZkEmailRecovery(ZK_EMAIL_RECOVERY).getGuardianConfig(smartAccount).threshold != 0; - } - - /*////////////////////////////////////////////////////////////////////////// - MODULE LOGIC - //////////////////////////////////////////////////////////////////////////*/ - - function recover(address account, bytes[] memory subjectParams) external { - if (msg.sender != ZK_EMAIL_RECOVERY) { - revert NotTrustedRecoveryContract(); - } - - // prevent out of bounds error message, in case subject params are invalid - if (subjectParams.length < 3) { - revert InvalidSubjectParams(); - } - - address oldOwner = abi.decode(subjectParams[1], (address)); - address newOwner = abi.decode(subjectParams[2], (address)); - bool isOwner = ISafe(account).isOwner(oldOwner); - if (!isOwner) { - revert InvalidOldOwner(); - } - if (newOwner == address(0)) { - revert InvalidNewOwner(); - } - - address previousOwnerInLinkedList = getPreviousOwnerInLinkedList(account, oldOwner); - _execute({ - account: account, - to: account, - value: 0, - data: abi.encodeCall(ISafe.swapOwner, (previousOwnerInLinkedList, oldOwner, newOwner)) - }); - } - - /** - * @notice Helper function that retrieves the owner that points to the owner to be - * replaced in the Safe `owners` linked list. Based on the logic used to swap - * owners in the safe core sdk. - * @param safe the safe account to query - * @param oldOwner the old owner to be swapped in the recovery attempt. - */ - function getPreviousOwnerInLinkedList( - address safe, - address oldOwner - ) - internal - view - returns (address) - { - address[] memory owners = ISafe(safe).getOwners(); - uint256 length = owners.length; - - uint256 oldOwnerIndex; - for (uint256 i; i < length; i++) { - if (owners[i] == oldOwner) { - oldOwnerIndex = i; - break; - } - } - address sentinelOwner = address(0x1); - return oldOwnerIndex == 0 ? sentinelOwner : owners[oldOwnerIndex - 1]; - } - - function getTrustedContract() external view returns (address) { - return ZK_EMAIL_RECOVERY; - } - - /*////////////////////////////////////////////////////////////////////////// - METADATA - //////////////////////////////////////////////////////////////////////////*/ - - /** - * The name of the module - * @return name The name of the module - */ - function name() external pure returns (string memory) { - return "SafeRecoveryModule"; - } - - /** - * The version of the module - * @return version The version of the module - */ - function version() external pure returns (string memory) { - return "0.0.1"; - } - - /** - * Check if the module is of a certain type - * @param typeID The type ID to check - * @return true if the module is of the given type, false otherwise - */ - function isModuleType(uint256 typeID) external pure returns (bool) { - return typeID == TYPE_EXECUTOR; - } -} diff --git a/test/integration/OwnableValidatorRecovery/OwnableValidatorBase.t.sol b/test/integration/OwnableValidatorRecovery/OwnableValidatorBase.t.sol deleted file mode 100644 index b17b8aec..00000000 --- a/test/integration/OwnableValidatorRecovery/OwnableValidatorBase.t.sol +++ /dev/null @@ -1,115 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; - -import "forge-std/console2.sol"; - -import { EmailAuthMsg, EmailProof } from "ether-email-auth/packages/contracts/src/EmailAuth.sol"; - -import { ZkEmailRecovery } from "src/ZkEmailRecovery.sol"; -import { IEmailAccountRecovery } from "src/interfaces/IEmailAccountRecovery.sol"; -import { IntegrationBase } from "../IntegrationBase.t.sol"; - -abstract contract OwnableValidatorBase is IntegrationBase { - ZkEmailRecovery zkEmailRecovery; - - function setUp() public virtual override { - super.setUp(); - - // Deploy ZkEmailRecovery - zkEmailRecovery = new ZkEmailRecovery( - address(verifier), address(ecdsaOwnedDkimRegistry), address(emailAuthImpl) - ); - - // Compute guardian addresses - guardian1 = zkEmailRecovery.computeEmailAuthAddress(accountSalt1); - guardian2 = zkEmailRecovery.computeEmailAuthAddress(accountSalt2); - guardian3 = zkEmailRecovery.computeEmailAuthAddress(accountSalt3); - - guardians = new address[](3); - guardians[0] = guardian1; - guardians[1] = guardian2; - guardians[2] = guardian3; - } - - // Helper functions - - function generateMockEmailProof( - string memory subject, - bytes32 nullifier, - bytes32 accountSalt - ) - public - view - returns (EmailProof memory) - { - EmailProof memory emailProof; - emailProof.domainName = "gmail.com"; - emailProof.publicKeyHash = bytes32( - vm.parseUint( - "6632353713085157925504008443078919716322386156160602218536961028046468237192" - ) - ); - emailProof.timestamp = block.timestamp; - emailProof.maskedSubject = subject; - emailProof.emailNullifier = nullifier; - emailProof.accountSalt = accountSalt; - emailProof.isCodeExist = true; - emailProof.proof = bytes("0"); - - return emailProof; - } - - function acceptGuardian(bytes32 accountSalt) public { - // Uncomment if getting "invalid subject" errors. Sometimes the subject needs updating after - // certain changes - // console2.log("accountAddress: ", accountAddress); - - string memory subject = - "Accept guardian request for 0x19F55F3fE4c8915F21cc92852CD8E924998fDa38"; - address router = zkEmailRecovery.getRouterForAccount(accountAddress); - bytes32 nullifier = keccak256(abi.encode("nullifier 1")); - uint256 templateIdx = 0; - - EmailProof memory emailProof = generateMockEmailProof(subject, nullifier, accountSalt); - - bytes[] memory subjectParamsForAcceptance = new bytes[](1); - subjectParamsForAcceptance[0] = abi.encode(accountAddress); - EmailAuthMsg memory emailAuthMsg = EmailAuthMsg({ - templateId: zkEmailRecovery.computeAcceptanceTemplateId(templateIdx), - subjectParams: subjectParamsForAcceptance, - skipedSubjectPrefix: 0, - proof: emailProof - }); - - IEmailAccountRecovery(router).handleAcceptance(emailAuthMsg, templateIdx); - } - - function handleRecovery(address newOwner, address recoveryModule, bytes32 accountSalt) public { - // Uncomment if getting "invalid subject" errors. Sometimes the subject needs updating after - // certain changes - // console2.log("accountAddress: ", accountAddress); - // console2.log("newOwner: ", newOwner); - // console2.log("recoveryModule: ", recoveryModule); - - string memory subject = - "Recover account 0x19F55F3fE4c8915F21cc92852CD8E924998fDa38 to new owner 0x7240b687730BE024bcfD084621f794C2e4F8408f using recovery module 0xbF6064f750F31Dc9c9E7347E0C2236Be80B014B4"; - address router = zkEmailRecovery.getRouterForAccount(accountAddress); - bytes32 nullifier = keccak256(abi.encode("nullifier 2")); - uint256 templateIdx = 0; - - EmailProof memory emailProof = generateMockEmailProof(subject, nullifier, accountSalt); - - bytes[] memory subjectParamsForRecovery = new bytes[](3); - subjectParamsForRecovery[0] = abi.encode(accountAddress); - subjectParamsForRecovery[1] = abi.encode(newOwner); - subjectParamsForRecovery[2] = abi.encode(recoveryModule); - - EmailAuthMsg memory emailAuthMsg = EmailAuthMsg({ - templateId: zkEmailRecovery.computeRecoveryTemplateId(templateIdx), - subjectParams: subjectParamsForRecovery, - skipedSubjectPrefix: 0, - proof: emailProof - }); - IEmailAccountRecovery(router).handleRecovery(emailAuthMsg, templateIdx); - } -} diff --git a/test/integration/OwnableValidatorRecovery/OwnableValidatorRecovery.t.sol b/test/integration/OwnableValidatorRecovery/OwnableValidatorRecovery.t.sol index 3ac1710b..7f8e439a 100644 --- a/test/integration/OwnableValidatorRecovery/OwnableValidatorRecovery.t.sol +++ b/test/integration/OwnableValidatorRecovery/OwnableValidatorRecovery.t.sol @@ -6,29 +6,32 @@ import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; import { IEmailAccountRecovery } from "src/interfaces/IEmailAccountRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; import { OwnableValidator } from "src/test/OwnableValidator.sol"; -import { OwnableValidatorBase } from "./OwnableValidatorBase.t.sol"; +import { OwnableValidatorRecoveryBase } from "./OwnableValidatorRecoveryBase.t.sol"; -contract OwnableValidatorRecovery_Integration_Test is OwnableValidatorBase { +contract OwnableValidatorRecovery_Integration_Test is OwnableValidatorRecoveryBase { using ModuleKitHelpers for *; using ModuleKitUserOp for *; OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; + bytes4 functionSelector; + function setUp() public override { super.setUp(); validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule{ salt: "test salt" }(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); + functionSelector = bytes4(keccak256(bytes("changeOwner(address,address,address)"))); + instance.installModule({ moduleTypeId: MODULE_TYPE_VALIDATOR, module: address(validator), @@ -38,162 +41,69 @@ contract OwnableValidatorRecovery_Integration_Test is OwnableValidatorBase { instance.installModule({ moduleTypeId: MODULE_TYPE_EXECUTOR, module: recoveryModuleAddress, - data: abi.encode(address(validator), guardians, guardianWeights, threshold, delay, expiry) + data: abi.encode( + address(validator), + functionSelector, + guardians, + guardianWeights, + threshold, + delay, + expiry + ) }); } function test_Recover_RotatesOwnerSuccessfully() public { - address router = zkEmailRecovery.getRouterForAccount(accountAddress); + bytes memory recoveryCalldata = abi.encodeWithSignature( + "changeOwner(address,address,address)", accountAddress, recoveryModuleAddress, newOwner + ); + bytes32 calldataHash = keccak256(recoveryCalldata); // Accept guardian 1 acceptGuardian(accountSalt1); GuardianStorage memory guardianStorage1 = - zkEmailRecovery.getGuardian(accountAddress, guardian1); + emailRecoveryManager.getGuardian(accountAddress, guardian1); assertEq(uint256(guardianStorage1.status), uint256(GuardianStatus.ACCEPTED)); assertEq(guardianStorage1.weight, uint256(1)); // Accept guardian 2 acceptGuardian(accountSalt2); GuardianStorage memory guardianStorage2 = - zkEmailRecovery.getGuardian(accountAddress, guardian2); + emailRecoveryManager.getGuardian(accountAddress, guardian2); assertEq(uint256(guardianStorage2.status), uint256(GuardianStatus.ACCEPTED)); assertEq(guardianStorage2.weight, uint256(2)); // Time travel so that EmailAuth timestamp is valid vm.warp(12 seconds); // handle recovery request for guardian 1 - handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); - IZkEmailRecovery.RecoveryRequest memory recoveryRequest = - zkEmailRecovery.getRecoveryRequest(accountAddress); + handleRecovery(recoveryModuleAddress, calldataHash, accountSalt1); + IEmailRecoveryManager.RecoveryRequest memory recoveryRequest = + emailRecoveryManager.getRecoveryRequest(accountAddress); assertEq(recoveryRequest.executeAfter, 0); assertEq(recoveryRequest.executeBefore, 0); assertEq(recoveryRequest.currentWeight, 1); - assertEq(recoveryRequest.subjectParams.length, 0); // handle recovery request for guardian 2 uint256 executeAfter = block.timestamp + delay; uint256 executeBefore = block.timestamp + expiry; - handleRecovery(newOwner, recoveryModuleAddress, accountSalt2); - recoveryRequest = zkEmailRecovery.getRecoveryRequest(accountAddress); + handleRecovery(recoveryModuleAddress, calldataHash, accountSalt2); + recoveryRequest = emailRecoveryManager.getRecoveryRequest(accountAddress); assertEq(recoveryRequest.executeAfter, executeAfter); assertEq(recoveryRequest.executeBefore, executeBefore); assertEq(recoveryRequest.currentWeight, 3); - assertEq(recoveryRequest.subjectParams.length, 3); - assertEq(recoveryRequest.subjectParams[0], abi.encode(accountAddress)); - assertEq(recoveryRequest.subjectParams[1], abi.encode(newOwner)); - assertEq(recoveryRequest.subjectParams[2], abi.encode(recoveryModuleAddress)); // Time travel so that the recovery delay has passed vm.warp(block.timestamp + delay); // Complete recovery - IEmailAccountRecovery(router).completeRecovery(); + emailRecoveryManager.completeRecovery(accountAddress, recoveryCalldata); - recoveryRequest = zkEmailRecovery.getRecoveryRequest(accountAddress); + recoveryRequest = emailRecoveryManager.getRecoveryRequest(accountAddress); address updatedOwner = validator.owners(accountAddress); assertEq(recoveryRequest.executeAfter, 0); assertEq(recoveryRequest.executeBefore, 0); assertEq(recoveryRequest.currentWeight, 0); - assertEq(recoveryRequest.subjectParams.length, 0); assertEq(updatedOwner, newOwner); } - - function test_Recover_TryInstallModuleAfterFailedConfigureRecovery() public { - vm.prank(accountAddress); - instance.uninstallModule(MODULE_TYPE_EXECUTOR, recoveryModuleAddress, ""); - vm.stopPrank(); - - // This call fails because the account forgot to install the module before starting the - // recovery flow - vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.RecoveryModuleNotInstalled.selector); - zkEmailRecovery.configureRecovery( - recoveryModuleAddress, guardians, guardianWeights, threshold, delay, expiry - ); - vm.stopPrank(); - - instance.installModule({ - moduleTypeId: MODULE_TYPE_EXECUTOR, - module: recoveryModuleAddress, - data: abi.encode(address(validator), guardians, guardianWeights, threshold, delay, expiry) - }); - - address router = zkEmailRecovery.getRouterForAccount(accountAddress); - - acceptGuardian(accountSalt1); - acceptGuardian(accountSalt2); - vm.warp(12 seconds); - handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); - handleRecovery(newOwner, recoveryModuleAddress, accountSalt2); - - vm.warp(block.timestamp + delay); - - IEmailAccountRecovery(router).completeRecovery(); - - IZkEmailRecovery.RecoveryRequest memory recoveryRequest = - zkEmailRecovery.getRecoveryRequest(accountAddress); - address updatedOwner = validator.owners(accountAddress); - - assertEq(recoveryRequest.executeAfter, 0); - assertEq(recoveryRequest.executeBefore, 0); - assertEq(recoveryRequest.currentWeight, 0); - assertEq(recoveryRequest.subjectParams.length, 0); - assertEq(updatedOwner, newOwner); - } - - function test_OnUninstall_DeInitsStateSuccessfully() public { - // configure and complete an entire recovery request - test_Recover_RotatesOwnerSuccessfully(); - address router = zkEmailRecovery.computeRouterAddress(keccak256(abi.encode(accountAddress))); - - // Uninstall module - vm.prank(accountAddress); - instance.uninstallModule(MODULE_TYPE_EXECUTOR, recoveryModuleAddress, ""); - vm.stopPrank(); - - bool isModuleInstalled = - instance.isModuleInstalled(MODULE_TYPE_EXECUTOR, recoveryModuleAddress, ""); - assertFalse(isModuleInstalled); - - // assert that recovery config has been cleared successfully - IZkEmailRecovery.RecoveryConfig memory recoveryConfig = - zkEmailRecovery.getRecoveryConfig(accountAddress); - assertEq(recoveryConfig.recoveryModule, address(0)); - assertEq(recoveryConfig.delay, 0); - assertEq(recoveryConfig.expiry, 0); - - // assert that the recovery request has been cleared successfully - IZkEmailRecovery.RecoveryRequest memory recoveryRequest = - zkEmailRecovery.getRecoveryRequest(accountAddress); - assertEq(recoveryRequest.executeAfter, 0); - assertEq(recoveryRequest.executeBefore, 0); - assertEq(recoveryRequest.currentWeight, 0); - assertEq(recoveryRequest.subjectParams.length, 0); - - // assert that guardian storage has been cleared successfully for guardian 1 - GuardianStorage memory guardianStorage1 = - zkEmailRecovery.getGuardian(accountAddress, guardian1); - assertEq(uint256(guardianStorage1.status), uint256(GuardianStatus.NONE)); - assertEq(guardianStorage1.weight, uint256(0)); - - // assert that guardian storage has been cleared successfully for guardian 2 - GuardianStorage memory guardianStorage2 = - zkEmailRecovery.getGuardian(accountAddress, guardian2); - assertEq(uint256(guardianStorage2.status), uint256(GuardianStatus.NONE)); - assertEq(guardianStorage2.weight, uint256(0)); - - // assert that guardian config has been cleared successfully - IZkEmailRecovery.GuardianConfig memory guardianConfig = - zkEmailRecovery.getGuardianConfig(accountAddress); - assertEq(guardianConfig.guardianCount, 0); - assertEq(guardianConfig.totalWeight, 0); - assertEq(guardianConfig.threshold, 0); - - // assert that the recovery router mappings have been cleared successfully - address accountForRouter = zkEmailRecovery.getAccountForRouter(router); - address routerForAccount = zkEmailRecovery.getRouterForAccount(accountAddress); - assertEq(accountForRouter, address(0)); - assertEq(routerForAccount, address(0)); - } } diff --git a/test/integration/ValidatorEmailRecoveryModule/ValidatorEmailRecoveryModuleBase.t.sol b/test/integration/OwnableValidatorRecovery/OwnableValidatorRecoveryBase.t.sol similarity index 67% rename from test/integration/ValidatorEmailRecoveryModule/ValidatorEmailRecoveryModuleBase.t.sol rename to test/integration/OwnableValidatorRecovery/OwnableValidatorRecoveryBase.t.sol index 498f3834..5db22b3e 100644 --- a/test/integration/ValidatorEmailRecoveryModule/ValidatorEmailRecoveryModuleBase.t.sol +++ b/test/integration/OwnableValidatorRecovery/OwnableValidatorRecoveryBase.t.sol @@ -4,25 +4,32 @@ pragma solidity ^0.8.25; import "forge-std/console2.sol"; import { EmailAuthMsg, EmailProof } from "ether-email-auth/packages/contracts/src/EmailAuth.sol"; -import { ZkEmailRecovery } from "src/ZkEmailRecovery.sol"; -import { IEmailAccountRecovery } from "src/interfaces/IEmailAccountRecoveryNew.sol"; +import { EmailRecoverySubjectHandler } from "src/handlers/EmailRecoverySubjectHandler.sol"; +import { EmailRecoveryManager } from "src/EmailRecoveryManager.sol"; +import { IEmailAccountRecovery } from "src/interfaces/IEmailAccountRecovery.sol"; import { IntegrationBase } from "../IntegrationBase.t.sol"; -abstract contract ValidatorEmailRecoveryModuleBase is IntegrationBase { - ZkEmailRecovery zkEmailRecovery; +abstract contract OwnableValidatorRecoveryBase is IntegrationBase { + EmailRecoverySubjectHandler emailRecoveryHandler; + EmailRecoveryManager emailRecoveryManager; function setUp() public virtual override { super.setUp(); - // Deploy ZkEmailRecovery - zkEmailRecovery = new ZkEmailRecovery( - address(verifier), address(ecdsaOwnedDkimRegistry), address(emailAuthImpl) + emailRecoveryHandler = new EmailRecoverySubjectHandler(); + + // Deploy EmailRecoveryManager + emailRecoveryManager = new EmailRecoveryManager( + address(verifier), + address(ecdsaOwnedDkimRegistry), + address(emailAuthImpl), + address(emailRecoveryHandler) ); // Compute guardian addresses - guardian1 = zkEmailRecovery.computeEmailAuthAddress(accountSalt1); - guardian2 = zkEmailRecovery.computeEmailAuthAddress(accountSalt2); - guardian3 = zkEmailRecovery.computeEmailAuthAddress(accountSalt3); + guardian1 = emailRecoveryManager.computeEmailAuthAddress(accountSalt1); + guardian2 = emailRecoveryManager.computeEmailAuthAddress(accountSalt2); + guardian3 = emailRecoveryManager.computeEmailAuthAddress(accountSalt3); guardians = new address[](3); guardians[0] = guardian1; @@ -79,10 +86,10 @@ abstract contract ValidatorEmailRecoveryModuleBase is IntegrationBase { templates[0][4] = "recovery"; templates[0][5] = "module"; templates[0][6] = "{ethAddr}"; - templates[0][7] = "to"; - templates[0][8] = "new"; - templates[0][9] = "owner"; - templates[0][10] = "{ethAddr}"; + templates[0][7] = "using"; + templates[0][8] = "recovery"; + templates[0][9] = "hash"; + templates[0][10] = "{string}"; return templates; } @@ -101,18 +108,18 @@ abstract contract ValidatorEmailRecoveryModuleBase is IntegrationBase { bytes[] memory subjectParamsForAcceptance = new bytes[](1); subjectParamsForAcceptance[0] = abi.encode(accountAddress); EmailAuthMsg memory emailAuthMsg = EmailAuthMsg({ - templateId: zkEmailRecovery.computeAcceptanceTemplateId(templateIdx), + templateId: emailRecoveryManager.computeAcceptanceTemplateId(templateIdx), subjectParams: subjectParamsForAcceptance, skipedSubjectPrefix: 0, proof: emailProof }); - zkEmailRecovery.handleAcceptance(accountAddress, emailAuthMsg, templateIdx); + emailRecoveryManager.handleAcceptance(emailAuthMsg, templateIdx); } function handleRecovery( - address newOwner, address recoveryModule, + bytes32 calldataHash, bytes32 accountSalt ) public @@ -121,10 +128,17 @@ abstract contract ValidatorEmailRecoveryModuleBase is IntegrationBase { // certain changes // console2.log("accountAddress: ", accountAddress); // console2.log("recoveryModule: ", recoveryModule); - // console2.log("newOwner: ", newOwner); + // console2.log("calldataHash:"); + // console2.logBytes32(calldataHash); - string memory subject = - "Recover account 0x19F55F3fE4c8915F21cc92852CD8E924998fDa38 via recovery module 0xAB3594842B8651c8183D156e747C0BF89AFF8942 to new owner 0x7240b687730BE024bcfD084621f794C2e4F8408f"; + // TODO: Ideally do this dynamically + string memory calldataHashString = + "0x774e575ec8d6368bbf9b564bd5827574b9f5f6c960e0f6ff9179eca3090df060"; + + string memory subject = string.concat( + "Recover account 0x19F55F3fE4c8915F21cc92852CD8E924998fDa38 via recovery module 0x2E15d2c3aBFfA78dA67Ebb55139902b85B746765 using recovery hash ", + calldataHashString + ); bytes32 nullifier = keccak256(abi.encode("nullifier 2")); uint256 templateIdx = 0; @@ -133,14 +147,16 @@ abstract contract ValidatorEmailRecoveryModuleBase is IntegrationBase { bytes[] memory subjectParamsForRecovery = new bytes[](3); subjectParamsForRecovery[0] = abi.encode(accountAddress); subjectParamsForRecovery[1] = abi.encode(recoveryModule); - subjectParamsForRecovery[2] = abi.encode(newOwner); + subjectParamsForRecovery[2] = abi.encode(calldataHashString); EmailAuthMsg memory emailAuthMsg = EmailAuthMsg({ - templateId: zkEmailRecovery.computeRecoveryTemplateId(templateIdx), + templateId: emailRecoveryManager.computeRecoveryTemplateId(templateIdx), subjectParams: subjectParamsForRecovery, skipedSubjectPrefix: 0, proof: emailProof }); - IEmailAccountRecovery(address(zkEmailRecovery)).handleRecovery(emailAuthMsg, templateIdx); + IEmailAccountRecovery(address(emailRecoveryManager)).handleRecovery( + emailAuthMsg, templateIdx + ); } } diff --git a/test/integration/SafeRecovery/SafeIntegrationBase.t.sol b/test/integration/SafeRecovery/SafeIntegrationBase.t.sol index ae100527..9b5d23b4 100644 --- a/test/integration/SafeRecovery/SafeIntegrationBase.t.sol +++ b/test/integration/SafeRecovery/SafeIntegrationBase.t.sol @@ -21,15 +21,17 @@ import { etchEntrypoint, IEntryPoint } from "modulekit/test/predeploy/EntryPoint import { MockExecutor, MockTarget } from "modulekit/Mocks.sol"; import { MockValidator } from "module-bases/mocks/MockValidator.sol"; import { EmailAuthMsg, EmailProof } from "ether-email-auth/packages/contracts/src/EmailAuth.sol"; - import { Solarray } from "solarray/Solarray.sol"; + +import { EmailRecoveryManager } from "src/EmailRecoveryManager.sol"; +import { EmailRecoverySubjectHandler } from "src/handlers/EmailRecoverySubjectHandler.sol"; import { MockRegistry } from "../external/MockRegistry.sol"; -import { SafeZkEmailRecovery } from "src/SafeZkEmailRecovery.sol"; import { IEmailAccountRecovery } from "src/interfaces/IEmailAccountRecovery.sol"; import { IntegrationBase } from "../IntegrationBase.t.sol"; abstract contract SafeIntegrationBase is IntegrationBase { - SafeZkEmailRecovery zkEmailRecovery; + EmailRecoverySubjectHandler emailRecoveryHandler; + EmailRecoveryManager emailRecoveryManager; Safe7579 safe7579; Safe singleton; @@ -47,17 +49,22 @@ abstract contract SafeIntegrationBase is IntegrationBase { function setUp() public virtual override { super.setUp(); - zkEmailRecovery = new SafeZkEmailRecovery( - address(verifier), address(ecdsaOwnedDkimRegistry), address(emailAuthImpl) + emailRecoveryHandler = new EmailRecoverySubjectHandler(); + + emailRecoveryManager = new EmailRecoveryManager( + address(verifier), + address(ecdsaOwnedDkimRegistry), + address(emailAuthImpl), + address(emailRecoveryHandler) ); safe = deploySafe(); accountAddress = address(safe); // Compute guardian addresses - guardian1 = zkEmailRecovery.computeEmailAuthAddress(accountSalt1); - guardian2 = zkEmailRecovery.computeEmailAuthAddress(accountSalt2); - guardian3 = zkEmailRecovery.computeEmailAuthAddress(accountSalt3); + guardian1 = emailRecoveryManager.computeEmailAuthAddress(accountSalt1); + guardian2 = emailRecoveryManager.computeEmailAuthAddress(accountSalt2); + guardian3 = emailRecoveryManager.computeEmailAuthAddress(accountSalt3); guardians = new address[](3); guardians[0] = guardian1; @@ -221,14 +228,14 @@ abstract contract SafeIntegrationBase is IntegrationBase { } function acceptGuardian(bytes32 accountSalt) public { - // Uncomment if getting "invalid subject" errors. Sometimes the subject needs updating after + // Uncomment if getting "invalid subject" errors. Sometimes the subject needs updating + // after // certain changes // console2.log("accountAddress: ", accountAddress); string memory subject = "Accept guardian request for 0xE760ccaE42b4EA7a93A4CfA75BC649aaE1033095"; - address router = zkEmailRecovery.getRouterForAccount(accountAddress); bytes32 nullifier = keccak256(abi.encode("nullifier 1")); uint256 templateIdx = 0; EmailProof memory emailProof = generateMockEmailProof(subject, nullifier, accountSalt); @@ -237,49 +244,53 @@ abstract contract SafeIntegrationBase is IntegrationBase { subjectParamsForAcceptance[0] = abi.encode(accountAddress); EmailAuthMsg memory emailAuthMsg = EmailAuthMsg({ - templateId: zkEmailRecovery.computeAcceptanceTemplateId(templateIdx), + templateId: emailRecoveryManager.computeAcceptanceTemplateId(templateIdx), subjectParams: subjectParamsForAcceptance, skipedSubjectPrefix: 0, proof: emailProof }); - IEmailAccountRecovery(router).handleAcceptance(emailAuthMsg, templateIdx); + emailRecoveryManager.handleAcceptance(emailAuthMsg, templateIdx); } function handleRecovery( - address oldOwner, - address newOwner, address recoveryModule, + bytes32 calldataHash, bytes32 accountSalt ) public { - // Uncomment if getting "invalid subject" errors. Sometimes the subject needs updating after + // Uncomment if getting "invalid subject" errors. Sometimes the subject needs updating + // after // certain changes // console2.log("accountAddress: ", accountAddress); - // console2.log("oldOwner: ", oldOwner); - // console2.log("newOwner: ", newOwner); - // console2.log("recoveryModule: ", recoveryModule); + console2.log("recoveryModule: ", recoveryModule); + console2.log("calldataHash:"); + console2.logBytes32(calldataHash); - string memory subject = - "Recover account 0xE760ccaE42b4EA7a93A4CfA75BC649aaE1033095 from old owner 0x7c8999dC9a822c1f0Df42023113EDB4FDd543266 to new owner 0x7240b687730BE024bcfD084621f794C2e4F8408f using recovery module 0x6d2Fa6974Ef18eB6da842D3c7ab3150326feaEEC"; - address router = zkEmailRecovery.getRouterForAccount(accountAddress); + // TODO: Ideally do this dynamically + string memory calldataHashString = + "0x4e66542ab78fcc7a2341586b67800e82b975078517d7d692e2aa98d2696c51d0"; + + string memory subject = string.concat( + "Recover account 0xE760ccaE42b4EA7a93A4CfA75BC649aaE1033095 via recovery module 0xD7F74A3A1d35495c1537f5377590e44A2bf44122 using recovery hash ", + calldataHashString + ); bytes32 nullifier = keccak256(abi.encode("nullifier 2")); uint256 templateIdx = 0; EmailProof memory emailProof = generateMockEmailProof(subject, nullifier, accountSalt); - bytes[] memory subjectParamsForRecovery = new bytes[](4); + bytes[] memory subjectParamsForRecovery = new bytes[](3); subjectParamsForRecovery[0] = abi.encode(accountAddress); - subjectParamsForRecovery[1] = abi.encode(oldOwner); - subjectParamsForRecovery[2] = abi.encode(newOwner); - subjectParamsForRecovery[3] = abi.encode(recoveryModule); + subjectParamsForRecovery[1] = abi.encode(recoveryModule); + subjectParamsForRecovery[2] = abi.encode(calldataHashString); EmailAuthMsg memory emailAuthMsg = EmailAuthMsg({ - templateId: zkEmailRecovery.computeRecoveryTemplateId(templateIdx), + templateId: emailRecoveryManager.computeRecoveryTemplateId(templateIdx), subjectParams: subjectParamsForRecovery, skipedSubjectPrefix: 0, proof: emailProof }); - IEmailAccountRecovery(router).handleRecovery(emailAuthMsg, templateIdx); + emailRecoveryManager.handleRecovery(emailAuthMsg, templateIdx); } } diff --git a/test/integration/SafeRecovery/SafeRecovery.t.sol b/test/integration/SafeRecovery/SafeRecovery.t.sol index 9729976d..06b773cf 100644 --- a/test/integration/SafeRecovery/SafeRecovery.t.sol +++ b/test/integration/SafeRecovery/SafeRecovery.t.sol @@ -2,30 +2,53 @@ pragma solidity ^0.8.25; import "forge-std/console2.sol"; - +import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; import { MODULE_TYPE_EXECUTOR } from "erc7579/interfaces/IERC7579Module.sol"; import { IERC7579Account } from "erc7579/interfaces/IERC7579Account.sol"; import { Safe } from "@safe-global/safe-contracts/contracts/Safe.sol"; -import { IEmailAccountRecovery } from "src/interfaces/IEmailAccountRecovery.sol"; -import { SafeRecoveryModule } from "src/modules/SafeRecoveryModule.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; import { SafeIntegrationBase } from "./SafeIntegrationBase.t.sol"; contract SafeRecovery_Integration_Test is SafeIntegrationBase { - SafeRecoveryModule recoveryModule; + using ModuleKitHelpers for *; + using ModuleKitUserOp for *; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; + bytes4 functionSelector; + function setUp() public override { super.setUp(); - recoveryModule = new SafeRecoveryModule(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); + + functionSelector = bytes4(keccak256(bytes("changeOwner(address,address,address)"))); + + instance.installModule({ + moduleTypeId: MODULE_TYPE_EXECUTOR, + module: recoveryModuleAddress, + data: abi.encode( + address(safe), // FIXME: requires rhinestone change + functionSelector, + guardians, + guardianWeights, + threshold, + delay, + expiry + ) + }); } function test_Recover_RotatesOwnerSuccessfully() public { IERC7579Account account = IERC7579Account(accountAddress); + bytes memory recoveryCalldata = abi.encodeWithSignature( + "changeOwner(address,address,address)", accountAddress, recoveryModuleAddress, newOwner + ); + bytes32 calldataHash = keccak256(recoveryCalldata); bytes[] memory subjectParamsForRecovery = new bytes[](4); subjectParamsForRecovery[0] = abi.encode(accountAddress); @@ -33,29 +56,26 @@ contract SafeRecovery_Integration_Test is SafeIntegrationBase { subjectParamsForRecovery[2] = abi.encode(newOwner); subjectParamsForRecovery[3] = abi.encode(recoveryModuleAddress); - // Install recovery module - configureRecovery is called on `onInstall` - vm.prank(accountAddress); - account.installModule( - MODULE_TYPE_EXECUTOR, - recoveryModuleAddress, - abi.encode(guardians, guardianWeights, threshold, delay, expiry) - ); - vm.stopPrank(); - - // Retrieve router now module has been installed - address router = zkEmailRecovery.getRouterForAccount(accountAddress); + // // Install recovery module - configureRecovery is called on `onInstall` + // vm.prank(accountAddress); + // account.installModule( + // MODULE_TYPE_EXECUTOR, + // recoveryModuleAddress, + // abi.encode(guardians, guardianWeights, threshold, delay, expiry) + // ); + // vm.stopPrank(); // Accept guardian acceptGuardian(accountSalt1); GuardianStorage memory guardianStorage1 = - zkEmailRecovery.getGuardian(accountAddress, guardian1); + emailRecoveryManager.getGuardian(accountAddress, guardian1); assertEq(uint256(guardianStorage1.status), uint256(GuardianStatus.ACCEPTED)); assertEq(guardianStorage1.weight, uint256(1)); // Accept guardian acceptGuardian(accountSalt2); GuardianStorage memory guardianStorage2 = - zkEmailRecovery.getGuardian(accountAddress, guardian2); + emailRecoveryManager.getGuardian(accountAddress, guardian2); assertEq(uint256(guardianStorage2.status), uint256(GuardianStatus.ACCEPTED)); assertEq(guardianStorage2.weight, uint256(2)); @@ -63,30 +83,28 @@ contract SafeRecovery_Integration_Test is SafeIntegrationBase { vm.warp(12 seconds); // handle recovery request for guardian 1 - handleRecovery(owner, newOwner, recoveryModuleAddress, accountSalt1); - IZkEmailRecovery.RecoveryRequest memory recoveryRequest = - zkEmailRecovery.getRecoveryRequest(accountAddress); + handleRecovery(recoveryModuleAddress, calldataHash, accountSalt1); + IEmailRecoveryManager.RecoveryRequest memory recoveryRequest = + emailRecoveryManager.getRecoveryRequest(accountAddress); assertEq(recoveryRequest.currentWeight, 1); // handle recovery request for guardian 2 uint256 executeAfter = block.timestamp + delay; uint256 executeBefore = block.timestamp + expiry; - handleRecovery(owner, newOwner, recoveryModuleAddress, accountSalt2); - recoveryRequest = zkEmailRecovery.getRecoveryRequest(accountAddress); + handleRecovery(recoveryModuleAddress, calldataHash, accountSalt2); + recoveryRequest = emailRecoveryManager.getRecoveryRequest(accountAddress); assertEq(recoveryRequest.executeAfter, executeAfter); assertEq(recoveryRequest.executeBefore, executeBefore); - assertEq(recoveryRequest.subjectParams, subjectParamsForRecovery); assertEq(recoveryRequest.currentWeight, 3); vm.warp(block.timestamp + delay); // Complete recovery - IEmailAccountRecovery(router).completeRecovery(); + emailRecoveryManager.completeRecovery(accountAddress, recoveryCalldata); - recoveryRequest = zkEmailRecovery.getRecoveryRequest(accountAddress); + recoveryRequest = emailRecoveryManager.getRecoveryRequest(accountAddress); assertEq(recoveryRequest.executeAfter, 0); assertEq(recoveryRequest.executeBefore, 0); - assertEq(recoveryRequest.subjectParams, new bytes[](0)); assertEq(recoveryRequest.currentWeight, 0); vm.prank(accountAddress); @@ -101,7 +119,7 @@ contract SafeRecovery_Integration_Test is SafeIntegrationBase { // function test_OnUninstall_DeInitsStateSuccessfully() public { // // configure and complete an entire recovery request // test_Recover_RotatesOwnerSuccessfully(); - // address router = zkEmailRecovery.computeRouterAddress( + // address router = emailRecoveryManager.computeRouterAddress( // keccak256(abi.encode(accountAddress)) // ); // IERC7579Account account = IERC7579Account(accountAddress); @@ -123,15 +141,15 @@ contract SafeRecovery_Integration_Test is SafeIntegrationBase { // // assertFalse(isModuleInstalled); // // assert that recovery config has been cleared successfully - // IZkEmailRecovery.RecoveryConfig memory recoveryConfig = zkEmailRecovery + // IEmailRecoveryManager.RecoveryConfig memory recoveryConfig = emailRecoveryManager // .getRecoveryConfig(accountAddress); // assertEq(recoveryConfig.recoveryModule, address(0)); // assertEq(recoveryConfig.delay, 0); // assertEq(recoveryConfig.expiry, 0); // // assert that the recovery request has been cleared successfully - // IZkEmailRecovery.RecoveryRequest - // memory recoveryRequest = zkEmailRecovery.getRecoveryRequest( + // IEmailRecoveryManager.RecoveryRequest + // memory recoveryRequest = emailRecoveryManager.getRecoveryRequest( // accountAddress // ); // assertEq(recoveryRequest.executeAfter, 0); @@ -140,7 +158,7 @@ contract SafeRecovery_Integration_Test is SafeIntegrationBase { // assertEq(recoveryRequest.subjectParams.length, 0); // // assert that guardian storage has been cleared successfully for guardian 1 - // GuardianStorage memory guardianStorage1 = zkEmailRecovery.getGuardian( + // GuardianStorage memory guardianStorage1 = emailRecoveryManager.getGuardian( // accountAddress, // guardian1 // ); @@ -151,7 +169,7 @@ contract SafeRecovery_Integration_Test is SafeIntegrationBase { // assertEq(guardianStorage1.weight, uint256(0)); // // assert that guardian storage has been cleared successfully for guardian 2 - // GuardianStorage memory guardianStorage2 = zkEmailRecovery.getGuardian( + // GuardianStorage memory guardianStorage2 = emailRecoveryManager.getGuardian( // accountAddress, // guardian2 // ); @@ -162,15 +180,15 @@ contract SafeRecovery_Integration_Test is SafeIntegrationBase { // assertEq(guardianStorage2.weight, uint256(0)); // // assert that guardian config has been cleared successfully - // IZkEmailRecovery.GuardianConfig memory guardianConfig = zkEmailRecovery + // IEmailRecoveryManager.GuardianConfig memory guardianConfig = emailRecoveryManager // .getGuardianConfig(accountAddress); // assertEq(guardianConfig.guardianCount, 0); // assertEq(guardianConfig.totalWeight, 0); // assertEq(guardianConfig.threshold, 0); // // assert that the recovery router mappings have been cleared successfully - // address accountForRouter = zkEmailRecovery.getAccountForRouter(router); - // address routerForAccount = zkEmailRecovery.getRouterForAccount( + // address accountForRouter = emailRecoveryManager.getAccountForRouter(router); + // address routerForAccount = emailRecoveryManager.getRouterForAccount( // accountAddress // ); // assertEq(accountForRouter, address(0)); diff --git a/test/integration/ValidatorEmailRecoveryModule/ValidatorEmailRecoveryModule.t.sol b/test/integration/ValidatorEmailRecoveryModule/ValidatorEmailRecoveryModule.t.sol deleted file mode 100644 index a42416a1..00000000 --- a/test/integration/ValidatorEmailRecoveryModule/ValidatorEmailRecoveryModule.t.sol +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; - -import "forge-std/console2.sol"; -import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; -import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; - -import { IEmailAccountRecovery } from "src/interfaces/IEmailAccountRecovery.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; -import { ValidatorEmailRecoveryModule } from "src/modules/ValidatorEmailRecoveryModule.sol"; -import { OwnableValidator } from "src/test/OwnableValidator.sol"; - -import { ValidatorEmailRecoveryModuleBase } from "./ValidatorEmailRecoveryModuleBase.t.sol"; - -contract ValidatorEmailRecoveryModule_Integration_Test is ValidatorEmailRecoveryModuleBase { - using ModuleKitHelpers for *; - using ModuleKitUserOp for *; - - OwnableValidator validator; - ValidatorEmailRecoveryModule recoveryModule; - address recoveryModuleAddress; - - bytes4 functionSelector; - - function setUp() public override { - super.setUp(); - - validator = new OwnableValidator(); - recoveryModule = - new ValidatorEmailRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); - recoveryModuleAddress = address(recoveryModule); - - functionSelector = bytes4(keccak256(bytes("changeOwner(address,address,address)"))); - - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: address(validator), - data: abi.encode(owner, recoveryModuleAddress) - }); - // Install recovery module - configureRecovery is called on `onInstall` - instance.installModule({ - moduleTypeId: MODULE_TYPE_EXECUTOR, - module: recoveryModuleAddress, - data: abi.encode( - address(validator), - functionSelector, - guardians, - guardianWeights, - threshold, - delay, - expiry, - acceptanceSubjectTemplates(), - recoverySubjectTemplates() - ) - }); - } - - function test_Recover_RotatesOwnerSuccessfully() public { - bytes memory recoveryCalldata = abi.encodeWithSignature( - "changeOwner(address,address,address)", accountAddress, recoveryModuleAddress, newOwner - ); - - // Accept guardian 1 - acceptGuardian(accountSalt1); - GuardianStorage memory guardianStorage1 = - zkEmailRecovery.getGuardian(accountAddress, guardian1); - assertEq(uint256(guardianStorage1.status), uint256(GuardianStatus.ACCEPTED)); - assertEq(guardianStorage1.weight, uint256(1)); - - // Accept guardian 2 - acceptGuardian(accountSalt2); - GuardianStorage memory guardianStorage2 = - zkEmailRecovery.getGuardian(accountAddress, guardian2); - assertEq(uint256(guardianStorage2.status), uint256(GuardianStatus.ACCEPTED)); - assertEq(guardianStorage2.weight, uint256(2)); - - // Time travel so that EmailAuth timestamp is valid - vm.warp(12 seconds); - // handle recovery request for guardian 1 - handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); - IZkEmailRecovery.RecoveryRequest memory recoveryRequest = - zkEmailRecovery.getRecoveryRequest(accountAddress); - assertEq(recoveryRequest.executeAfter, 0); - assertEq(recoveryRequest.executeBefore, 0); - assertEq(recoveryRequest.currentWeight, 1); - - // handle recovery request for guardian 2 - uint256 executeAfter = block.timestamp + delay; - uint256 executeBefore = block.timestamp + expiry; - handleRecovery(newOwner, recoveryModuleAddress, accountSalt2); - recoveryRequest = zkEmailRecovery.getRecoveryRequest(accountAddress); - assertEq(recoveryRequest.executeAfter, executeAfter); - assertEq(recoveryRequest.executeBefore, executeBefore); - assertEq(recoveryRequest.currentWeight, 3); - - // Time travel so that the recovery delay has passed - vm.warp(block.timestamp + delay); - - // Complete recovery - zkEmailRecovery.completeRecovery(accountAddress); - - recoveryRequest = zkEmailRecovery.getRecoveryRequest(accountAddress); - address updatedOwner = validator.owners(accountAddress); - - assertEq(recoveryRequest.executeAfter, 0); - assertEq(recoveryRequest.executeBefore, 0); - assertEq(recoveryRequest.currentWeight, 0); - assertEq(updatedOwner, newOwner); - } -} diff --git a/test/integration/ZkEmailRecovery/ZkEmailRecovery.integration.t.sol b/test/integration/ZkEmailRecovery/ZkEmailRecovery.integration.t.sol index 6b771ac9..fb98914f 100644 --- a/test/integration/ZkEmailRecovery/ZkEmailRecovery.integration.t.sol +++ b/test/integration/ZkEmailRecovery/ZkEmailRecovery.integration.t.sol @@ -1,279 +1,271 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.25; -import "forge-std/console2.sol"; -import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; -import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; - -import { IEmailAccountRecovery } from "src/interfaces/IEmailAccountRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; -import { OwnableValidator } from "src/test/OwnableValidator.sol"; - -import { OwnableValidatorBase } from "../OwnableValidatorRecovery/OwnableValidatorBase.t.sol"; - -contract ZkEmailRecovery_Integration_Test is OwnableValidatorBase { - using ModuleKitHelpers for *; - using ModuleKitUserOp for *; - - OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; - address recoveryModuleAddress; - - function setUp() public override { - super.setUp(); - - validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); - recoveryModuleAddress = address(recoveryModule); - - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: address(validator), - data: abi.encode(owner, recoveryModuleAddress) - }); - // Install recovery module - configureRecovery is called on `onInstall` - instance.installModule({ - moduleTypeId: MODULE_TYPE_EXECUTOR, - module: recoveryModuleAddress, - data: abi.encode(address(validator), guardians, guardianWeights, threshold, delay, expiry) - }); - } - - function test_RevertWhen_HandleAcceptanceCalled_BeforeConfigureRecovery() public { - address router = zkEmailRecovery.getRouterForAccount(accountAddress); - - vm.prank(accountAddress); - instance.uninstallModule(MODULE_TYPE_EXECUTOR, recoveryModuleAddress, ""); - vm.stopPrank(); - - // Issue where forge cannot detect revert even though the call does indeed revert when - // is - // "expectRevert" commented out - // vm.expectRevert(); - // acceptGuardian(accountSalt1); - } - - function test_RevertWhen_HandleRecoveryCalled_BeforeTimeStampChanged() public { - address router = zkEmailRecovery.getRouterForAccount(accountAddress); - - acceptGuardian(accountSalt1); - - // Issue where forge cannot detect revert even though this is the revert message when - // the call is made with "expectRevert" - // vm.expectRevert("invalid timestamp"); - // handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); - } - - function test_RevertWhen_HandleAcceptanceCalled_DuringRecovery() public { - address router = zkEmailRecovery.getRouterForAccount(accountAddress); - - acceptGuardian(accountSalt1); - vm.warp(12 seconds); - handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); - - // Issue where forge cannot detect revert even though this is the revert error when - // the call is made with "expectRevert" - // vm.expectRevert(IZkEmailRecovery.RecoveryInProcess.selector); - // acceptGuardian(accountSalt2); - } - - function test_RevertWhen_HandleAcceptanceCalled_AfterRecoveryProcessedButBeforeCompleteRecovery( - ) - public - { - address router = zkEmailRecovery.getRouterForAccount(accountAddress); - - acceptGuardian(accountSalt1); - acceptGuardian(accountSalt2); - vm.warp(12 seconds); - handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); - handleRecovery(newOwner, recoveryModuleAddress, accountSalt2); - - // Issue where forge cannot detect revert even though this is the revert error when - // the call is made with "expectRevert" - // vm.expectRevert(IZkEmailRecovery.RecoveryInProcess.selector); - // acceptGuardian(accountSalt3); - } - - function test_HandleNewAcceptanceSucceeds_AfterCompleteRecovery() public { - address router = zkEmailRecovery.getRouterForAccount(accountAddress); - - acceptGuardian(accountSalt1); - acceptGuardian(accountSalt2); - vm.warp(12 seconds); - handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); - handleRecovery(newOwner, recoveryModuleAddress, accountSalt2); - - vm.warp(block.timestamp + delay); - - // Complete recovery - IEmailAccountRecovery(router).completeRecovery(); - - acceptGuardian(accountSalt3); - - GuardianStorage memory guardianStorage = - zkEmailRecovery.getGuardian(accountAddress, guardian3); - assertEq(uint256(guardianStorage.status), uint256(GuardianStatus.ACCEPTED)); - assertEq(guardianStorage.weight, uint256(1)); - } - - function test_RevertWhen_HandleRecoveryCalled_BeforeConfigureRecovery() public { - address router = zkEmailRecovery.getRouterForAccount(accountAddress); - - vm.prank(accountAddress); - instance.uninstallModule(MODULE_TYPE_EXECUTOR, recoveryModuleAddress, ""); - vm.stopPrank(); - - // Issue where forge cannot detect revert even though the call does indeed revert when - // is - // vm.expectRevert(); - // handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); - } - - function test_RevertWhen_HandleRecoveryCalled_BeforeHandleAcceptance() public { - // Issue where forge cannot detect revert even though this is the revert message when - // the call is made with "expectRevert" - // vm.expectRevert("guardian is not deployed"); - // handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); - } - - function test_RevertWhen_HandleRecoveryCalled_DuringRecoveryWithoutGuardianBeingDeployed() - public - { - address router = zkEmailRecovery.getRouterForAccount(accountAddress); - - acceptGuardian(accountSalt1); - vm.warp(12 seconds); - handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); - - // Issue where forge cannot detect revert even though this is the revert message when - // the call is made with "expectRevert" - // vm.expectRevert("guardian is not deployed"); - // handleRecovery(newOwner, recoveryModuleAddress, accountSalt2); - } - - function test_RevertWhen_HandleRecoveryCalled_AfterRecoveryProcessedButBeforeCompleteRecovery() - public - { - address router = zkEmailRecovery.getRouterForAccount(accountAddress); - - acceptGuardian(accountSalt1); - acceptGuardian(accountSalt2); - vm.warp(12 seconds); - handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); - handleRecovery(newOwner, recoveryModuleAddress, accountSalt2); - - // Issue where forge cannot detect revert even though this is the revert message when - // the call is made with "expectRevert" - // vm.expectRevert("guardian is not deployed"); - // handleRecovery(newOwner, recoveryModuleAddress, accountSalt3); - } - - function test_RevertWhen_HandleRecoveryCalled_AfterCompleteRecovery() public { - address router = zkEmailRecovery.getRouterForAccount(accountAddress); - - acceptGuardian(accountSalt1); - acceptGuardian(accountSalt2); - vm.warp(12 seconds); - handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); - handleRecovery(newOwner, recoveryModuleAddress, accountSalt2); - - vm.warp(block.timestamp + delay); - - // Complete recovery - IEmailAccountRecovery(router).completeRecovery(); - - // Issue where forge cannot detect revert even though this is the revert message when - // the call is made with "expectRevert" - // vm.expectRevert("email nullifier already used"); - // handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); - } - - function test_RevertWhen_CompleteRecoveryCalled_BeforeConfigureRecovery() public { - address router = zkEmailRecovery.getRouterForAccount(accountAddress); - - vm.prank(accountAddress); - instance.uninstallModule(MODULE_TYPE_EXECUTOR, recoveryModuleAddress, ""); - vm.stopPrank(); - - vm.expectRevert(IZkEmailRecovery.InvalidAccountAddress.selector); - IEmailAccountRecovery(router).completeRecovery(); - } - - function test_RevertWhen_CompleteRecoveryCalled_BeforeHandleAcceptance() public { - address router = zkEmailRecovery.getRouterForAccount(accountAddress); - - vm.expectRevert(IZkEmailRecovery.NotEnoughApprovals.selector); - IEmailAccountRecovery(router).completeRecovery(); - } - - function test_RevertWhen_CompleteRecoveryCalled_BeforeProcessRecovery() public { - address router = zkEmailRecovery.getRouterForAccount(accountAddress); - acceptGuardian(accountSalt1); - - vm.expectRevert(IZkEmailRecovery.NotEnoughApprovals.selector); - IEmailAccountRecovery(router).completeRecovery(); - } - - function test_TryRecoverWhenModuleNotInstalled() public { - vm.prank(accountAddress); - instance.uninstallModule(MODULE_TYPE_EXECUTOR, recoveryModuleAddress, ""); - vm.stopPrank(); - - vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.RecoveryModuleNotInstalled.selector); - zkEmailRecovery.configureRecovery( - recoveryModuleAddress, guardians, guardianWeights, threshold, delay, expiry - ); - // vm.stopPrank(); - - // address router = zkEmailRecovery.getRouterForAccount(accountAddress); - - // acceptGuardian(accountSalt1); - // acceptGuardian(accountSalt2); - // vm.warp(12 seconds); - // handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); - // handleRecovery(newOwner, recoveryModuleAddress, accountSalt2); - - // vm.warp(block.timestamp + delay); - - // // vm.expectRevert( - // // abi.encodeWithSelector( - // // InvalidModule.selector, - // // recoveryModuleAddress - // // ) - // // ); - // vm.expectRevert(); - // IEmailAccountRecovery(router).completeRecovery(); - } - - function test_StaleRecoveryRequest() public { - address router = zkEmailRecovery.getRouterForAccount(accountAddress); - - acceptGuardian(accountSalt1); - acceptGuardian(accountSalt2); - vm.warp(12 seconds); - handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); - handleRecovery(newOwner, recoveryModuleAddress, accountSalt2); - - vm.warp(10 weeks); - - vm.expectRevert(IZkEmailRecovery.RecoveryRequestExpired.selector); - IEmailAccountRecovery(router).completeRecovery(); - - // Can cancel recovery even when stale - vm.startPrank(accountAddress); - zkEmailRecovery.cancelRecovery(bytes("")); - vm.stopPrank(); - - IZkEmailRecovery.RecoveryRequest memory recoveryRequest = - zkEmailRecovery.getRecoveryRequest(accountAddress); - assertEq(recoveryRequest.executeAfter, 0); - assertEq(recoveryRequest.executeBefore, 0); - assertEq(recoveryRequest.currentWeight, 0); - assertEq(recoveryRequest.subjectParams.length, 0); - } -} +// import "forge-std/console2.sol"; +// import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; +// import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; + +// import { IEmailAccountRecovery } from "src/interfaces/IEmailAccountRecovery.sol"; +// import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; +// import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; +// import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; +// import { OwnableValidator } from "src/test/OwnableValidator.sol"; + +// import { OwnableValidatorBase } from "../OwnableValidatorRecovery/OwnableValidatorBase.t.sol"; + +// contract ZkEmailRecovery_Integration_Test is OwnableValidatorBase { +// using ModuleKitHelpers for *; +// using ModuleKitUserOp for *; + +// OwnableValidator validator; +// EmailRecoveryModule recoveryModule; +// address recoveryModuleAddress; + +// bytes recoveryCalldata; + +// function setUp() public override { +// super.setUp(); + +// validator = new OwnableValidator(); +// recoveryModule = +// new EmailRecoveryModule{ salt: "test salt" +// }(address(emailRecoveryManager)); +// recoveryModuleAddress = address(recoveryModule); + +// instance.installModule({ +// moduleTypeId: MODULE_TYPE_VALIDATOR, +// module: address(validator), +// data: abi.encode(owner, recoveryModuleAddress) +// }); +// // Install recovery module - configureRecovery is called on `onInstall` +// instance.installModule({ +// moduleTypeId: MODULE_TYPE_EXECUTOR, +// module: recoveryModuleAddress, +// data: abi.encode(address(validator), guardians, guardianWeights, threshold, delay, +// expiry) +// }); + +// recoveryCalldata = abi.encodeWithSignature( +// "changeOwner(address,address,address)", accountAddress, recoveryModuleAddress, +// newOwner +// ); +// } + +// function test_RevertWhen_HandleAcceptanceCalled_BeforeConfigureRecovery() public { +// vm.prank(accountAddress); +// instance.uninstallModule(MODULE_TYPE_EXECUTOR, recoveryModuleAddress, ""); +// vm.stopPrank(); + +// // Issue where forge cannot detect revert even though the call does indeed revert when +// // is +// // "expectRevert" commented out +// // vm.expectRevert(); +// // acceptGuardian(accountSalt1); +// } + +// function test_RevertWhen_HandleRecoveryCalled_BeforeTimeStampChanged() public { +// acceptGuardian(accountSalt1); + +// // Issue where forge cannot detect revert even though this is the revert message when +// // the call is made with "expectRevert" +// // vm.expectRevert("invalid timestamp"); +// // handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); +// } + +// function test_RevertWhen_HandleAcceptanceCalled_DuringRecovery() public { +// acceptGuardian(accountSalt1); +// vm.warp(12 seconds); +// handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); + +// // Issue where forge cannot detect revert even though this is the revert error when +// // the call is made with "expectRevert" +// // vm.expectRevert(IEmailRecoveryManager.RecoveryInProcess.selector); +// // acceptGuardian(accountSalt2); +// } + +// function +// test_RevertWhen_HandleAcceptanceCalled_AfterRecoveryProcessedButBeforeCompleteRecovery( +// ) +// public +// { +// acceptGuardian(accountSalt1); +// acceptGuardian(accountSalt2); +// vm.warp(12 seconds); +// handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); +// handleRecovery(newOwner, recoveryModuleAddress, accountSalt2); + +// // Issue where forge cannot detect revert even though this is the revert error when +// // the call is made with "expectRevert" +// // vm.expectRevert(IEmailRecoveryManager.RecoveryInProcess.selector); +// // acceptGuardian(accountSalt3); +// } + +// function test_HandleNewAcceptanceSucceeds_AfterCompleteRecovery() public { +// acceptGuardian(accountSalt1); +// acceptGuardian(accountSalt2); +// vm.warp(12 seconds); +// handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); +// handleRecovery(newOwner, recoveryModuleAddress, accountSalt2); + +// vm.warp(block.timestamp + delay); + +// // Complete recovery +// emailRecoveryManager.completeRecovery(accountAddress); + +// acceptGuardian(accountSalt3); + +// GuardianStorage memory guardianStorage = +// emailRecoveryManager.getGuardian(accountAddress, guardian3); +// assertEq(uint256(guardianStorage.status), uint256(GuardianStatus.ACCEPTED)); +// assertEq(guardianStorage.weight, uint256(1)); +// } + +// function test_RevertWhen_HandleRecoveryCalled_BeforeConfigureRecovery() public { +// vm.prank(accountAddress); +// instance.uninstallModule(MODULE_TYPE_EXECUTOR, recoveryModuleAddress, ""); +// vm.stopPrank(); + +// // Issue where forge cannot detect revert even though the call does indeed revert when +// // is +// // vm.expectRevert(); +// // handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); +// } + +// function test_RevertWhen_HandleRecoveryCalled_BeforeHandleAcceptance() public { +// // Issue where forge cannot detect revert even though this is the revert message when +// // the call is made with "expectRevert" +// // vm.expectRevert("guardian is not deployed"); +// // handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); +// } + +// function test_RevertWhen_HandleRecoveryCalled_DuringRecoveryWithoutGuardianBeingDeployed() +// public +// { +// acceptGuardian(accountSalt1); +// vm.warp(12 seconds); +// handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); + +// // Issue where forge cannot detect revert even though this is the revert message when +// // the call is made with "expectRevert" +// // vm.expectRevert("guardian is not deployed"); +// // handleRecovery(newOwner, recoveryModuleAddress, accountSalt2); +// } + +// function +// test_RevertWhen_HandleRecoveryCalled_AfterRecoveryProcessedButBeforeCompleteRecovery() +// public +// { +// acceptGuardian(accountSalt1); +// acceptGuardian(accountSalt2); +// vm.warp(12 seconds); +// handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); +// handleRecovery(newOwner, recoveryModuleAddress, accountSalt2); + +// // Issue where forge cannot detect revert even though this is the revert message when +// // the call is made with "expectRevert" +// // vm.expectRevert("guardian is not deployed"); +// // handleRecovery(newOwner, recoveryModuleAddress, accountSalt3); +// } + +// function test_RevertWhen_HandleRecoveryCalled_AfterCompleteRecovery() public { +// acceptGuardian(accountSalt1); +// acceptGuardian(accountSalt2); +// vm.warp(12 seconds); +// handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); +// handleRecovery(newOwner, recoveryModuleAddress, accountSalt2); + +// vm.warp(block.timestamp + delay); + +// // Complete recovery +// emailRecoveryManager.completeRecovery(accountAddress); + +// // Issue where forge cannot detect revert even though this is the revert message when +// // the call is made with "expectRevert" +// // vm.expectRevert("email nullifier already used"); +// // handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); +// } + +// function test_RevertWhen_CompleteRecoveryCalled_BeforeConfigureRecovery() public { +// vm.prank(accountAddress); +// instance.uninstallModule(MODULE_TYPE_EXECUTOR, recoveryModuleAddress, ""); +// vm.stopPrank(); + +// vm.expectRevert(IEmailRecoveryManager.InvalidAccountAddress.selector); +// emailRecoveryManager.completeRecovery(accountAddress); +// } + +// function test_RevertWhen_CompleteRecoveryCalled_BeforeHandleAcceptance() public { +// vm.expectRevert(IEmailRecoveryManager.NotEnoughApprovals.selector); +// emailRecoveryManager.completeRecovery(accountAddress); +// } + +// function test_RevertWhen_CompleteRecoveryCalled_BeforeProcessRecovery() public { +// acceptGuardian(accountSalt1); + +// vm.expectRevert(IEmailRecoveryManager.NotEnoughApprovals.selector); +// emailRecoveryManager.completeRecovery(accountAddress); +// } + +// function test_TryRecoverWhenModuleNotInstalled() public { +// vm.prank(accountAddress); +// instance.uninstallModule(MODULE_TYPE_EXECUTOR, recoveryModuleAddress, ""); +// vm.stopPrank(); + +// vm.startPrank(accountAddress); +// vm.expectRevert(IEmailRecoveryManager.RecoveryModuleNotInstalled.selector); +// emailRecoveryManager.configureRecovery( +// recoveryModuleAddress, +// guardians, +// guardianWeights, +// threshold, +// delay, +// expiry, +// acceptanceSubjectTemplates(), +// recoverySubjectTemplates() +// ); +// // vm.stopPrank(); + +// // + +// // acceptGuardian(accountSalt1); +// // acceptGuardian(accountSalt2); +// // vm.warp(12 seconds); +// // handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); +// // handleRecovery(newOwner, recoveryModuleAddress, accountSalt2); + +// // vm.warp(block.timestamp + delay); + +// // // vm.expectRevert( +// // // abi.encodeWithSelector( +// // // InvalidModule.selector, +// // // recoveryModuleAddress +// // // ) +// // // ); +// // vm.expectRevert(); +// // emailRecoveryManager.completeRecovery(accountAddress, recoveryCalldata); +// } + +// function test_StaleRecoveryRequest() public { +// acceptGuardian(accountSalt1); +// acceptGuardian(accountSalt2); +// vm.warp(12 seconds); +// handleRecovery(newOwner, recoveryModuleAddress, accountSalt1); +// handleRecovery(newOwner, recoveryModuleAddress, accountSalt2); + +// vm.warp(10 weeks); + +// vm.expectRevert(IEmailRecoveryManager.RecoveryRequestExpired.selector); +// emailRecoveryManager.completeRecovery(accountAddress); + +// // Can cancel recovery even when stale +// vm.startPrank(accountAddress); +// emailRecoveryManager.cancelRecovery(bytes("")); +// vm.stopPrank(); + +// IEmailRecoveryManager.RecoveryRequest memory recoveryRequest = +// emailRecoveryManager.getRecoveryRequest(accountAddress); +// assertEq(recoveryRequest.executeAfter, 0); +// assertEq(recoveryRequest.executeBefore, 0); +// assertEq(recoveryRequest.currentWeight, 0); +// } +// } diff --git a/test/unit/EmailRecoveryManagerHarness.sol b/test/unit/EmailRecoveryManagerHarness.sol new file mode 100644 index 00000000..582a0849 --- /dev/null +++ b/test/unit/EmailRecoveryManagerHarness.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import "forge-std/console2.sol"; +import { EmailRecoveryManager } from "src/EmailRecoveryManager.sol"; + +contract EmailRecoveryManagerHarness is EmailRecoveryManager { + constructor( + address verifier, + address dkimRegistry, + address emailAuthImpl, + address subjectHandler + ) + EmailRecoveryManager(verifier, dkimRegistry, emailAuthImpl, subjectHandler) + { } + + function exposed_acceptGuardian( + address guardian, + uint256 templateIdx, + bytes[] memory subjectParams, + bytes32 nullifier + ) + external + { + acceptGuardian(guardian, templateIdx, subjectParams, nullifier); + } + + function exposed_processRecovery( + address guardian, + uint256 templateIdx, + bytes[] memory subjectParams, + bytes32 nullifier + ) + external + { + processRecovery(guardian, templateIdx, subjectParams, nullifier); + } + + function exposed_setupGuardians( + address account, + address[] memory guardians, + uint256[] memory weights, + uint256 threshold + ) + external + { + setupGuardians(account, guardians, weights, threshold); + } +} diff --git a/test/unit/UnitBase.t.sol b/test/unit/UnitBase.t.sol index c036ac8b..8b9fbcc9 100644 --- a/test/unit/UnitBase.t.sol +++ b/test/unit/UnitBase.t.sol @@ -14,8 +14,9 @@ import { } from "ether-email-auth/packages/contracts/src/EmailAuth.sol"; import { ECDSA } from "solady/utils/ECDSA.sol"; -import { ZkEmailRecoveryHarness } from "./ZkEmailRecoveryHarness.sol"; +import { EmailRecoveryManagerHarness } from "./EmailRecoveryManagerHarness.sol"; import { IEmailAccountRecovery } from "src/interfaces/IEmailAccountRecovery.sol"; +import { EmailRecoverySubjectHandler } from "src/handlers/EmailRecoverySubjectHandler.sol"; import { MockGroth16Verifier } from "src/test/MockGroth16Verifier.sol"; abstract contract UnitBase is RhinestoneModuleKit, Test { @@ -25,7 +26,8 @@ abstract contract UnitBase is RhinestoneModuleKit, Test { MockGroth16Verifier verifier; EmailAuth emailAuthImpl; - ZkEmailRecoveryHarness zkEmailRecovery; + EmailRecoverySubjectHandler emailRecoveryHandler; + EmailRecoveryManagerHarness emailRecoveryManager; // account and owners AccountInstance instance; @@ -78,9 +80,14 @@ abstract contract UnitBase is RhinestoneModuleKit, Test { address[] memory owners = new address[](1); owners[0] = owner; - // Deploy ZkEmailRecovery - zkEmailRecovery = new ZkEmailRecoveryHarness( - address(verifier), address(ecdsaOwnedDkimRegistry), address(emailAuthImpl) + emailRecoveryHandler = new EmailRecoverySubjectHandler(); + + // Deploy EmailRecoveryManager + emailRecoveryManager = new EmailRecoveryManagerHarness( + address(verifier), + address(ecdsaOwnedDkimRegistry), + address(emailAuthImpl), + address(emailRecoveryHandler) ); // Deploy and fund the account @@ -93,9 +100,9 @@ abstract contract UnitBase is RhinestoneModuleKit, Test { accountSalt3 = keccak256(abi.encode("account salt 3")); // Compute guardian addresses - guardian1 = zkEmailRecovery.computeEmailAuthAddress(accountSalt1); - guardian2 = zkEmailRecovery.computeEmailAuthAddress(accountSalt2); - guardian3 = zkEmailRecovery.computeEmailAuthAddress(accountSalt3); + guardian1 = emailRecoveryManager.computeEmailAuthAddress(accountSalt1); + guardian2 = emailRecoveryManager.computeEmailAuthAddress(accountSalt2); + guardian3 = emailRecoveryManager.computeEmailAuthAddress(accountSalt3); guardians = new address[](3); guardians[0] = guardian1; @@ -116,6 +123,38 @@ abstract contract UnitBase is RhinestoneModuleKit, Test { // Helper functions + function acceptanceSubjectTemplates() public pure returns (string[][] memory) { + string[][] memory templates = new string[][](1); + templates[0] = new string[](5); + templates[0][0] = "Accept"; + templates[0][1] = "guardian"; + templates[0][2] = "request"; + templates[0][3] = "for"; + templates[0][4] = "{ethAddr}"; + return templates; + } + + function recoverySubjectTemplates() public pure returns (string[][] memory) { + string[][] memory templates = new string[][](1); + templates[0] = new string[](15); + templates[0][0] = "Recover"; + templates[0][1] = "account"; + templates[0][2] = "{ethAddr}"; + templates[0][3] = "to"; + templates[0][4] = "new"; + templates[0][5] = "owner"; + templates[0][6] = "{ethAddr}"; + templates[0][7] = "using"; + templates[0][8] = "recovery"; + templates[0][9] = "module"; + templates[0][10] = "{ethAddr}"; + templates[0][11] = "and"; + templates[0][12] = "calldata"; + templates[0][13] = "hash"; + templates[0][14] = "{string}"; + return templates; + } + function generateMockEmailProof( string memory subject, bytes32 nullifier, @@ -147,7 +186,6 @@ abstract contract UnitBase is RhinestoneModuleKit, Test { // certain changes // console2.log("accountAddress: ", accountAddress); - address router = zkEmailRecovery.getRouterForAccount(accountAddress); string memory subject = "Accept guardian request for 0x50Bc6f1F08ff752F7F5d687F35a0fA25Ab20EF52"; bytes32 nullifier = keccak256(abi.encode("nullifier 1")); @@ -157,13 +195,13 @@ abstract contract UnitBase is RhinestoneModuleKit, Test { bytes[] memory subjectParamsForAcceptance = new bytes[](1); subjectParamsForAcceptance[0] = abi.encode(accountAddress); EmailAuthMsg memory emailAuthMsg = EmailAuthMsg({ - templateId: zkEmailRecovery.computeAcceptanceTemplateId(templateIdx), + templateId: emailRecoveryManager.computeAcceptanceTemplateId(templateIdx), subjectParams: subjectParamsForAcceptance, skipedSubjectPrefix: 0, proof: emailProof }); - IEmailAccountRecovery(router).handleAcceptance(emailAuthMsg, templateIdx); + emailRecoveryManager.handleAcceptance(emailAuthMsg, templateIdx); } function handleRecovery(address recoveryModule, bytes32 accountSalt) public { @@ -173,7 +211,6 @@ abstract contract UnitBase is RhinestoneModuleKit, Test { // console2.log("newOwner: ", newOwner); // console2.log("recoveryModule: ", recoveryModule); - address router = zkEmailRecovery.getRouterForAccount(accountAddress); string memory subject = "Recover account 0x50Bc6f1F08ff752F7F5d687F35a0fA25Ab20EF52 to new owner 0x7240b687730BE024bcfD084621f794C2e4F8408f using recovery module 0x07859195125c40eE1f7dA0A9B88D2eF19b633947"; bytes32 nullifier = keccak256(abi.encode("nullifier 2")); @@ -185,11 +222,11 @@ abstract contract UnitBase is RhinestoneModuleKit, Test { subjectParamsForRecovery[2] = abi.encode(recoveryModule); EmailAuthMsg memory emailAuthMsg = EmailAuthMsg({ - templateId: zkEmailRecovery.computeRecoveryTemplateId(templateIdx), + templateId: emailRecoveryManager.computeRecoveryTemplateId(templateIdx), subjectParams: subjectParamsForRecovery, skipedSubjectPrefix: 0, proof: emailProof }); - IEmailAccountRecovery(router).handleRecovery(emailAuthMsg, templateIdx); + emailRecoveryManager.handleRecovery(emailAuthMsg, templateIdx); } } diff --git a/test/unit/ZkEmailRecovery/acceptGuardian.t.sol b/test/unit/ZkEmailRecovery/acceptGuardian.t.sol index f58c8532..bf119505 100644 --- a/test/unit/ZkEmailRecovery/acceptGuardian.t.sol +++ b/test/unit/ZkEmailRecovery/acceptGuardian.t.sol @@ -4,8 +4,8 @@ pragma solidity ^0.8.25; import "forge-std/console2.sol"; import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; import { UnitBase } from "../UnitBase.t.sol"; import { OwnableValidator } from "src/test/OwnableValidator.sol"; @@ -15,15 +15,14 @@ contract ZkEmailRecovery_acceptGuardian_Test is UnitBase { using ModuleKitUserOp for *; OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; function setUp() public override { super.setUp(); validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule{ salt: "test salt" }(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); instance.installModule({ @@ -48,8 +47,10 @@ contract ZkEmailRecovery_acceptGuardian_Test is UnitBase { subjectParams[0] = abi.encode(accountAddress); bytes32 nullifier = keccak256(abi.encode("nullifier 1")); - vm.expectRevert(IZkEmailRecovery.RecoveryInProcess.selector); - zkEmailRecovery.exposed_acceptGuardian(guardian1, templateIdx, subjectParams, nullifier); + vm.expectRevert(IEmailRecoveryManager.RecoveryInProcess.selector); + emailRecoveryManager.exposed_acceptGuardian( + guardian1, templateIdx, subjectParams, nullifier + ); } function test_AcceptGuardian_RevertWhen_GuardianStatusIsNONE() public { @@ -63,12 +64,14 @@ contract ZkEmailRecovery_acceptGuardian_Test is UnitBase { vm.expectRevert( abi.encodeWithSelector( - IZkEmailRecovery.InvalidGuardianStatus.selector, + IEmailRecoveryManager.InvalidGuardianStatus.selector, uint256(GuardianStatus.NONE), uint256(GuardianStatus.REQUESTED) ) ); - zkEmailRecovery.exposed_acceptGuardian(guardian1, templateIdx, subjectParams, nullifier); + emailRecoveryManager.exposed_acceptGuardian( + guardian1, templateIdx, subjectParams, nullifier + ); } function test_AcceptGuardian_RevertWhen_GuardianStatusIsACCEPTED() public { @@ -76,16 +79,20 @@ contract ZkEmailRecovery_acceptGuardian_Test is UnitBase { subjectParams[0] = abi.encode(accountAddress); bytes32 nullifier = keccak256(abi.encode("nullifier 1")); - zkEmailRecovery.exposed_acceptGuardian(guardian1, templateIdx, subjectParams, nullifier); + emailRecoveryManager.exposed_acceptGuardian( + guardian1, templateIdx, subjectParams, nullifier + ); vm.expectRevert( abi.encodeWithSelector( - IZkEmailRecovery.InvalidGuardianStatus.selector, + IEmailRecoveryManager.InvalidGuardianStatus.selector, uint256(GuardianStatus.ACCEPTED), uint256(GuardianStatus.REQUESTED) ) ); - zkEmailRecovery.exposed_acceptGuardian(guardian1, templateIdx, subjectParams, nullifier); + emailRecoveryManager.exposed_acceptGuardian( + guardian1, templateIdx, subjectParams, nullifier + ); } function test_AcceptGuardian_Succeeds() public { @@ -93,10 +100,12 @@ contract ZkEmailRecovery_acceptGuardian_Test is UnitBase { subjectParams[0] = abi.encode(accountAddress); bytes32 nullifier = keccak256(abi.encode("nullifier 1")); - zkEmailRecovery.exposed_acceptGuardian(guardian1, templateIdx, subjectParams, nullifier); + emailRecoveryManager.exposed_acceptGuardian( + guardian1, templateIdx, subjectParams, nullifier + ); GuardianStorage memory guardianStorage = - zkEmailRecovery.getGuardian(accountAddress, guardian1); + emailRecoveryManager.getGuardian(accountAddress, guardian1); assertEq(uint256(guardianStorage.status), uint256(GuardianStatus.ACCEPTED)); assertEq(guardianStorage.weight, uint256(1)); } diff --git a/test/unit/ZkEmailRecovery/acceptanceSubjectTemplates.t.sol b/test/unit/ZkEmailRecovery/acceptanceSubjectTemplates.t.sol index 635826f1..7a5dbc7a 100644 --- a/test/unit/ZkEmailRecovery/acceptanceSubjectTemplates.t.sol +++ b/test/unit/ZkEmailRecovery/acceptanceSubjectTemplates.t.sol @@ -1,23 +1,23 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.25; -import "forge-std/console2.sol"; -import { UnitBase } from "../UnitBase.t.sol"; +// import "forge-std/console2.sol"; +// import { UnitBase } from "../UnitBase.t.sol"; -contract ZkEmailRecovery_acceptanceSubjectTemplates_Test is UnitBase { - function setUp() public override { - super.setUp(); - } +// contract ZkEmailRecovery_acceptanceSubjectTemplates_Test is UnitBase { +// function setUp() public override { +// super.setUp(); +// } - function test_AcceptanceSubjectTemplates_Succeeds() public view { - string[][] memory templates = zkEmailRecovery.acceptanceSubjectTemplates(); +// function test_AcceptanceSubjectTemplates_Succeeds() public view { +// string[][] memory templates = emailRecoveryManager.acceptanceSubjectTemplates(); - assertEq(templates.length, 1); - assertEq(templates[0].length, 5); - assertEq(templates[0][0], "Accept"); - assertEq(templates[0][1], "guardian"); - assertEq(templates[0][2], "request"); - assertEq(templates[0][3], "for"); - assertEq(templates[0][4], "{ethAddr}"); - } -} +// assertEq(templates.length, 1); +// assertEq(templates[0].length, 5); +// assertEq(templates[0][0], "Accept"); +// assertEq(templates[0][1], "guardian"); +// assertEq(templates[0][2], "request"); +// assertEq(templates[0][3], "for"); +// assertEq(templates[0][4], "{ethAddr}"); +// } +// } diff --git a/test/unit/ZkEmailRecovery/addGuardian.t.sol b/test/unit/ZkEmailRecovery/addGuardian.t.sol index faaaa0b3..e8334a12 100644 --- a/test/unit/ZkEmailRecovery/addGuardian.t.sol +++ b/test/unit/ZkEmailRecovery/addGuardian.t.sol @@ -5,8 +5,8 @@ import "forge-std/console2.sol"; import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; import { UnitBase } from "../UnitBase.t.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; import { OwnableValidator } from "src/test/OwnableValidator.sol"; @@ -15,15 +15,14 @@ contract ZkEmailRecovery_addGuardian_Test is UnitBase { using ModuleKitUserOp for *; OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; function setUp() public override { super.setUp(); validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule{ salt: "test salt" }(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); instance.installModule({ @@ -45,8 +44,8 @@ contract ZkEmailRecovery_addGuardian_Test is UnitBase { handleRecovery(recoveryModuleAddress, accountSalt1); vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.RecoveryInProcess.selector); - zkEmailRecovery.addGuardian(guardians[0], guardianWeights[0], threshold); + vm.expectRevert(IEmailRecoveryManager.RecoveryInProcess.selector); + emailRecoveryManager.addGuardian(guardians[0], guardianWeights[0], threshold); } function test_AddGuardian_RevertWhen_SetupNotCalled() public { @@ -55,8 +54,8 @@ contract ZkEmailRecovery_addGuardian_Test is UnitBase { vm.stopPrank(); vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.SetupNotCalled.selector); - zkEmailRecovery.addGuardian(guardians[0], guardianWeights[0], threshold); + vm.expectRevert(IEmailRecoveryManager.SetupNotCalled.selector); + emailRecoveryManager.addGuardian(guardians[0], guardianWeights[0], threshold); } function test_AddGuardian_RevertWhen_InvalidGuardianAddress() public { @@ -64,8 +63,8 @@ contract ZkEmailRecovery_addGuardian_Test is UnitBase { vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.InvalidGuardianAddress.selector); - zkEmailRecovery.addGuardian(invalidGuardianAddress, guardianWeights[0], threshold); + vm.expectRevert(IEmailRecoveryManager.InvalidGuardianAddress.selector); + emailRecoveryManager.addGuardian(invalidGuardianAddress, guardianWeights[0], threshold); } function test_AddGuardian_RevertWhen_GuardianAddressIsAccountAddress() public { @@ -73,15 +72,15 @@ contract ZkEmailRecovery_addGuardian_Test is UnitBase { vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.InvalidGuardianAddress.selector); - zkEmailRecovery.addGuardian(invalidGuardianAddress, guardianWeights[0], threshold); + vm.expectRevert(IEmailRecoveryManager.InvalidGuardianAddress.selector); + emailRecoveryManager.addGuardian(invalidGuardianAddress, guardianWeights[0], threshold); } function test_AddGuardian_RevertWhen_AddressAlreadyGuardian() public { vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.AddressAlreadyGuardian.selector); - zkEmailRecovery.addGuardian(guardians[0], guardianWeights[0], threshold); + vm.expectRevert(IEmailRecoveryManager.AddressAlreadyGuardian.selector); + emailRecoveryManager.addGuardian(guardians[0], guardianWeights[0], threshold); } function test_AddGuardian_RevertWhen_InvalidGuardianWeight() public { @@ -90,8 +89,8 @@ contract ZkEmailRecovery_addGuardian_Test is UnitBase { vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.InvalidGuardianWeight.selector); - zkEmailRecovery.addGuardian(newGuardian, invalidGuardianWeight, threshold); + vm.expectRevert(IEmailRecoveryManager.InvalidGuardianWeight.selector); + emailRecoveryManager.addGuardian(newGuardian, invalidGuardianWeight, threshold); } function test_AddGuardian_AddGuardian_SameThreshold() public { @@ -105,16 +104,16 @@ contract ZkEmailRecovery_addGuardian_Test is UnitBase { vm.startPrank(accountAddress); vm.expectEmit(); - emit IZkEmailRecovery.AddedGuardian(accountAddress, newGuardian); - zkEmailRecovery.addGuardian(newGuardian, newGuardianWeight, threshold); + emit IEmailRecoveryManager.AddedGuardian(accountAddress, newGuardian); + emailRecoveryManager.addGuardian(newGuardian, newGuardianWeight, threshold); GuardianStorage memory guardianStorage = - zkEmailRecovery.getGuardian(accountAddress, newGuardian); + emailRecoveryManager.getGuardian(accountAddress, newGuardian); assertEq(uint256(guardianStorage.status), uint256(GuardianStatus.REQUESTED)); assertEq(guardianStorage.weight, newGuardianWeight); - IZkEmailRecovery.GuardianConfig memory guardianConfig = - zkEmailRecovery.getGuardianConfig(accountAddress); + IEmailRecoveryManager.GuardianConfig memory guardianConfig = + emailRecoveryManager.getGuardianConfig(accountAddress); assertEq(guardianConfig.guardianCount, expectedGuardianCount); assertEq(guardianConfig.totalWeight, expectedTotalWeight); assertEq(guardianConfig.threshold, expectedThreshold); @@ -129,10 +128,10 @@ contract ZkEmailRecovery_addGuardian_Test is UnitBase { vm.startPrank(accountAddress); - zkEmailRecovery.addGuardian(newGuardian, newGuardianWeight, newThreshold); + emailRecoveryManager.addGuardian(newGuardian, newGuardianWeight, newThreshold); - IZkEmailRecovery.GuardianConfig memory guardianConfig = - zkEmailRecovery.getGuardianConfig(accountAddress); + IEmailRecoveryManager.GuardianConfig memory guardianConfig = + emailRecoveryManager.getGuardianConfig(accountAddress); assertEq(guardianConfig.threshold, expectedThreshold); } } diff --git a/test/unit/ZkEmailRecovery/cancelRecovery.t.sol b/test/unit/ZkEmailRecovery/cancelRecovery.t.sol index 33299f2e..49e70fd9 100644 --- a/test/unit/ZkEmailRecovery/cancelRecovery.t.sol +++ b/test/unit/ZkEmailRecovery/cancelRecovery.t.sol @@ -5,8 +5,8 @@ import "forge-std/console2.sol"; import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; import { UnitBase } from "../UnitBase.t.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; import { OwnableValidator } from "src/test/OwnableValidator.sol"; contract ZkEmailRecovery_cancelRecovery_Test is UnitBase { @@ -14,15 +14,14 @@ contract ZkEmailRecovery_cancelRecovery_Test is UnitBase { using ModuleKitUserOp for *; OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; function setUp() public override { super.setUp(); validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule{ salt: "test salt" }(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); instance.installModule({ @@ -45,21 +44,19 @@ contract ZkEmailRecovery_cancelRecovery_Test is UnitBase { vm.warp(12 seconds); handleRecovery(recoveryModuleAddress, accountSalt1); - IZkEmailRecovery.RecoveryRequest memory recoveryRequest = - zkEmailRecovery.getRecoveryRequest(accountAddress); + IEmailRecoveryManager.RecoveryRequest memory recoveryRequest = + emailRecoveryManager.getRecoveryRequest(accountAddress); assertEq(recoveryRequest.executeAfter, 0); assertEq(recoveryRequest.executeBefore, 0); assertEq(recoveryRequest.currentWeight, 1); - assertEq(recoveryRequest.subjectParams.length, 0); vm.startPrank(otherAddress); - zkEmailRecovery.cancelRecovery(""); + emailRecoveryManager.cancelRecovery(""); - recoveryRequest = zkEmailRecovery.getRecoveryRequest(accountAddress); + recoveryRequest = emailRecoveryManager.getRecoveryRequest(accountAddress); assertEq(recoveryRequest.executeAfter, 0); assertEq(recoveryRequest.executeBefore, 0); assertEq(recoveryRequest.currentWeight, 1); - assertEq(recoveryRequest.subjectParams.length, 0); } function test_CancelRecovery_PartialRequest_Succeeds() public { @@ -67,21 +64,19 @@ contract ZkEmailRecovery_cancelRecovery_Test is UnitBase { vm.warp(12 seconds); handleRecovery(recoveryModuleAddress, accountSalt1); - IZkEmailRecovery.RecoveryRequest memory recoveryRequest = - zkEmailRecovery.getRecoveryRequest(accountAddress); + IEmailRecoveryManager.RecoveryRequest memory recoveryRequest = + emailRecoveryManager.getRecoveryRequest(accountAddress); assertEq(recoveryRequest.executeAfter, 0); assertEq(recoveryRequest.executeBefore, 0); assertEq(recoveryRequest.currentWeight, 1); - assertEq(recoveryRequest.subjectParams.length, 0); vm.startPrank(accountAddress); - zkEmailRecovery.cancelRecovery(""); + emailRecoveryManager.cancelRecovery(""); - recoveryRequest = zkEmailRecovery.getRecoveryRequest(accountAddress); + recoveryRequest = emailRecoveryManager.getRecoveryRequest(accountAddress); assertEq(recoveryRequest.executeAfter, 0); assertEq(recoveryRequest.executeBefore, 0); assertEq(recoveryRequest.currentWeight, 0); - assertEq(recoveryRequest.subjectParams.length, 0); } function test_CancelRecovery_FullRequest_Succeeds() public { @@ -91,23 +86,18 @@ contract ZkEmailRecovery_cancelRecovery_Test is UnitBase { handleRecovery(recoveryModuleAddress, accountSalt1); handleRecovery(recoveryModuleAddress, accountSalt2); - IZkEmailRecovery.RecoveryRequest memory recoveryRequest = - zkEmailRecovery.getRecoveryRequest(accountAddress); + IEmailRecoveryManager.RecoveryRequest memory recoveryRequest = + emailRecoveryManager.getRecoveryRequest(accountAddress); assertEq(recoveryRequest.executeAfter, block.timestamp + delay); assertEq(recoveryRequest.executeBefore, block.timestamp + expiry); assertEq(recoveryRequest.currentWeight, 3); - assertEq(recoveryRequest.subjectParams.length, 3); - assertEq(recoveryRequest.subjectParams[0], abi.encode(accountAddress)); - assertEq(recoveryRequest.subjectParams[1], abi.encode(newOwner)); - assertEq(recoveryRequest.subjectParams[2], abi.encode(recoveryModuleAddress)); vm.startPrank(accountAddress); - zkEmailRecovery.cancelRecovery(""); + emailRecoveryManager.cancelRecovery(""); - recoveryRequest = zkEmailRecovery.getRecoveryRequest(accountAddress); + recoveryRequest = emailRecoveryManager.getRecoveryRequest(accountAddress); assertEq(recoveryRequest.executeAfter, 0); assertEq(recoveryRequest.executeBefore, 0); assertEq(recoveryRequest.currentWeight, 0); - assertEq(recoveryRequest.subjectParams.length, 0); } } diff --git a/test/unit/ZkEmailRecovery/changeThreshold.t.sol b/test/unit/ZkEmailRecovery/changeThreshold.t.sol index 4ee00edd..e1b920db 100644 --- a/test/unit/ZkEmailRecovery/changeThreshold.t.sol +++ b/test/unit/ZkEmailRecovery/changeThreshold.t.sol @@ -5,8 +5,8 @@ import "forge-std/console2.sol"; import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; import { UnitBase } from "../UnitBase.t.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; import { OwnableValidator } from "src/test/OwnableValidator.sol"; contract ZkEmailRecovery_changeThreshold_Test is UnitBase { @@ -14,15 +14,14 @@ contract ZkEmailRecovery_changeThreshold_Test is UnitBase { using ModuleKitUserOp for *; OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; function setUp() public override { super.setUp(); validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule{ salt: "test salt" }(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); instance.installModule({ @@ -44,29 +43,29 @@ contract ZkEmailRecovery_changeThreshold_Test is UnitBase { handleRecovery(recoveryModuleAddress, accountSalt1); vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.RecoveryInProcess.selector); - zkEmailRecovery.changeThreshold(threshold); + vm.expectRevert(IEmailRecoveryManager.RecoveryInProcess.selector); + emailRecoveryManager.changeThreshold(threshold); } function test_RevertWhen_SetupNotCalled() public { - vm.expectRevert(IZkEmailRecovery.SetupNotCalled.selector); - zkEmailRecovery.changeThreshold(threshold); + vm.expectRevert(IEmailRecoveryManager.SetupNotCalled.selector); + emailRecoveryManager.changeThreshold(threshold); } function test_RevertWhen_ThresholdExceedsTotalWeight() public { uint256 highThreshold = totalWeight + 1; vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.ThresholdCannotExceedTotalWeight.selector); - zkEmailRecovery.changeThreshold(highThreshold); + vm.expectRevert(IEmailRecoveryManager.ThresholdCannotExceedTotalWeight.selector); + emailRecoveryManager.changeThreshold(highThreshold); } function test_RevertWhen_ThresholdIsZero() public { uint256 zeroThreshold = 0; vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.ThresholdCannotBeZero.selector); - zkEmailRecovery.changeThreshold(zeroThreshold); + vm.expectRevert(IEmailRecoveryManager.ThresholdCannotBeZero.selector); + emailRecoveryManager.changeThreshold(zeroThreshold); } function test_ChangeThreshold_IncreaseThreshold() public { @@ -74,11 +73,11 @@ contract ZkEmailRecovery_changeThreshold_Test is UnitBase { vm.startPrank(accountAddress); vm.expectEmit(); - emit IZkEmailRecovery.ChangedThreshold(accountAddress, newThreshold); - zkEmailRecovery.changeThreshold(newThreshold); + emit IEmailRecoveryManager.ChangedThreshold(accountAddress, newThreshold); + emailRecoveryManager.changeThreshold(newThreshold); - IZkEmailRecovery.GuardianConfig memory guardianConfig = - zkEmailRecovery.getGuardianConfig(accountAddress); + IEmailRecoveryManager.GuardianConfig memory guardianConfig = + emailRecoveryManager.getGuardianConfig(accountAddress); assertEq(guardianConfig.guardianCount, guardians.length); assertEq(guardianConfig.threshold, newThreshold); } @@ -88,11 +87,11 @@ contract ZkEmailRecovery_changeThreshold_Test is UnitBase { vm.startPrank(accountAddress); vm.expectEmit(); - emit IZkEmailRecovery.ChangedThreshold(accountAddress, newThreshold); - zkEmailRecovery.changeThreshold(newThreshold); + emit IEmailRecoveryManager.ChangedThreshold(accountAddress, newThreshold); + emailRecoveryManager.changeThreshold(newThreshold); - IZkEmailRecovery.GuardianConfig memory guardianConfig = - zkEmailRecovery.getGuardianConfig(accountAddress); + IEmailRecoveryManager.GuardianConfig memory guardianConfig = + emailRecoveryManager.getGuardianConfig(accountAddress); assertEq(guardianConfig.guardianCount, guardians.length); assertEq(guardianConfig.threshold, newThreshold); } diff --git a/test/unit/ZkEmailRecovery/completeRecovery.t.sol b/test/unit/ZkEmailRecovery/completeRecovery.t.sol index dc8734dd..6d8d5e81 100644 --- a/test/unit/ZkEmailRecovery/completeRecovery.t.sol +++ b/test/unit/ZkEmailRecovery/completeRecovery.t.sol @@ -6,25 +6,26 @@ import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; import { UnitBase } from "../UnitBase.t.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; import { OwnableValidator } from "src/test/OwnableValidator.sol"; -// completeRecovery() +// completeRecovery(accountAddress, recoveryCalldata) contract ZkEmailRecovery_completeRecovery_Test is UnitBase { using ModuleKitHelpers for *; using ModuleKitUserOp for *; OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; + bytes recoveryCalldata; + function setUp() public override { super.setUp(); validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule{ salt: "test salt" }(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); instance.installModule({ @@ -38,6 +39,10 @@ contract ZkEmailRecovery_completeRecovery_Test is UnitBase { module: recoveryModuleAddress, data: abi.encode(address(validator), guardians, guardianWeights, threshold, delay, expiry) }); + + recoveryCalldata = abi.encodeWithSignature( + "changeOwner(address,address,address)", accountAddress, recoveryModuleAddress, newOwner + ); } function test_CompleteRecovery_RevertWhen_NotCalledFromCorrectRouter() public { @@ -49,13 +54,11 @@ contract ZkEmailRecovery_completeRecovery_Test is UnitBase { vm.warp(block.timestamp + delay); - vm.expectRevert(IZkEmailRecovery.InvalidAccountAddress.selector); - zkEmailRecovery.completeRecovery(); + vm.expectRevert(IEmailRecoveryManager.InvalidAccountAddress.selector); + emailRecoveryManager.completeRecovery(accountAddress, recoveryCalldata); } function test_CompleteRecovery_Succeeds() public { - address router = zkEmailRecovery.getRouterForAccount(accountAddress); - acceptGuardian(accountSalt1); acceptGuardian(accountSalt2); vm.warp(12 seconds); @@ -64,15 +67,13 @@ contract ZkEmailRecovery_completeRecovery_Test is UnitBase { vm.warp(block.timestamp + delay); - vm.prank(router); - zkEmailRecovery.completeRecovery(); + emailRecoveryManager.completeRecovery(accountAddress, recoveryCalldata); - IZkEmailRecovery.RecoveryRequest memory recoveryRequest = - zkEmailRecovery.getRecoveryRequest(accountAddress); + IEmailRecoveryManager.RecoveryRequest memory recoveryRequest = + emailRecoveryManager.getRecoveryRequest(accountAddress); assertEq(recoveryRequest.executeAfter, 0); assertEq(recoveryRequest.executeBefore, 0); assertEq(recoveryRequest.currentWeight, 0); - assertEq(recoveryRequest.subjectParams.length, 0); } } @@ -82,15 +83,16 @@ contract ZkEmailRecovery_completeRecoveryWithAddress_Test is UnitBase { using ModuleKitUserOp for *; OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; + bytes recoveryCalldata; + function setUp() public override { super.setUp(); validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule{ salt: "test salt" }(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); instance.installModule({ @@ -104,13 +106,17 @@ contract ZkEmailRecovery_completeRecoveryWithAddress_Test is UnitBase { module: recoveryModuleAddress, data: abi.encode(address(validator), guardians, guardianWeights, threshold, delay, expiry) }); + + recoveryCalldata = abi.encodeWithSignature( + "changeOwner(address,address,address)", accountAddress, recoveryModuleAddress, newOwner + ); } function test_CompleteRecovery_RevertWhen_InvalidAccountAddress() public { address invalidAccount = address(0); - vm.expectRevert(IZkEmailRecovery.InvalidAccountAddress.selector); - zkEmailRecovery.completeRecovery(invalidAccount); + vm.expectRevert(IEmailRecoveryManager.InvalidAccountAddress.selector); + emailRecoveryManager.completeRecovery(invalidAccount, recoveryCalldata); } function test_CompleteRecovery_RevertWhen_NotEnoughApprovals() public { @@ -119,8 +125,8 @@ contract ZkEmailRecovery_completeRecoveryWithAddress_Test is UnitBase { handleRecovery(recoveryModuleAddress, accountSalt1); // only one guardian added and one // approval - vm.expectRevert(IZkEmailRecovery.NotEnoughApprovals.selector); - zkEmailRecovery.completeRecovery(accountAddress); + vm.expectRevert(IEmailRecoveryManager.NotEnoughApprovals.selector); + emailRecoveryManager.completeRecovery(accountAddress, recoveryCalldata); } function test_CompleteRecovery_RevertWhen_DelayNotPassed() public { @@ -132,8 +138,8 @@ contract ZkEmailRecovery_completeRecoveryWithAddress_Test is UnitBase { vm.warp(block.timestamp + delay - 1 seconds); // one second before it should be valid - vm.expectRevert(IZkEmailRecovery.DelayNotPassed.selector); - zkEmailRecovery.completeRecovery(accountAddress); + vm.expectRevert(IEmailRecoveryManager.DelayNotPassed.selector); + emailRecoveryManager.completeRecovery(accountAddress, recoveryCalldata); } function test_CompleteRecovery_RevertWhen_RecoveryRequestExpiredAndTimestampEqualToExpiry() @@ -147,8 +153,8 @@ contract ZkEmailRecovery_completeRecoveryWithAddress_Test is UnitBase { vm.warp(block.timestamp + expiry); // block.timestamp == recoveryRequest.executeBefore - vm.expectRevert(IZkEmailRecovery.RecoveryRequestExpired.selector); - zkEmailRecovery.completeRecovery(accountAddress); + vm.expectRevert(IEmailRecoveryManager.RecoveryRequestExpired.selector); + emailRecoveryManager.completeRecovery(accountAddress, recoveryCalldata); } function test_CompleteRecovery_RevertWhen_RecoveryRequestExpiredAndTimestampMoreThanExpiry() @@ -163,8 +169,8 @@ contract ZkEmailRecovery_completeRecoveryWithAddress_Test is UnitBase { vm.warp(block.timestamp + expiry + 1 seconds); // block.timestamp > // recoveryRequest.executeBefore - vm.expectRevert(IZkEmailRecovery.RecoveryRequestExpired.selector); - zkEmailRecovery.completeRecovery(accountAddress); + vm.expectRevert(IEmailRecoveryManager.RecoveryRequestExpired.selector); + emailRecoveryManager.completeRecovery(accountAddress, recoveryCalldata); } function test_CompleteRecovery_CompleteRecovery_Succeeds() public { @@ -177,15 +183,14 @@ contract ZkEmailRecovery_completeRecoveryWithAddress_Test is UnitBase { vm.warp(block.timestamp + delay); vm.expectEmit(); - emit IZkEmailRecovery.RecoveryCompleted(accountAddress); - zkEmailRecovery.completeRecovery(accountAddress); + emit IEmailRecoveryManager.RecoveryCompleted(accountAddress); + emailRecoveryManager.completeRecovery(accountAddress, recoveryCalldata); - IZkEmailRecovery.RecoveryRequest memory recoveryRequest = - zkEmailRecovery.getRecoveryRequest(accountAddress); + IEmailRecoveryManager.RecoveryRequest memory recoveryRequest = + emailRecoveryManager.getRecoveryRequest(accountAddress); assertEq(recoveryRequest.executeAfter, 0); assertEq(recoveryRequest.executeBefore, 0); assertEq(recoveryRequest.currentWeight, 0); - assertEq(recoveryRequest.subjectParams.length, 0); } function test_CompleteRecovery_SucceedsAlmostExpiry() public { @@ -198,14 +203,13 @@ contract ZkEmailRecovery_completeRecoveryWithAddress_Test is UnitBase { vm.warp(block.timestamp + expiry - 1 seconds); vm.expectEmit(); - emit IZkEmailRecovery.RecoveryCompleted(accountAddress); - zkEmailRecovery.completeRecovery(accountAddress); + emit IEmailRecoveryManager.RecoveryCompleted(accountAddress); + emailRecoveryManager.completeRecovery(accountAddress, recoveryCalldata); - IZkEmailRecovery.RecoveryRequest memory recoveryRequest = - zkEmailRecovery.getRecoveryRequest(accountAddress); + IEmailRecoveryManager.RecoveryRequest memory recoveryRequest = + emailRecoveryManager.getRecoveryRequest(accountAddress); assertEq(recoveryRequest.executeAfter, 0); assertEq(recoveryRequest.executeBefore, 0); assertEq(recoveryRequest.currentWeight, 0); - assertEq(recoveryRequest.subjectParams.length, 0); } } diff --git a/test/unit/ZkEmailRecovery/computeRouterAddress.t.sol b/test/unit/ZkEmailRecovery/computeRouterAddress.t.sol deleted file mode 100644 index 748f7c16..00000000 --- a/test/unit/ZkEmailRecovery/computeRouterAddress.t.sol +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; - -import "forge-std/console2.sol"; -import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; -import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; -import { UnitBase } from "../UnitBase.t.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; -import { OwnableValidator } from "src/test/OwnableValidator.sol"; - -contract ZkEmailRecovery_computeRouterAddress_Test is UnitBase { - using ModuleKitHelpers for *; - using ModuleKitUserOp for *; - - OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; - address recoveryModuleAddress; - - function setUp() public override { - super.setUp(); - - validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); - recoveryModuleAddress = address(recoveryModule); - - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: address(validator), - data: abi.encode(owner, recoveryModuleAddress) - }); - // Install recovery module - configureRecovery is called on `onInstall` - instance.installModule({ - moduleTypeId: MODULE_TYPE_EXECUTOR, - module: recoveryModuleAddress, - data: abi.encode(address(validator), guardians, guardianWeights, threshold, delay, expiry) - }); - } - - function test_ComputeRouterAddress_FailsWhen_InvalidSalt() public { - bytes32 salt = keccak256(abi.encode("I'm not the right salt")); - address router = zkEmailRecovery.computeRouterAddress(salt); - - address expectedRouter = zkEmailRecovery.getRouterForAccount(accountAddress); - - assertNotEq(router, expectedRouter); - } - - function test_ComputeRouterAddress_FailsWhen_CorrectSaltValueButWrongEncoding() public { - bytes32 salt = keccak256(abi.encodePacked(accountAddress)); - address router = zkEmailRecovery.computeRouterAddress(salt); - - address expectedRouter = zkEmailRecovery.getRouterForAccount(accountAddress); - - assertNotEq(router, expectedRouter); - } - - function test_ComputeRouterAddress_Succeeds() public { - bytes32 salt = keccak256(abi.encode(accountAddress)); - address router = zkEmailRecovery.computeRouterAddress(salt); - - address expectedRouter = zkEmailRecovery.getRouterForAccount(accountAddress); - - assertEq(router, expectedRouter); - } -} diff --git a/test/unit/ZkEmailRecovery/configureRecovery.t.sol b/test/unit/ZkEmailRecovery/configureRecovery.t.sol index 991f6172..d000c5b2 100644 --- a/test/unit/ZkEmailRecovery/configureRecovery.t.sol +++ b/test/unit/ZkEmailRecovery/configureRecovery.t.sol @@ -5,8 +5,8 @@ import "forge-std/console2.sol"; import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; import { OwnableValidator } from "src/test/OwnableValidator.sol"; import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; import { UnitBase } from "../UnitBase.t.sol"; @@ -17,15 +17,14 @@ contract ZkEmailRecovery_configureRecovery_Test is UnitBase { using ModuleKitUserOp for *; OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; function setUp() public override { super.setUp(); validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule{ salt: "test salt" }(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); instance.installModule({ @@ -37,7 +36,16 @@ contract ZkEmailRecovery_configureRecovery_Test is UnitBase { instance.installModule({ moduleTypeId: MODULE_TYPE_EXECUTOR, module: recoveryModuleAddress, - data: abi.encode(address(validator), guardians, guardianWeights, threshold, delay, expiry) + data: abi.encode( + address(validator), + guardians, + guardianWeights, + threshold, + delay, + expiry, + acceptanceSubjectTemplates(), + recoverySubjectTemplates() + ) }); } @@ -46,9 +54,9 @@ contract ZkEmailRecovery_configureRecovery_Test is UnitBase { vm.warp(12 seconds); handleRecovery(recoveryModuleAddress, accountSalt1); - vm.expectRevert(IZkEmailRecovery.SetupAlreadyCalled.selector); + vm.expectRevert(IEmailRecoveryManager.SetupAlreadyCalled.selector); vm.startPrank(accountAddress); - zkEmailRecovery.configureRecovery( + emailRecoveryManager.configureRecovery( recoveryModuleAddress, guardians, guardianWeights, threshold, delay, expiry ); vm.stopPrank(); @@ -58,8 +66,8 @@ contract ZkEmailRecovery_configureRecovery_Test is UnitBase { function test_ConfigureRecovery_RevertWhen_ConfigureRecoveryCalledTwice() public { vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.SetupAlreadyCalled.selector); - zkEmailRecovery.configureRecovery( + vm.expectRevert(IEmailRecoveryManager.SetupAlreadyCalled.selector); + emailRecoveryManager.configureRecovery( recoveryModuleAddress, guardians, guardianWeights, threshold, delay, expiry ); vm.stopPrank(); @@ -70,41 +78,42 @@ contract ZkEmailRecovery_configureRecovery_Test is UnitBase { instance.uninstallModule(MODULE_TYPE_EXECUTOR, recoveryModuleAddress, ""); vm.stopPrank(); - address expectedRouterAddress = - zkEmailRecovery.computeRouterAddress(keccak256(abi.encode(accountAddress))); - // Install recovery module - configureRecovery is called on `onInstall` vm.prank(accountAddress); vm.expectEmit(); - emit IZkEmailRecovery.RecoveryConfigured( - accountAddress, recoveryModuleAddress, guardians.length, expectedRouterAddress + emit IEmailRecoveryManager.RecoveryConfigured( + accountAddress, recoveryModuleAddress, guardians.length ); instance.installModule({ moduleTypeId: MODULE_TYPE_EXECUTOR, module: recoveryModuleAddress, - data: abi.encode(address(validator), guardians, guardianWeights, threshold, delay, expiry) + data: abi.encode( + address(validator), + guardians, + guardianWeights, + threshold, + delay, + expiry, + acceptanceSubjectTemplates(), + recoverySubjectTemplates() + ) }); vm.stopPrank(); - IZkEmailRecovery.RecoveryConfig memory recoveryConfig = - zkEmailRecovery.getRecoveryConfig(accountAddress); + IEmailRecoveryManager.RecoveryConfig memory recoveryConfig = + emailRecoveryManager.getRecoveryConfig(accountAddress); assertEq(recoveryConfig.recoveryModule, recoveryModuleAddress); assertEq(recoveryConfig.delay, delay); assertEq(recoveryConfig.expiry, expiry); - IZkEmailRecovery.GuardianConfig memory guardianConfig = - zkEmailRecovery.getGuardianConfig(accountAddress); + IEmailRecoveryManager.GuardianConfig memory guardianConfig = + emailRecoveryManager.getGuardianConfig(accountAddress); assertEq(guardianConfig.guardianCount, guardians.length); assertEq(guardianConfig.threshold, threshold); - GuardianStorage memory guardian = zkEmailRecovery.getGuardian(accountAddress, guardians[0]); + GuardianStorage memory guardian = + emailRecoveryManager.getGuardian(accountAddress, guardians[0]); assertEq(uint256(guardian.status), uint256(GuardianStatus.REQUESTED)); assertEq(guardian.weight, guardianWeights[0]); - - address accountForRouter = zkEmailRecovery.getAccountForRouter(expectedRouterAddress); - assertEq(accountForRouter, accountAddress); - - address routerForAccount = zkEmailRecovery.getRouterForAccount(accountAddress); - assertEq(routerForAccount, expectedRouterAddress); } } diff --git a/test/unit/ZkEmailRecovery/constructor.t.sol b/test/unit/ZkEmailRecovery/constructor.t.sol index f4110778..b1e0cea3 100644 --- a/test/unit/ZkEmailRecovery/constructor.t.sol +++ b/test/unit/ZkEmailRecovery/constructor.t.sol @@ -3,7 +3,8 @@ pragma solidity ^0.8.25; import "forge-std/console2.sol"; import { UnitBase } from "../UnitBase.t.sol"; -import { ZkEmailRecovery } from "src/ZkEmailRecovery.sol"; +import { EmailRecoveryManager } from "src/EmailRecoveryManager.sol"; +import { EmailRecoverySubjectHandler } from "src/handlers/EmailRecoverySubjectHandler.sol"; contract ZkEmailRecovery_constructor_Test is UnitBase { function setUp() public override { @@ -11,12 +12,15 @@ contract ZkEmailRecovery_constructor_Test is UnitBase { } function test_Constructor() public { - ZkEmailRecovery zkEmailRecovery = new ZkEmailRecovery( - address(verifier), address(ecdsaOwnedDkimRegistry), address(emailAuthImpl) + EmailRecoveryManager emailRecoveryManager = new EmailRecoveryManager( + address(verifier), + address(ecdsaOwnedDkimRegistry), + address(emailAuthImpl), + address(emailRecoveryHandler) ); - assertEq(address(verifier), zkEmailRecovery.verifier()); - assertEq(address(ecdsaOwnedDkimRegistry), zkEmailRecovery.dkim()); - assertEq(address(emailAuthImpl), zkEmailRecovery.emailAuthImplementation()); + assertEq(address(verifier), emailRecoveryManager.verifier()); + assertEq(address(ecdsaOwnedDkimRegistry), emailRecoveryManager.dkim()); + assertEq(address(emailAuthImpl), emailRecoveryManager.emailAuthImplementation()); } } diff --git a/test/unit/ZkEmailRecovery/deInitRecoveryFromModule.t.sol b/test/unit/ZkEmailRecovery/deInitRecoveryFromModule.t.sol index 6d7c7723..134b4673 100644 --- a/test/unit/ZkEmailRecovery/deInitRecoveryFromModule.t.sol +++ b/test/unit/ZkEmailRecovery/deInitRecoveryFromModule.t.sol @@ -6,9 +6,9 @@ import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; import { UnitBase } from "../UnitBase.t.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; import { OwnableValidator } from "src/test/OwnableValidator.sol"; contract ZkEmailRecovery_deInitRecoveryFromModule_Test is UnitBase { @@ -16,15 +16,14 @@ contract ZkEmailRecovery_deInitRecoveryFromModule_Test is UnitBase { using ModuleKitUserOp for *; OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; function setUp() public override { super.setUp(); validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule{ salt: "test salt" }(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); instance.installModule({ @@ -41,8 +40,8 @@ contract ZkEmailRecovery_deInitRecoveryFromModule_Test is UnitBase { } function test_DeInitRecoveryFromModule_RevertWhen_NotCalledFromRecoveryModule() public { - vm.expectRevert(IZkEmailRecovery.NotRecoveryModule.selector); - zkEmailRecovery.deInitRecoveryFromModule(accountAddress); + vm.expectRevert(IEmailRecoveryManager.NotRecoveryModule.selector); + emailRecoveryManager.deInitRecoveryFromModule(accountAddress); } function test_DeInitRecoveryFromModule_RevertWhen_RecoveryInProcess() public { @@ -51,59 +50,50 @@ contract ZkEmailRecovery_deInitRecoveryFromModule_Test is UnitBase { handleRecovery(recoveryModuleAddress, accountSalt1); vm.prank(recoveryModuleAddress); - vm.expectRevert(IZkEmailRecovery.RecoveryInProcess.selector); - zkEmailRecovery.deInitRecoveryFromModule(accountAddress); + vm.expectRevert(IEmailRecoveryManager.RecoveryInProcess.selector); + emailRecoveryManager.deInitRecoveryFromModule(accountAddress); } function test_DeInitRecoveryFromModule_Succeeds() public { - address router = zkEmailRecovery.getRouterForAccount(accountAddress); - acceptGuardian(accountSalt1); acceptGuardian(accountSalt2); vm.prank(recoveryModuleAddress); vm.expectEmit(); - emit IZkEmailRecovery.RecoveryDeInitialized(accountAddress); - zkEmailRecovery.deInitRecoveryFromModule(accountAddress); + emit IEmailRecoveryManager.RecoveryDeInitialized(accountAddress); + emailRecoveryManager.deInitRecoveryFromModule(accountAddress); // assert that recovery config has been cleared successfully - IZkEmailRecovery.RecoveryConfig memory recoveryConfig = - zkEmailRecovery.getRecoveryConfig(accountAddress); + IEmailRecoveryManager.RecoveryConfig memory recoveryConfig = + emailRecoveryManager.getRecoveryConfig(accountAddress); assertEq(recoveryConfig.recoveryModule, address(0)); assertEq(recoveryConfig.delay, 0); assertEq(recoveryConfig.expiry, 0); // assert that the recovery request has been cleared successfully - IZkEmailRecovery.RecoveryRequest memory recoveryRequest = - zkEmailRecovery.getRecoveryRequest(accountAddress); + IEmailRecoveryManager.RecoveryRequest memory recoveryRequest = + emailRecoveryManager.getRecoveryRequest(accountAddress); assertEq(recoveryRequest.executeAfter, 0); assertEq(recoveryRequest.executeBefore, 0); assertEq(recoveryRequest.currentWeight, 0); - assertEq(recoveryRequest.subjectParams.length, 0); // assert that guardian storage has been cleared successfully for guardian 1 GuardianStorage memory guardianStorage1 = - zkEmailRecovery.getGuardian(accountAddress, guardian1); + emailRecoveryManager.getGuardian(accountAddress, guardian1); assertEq(uint256(guardianStorage1.status), uint256(GuardianStatus.NONE)); assertEq(guardianStorage1.weight, uint256(0)); // assert that guardian storage has been cleared successfully for guardian 2 GuardianStorage memory guardianStorage2 = - zkEmailRecovery.getGuardian(accountAddress, guardian2); + emailRecoveryManager.getGuardian(accountAddress, guardian2); assertEq(uint256(guardianStorage2.status), uint256(GuardianStatus.NONE)); assertEq(guardianStorage2.weight, uint256(0)); // assert that guardian config has been cleared successfully - IZkEmailRecovery.GuardianConfig memory guardianConfig = - zkEmailRecovery.getGuardianConfig(accountAddress); + IEmailRecoveryManager.GuardianConfig memory guardianConfig = + emailRecoveryManager.getGuardianConfig(accountAddress); assertEq(guardianConfig.guardianCount, 0); assertEq(guardianConfig.totalWeight, 0); assertEq(guardianConfig.threshold, 0); - - // assert that the recovery router mappings have been cleared successfully - address accountForRouter = zkEmailRecovery.getAccountForRouter(router); - address routerForAccount = zkEmailRecovery.getRouterForAccount(accountAddress); - assertEq(accountForRouter, address(0)); - assertEq(routerForAccount, address(0)); } } diff --git a/test/unit/ZkEmailRecovery/deployRouterForAccount.t.sol b/test/unit/ZkEmailRecovery/deployRouterForAccount.t.sol deleted file mode 100644 index 96c8d7e9..00000000 --- a/test/unit/ZkEmailRecovery/deployRouterForAccount.t.sol +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; - -import "forge-std/console2.sol"; -import { UnitBase } from "../UnitBase.t.sol"; - -contract ZkEmailRecovery_deployRouterForAccount_Test is UnitBase { - function setUp() public override { - super.setUp(); - } - - function test_DeployRouterForAccount_RouterAlreadyDeployed() public { - address expectedRouter = zkEmailRecovery.getRouterForAccount(accountAddress); - assertEq(expectedRouter.code.length, 0); - - // Deploy router - address router = zkEmailRecovery.exposed_deployRouterForAccount(accountAddress); - expectedRouter = zkEmailRecovery.getRouterForAccount(accountAddress); - assertGt(expectedRouter.code.length, 0); - assertEq(router, expectedRouter); - - // Try to deploy agin - router = zkEmailRecovery.exposed_deployRouterForAccount(accountAddress); - expectedRouter = zkEmailRecovery.getRouterForAccount(accountAddress); - assertGt(expectedRouter.code.length, 0); - assertEq(router, expectedRouter); - } - - function test_DeployRouterForAccount_DeployNewRouter() public { - address expectedRouter = zkEmailRecovery.getRouterForAccount(accountAddress); - assertEq(expectedRouter.code.length, 0); - - // Deploy router - address router = zkEmailRecovery.exposed_deployRouterForAccount(accountAddress); - expectedRouter = zkEmailRecovery.getRouterForAccount(accountAddress); - assertGt(expectedRouter.code.length, 0); - assertEq(router, expectedRouter); - } -} diff --git a/test/unit/ZkEmailRecovery/getAccountForRouter.t.sol b/test/unit/ZkEmailRecovery/getAccountForRouter.t.sol deleted file mode 100644 index 803c62eb..00000000 --- a/test/unit/ZkEmailRecovery/getAccountForRouter.t.sol +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; - -import "forge-std/console2.sol"; -import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; -import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; -import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; -import { UnitBase } from "../UnitBase.t.sol"; -import { OwnableValidator } from "src/test/OwnableValidator.sol"; - -contract ZkEmailRecovery_getAccountForRouter_Test is UnitBase { - using ModuleKitHelpers for *; - using ModuleKitUserOp for *; - - OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; - address recoveryModuleAddress; - - function setUp() public override { - super.setUp(); - - validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); - recoveryModuleAddress = address(recoveryModule); - - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: address(validator), - data: abi.encode(owner, recoveryModuleAddress) - }); - // Install recovery module - configureRecovery is called on `onInstall` - instance.installModule({ - moduleTypeId: MODULE_TYPE_EXECUTOR, - module: recoveryModuleAddress, - data: abi.encode(address(validator), guardians, guardianWeights, threshold, delay, expiry) - }); - } - - function test_GetAccountForRouter_Succeeds() public { - address account = zkEmailRecovery.getAccountForRouter(accountAddress); - // TODO: finish implementing - } -} diff --git a/test/unit/ZkEmailRecovery/getGuardian.t.sol b/test/unit/ZkEmailRecovery/getGuardian.t.sol index 347ab885..1328beb8 100644 --- a/test/unit/ZkEmailRecovery/getGuardian.t.sol +++ b/test/unit/ZkEmailRecovery/getGuardian.t.sol @@ -2,20 +2,19 @@ pragma solidity ^0.8.25; import "forge-std/console2.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; import { UnitBase } from "../UnitBase.t.sol"; contract ZkEmailRecovery_getGuardian_Test is UnitBase { - OwnableValidatorRecoveryModule recoveryModule; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; function setUp() public override { super.setUp(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule{ salt: "test salt" }(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); } diff --git a/test/unit/ZkEmailRecovery/getGuardianConfig.t.sol b/test/unit/ZkEmailRecovery/getGuardianConfig.t.sol index 97438c13..734ceb23 100644 --- a/test/unit/ZkEmailRecovery/getGuardianConfig.t.sol +++ b/test/unit/ZkEmailRecovery/getGuardianConfig.t.sol @@ -2,20 +2,19 @@ pragma solidity ^0.8.25; import "forge-std/console2.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; import { UnitBase } from "../UnitBase.t.sol"; contract ZkEmailRecovery_getGuardianConfig_Test is UnitBase { - OwnableValidatorRecoveryModule recoveryModule; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; function setUp() public override { super.setUp(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule{ salt: "test salt" }(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); } diff --git a/test/unit/ZkEmailRecovery/getRecoveryConfig.t.sol b/test/unit/ZkEmailRecovery/getRecoveryConfig.t.sol index 71eddc28..d45df355 100644 --- a/test/unit/ZkEmailRecovery/getRecoveryConfig.t.sol +++ b/test/unit/ZkEmailRecovery/getRecoveryConfig.t.sol @@ -2,20 +2,19 @@ pragma solidity ^0.8.25; import "forge-std/console2.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; import { UnitBase } from "../UnitBase.t.sol"; contract ZkEmailRecovery_getRecoveryConfig_Test is UnitBase { - OwnableValidatorRecoveryModule recoveryModule; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; function setUp() public override { super.setUp(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule{ salt: "test salt" }(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); } diff --git a/test/unit/ZkEmailRecovery/getRecoveryRequest.t.sol b/test/unit/ZkEmailRecovery/getRecoveryRequest.t.sol index 731a0b46..791b05a3 100644 --- a/test/unit/ZkEmailRecovery/getRecoveryRequest.t.sol +++ b/test/unit/ZkEmailRecovery/getRecoveryRequest.t.sol @@ -2,20 +2,19 @@ pragma solidity ^0.8.25; import "forge-std/console2.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; import { UnitBase } from "../UnitBase.t.sol"; contract ZkEmailRecovery_getRecoveryRequest_Test is UnitBase { - OwnableValidatorRecoveryModule recoveryModule; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; function setUp() public override { super.setUp(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule{ salt: "test salt" }(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); } diff --git a/test/unit/ZkEmailRecovery/getRouterForAccount.t.sol b/test/unit/ZkEmailRecovery/getRouterForAccount.t.sol deleted file mode 100644 index 634227ac..00000000 --- a/test/unit/ZkEmailRecovery/getRouterForAccount.t.sol +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; - -import "forge-std/console2.sol"; -import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; -import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; -import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; -import { UnitBase } from "../UnitBase.t.sol"; -import { OwnableValidator } from "src/test/OwnableValidator.sol"; - -contract ZkEmailRecovery_getRouterForAccount_Test is UnitBase { - using ModuleKitHelpers for *; - using ModuleKitUserOp for *; - - OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; - address recoveryModuleAddress; - - function setUp() public override { - super.setUp(); - - validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); - recoveryModuleAddress = address(recoveryModule); - - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: address(validator), - data: abi.encode(owner, recoveryModuleAddress) - }); - // Install recovery module - configureRecovery is called on `onInstall` - instance.installModule({ - moduleTypeId: MODULE_TYPE_EXECUTOR, - module: recoveryModuleAddress, - data: abi.encode(address(validator), guardians, guardianWeights, threshold, delay, expiry) - }); - } - - function test_GetRouterForAccount_Succeeds() public { - // address account = zkEmailRecovery.GetRouterForAccount(accountAddress); - // TODO: finish implementing - } -} diff --git a/test/unit/ZkEmailRecovery/processRecovery.t.sol b/test/unit/ZkEmailRecovery/processRecovery.t.sol index d6869e71..24523230 100644 --- a/test/unit/ZkEmailRecovery/processRecovery.t.sol +++ b/test/unit/ZkEmailRecovery/processRecovery.t.sol @@ -6,8 +6,8 @@ import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; import { UnitBase } from "../UnitBase.t.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; import { OwnableValidator } from "src/test/OwnableValidator.sol"; import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; @@ -16,15 +16,14 @@ contract ZkEmailRecovery_processRecovery_Test is UnitBase { using ModuleKitUserOp for *; OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; function setUp() public override { super.setUp(); validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule{ salt: "test salt" }(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); instance.installModule({ @@ -52,12 +51,12 @@ contract ZkEmailRecovery_processRecovery_Test is UnitBase { // invalidGuardian has not been configured nor accepted, so the guardian status is NONE vm.expectRevert( abi.encodeWithSelector( - IZkEmailRecovery.InvalidGuardianStatus.selector, + IEmailRecoveryManager.InvalidGuardianStatus.selector, uint256(GuardianStatus.NONE), uint256(GuardianStatus.ACCEPTED) ) ); - zkEmailRecovery.exposed_processRecovery( + emailRecoveryManager.exposed_processRecovery( invalidGuardian, templateIdx, subjectParams, nullifier ); } @@ -73,12 +72,14 @@ contract ZkEmailRecovery_processRecovery_Test is UnitBase { // REQUESTED vm.expectRevert( abi.encodeWithSelector( - IZkEmailRecovery.InvalidGuardianStatus.selector, + IEmailRecoveryManager.InvalidGuardianStatus.selector, uint256(GuardianStatus.REQUESTED), uint256(GuardianStatus.ACCEPTED) ) ); - zkEmailRecovery.exposed_processRecovery(guardian1, templateIdx, subjectParams, nullifier); + emailRecoveryManager.exposed_processRecovery( + guardian1, templateIdx, subjectParams, nullifier + ); } function test_ProcessRecovery_IncreasesTotalWeight() public { @@ -92,14 +93,15 @@ contract ZkEmailRecovery_processRecovery_Test is UnitBase { acceptGuardian(accountSalt1); - zkEmailRecovery.exposed_processRecovery(guardian1, templateIdx, subjectParams, nullifier); + emailRecoveryManager.exposed_processRecovery( + guardian1, templateIdx, subjectParams, nullifier + ); - IZkEmailRecovery.RecoveryRequest memory recoveryRequest = - zkEmailRecovery.getRecoveryRequest(accountAddress); + IEmailRecoveryManager.RecoveryRequest memory recoveryRequest = + emailRecoveryManager.getRecoveryRequest(accountAddress); assertEq(recoveryRequest.executeAfter, 0); assertEq(recoveryRequest.executeBefore, 0); assertEq(recoveryRequest.currentWeight, guardian1Weight); - assertEq(recoveryRequest.subjectParams.length, 0); } function test_ProcessRecovery_InitiatesRecovery() public { @@ -119,17 +121,15 @@ contract ZkEmailRecovery_processRecovery_Test is UnitBase { handleRecovery(recoveryModuleAddress, accountSalt1); // Call processRecovery with guardian2 which increases currentWeight to >= threshold - zkEmailRecovery.exposed_processRecovery(guardian2, templateIdx, subjectParams, nullifier); + emailRecoveryManager.exposed_processRecovery( + guardian2, templateIdx, subjectParams, nullifier + ); - IZkEmailRecovery.RecoveryRequest memory recoveryRequest = - zkEmailRecovery.getRecoveryRequest(accountAddress); + IEmailRecoveryManager.RecoveryRequest memory recoveryRequest = + emailRecoveryManager.getRecoveryRequest(accountAddress); assertEq(recoveryRequest.executeAfter, block.timestamp + delay); assertEq(recoveryRequest.executeBefore, block.timestamp + expiry); assertEq(recoveryRequest.currentWeight, guardian1Weight + guardian2Weight); - assertEq(recoveryRequest.subjectParams.length, 3); - assertEq(recoveryRequest.subjectParams[0], subjectParams[0]); - assertEq(recoveryRequest.subjectParams[1], subjectParams[1]); - assertEq(recoveryRequest.subjectParams[2], subjectParams[2]); } function test_ProcessRecovery_CompletesRecoveryIfDelayIsZero() public { @@ -144,8 +144,8 @@ contract ZkEmailRecovery_processRecovery_Test is UnitBase { // Since configureRecovery is already called in `onInstall`, we update the delay to be 0 // here vm.prank(accountAddress); - zkEmailRecovery.updateRecoveryConfig( - IZkEmailRecovery.RecoveryConfig(recoveryModuleAddress, zeroDelay, expiry) + emailRecoveryManager.updateRecoveryConfig( + IEmailRecoveryManager.RecoveryConfig(recoveryModuleAddress, zeroDelay, expiry) ); vm.stopPrank(); @@ -156,13 +156,14 @@ contract ZkEmailRecovery_processRecovery_Test is UnitBase { handleRecovery(recoveryModuleAddress, accountSalt1); // Call processRecovery with guardian2 which increases currentWeight to >= threshold - zkEmailRecovery.exposed_processRecovery(guardian2, templateIdx, subjectParams, nullifier); + emailRecoveryManager.exposed_processRecovery( + guardian2, templateIdx, subjectParams, nullifier + ); - IZkEmailRecovery.RecoveryRequest memory recoveryRequest = - zkEmailRecovery.getRecoveryRequest(accountAddress); + IEmailRecoveryManager.RecoveryRequest memory recoveryRequest = + emailRecoveryManager.getRecoveryRequest(accountAddress); assertEq(recoveryRequest.executeAfter, 0); assertEq(recoveryRequest.executeBefore, 0); assertEq(recoveryRequest.currentWeight, 0); - assertEq(recoveryRequest.subjectParams.length, 0); } } diff --git a/test/unit/ZkEmailRecovery/recoverySubjectTemplates.t.sol b/test/unit/ZkEmailRecovery/recoverySubjectTemplates.t.sol index d0d91381..02593277 100644 --- a/test/unit/ZkEmailRecovery/recoverySubjectTemplates.t.sol +++ b/test/unit/ZkEmailRecovery/recoverySubjectTemplates.t.sol @@ -1,29 +1,29 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.25; -import "forge-std/console2.sol"; -import { UnitBase } from "../UnitBase.t.sol"; +// import "forge-std/console2.sol"; +// import { UnitBase } from "../UnitBase.t.sol"; -contract ZkEmailRecovery_recoverySubjectTemplates_Test is UnitBase { - function setUp() public override { - super.setUp(); - } +// contract ZkEmailRecovery_recoverySubjectTemplates_Test is UnitBase { +// function setUp() public override { +// super.setUp(); +// } - function test_RecoverySubjectTemplates_Succeeds() public view { - string[][] memory templates = zkEmailRecovery.recoverySubjectTemplates(); +// function test_RecoverySubjectTemplates_Succeeds() public view { +// string[][] memory templates = emailRecoveryManager.recoverySubjectTemplates(); - assertEq(templates.length, 1); - assertEq(templates[0].length, 11); - assertEq(templates[0][0], "Recover"); - assertEq(templates[0][1], "account"); - assertEq(templates[0][2], "{ethAddr}"); - assertEq(templates[0][3], "to"); - assertEq(templates[0][4], "new"); - assertEq(templates[0][5], "owner"); - assertEq(templates[0][6], "{ethAddr}"); - assertEq(templates[0][7], "using"); - assertEq(templates[0][8], "recovery"); - assertEq(templates[0][9], "module"); - assertEq(templates[0][10], "{ethAddr}"); - } -} +// assertEq(templates.length, 1); +// assertEq(templates[0].length, 11); +// assertEq(templates[0][0], "Recover"); +// assertEq(templates[0][1], "account"); +// assertEq(templates[0][2], "{ethAddr}"); +// assertEq(templates[0][3], "to"); +// assertEq(templates[0][4], "new"); +// assertEq(templates[0][5], "owner"); +// assertEq(templates[0][6], "{ethAddr}"); +// assertEq(templates[0][7], "using"); +// assertEq(templates[0][8], "recovery"); +// assertEq(templates[0][9], "module"); +// assertEq(templates[0][10], "{ethAddr}"); +// } +// } diff --git a/test/unit/ZkEmailRecovery/removeGuardian.t.sol b/test/unit/ZkEmailRecovery/removeGuardian.t.sol index 561b2c84..e667c1a8 100644 --- a/test/unit/ZkEmailRecovery/removeGuardian.t.sol +++ b/test/unit/ZkEmailRecovery/removeGuardian.t.sol @@ -6,8 +6,8 @@ import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; import { UnitBase } from "../UnitBase.t.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; import { OwnableValidator } from "src/test/OwnableValidator.sol"; import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; @@ -16,15 +16,14 @@ contract ZkEmailRecovery_removeGuardian_Test is UnitBase { using ModuleKitUserOp for *; OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; function setUp() public override { super.setUp(); validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule{ salt: "test salt" }(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); instance.installModule({ @@ -43,8 +42,8 @@ contract ZkEmailRecovery_removeGuardian_Test is UnitBase { function test_RemoveGuardian_RevertWhen_UnauthorizedAccountForGuardian() public { address guardian = guardian1; - vm.expectRevert(IZkEmailRecovery.UnauthorizedAccountForGuardian.selector); - zkEmailRecovery.removeGuardian(guardian, threshold); + vm.expectRevert(IEmailRecoveryManager.UnauthorizedAccountForGuardian.selector); + emailRecoveryManager.removeGuardian(guardian, threshold); } function test_RemoveGuardian_RevertWhen_AlreadyRecovering() public { @@ -55,8 +54,8 @@ contract ZkEmailRecovery_removeGuardian_Test is UnitBase { handleRecovery(recoveryModuleAddress, accountSalt1); vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.RecoveryInProcess.selector); - zkEmailRecovery.removeGuardian(guardian, threshold); + vm.expectRevert(IEmailRecoveryManager.RecoveryInProcess.selector); + emailRecoveryManager.removeGuardian(guardian, threshold); } function test_RemoveGuardian_RevertWhen_ThresholdExceedsTotalWeight() public { @@ -72,8 +71,8 @@ contract ZkEmailRecovery_removeGuardian_Test is UnitBase { acceptGuardian(accountSalt1); vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.ThresholdCannotExceedTotalWeight.selector); - zkEmailRecovery.removeGuardian(guardian, threshold); + vm.expectRevert(IEmailRecoveryManager.ThresholdCannotExceedTotalWeight.selector); + emailRecoveryManager.removeGuardian(guardian, threshold); } function test_RemoveGuardian_SucceedsWithSameThreshold() public { @@ -89,15 +88,15 @@ contract ZkEmailRecovery_removeGuardian_Test is UnitBase { acceptGuardian(accountSalt1); vm.startPrank(accountAddress); - zkEmailRecovery.removeGuardian(guardian, threshold); + emailRecoveryManager.removeGuardian(guardian, threshold); GuardianStorage memory guardianStorage = - zkEmailRecovery.getGuardian(accountAddress, guardian); + emailRecoveryManager.getGuardian(accountAddress, guardian); assertEq(uint256(guardianStorage.status), uint256(GuardianStatus.NONE)); assertEq(guardianStorage.weight, 0); - IZkEmailRecovery.GuardianConfig memory guardianConfig = - zkEmailRecovery.getGuardianConfig(accountAddress); + IEmailRecoveryManager.GuardianConfig memory guardianConfig = + emailRecoveryManager.getGuardianConfig(accountAddress); assertEq(guardianConfig.guardianCount, guardians.length - 1); assertEq(guardianConfig.totalWeight, totalWeight - guardianWeights[0]); assertEq(guardianConfig.threshold, threshold); @@ -110,10 +109,10 @@ contract ZkEmailRecovery_removeGuardian_Test is UnitBase { acceptGuardian(accountSalt1); vm.startPrank(accountAddress); - zkEmailRecovery.removeGuardian(guardian, newThreshold); + emailRecoveryManager.removeGuardian(guardian, newThreshold); - IZkEmailRecovery.GuardianConfig memory guardianConfig = - zkEmailRecovery.getGuardianConfig(accountAddress); + IEmailRecoveryManager.GuardianConfig memory guardianConfig = + emailRecoveryManager.getGuardianConfig(accountAddress); assertEq(guardianConfig.threshold, newThreshold); } } diff --git a/test/unit/ZkEmailRecovery/setupGuardians.t.sol b/test/unit/ZkEmailRecovery/setupGuardians.t.sol index 3af940d6..cce3a25a 100644 --- a/test/unit/ZkEmailRecovery/setupGuardians.t.sol +++ b/test/unit/ZkEmailRecovery/setupGuardians.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.25; import "forge-std/console2.sol"; import { UnitBase } from "../UnitBase.t.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; contract ZkEmailRecovery_setupGuardians_Test is UnitBase { @@ -12,12 +12,12 @@ contract ZkEmailRecovery_setupGuardians_Test is UnitBase { } function test_SetupGuardians_RevertWhen_SetupAlreadyCalled() public { - zkEmailRecovery.exposed_setupGuardians( + emailRecoveryManager.exposed_setupGuardians( accountAddress, guardians, guardianWeights, threshold ); - vm.expectRevert(IZkEmailRecovery.SetupAlreadyCalled.selector); - zkEmailRecovery.exposed_setupGuardians( + vm.expectRevert(IEmailRecoveryManager.SetupAlreadyCalled.selector); + emailRecoveryManager.exposed_setupGuardians( accountAddress, guardians, guardianWeights, threshold ); } @@ -29,8 +29,8 @@ contract ZkEmailRecovery_setupGuardians_Test is UnitBase { invalidGuardianWeights[2] = 1; invalidGuardianWeights[3] = 1; - vm.expectRevert(IZkEmailRecovery.IncorrectNumberOfWeights.selector); - zkEmailRecovery.exposed_setupGuardians( + vm.expectRevert(IEmailRecoveryManager.IncorrectNumberOfWeights.selector); + emailRecoveryManager.exposed_setupGuardians( accountAddress, guardians, invalidGuardianWeights, threshold ); } @@ -38,8 +38,8 @@ contract ZkEmailRecovery_setupGuardians_Test is UnitBase { function test_SetupGuardians_RevertWhen_ThresholdIsZero() public { uint256 zeroThreshold = 0; - vm.expectRevert(IZkEmailRecovery.ThresholdCannotBeZero.selector); - zkEmailRecovery.exposed_setupGuardians( + vm.expectRevert(IEmailRecoveryManager.ThresholdCannotBeZero.selector); + emailRecoveryManager.exposed_setupGuardians( accountAddress, guardians, guardianWeights, zeroThreshold ); } @@ -47,8 +47,8 @@ contract ZkEmailRecovery_setupGuardians_Test is UnitBase { function test_SetupGuardians_RevertWhen_InvalidGuardianAddress() public { guardians[2] = address(0); - vm.expectRevert(IZkEmailRecovery.InvalidGuardianAddress.selector); - zkEmailRecovery.exposed_setupGuardians( + vm.expectRevert(IEmailRecoveryManager.InvalidGuardianAddress.selector); + emailRecoveryManager.exposed_setupGuardians( accountAddress, guardians, guardianWeights, threshold ); } @@ -56,8 +56,8 @@ contract ZkEmailRecovery_setupGuardians_Test is UnitBase { function test_SetupGuardians_RevertWhen_GuardianAddressIsAccountAddress() public { guardians[1] = accountAddress; - vm.expectRevert(IZkEmailRecovery.InvalidGuardianAddress.selector); - zkEmailRecovery.exposed_setupGuardians( + vm.expectRevert(IEmailRecoveryManager.InvalidGuardianAddress.selector); + emailRecoveryManager.exposed_setupGuardians( accountAddress, guardians, guardianWeights, threshold ); } @@ -65,8 +65,8 @@ contract ZkEmailRecovery_setupGuardians_Test is UnitBase { function test_SetupGuardians_RevertWhen_InvalidGuardianWeight() public { guardianWeights[1] = 0; - vm.expectRevert(IZkEmailRecovery.InvalidGuardianWeight.selector); - zkEmailRecovery.exposed_setupGuardians( + vm.expectRevert(IEmailRecoveryManager.InvalidGuardianWeight.selector); + emailRecoveryManager.exposed_setupGuardians( accountAddress, guardians, guardianWeights, threshold ); } @@ -74,8 +74,8 @@ contract ZkEmailRecovery_setupGuardians_Test is UnitBase { function test_SetupGuardians_RevertWhen_AddressAlreadyGuardian() public { guardians[0] = guardians[1]; - vm.expectRevert(IZkEmailRecovery.AddressAlreadyGuardian.selector); - zkEmailRecovery.exposed_setupGuardians( + vm.expectRevert(IEmailRecoveryManager.AddressAlreadyGuardian.selector); + emailRecoveryManager.exposed_setupGuardians( accountAddress, guardians, guardianWeights, threshold ); } @@ -83,8 +83,8 @@ contract ZkEmailRecovery_setupGuardians_Test is UnitBase { function test_SetupGuardians_RevertWhen_ThresholdExceedsTotalWeight() public { uint256 invalidThreshold = totalWeight + 1; - vm.expectRevert(IZkEmailRecovery.ThresholdCannotExceedTotalWeight.selector); - zkEmailRecovery.exposed_setupGuardians( + vm.expectRevert(IEmailRecoveryManager.ThresholdCannotExceedTotalWeight.selector); + emailRecoveryManager.exposed_setupGuardians( accountAddress, guardians, guardianWeights, invalidThreshold ); } @@ -94,16 +94,16 @@ contract ZkEmailRecovery_setupGuardians_Test is UnitBase { uint256 expectedTotalWeight = totalWeight; uint256 expectedThreshold = threshold; - zkEmailRecovery.exposed_setupGuardians( + emailRecoveryManager.exposed_setupGuardians( accountAddress, guardians, guardianWeights, threshold ); GuardianStorage memory guardianStorage1 = - zkEmailRecovery.getGuardian(accountAddress, guardians[0]); + emailRecoveryManager.getGuardian(accountAddress, guardians[0]); GuardianStorage memory guardianStorage2 = - zkEmailRecovery.getGuardian(accountAddress, guardians[1]); + emailRecoveryManager.getGuardian(accountAddress, guardians[1]); GuardianStorage memory guardianStorage3 = - zkEmailRecovery.getGuardian(accountAddress, guardians[2]); + emailRecoveryManager.getGuardian(accountAddress, guardians[2]); assertEq(uint256(guardianStorage1.status), uint256(GuardianStatus.REQUESTED)); assertEq(guardianStorage1.weight, guardianWeights[0]); assertEq(uint256(guardianStorage2.status), uint256(GuardianStatus.REQUESTED)); @@ -111,8 +111,8 @@ contract ZkEmailRecovery_setupGuardians_Test is UnitBase { assertEq(uint256(guardianStorage3.status), uint256(GuardianStatus.REQUESTED)); assertEq(guardianStorage3.weight, guardianWeights[2]); - IZkEmailRecovery.GuardianConfig memory guardianConfig = - zkEmailRecovery.getGuardianConfig(accountAddress); + IEmailRecoveryManager.GuardianConfig memory guardianConfig = + emailRecoveryManager.getGuardianConfig(accountAddress); assertEq(guardianConfig.guardianCount, expectedGuardianCount); assertEq(guardianConfig.totalWeight, expectedTotalWeight); assertEq(guardianConfig.threshold, expectedThreshold); diff --git a/test/unit/ZkEmailRecovery/updateGuardianDKIMRegistry.t.sol b/test/unit/ZkEmailRecovery/updateGuardianDKIMRegistry.t.sol index 5cc4b609..945eecc4 100644 --- a/test/unit/ZkEmailRecovery/updateGuardianDKIMRegistry.t.sol +++ b/test/unit/ZkEmailRecovery/updateGuardianDKIMRegistry.t.sol @@ -9,8 +9,8 @@ import { ECDSAOwnedDKIMRegistry } from "ether-email-auth/packages/contracts/src/utils/ECDSAOwnedDKIMRegistry.sol"; import { UnitBase } from "../UnitBase.t.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; import { OwnableValidator } from "src/test/OwnableValidator.sol"; contract ZkEmailRecovery_updateGuardianDKIMRegistry_Test is UnitBase { @@ -18,15 +18,14 @@ contract ZkEmailRecovery_updateGuardianDKIMRegistry_Test is UnitBase { using ModuleKitUserOp for *; OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; function setUp() public override { super.setUp(); validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule{ salt: "test salt" }(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); instance.installModule({ @@ -48,8 +47,8 @@ contract ZkEmailRecovery_updateGuardianDKIMRegistry_Test is UnitBase { ECDSAOwnedDKIMRegistry newDkim = new ECDSAOwnedDKIMRegistry(accountAddress); address newDkimAddr = address(newDkim); - vm.expectRevert(IZkEmailRecovery.UnauthorizedAccountForGuardian.selector); - zkEmailRecovery.updateGuardianDKIMRegistry(guardian, newDkimAddr); + vm.expectRevert(IEmailRecoveryManager.UnauthorizedAccountForGuardian.selector); + emailRecoveryManager.updateGuardianDKIMRegistry(guardian, newDkimAddr); } function test_UpdateGuardianDKIMRegistry_RevertWhen_RecoveryInProcess() public { @@ -63,8 +62,8 @@ contract ZkEmailRecovery_updateGuardianDKIMRegistry_Test is UnitBase { handleRecovery(recoveryModuleAddress, accountSalt1); vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.RecoveryInProcess.selector); - zkEmailRecovery.updateGuardianDKIMRegistry(guardian, newDkimAddr); + vm.expectRevert(IEmailRecoveryManager.RecoveryInProcess.selector); + emailRecoveryManager.updateGuardianDKIMRegistry(guardian, newDkimAddr); } function test_UpdateGuardianDKIMRegistry_Succeeds() public { @@ -80,7 +79,7 @@ contract ZkEmailRecovery_updateGuardianDKIMRegistry_Test is UnitBase { assertEq(dkim, address(ecdsaOwnedDkimRegistry)); vm.startPrank(accountAddress); - zkEmailRecovery.updateGuardianDKIMRegistry(guardian, newDkimAddr); + emailRecoveryManager.updateGuardianDKIMRegistry(guardian, newDkimAddr); dkim = guardianEmailAuth.dkimRegistryAddr(); assertEq(dkim, newDkimAddr); diff --git a/test/unit/ZkEmailRecovery/updateGuardianVerifier.t.sol b/test/unit/ZkEmailRecovery/updateGuardianVerifier.t.sol index 55ec8264..dac20393 100644 --- a/test/unit/ZkEmailRecovery/updateGuardianVerifier.t.sol +++ b/test/unit/ZkEmailRecovery/updateGuardianVerifier.t.sol @@ -7,8 +7,8 @@ import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ import { EmailAuth } from "ether-email-auth/packages/contracts/src/EmailAuth.sol"; import { UnitBase } from "../UnitBase.t.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; import { MockGroth16Verifier } from "src/test/MockGroth16Verifier.sol"; import { OwnableValidator } from "src/test/OwnableValidator.sol"; @@ -17,15 +17,14 @@ contract ZkEmailRecovery_updateGuardianVerifier_Test is UnitBase { using ModuleKitUserOp for *; OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; function setUp() public override { super.setUp(); validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule{ salt: "test salt" }(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); instance.installModule({ @@ -47,8 +46,8 @@ contract ZkEmailRecovery_updateGuardianVerifier_Test is UnitBase { MockGroth16Verifier newVerifier = new MockGroth16Verifier(); address newVerifierAddr = address(newVerifier); - vm.expectRevert(IZkEmailRecovery.UnauthorizedAccountForGuardian.selector); - zkEmailRecovery.updateGuardianVerifier(guardian, newVerifierAddr); + vm.expectRevert(IEmailRecoveryManager.UnauthorizedAccountForGuardian.selector); + emailRecoveryManager.updateGuardianVerifier(guardian, newVerifierAddr); } function test_UpdateGuardianVerifier_RevertWhen_RecoveryInProcess() public { @@ -62,8 +61,8 @@ contract ZkEmailRecovery_updateGuardianVerifier_Test is UnitBase { handleRecovery(recoveryModuleAddress, accountSalt1); vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.RecoveryInProcess.selector); - zkEmailRecovery.updateGuardianVerifier(guardian, newVerifierAddr); + vm.expectRevert(IEmailRecoveryManager.RecoveryInProcess.selector); + emailRecoveryManager.updateGuardianVerifier(guardian, newVerifierAddr); } function test_UpdateGuardianVerifier_Succeeds() public { @@ -79,7 +78,7 @@ contract ZkEmailRecovery_updateGuardianVerifier_Test is UnitBase { assertEq(expectedVerifier, address(verifier)); vm.startPrank(accountAddress); - zkEmailRecovery.updateGuardianVerifier(guardian, newVerifierAddr); + emailRecoveryManager.updateGuardianVerifier(guardian, newVerifierAddr); expectedVerifier = guardianEmailAuth.verifierAddr(); assertEq(expectedVerifier, newVerifierAddr); diff --git a/test/unit/ZkEmailRecovery/updateRecoveryConfig.t.sol b/test/unit/ZkEmailRecovery/updateRecoveryConfig.t.sol index 32d968ce..8a543e68 100644 --- a/test/unit/ZkEmailRecovery/updateRecoveryConfig.t.sol +++ b/test/unit/ZkEmailRecovery/updateRecoveryConfig.t.sol @@ -6,8 +6,8 @@ import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; import { UnitBase } from "../UnitBase.t.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; import { OwnableValidator } from "src/test/OwnableValidator.sol"; contract ZkEmailRecovery_updateRecoveryConfig_Test is UnitBase { @@ -15,15 +15,14 @@ contract ZkEmailRecovery_updateRecoveryConfig_Test is UnitBase { using ModuleKitUserOp for *; OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; function setUp() public override { super.setUp(); validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule{ salt: "test salt" }(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); instance.installModule({ @@ -40,8 +39,8 @@ contract ZkEmailRecovery_updateRecoveryConfig_Test is UnitBase { } function test_UpdateRecoveryConfig_RevertWhen_AlreadyRecovering() public { - IZkEmailRecovery.RecoveryConfig memory recoveryConfig = - IZkEmailRecovery.RecoveryConfig(recoveryModuleAddress, delay, expiry); + IEmailRecoveryManager.RecoveryConfig memory recoveryConfig = + IEmailRecoveryManager.RecoveryConfig(recoveryModuleAddress, delay, expiry); acceptGuardian(accountSalt1); acceptGuardian(accountSalt2); @@ -50,64 +49,64 @@ contract ZkEmailRecovery_updateRecoveryConfig_Test is UnitBase { handleRecovery(recoveryModuleAddress, accountSalt2); vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.RecoveryInProcess.selector); - zkEmailRecovery.updateRecoveryConfig(recoveryConfig); + vm.expectRevert(IEmailRecoveryManager.RecoveryInProcess.selector); + emailRecoveryManager.updateRecoveryConfig(recoveryConfig); } function test_UpdateRecoveryConfig_RevertWhen_AccountNotConfigured() public { address nonConfiguredAccount = address(0); - IZkEmailRecovery.RecoveryConfig memory recoveryConfig = - IZkEmailRecovery.RecoveryConfig(recoveryModuleAddress, delay, expiry); + IEmailRecoveryManager.RecoveryConfig memory recoveryConfig = + IEmailRecoveryManager.RecoveryConfig(recoveryModuleAddress, delay, expiry); vm.startPrank(nonConfiguredAccount); - vm.expectRevert(IZkEmailRecovery.AccountNotConfigured.selector); - zkEmailRecovery.updateRecoveryConfig(recoveryConfig); + vm.expectRevert(IEmailRecoveryManager.AccountNotConfigured.selector); + emailRecoveryManager.updateRecoveryConfig(recoveryConfig); } function test_UpdateRecoveryConfig_RevertWhen_InvalidRecoveryModule() public { address invalidRecoveryModule = address(0); - IZkEmailRecovery.RecoveryConfig memory recoveryConfig = - IZkEmailRecovery.RecoveryConfig(invalidRecoveryModule, delay, expiry); + IEmailRecoveryManager.RecoveryConfig memory recoveryConfig = + IEmailRecoveryManager.RecoveryConfig(invalidRecoveryModule, delay, expiry); vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.InvalidRecoveryModule.selector); - zkEmailRecovery.updateRecoveryConfig(recoveryConfig); + vm.expectRevert(IEmailRecoveryManager.InvalidRecoveryModule.selector); + emailRecoveryManager.updateRecoveryConfig(recoveryConfig); } function test_UpdateRecoveryConfig_RevertWhen_DelayMoreThanExpiry() public { uint256 invalidDelay = expiry + 1 seconds; - IZkEmailRecovery.RecoveryConfig memory recoveryConfig = - IZkEmailRecovery.RecoveryConfig(recoveryModuleAddress, invalidDelay, expiry); + IEmailRecoveryManager.RecoveryConfig memory recoveryConfig = + IEmailRecoveryManager.RecoveryConfig(recoveryModuleAddress, invalidDelay, expiry); vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.DelayMoreThanExpiry.selector); - zkEmailRecovery.updateRecoveryConfig(recoveryConfig); + vm.expectRevert(IEmailRecoveryManager.DelayMoreThanExpiry.selector); + emailRecoveryManager.updateRecoveryConfig(recoveryConfig); } function test_UpdateRecoveryConfig_RevertWhen_RecoveryWindowTooShort() public { uint256 newDelay = 1 days; uint256 newExpiry = 2 days; - IZkEmailRecovery.RecoveryConfig memory recoveryConfig = - IZkEmailRecovery.RecoveryConfig(recoveryModuleAddress, newDelay, newExpiry); + IEmailRecoveryManager.RecoveryConfig memory recoveryConfig = + IEmailRecoveryManager.RecoveryConfig(recoveryModuleAddress, newDelay, newExpiry); vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.RecoveryWindowTooShort.selector); - zkEmailRecovery.updateRecoveryConfig(recoveryConfig); + vm.expectRevert(IEmailRecoveryManager.RecoveryWindowTooShort.selector); + emailRecoveryManager.updateRecoveryConfig(recoveryConfig); } function test_UpdateRecoveryConfig_RevertWhen_RecoveryWindowTooShortByOneSecond() public { uint256 newDelay = 1 seconds; uint256 newExpiry = 2 days; - IZkEmailRecovery.RecoveryConfig memory recoveryConfig = - IZkEmailRecovery.RecoveryConfig(recoveryModuleAddress, newDelay, newExpiry); + IEmailRecoveryManager.RecoveryConfig memory recoveryConfig = + IEmailRecoveryManager.RecoveryConfig(recoveryModuleAddress, newDelay, newExpiry); vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.RecoveryWindowTooShort.selector); - zkEmailRecovery.updateRecoveryConfig(recoveryConfig); + vm.expectRevert(IEmailRecoveryManager.RecoveryWindowTooShort.selector); + emailRecoveryManager.updateRecoveryConfig(recoveryConfig); } function test_UpdateRecoveryConfig_SucceedsWhenRecoveryWindowEqualsMinimumRecoveryWindow() @@ -116,13 +115,13 @@ contract ZkEmailRecovery_updateRecoveryConfig_Test is UnitBase { uint256 newDelay = 0 seconds; uint256 newExpiry = 2 days; - IZkEmailRecovery.RecoveryConfig memory recoveryConfig = - IZkEmailRecovery.RecoveryConfig(recoveryModuleAddress, newDelay, newExpiry); + IEmailRecoveryManager.RecoveryConfig memory recoveryConfig = + IEmailRecoveryManager.RecoveryConfig(recoveryModuleAddress, newDelay, newExpiry); vm.startPrank(accountAddress); - zkEmailRecovery.updateRecoveryConfig(recoveryConfig); + emailRecoveryManager.updateRecoveryConfig(recoveryConfig); - recoveryConfig = zkEmailRecovery.getRecoveryConfig(accountAddress); + recoveryConfig = emailRecoveryManager.getRecoveryConfig(accountAddress); assertEq(recoveryConfig.recoveryModule, recoveryModuleAddress); assertEq(recoveryConfig.delay, newDelay); assertEq(recoveryConfig.expiry, newExpiry); @@ -133,13 +132,13 @@ contract ZkEmailRecovery_updateRecoveryConfig_Test is UnitBase { uint256 newDelay = 1 days; uint256 newExpiry = 4 weeks; - IZkEmailRecovery.RecoveryConfig memory recoveryConfig = - IZkEmailRecovery.RecoveryConfig(newRecoveryModule, newDelay, newExpiry); + IEmailRecoveryManager.RecoveryConfig memory recoveryConfig = + IEmailRecoveryManager.RecoveryConfig(newRecoveryModule, newDelay, newExpiry); vm.startPrank(accountAddress); - zkEmailRecovery.updateRecoveryConfig(recoveryConfig); + emailRecoveryManager.updateRecoveryConfig(recoveryConfig); - recoveryConfig = zkEmailRecovery.getRecoveryConfig(accountAddress); + recoveryConfig = emailRecoveryManager.getRecoveryConfig(accountAddress); assertEq(recoveryConfig.recoveryModule, newRecoveryModule); assertEq(recoveryConfig.delay, newDelay); assertEq(recoveryConfig.expiry, newExpiry); diff --git a/test/unit/ZkEmailRecovery/upgradeEmailAuthGuardian.t.sol b/test/unit/ZkEmailRecovery/upgradeEmailAuthGuardian.t.sol index 61689dc8..95fb586c 100644 --- a/test/unit/ZkEmailRecovery/upgradeEmailAuthGuardian.t.sol +++ b/test/unit/ZkEmailRecovery/upgradeEmailAuthGuardian.t.sol @@ -7,8 +7,8 @@ import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ import { EmailAuth } from "ether-email-auth/packages/contracts/src/EmailAuth.sol"; import { UnitBase } from "../UnitBase.t.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; +import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; +import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; import { OwnableValidator } from "src/test/OwnableValidator.sol"; contract ZkEmailRecovery_upgradeEmailAuthGuardian_Test is UnitBase { @@ -16,15 +16,14 @@ contract ZkEmailRecovery_upgradeEmailAuthGuardian_Test is UnitBase { using ModuleKitUserOp for *; OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; + EmailRecoveryModule recoveryModule; address recoveryModuleAddress; function setUp() public override { super.setUp(); validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); + recoveryModule = new EmailRecoveryModule{ salt: "test salt" }(address(emailRecoveryManager)); recoveryModuleAddress = address(recoveryModule); instance.installModule({ @@ -44,8 +43,8 @@ contract ZkEmailRecovery_upgradeEmailAuthGuardian_Test is UnitBase { address newImplementation = address(1); bytes memory data = ""; - vm.expectRevert(IZkEmailRecovery.UnauthorizedAccountForGuardian.selector); - zkEmailRecovery.upgradeEmailAuthGuardian(guardian1, newImplementation, data); + vm.expectRevert(IEmailRecoveryManager.UnauthorizedAccountForGuardian.selector); + emailRecoveryManager.upgradeEmailAuthGuardian(guardian1, newImplementation, data); } function test_UpgradeEmailAuthGuardian_RevertWhen_RecoveryInProcess() public { @@ -58,8 +57,8 @@ contract ZkEmailRecovery_upgradeEmailAuthGuardian_Test is UnitBase { handleRecovery(recoveryModuleAddress, accountSalt1); vm.startPrank(accountAddress); - vm.expectRevert(IZkEmailRecovery.RecoveryInProcess.selector); - zkEmailRecovery.upgradeEmailAuthGuardian(guardian1, newImplementation, data); + vm.expectRevert(IEmailRecoveryManager.RecoveryInProcess.selector); + emailRecoveryManager.upgradeEmailAuthGuardian(guardian1, newImplementation, data); } function test_UpgradeEmailAuthGuardian_Succeeds() public { @@ -70,6 +69,6 @@ contract ZkEmailRecovery_upgradeEmailAuthGuardian_Test is UnitBase { acceptGuardian(accountSalt1); vm.startPrank(accountAddress); - zkEmailRecovery.upgradeEmailAuthGuardian(guardian1, newImplementation, data); + emailRecoveryManager.upgradeEmailAuthGuardian(guardian1, newImplementation, data); } } diff --git a/test/unit/ZkEmailRecovery/validateAcceptanceSubjectTemplates.t.sol b/test/unit/ZkEmailRecovery/validateAcceptanceSubjectTemplates.t.sol index 8e859a3d..e6590df9 100644 --- a/test/unit/ZkEmailRecovery/validateAcceptanceSubjectTemplates.t.sol +++ b/test/unit/ZkEmailRecovery/validateAcceptanceSubjectTemplates.t.sol @@ -1,65 +1,69 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.25; -import "forge-std/console2.sol"; -import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; -import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; +// import "forge-std/console2.sol"; +// import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; +// import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; -import { OwnableValidator } from "src/test/OwnableValidator.sol"; -import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; -import { UnitBase } from "../UnitBase.t.sol"; +// import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; +// import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; +// import { OwnableValidator } from "src/test/OwnableValidator.sol"; +// import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; +// import { UnitBase } from "../UnitBase.t.sol"; -contract ZkEmailRecovery_validateAcceptanceSubjectTemplates_Test is UnitBase { - using ModuleKitHelpers for *; - using ModuleKitUserOp for *; +// contract ZkEmailRecovery_validateAcceptanceSubjectTemplates_Test is UnitBase { +// using ModuleKitHelpers for *; +// using ModuleKitUserOp for *; - OwnableValidatorRecoveryModule recoveryModule; - address recoveryModuleAddress; +// EmailRecoveryModule recoveryModule; +// address recoveryModuleAddress; - function setUp() public override { - super.setUp(); +// function setUp() public override { +// super.setUp(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); - recoveryModuleAddress = address(recoveryModule); - } +// recoveryModule = +// new EmailRecoveryModule{ salt: "test salt" +// }(address(emailRecoveryManager)); +// recoveryModuleAddress = address(recoveryModule); +// } - function test_ValidateAcceptanceSubjectTemplates_RevertWhen_InvalidTemplateIndex() public { - uint256 invalidTemplateIdx = 1; +// function test_ValidateAcceptanceSubjectTemplates_RevertWhen_InvalidTemplateIndex() public { +// uint256 invalidTemplateIdx = 1; - bytes[] memory subjectParams = new bytes[](1); - subjectParams[0] = abi.encode(accountAddress); +// bytes[] memory subjectParams = new bytes[](1); +// subjectParams[0] = abi.encode(accountAddress); - vm.expectRevert(IZkEmailRecovery.InvalidTemplateIndex.selector); - zkEmailRecovery.exposed_validateAcceptanceSubjectTemplates( - invalidTemplateIdx, subjectParams - ); - } +// vm.expectRevert(IEmailRecoveryManager.InvalidTemplateIndex.selector); +// emailRecoveryManager.exposed_validateAcceptanceSubjectTemplates( +// invalidTemplateIdx, subjectParams +// ); +// } - function test_ValidateAcceptanceSubjectTemplates_RevertWhen_NoSubjectParams() public { - bytes[] memory emptySubjectParams; +// function test_ValidateAcceptanceSubjectTemplates_RevertWhen_NoSubjectParams() public { +// bytes[] memory emptySubjectParams; - vm.expectRevert(IZkEmailRecovery.InvalidSubjectParams.selector); - zkEmailRecovery.exposed_validateAcceptanceSubjectTemplates(templateIdx, emptySubjectParams); - } +// vm.expectRevert(IEmailRecoveryManager.InvalidSubjectParams.selector); +// emailRecoveryManager.exposed_validateAcceptanceSubjectTemplates(templateIdx, +// emptySubjectParams); +// } - function test_ValidateAcceptanceSubjectTemplates_RevertWhen_TooManySubjectParams() public { - bytes[] memory subjectParams = new bytes[](2); - subjectParams[0] = abi.encode(accountAddress); - subjectParams[1] = abi.encode("extra param"); +// function test_ValidateAcceptanceSubjectTemplates_RevertWhen_TooManySubjectParams() public { +// bytes[] memory subjectParams = new bytes[](2); +// subjectParams[0] = abi.encode(accountAddress); +// subjectParams[1] = abi.encode("extra param"); - vm.expectRevert(IZkEmailRecovery.InvalidSubjectParams.selector); - zkEmailRecovery.exposed_validateAcceptanceSubjectTemplates(templateIdx, subjectParams); - } +// vm.expectRevert(IEmailRecoveryManager.InvalidSubjectParams.selector); +// emailRecoveryManager.exposed_validateAcceptanceSubjectTemplates(templateIdx, +// subjectParams); +// } - function test_ValidateAcceptanceSubjectTemplates_Succeeds() public view { - bytes[] memory subjectParams = new bytes[](1); - subjectParams[0] = abi.encode(accountAddress); +// function test_ValidateAcceptanceSubjectTemplates_Succeeds() public view { +// bytes[] memory subjectParams = new bytes[](1); +// subjectParams[0] = abi.encode(accountAddress); - address account = - zkEmailRecovery.exposed_validateAcceptanceSubjectTemplates(templateIdx, subjectParams); - assertEq(account, accountAddress); - } -} +// address account = +// emailRecoveryManager.exposed_validateAcceptanceSubjectTemplates(templateIdx, +// subjectParams); +// assertEq(account, accountAddress); +// } +// } diff --git a/test/unit/ZkEmailRecovery/validateRecoverySubjectTemplates.t.sol b/test/unit/ZkEmailRecovery/validateRecoverySubjectTemplates.t.sol index d4c831a5..ef02bc18 100644 --- a/test/unit/ZkEmailRecovery/validateRecoverySubjectTemplates.t.sol +++ b/test/unit/ZkEmailRecovery/validateRecoverySubjectTemplates.t.sol @@ -1,114 +1,124 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.25; -import "forge-std/console2.sol"; -import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; -import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; - -import { IZkEmailRecovery } from "src/interfaces/IZkEmailRecovery.sol"; -import { OwnableValidatorRecoveryModule } from "src/modules/OwnableValidatorRecoveryModule.sol"; -import { OwnableValidator } from "src/test/OwnableValidator.sol"; -import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; -import { UnitBase } from "../UnitBase.t.sol"; - -contract ZkEmailRecovery_validateRecoverySubjectTemplates_Test is UnitBase { - using ModuleKitHelpers for *; - using ModuleKitUserOp for *; - - OwnableValidator validator; - OwnableValidatorRecoveryModule recoveryModule; - address recoveryModuleAddress; - - function setUp() public override { - super.setUp(); - - validator = new OwnableValidator(); - recoveryModule = - new OwnableValidatorRecoveryModule{ salt: "test salt" }(address(zkEmailRecovery)); - recoveryModuleAddress = address(recoveryModule); - - instance.installModule({ - moduleTypeId: MODULE_TYPE_VALIDATOR, - module: address(validator), - data: abi.encode(owner, recoveryModuleAddress) - }); - // Install recovery module - configureRecovery is called on `onInstall` - instance.installModule({ - moduleTypeId: MODULE_TYPE_EXECUTOR, - module: recoveryModuleAddress, - data: abi.encode(address(validator), guardians, guardianWeights, threshold, delay, expiry) - }); - } - - function test_ValidateRecoverySubjectTemplates_RevertWhen_InvalidTemplateIndex() public { - uint256 invalidTemplateIdx = 1; - - bytes[] memory subjectParams = new bytes[](3); - subjectParams[0] = abi.encode(accountAddress); - subjectParams[1] = abi.encode(newOwner); - subjectParams[2] = abi.encode(recoveryModuleAddress); - - vm.expectRevert(IZkEmailRecovery.InvalidTemplateIndex.selector); - zkEmailRecovery.exposed_validateRecoverySubjectTemplates(invalidTemplateIdx, subjectParams); - } - - function test_ValidateAcceptanceSubjectTemplates_RevertWhen_NoSubjectParams() public { - bytes[] memory emptySubjectParams; - - vm.expectRevert(IZkEmailRecovery.InvalidSubjectParams.selector); - zkEmailRecovery.exposed_validateRecoverySubjectTemplates(templateIdx, emptySubjectParams); - } - - function test_ValidateAcceptanceSubjectTemplates_RevertWhen_TooManySubjectParams() public { - bytes[] memory subjectParams = new bytes[](4); - subjectParams[0] = abi.encode(accountAddress); - subjectParams[1] = abi.encode(newOwner); - subjectParams[2] = abi.encode(recoveryModuleAddress); - subjectParams[3] = abi.encode("extra param"); - - vm.expectRevert(IZkEmailRecovery.InvalidSubjectParams.selector); - zkEmailRecovery.exposed_validateRecoverySubjectTemplates(templateIdx, subjectParams); - } - - function test_ProcessRecovery_RevertWhen_InvalidNewOwner() public { - bytes[] memory subjectParams = new bytes[](3); - subjectParams[0] = abi.encode(accountAddress); - subjectParams[1] = abi.encode(address(0)); - subjectParams[2] = abi.encode(recoveryModuleAddress); - - vm.expectRevert(IZkEmailRecovery.InvalidNewOwner.selector); - zkEmailRecovery.exposed_validateRecoverySubjectTemplates(templateIdx, subjectParams); - } - - function test_ProcessRecovery_RevertWhen_RecoveryModuleAddressIsZero() public { - bytes[] memory subjectParams = new bytes[](3); - subjectParams[0] = abi.encode(accountAddress); - subjectParams[1] = abi.encode(newOwner); - subjectParams[2] = abi.encode(address(0)); - - vm.expectRevert(IZkEmailRecovery.InvalidRecoveryModule.selector); - zkEmailRecovery.exposed_validateRecoverySubjectTemplates(templateIdx, subjectParams); - } - - function test_ProcessRecovery_RevertWhen_RecoveryModuleNotEqualToExpectedAddress() public { - bytes[] memory subjectParams = new bytes[](3); - subjectParams[0] = abi.encode(address(1)); - subjectParams[1] = abi.encode(newOwner); - subjectParams[2] = abi.encode(recoveryModuleAddress); // recovery module is valid, but not - // for the owner passed in - - vm.expectRevert(IZkEmailRecovery.InvalidRecoveryModule.selector); - zkEmailRecovery.exposed_validateRecoverySubjectTemplates(templateIdx, subjectParams); - } - - function test_ProcessRecovery_Succeeds() public { - bytes[] memory subjectParams = new bytes[](3); - subjectParams[0] = abi.encode(accountAddress); - subjectParams[1] = abi.encode(newOwner); - subjectParams[2] = abi.encode(recoveryModuleAddress); - - address account = - zkEmailRecovery.exposed_validateRecoverySubjectTemplates(templateIdx, subjectParams); - assertEq(account, accountAddress); - } -} +// import "forge-std/console2.sol"; +// import { ModuleKitHelpers, ModuleKitUserOp } from "modulekit/ModuleKit.sol"; +// import { MODULE_TYPE_EXECUTOR, MODULE_TYPE_VALIDATOR } from "modulekit/external/ERC7579.sol"; + +// import { IEmailRecoveryManager } from "src/interfaces/IEmailRecoveryManager.sol"; +// import { EmailRecoveryModule } from "src/modules/EmailRecoveryModule.sol"; +// import { OwnableValidator } from "src/test/OwnableValidator.sol"; +// import { GuardianStorage, GuardianStatus } from "src/libraries/EnumerableGuardianMap.sol"; +// import { UnitBase } from "../UnitBase.t.sol"; + +// contract ZkEmailRecovery_validateRecoverySubjectTemplates_Test is UnitBase { +// using ModuleKitHelpers for *; +// using ModuleKitUserOp for *; + +// OwnableValidator validator; +// EmailRecoveryModule recoveryModule; +// address recoveryModuleAddress; + +// function setUp() public override { +// super.setUp(); + +// validator = new OwnableValidator(); +// recoveryModule = +// new EmailRecoveryModule{ salt: "test salt" +// }(address(emailRecoveryManager)); +// recoveryModuleAddress = address(recoveryModule); + +// instance.installModule({ +// moduleTypeId: MODULE_TYPE_VALIDATOR, +// module: address(validator), +// data: abi.encode(owner, recoveryModuleAddress) +// }); +// // Install recovery module - configureRecovery is called on `onInstall` +// instance.installModule({ +// moduleTypeId: MODULE_TYPE_EXECUTOR, +// module: recoveryModuleAddress, +// data: abi.encode(address(validator), guardians, guardianWeights, threshold, delay, +// expiry) +// }); +// } + +// function test_ValidateRecoverySubjectTemplates_RevertWhen_InvalidTemplateIndex() public { +// uint256 invalidTemplateIdx = 1; + +// bytes[] memory subjectParams = new bytes[](3); +// subjectParams[0] = abi.encode(accountAddress); +// subjectParams[1] = abi.encode(newOwner); +// subjectParams[2] = abi.encode(recoveryModuleAddress); + +// vm.expectRevert(IEmailRecoveryManager.InvalidTemplateIndex.selector); +// emailRecoveryManager.exposed_validateRecoverySubjectTemplates(invalidTemplateIdx, +// subjectParams); +// } + +// function test_ValidateAcceptanceSubjectTemplates_RevertWhen_NoSubjectParams() public { +// bytes[] memory emptySubjectParams; + +// vm.expectRevert(IEmailRecoveryManager.InvalidSubjectParams.selector); +// emailRecoveryManager.exposed_validateRecoverySubjectTemplates(templateIdx, +// emptySubjectParams); +// } + +// function test_ValidateAcceptanceSubjectTemplates_RevertWhen_TooManySubjectParams() public { +// bytes[] memory subjectParams = new bytes[](4); +// subjectParams[0] = abi.encode(accountAddress); +// subjectParams[1] = abi.encode(newOwner); +// subjectParams[2] = abi.encode(recoveryModuleAddress); +// subjectParams[3] = abi.encode("extra param"); + +// vm.expectRevert(IEmailRecoveryManager.InvalidSubjectParams.selector); +// emailRecoveryManager.exposed_validateRecoverySubjectTemplates(templateIdx, +// subjectParams); +// } + +// function test_ProcessRecovery_RevertWhen_InvalidNewOwner() public { +// bytes[] memory subjectParams = new bytes[](3); +// subjectParams[0] = abi.encode(accountAddress); +// subjectParams[1] = abi.encode(address(0)); +// subjectParams[2] = abi.encode(recoveryModuleAddress); + +// vm.expectRevert(IEmailRecoveryManager.InvalidNewOwner.selector); +// emailRecoveryManager.exposed_validateRecoverySubjectTemplates(templateIdx, +// subjectParams); +// } + +// function test_ProcessRecovery_RevertWhen_RecoveryModuleAddressIsZero() public { +// bytes[] memory subjectParams = new bytes[](3); +// subjectParams[0] = abi.encode(accountAddress); +// subjectParams[1] = abi.encode(newOwner); +// subjectParams[2] = abi.encode(address(0)); + +// vm.expectRevert(IEmailRecoveryManager.InvalidRecoveryModule.selector); +// emailRecoveryManager.exposed_validateRecoverySubjectTemplates(templateIdx, +// subjectParams); +// } + +// function test_ProcessRecovery_RevertWhen_RecoveryModuleNotEqualToExpectedAddress() public { +// bytes[] memory subjectParams = new bytes[](3); +// subjectParams[0] = abi.encode(address(1)); +// subjectParams[1] = abi.encode(newOwner); +// subjectParams[2] = abi.encode(recoveryModuleAddress); // recovery module is valid, but +// not +// // for the owner passed in + +// vm.expectRevert(IEmailRecoveryManager.InvalidRecoveryModule.selector); +// emailRecoveryManager.exposed_validateRecoverySubjectTemplates(templateIdx, +// subjectParams); +// } + +// function test_ProcessRecovery_Succeeds() public { +// bytes[] memory subjectParams = new bytes[](3); +// subjectParams[0] = abi.encode(accountAddress); +// subjectParams[1] = abi.encode(newOwner); +// subjectParams[2] = abi.encode(recoveryModuleAddress); + +// address account = +// emailRecoveryManager.exposed_validateRecoverySubjectTemplates(templateIdx, +// subjectParams); +// assertEq(account, accountAddress); +// } +// } diff --git a/test/unit/ZkEmailRecoveryHarness.sol b/test/unit/ZkEmailRecoveryHarness.sol deleted file mode 100644 index 4a9d5819..00000000 --- a/test/unit/ZkEmailRecoveryHarness.sol +++ /dev/null @@ -1,74 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; - -import "forge-std/console2.sol"; -import { ZkEmailRecovery } from "src/ZkEmailRecovery.sol"; - -contract ZkEmailRecoveryHarness is ZkEmailRecovery { - constructor( - address _verifier, - address _dkimRegistry, - address _emailAuthImpl - ) - ZkEmailRecovery(_verifier, _dkimRegistry, _emailAuthImpl) - { } - - function exposed_acceptGuardian( - address guardian, - uint256 templateIdx, - bytes[] memory subjectParams, - bytes32 nullifier - ) - external - { - acceptGuardian(guardian, templateIdx, subjectParams, nullifier); - } - - function exposed_validateAcceptanceSubjectTemplates( - uint256 templateIdx, - bytes[] memory subjectParams - ) - external - pure - returns (address) - { - return validateAcceptanceSubjectTemplates(templateIdx, subjectParams); - } - - function exposed_validateRecoverySubjectTemplates( - uint256 templateIdx, - bytes[] memory subjectParams - ) - external - view - returns (address) - { - return validateRecoverySubjectTemplates(templateIdx, subjectParams); - } - - function exposed_processRecovery( - address guardian, - uint256 templateIdx, - bytes[] memory subjectParams, - bytes32 nullifier - ) - external - { - processRecovery(guardian, templateIdx, subjectParams, nullifier); - } - - function exposed_setupGuardians( - address account, - address[] memory guardians, - uint256[] memory weights, - uint256 threshold - ) - external - { - setupGuardians(account, guardians, weights, threshold); - } - - function exposed_deployRouterForAccount(address account) external returns (address) { - return deployRouterForAccount(account); - } -}