Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions contracts/EmailRecoveryCommandHandler.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {IEmailRecoveryCommandHandler} from "@zk-email/email-recovery/src/interfaces/IEmailRecoveryCommandHandler.sol";
import {IEmailRecoveryManager} from "@zk-email/email-recovery/src/interfaces/IEmailRecoveryManager.sol";
import {IEmailRecoveryCommandHandler} from "@zk-email/email-recovery-clave/src/interfaces/IEmailRecoveryCommandHandler.sol";
import {IEmailRecoveryManager} from "@zk-email/email-recovery-clave/src/interfaces/IEmailRecoveryManager.sol";
import {StringUtils} from "@zk-email/ether-email-auth-contracts/src/libraries/StringUtils.sol";

/**
Expand Down
99 changes: 95 additions & 4 deletions contracts/EmailRecoveryModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,58 @@
pragma solidity ^0.8.17;

import {IModule} from "./interfaces/IModule.sol";
import {IEmailRecoveryModule} from "@zk-email/email-recovery/src/interfaces/IEmailRecoveryModule.sol";
import {IEmailRecoveryModule} from "@zk-email/email-recovery-clave/src/interfaces/IEmailRecoveryModule.sol";
import {IClaveAccount} from "./interfaces/IClave.sol";
import {Errors} from "./libraries/Errors.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {EmailRecoveryManagerZkSync} from "@zk-email/email-recovery/src/EmailRecoveryManagerZkSync.sol";
import {GuardianManager} from "@zk-email/email-recovery/src/GuardianManager.sol";
import {EmailRecoveryManagerZkSync} from "@zk-email/email-recovery-clave/src/EmailRecoveryManagerZkSync.sol";
import {EmailRecoveryManager} from "@zk-email/email-recovery-clave/src/EmailRecoveryManager.sol";
import {GuardianManager} from "@zk-email/email-recovery-clave/src/GuardianManager.sol";
import {EmailAccountRecovery} from "@zk-email/ether-email-auth-contracts/src/EmailAccountRecovery.sol";

contract EmailRecoveryModule is
EmailRecoveryManagerZkSync,
IModule,
IEmailRecoveryModule
{
/**
* Deployment timestamp
*/
uint256 public immutable deploymentTimestamp;

/**
* Account address to isInited
*/
mapping(address account => bool) internal inited;

/**
* Account address to initiate transactions
*/
mapping(address account => bool isInitiator) internal transactionInitiators;

/**
* @notice Emitted when a recovery is executed
* @param account address - Recovered account
* @param newOwner bytes - New owner of the account
*/
event RecoveryExecuted(address indexed account, bytes newOwner);

/**
* @notice Modifier to check if the caller is an initiator
*/
modifier isInitiator() {
Comment thread
aalimsahin marked this conversation as resolved.
bool isOpenToAll = transactionInitiators[address(0)] ||
block.timestamp >= deploymentTimestamp + 6 * 30 days;

if (!isOpenToAll) {
require(
transactionInitiators[msg.sender],
"Only allowed accounts can call this function"
);
}
_;
}

/**
* @notice Initializes the EmailRecoveryModule contract
* @param _verifier Address of the verifier contract
Expand Down Expand Up @@ -57,7 +85,9 @@ contract EmailRecoveryModule is
_factoryAddr,
_proxyBytecodeHash
)
{}
{
deploymentTimestamp = block.timestamp;
}

/**
* @notice Initializes the recovery module for the calling account using the provided configuration data.
Expand Down Expand Up @@ -113,6 +143,17 @@ contract EmailRecoveryModule is
emit Disabled(msg.sender);
}

/**
* @notice Sets the transaction initiator status for an account
* @dev Can only be called by the kill switch authorizer
*/
function setTransactionInitiator(
address account,
bool canInitiate
) external onlyOwner {
transactionInitiators[account] = canInitiate;
}

function canStartRecoveryRequest(
address account
) external view returns (bool) {
Expand All @@ -134,6 +175,55 @@ contract EmailRecoveryModule is
interfaceId == type(IERC165).interfaceId;
}

