Skip to content

Commit

Permalink
Merge pull request #18 from zkemail/feat/clean-up-and-documentation
Browse files Browse the repository at this point in the history
Feat/clean up and documentation
  • Loading branch information
JohnGuilding committed Jul 4, 2024
2 parents bbacc56 + e0cf7bf commit 4e70316
Show file tree
Hide file tree
Showing 33 changed files with 665 additions and 297 deletions.
6 changes: 0 additions & 6 deletions .gitmodules

This file was deleted.

133 changes: 95 additions & 38 deletions README.md

Large diffs are not rendered by default.

Binary file added docs/email-recovery-diagram.drawio.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/recovery-module-contracts.drawio.png
Binary file not shown.
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@ quote_style = "double"
tab_width = 4
wrap_comments = true
ignore = [
"./src/zksyncDeps/contracts/L2ContractHelper.sol",
"./src/libraries/L2ContractHelper.sol",
]
1 change: 0 additions & 1 deletion lib/email-wallet-sdk
Submodule email-wallet-sdk deleted from a8c200
1 change: 0 additions & 1 deletion lib/ether-email-auth
Submodule ether-email-auth deleted from 6eebd9
34 changes: 17 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"name": "@rhinestone/module-template",
"version": "0.4.1",
"description": "A Foundry template for building modules using the ModuleKit",
"license": "GPL-3.0",
"name": "email-recovery",
"version": "0.0.1",
"description": "Smart account module and related contracts to enable email recovery for validators",
"license": "MIT",
"author": {
"name": "Rhinestone",
"url": "https://rhinestone.wtf"
"name": "email-recovery",
"url": "https://prove.email/"
},
"scripts": {
"build": "forge build",
Expand All @@ -21,18 +21,18 @@
"prettier:check": "prettier --check \"**/*.{json,md,svg,yml}\"",
"prettier:write": "prettier --write \"**/*.{json,md,svg,yml}\"",
"test": "forge test",
"test:safe": "ACCOUNT_TYPE=SAFE forge test",
"test:kernel": "ACCOUNT_TYPE=KERNEL forge test",
"test:lite": "FOUNDRY_PROFILE=lite forge test",
"test:optimized": "pnpm run build:optimized && FOUNDRY_PROFILE=test-optimized forge test"
},
"dependencies": {
"@openzeppelin/contracts-upgradeable": "v5.0.1",
"@zk-email/contracts": "v6.0.3",
"@matterlabs": "github:matter-labs/era-contracts",
"@openzeppelin/contracts-upgradeable": "v5.0.1",
"@rhinestone/modulekit": "github:rhinestonewtf/modulekit#test/safe-latest",
"erc7579-implementation": "https://github.com/erc7579/erc7579-implementation.git",
"solidity-stringutils": "https://github.com/Arachnid/solidity-stringutils.git"
"@zk-email/contracts": "v6.0.3",
"email-wallet-sdk": "github:zkemail/email-wallet-sdk",
"erc7579-implementation": "github:erc7579/erc7579-implementation",
"ether-email-auth": "github:zkemail/ether-email-auth",
"solidity-stringutils": "github:Arachnid/solidity-stringutils"
},
"files": [
"src",
Expand All @@ -42,18 +42,18 @@
"foundry.toml",
"remappings.txt"
],
"homepage": "https://docs.rhinestone.wtf/module-template",
"repository": {
"type": "git",
"url": "git+https://github.com/rhinestonewtf/module-template.git"
"url": "git+https://github.com/zkemail/email-recovery.git"
},
"bugs": {
"url": "https://github.com/rhinestonewtf/module-template/issues"
"url": "https://github.com/zkemail/email-recovery/issues"
},
"keywords": [
"zk email",
"recovery",
"account abstraction",
"smart account modules",
"module template"
"smart account modules"
],
"publishConfig": {
"access": "public"
Expand Down
169 changes: 137 additions & 32 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions remappings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ solady/=node_modules/solady/src/
solarray/=node_modules/solarray/src/
@prb/math/=node_modules/@prb/math/src/

ether-email-auth/=lib/ether-email-auth/
ether-email-auth/=node_modules/ether-email-auth/
@zk-email/contracts/=node_modules/@zk-email/contracts/
solidity-stringutils/=node_modules/solidity-stringutils/
@matterlabs/zksync-contracts/l2/=src/zksyncDeps/
@matterlabs/zksync-contracts/l2/contracts/=src/libraries/
erc7579-implementation/=node_modules/erc7579-implementation/
kernel/=node_modules/@zerodev/kernel/src/
ExcessivelySafeCall/=node_modules/excessively-safe-call/src/
2 changes: 1 addition & 1 deletion script/DeployEmailRecoveryModule.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Verifier } from "ether-email-auth/packages/contracts/src/utils/Verifier
import { ECDSAOwnedDKIMRegistry } from
"ether-email-auth/packages/contracts/src/utils/ECDSAOwnedDKIMRegistry.sol";
import { EmailAuth } from "ether-email-auth/packages/contracts/src/EmailAuth.sol";
import { EmailRecoveryFactory } from "src/EmailRecoveryFactory.sol";
import { EmailRecoveryFactory } from "src/factories/EmailRecoveryFactory.sol";
import { OwnableValidator } from "src/test/OwnableValidator.sol";

