zksync_web3_rs/contracts/
main_contract.rs

1use std::sync::Arc;
2
3use ethers::prelude::k256::ecdsa::{RecoveryId, Signature};
4use ethers::prelude::k256::schnorr::signature::hazmat::PrehashSigner;
5use ethers::prelude::signer::SignerMiddlewareError;
6use ethers::prelude::ProviderError;
7use ethers::prelude::SignerMiddleware;
8use ethers::providers::Middleware;
9use ethers::signers::Wallet;
10use ethers::types::{Address, Bytes, TransactionReceipt, U256};
11use ethers_contract::{abigen, ContractError};
12
13abigen!(MainContract, "./src/abi/IZkSync.json");
14
15// ╔══════════════════════════════════════════════════════════════════════════════════════════╗
16// ║ Error enum:                                                                              ║
17// ╚══════════════════════════════════════════════════════════════════════════════════════════╝
18
19#[derive(thiserror::Error, Debug)]
20pub enum MainContractError<M, D>
21where
22    M: Middleware,
23    D: PrehashSigner<(Signature, RecoveryId)> + Sync + Send,
24{
25    #[error("Middleware error: {0}")]
26    MiddlewareError(#[from] SignerMiddlewareError<M, Wallet<D>>),
27    #[error("Contract error: {0}")]
28    ContractError(#[from] ContractError<SignerMiddleware<M, Wallet<D>>>),
29    #[error("Provider error: {0}")]
30    ProviderError(#[from] ProviderError),
31    #[error("Transaction receipt not found")]
32    TransactionReceiptNotFound,
33}
34
35// ╔══════════════════════════════════════════════════════════════════════════════════════════╗
36// ║ Decorator:                                                                               ║
37// ╚══════════════════════════════════════════════════════════════════════════════════════════╝
38type SM<M, D> = SignerMiddleware<M, Wallet<D>>;
39
40pub struct MainContractInstance<M, D>
41where
42    M: Middleware,
43    D: PrehashSigner<(Signature, RecoveryId)> + Sync + Send,
44{
45    provider: Arc<SM<M, D>>,
46    contract: MainContract<SM<M, D>>,
47}
48
49impl<M, D> MainContractInstance<M, D>
50where
51    M: Middleware,
52    D: PrehashSigner<(Signature, RecoveryId)> + Sync + Send,
53{
54    pub fn new(address: Address, provider: Arc<SignerMiddleware<M, Wallet<D>>>) -> Self {
55        let contract = MainContract::new(address, Arc::clone(&provider));
56        Self { provider, contract }
57    }
58
59    pub async fn get_base_cost(
60        &self,
61        gas_price: U256,
62        l2_gas_limit: U256,
63        l2_gas_per_pubdata_byte_limit: U256,
64    ) -> Result<U256, ContractError<SM<M, D>>> {
65        self.contract
66            .l_2_transaction_base_cost(gas_price, l2_gas_limit, l2_gas_per_pubdata_byte_limit)
67            .call()
68            .await
69    }
70
71    async fn nonce(&self) -> Result<U256, MainContractError<M, D>> {
72        let signer_address = self.provider.address();
73        let nonce = self
74            .provider
75            .get_transaction_count(signer_address, None)
76            .await?;
77        Ok(nonce)
78    }
79
80    pub async fn request_l2_transaction(
81        &self,
82        contract_l2: Address,
83        l2_value: U256,
84        call_data: Bytes,
85        l2_gas_limit: U256,
86        l2_gas_per_pubdata_byte_limit: U256,
87        factory_deps: Vec<Bytes>,
88        refund_recipient: Address,
89        gas_price: U256,
90        gas_limit: U256,
91        l1_value: U256,
92    ) -> Result<TransactionReceipt, MainContractError<M, D>> {
93        let nonce = self.nonce().await?;
94        let function_call = self
95            .contract
96            .request_l2_transaction(
97                contract_l2,
98                l2_value,
99                call_data,
100                l2_gas_limit,
101                l2_gas_per_pubdata_byte_limit,
102                factory_deps,
103                refund_recipient,
104            )
105            .nonce(nonce)
106            .from(self.provider.address())
107            .gas_price(gas_price)
108            .gas(gas_limit)
109            .value(l1_value);
110        let receipt = function_call
111            .send()
112            .await?
113            // FIXME: Awaiting on a `PendingTransaction` results in an
114            // `Option<TransactionReceipt>`. Under which circumpstances does it return `None`?
115            .await?
116            .ok_or(MainContractError::<M, D>::TransactionReceiptNotFound)?;
117
118        Ok(receipt)
119    }
120}