From a7a717778b79721b236f994bdd5e51fc1f56cc59 Mon Sep 17 00:00:00 2001 From: wshino Date: Sat, 12 Oct 2024 23:34:13 +0900 Subject: [PATCH] Add test cases for EmailAccountRecovery --- ...mailAccountRecovery_handleAcceptance.t.sol | 220 ++++++++++++++++++ .../EmailAccountRecovery_handleRecovery.t.sol | 122 +++++++++- ...EmailAccountRecovery_requestGuardian.t.sol | 99 +++++--- 3 files changed, 411 insertions(+), 30 deletions(-) diff --git a/packages/contracts/test/EmailAccountRecovery/EmailAccountRecovery_handleAcceptance.t.sol b/packages/contracts/test/EmailAccountRecovery/EmailAccountRecovery_handleAcceptance.t.sol index 5d3e3428..3e689134 100644 --- a/packages/contracts/test/EmailAccountRecovery/EmailAccountRecovery_handleAcceptance.t.sol +++ b/packages/contracts/test/EmailAccountRecovery/EmailAccountRecovery_handleAcceptance.t.sol @@ -8,6 +8,7 @@ import {RecoveryController} from "../helpers/RecoveryController.sol"; import {StructHelper} from "../helpers/StructHelper.sol"; import {SimpleWallet} from "../helpers/SimpleWallet.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; contract EmailAccountRecoveryTest_handleAcceptance is StructHelper { constructor() {} @@ -35,6 +36,225 @@ contract EmailAccountRecoveryTest_handleAcceptance is StructHelper { ); } + function testExpectRevertHandleAcceptanceInvalidRecoveredAccount() public { + skipIfZkSync(); + + EmailAuthMsg memory emailAuthMsg = buildEmailAuthMsg(); + emailAuthMsg.templateId = recoveryController + .computeAcceptanceTemplateId(0); + emailAuthMsg.commandParams[0] = abi.encode(address(0x0)); // Invalid account + + vm.startPrank(someRelayer); + vm.expectRevert(bytes("invalid command params")); + recoveryController.handleAcceptance(emailAuthMsg, 0); + vm.stopPrank(); + } + + function testExpectRevertHandleAcceptanceInvalidTemplateId() public { + skipIfZkSync(); + + uint templateIdx = 0; + + EmailAuthMsg memory emailAuthMsg = buildEmailAuthMsg(); + uint templateId = recoveryController.computeAcceptanceTemplateId( + templateIdx + ); + emailAuthMsg.templateId = 999; // invalid template id + bytes[] memory commandParamsForAcceptance = new bytes[](1); + commandParamsForAcceptance[0] = abi.encode(address(simpleWallet)); + emailAuthMsg.commandParams = commandParamsForAcceptance; + + vm.startPrank(someRelayer); + vm.expectRevert(bytes("invalid template id")); + recoveryController.handleAcceptance(emailAuthMsg, 0); + vm.stopPrank(); + } + + function testExpectRevertHandleAcceptanceInvalidEmailAuthMsgStructure() + public + { + skipIfZkSync(); + + requestGuardian(); + + require( + recoveryController.guardians(guardian) == + RecoveryController.GuardianStatus.REQUESTED + ); + + uint templateIdx = 0; + + // Create an invalid EmailAuthMsg with empty commandParams + EmailAuthMsg memory emailAuthMsg; + emailAuthMsg.templateId = recoveryController + .computeAcceptanceTemplateId(templateIdx); + emailAuthMsg.commandParams = new bytes[](0); // Invalid structure + + vm.mockCall( + address(recoveryController.emailAuthImplementationAddr()), + abi.encodeWithSelector(EmailAuth.authEmail.selector, emailAuthMsg), + abi.encode(0x0) + ); + + vm.startPrank(someRelayer); + vm.expectRevert(bytes("invalid command params")); + recoveryController.handleAcceptance(emailAuthMsg, templateIdx); + vm.stopPrank(); + } + + function testExpectRevertHandleAcceptanceInvalidVerifier() public { + skipIfZkSync(); + + requestGuardian(); + + require( + recoveryController.guardians(guardian) == + RecoveryController.GuardianStatus.REQUESTED + ); + + uint templateIdx = 0; + + EmailAuthMsg memory emailAuthMsg = buildEmailAuthMsg(); + uint templateId = recoveryController.computeAcceptanceTemplateId( + templateIdx + ); + emailAuthMsg.templateId = templateId; + bytes[] memory commandParamsForAcceptance = new bytes[](1); + commandParamsForAcceptance[0] = abi.encode(address(simpleWallet)); + emailAuthMsg.commandParams = commandParamsForAcceptance; + + // Set Verifier address to address(0) + vm.store( + address(recoveryController), + bytes32(uint256(0)), // Assuming Verifier is the 1st storage slot in RecoveryController + bytes32(uint256(0)) + ); + + vm.startPrank(someRelayer); + vm.expectRevert(bytes("invalid verifier address")); + recoveryController.handleAcceptance(emailAuthMsg, templateIdx); + vm.stopPrank(); + } + + function testExpectRevertHandleAcceptanceInvalidDKIMRegistry() public { + skipIfZkSync(); + + requestGuardian(); + + require( + recoveryController.guardians(guardian) == + RecoveryController.GuardianStatus.REQUESTED + ); + + uint templateIdx = 0; + + EmailAuthMsg memory emailAuthMsg = buildEmailAuthMsg(); + uint templateId = recoveryController.computeAcceptanceTemplateId( + templateIdx + ); + emailAuthMsg.templateId = templateId; + bytes[] memory commandParamsForAcceptance = new bytes[](1); + commandParamsForAcceptance[0] = abi.encode(address(simpleWallet)); + emailAuthMsg.commandParams = commandParamsForAcceptance; + + // Set DKIMRegistry address to address(0) + vm.store( + address(recoveryController), + bytes32(uint256(1)), // Assuming DKIMRegistry is the 2nd storage slot in RecoveryController + bytes32(uint256(0)) + ); + + vm.startPrank(someRelayer); + vm.expectRevert(bytes("invalid dkim registry address")); + recoveryController.handleAcceptance(emailAuthMsg, templateIdx); + vm.stopPrank(); + } + + function testExpectRevertHandleAcceptanceInvalidEmailAuthImplementationAddr() + public + { + skipIfZkSync(); + + requestGuardian(); + + require( + recoveryController.guardians(guardian) == + RecoveryController.GuardianStatus.REQUESTED + ); + + uint templateIdx = 0; + + EmailAuthMsg memory emailAuthMsg = buildEmailAuthMsg(); + uint templateId = recoveryController.computeAcceptanceTemplateId( + templateIdx + ); + emailAuthMsg.templateId = templateId; + bytes[] memory commandParamsForAcceptance = new bytes[](1); + commandParamsForAcceptance[0] = abi.encode(address(simpleWallet)); + emailAuthMsg.commandParams = commandParamsForAcceptance; + + // Set EmailAuthImplementationAddr address to address(0) + vm.store( + address(recoveryController), + bytes32(uint256(2)), // Assuming EmailAuthImplementationAddr is the 3rd storage slot in RecoveryController + bytes32(uint256(0)) + ); + + vm.startPrank(someRelayer); + vm.expectRevert( + abi.encodeWithSelector( + ERC1967Utils.ERC1967InvalidImplementation.selector, + address(0) + ) + ); + recoveryController.handleAcceptance(emailAuthMsg, templateIdx); + vm.stopPrank(); + } + + function testExpectRevertHandleAcceptanceInvalidController() public { + skipIfZkSync(); + + // First, request and accept a guardian + requestGuardian(); + uint templateIdx = 0; + EmailAuthMsg memory emailAuthMsg = buildEmailAuthMsg(); + uint templateId = recoveryController.computeAcceptanceTemplateId( + templateIdx + ); + emailAuthMsg.templateId = templateId; + bytes[] memory commandParamsForAcceptance = new bytes[](1); + commandParamsForAcceptance[0] = abi.encode(address(simpleWallet)); + emailAuthMsg.commandParams = commandParamsForAcceptance; + + vm.mockCall( + address(recoveryController.emailAuthImplementationAddr()), + abi.encodeWithSelector(EmailAuth.authEmail.selector, emailAuthMsg), + abi.encode(0x0) + ); + + vm.prank(someRelayer); + recoveryController.handleAcceptance(emailAuthMsg, templateIdx); + + require( + recoveryController.guardians(guardian) == + RecoveryController.GuardianStatus.ACCEPTED, + "Guardian should be accepted" + ); + + // Now, set an invalid controller for the guardian's EmailAuth contract + address invalidController = address(0x1234); + vm.mockCall( + guardian, + abi.encodeWithSelector(bytes4(keccak256("controller()"))), + abi.encode(invalidController) + ); + + // Try to handle acceptance again, which should fail due to invalid controller + vm.expectRevert("invalid controller"); + vm.prank(someRelayer); + recoveryController.handleAcceptance(emailAuthMsg, templateIdx); + } + function testHandleAcceptance() public { skipIfZkSync(); diff --git a/packages/contracts/test/EmailAccountRecovery/EmailAccountRecovery_handleRecovery.t.sol b/packages/contracts/test/EmailAccountRecovery/EmailAccountRecovery_handleRecovery.t.sol index ccaca48e..f324f20a 100644 --- a/packages/contracts/test/EmailAccountRecovery/EmailAccountRecovery_handleRecovery.t.sol +++ b/packages/contracts/test/EmailAccountRecovery/EmailAccountRecovery_handleRecovery.t.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.12; import "forge-std/Test.sol"; import "forge-std/console.sol"; import {EmailAuth, EmailAuthMsg} from "../../src/EmailAuth.sol"; -import {RecoveryController} from "../helpers/RecoveryController.sol"; +import {RecoveryController, EmailAccountRecovery} from "../helpers/RecoveryController.sol"; import {StructHelper} from "../helpers/StructHelper.sol"; import {SimpleWallet} from "../helpers/SimpleWallet.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; @@ -73,6 +73,126 @@ contract EmailAccountRecoveryTest_handleRecovery is StructHelper { ); } +function testExpectRevertHandleRecoveryInvalidRecoveredAccount() public { + skipIfZkSync(); + + EmailAuthMsg memory emailAuthMsg = buildEmailAuthMsg(); + emailAuthMsg.templateId = recoveryController.computeRecoveryTemplateId(0); + emailAuthMsg.commandParams[0] = abi.encode(address(0x0)); // Invalid account + + vm.startPrank(someRelayer); + vm.expectRevert(bytes("invalid account in email")); + recoveryController.handleRecovery(emailAuthMsg, 0); + vm.stopPrank(); +} + function testExpectRevertHandleRecoveryInvalidAccountInEmail() public { + skipIfZkSync(); + + handleAcceptance(); + + uint templateIdx = 0; + + EmailAuthMsg memory emailAuthMsg = buildEmailAuthMsg(); + emailAuthMsg.templateId = recoveryController.computeRecoveryTemplateId( + templateIdx + ); + bytes[] memory commandParamsForRecovery = new bytes[](2); + commandParamsForRecovery[0] = abi.encode(address(0x0)); // Invalid account + commandParamsForRecovery[1] = abi.encode(newSigner); + emailAuthMsg.commandParams = commandParamsForRecovery; + + vm.mockCall( + address(recoveryController.emailAuthImplementationAddr()), + abi.encodeWithSelector(EmailAuth.authEmail.selector, emailAuthMsg), + abi.encode(0x0) + ); + + vm.startPrank(someRelayer); + vm.expectRevert(bytes("invalid account in email")); + recoveryController.handleRecovery(emailAuthMsg, templateIdx); + vm.stopPrank(); + } + + function testExpectRevertHandleRecoveryGuardianCodeLengthZero() public { + skipIfZkSync(); + + handleAcceptance(); + + uint templateIdx = 0; + + EmailAuthMsg memory emailAuthMsg = buildEmailAuthMsg(); + emailAuthMsg.templateId = recoveryController.computeRecoveryTemplateId( + templateIdx + ); + bytes[] memory commandParamsForRecovery = new bytes[](2); + commandParamsForRecovery[0] = abi.encode(simpleWallet); + commandParamsForRecovery[1] = abi.encode(newSigner); + emailAuthMsg.commandParams = commandParamsForRecovery; + + // Mock guardian with no code + vm.etch(guardian, ""); + + vm.startPrank(someRelayer); + vm.expectRevert(bytes("guardian is not deployed")); + recoveryController.handleRecovery(emailAuthMsg, templateIdx); + vm.stopPrank(); + } + + function testExpectRevertHandleRecoveryTemplateIdMismatch() public { + skipIfZkSync(); + + handleAcceptance(); + + uint templateIdx = 0; + + EmailAuthMsg memory emailAuthMsg = buildEmailAuthMsg(); + emailAuthMsg.templateId = 999; // Invalid template ID + bytes[] memory commandParamsForRecovery = new bytes[](2); + commandParamsForRecovery[0] = abi.encode(simpleWallet); + commandParamsForRecovery[1] = abi.encode(newSigner); + emailAuthMsg.commandParams = commandParamsForRecovery; + + vm.mockCall( + address(recoveryController.emailAuthImplementationAddr()), + abi.encodeWithSelector(EmailAuth.authEmail.selector, emailAuthMsg), + abi.encode(0x0) + ); + + vm.startPrank(someRelayer); + vm.expectRevert(bytes("invalid template id")); + recoveryController.handleRecovery(emailAuthMsg, templateIdx); + vm.stopPrank(); + } + + function testExpectRevertHandleRecoveryAuthEmailFailure() public { + skipIfZkSync(); + + handleAcceptance(); + + uint templateIdx = 0; + + EmailAuthMsg memory emailAuthMsg = buildEmailAuthMsg(); + emailAuthMsg.templateId = recoveryController.computeRecoveryTemplateId( + templateIdx + ); + bytes[] memory commandParamsForRecovery = new bytes[](2); + commandParamsForRecovery[0] = abi.encode(simpleWallet); + commandParamsForRecovery[1] = abi.encode(newSigner); + emailAuthMsg.commandParams = commandParamsForRecovery; + + // Mock authEmail to fail + vm.mockCallRevert( + address(recoveryController.emailAuthImplementationAddr()), + abi.encodeWithSelector(EmailAuth.authEmail.selector, emailAuthMsg), + "REVERT_MESSAGE" + ); + + vm.startPrank(someRelayer); + vm.expectRevert(); // Expect any revert due to authEmail failure + recoveryController.handleRecovery(emailAuthMsg, templateIdx); + vm.stopPrank(); + } + function testHandleRecovery() public { skipIfZkSync(); diff --git a/packages/contracts/test/EmailAccountRecovery/EmailAccountRecovery_requestGuardian.t.sol b/packages/contracts/test/EmailAccountRecovery/EmailAccountRecovery_requestGuardian.t.sol index e03bdaf3..3e760fb5 100644 --- a/packages/contracts/test/EmailAccountRecovery/EmailAccountRecovery_requestGuardian.t.sol +++ b/packages/contracts/test/EmailAccountRecovery/EmailAccountRecovery_requestGuardian.t.sol @@ -10,48 +10,32 @@ import {SimpleWallet} from "../helpers/SimpleWallet.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; contract EmailAccountRecoveryTest_requestGuardian is StructHelper { + using stdStorage for StdStorage; + constructor() {} function setUp() public override { super.setUp(); } - function testRequestGuardian() public { + function testExpectRevertRequestGuardianRecoveryInProgress() public { skipIfZkSync(); setUp(); - require( - recoveryController.guardians(guardian) == - RecoveryController.GuardianStatus.NONE - ); - vm.startPrank(deployer); recoveryController.requestGuardian(guardian); - vm.stopPrank(); - - require( - recoveryController.guardians(guardian) == - RecoveryController.GuardianStatus.REQUESTED - ); - } - // function testRequestGuardianNotOwner() public { - // setUp(); + // Simulate recovery in progress + stdstore + .target(address(recoveryController)) + .sig("isRecovering(address)") + .with_key(address(deployer)) + .checked_write(true); - // require( - // recoveryController.guardians(guardian) == - // recoveryController.GuardianStatus.NONE - // ); - - // vm.startPrank(receiver); - // recoveryController.requestGuardian(guardian); - // vm.stopPrank(); - - // require( - // recoveryController.guardians(guardian) == - // recoveryController.GuardianStatus.NONE - // ); - // } + vm.expectRevert(bytes("recovery in progress")); + recoveryController.requestGuardian(address(0x123)); // Try to request a new guardian + vm.stopPrank(); + } function testExpectRevertRequestGuardianInvalidGuardian() public { skipIfZkSync(); @@ -85,4 +69,61 @@ contract EmailAccountRecoveryTest_requestGuardian is StructHelper { recoveryController.requestGuardian(guardian); vm.stopPrank(); } + + function testRequestGuardian() public { + skipIfZkSync(); + + setUp(); + require( + recoveryController.guardians(guardian) == + RecoveryController.GuardianStatus.NONE + ); + + vm.startPrank(deployer); + recoveryController.requestGuardian(guardian); + vm.stopPrank(); + + require( + recoveryController.guardians(guardian) == + RecoveryController.GuardianStatus.REQUESTED + ); + } + + function testMultipleGuardianRequests() public { + skipIfZkSync(); + + address anotherGuardian = vm.addr(9); + setUp(); + vm.startPrank(deployer); + recoveryController.requestGuardian(guardian); + recoveryController.requestGuardian(anotherGuardian); // Assuming anotherGuardian is defined + vm.stopPrank(); + + require( + recoveryController.guardians(guardian) == + RecoveryController.GuardianStatus.REQUESTED + ); + require( + recoveryController.guardians(anotherGuardian) == + RecoveryController.GuardianStatus.REQUESTED + ); + } + + // function testRequestGuardianNotOwner() public { + // setUp(); + + // require( + // recoveryController.guardians(guardian) == + // recoveryController.GuardianStatus.NONE + // ); + + // vm.startPrank(receiver); + // recoveryController.requestGuardian(guardian); + // vm.stopPrank(); + + // require( + // recoveryController.guardians(guardian) == + // recoveryController.GuardianStatus.NONE + // ); + // } }