Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

13 EmailRecoveryManager delay can be set to zero #56

Merged
Merged
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
6 changes: 3 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ env:

jobs:
build:
uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-build.yaml@15f6d25eb382057ce7c513de7f38f4b6bca49f1d"
uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-build.yaml@main"

test-multi-account:
needs: ["build"]
uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-test-multi-account.yaml@15f6d25eb382057ce7c513de7f38f4b6bca49f1d"
uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-test-multi-account.yaml@main"
with:
foundry-fuzz-runs: 5000
foundry-profile: "test"
match-path: "test/**/*.sol"

test-simulate:
needs: ["build"]
uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-test-simulate.yaml@15f6d25eb382057ce7c513de7f38f4b6bca49f1d"
uses: "rhinestonewtf/reusable-workflows/.github/workflows/forge-test-simulate.yaml@main"

with:
foundry-fuzz-runs: 5000
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zk-email/email-recovery",
"version": "0.0.10",
"version": "0.0.11-preview",
"description": "Smart account module and related contracts to enable email recovery for validators",
"license": "MIT",
"author": {
Expand Down Expand Up @@ -34,8 +34,8 @@
"@matterlabs/era-contracts": "github:matter-labs/era-contracts",
"@openzeppelin/contracts-upgradeable": "5.0.1",
"@rhinestone/modulekit": "github:rhinestonewtf/modulekit",
"@zk-email/contracts": "https://gitpkg.vercel.app/zkemail/zk-email-verify/packages/contracts?feat/dkim-registry-updates",
"@zk-email/ether-email-auth-contracts": "https://gitpkg.vercel.app/zkemail/ether-email-auth/packages/contracts?feat/audit-fix-2024-09-registry",
"@zk-email/contracts": "https://gitpkg.vercel.app/zkemail/zk-email-verify/packages/contracts?057b8e95b7bca2884d8da384379c15be9975b30d",
"@zk-email/ether-email-auth-contracts": "0.2.0-preview",
"erc7579-implementation": "github:erc7579/erc7579-implementation",
"solidity-stringutils": "github:LayerZero-Labs/solidity-stringutils"
},
Expand Down
151 changes: 75 additions & 76 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions script/DeployEmailRecoveryModule.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ contract DeployEmailRecoveryModuleScript is Script {
address dkimRegistrySigner = vm.envOr("DKIM_REGISTRY_SIGNER", address(0));
address emailAuthImpl = vm.envOr("EMAIL_AUTH_IMPL", address(0));
address validatorAddr = vm.envOr("VALIDATOR", address(0));
uint256 minimumDelay = vm.envOr("MINIMUM_DELAY", uint256(0));

address initialOwner = vm.addr(vm.envUint("PRIVATE_KEY"));

Expand Down Expand Up @@ -84,6 +85,7 @@ contract DeployEmailRecoveryModuleScript is Script {
bytes32(uint256(0)),
bytes32(uint256(0)),
type(EmailRecoveryCommandHandler).creationCode,
minimumDelay,
address(dkim),
validatorAddr,
bytes4(keccak256(bytes("changeOwner(address)")))
Expand Down
5 changes: 4 additions & 1 deletion script/DeploySafeNativeRecovery.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ contract DeploySafeNativeRecovery_Script is Script {
address dkimRegistrySigner = vm.envOr("DKIM_REGISTRY_SIGNER", address(0));
address emailAuthImpl = vm.envOr("EMAIL_AUTH_IMPL", address(0));
address commandHandler = vm.envOr("COMMAND_HANDLER", address(0));
uint256 minimumDelay = vm.envOr("MINIMUM_DELAY", uint256(0));

address initialOwner = vm.addr(vm.envUint("PRIVATE_KEY"));

Expand Down Expand Up @@ -74,7 +75,9 @@ contract DeploySafeNativeRecovery_Script is Script {
}

address module = address(
new SafeEmailRecoveryModule(verifier, address(dkim), emailAuthImpl, commandHandler)
new SafeEmailRecoveryModule(
verifier, address(dkim), emailAuthImpl, commandHandler, minimumDelay
)
);

console.log("Deployed Email Recovery Module at ", vm.toString(module));
Expand Down
2 changes: 2 additions & 0 deletions script/DeploySafeRecovery.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ contract DeploySafeRecovery_Script is Script {
address verifier = vm.envOr("VERIFIER", address(0));
address dkimRegistrySigner = vm.envOr("DKIM_REGISTRY_SIGNER", address(0));
address emailAuthImpl = vm.envOr("EMAIL_AUTH_IMPL", address(0));
uint256 minimumDelay = vm.envOr("MINIMUM_DELAY", uint256(0));

address initialOwner = vm.addr(vm.envUint("PRIVATE_KEY"));
uint256 salt = vm.envOr("CREATE2_SALT", uint256(0));
Expand Down Expand Up @@ -83,6 +84,7 @@ contract DeploySafeRecovery_Script is Script {
bytes32(salt),
bytes32(salt),
type(SafeRecoveryCommandHandler).creationCode,
minimumDelay,
address(dkim)
);

Expand Down
2 changes: 2 additions & 0 deletions script/DeploySafeRecoveryWithAccountHiding.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ contract DeploySafeRecoveryWithAccountHiding_Script is Script {
address dkimRegistry = vm.envOr("DKIM_REGISTRY", address(0));
address dkimRegistrySigner = vm.envOr("SIGNER", address(0));
address emailAuthImpl = vm.envOr("EMAIL_AUTH_IMPL", address(0));
uint256 minimumDelay = vm.envOr("MINIMUM_DELAY", uint256(0));

address initialOwner = vm.addr(vm.envUint("PRIVATE_KEY"));

Expand Down Expand Up @@ -82,6 +83,7 @@ contract DeploySafeRecoveryWithAccountHiding_Script is Script {
bytes32(uint256(0)),
bytes32(uint256(0)),
type(AccountHidingRecoveryCommandHandler).creationCode,
minimumDelay,
dkimRegistry
);

Expand Down
2 changes: 2 additions & 0 deletions script/DeployUniversalEmailRecoveryModule.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ contract DeployUniversalEmailRecoveryModuleScript is Script {
address verifier = vm.envOr("VERIFIER", address(0));
address dkimRegistrySigner = vm.envOr("DKIM_REGISTRY_SIGNER", address(0));
address emailAuthImpl = vm.envOr("EMAIL_AUTH_IMPL", address(0));
uint256 minimumDelay = vm.envOr("MINIMUM_DELAY", uint256(0));

address initialOwner = vm.addr(vm.envUint("PRIVATE_KEY"));

Expand Down Expand Up @@ -77,6 +78,7 @@ contract DeployUniversalEmailRecoveryModuleScript is Script {
bytes32(uint256(0)),
bytes32(uint256(0)),
type(EmailRecoveryCommandHandler).creationCode,
minimumDelay,
address(dkim)
);

Expand Down
3 changes: 3 additions & 0 deletions script/test/BaseDeployTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ abstract contract BaseDeployTest is Test {
address dkimRegistry = deployDKIMRegistry(dkimRegistrySigner);
vm.setEnv("DKIM_REGISTRY", vm.toString(address(dkimRegistry)));

vm.setEnv("MINIMUM_DELAY", vm.toString(uint256(0)));

// Set EmailAuth implementation address
address emailAuthImpl = address(new EmailAuth());
vm.setEnv("EMAIL_AUTH_IMPL", vm.toString(emailAuthImpl));
Expand Down Expand Up @@ -102,6 +104,7 @@ abstract contract BaseDeployTest is Test {
bytes32(uint256(0)),
bytes32(uint256(0)),
type(EmailRecoveryCommandHandler).creationCode,
vm.envUint("MINIMUM_DELAY"),
vm.envAddress("DKIM_REGISTRY")
);
vm.setEnv("RECOVERY_MODULE", vm.toString(module));
Expand Down
12 changes: 11 additions & 1 deletion src/EmailRecoveryManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ abstract contract EmailRecoveryManager is
*/
address public immutable commandHandler;

/**
* The minimum delay before a successful recovery attempt can be executed
*/
uint256 public immutable minimumDelay;

/**
* Account address to recovery config
*/
Expand All @@ -73,7 +78,8 @@ abstract contract EmailRecoveryManager is
address _verifier,
address _dkimRegistry,
address _emailAuthImpl,
address _commandHandler
address _commandHandler,
uint256 _minimumDelay
) {
if (_verifier == address(0)) {
revert InvalidVerifier();
Expand All @@ -91,6 +97,7 @@ abstract contract EmailRecoveryManager is
dkimAddr = _dkimRegistry;
emailAuthImplementationAddr = _emailAuthImpl;
commandHandler = _commandHandler;
minimumDelay = _minimumDelay;
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
Expand Down Expand Up @@ -297,6 +304,9 @@ abstract contract EmailRecoveryManager is
if (guardianConfigs[account].threshold == 0) {
revert AccountNotConfigured();
}
if (recoveryConfig.delay < minimumDelay) {
revert DelayLessThanMinimumDelay(recoveryConfig.delay, minimumDelay);
}
if (recoveryConfig.delay > recoveryConfig.expiry) {
revert DelayMoreThanExpiry(recoveryConfig.delay, recoveryConfig.expiry);
}
Expand Down
3 changes: 2 additions & 1 deletion src/EmailRecoveryManagerZkSync.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ abstract contract EmailRecoveryManagerZkSync is EmailRecoveryManager, EmailAccou
address _dkimRegistry,
address _emailAuthImpl,
address _commandHandler,
uint256 _minimumDelay,
address _factoryAddr,
bytes32 _proxyBytecodeHash
)
EmailRecoveryManager(_verifier, _dkimRegistry, _emailAuthImpl, _commandHandler)
EmailRecoveryManager(_verifier, _dkimRegistry, _emailAuthImpl, _commandHandler, _minimumDelay)
{
if (_factoryAddr == address(0)) {
revert InvalidFactory();
Expand Down
9 changes: 8 additions & 1 deletion src/factories/EmailRecoveryFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ contract EmailRecoveryFactory {
bytes32 commandHandlerSalt,
bytes32 recoveryModuleSalt,
bytes calldata commandHandlerBytecode,
uint256 minimumDelay,
address dkimRegistry,
address validator,
bytes4 functionSelector
Expand All @@ -79,7 +80,13 @@ contract EmailRecoveryFactory {
// Deploy recovery module
address emailRecoveryModule = address(
new EmailRecoveryModule{ salt: recoveryModuleSalt }(
verifier, dkimRegistry, emailAuthImpl, commandHandler, validator, functionSelector
verifier,
dkimRegistry,
emailAuthImpl,
commandHandler,
minimumDelay,
validator,
functionSelector
)
);

Expand Down
3 changes: 2 additions & 1 deletion src/factories/EmailRecoveryUniversalFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ contract EmailRecoveryUniversalFactory {
bytes32 commandHandlerSalt,
bytes32 recoveryModuleSalt,
bytes calldata commandHandlerBytecode,
uint256 minimumDelay,
address dkimRegistry
)
external
Expand All @@ -73,7 +74,7 @@ contract EmailRecoveryUniversalFactory {
// Deploy recovery module
address emailRecoveryModule = address(
new UniversalEmailRecoveryModule{ salt: recoveryModuleSalt }(
verifier, dkimRegistry, emailAuthImpl, commandHandler
verifier, dkimRegistry, emailAuthImpl, commandHandler, minimumDelay
)
);

Expand Down
1 change: 1 addition & 0 deletions src/interfaces/IEmailRecoveryManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ interface IEmailRecoveryManager {
error InvalidProxyBytecodeHash();
error SetupAlreadyCalled();
error AccountNotConfigured();
error DelayLessThanMinimumDelay(uint256 delay, uint256 minimumDelay);
error DelayMoreThanExpiry(uint256 delay, uint256 expiry);
error RecoveryWindowTooShort(uint256 recoveryWindow);
error ThresholdExceedsAcceptedWeight(uint256 threshold, uint256 acceptedWeight);
Expand Down
3 changes: 2 additions & 1 deletion src/modules/EmailRecoveryModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@ contract EmailRecoveryModule is EmailRecoveryManager, ERC7579ExecutorBase, IEmai
address dkimRegistry,
address emailAuthImpl,
address commandHandler,
uint256 minimumDelay,
address _validator,
bytes4 _selector
)
EmailRecoveryManager(verifier, dkimRegistry, emailAuthImpl, commandHandler)
EmailRecoveryManager(verifier, dkimRegistry, emailAuthImpl, commandHandler, minimumDelay)
{
if (_validator == address(0)) {
revert InvalidValidator(_validator);
Expand Down
5 changes: 3 additions & 2 deletions src/modules/SafeEmailRecoveryModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ contract SafeEmailRecoveryModule is EmailRecoveryManager {
address verifier,
address dkimRegistry,
address emailAuthImpl,
address commandHandler
address commandHandler,
uint256 minimumDelay
)
EmailRecoveryManager(verifier, dkimRegistry, emailAuthImpl, commandHandler)
EmailRecoveryManager(verifier, dkimRegistry, emailAuthImpl, commandHandler, minimumDelay)
{ }

/**
Expand Down
5 changes: 3 additions & 2 deletions src/modules/UniversalEmailRecoveryModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,10 @@ contract UniversalEmailRecoveryModule is
address verifier,
address dkimRegistry,
address emailAuthImpl,
address commandHandler
address commandHandler,
uint256 minimumDelay
)
EmailRecoveryManager(verifier, dkimRegistry, emailAuthImpl, commandHandler)
EmailRecoveryManager(verifier, dkimRegistry, emailAuthImpl, commandHandler, minimumDelay)
{ }

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
Expand Down
20 changes: 9 additions & 11 deletions src/test/MockGroth16Verifier.sol
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.25;

struct EmailProof {
string domainName; // Domain name of the sender's email
bytes32 publicKeyHash; // Hash of the DKIM public key used in email/proof
uint256 timestamp; // Timestamp of the email
string maskedCommand; // Masked command of the email
bytes32 emailNullifier; // Nullifier of the email to prevent its reuse.
bytes32 accountSalt; // Create2 salt of the account
bool isCodeExist; // Check if the account code is exist
bytes proof; // ZK Proof of Email
}
import {
IVerifier,
EmailProof
} from "@zk-email/ether-email-auth-contracts/src/interfaces/IVerifier.sol";

/**
* @notice Mock snarkjs Groth16 Solidity verifier
*/
contract MockGroth16Verifier {
contract MockGroth16Verifier is IVerifier {
uint256 public constant DOMAIN_FIELDS = 9;
uint256 public constant DOMAIN_BYTES = 255;
uint256 public constant COMMAND_FIELDS = 20;
uint256 public constant COMMAND_BYTES = 605;

function commandBytes() external pure returns (uint256) {
return COMMAND_BYTES;
}

function verifyEmailProof(EmailProof memory proof) public pure returns (bool) {
proof;

Expand Down
3 changes: 2 additions & 1 deletion test/Base.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ abstract contract BaseTest is RhinestoneModuleKit, Test {
string public domainName = "gmail.com";
bytes32 public publicKeyHash =
0x0ea9c777dc7110e5a9e89b13f0cfc540e3845ba120b2b6dc24024d61488d4788;
uint256 public minimumDelay = 12 hours;

bytes4 public functionSelector;
bytes public recoveryCalldata;
Expand Down Expand Up @@ -171,7 +172,7 @@ abstract contract BaseTest is RhinestoneModuleKit, Test {
guardianWeights[1] = 2;
guardianWeights[2] = 1;
totalWeight = 4;
delay = 1 seconds;
delay = 1 days;
expiry = 2 weeks;
threshold = 3;
templateIdx = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ abstract contract OwnableValidatorRecovery_EmailRecoveryModule_Base is BaseTest
commandHandlerSalt,
recoveryModuleSalt,
handlerBytecode,
minimumDelay,
address(dkimRegistry),
validatorAddress,
functionSelector
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,11 @@ abstract contract OwnableValidatorRecovery_UniversalEmailRecoveryModule_Base is
commandHandlerAddress = Create2.deploy(0, commandHandlerSalt, handlerBytecode);

emailRecoveryModule = new UniversalEmailRecoveryModuleHarness(
address(verifier), address(dkimRegistry), address(emailAuthImpl), commandHandlerAddress
address(verifier),
address(dkimRegistry),
address(emailAuthImpl),
commandHandlerAddress,
minimumDelay
);
emailRecoveryModuleAddress = address(emailRecoveryModule);

Expand Down
6 changes: 5 additions & 1 deletion test/integration/SafeRecovery/SafeIntegrationBase.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ abstract contract SafeIntegrationBase is BaseTest {
commandHandlerAddress = Create2.deploy(0, commandHandlerSalt, handlerBytecode);

emailRecoveryModule = new UniversalEmailRecoveryModule(
address(verifier), address(dkimRegistry), address(emailAuthImpl), commandHandlerAddress
address(verifier),
address(dkimRegistry),
address(emailAuthImpl),
commandHandlerAddress,
minimumDelay
);
emailRecoveryModuleAddress = address(emailRecoveryModule);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,11 @@ abstract contract SafeNativeIntegrationBase is BaseTest {
commandHandlerAddress = Create2.deploy(0, commandHandlerSalt, handlerBytecode);

emailRecoveryModule = new SafeEmailRecoveryModuleHarness(
address(verifier), address(dkimRegistry), address(emailAuthImpl), commandHandlerAddress
address(verifier),
address(dkimRegistry),
address(emailAuthImpl),
commandHandlerAddress,
minimumDelay
);
emailRecoveryModuleAddress = address(emailRecoveryModule);
}
Expand Down
6 changes: 3 additions & 3 deletions test/unit/EmailRecoveryManager/completeRecovery.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ contract EmailRecoveryManager_completeRecovery_Test is UnitBase {
handleRecovery(accountAddress1, guardians1[0], recoveryDataHash, emailRecoveryModuleAddress);
handleRecovery(accountAddress1, guardians1[1], recoveryDataHash, emailRecoveryModuleAddress);

uint256 expectedExecuteAfter = block.timestamp + delay;

// one second before it should be valid
vm.warp(block.timestamp + delay - 1 seconds);

vm.expectRevert(
abi.encodeWithSelector(
IEmailRecoveryManager.DelayNotPassed.selector,
block.timestamp,
block.timestamp + delay
IEmailRecoveryManager.DelayNotPassed.selector, block.timestamp, expectedExecuteAfter
)
);
emailRecoveryModule.completeRecovery(accountAddress1, recoveryData);
Expand Down
Loading