Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into feat/docs-updates
Browse files Browse the repository at this point in the history
  • Loading branch information
wshino committed Sep 4, 2024
2 parents f203220 + 7fbdd47 commit ec22c88
Show file tree
Hide file tree
Showing 58 changed files with 3,522 additions and 1,336 deletions.
20 changes: 18 additions & 2 deletions .github/workflows/build-test-fmt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,24 @@ jobs:
working-directory: packages/contracts
run: forge build

- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@main
with:
# this might remove tools that are actually needed,
# if set to "true" but frees about 6 GB
tool-cache: false

# all of these default to true, but feel free to set to
# "false" if necessary for your workflow
android: true
dotnet: true
haskell: true
large-packages: true
docker-images: true
swap-storage: true

- name: Build
run: cargo build
run: cargo build --release

- name: Test
run: cargo test
run: cargo test --release
6 changes: 4 additions & 2 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,12 @@ jobs:
- uses: actions/checkout@v3

- name: Install Node.js
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: 18
cache: "yarn"

- name: Install yarn
run: npm install -g yarn

- name: Install dependencies
run: yarn install --frozen-lockfile
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,9 @@ In short, by 1) making a contract called **controller** that implements seven mi
Our SDK cannot ensure security and privacy in the entire process without your careful implementation.

Specifically, you can integrate the email-based account recovery into your smart accounts in the following steps.
1. (Contracts 1/6) First, you build a new controller contract with imports of the `EmailAccountRecovery` abstract contract in `EmailAccountRecovery.sol`. Your Solidity compiler will require you to implement the following seven functions: `acceptanceSubjectTemplates`, `recoverySubjectTemplates`, `extractRecoveredAccountFromAcceptanceSubject`, `extractRecoveredAccountFromRecoverySubject`, `acceptGuardian`, `processRecovery`, and `completeRecovery`.
1. (Contracts 1/6) First, you build a new controller contract with imports of the `EmailAccountRecovery` abstract contract in `EmailAccountRecovery.sol`. Your Solidity compiler will require you to implement the following seven functions:
`isActivated`,
`acceptanceSubjectTemplates`, `recoverySubjectTemplates`, `extractRecoveredAccountFromAcceptanceSubject`, `extractRecoveredAccountFromRecoverySubject`, `acceptGuardian`, `processRecovery`, and `completeRecovery`.
2. (Contracts 2/6) You define expected subject templates for two types of emails sent from guardians, one for accepting the role of the guardian, and the other for confirming the account recovery. You can implement the former and latter subject templates in the `acceptanceSubjectTemplates` and `recoverySubjectTemplates` functions, respectively. This is an example of the subject templates:
- Template in `acceptanceSubjectTemplates`: `"Accept guardian request for {ethAddr}"`, where the value of `"{ethAddr}"` represents the account address.
- Template in `recoverySubjectTemplates`: `"Set the new signer of {ethAddr} to {ethAddr}"`, where the values of the first and second `"{ethAddr}"`, respectively, represent the account address and the new owner address.
Expand Down
7 changes: 0 additions & 7 deletions kubernetes/relayer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,6 @@ spec:
envFrom:
- secretRef:
name: relayer-imap-secret
- name: safe-tracker-container
image: bisht13/safe-tracker-0:latest
envFrom:
- configMapRef:
name: safe-tracker-config
- secretRef:
name: safe-tracker-secret
volumes:
- name: pem-volume
secret:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "ether-email-auth",
"name": "@zk-email/ether-email-auth",
"private": true,
"version": "1.0.0",
"description": "Smart contracts to auth messages via emails",
Expand Down
2 changes: 1 addition & 1 deletion packages/circuits/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@ether-email-auth/circom",
"name": "@zk-email/ether-email-auth-circom",
"license": "MIT",
"version": "1.0.0",
"scripts": {
Expand Down
38 changes: 36 additions & 2 deletions packages/contracts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Then, move `email_auth.zkey` and `email_auth.wasm` in the unzipped directory `pa

Run each integration tests **one by one** as each test will consume lot of memory.
```bash
Eg: forge test --match-test 'testIntegration_Account_Recovery' -vvv --chain 31337 --ffi
Eg: forge test --match-test 'testIntegration_Account_Recovery' -vvv --chain 8453 --ffi
```
#### Deploy Common Contracts.
You need to deploy common contracts, i.e., `ECDSAOwnedDKIMRegistry`, `Verifier`, and implementations of `EmailAuth` and `SimpleWallet`, only once before deploying each wallet.
Expand All @@ -58,6 +58,8 @@ It requires a function `isDKIMPublicKeyHashValid(string domainName, bytes32 publ
One of its implementations is [`ECDSAOwnedDKIMRegistry`](https://github.com/zkemail/ether-email-auth/blob/main/packages/contracts/src/utils/ECDSAOwnedDKIMRegistry.sol).
It stores the Ethereum address `signer` who can update the registry.

We also provide another implementation called [`ForwardDKIMRegistry`](https://github.com/zkemail/ether-email-auth/blob/main/packages/contracts/src/utils/ForwardDKIMRegistry.sol). It stores an address of any internal DKIM registry and forwards its outputs. We can use it to upgrade a proxy of the ECDSAOwnedDKIMRegistry registry to a new DKIM registry with a different storage slots design by 1) upgrading its implementation into ForwardDKIMRegistry and 2) calling resetStorageForUpgradeFromECDSAOwnedDKIMRegistry function with an address of the internal DKIM registry.

### `Verifier` Contract
It has a responsibility to verify a ZK proof for the [`email_auth.circom` circuit](https://github.com/zkemail/ether-email-auth/blob/main/packages/circuits/src/email_auth.circom).
It is implemented in [`utils/Verifier.sol`](https://github.com/zkemail/ether-email-auth/blob/main/packages/contracts/src/utils/Verifier.sol).
Expand Down Expand Up @@ -173,6 +175,7 @@ It provides the following functions.
### `EmailAccountRecovery` Contract
It is an abstract contract for each smart account brand to implement the email-based account recovery. **Each smart account provider only needs to implement the following functions in a new contract called controller.** In the following, the `templateIdx` is different from `templateId` in the email-auth contract in the sense that the `templateIdx` is an incremental index defined for each of the subject templates in `acceptanceSubjectTemplates()` and `recoverySubjectTemplates()`.

- `isActivated(address recoveredAccount) public view virtual returns (bool)`: it returns if the account to be recovered has already activated the controller (the contract implementing `EmailAccountRecovery`).
- `acceptanceSubjectTemplates() public view virtual returns (string[][])`: it returns multiple subject templates for an email to accept becoming a guardian (acceptance email).
- `recoverySubjectTemplates() public view virtual returns (string[][])`: it returns multiple subject templates for an email to confirm the account recovery (recovery email).
- `extractRecoveredAccountFromAcceptanceSubject(bytes[] memory subjectParams, uint templateIdx) public view virtual returns (address)`: it takes as input the parameters `subjectParams` and the index of the chosen subject template `templateIdx` in those for acceptance emails.
Expand Down Expand Up @@ -242,6 +245,21 @@ https://github.com/matter-labs/foundry-zksync/issues/411

To fix this, you should copy `node_modules` in the project root dir to `packages/contracts/node_modules`. And then you should replace `libs = ["../../node_modules", "lib"]` to `libs = ["node_modules", "lib"]` in `foundry.toml`. At the end, you should replace `../../node_modules` to `node_modules` in `remappings.txt`.

Next, you should uncomment the following lines in `foundry.toml`.

```
# via-ir = true
```

And then you should uncomment the following lines in `src/EmailAccountRecovery.sol`.

```
// import {SystemContractsCaller} from "@matterlabs/zksync-contracts/l2/system-contracts/libraries/SystemContractsCaller.sol";
// import {DEPLOYER_SYSTEM_CONTRACT} from "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol";
```

And lines 229 - 263 in the `handleAcceptance` function too.

At the first forge build, you got the following warning like the following.

```
Expand Down Expand Up @@ -299,7 +317,7 @@ We need to hardcode the `type(ERC1967Proxy).creationCode` to bytecodeHash.
Perhaps that is different value in each compiler version.

You should replace the following line to the correct hash.
packages/contracts/src/EmailAccountRecovery.sol:L119
packages/contracts/src/EmailAccountRecovery.sol:L111

See, test/ComputeCreate2Address.t.sol

Expand Down Expand Up @@ -330,6 +348,22 @@ EmailAuth.t.sol
- testExpectRevertAuthEmailInvalidSubject()
- testExpectRevertAuthEmailInvalidTimestamp()

DeployCommons.t.sol

- test_run()

DeployRecoveryController.t.sol

- test_run()

DeploySimpleWallet.t.sol

- test_run()
- test_run_no_dkim()
- test_run_no_email_auth()
- test_run_no_simple_wallet()
- test_run_no_verifier()

# For integration testing

forge test --match-test 'testIntegration_Account_Recovery' --zksync --chain 300 -vvv --ffi
Expand Down
6 changes: 4 additions & 2 deletions packages/contracts/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ src = "src"
out = "artifacts"
libs = ["../../node_modules", "lib"]
optimizer = true
# via-ir = true
# The following line `via-ir = true` is needed to compile this project using zksync features
# See README.md for more details -> TODO
# via-ir = true
optimizer-runs = 20_000
fs_permissions = [
{ access = "read", path = "./artifacts/WETH9.sol/WETH9.json" },
Expand Down Expand Up @@ -35,7 +37,7 @@ mainnet = { key = "${ETHERSCAN_API_KEY}" }
src = 'src'
libs = ["node_modules", "lib"]
fallback_oz = true
is_system = false
is_system = true
mode = "3"

zksolc = "1.5.0"
2 changes: 1 addition & 1 deletion packages/contracts/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@ether-email-auth/contracts",
"name": "@zk-email/ether-email-auth-contracts",
"version": "1.0.0",
"license": "MIT",
"scripts": {
Expand Down
39 changes: 39 additions & 0 deletions packages/contracts/script/ChangeOwners.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Script.sol";

import "../src/utils/Verifier.sol";
import "../src/utils/ECDSAOwnedDKIMRegistry.sol";
import "../src/utils/ForwardDKIMRegistry.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

contract ChangeOwners is Script {
function run() external {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
if (deployerPrivateKey == 0) {
console.log("PRIVATE_KEY env var not set");
return;
}
address verifier = vm.envOr("VERIFIER", address(0));
address ecdsaDkim = vm.envOr("ECDSA_DKIM", address(0));
address dkim = vm.envOr("DKIM", address(0));
address newOwner = vm.envAddress("NEW_OWNER");
if (newOwner == address(0)) {
console.log("NEW_OWNER env var not set");
return;
}

vm.startBroadcast(deployerPrivateKey);
if (verifier != address(0)) {
OwnableUpgradeable(verifier).transferOwnership(newOwner);
}
if (ecdsaDkim != address(0)) {
OwnableUpgradeable(ecdsaDkim).transferOwnership(newOwner);
}
if (dkim != address(0)) {
OwnableUpgradeable(dkim).transferOwnership(newOwner);
}
vm.stopBroadcast();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Script.sol";

import {ECDSAOwnedDKIMRegistry} from "../src/utils/ECDSAOwnedDKIMRegistry.sol";

contract ChangeSigner is Script {
function run() external {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
if (deployerPrivateKey == 0) {
console.log("PRIVATE_KEY env var not set");
return;
}
address ecdsaDkimAddr = vm.envAddress("ECDSA_DKIM");
if (ecdsaDkimAddr == address(0)) {
console.log("ECDSA_DKIM env var not set");
return;
}
address newSigner = vm.envAddress("NEW_SIGNER");
if (newSigner == address(0)) {
console.log("NEW_SIGNER env var not set");
return;
}
vm.startBroadcast(deployerPrivateKey);
ECDSAOwnedDKIMRegistry ecdsaDkim = ECDSAOwnedDKIMRegistry(
ecdsaDkimAddr
);
ecdsaDkim.changeSigner(newSigner);
vm.stopBroadcast();
}
}
30 changes: 30 additions & 0 deletions packages/contracts/script/ChangeSourceInForwardDKIMRegistry.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Script.sol";

import "../src/utils/ForwardDKIMRegistry.sol";

contract ChangeSource is Script {
function run() external {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
if (deployerPrivateKey == 0) {
console.log("PRIVATE_KEY env var not set");
return;
}
address dkimAddr = vm.envAddress("DKIM");
if (dkimAddr == address(0)) {
console.log("DKIM env var not set");
return;
}
address newSource = vm.envAddress("NEW_SOURCE");
if (newSource == address(0)) {
console.log("NEW_SOURCE env var not set");
return;
}
vm.startBroadcast(deployerPrivateKey);
ForwardDKIMRegistry dkim = ForwardDKIMRegistry(dkimAddr);
dkim.changeSourceDKIMRegistry(newSource);
vm.stopBroadcast();
}
}
62 changes: 55 additions & 7 deletions packages/contracts/script/DeployCommons.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@ import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "../test/helpers/SimpleWallet.sol";
import "../src/utils/Verifier.sol";
import "../src/utils/ECDSAOwnedDKIMRegistry.sol";
// import "../src/utils/ForwardDKIMRegistry.sol";
import "../src/EmailAuth.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";

contract Deploy is Script {
using ECDSA for *;

ECDSAOwnedDKIMRegistry dkimImpl;
ECDSAOwnedDKIMRegistry dkim;
// ForwardDKIMRegistry dkimImpl;
// ForwardDKIMRegistry dkim;
Verifier verifierImpl;
Verifier verifier;
EmailAuth emailAuthImpl;
SimpleWallet simpleWalletImpl;
Expand All @@ -30,16 +36,58 @@ contract Deploy is Script {
}

vm.startBroadcast(deployerPrivateKey);
address initialOwner = vm.addr(deployerPrivateKey);
console.log("Initial owner: %s", vm.toString(initialOwner));
// Deploy ECDSA DKIM registry
{
dkimImpl = new ECDSAOwnedDKIMRegistry();
console.log(
"ECDSAOwnedDKIMRegistry implementation deployed at: %s",
address(dkimImpl)
);
ERC1967Proxy dkimProxy = new ERC1967Proxy(
address(dkimImpl),
abi.encodeCall(dkimImpl.initialize, (initialOwner, signer))
);
dkim = ECDSAOwnedDKIMRegistry(address(dkimProxy));
console.log(
"ECDSAOwnedDKIMRegistry deployed at: %s",
address(dkim)
);
vm.setEnv("ECDSA_DKIM", vm.toString(address(dkim)));
}

// Deploy DKIM registry
dkim = new ECDSAOwnedDKIMRegistry(signer);
console.log("ECDSAOwnedDKIMRegistry deployed at: %s", address(dkim));
vm.setEnv("DKIM", vm.toString(address(dkim)));
// Deploy Forward DKIM registry
// {
// dkimImpl = new ForwardDKIMRegistry();
// console.log(
// "ForwardDKIMRegistry implementation deployed at: %s",
// address(dkimImpl)
// );
// ERC1967Proxy dkimProxy = new ERC1967Proxy(
// address(dkimImpl),
// abi.encodeCall(dkimImpl.initialize, (initialOwner, signer))
// );
// dkim = ForwardDKIMRegistry(address(dkimProxy));
// console.log("ForwardDKIMRegistry deployed at: %s", address(dkim));
// vm.setEnv("DKIM", vm.toString(address(dkim)));
// }

// Deploy Verifier
verifier = new Verifier();
console.log("Verifier deployed at: %s", address(verifier));
vm.setEnv("VERIFIER", vm.toString(address(verifier)));
{
verifierImpl = new Verifier();
console.log(
"Verifier implementation deployed at: %s",
address(verifierImpl)
);
ERC1967Proxy verifierProxy = new ERC1967Proxy(
address(verifierImpl),
abi.encodeCall(verifierImpl.initialize, (initialOwner))
);
verifier = Verifier(address(verifierProxy));
console.log("Verifier deployed at: %s", address(verifier));
vm.setEnv("VERIFIER", vm.toString(address(verifier)));
}

// Deploy EmailAuth Implementation
{
Expand Down
Loading

0 comments on commit ec22c88

Please sign in to comment.