Skip to content

Commit

Permalink
Reduce the codesize of EmailWalletCore and refactor relayer for the n…
Browse files Browse the repository at this point in the history
…ew relayer-utils
  • Loading branch information
SoraSuegami committed Sep 22, 2024
1 parent b9a0111 commit 4d381a9
Show file tree
Hide file tree
Showing 16 changed files with 475 additions and 469 deletions.
751 changes: 372 additions & 379 deletions Cargo.lock

Large diffs are not rendered by default.

65 changes: 34 additions & 31 deletions packages/contracts/src/EmailWalletCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,11 @@ contract EmailWalletCore is Initializable, UUPSUpgradeable, OwnableUpgradeable {
require(bytes(emailOp.command).length != 0, "command cannot be empty");
require(_getFeeConversionRate(emailOp.feeTokenName) != 0, "unsupported fee token");
require(emailOp.feePerGas <= maxFeePerGas, "fee per gas too high");
require(emailNullifiers[emailOp.emailProof.emailNullifier] == false, "email nullified");
require(accountHandler.emailNullifiers(emailOp.emailProof.emailNullifier) == false, "email nullified");
require(
emailNullifiers[emailOp.emailProof.emailNullifier] == false &&
accountHandler.emailNullifiers(emailOp.emailProof.emailNullifier) == false,
"email nullified"
);
require(
accountHandler.isDKIMPublicKeyHashValid(
emailOp.emailProof.accountSalt,
Expand All @@ -160,19 +163,20 @@ contract EmailWalletCore is Initializable, UUPSUpgradeable, OwnableUpgradeable {
require(emailOp.emailProof.timestamp + emailValidityDuration > block.timestamp, "email expired");
}

if (emailOp.emailProof.hasEmailRecipient) {
require(emailOp.recipientETHAddr == address(0), "cannot have both recipient types");
require(emailOp.emailProof.recipientEmailAddrCommit != bytes32(0), "recipientEmailAddrCommit not found");
} else {
require(emailOp.emailProof.recipientEmailAddrCommit == bytes32(0), "recipientEmailAddrCommit not allowed");
}
// if (emailOp.emailProof.hasEmailRecipient) {
// require(emailOp.recipientETHAddr == address(0), "cannot have both recipient types");
// }
require(
!emailOp.emailProof.hasEmailRecipient || emailOp.recipientETHAddr == address(0),
"Invalid recipientETHAddr"
);
require(
(emailOp.emailProof.hasEmailRecipient && emailOp.emailProof.recipientEmailAddrCommit != bytes32(0)) ||
(!emailOp.emailProof.hasEmailRecipient && emailOp.emailProof.recipientEmailAddrCommit == bytes32(0)),
"Invalid recipientEmailAddrCommit"
);

// Validate computed subject = passed subject
// (string memory computedSubject, ) = SubjectUtils.computeMaskedSubjectForEmailOp(
// emailOp,
// accountHandler.getWalletOfSalt(emailOp.emailProof.accountSalt),
// this // Core contract to read some states
// );
bytes memory maskedSubjectBytes = bytes(emailOp.emailProof.maskedSubject);
require(emailOp.skipSubjectPrefix < maskedSubjectBytes.length, "skipSubjectPrefix too high");
bytes memory skippedSubjectBytes = new bytes(maskedSubjectBytes.length - emailOp.skipSubjectPrefix);
Expand Down Expand Up @@ -201,10 +205,6 @@ contract EmailWalletCore is Initializable, UUPSUpgradeable, OwnableUpgradeable {
);
}
}
// require(
// Strings.equal(computedSubject, string(skippedSubjectBytes)),
// string.concat("subject != ", computedSubject)
// );

// Verify proof
require(verifier.verifyEmailProof(emailOp.emailProof), "invalid email proof");
Expand Down Expand Up @@ -258,7 +258,7 @@ contract EmailWalletCore is Initializable, UUPSUpgradeable, OwnableUpgradeable {
else {
require(
currContext.registeredUnclaimId == 0,
"registeredUnclaimId must be zero if no unclaimed fund/state is registered"
"registeredUnclaimId must be zero for no unclaimed fund/state"
);
payable(msg.sender).transfer(msg.value);
}
Expand Down Expand Up @@ -372,12 +372,13 @@ contract EmailWalletCore is Initializable, UUPSUpgradeable, OwnableUpgradeable {
"target cannot be core or handlers"
);

require(Address.isContract(target), "target is not a contract");

require(target != currContext.walletAddr, "target cannot be wallet");

// Prevent extension from calling ERC20 tokens directly (tokenName should be empty)
require(bytes(tokenRegistry.getTokenNameOfAddress(target)).length == 0, "target cannot be a token");
require(
Address.isContract(target) &&
target != currContext.walletAddr &&
bytes(tokenRegistry.getTokenNameOfAddress(target)).length == 0,
"invalid target for executeAsExtension"
);

Wallet(payable(currContext.walletAddr)).execute(target, 0, data);
}
Expand Down Expand Up @@ -461,7 +462,7 @@ contract EmailWalletCore is Initializable, UUPSUpgradeable, OwnableUpgradeable {
returnData = bytes(reason);
} catch {
success = false;
returnData = bytes("err executing calldata on wallet");
returnData = bytes("err executing calldata");
}
}
// Set custom extension for the user
Expand Down Expand Up @@ -489,7 +490,7 @@ contract EmailWalletCore is Initializable, UUPSUpgradeable, OwnableUpgradeable {
returnData = bytes(reason);
} catch {
success = false;
returnData = bytes("err executing transferOwnership on wallet");
returnData = bytes("err executing transferOwnership");
}
}
// Set DKIM registry
Expand Down Expand Up @@ -576,23 +577,25 @@ contract EmailWalletCore is Initializable, UUPSUpgradeable, OwnableUpgradeable {
} catch Error(string memory reason) {
return (false, bytes(reason));
} catch {
return (false, bytes("unknown wallet exec error"));
return (false, bytes("err unknown wallet exec"));
}
}

