alloy_zksync/provider/fillers/
mod.rs

1//! ZKsync-specific transaction data filler.
2
3use alloy::{
4    network::TransactionBuilder,
5    primitives::U256,
6    providers::{
7        Provider, SendableTx,
8        fillers::{FillerControlFlow, TxFiller},
9    },
10    transports::TransportResult,
11};
12
13use crate::network::{Zksync, transaction_request::TransactionRequest};
14
15use super::{Eip712Fee, ZksyncProvider};
16
17/// [Filler](https://docs.rs/alloy/latest/alloy/providers/fillers/trait.TxFiller.html) for EIP-712 transaction type.
18///
19/// Can fill fields such as `gas_limit`, `max_fee_per_gas`, `max_priority_fee_per_gas`, and `gas_per_pubdata`.
20#[derive(Debug, Clone, Copy, Default)]
21#[non_exhaustive]
22pub struct Eip712FeeFiller {}
23
24impl TxFiller<Zksync> for Eip712FeeFiller {
25    type Fillable = Eip712Fee;
26
27    fn status(&self, tx: &TransactionRequest) -> FillerControlFlow {
28        if tx.gas_per_pubdata().unwrap_or_default() > U256::ZERO  // TODO: Should be `is_none()` once `gas_per_pubdata` in TransactionRequest is `Option`
29            && tx.gas_limit().is_some()
30            && tx.max_fee_per_gas().is_some()
31            && tx.max_priority_fee_per_gas().is_some()
32        {
33            return FillerControlFlow::Finished;
34        }
35        if tx.from().is_none() {
36            return FillerControlFlow::missing("Eip712FeeFiller", vec!["from"]);
37        }
38        FillerControlFlow::Ready
39    }
40
41    fn fill_sync(&self, _tx: &mut SendableTx<Zksync>) {}
42
43    async fn prepare<P>(
44        &self,
45        provider: &P,
46        tx: &TransactionRequest,
47    ) -> TransportResult<Self::Fillable>
48    where
49        P: Provider<Zksync>,
50    {
51        let fee = provider.estimate_fee(tx.clone()).await?;
52        Ok(fee)
53    }
54
55    async fn fill(
56        &self,
57        fee: Self::Fillable,
58        mut tx: SendableTx<Zksync>,
59    ) -> TransportResult<SendableTx<Zksync>> {
60        if let Some(builder) = tx.as_mut_builder() {
61            // Only set fields that are missing to prevent accidental overrides.
62            if builder.gas_limit().is_none() {
63                builder.set_gas_limit(fee.gas_limit);
64            }
65            if builder.max_fee_per_gas().is_none() {
66                builder.set_max_fee_per_gas(fee.max_fee_per_gas);
67            }
68            if builder.max_priority_fee_per_gas().is_none() {
69                builder.set_max_priority_fee_per_gas(fee.max_priority_fee_per_gas);
70            }
71            // TODO: Should be `is_none()` once `gas_per_pubdata` in TransactionRequest is `Option`
72            if builder.gas_per_pubdata().unwrap_or_default() == U256::ZERO {
73                builder.set_gas_per_pubdata(fee.gas_per_pubdata_limit);
74            }
75        }
76        Ok(tx)
77    }
78}