contract DeployEmailRecoveryModuleScript is Script {
Expand Down
4 changes: 2 additions & 2 deletions script/DeploySafeRecovery.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ pragma solidity ^0.8.25;
import { Script } from "forge-std/Script.sol";
import { console } from "forge-std/console.sol";
import { SafeRecoverySubjectHandler } from "src/handlers/SafeRecoverySubjectHandler.sol";
import { EmailRecoveryFactory } from "src/EmailRecoveryFactory.sol";
import { EmailRecoveryUniversalFactory } from "src/EmailRecoveryUniversalFactory.sol";
import { EmailRecoveryFactory } from "src/factories/EmailRecoveryFactory.sol";
import { EmailRecoveryUniversalFactory } from "src/factories/EmailRecoveryUniversalFactory.sol";
import { Verifier } from "ether-email-auth/packages/contracts/src/utils/Verifier.sol";
import { ECDSAOwnedDKIMRegistry } from
"ether-email-auth/packages/contracts/src/utils/ECDSAOwnedDKIMRegistry.sol";
Expand Down
2 changes: 1 addition & 1 deletion script/DeployUniversalEmailRecoveryModule.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Verifier } from "ether-email-auth/packages/contracts/src/utils/Verifier
import { ECDSAOwnedDKIMRegistry } from
"ether-email-auth/packages/contracts/src/utils/ECDSAOwnedDKIMRegistry.sol";
import { EmailAuth } from "ether-email-auth/packages/contracts/src/EmailAuth.sol";
import { EmailRecoveryUniversalFactory } from "src/EmailRecoveryUniversalFactory.sol";
import { EmailRecoveryUniversalFactory } from "src/factories/EmailRecoveryUniversalFactory.sol";

