diff --git a/Cargo.lock b/Cargo.lock index 15538d0..e54fc66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -87,6 +87,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "anyhow" +version = "1.0.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e1496f8fb1fbf272686b8d37f523dab3e4a7443300055e74cdaa449f3114356" + [[package]] name = "arrayvec" version = "0.7.2" @@ -2162,9 +2168,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.58" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -3047,11 +3053,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -3059,9 +3064,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.24" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", @@ -3070,9 +3075,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] @@ -3579,6 +3584,7 @@ dependencies = [ name = "zksync-web3-rs" version = "0.2.0" dependencies = [ + "anyhow", "async-trait", "clap", "env_logger", diff --git a/Cargo.toml b/Cargo.toml index ec7527a..6d191a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ env_logger = "0.10" # Hash sha2 = "0.9.5" +anyhow = "1.0.88" [features] ethers-solc = ["ethers/ethers-solc"] diff --git a/examples/paymaster/main.rs b/examples/paymaster/main.rs new file mode 100644 index 0000000..f90d614 --- /dev/null +++ b/examples/paymaster/main.rs @@ -0,0 +1,98 @@ +use ethers::abi::Bytes; +use ethers::core::k256::ecdsa::SigningKey; +use ethers::prelude::*; +use ethers::providers::Http; +use ethers::{ + abi::Address, + providers::Provider, + signers::{Signer, Wallet}, + types::U256, +}; +use std::str::FromStr; +use std::sync::Arc; +use zksync_web3_rs::core::abi::{Contract, Token}; +use zksync_web3_rs::eip712::{Eip712Meta, Eip712TransactionRequest, PaymasterParams}; +use zksync_web3_rs::ZKSWallet; +use zksync_web3_rs::zks_provider::ZKSProvider; + +static ERA_PROVIDER_URL: &str = "http://127.0.0.1:3050"; +static PK: &str = "0x27593fea79697e947890ecbecce7901b0008345e5d7259710d0dd5e500d040be"; +static PAYMASTER_ADDRESS: &str = ""; + +const PAYMASTER_ABI: &str = r#" + [ + { + "inputs": [ + { + "internalType": "bytes", + "name": "input", + "type": "bytes" + } + ], + "name": "general", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] + "#; + +pub struct PaymasterFlow { + paymaster: Address, + amount: U256, + paymaster_encoded_input: Bytes, + zk_wallet: ZKSWallet, SigningKey>, + era_provider: Arc, Wallet>>, +} + +impl PaymasterFlow { + pub fn new(private_key: String, + paymaster_address: H160, + chain_id: u64, + provider:Provider) -> Self { + let paymaster_contract = Contract::load(PAYMASTER_ABI.as_bytes()).expect("Failed to load the paymaster ABI"); + let paymaster_general_fn = paymaster_contract.function("general").expect("Failed to get the general function"); + let wallet = Wallet::from_str(private_key.as_str()).expect("Failed to create wallet from private key"); + let signer = Wallet::with_chain_id(wallet, chain_id); + let zk_wallet = ZKSWallet::new(signer, None, Some(provider.clone()), None).unwrap(); + let era_provider = zk_wallet.get_era_provider().expect("Failed to get era provider from zk wallet"); + let paymaster_encoded_input = paymaster_general_fn.encode_input(&[Token::Bytes(vec![])]).expect("Failed to encode paymaster input"); + + Self { + paymaster: paymaster_address, + amount: U256::from_dec_str("1").expect("Failed to parse amount"), + paymaster_encoded_input, + zk_wallet, + era_provider + } + } + + fn tx_request(&self) -> Eip712TransactionRequest { + let address = self.zk_wallet.l1_wallet.address(); + Eip712TransactionRequest::new() + .from(address) + .to(address) + .value(self.amount) + .custom_data(Eip712Meta::new().paymaster_params(PaymasterParams { + paymaster: self.paymaster, + paymaster_input: self.paymaster_encoded_input.clone() + })) + } + + async fn send_transaction(&self) -> anyhow::Result> { + let result = self.era_provider + .send_transaction_eip712(&self.zk_wallet.l2_wallet, self.tx_request()) + .await?; + Ok(result) + } +} + +#[tokio::main] +async fn main() { + let era_provider = Provider::try_from(ERA_PROVIDER_URL).unwrap(); + let paymaster_address = Address::from_str(PAYMASTER_ADDRESS).unwrap(); + let chain_id = era_provider.get_chainid().await.unwrap(); + let flow = PaymasterFlow::new(PK.to_string(), paymaster_address, chain_id.as_u64(), era_provider.clone()); + let tx = flow.send_transaction().await.unwrap().await.unwrap().unwrap(); + println!("Transaction sent: {:#?}", tx); +}