/**
* @notice Accepts a guardian for the specified account. This is the second core function
* that must be called during the end-to-end recovery flow
* @dev Called once per guardian added. Although this adds an extra step to recovery, this
* acceptance flow is an important security feature to ensure that no typos are made when adding
* a guardian, and that the guardian is in control of the specified email address. Called as
* part of handleAcceptance in EmailAccountRecovery
* @param guardian The address of the guardian to be accepted
* @param templateIdx The index of the template used for acceptance
* @param commandParams An array of bytes containing the command parameters
* @param nullifier The unique identifier for an email (unused in this implementation)
*/
function acceptGuardian(
address guardian,
uint256 templateIdx,
bytes[] memory commandParams,
bytes32 nullifier
)
internal
override(EmailAccountRecovery, EmailRecoveryManager)
onlyWhenActive
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was there a reason onlyWhenActive was added here? onlyWhenActive will be called twice so can be safely removed here and for processRecovery. Unless you wanted to execute it twice but always show the KillSwitchEnabled first if that error occurrs at the same time as "Only allowed accounts can call this function"

isInitiator
{
super.acceptGuardian(guardian, templateIdx, commandParams, nullifier);
}

/**
* @notice Processes a recovery request for a given account. This is the third core function
* that must be called during the end-to-end recovery flow
* @dev Called once per guardian until the threshold is reached
* @param guardian The address of the guardian initiating/voting on the recovery request
* @param templateIdx The index of the template used for the recovery request
* @param commandParams An array of bytes containing the command parameters
* @param nullifier The unique identifier for an email (unused in this implementation)
*/
function processRecovery(
address guardian,
uint256 templateIdx,
bytes[] memory commandParams,
bytes32 nullifier
)
internal
override(EmailAccountRecovery, EmailRecoveryManager)
onlyWhenActive
isInitiator
{
super.processRecovery(guardian, templateIdx, commandParams, nullifier);
}

/**
* @notice Recovers the ownership or control of the given account by setting a new owner or validator.
* @dev
Expand All @@ -145,6 +235,7 @@ contract EmailRecoveryModule is
* @param account The address of the account for which the recovery is being executed.
* @param newOwner The new owner of the account
*/