/// @notice Return the conversion rate for a token. i.e returns how many tokens 1 ETH could buy in wei format
/// @param tokenName Name of the token
/// @return Conversion rate in wei format
function _getFeeConversionRate(string memory tokenName) internal view returns (uint256) {
require(
Strings.equal(tokenName, "ETH") ||
Strings.equal(tokenName, "WETH") ||
Strings.equal(tokenName, "DAI") ||
Strings.equal(tokenName, "USDC"),
"unsupported fee token"
);
if (Strings.equal(tokenName, "ETH") || Strings.equal(tokenName, "WETH")) {
return 1 ether;
}

bool validToken = Strings.equal(tokenName, "DAI") || Strings.equal(tokenName, "USDC");
if (!validToken) {
return 0;
}

address tokenAddr = tokenRegistry.getTokenAddress(tokenName);
if (tokenAddr == address(0)) {
return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ contract ExtensionCommandTest is EmailWalletCoreTestHelper {
vm.stopPrank();

assertTrue(!success, "handleEmailOp should have failed");
assertEq(string(reason), "target cannot be wallet", "invalid reason");
assertEq(string(reason), "invalid target for executeAsExtension", "invalid reason");
}

function test_RevertIf_ExecuteAsExtension_TargetIsToken() public {
Expand All @@ -461,7 +461,7 @@ contract ExtensionCommandTest is EmailWalletCoreTestHelper {
vm.stopPrank();

assertTrue(!success, "handleEmailOp should have failed");
assertEq(string(reason), "target cannot be a token", "invalid reason");
assertEq(string(reason), "invalid target for executeAsExtension", "invalid reason");
}

// Testing extension cannot execute when not part of an emailOp
Expand Down
6 changes: 3 additions & 3 deletions packages/contracts/test/EmailWalletCore.emailOp.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ contract EmailOpValidationTest is EmailWalletCoreTestHelper {
emailOp.emailProof.recipientEmailAddrCommit = bytes32(uint256(123));

vm.startPrank(relayer);
vm.expectRevert("cannot have both recipient types");
vm.expectRevert("Invalid recipientETHAddr");
core.validateEmailOp(emailOp);
vm.stopPrank();
}
Expand All @@ -133,7 +133,7 @@ contract EmailOpValidationTest is EmailWalletCoreTestHelper {
emailOp.emailProof.recipientEmailAddrCommit = bytes32(0);

vm.startPrank(relayer);
vm.expectRevert("recipientEmailAddrCommit not found");
vm.expectRevert("Invalid recipientEmailAddrCommit");
core.validateEmailOp(emailOp);
vm.stopPrank();
}
Expand All @@ -151,7 +151,7 @@ contract EmailOpValidationTest is EmailWalletCoreTestHelper {
);

vm.startPrank(relayer);
vm.expectRevert("recipientEmailAddrCommit not allowed");
vm.expectRevert("Invalid recipientEmailAddrCommit");
core.validateEmailOp(emailOp);
vm.stopPrank();
}
Expand Down
8 changes: 6 additions & 2 deletions packages/relayer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.68"
lettre = { version = "0.10.4", features = ["tokio1", "tokio1-native-tls"] }
ethers = { version = "2.0.10", features = ["abigen"] }
relayer-utils = { git = "https://github.com/zkemail/relayer-utils", rev = "fba0e90" }
relayer-utils = { version = "0.3.7", git = "https://github.com/zkemail/relayer-utils.git" }
slog = { version = "2.7.0", features = [
"max_level_trace",
"release_max_level_warn",
] }
sqlx = { version = "=0.6.3", features = ["postgres", "runtime-tokio-native-tls"] }
sqlx = { version = "=0.6.3", features = [
"postgres",
"runtime-tokio-native-tls",
] }
poseidon-rs = { git = "https://github.com/zkemail/poseidon-rs.git", version = "1.0.0" }
regex = "1.10.2"
axum = "0.6.20"
rand = "0.8.5"
Expand Down
4 changes: 2 additions & 2 deletions packages/relayer/src/abis/nft_extension.rs

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions packages/relayer/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use ethers::prelude::*;
use ethers::signers::Signer;
use futures::future::BoxFuture;
const CONFIRMATIONS: usize = 1;
use poseidon_rs::Fr;

#[derive(Default, Debug)]
pub struct AccountCreationInput {
Expand Down Expand Up @@ -694,8 +695,8 @@ impl ChainClient {

pub async fn check_if_point_registered(&self, point: Point) -> Result<bool> {
let Point { x, y } = point;
let x = hex2field(&x)?;
let y = hex2field(&y)?;
let x = hex_to_field(&x)?;
let y = hex_to_field(&y)?;
let x = U256::from_little_endian(&x.to_bytes());
let y = U256::from_little_endian(&y.to_bytes());
let account_salt = self
Expand All @@ -709,8 +710,8 @@ impl ChainClient {

pub async fn check_if_account_created_by_point(&self, point: Point) -> Result<bool> {
let Point { x, y } = point;
let x = hex2field(&x)?;
let y = hex2field(&y)?;
let x = hex_to_field(&x)?;
let y = hex_to_field(&y)?;
let x = U256::from_little_endian(&x.to_bytes());
let y = U256::from_little_endian(&y.to_bytes());
let account_salt = self
Expand All @@ -731,7 +732,7 @@ impl ChainClient {
email_addr: &str,
account_code: &str,
) -> Result<bool> {
let account_code = AccountCode(hex2field(account_code)?);
let account_code = AccountCode(hex_to_field(account_code)?);
let padded_email_addr = PaddedEmailAddr::from_email_addr(email_addr);
let account_salt = AccountSalt::new(&padded_email_addr, account_code)?;
let is_deployed = self
Expand Down
31 changes: 17 additions & 14 deletions packages/relayer/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,32 @@ pub async fn handle_email(email: String) -> Result<EmailWalletEvent> {
let original_subject = parsed_email.get_subject_all()?;
trace!(LOG, "Original Subject: {}", original_subject; "func" => function_name!());
check_and_update_dkim(&email, &parsed_email).await?;
if let Ok(invitation_code) = parsed_email.get_invitation_code() {
if let Ok(invitation_code) = parsed_email.get_invitation_code(true) {
trace!(LOG, "Email with invitation code"; "func" => function_name!());
let account_code = AccountCode::from(hex2field(&format!("0x{}", invitation_code))?);
trace!(LOG, "Account code: {}", field2hex(&account_code.0); "func" => function_name!());
let account_code = AccountCode::from(hex_to_field(&format!("0x{}", invitation_code))?);
trace!(LOG, "Account code: {}", field_to_hex(&account_code.0); "func" => function_name!());
let stored_account_code = DB.get_account_code(&from_addr).await?;
if let Some(stored_account_code) = stored_account_code.as_ref() {
if stored_account_code != &field2hex(&account_code.0) {
if stored_account_code != &field_to_hex(&account_code.0) {
return Err(anyhow!(
"Stored account key is not equal to one in the email: {} != {}",
stored_account_code,
field2hex(&account_code.0)
field_to_hex(&account_code.0)
));
}
}
let account_salt = AccountSalt::new(&padded_from_addr, account_code)?;
trace!(LOG, "Wallet salt: {}", field2hex(&account_salt.0); "func" => function_name!());
trace!(LOG, "Wallet salt: {}", field_to_hex(&account_salt.0); "func" => function_name!());
if !CLIENT
.check_if_account_created_by_account_code(&from_addr, &field2hex(&account_code.0))
.check_if_account_created_by_account_code(&from_addr, &field_to_hex(&account_code.0))
.await?
{
info!(LOG, "Account creation"; "func" => function_name!());
let input =
generate_account_creation_input(&email, RELAYER_RAND.get().unwrap()).await?;
let input = {
let all_input: EmailCircu = serde_json::from_str(
&generate_email_circuit_input(&email, RELAYER_RAND.get().unwrap()).await?,
)?;
};
info!(LOG, "Account creation input {:?}", input; "func" => function_name!());
let (masked_subject, num_recipient_email_addr_bytes) =
get_masked_subject(&original_subject)?;
Expand Down Expand Up @@ -85,7 +88,7 @@ pub async fn handle_email(email: String) -> Result<EmailWalletEvent> {
} else {
DB.insert_user(
&from_addr,
&field2hex(&account_code.0),
&field_to_hex(&account_code.0),
&res,
true,
&format!("0x{}", hex::encode(wallet_addr.as_bytes())),
Expand Down Expand Up @@ -123,10 +126,10 @@ pub async fn handle_email(email: String) -> Result<EmailWalletEvent> {
{
bail!("The user of email address {} is not registered.", from_addr);
}
let account_code = AccountCode(hex2field(&account_code_str)?);
let relayer_rand = RelayerRand(hex2field(RELAYER_RAND.get().unwrap())?);
let account_code = AccountCode(hex_to_field(&account_code_str)?);
let relayer_rand = RelayerRand(hex_to_field(RELAYER_RAND.get().unwrap())?);
let account_salt = AccountSalt::new(&padded_from_addr, account_code)?;
trace!(LOG, "Wallet salt: {}", field2hex(&account_salt.0); "func" => function_name!());
trace!(LOG, "Wallet salt: {}", field_to_hex(&account_salt.0); "func" => function_name!());
let wallet_addr = CLIENT.get_wallet_addr_from_salt(&account_salt.0).await?;
info!(LOG, "Sender wallet address: {}", wallet_addr; "func" => function_name!());
let (command, skip_subject_prefix) =
Expand Down Expand Up @@ -362,7 +365,7 @@ pub async fn handle_email(email: String) -> Result<EmailWalletEvent> {
id: registered_unclaim_id,
email_address: email_addr.clone(),
commit,
random: field2hex(&commit_rand),
random: field_to_hex(&commit_rand),
expiry_time,
is_fund,
is_announced: false,
Expand Down
12 changes: 6 additions & 6 deletions packages/relayer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use anyhow::{anyhow, bail, Result};
use dotenv::dotenv;
use ethers::prelude::*;
use lazy_static::lazy_static;
use relayer_utils::{converters::*, cryptos::*, Fr, LOG};
use relayer_utils::{converters::*, cryptos::*, LOG};
use slog::{error, info, trace};
use std::env;
use std::path::PathBuf;
Expand Down Expand Up @@ -153,7 +153,7 @@ pub async fn run(config: RelayerConfig) -> Result<()> {
.unwrap();

let relayer_rand = derive_relayer_rand(PRIVATE_KEY.get().unwrap())?;
RELAYER_RAND.set(field2hex(&relayer_rand.0)).unwrap();
RELAYER_RAND.set(field_to_hex(&relayer_rand.0)).unwrap();

let safe_task = tokio::task::spawn(async move {
loop {
Expand Down Expand Up @@ -192,10 +192,10 @@ pub async fn run(config: RelayerConfig) -> Result<()> {
if event.email_addr.is_empty() {
return Ok(());
}
let random = field2hex(&bytes32_to_fr(&u256_to_bytes32(
let random = field_to_hex(&bytes32_to_fr(&u256_to_bytes32(
&event.commitment_randomness,
))?);
let commit = field2hex(&bytes32_to_fr(&event.email_addr_commit)?);
let commit = field_to_hex(&bytes32_to_fr(&event.email_addr_commit)?);
let claim = Claim {
tx_hash: meta.transaction_hash.to_string(),
id: event.id,
Expand Down Expand Up @@ -224,10 +224,10 @@ pub async fn run(config: RelayerConfig) -> Result<()> {
if event.email_addr.is_empty() {
return Ok(());
}
let random = field2hex(&bytes32_to_fr(&u256_to_bytes32(
let random = field_to_hex(&bytes32_to_fr(&u256_to_bytes32(
&event.commitment_randomness,
))?);
let commit = field2hex(&bytes32_to_fr(&event.email_addr_commit)?);
let commit = field_to_hex(&bytes32_to_fr(&event.email_addr_commit)?);
let claim = Claim {
tx_hash: meta.transaction_hash.to_string(),
id: event.id,
Expand Down
Loading

0 comments on commit 4d381a9

Please sign in to comment.