Skip to content
This repository has been archived by the owner on Sep 30, 2024. It is now read-only.

Commit

Permalink
Merge pull request #230 from SoraSuegami/pr/email-recovery-circuits
Browse files Browse the repository at this point in the history
Update EmailAccountRecoveryRouter and SafeZkEmailRecoveryPlugin contracts.
  • Loading branch information
jacque006 authored Apr 5, 2024
2 parents 1036f53 + 98e32c8 commit 01353c1
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 32 deletions.
87 changes: 87 additions & 0 deletions packages/plugins/src/safe/EmailAccountRecoveryRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,37 @@
pragma solidity ^0.8.0;

import {EmailAuthMsg} from "ether-email-auth/packages/contracts/src/EmailAuth.sol";
// import "forge-std/console.sol";

interface IEmailAccountRecovery {
function verifier() external view returns (address);

function dkim() external view returns (address);

function emailAuthImplementation() external view returns (address);

function acceptanceSubjectTemplates()
external
view
returns (string[][] memory);

function recoverySubjectTemplates()
external
view
returns (string[][] memory);

function computeEmailAuthAddress(
bytes32 accountSalt
) external view returns (address);

function computeAcceptanceTemplateId(
uint templateIdx
) external view returns (uint);

function computeRecoveryTemplateId(
uint templateIdx
) external view returns (uint);

function handleAcceptance(
EmailAuthMsg memory emailAuthMsg,
uint templateIdx
Expand All @@ -25,6 +54,64 @@ contract EmailAccountRecoveryRouter {
emailAccountRecoveryImpl = _emailAccountRecoveryImpl;
}

function verifier() external view returns (address) {
return IEmailAccountRecovery(emailAccountRecoveryImpl).verifier();
}

function dkim() external view returns (address) {
return IEmailAccountRecovery(emailAccountRecoveryImpl).dkim();
}

function emailAuthImplementation() external view returns (address) {
return
IEmailAccountRecovery(emailAccountRecoveryImpl)
.emailAuthImplementation();
}

function acceptanceSubjectTemplates()
external
view
returns (string[][] memory)
{
return
IEmailAccountRecovery(emailAccountRecoveryImpl)
.acceptanceSubjectTemplates();
}

function recoverySubjectTemplates()
external
view
returns (string[][] memory)
{
return
IEmailAccountRecovery(emailAccountRecoveryImpl)
.recoverySubjectTemplates();
}

function computeEmailAuthAddress(
bytes32 accountSalt
) external view returns (address) {
return
IEmailAccountRecovery(emailAccountRecoveryImpl)
.computeEmailAuthAddress(accountSalt);
}

function computeAcceptanceTemplateId(
uint templateIdx
) external view returns (uint) {
return
IEmailAccountRecovery(emailAccountRecoveryImpl)
.computeAcceptanceTemplateId(templateIdx);
}

function computeRecoveryTemplateId(
uint templateIdx
) external view returns (uint) {
return
IEmailAccountRecovery(emailAccountRecoveryImpl)
.computeRecoveryTemplateId(templateIdx);
}

function handleAcceptance(
EmailAuthMsg memory emailAuthMsg,
uint templateIdx
Expand Down
49 changes: 34 additions & 15 deletions packages/plugins/src/safe/SafeZkEmailRecoveryPlugin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ pragma solidity ^0.8.0;
import {ISafe} from "./utils/Safe4337Base.sol";
import {EmailAccountRecoveryRouter} from "./EmailAccountRecoveryRouter.sol";
import {EmailAccountRecovery} from "ether-email-auth/packages/contracts/src/EmailAccountRecovery.sol";

// import "forge-std/console.sol";
/*//////////////////////////////////////////////////////////////////////////
THIS CONTRACT IS STILL IN ACTIVE DEVELOPMENT. NOT FOR PRODUCTION USE
//////////////////////////////////////////////////////////////////////////*/

struct RecoveryRequest {
address guardian;
uint256 executeAfter;
address ownerToSwap;
address pendingNewOwner;
Expand Down Expand Up @@ -46,6 +45,10 @@ contract SafeZkEmailRecoveryPlugin is EmailAccountRecovery {
/** Mapping of email account recovery router contracts to safe details needed to complete recovery */
mapping(address => SafeAccountInfo) public recoveryRouterToSafeInfo;

/** Mapping of safe account addresses to email account recovery router contracts**/
/** These are stored for frontends to easily find the router contract address from the given safe account address**/
mapping(address => address) public safeAddrToRecoveryRouter;

/** Mapping of safe address to dkim registry address */
// TODO How can we use a custom DKIM reigstry/key with email auth?
// mapping(address => address) public dkimRegistryOfSafe;
Expand Down Expand Up @@ -149,10 +152,16 @@ contract SafeZkEmailRecoveryPlugin is EmailAccountRecovery {
guardianRequests[guardian].safe != address(0),
"guardian not requested"
);
require(
!guardianRequests[guardian].accepted,
"guardian has already accepted"
);
require(templateIdx == 0, "invalid template index");
require(subjectParams.length == 1, "invalid subject params");

address safeInEmail = abi.decode(subjectParams[0], (address));
address safeForRouter = recoveryRouterToSafeInfo[msg.sender].safe;
require(safeForRouter == safeInEmail, "invalid account for router");
require(
guardianRequests[guardian].safe == safeInEmail,
"invalid account in email"
Expand Down Expand Up @@ -183,6 +192,8 @@ contract SafeZkEmailRecoveryPlugin is EmailAccountRecovery {
require(newOwnerInEmail != address(0), "invalid new owner in email");

address safeInEmail = abi.decode(subjectParams[1], (address));
address safeForRouter = recoveryRouterToSafeInfo[msg.sender].safe;
require(safeForRouter == safeInEmail, "invalid account for router");
require(
guardianRequests[guardian].safe == safeInEmail,
"invalid account in email"
Expand Down Expand Up @@ -257,39 +268,47 @@ contract SafeZkEmailRecoveryPlugin is EmailAccountRecovery {
address previousOwnerInLinkedList
) external returns (address emailAccountRecoveryRouterAddress) {
address safe = msg.sender;
bool moduleEnabled = ISafe(safe).isModuleEnabled(address(this));
if (!moduleEnabled) revert MODULE_NOT_ENABLED();

require(
guardianRequests[guardian].safe == address(0),
"guardian already requested"
);

bool isOwner = ISafe(safe).isOwner(owner);
if (!isOwner) revert INVALID_OWNER(owner);

if (recoveryRequests[guardian].executeAfter > 0) {
revert RECOVERY_ALREADY_INITIATED();
}
require(
safeAddrToRecoveryRouter[safe] == address(0),
"router contract for safe already exits"
);

EmailAccountRecoveryRouter emailAccountRecoveryRouter = new EmailAccountRecoveryRouter(
address(this)
);
emailAccountRecoveryRouterAddress = address(emailAccountRecoveryRouter);

// TODO: check entry contract exists before deploying
require(
recoveryRouterToSafeInfo[emailAccountRecoveryRouterAddress].safe ==
address(0),
"entry contract for safe already exits"
"safe for the router contract already exits"
);
recoveryRouterToSafeInfo[
emailAccountRecoveryRouterAddress
] = SafeAccountInfo(safe, previousOwnerInLinkedList);

bool moduleEnabled = ISafe(safe).isModuleEnabled(address(this));
if (!moduleEnabled) revert MODULE_NOT_ENABLED();

bool isOwner = ISafe(safe).isOwner(owner);
if (!isOwner) revert INVALID_OWNER(owner);

if (recoveryRequests[guardian].executeAfter > 0) {
revert RECOVERY_ALREADY_INITIATED();
}
safeAddrToRecoveryRouter[safe] = emailAccountRecoveryRouterAddress;

uint256 delay = defaultDelay;
if (customDelay > 0) {
delay = customDelay;
}

recoveryRequests[safe] = RecoveryRequest({
guardian: guardian,
// guardian: guardian,
executeAfter: 0,
ownerToSwap: owner,
pendingNewOwner: address(0),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ contract SafeZkEmailRecoveryPlugin_Integration_Test is TestHelper {
address public owner;

// ZK email contracts
EmailAuth emailAuth;
// EmailAuth emailAuth;
ECDSAOwnedDKIMRegistry ecdsaOwnedDkimRegistry;
MockGroth16Verifier verifier;
bytes32 accountSalt;
Expand Down Expand Up @@ -78,9 +78,9 @@ contract SafeZkEmailRecoveryPlugin_Integration_Test is TestHelper {
accountSalt
)
);
emailAuth = EmailAuth(payable(address(emailAuthProxy)));
emailAuth.updateVerifier(address(verifier));
emailAuth.updateDKIMRegistry(address(ecdsaOwnedDkimRegistry));
// emailAuth = EmailAuth(payable(address(emailAuthProxy)));
// emailAuth.updateVerifier(address(verifier));
// emailAuth.updateDKIMRegistry(address(ecdsaOwnedDkimRegistry));
vm.stopPrank();

safeZkEmailRecoveryPlugin = new SafeZkEmailRecoveryPlugin(
Expand Down Expand Up @@ -159,7 +159,7 @@ contract SafeZkEmailRecoveryPlugin_Integration_Test is TestHelper {

// Handle acceptance
bytes[] memory subjectParamsForAcceptance = new bytes[](1);
subjectParamsForAcceptance[0] = abi.encode(safeAddress); // TODO: might need to be entry contract
subjectParamsForAcceptance[0] = abi.encode(safeAddress);
EmailAuthMsg memory emailAuthMsg = EmailAuthMsg({
templateId: safeZkEmailRecoveryPlugin.computeAcceptanceTemplateId(
templateIdx
Expand All @@ -168,7 +168,6 @@ contract SafeZkEmailRecoveryPlugin_Integration_Test is TestHelper {
skipedSubjectPrefix: 0,
proof: emailProof
});

IEmailAccountRecovery(emailAccountRecoveryRouterAddress)
.handleAcceptance(emailAuthMsg, templateIdx);

Expand Down
22 changes: 11 additions & 11 deletions packages/plugins/test/unit/safe/SafeZkEmailRecoveryPlugin.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ contract SafeZkEmailRecoveryPluginTest is TestHelper {
string dkimPublicKey;

// ZK email contracts
EmailAuth emailAuth;
// EmailAuth emailAuth;
ECDSAOwnedDKIMRegistry ecdsaOwnedDkimRegistry;
Verifier verifier;
bytes32 accountSalt;
Expand Down Expand Up @@ -95,16 +95,16 @@ contract SafeZkEmailRecoveryPluginTest is TestHelper {
accountSalt = 0x2c3abbf3d1171bfefee99c13bf9c47f1e8447576afd89096652a34f27b297971;

EmailAuth emailAuthImpl = new EmailAuth();
ERC1967Proxy emailAuthProxy = new ERC1967Proxy(
address(emailAuthImpl),
abi.encodeWithSelector(
emailAuthImpl.initialize.selector,
accountSalt
)
);
emailAuth = EmailAuth(payable(address(emailAuthProxy)));
emailAuth.updateVerifier(address(verifier));
emailAuth.updateDKIMRegistry(address(ecdsaOwnedDkimRegistry));
// ERC1967Proxy emailAuthProxy = new ERC1967Proxy(
// address(emailAuthImpl),
// abi.encodeWithSelector(
// emailAuthImpl.initialize.selector,
// accountSalt
// )
// );
// emailAuth = EmailAuth(payable(address(emailAuthProxy)));
// emailAuth.updateVerifier(address(verifier));
// emailAuth.updateDKIMRegistry(address(ecdsaOwnedDkimRegistry));
vm.stopPrank();

safeZkEmailRecoveryPlugin = new SafeZkEmailRecoveryPluginHarness(
Expand Down

0 comments on commit 01353c1

Please sign in to comment.