function recover(
address account,
bytes calldata newOwner
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"@openzeppelin/contracts": "^5.0.0",
"@openzeppelin/contracts-upgradeable": "^5.0.0",
"@zk-email/contracts": "6.3.2",
"@zk-email/email-recovery": "1.1.0",
"@zk-email/email-recovery-clave": "1.1.1",
"@zk-email/ether-email-auth-contracts": "1.1.0",
"commander": "^12.1.0",
"ts-morph": "^19.0.0"
Expand Down
89 changes: 10 additions & 79 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# yarn lockfile v1


"@ERC4337/account-abstraction-v0.6@github:eth-infinitism/account-abstraction#v0.6.0":
"@ERC4337/account-abstraction-v0.6@github:eth-infinitism/account-abstraction#v0.6.0", "account-abstraction-v0.6@github:eth-infinitism/account-abstraction#v0.6.0":
version "0.6.0"
resolved "https://codeload.github.com/eth-infinitism/account-abstraction/tar.gz/abff2aca61a8f0934e533d0d352978055fddbd96"
dependencies:
Expand All @@ -21,7 +21,7 @@
table "^6.8.0"
typescript "^4.3.5"

"@ERC4337/account-abstraction@github:kopy-kat/account-abstraction#develop":
"@ERC4337/account-abstraction@github:kopy-kat/account-abstraction#develop", "account-abstraction@github:kopy-kat/account-abstraction#develop":
version "0.7.0"
resolved "https://codeload.github.com/kopy-kat/account-abstraction/tar.gz/c5887153fbfe3ed09b2637cac39873f96d676f38"
dependencies:
Expand Down Expand Up @@ -1062,7 +1062,7 @@
node-fetch "^2.6.0"
semver "^6.3.0"

"@openzeppelin/contracts-hardhat-zksync-upgradable@npm:@openzeppelin/contracts@^5.0.2":
"@openzeppelin/contracts-hardhat-zksync-upgradable@npm:@openzeppelin/contracts@^5.0.2", "@openzeppelin/contracts@^5.0.0":
version "5.1.0"
resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-5.1.0.tgz#4e61162f2a2bf414c4e10c45eca98ce5f1aadbd4"
integrity sha512-p1ULhl7BXzjjbha5aqst+QMLY+4/LCWADXOCsmLHRM77AqiPjnd9vvUN9sosUfhL9JGKpZ0TjEGxgvnizmWGSA==
Expand Down Expand Up @@ -1097,11 +1097,6 @@
resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.6.tgz#2a880a24eb19b4f8b25adc2a5095f2aa27f39677"
integrity sha512-xSmezSupL+y9VkHZJGDoCBpmnB2ogM13ccaYDWqJTfS3dbuHkgjuwDFUmaFauBCboQMGB/S5UqUl2y54X99BmA==

"@openzeppelin/contracts@^5.0.0":
version "5.1.0"
resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-5.1.0.tgz#4e61162f2a2bf414c4e10c45eca98ce5f1aadbd4"
integrity sha512-p1ULhl7BXzjjbha5aqst+QMLY+4/LCWADXOCsmLHRM77AqiPjnd9vvUN9sosUfhL9JGKpZ0TjEGxgvnizmWGSA==

"@openzeppelin/contracts@~4.3.3":
version "4.3.3"
resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.3.3.tgz#ff6ee919fc2a1abaf72b22814bfb72ed129ec137"
Expand Down Expand Up @@ -1685,10 +1680,10 @@
"@openzeppelin/contracts-upgradeable" "^5.0.0"
dotenv "^16.3.1"

"@zk-email/email-recovery@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@zk-email/email-recovery/-/email-recovery-1.1.0.tgz#1f17fe9fb75c35d333e3fc7eb30c4b69fb612ffc"
integrity sha512-Psbu0Zh+HoItvHPX5MjGSsogfHFnX1z4RxcReLyGEBGgN6kR623bz0nCL/U/S7gtDydp+eZ0nrtNiXZ2qyoB+g==
"@zk-email/email-recovery-clave@1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@zk-email/email-recovery-clave/-/email-recovery-clave-1.1.1.tgz#d52edd50a8c288d840142dd4bef0a3833ba326d6"
integrity sha512-Fw/JwncYmJexudlqKm9hgVIJOl5vR2DUokaJVajF6ojkK+5BYTFQFFnZVXB0f5sqVIj4hk8Hx3ymxbaujio0Xw==
dependencies:
"@matterlabs/era-contracts" "github:matter-labs/era-contracts"
"@openzeppelin/contracts-upgradeable" "5.0.1"
Expand Down Expand Up @@ -1728,45 +1723,6 @@ abbrev@1.0.x:
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135"
integrity sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==

"account-abstraction-v0.6@github:eth-infinitism/account-abstraction#v0.6.0":
version "0.6.0"
resolved "https://codeload.github.com/eth-infinitism/account-abstraction/tar.gz/abff2aca61a8f0934e533d0d352978055fddbd96"
dependencies:
"@gnosis.pm/safe-contracts" "^1.3.0"
"@nomiclabs/hardhat-etherscan" "^2.1.6"
"@openzeppelin/contracts" "^4.2.0"
"@thehubbleproject/bls" "^0.5.1"
"@typechain/hardhat" "^2.3.0"
"@types/mocha" "^9.0.0"
ethereumjs-util "^7.1.0"
ethereumjs-wallet "^1.0.1"
hardhat-deploy "^0.11.23"
hardhat-deploy-ethers "^0.3.0-beta.11"
solidity-coverage "^0.8.2"
source-map-support "^0.5.19"
table "^6.8.0"
typescript "^4.3.5"

"account-abstraction@github:kopy-kat/account-abstraction#develop":
version "0.7.0"
resolved "https://codeload.github.com/kopy-kat/account-abstraction/tar.gz/c5887153fbfe3ed09b2637cac39873f96d676f38"
dependencies:
"@nomiclabs/hardhat-etherscan" "^2.1.6"
"@openzeppelin/contracts" "^5.0.0"
"@thehubbleproject/bls" "^0.5.1"
"@typechain/hardhat" "^2.3.0"
"@types/debug" "^4.1.12"
"@types/mocha" "^9.0.0"
debug "^4.3.4"
ethereumjs-util "^7.1.0"
ethereumjs-wallet "^1.0.1"
hardhat-deploy "^0.11.23"
hardhat-deploy-ethers "^0.3.0-beta.11"
solidity-coverage "^0.8.4"
source-map-support "^0.5.19"
table "^6.8.0"
typescript "^4.3.5"

acorn-walk@^8.1.1:
version "8.3.4"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7"
Expand Down Expand Up @@ -5162,16 +5118,7 @@ string-format@^2.0.0:
resolved "https://registry.yarnpkg.com/string-format/-/string-format-2.0.0.tgz#f2df2e7097440d3b65de31b6d40d54c96eaffb9b"
integrity sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==

"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"

string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
Expand Down Expand Up @@ -5208,14 +5155,7 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"

"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"

strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
Expand Down Expand Up @@ -5700,16 +5640,7 @@ workerpool@^6.5.1:
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544"
integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==

"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"

wrap-ansi@^7.0.0:
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
Expand Down