From 90919c0075aaa4e1820c1a46d6f0a52b48432dea Mon Sep 17 00:00:00 2001 From: Saleel Date: Tue, 24 Oct 2023 00:20:03 +0530 Subject: [PATCH 1/4] chore: add script to deploy ECDSAOwnedDKIMRegistry --- packages/contracts/README.md | 17 +++++++++++ .../script/DeployECDSAOwnedDKIMRegistry.s.sol | 30 +++++++++++++++++++ .../src/utils/ECDSAOwnedDKIMRegistry.sol | 2 +- 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 packages/contracts/script/DeployECDSAOwnedDKIMRegistry.s.sol diff --git a/packages/contracts/README.md b/packages/contracts/README.md index 352145a8..22aac9cc 100644 --- a/packages/contracts/README.md +++ b/packages/contracts/README.md @@ -146,3 +146,20 @@ Copy the addresses from log: NFT Extension deployed at: 0xb7F8bD28719aA118EcD8D01293acEe0E804b2EE6 Uniswap Extension deployed at: 0x6CE6893f06A438A85686DC1104688ad3b032de05 ``` + +#### Deploy ECDSAOwnedDKIMRegistry +Set the `SIGNER` to the address of the Ethereum wallet who will be setting the DKIM public key for a domain. + +``` +PRIVATE_KEY="" \ +SIGNER=0x2f6e79a6e1a982a49ca248b70b02f76e921af400 \ +forge script script/DeployECDSAOwnedDKIMRegistry.s.sol:Deploy \ +-vvvv \ +--rpc-url https://ethereum-sepolia.publicnode.com \ +--chain-id 11155111 \ +--broadcast \ +--etherscan-api-key "S7RWR1ENYB73HZY7WTV3EER7U8CQNBBTAJ" \ +--verify +``` + +Copy the address from log `ECDSAOwnedDKIMRegistry deployed at: 0xB50a02E2Da524feC1209542985b2ae2917aF7265` diff --git a/packages/contracts/script/DeployECDSAOwnedDKIMRegistry.s.sol b/packages/contracts/script/DeployECDSAOwnedDKIMRegistry.s.sol new file mode 100644 index 00000000..70348350 --- /dev/null +++ b/packages/contracts/script/DeployECDSAOwnedDKIMRegistry.s.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "forge-std/Script.sol"; +import "forge-std/console.sol"; +import "../src/utils/ECDSAOwnedDKIMRegistry.sol"; + +contract Deploy is Script { + function run() external { + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + if (deployerPrivateKey == 0) { + console.log("PRIVATE_KEY env var not set"); + return; + } + + address signer = vm.envAddress("SIGNER"); + if (signer == address(0)) { + console.log("SIGNER env var not set"); + return; + } + + uint signValidityDuration = 1 hours; + + vm.startBroadcast(deployerPrivateKey); + ECDSAOwnedDKIMRegistry dkim = new ECDSAOwnedDKIMRegistry(signer, signValidityDuration); + vm.stopBroadcast(); + + console.log("ECDSAOwnedDKIMRegistry deployed at: %s", address(dkim)); + } +} diff --git a/packages/contracts/src/utils/ECDSAOwnedDKIMRegistry.sol b/packages/contracts/src/utils/ECDSAOwnedDKIMRegistry.sol index e526536d..12b081e4 100644 --- a/packages/contracts/src/utils/ECDSAOwnedDKIMRegistry.sol +++ b/packages/contracts/src/utils/ECDSAOwnedDKIMRegistry.sol @@ -16,7 +16,7 @@ contract ECDSAOwnedDKIMRegistry is IDKIMRegistry { DKIMRegistry public dkimRegistry; address public signer; - constructor(address _signer, uint _signValidityDuration) { + constructor(address _signer, uint256 _signValidityDuration) { dkimRegistry = new DKIMRegistry(); signer = _signer; signValidityDuration = _signValidityDuration; From d9daf6e539fcf4b4b8b545008b7d2f7a0d17ae35 Mon Sep 17 00:00:00 2001 From: Magamedrasul Ibragimov Date: Mon, 23 Oct 2023 23:19:37 +0400 Subject: [PATCH 2/4] chore(relayer): minor features and replies --- packages/relayer/src/chain.rs | 31 ++++++++++++++++++++++++++++--- packages/relayer/src/config.rs | 8 ++++++++ packages/relayer/src/core.rs | 31 +++++++++++++++++++++++++++++-- packages/relayer/src/lib.rs | 11 +++++++++++ packages/relayer/src/main.rs | 1 + packages/relayer/src/strings.rs | 4 ++++ 6 files changed, 81 insertions(+), 5 deletions(-) diff --git a/packages/relayer/src/chain.rs b/packages/relayer/src/chain.rs index 7f0c12be..7c368d78 100644 --- a/packages/relayer/src/chain.rs +++ b/packages/relayer/src/chain.rs @@ -1,7 +1,5 @@ use crate::*; -use ethers::prelude::*; - #[derive(Default)] pub(crate) struct WalletParams { pub(crate) token_name: String, @@ -46,13 +44,40 @@ pub(crate) struct AccountCreation { } #[derive(Default)] -pub(crate) struct AccountInitialization {} +pub(crate) struct AccountInitialization { + pub(crate) email_addr_pointer: [u8; 32], + pub(crate) email_domain: String, + pub(crate) email_timestamp: U256, + pub(crate) email_nullifier: [u8; 32], + pub(crate) proof: Bytes, +} pub(crate) async fn call_handle_email_op(email_op: EmailOp) -> Result { + let provider = Provider::::try_from(CHAIN_RPC_PROVIDER.get().unwrap())?; + + let wallet: LocalWallet = PRIVATE_KEY.get().unwrap().parse()?; + let client = Arc::new(SignerMiddleware::new( + provider, + wallet.with_chain_id(*CHAIN_ID.get().unwrap()), + )); + + let contract_address: Address = CORE_CONTRACT_ADDRESS.get().unwrap().parse()?; + + let abi_source = "./packages/contracts/artifacts/EmailWalletCore.sol/EmailWalletCore.json"; + + // client.send_transaction(tx, block) + todo!() } pub(crate) async fn call_account_creation_op(data: AccountCreation) -> Result { + let provider = Provider::::try_from(CHAIN_RPC_PROVIDER.get().unwrap())?; + + let wallet: LocalWallet = PRIVATE_KEY.get().unwrap().parse()?; + let client = SignerMiddleware::new(provider, wallet.with_chain_id(*CHAIN_ID.get().unwrap())); + + // client.se + todo!() } diff --git a/packages/relayer/src/config.rs b/packages/relayer/src/config.rs index 2ee0d93a..8e4b2cbd 100644 --- a/packages/relayer/src/config.rs +++ b/packages/relayer/src/config.rs @@ -13,6 +13,10 @@ pub struct RelayerConfig { pub(crate) web_server_address: String, pub(crate) circuits_dir_path: PathBuf, pub(crate) prover_address: String, + pub(crate) chain_rpc_provider: String, + pub(crate) chain_id: u32, + pub(crate) private_key: String, + pub(crate) core_contract_address: String, } impl RelayerConfig { @@ -57,6 +61,10 @@ impl RelayerConfig { web_server_address: env::var(WEB_SERVER_ADDRESS_KEY).unwrap(), circuits_dir_path: env::var(CIRCUITS_DIR_PATH_KEY).unwrap().into(), prover_address: env::var(PROVER_ADDRESS_KEY).unwrap(), + chain_rpc_provider: env::var(CHAIN_RPC_PROVIDER_KEY).unwrap(), + chain_id: env::var(CHAIN_ID_KEY).unwrap().parse().unwrap(), + private_key: env::var(PRIVATE_KEY_KEY).unwrap(), + core_contract_address: env::var(CORE_CONTRACT_ADDRESS_KEY).unwrap(), } } } diff --git a/packages/relayer/src/core.rs b/packages/relayer/src/core.rs index ffa028c2..879c6f95 100644 --- a/packages/relayer/src/core.rs +++ b/packages/relayer/src/core.rs @@ -41,8 +41,27 @@ pub(crate) async fn handle_email( generate_proof(&input, "generateSendProof", PROVER_ADDRESS.get().unwrap()) .await?; - let data = AccountInitialization::default(); - let res = call_account_initialization_op(data).await?; + let relayer_rand = hex2field(RELAYER_RAND.get().unwrap())?; + let email_addr_pointer = PaddedEmailAddr::from_email_addr(&from_address) + .to_pointer(&RelayerRand(relayer_rand))?; + let email_addr_pointer = Fr::to_bytes(&email_addr_pointer); + + let data = AccountInitialization { + email_addr_pointer, + email_domain: get_email_domain(&from_address)?, + email_timestamp: U256::from(parsed_email.get_timestamp()?), + email_nullifier: Fr::to_bytes(&email_nullifier(&parsed_email.signature)?), + proof: Bytes::from(proof.into_bytes()), + }; + let result = call_account_initialization_op(data).await?; + + tx.send(EmailMessage { + subject: "Your Account was initialized".to_string(), + body: result, + to: from_address, + message_id: None, + }) + .unwrap(); } } } else { @@ -108,6 +127,14 @@ pub(crate) async fn handle_email( }; let result = call_handle_email_op(email_op).await?; + + tx.send(EmailMessage { + subject: "Transaction were completed".to_string(), + body: result, + to: from_address, + message_id: None, + }) + .unwrap(); } Ok(()) diff --git a/packages/relayer/src/lib.rs b/packages/relayer/src/lib.rs index 413d3539..266a31da 100644 --- a/packages/relayer/src/lib.rs +++ b/packages/relayer/src/lib.rs @@ -25,17 +25,28 @@ use std::sync::{Arc, OnceLock}; use anyhow::{anyhow, bail, Result}; use email_wallet_utils::{converters::*, cryptos::*, parse_email::ParsedEmail, Fr}; +use ethers::prelude::*; static CIRCUITS_DIR_PATH: OnceLock = OnceLock::new(); static WEB_SERVER_ADDRESS: OnceLock = OnceLock::new(); static RELAYER_RAND: OnceLock = OnceLock::new(); static PROVER_ADDRESS: OnceLock = OnceLock::new(); +static PRIVATE_KEY: OnceLock = OnceLock::new(); +static CHAIN_ID: OnceLock = OnceLock::new(); +static CHAIN_RPC_PROVIDER: OnceLock = OnceLock::new(); +static CORE_CONTRACT_ADDRESS: OnceLock = OnceLock::new(); pub async fn run(config: RelayerConfig) -> Result<()> { CIRCUITS_DIR_PATH.set(config.circuits_dir_path).unwrap(); WEB_SERVER_ADDRESS.set(config.web_server_address).unwrap(); RELAYER_RAND.set(config.relayer_randomness).unwrap(); PROVER_ADDRESS.set(config.prover_address).unwrap(); + PRIVATE_KEY.set(config.private_key).unwrap(); + CHAIN_ID.set(config.chain_id).unwrap(); + CHAIN_RPC_PROVIDER.set(config.chain_rpc_provider).unwrap(); + CORE_CONTRACT_ADDRESS + .set(config.core_contract_address) + .unwrap(); let (tx_handler, mut rx_handler) = tokio::sync::mpsc::unbounded_channel(); let (tx_sender, mut rx_sender) = tokio::sync::mpsc::unbounded_channel::(); diff --git a/packages/relayer/src/main.rs b/packages/relayer/src/main.rs index 8876d9cf..10fb6643 100644 --- a/packages/relayer/src/main.rs +++ b/packages/relayer/src/main.rs @@ -1,6 +1,7 @@ use relayer::*; use anyhow::Result; +use ethers::prelude::*; #[tokio::main] async fn main() -> Result<()> { diff --git a/packages/relayer/src/strings.rs b/packages/relayer/src/strings.rs index bb375753..5725e5c5 100644 --- a/packages/relayer/src/strings.rs +++ b/packages/relayer/src/strings.rs @@ -19,6 +19,10 @@ pub const RELAYER_RANDOMNESS_KEY: &str = "RELAYER_RANDOMNESS"; pub const WEB_SERVER_ADDRESS_KEY: &str = "WEB_SERVER_ADDRESS"; pub const CIRCUITS_DIR_PATH_KEY: &str = "CIRCUITS_DIR_PATH"; pub const PROVER_ADDRESS_KEY: &str = "PROVER_ADDRESS"; +pub const CHAIN_RPC_PROVIDER_KEY: &str = "CHAIN_RPC_PROVIDER"; +pub const PRIVATE_KEY_KEY: &str = "PRIVATE_KEY"; +pub const CHAIN_ID_KEY: &str = "CHAIN_ID"; +pub const CORE_CONTRACT_ADDRESS_KEY: &str = "CORE_CONTRACT_ADDRESS"; // Error strings pub const WRONG_AUTH_METHOD: &str = "Not supported auth type"; From 2cd4b0c5386f6478bb67ccd78eae5dba19e3be28 Mon Sep 17 00:00:00 2001 From: Magamedrasul Ibragimov Date: Mon, 23 Oct 2023 23:20:41 +0400 Subject: [PATCH 3/4] chore(prover): remove coordinator.py --- packages/prover/coordinator.py | 1 - 1 file changed, 1 deletion(-) delete mode 100644 packages/prover/coordinator.py diff --git a/packages/prover/coordinator.py b/packages/prover/coordinator.py deleted file mode 100644 index 6d95fe97..00000000 --- a/packages/prover/coordinator.py +++ /dev/null @@ -1 +0,0 @@ -print("Hello world") \ No newline at end of file From eadf900ef356570e7ec55663503f48cfa265da27 Mon Sep 17 00:00:00 2001 From: Saleel Date: Tue, 24 Oct 2023 01:24:44 +0530 Subject: [PATCH 4/4] chore: add test for email in between subject --- .../test/EmailWalletCore.cmd.extension.t.sol | 46 ++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/packages/contracts/test/EmailWalletCore.cmd.extension.t.sol b/packages/contracts/test/EmailWalletCore.cmd.extension.t.sol index 77e41a3b..a56f9b1c 100644 --- a/packages/contracts/test/EmailWalletCore.cmd.extension.t.sol +++ b/packages/contracts/test/EmailWalletCore.cmd.extension.t.sol @@ -13,7 +13,7 @@ contract ExtensionCommandTest is EmailWalletCoreTestHelper { NFTExtension nftExtension; DummyNFT dummyNFT; string[][] public nftExtTemplates = new string[][](1); - string[][] public mockExtTemplates = new string[][](9); + string[][] public mockExtTemplates = new string[][](10); function setUp() public override { super.setUp(); @@ -36,7 +36,7 @@ contract ExtensionCommandTest is EmailWalletCoreTestHelper { mockExtTemplates[5] = ["Test", "Request Token Twice", "{tokenAmount}"]; mockExtTemplates[6] = ["Test", "Deposit Token", "{tokenAmount}"]; mockExtTemplates[7] = ["Test", "Execute on", "{address}"]; - // A dummy template to test the subject matchers that are not above + // Dummy templates to test the subject matchers that are not above // mockExtension has wont do anything with this template mockExtTemplates[8] = [ "Test", @@ -51,6 +51,12 @@ contract ExtensionCommandTest is EmailWalletCoreTestHelper { "then send to", "{address}" ]; + mockExtTemplates[9] = [ + "Test", + "to", + "{recipient}", + "now" + ]; extensionHandler.publishExtension("mockExtension", address(mockExtension), mockExtTemplates, 0.1 ether); EmailOp memory emailOp = _getBaseEmailOp(); @@ -146,6 +152,42 @@ contract ExtensionCommandTest is EmailWalletCoreTestHelper { vm.stopPrank(); } + function test_SubjectWithEmailInBetween() public { + bytes memory subject = new bytes(22); + subject[0] = "T"; + subject[1] = "e"; + subject[2] = "s"; + subject[3] = "t"; + subject[4] = " "; + subject[5] = "t"; + subject[6] = "o"; + subject[7] = " "; + + // Assume emailAddr is 10 chars + for(uint i = 8; i < 18; i++) { + subject[i] = 0x0; + } + + subject[18] = " "; + subject[19] = "n"; + subject[20] = "o"; + subject[21] = "w"; + + EmailOp memory emailOp = _getBaseEmailOp(); + emailOp.command = "Test"; + // If the subject email is in between, then the padding will be equal to email addr length + emailOp.maskedSubject = string(subject); + emailOp.extensionParams.subjectTemplateIndex = 9; + emailOp.extensionParams.subjectParams = new bytes[](0); + emailOp.hasEmailRecipient = true; + emailOp.recipientEmailAddrCommit = bytes32(uint256(32333)); + emailOp.numRecipientEmailAddrBytes = 10; + + vm.startPrank(relayer); + core.handleEmailOp(emailOp); // We only need to verify subjects match (i.e dont revert) + vm.stopPrank(); + } + function test_RevertIf_CommandIsInvalid() public { EmailOp memory emailOp = _getBaseEmailOp(); emailOp.command = "INVALID ";