From 02e507636e68a2c61d8d8e473a980f828755923f Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Fri, 22 Dec 2023 16:43:55 -0300 Subject: [PATCH 1/9] Add salt field for EIP712 custom data --- src/eip712/meta.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/eip712/meta.rs b/src/eip712/meta.rs index a17ac9f..0cbe917 100644 --- a/src/eip712/meta.rs +++ b/src/eip712/meta.rs @@ -15,6 +15,8 @@ pub struct Eip712Meta { pub custom_signature: Option, #[serde(skip_serializing_if = "Option::is_none")] pub paymaster_params: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub salt: Option, } impl Eip712Meta { @@ -50,6 +52,11 @@ impl Eip712Meta { self.paymaster_params = Some(paymaster_params); self } + + pub fn salt(mut self, salt: Bytes) -> Self { + self.salt = Some(salt); + self + } } impl Default for Eip712Meta { @@ -59,6 +66,7 @@ impl Default for Eip712Meta { factory_deps: Default::default(), custom_signature: Default::default(), paymaster_params: Default::default(), + salt: Default::default(), } } } From 285c6e568f50b1d4232f89074c5bfaa7d125ab19 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Fri, 22 Dec 2023 16:44:45 -0300 Subject: [PATCH 2/9] Deploy type to use create and create 2 --- src/zks_wallet/requests/deploy_request.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/zks_wallet/requests/deploy_request.rs b/src/zks_wallet/requests/deploy_request.rs index 26bb6db..5fad988 100644 --- a/src/zks_wallet/requests/deploy_request.rs +++ b/src/zks_wallet/requests/deploy_request.rs @@ -8,6 +8,7 @@ pub struct DeployRequest { pub constructor_parameters: Vec, pub from: Address, pub factory_deps: Option>>, + pub deploy_type: String, } impl DeployRequest { @@ -22,6 +23,7 @@ impl DeployRequest { constructor_parameters, from: Default::default(), factory_deps: None, + deploy_type: "create".to_string(), } } @@ -34,4 +36,9 @@ impl DeployRequest { self.factory_deps = Some(factory_deps); self } + + pub fn deploy_type(mut self, deploy_type: &str) -> Self { + self.deploy_type = deploy_type.to_string(); + self + } } From cab86bdf859439e1e150ff5134dbf2696a05b0d2 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Fri, 22 Dec 2023 16:49:58 -0300 Subject: [PATCH 3/9] Encode create2 function for eip712 transaction request --- src/eip712/transaction_request.rs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/eip712/transaction_request.rs b/src/eip712/transaction_request.rs index ddefc2e..c8a53e4 100644 --- a/src/eip712/transaction_request.rs +++ b/src/eip712/transaction_request.rs @@ -282,15 +282,19 @@ impl TryFrom for Eip712TransactionRequest { fn try_from(request: DeployRequest) -> Result { let mut contract_deployer_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); contract_deployer_path.push("src/abi/ContractDeployer.json"); - - let custom_data = Eip712Meta::new().factory_deps({ - let mut factory_deps = Vec::new(); - if let Some(factory_dependencies) = request.factory_deps { - factory_deps.extend(factory_dependencies); - } - factory_deps.push(request.contract_bytecode.clone()); - factory_deps - }); + // TODO: User could provide this instead of defaulting. + let salt = [1_u8; 32]; + + let custom_data = Eip712Meta::new() + .factory_deps({ + let mut factory_deps = Vec::new(); + if let Some(factory_dependencies) = request.factory_deps { + factory_deps.extend(factory_dependencies); + } + factory_deps.push(request.contract_bytecode.clone()); + factory_deps + }) + .salt(Bytes::from(salt)); let contract_deployer = Abi::load(BufReader::new( File::open(contract_deployer_path).map_err(|e| { @@ -299,10 +303,8 @@ impl TryFrom for Eip712TransactionRequest { )) })?, ))?; - let create = contract_deployer.function("create")?; + let create_function = contract_deployer.function(&request.deploy_type)?; - // TODO: User could provide this instead of defaulting. - let salt = [0_u8; 32]; let bytecode_hash = hash_bytecode(&request.contract_bytecode).map_err(|e| { ZKRequestError::CustomError(format!("Error hashing contract bytecode {e:?}")) })?; @@ -322,7 +324,7 @@ impl TryFrom for Eip712TransactionRequest { } }; - let data = encode_function_data(create, (salt, bytecode_hash, call_data))?; + let data = encode_function_data(create_function, (salt, bytecode_hash, call_data))?; let contract_deployer_address = Address::from_str(CONTRACT_DEPLOYER_ADDR).map_err(|e| { ZKRequestError::CustomError(format!("Error getting contract deployer address {e:?}")) From c48056cf8d590b2e090aee76e6f34bfe1a96106d Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 26 Dec 2023 20:35:42 -0300 Subject: [PATCH 4/9] Add rand as dev dependency for test purposes --- Cargo.lock | 1 + Cargo.toml | 3 +++ 2 files changed, 4 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 9b136ec..638d501 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3587,6 +3587,7 @@ dependencies = [ "hex", "lazy_static", "log", + "rand", "serde", "serde_json", "sha2 0.9.9", diff --git a/Cargo.toml b/Cargo.toml index c4fac4c..cea9fb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,9 @@ env_logger = "0.10" # Hash sha2 = "0.9.5" +[dev-dependencies] +rand = "0.8.5" + [features] ethers-solc = ["ethers/ethers-solc"] From 21fc67ddf994c91adb4f534fc1baf2d5a871c5c9 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 26 Dec 2023 20:36:00 -0300 Subject: [PATCH 5/9] Remove salt as field for eip712 transaction request --- src/eip712/meta.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/eip712/meta.rs b/src/eip712/meta.rs index 0cbe917..a17ac9f 100644 --- a/src/eip712/meta.rs +++ b/src/eip712/meta.rs @@ -15,8 +15,6 @@ pub struct Eip712Meta { pub custom_signature: Option, #[serde(skip_serializing_if = "Option::is_none")] pub paymaster_params: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub salt: Option, } impl Eip712Meta { @@ -52,11 +50,6 @@ impl Eip712Meta { self.paymaster_params = Some(paymaster_params); self } - - pub fn salt(mut self, salt: Bytes) -> Self { - self.salt = Some(salt); - self - } } impl Default for Eip712Meta { @@ -66,7 +59,6 @@ impl Default for Eip712Meta { factory_deps: Default::default(), custom_signature: Default::default(), paymaster_params: Default::default(), - salt: Default::default(), } } } From 31cea88b005d5e846accdd5ea4895a893a02e26e Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 26 Dec 2023 20:36:58 -0300 Subject: [PATCH 6/9] Add salt as field for deploy request --- src/zks_wallet/requests/deploy_request.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/zks_wallet/requests/deploy_request.rs b/src/zks_wallet/requests/deploy_request.rs index 5fad988..3922ba4 100644 --- a/src/zks_wallet/requests/deploy_request.rs +++ b/src/zks_wallet/requests/deploy_request.rs @@ -9,6 +9,7 @@ pub struct DeployRequest { pub from: Address, pub factory_deps: Option>>, pub deploy_type: String, + pub salt: Option<[u8; 32]>, } impl DeployRequest { @@ -24,6 +25,7 @@ impl DeployRequest { from: Default::default(), factory_deps: None, deploy_type: "create".to_string(), + salt: None, } } @@ -41,4 +43,9 @@ impl DeployRequest { self.deploy_type = deploy_type.to_string(); self } + + pub fn salt(mut self, salt: [u8; 32]) -> Self { + self.salt = Some(salt); + self + } } From f1555e14bfc1f2a6bd84f5cc8f908da36aa21e55 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 26 Dec 2023 20:37:19 -0300 Subject: [PATCH 7/9] Correct encoding for create 2 function --- src/eip712/transaction_request.rs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/eip712/transaction_request.rs b/src/eip712/transaction_request.rs index c8a53e4..9e5b588 100644 --- a/src/eip712/transaction_request.rs +++ b/src/eip712/transaction_request.rs @@ -282,19 +282,15 @@ impl TryFrom for Eip712TransactionRequest { fn try_from(request: DeployRequest) -> Result { let mut contract_deployer_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); contract_deployer_path.push("src/abi/ContractDeployer.json"); - // TODO: User could provide this instead of defaulting. - let salt = [1_u8; 32]; - - let custom_data = Eip712Meta::new() - .factory_deps({ - let mut factory_deps = Vec::new(); - if let Some(factory_dependencies) = request.factory_deps { - factory_deps.extend(factory_dependencies); - } - factory_deps.push(request.contract_bytecode.clone()); - factory_deps - }) - .salt(Bytes::from(salt)); + + let custom_data = Eip712Meta::new().factory_deps({ + let mut factory_deps = Vec::new(); + if let Some(factory_dependencies) = request.factory_deps { + factory_deps.extend(factory_dependencies); + } + factory_deps.push(request.contract_bytecode.clone()); + factory_deps + }); let contract_deployer = Abi::load(BufReader::new( File::open(contract_deployer_path).map_err(|e| { @@ -323,7 +319,7 @@ impl TryFrom for Eip712TransactionRequest { .into() } }; - + let salt = request.salt.unwrap_or_else(|| [0_u8; 32]); let data = encode_function_data(create_function, (salt, bytecode_hash, call_data))?; let contract_deployer_address = Address::from_str(CONTRACT_DEPLOYER_ADDR).map_err(|e| { From 82bdc39723172de3f6df00aca6cb54c094c0cb9b Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Tue, 26 Dec 2023 20:37:35 -0300 Subject: [PATCH 8/9] Add test for create 2 deployment --- src/tests/wallet_tests.rs | 65 ++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 11 deletions(-) diff --git a/src/tests/wallet_tests.rs b/src/tests/wallet_tests.rs index a4893dc..a74594c 100644 --- a/src/tests/wallet_tests.rs +++ b/src/tests/wallet_tests.rs @@ -9,9 +9,10 @@ mod zks_signer_tests { use ethers::contract::abigen; use ethers::providers::Middleware; use ethers::signers::{LocalWallet, Signer}; - use ethers::types::Address; use ethers::types::U256; + use ethers::types::{Address, Bytes}; use ethers::utils::parse_units; + use rand::RngCore; use std::fs::File; use std::path::PathBuf; use std::str::FromStr; @@ -27,7 +28,7 @@ mod zks_signer_tests { #[tokio::test] async fn test_transfer() { let sender_private_key = - "0x28a574ab2de8a00364d5dd4b07c4f2f574ef7fcc2a86a197f65abaec836d1959"; + "0xe131bc3f481277a8f73d680d9ba404cc6f959e64296e0914dded403030d4f705"; let receiver_address: Address = "0xa61464658AfeAf65CccaaFD3a512b69A83B77618" .parse() .unwrap(); @@ -91,7 +92,7 @@ mod zks_signer_tests { #[tokio::test] async fn test_deposit() { - let private_key = "0x28a574ab2de8a00364d5dd4b07c4f2f574ef7fcc2a86a197f65abaec836d1959"; + let private_key = "0xe131bc3f481277a8f73d680d9ba404cc6f959e64296e0914dded403030d4f705"; let request = DepositRequest::new(parse_units("0.01", "ether").unwrap().into()); println!("Amount: {}", request.amount); @@ -143,7 +144,7 @@ mod zks_signer_tests { #[tokio::test] async fn test_deposit_to_another_address() { - let private_key = "0x28a574ab2de8a00364d5dd4b07c4f2f574ef7fcc2a86a197f65abaec836d1959"; + let private_key = "0xe131bc3f481277a8f73d680d9ba404cc6f959e64296e0914dded403030d4f705"; let to: Address = "0xa61464658AfeAf65CccaaFD3a512b69A83B77618" .parse() .unwrap(); @@ -200,7 +201,7 @@ mod zks_signer_tests { #[tokio::test] async fn test_deposit_erc20_token() { let amount: U256 = 1_i32.into(); - let private_key = "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110"; + let private_key = "0xe131bc3f481277a8f73d680d9ba404cc6f959e64296e0914dded403030d4f705"; let l1_provider = eth_provider(); let l2_provider = era_provider(); let wallet = LocalWallet::from_str(private_key).unwrap(); @@ -249,7 +250,7 @@ mod zks_signer_tests { #[tokio::test] async fn test_transfer_eip712() { let sender_private_key = - "0x28a574ab2de8a00364d5dd4b07c4f2f574ef7fcc2a86a197f65abaec836d1959"; + "0xe131bc3f481277a8f73d680d9ba404cc6f959e64296e0914dded403030d4f705"; let receiver_address: Address = "0xa61464658AfeAf65CccaaFD3a512b69A83B77618" .parse() .unwrap(); @@ -313,10 +314,52 @@ mod zks_signer_tests { ); } + #[tokio::test] + async fn test_deploy_contract_with_create2() { + let deployer_private_key = + "e131bc3f481277a8f73d680d9ba404cc6f959e64296e0914dded403030d4f705"; + let era_provider = era_provider(); + let wallet = LocalWallet::from_str(deployer_private_key) + .unwrap() + .with_chain_id(ERA_CHAIN_ID); + let zk_wallet = ZKSWallet::new(wallet, None, Some(era_provider.clone()), None).unwrap(); + + let mut contract_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + contract_path.push("src/abi/test_contracts/counter_combined.json"); + let contract: CompiledContract = + serde_json::from_reader(File::open(contract_path).unwrap()).unwrap(); + let mut salt = [0_u8; 32]; + rand::thread_rng().fill_bytes(&mut salt[..]); + let deploy_request = DeployRequest::with(contract.abi, contract.bin.to_vec(), vec![]) + .from(zk_wallet.l2_address()) + .deploy_type("create2") + .salt(salt); + let first_deploy_contract_address = zk_wallet.deploy(&deploy_request).await.unwrap(); + let deploy_result = era_provider + .get_code(first_deploy_contract_address, None) + .await; + assert!( + deploy_result.is_ok(), + "Contract should be deployed successfully the first time" + ); + + rand::thread_rng().fill_bytes(&mut salt[..]); + let second_deploy_request = deploy_request.salt(salt); + let second_deploy_contract_address = + zk_wallet.deploy(&second_deploy_request).await.unwrap(); + let deploy_result: Result = era_provider + .get_code(second_deploy_contract_address, None) + .await; + assert!( + deploy_result.is_ok(), + "Contract should be deployed successfully the second time" + ); + } + #[tokio::test] async fn test_deploy_contract_with_constructor_arg_uint() { let deployer_private_key = - "7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110"; + "0xe131bc3f481277a8f73d680d9ba404cc6f959e64296e0914dded403030d4f705"; let era_provider = era_provider(); let wallet = LocalWallet::from_str(deployer_private_key) .unwrap() @@ -340,7 +383,7 @@ mod zks_signer_tests { #[tokio::test] async fn test_deploy_contract_with_constructor_arg_string() { let deployer_private_key = - "7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110"; + "0xe131bc3f481277a8f73d680d9ba404cc6f959e64296e0914dded403030d4f705"; let era_provider = era_provider(); let wallet = LocalWallet::from_str(deployer_private_key) .unwrap() @@ -364,7 +407,7 @@ mod zks_signer_tests { #[tokio::test] async fn test_deploy_contract_with_import() { let deployer_private_key = - "7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110"; + "0xe131bc3f481277a8f73d680d9ba404cc6f959e64296e0914dded403030d4f705"; let era_provider = era_provider(); let wallet = LocalWallet::from_str(deployer_private_key) .unwrap() @@ -413,7 +456,7 @@ mod zks_signer_tests { #[tokio::test] async fn test_withdraw_to_same_address() { let sender_private_key = - "0x28a574ab2de8a00364d5dd4b07c4f2f574ef7fcc2a86a197f65abaec836d1959"; + "0xe131bc3f481277a8f73d680d9ba404cc6f959e64296e0914dded403030d4f705"; let wallet = LocalWallet::from_str(sender_private_key) .unwrap() .with_chain_id(ERA_CHAIN_ID); @@ -510,7 +553,7 @@ mod zks_signer_tests { #[tokio::test] async fn test_withdraw_to_other_address() { let sender_private_key = - "0x28a574ab2de8a00364d5dd4b07c4f2f574ef7fcc2a86a197f65abaec836d1959"; + "0xe131bc3f481277a8f73d680d9ba404cc6f959e64296e0914dded403030d4f705"; let receiver_private_key = "0xe667e57a9b8aaa6709e51ff7d093f1c5b73b63f9987e4ab4aa9a5c699e024ee8"; let l2_wallet = LocalWallet::from_str(sender_private_key) From 2f6db87a501d34c772e6986a414d3a5415d3e841 Mon Sep 17 00:00:00 2001 From: IAvecilla Date: Wed, 27 Dec 2023 11:12:31 -0300 Subject: [PATCH 9/9] Add enum for deploy types --- src/eip712/transaction_request.rs | 5 +++-- src/tests/wallet_tests.rs | 5 +++-- src/zks_wallet/mod.rs | 7 +++++-- src/zks_wallet/requests/deploy_request.rs | 25 ++++++++++++++++++----- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/eip712/transaction_request.rs b/src/eip712/transaction_request.rs index 9e5b588..6b807f5 100644 --- a/src/eip712/transaction_request.rs +++ b/src/eip712/transaction_request.rs @@ -299,7 +299,7 @@ impl TryFrom for Eip712TransactionRequest { )) })?, ))?; - let create_function = contract_deployer.function(&request.deploy_type)?; + let create_function = contract_deployer.function(&request.deploy_type.to_string())?; let bytecode_hash = hash_bytecode(&request.contract_bytecode).map_err(|e| { ZKRequestError::CustomError(format!("Error hashing contract bytecode {e:?}")) @@ -319,7 +319,8 @@ impl TryFrom for Eip712TransactionRequest { .into() } }; - let salt = request.salt.unwrap_or_else(|| [0_u8; 32]); + + let salt = request.salt.unwrap_or([0_u8; 32]); let data = encode_function_data(create_function, (salt, bytecode_hash, call_data))?; let contract_deployer_address = Address::from_str(CONTRACT_DEPLOYER_ADDR).map_err(|e| { diff --git a/src/tests/wallet_tests.rs b/src/tests/wallet_tests.rs index a74594c..13157ad 100644 --- a/src/tests/wallet_tests.rs +++ b/src/tests/wallet_tests.rs @@ -3,7 +3,8 @@ mod zks_signer_tests { use crate::zks_provider::ZKSProvider; use crate::zks_utils::{ERA_CHAIN_ID, ETH_CHAIN_ID}; use crate::zks_wallet::{ - CallRequest, DeployRequest, DepositRequest, TransferRequest, WithdrawRequest, ZKSWallet, + CallRequest, DepositRequest, TransferRequest, WithdrawRequest, ZKSWallet, + {DeployRequest, DeployType}, }; use ethers::abi::Tokenize; use ethers::contract::abigen; @@ -332,7 +333,7 @@ mod zks_signer_tests { rand::thread_rng().fill_bytes(&mut salt[..]); let deploy_request = DeployRequest::with(contract.abi, contract.bin.to_vec(), vec![]) .from(zk_wallet.l2_address()) - .deploy_type("create2") + .deploy_type(DeployType::Create2) .salt(salt); let first_deploy_contract_address = zk_wallet.deploy(&deploy_request).await.unwrap(); let deploy_result = era_provider diff --git a/src/zks_wallet/mod.rs b/src/zks_wallet/mod.rs index f408b6c..d4508b3 100644 --- a/src/zks_wallet/mod.rs +++ b/src/zks_wallet/mod.rs @@ -3,8 +3,11 @@ pub use errors::{ZKRequestError, ZKSWalletError}; mod requests; pub use requests::{ - call_request::CallRequest, deploy_request::DeployRequest, deposit_request::DepositRequest, - transfer_request::TransferRequest, withdraw_request::WithdrawRequest, + call_request::CallRequest, + deploy_request::{DeployRequest, DeployType}, + deposit_request::DepositRequest, + transfer_request::TransferRequest, + withdraw_request::WithdrawRequest, }; mod wallet; diff --git a/src/zks_wallet/requests/deploy_request.rs b/src/zks_wallet/requests/deploy_request.rs index 3922ba4..65dac2a 100644 --- a/src/zks_wallet/requests/deploy_request.rs +++ b/src/zks_wallet/requests/deploy_request.rs @@ -1,5 +1,20 @@ use ethers::{abi::Abi, types::Address}; -use std::fmt::Debug; +use std::{fmt::Debug, fmt::Display}; + +#[derive(Clone, Debug)] +pub enum DeployType { + Create, + Create2, +} + +impl Display for DeployType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + DeployType::Create => write!(f, "create"), + DeployType::Create2 => write!(f, "create2"), + } + } +} #[derive(Clone, Debug)] pub struct DeployRequest { @@ -8,7 +23,7 @@ pub struct DeployRequest { pub constructor_parameters: Vec, pub from: Address, pub factory_deps: Option>>, - pub deploy_type: String, + pub deploy_type: DeployType, pub salt: Option<[u8; 32]>, } @@ -24,7 +39,7 @@ impl DeployRequest { constructor_parameters, from: Default::default(), factory_deps: None, - deploy_type: "create".to_string(), + deploy_type: DeployType::Create, salt: None, } } @@ -39,8 +54,8 @@ impl DeployRequest { self } - pub fn deploy_type(mut self, deploy_type: &str) -> Self { - self.deploy_type = deploy_type.to_string(); + pub fn deploy_type(mut self, deploy_type: DeployType) -> Self { + self.deploy_type = deploy_type; self }