contract DeployUniversalEmailRecoveryModuleScript is Script {
function run() public {
Expand Down
57 changes: 0 additions & 57 deletions src/EmailRecoveryFactory.sol

This file was deleted.

102 changes: 76 additions & 26 deletions src/EmailRecoveryManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ import { GuardianUtils } from "./libraries/GuardianUtils.sol";
*
* 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 recovery module defines “how that recovery attempt is executed on the account”. A
* specific email subject handler is also accociated with a recovery manager. A subject handler
* defines and validates the recovery email subjects. Developers can write their own subject
* handlers to make specifc subjects for recovering modules
*/
contract EmailRecoveryManager is EmailAccountRecovery, Initializable, IEmailRecoveryManager {
using GuardianUtils for mapping(address => GuardianConfig);
Expand Down Expand Up @@ -142,11 +145,9 @@ contract EmailRecoveryManager is EmailAccountRecovery, Initializable, IEmailReco
/**
* @notice Returns a two-dimensional array of strings representing the subject templates for an
* acceptance by a new guardian.
* @dev This function is overridden from EmailAccountRecovery. It is also virtual so can be
* re-implemented by inheriting contracts
* to define different acceptance subject templates. This is useful for account implementations
* which require different data
* in the subject or if the email should be in a language that is not English.
* @dev This is retrieved from the associated subject handler. Developers can write their own
* subject handlers, this is useful for account implementations which require different data 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.
*/
Expand All @@ -157,18 +158,23 @@ contract EmailRecoveryManager is EmailAccountRecovery, Initializable, IEmailReco
/**
* @notice Returns a two-dimensional array of strings representing the subject templates for
* email recovery.
* @dev This function is overridden from EmailAccountRecovery. It is also virtual so can be
* re-implemented by inheriting contracts
* to define different recovery subject templates. This is useful for account implementations
* which require different data
* in the subject or if the email should be in a language that is not English.
* @dev This is retrieved from the associated subject handler. Developers can write their own
* subject handlers, this is useful for account implementations which require different data 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 view override returns (string[][] memory) {
return IEmailRecoverySubjectHandler(subjectHandler).recoverySubjectTemplates();
}

/**
* @notice Extracts the account address to be recovered from the subject parameters of an
* acceptance email.
* @dev This is retrieved from the associated subject handler.
* @param subjectParams The subject parameters of the acceptance email.
* @param templateIdx The index of the acceptance subject template.
*/
function extractRecoveredAccountFromAcceptanceSubject(
bytes[] memory subjectParams,
uint256 templateIdx
Expand All @@ -182,6 +188,13 @@ contract EmailRecoveryManager is EmailAccountRecovery, Initializable, IEmailReco
.extractRecoveredAccountFromAcceptanceSubject(subjectParams, templateIdx);
}

/**
* @notice Extracts the account address to be recovered from the subject parameters of a
* recovery email.
* @dev This is retrieved from the associated subject handler.
* @param subjectParams The subject parameters of the recovery email.
* @param templateIdx The index of the recovery subject template.
*/
function extractRecoveredAccountFromRecoverySubject(
bytes[] memory subjectParams,
uint256 templateIdx
Expand All @@ -202,8 +215,9 @@ contract EmailRecoveryManager is EmailAccountRecovery, Initializable, IEmailReco
/**
* @notice Configures recovery for the caller's account. This is the first core function
* that must be called during the end-to-end recovery flow
* @dev Can only be called once for configuration. Sets up the guardians, deploys a router
* contract, and validates config parameters, ensuring that no recovery is in process
* @dev Can only be called once for configuration. Sets up the guardians, and validates config
* parameters, ensuring that no recovery is in process. It is possible to configure guardians at
* a later stage if neccessary
* @param guardians An array of guardian addresses
* @param weights An array of weights corresponding to each guardian
* @param threshold The threshold weight required for recovery
Expand Down Expand Up @@ -247,9 +261,7 @@ contract EmailRecoveryManager is EmailAccountRecovery, Initializable, IEmailReco
/**
* @notice Updates and validates the recovery configuration for the caller's account
* @dev Validates and sets the new recovery configuration for the caller's account, ensuring
* that no
* recovery is in process. Reverts if the recovery module address is invalid, if the
* delay is greater than the expiry, or if the recovery window is too short
* that no recovery is in process.
* @param recoveryConfig The new recovery configuration to be set for the caller's account
*/
function updateRecoveryConfig(RecoveryConfig memory recoveryConfig)
Expand Down Expand Up @@ -281,10 +293,9 @@ contract EmailRecoveryManager is EmailAccountRecovery, Initializable, IEmailReco
* @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 explicitly consents to the role. Called as part of handleAcceptance
* in EmailAccountRecovery
* 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 subjectParams An array of bytes containing the subject parameters
Expand Down Expand Up @@ -333,8 +344,7 @@ contract EmailRecoveryManager is EmailAccountRecovery, Initializable, IEmailReco
/**
* @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 Reverts if the guardian address is invalid, if the template index is not zero, or if the
* guardian status is not accepted
* @dev Called once per guardian until the threshold is reached
* @param guardian The address of the guardian initiating the recovery
* @param templateIdx The index of the template used for the recovery request
* @param subjectParams An array of bytes containing the subject parameters
Expand Down Expand Up @@ -393,11 +403,11 @@ contract EmailRecoveryManager is EmailAccountRecovery, Initializable, IEmailReco
* anyone.
* @dev Validates the recovery request by checking the total weight, that the delay has passed,
* and the request has not expired. Triggers the recovery module to perform the recovery. The
* recovery module trusts that this contract has validated the recovery attempt. Deletes the
* recovery
* request but recovery config state is maintained so future recovery requests can be made
* without having to reconfigure everything
* recovery module trusts that this contract has validated the recovery attempt. This function
* deletes the recovery request but recovery config state is maintained so future recovery
* requests can be made without having to reconfigure everything
* @param account The address of the account for which the recovery is being completed
* @param recoveryCalldata The calldata that is passed to recover the validator
*/
function completeRecovery(address account, bytes memory recoveryCalldata) public override {
if (account == address(0)) {
Expand Down Expand Up @@ -476,10 +486,22 @@ contract EmailRecoveryManager is EmailAccountRecovery, Initializable, IEmailReco
/* GUARDIAN LOGIC */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/**
* @notice Retrieves the guardian configuration for a given account
* @param account The address of the account for which the guardian configuration is being
* retrieved
* @return GuardianConfig The guardian configuration for the specified account
*/
function getGuardianConfig(address account) external view returns (GuardianConfig memory) {
return guardianConfigs[account];
}

/**
* @notice Retrieves the guardian storage details for a given guardian and account
* @param account The address of the account associated with the guardian
* @param guardian The address of the guardian
* @return GuardianStorage The guardian storage details for the specified guardian and account
*/
function getGuardian(
address account,
address guardian
Expand All @@ -491,6 +513,15 @@ contract EmailRecoveryManager is EmailAccountRecovery, Initializable, IEmailReco
return guardiansStorage.getGuardianStorage(account, guardian);
}

/**
* @notice Sets up guardians for a given account with specified weights and threshold
* @dev This function can only be called once and ensures the guardians, weights, and threshold
* are correctly configured
* @param account The address of the account for which guardians are being set up
* @param guardians An array of guardian addresses
* @param weights An array of weights corresponding to each guardian
* @param threshold The threshold weight required for guardians to approve recovery attempts
*/
function setupGuardians(
address account,
address[] memory guardians,
Expand All @@ -502,14 +533,33 @@ contract EmailRecoveryManager is EmailAccountRecovery, Initializable, IEmailReco
guardianConfigs.setupGuardians(guardiansStorage, account, guardians, weights, threshold);
}

/**
* @notice Adds a guardian for the caller's account with a specified weight
* @dev This function can only be called by the account associated with the guardian and only if
* no recovery is in process
* @param guardian The address of the guardian to be added
* @param weight The weight assigned to the guardian
*/
function addGuardian(address guardian, uint256 weight) external onlyWhenNotRecovering {
guardiansStorage.addGuardian(guardianConfigs, msg.sender, guardian, weight);
}

/**
* @notice Removes a guardian for the caller's account
* @dev This function can only be called by the account associated with the guardian and only if
* no recovery is in process
* @param guardian The address of the guardian to be removed
*/
function removeGuardian(address guardian) external onlyWhenNotRecovering {
guardiansStorage.removeGuardian(guardianConfigs, msg.sender, guardian);
}

/**
* @notice Changes the threshold for guardian approvals for the caller's account
* @dev This function can only be called by the account associated with the guardian config and
* only if no recovery is in process
* @param threshold The new threshold for guardian approvals
*/
function changeThreshold(uint256 threshold) external onlyWhenNotRecovering {
guardianConfigs.changeThreshold(msg.sender, threshold);
}
Expand Down
Loading

0 comments on commit 4e70316

Please sign in to comment.