alloy_provider/fillers/
mod.rs

1//! Transaction fillers.
2//!
3//! Fillers decorate a [`Provider`], filling transaction details before they
4//! are sent to the network, like nonces, gas limits, and gas prices.
5//!
6//! Fillers are called before any other layer in the provider.
7//!
8//! # Implementing a filler
9//!
10//! Fillers implement the [`TxFiller`] trait. Before a filler is called, [`TxFiller::status`] is
11//! called to determine whether the filler has any work to do. If this function returns
12//! [`FillerControlFlow::Ready`], the filler will be called.
13//!
14//! # Composing fillers
15//!
16//! To layer fillers, a utility filler is provided called [`JoinFill`], which is a composition of
17//! two fillers, left and right. The left filler is called before the right filler.
18//!
19//! [`Provider`]: crate::Provider
20
21mod chain_id;
22use alloy_eips::{BlockId, BlockNumberOrTag};
23use alloy_primitives::{
24    Address, BlockHash, BlockNumber, StorageKey, StorageValue, TxHash, B256, U128, U256,
25};
26use alloy_rpc_client::NoParams;
27#[cfg(feature = "pubsub")]
28use alloy_rpc_types_eth::pubsub::{Params, SubscriptionKind};
29use alloy_rpc_types_eth::{Bundle, Index, SyncStatus};
30pub use chain_id::ChainIdFiller;
31use std::borrow::Cow;
32
33mod wallet;
34pub use wallet::WalletFiller;
35
36mod nonce;
37pub use nonce::{CachedNonceManager, NonceFiller, NonceManager, SimpleNonceManager};
38
39mod gas;
40pub use gas::{BlobGasFiller, GasFillable, GasFiller};
41
42mod join_fill;
43pub use join_fill::JoinFill;
44use tracing::error;
45
46#[cfg(feature = "pubsub")]
47use crate::GetSubscription;
48use crate::{
49    provider::SendableTx, EthCall, EthCallMany, EthGetBlock, FilterPollerBuilder, Identity,
50    PendingTransaction, PendingTransactionBuilder, PendingTransactionConfig,
51    PendingTransactionError, Provider, ProviderCall, ProviderLayer, RootProvider, RpcWithBlock,
52    SendableTxErr,
53};
54use alloy_json_rpc::RpcError;
55use alloy_network::{AnyNetwork, Ethereum, Network};
56use alloy_primitives::{Bytes, U64};
57use alloy_rpc_types_eth::{
58    erc4337::TransactionConditional,
59    simulate::{SimulatePayload, SimulatedBlock},
60    AccessListResult, EIP1186AccountProofResponse, EthCallResponse, FeeHistory, Filter,
61    FilterChanges, Log,
62};
63use alloy_transport::{TransportError, TransportResult};
64use async_trait::async_trait;
65use futures_utils_wasm::impl_future;
66use serde_json::value::RawValue;
67use std::marker::PhantomData;
68
69/// The recommended filler, a preconfigured set of layers handling gas estimation, nonce
70/// management, and chain-id fetching.
71pub type RecommendedFiller =
72    JoinFill<JoinFill<JoinFill<Identity, GasFiller>, NonceFiller>, ChainIdFiller>;
73
74/// Error type for failures in the `fill_envelope` function.
75#[derive(Debug, thiserror::Error)]
76pub enum FillEnvelopeError<T> {
77    /// A transport error occurred during the filling process.
78    #[error("transport error during filling: {0}")]
79    Transport(TransportError),
80
81    /// The transaction is not ready to be converted to an envelope.
82    #[error("transaction not ready: {0}")]
83    NotReady(SendableTxErr<T>),
84}
85
86/// The control flow for a filler.
87#[derive(Clone, Debug, PartialEq, Eq)]
88pub enum FillerControlFlow {
89    /// The filler is missing a required property.
90    ///
91    /// To allow joining fillers while preserving their associated missing
92    /// lists, this variant contains a list of `(name, missing)` tuples. When
93    /// absorbing another control flow, if both are missing, the missing lists
94    /// are combined.
95    Missing(Vec<(&'static str, Vec<&'static str>)>),
96    /// The filler is ready to fill in the transaction request.
97    Ready,
98    /// The filler has filled in all properties that it can fill.
99    Finished,
100}
101
102impl FillerControlFlow {
103    /// Absorb the control flow of another filler.
104    ///
105    /// # Behavior:
106    /// - If either is finished, return the unfinished one
107    /// - If either is ready, return ready.
108    /// - If both are missing, return missing.
109    pub fn absorb(self, other: Self) -> Self {
110        if other.is_finished() {
111            return self;
112        }
113
114        if self.is_finished() {
115            return other;
116        }
117
118        if other.is_ready() || self.is_ready() {
119            return Self::Ready;
120        }
121
122        if let (Self::Missing(mut a), Self::Missing(b)) = (self, other) {
123            a.extend(b);
124            return Self::Missing(a);
125        }
126
127        unreachable!()
128    }
129
130    /// Creates a new `Missing` control flow.
131    pub fn missing(name: &'static str, missing: Vec<&'static str>) -> Self {
132        Self::Missing(vec![(name, missing)])
133    }
134
135    /// Returns true if the filler is missing a required property.
136    pub fn as_missing(&self) -> Option<&[(&'static str, Vec<&'static str>)]> {
137        match self {
138            Self::Missing(missing) => Some(missing),
139            _ => None,
140        }
141    }
142
143    /// Returns `true` if the filler is missing information required to fill in
144    /// the transaction request.
145    pub const fn is_missing(&self) -> bool {
146        matches!(self, Self::Missing(_))
147    }
148
149    /// Returns `true` if the filler is ready to fill in the transaction
150    /// request.
151    pub const fn is_ready(&self) -> bool {
152        matches!(self, Self::Ready)
153    }
154
155    /// Returns `true` if the filler is finished filling in the transaction
156    /// request.
157    pub const fn is_finished(&self) -> bool {
158        matches!(self, Self::Finished)
159    }
160}
161
162/// A layer that can fill in a `TransactionRequest` with additional information.
163///
164/// ## Lifecycle Notes
165///
166/// The [`FillerControlFlow`] determines the lifecycle of a filler. Fillers
167/// may be in one of three states:
168/// - **Missing**: The filler is missing a required property to fill in the transaction request.
169///   [`TxFiller::status`] should return [`FillerControlFlow::Missing`]. with a list of the missing
170///   properties.
171/// - **Ready**: The filler is ready to fill in the transaction request. [`TxFiller::status`] should
172///   return [`FillerControlFlow::Ready`].
173/// - **Finished**: The filler has filled in all properties that it can fill. [`TxFiller::status`]
174///   should return [`FillerControlFlow::Finished`].
175#[doc(alias = "TransactionFiller")]
176pub trait TxFiller<N: Network = Ethereum>: Clone + Send + Sync + std::fmt::Debug {
177    /// The properties that this filler retrieves from the RPC. to fill in the
178    /// TransactionRequest.
179    type Fillable: Send + Sync + 'static;
180
181    /// Joins this filler with another filler to compose multiple fillers.
182    fn join_with<T>(self, other: T) -> JoinFill<Self, T>
183    where
184        T: TxFiller<N>,
185    {
186        JoinFill::new(self, other)
187    }
188
189    /// Return a control-flow enum indicating whether the filler is ready to
190    /// fill in the transaction request, or if it is missing required
191    /// properties.
192    fn status(&self, tx: &N::TransactionRequest) -> FillerControlFlow;
193
194    /// Returns `true` if the filler should continue filling.
195    fn continue_filling(&self, tx: &SendableTx<N>) -> bool {
196        tx.as_builder().is_some_and(|tx| self.status(tx).is_ready())
197    }
198
199    /// Returns `true` if the filler is ready to fill in the transaction request.
200    fn ready(&self, tx: &N::TransactionRequest) -> bool {
201        self.status(tx).is_ready()
202    }
203
204    /// Returns `true` if the filler is finished filling in the transaction request.
205    fn finished(&self, tx: &N::TransactionRequest) -> bool {
206        self.status(tx).is_finished()
207    }
208
209    /// Performs any synchronous filling. This should be called before
210    /// [`TxFiller::prepare`] and [`TxFiller::fill`] to fill in any properties
211    /// that can be filled synchronously.
212    fn fill_sync(&self, tx: &mut SendableTx<N>);
213
214    /// Prepares fillable properties, potentially by making an RPC request.
215    fn prepare<P: Provider<N>>(
216        &self,
217        provider: &P,
218        tx: &N::TransactionRequest,
219    ) -> impl_future!(<Output = TransportResult<Self::Fillable>>);
220
221    /// Fills in the transaction request with the fillable properties.
222    fn fill(
223        &self,
224        fillable: Self::Fillable,
225        tx: SendableTx<N>,
226    ) -> impl_future!(<Output = TransportResult<SendableTx<N>>>);
227
228    /// Fills in the transaction request and try to convert it to an envelope.
229    fn fill_envelope(
230        &self,
231        fillable: Self::Fillable,
232        tx: SendableTx<N>,
233    ) -> impl_future!(<Output = Result<N::TxEnvelope, FillEnvelopeError<N::TransactionRequest>>>)
234    {
235        async move {
236            let tx = self.fill(fillable, tx).await.map_err(FillEnvelopeError::Transport)?;
237            let envelope = tx.try_into_envelope().map_err(FillEnvelopeError::NotReady)?;
238            Ok(envelope)
239        }
240    }
241
242    /// Prepares and fills the transaction request with the fillable properties.
243    fn prepare_and_fill<P>(
244        &self,
245        provider: &P,
246        tx: SendableTx<N>,
247    ) -> impl_future!(<Output = TransportResult<SendableTx<N>>>)
248    where
249        P: Provider<N>,
250    {
251        async move {
252            if tx.is_envelope() {
253                return Ok(tx);
254            }
255
256            let fillable =
257                self.prepare(provider, tx.as_builder().expect("checked by is_envelope")).await?;
258
259            self.fill(fillable, tx).await
260        }
261    }
262
263    /// Prepares transaction request with necessary fillers required for eth_call operations
264    /// asynchronously
265    fn prepare_call(
266        &self,
267        tx: &mut N::TransactionRequest,
268    ) -> impl_future!(<Output = TransportResult<()>>) {
269        let _ = tx;
270        // This is a no-op by default
271        futures::future::ready(Ok(()))
272    }
273
274    /// Prepares transaction request with necessary fillers required for eth_call operations
275    /// synchronously
276    fn prepare_call_sync(&self, tx: &mut N::TransactionRequest) -> TransportResult<()> {
277        let _ = tx;
278        // No-op default
279        Ok(())
280    }
281}
282
283/// A [`Provider`] that applies one or more [`TxFiller`]s.
284///
285/// Fills arbitrary properties in a transaction request by composing multiple
286/// fill layers. This struct should always be the outermost layer in a provider
287/// stack, and this is enforced when using [`ProviderBuilder::filler`] to
288/// construct this layer.
289///
290/// Users should NOT use this struct directly. Instead, use
291/// [`ProviderBuilder::filler`] to construct and apply it to a stack.
292///
293/// [`ProviderBuilder::filler`]: crate::ProviderBuilder::filler
294#[derive(Clone, Debug)]
295pub struct FillProvider<F, P, N = Ethereum>
296where
297    F: TxFiller<N>,
298    P: Provider<N>,
299    N: Network,
300{
301    pub(crate) inner: P,
302    pub(crate) filler: F,
303    _pd: PhantomData<fn() -> N>,
304}
305
306impl<F, P, N> FillProvider<F, P, N>
307where
308    F: TxFiller<N>,
309    P: Provider<N>,
310    N: Network,
311{
312    /// Creates a new `FillProvider` with the given filler and inner provider.
313    pub fn new(inner: P, filler: F) -> Self {
314        Self { inner, filler, _pd: PhantomData }
315    }
316
317    /// Joins a filler to this provider
318    pub fn join_with<Other: TxFiller<N>>(
319        self,
320        other: Other,
321    ) -> FillProvider<JoinFill<F, Other>, P, N> {
322        self.filler.join_with(other).layer(self.inner)
323    }
324
325    async fn fill_inner(&self, mut tx: SendableTx<N>) -> TransportResult<SendableTx<N>> {
326        let mut count = 0;
327
328        while self.filler.continue_filling(&tx) {
329            self.filler.fill_sync(&mut tx);
330            tx = self.filler.prepare_and_fill(&self.inner, tx).await?;
331
332            count += 1;
333            if count >= 20 {
334                const ERROR: &str = "Tx filler loop detected. This indicates a bug in some filler implementation. Please file an issue containing this message.";
335                error!(
336                    ?tx, ?self.filler,
337                    ERROR
338                );
339                panic!("{}, {:?}, {:?}", ERROR, &tx, &self.filler);
340            }
341        }
342        Ok(tx)
343    }
344
345    /// Fills the transaction request, using the configured fillers
346    ///
347    /// # Example
348    ///
349    /// ```rust
350    /// # use alloy_consensus::{TypedTransaction, SignableTransaction};
351    /// # use alloy_primitives::{address, U256};
352    /// # use alloy_provider::ProviderBuilder;
353    /// # use alloy_rpc_types_eth::TransactionRequest;
354    /// # use alloy_network::TransactionBuilder;
355    ///
356    /// async fn example() -> Result<(), Box<dyn std::error::Error>> {
357    ///     // Create transaction request
358    ///     let tx_request = TransactionRequest::default()
359    ///         .with_from(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"))
360    ///         .with_value(U256::from(1000));
361    ///
362    ///     let provider = ProviderBuilder::new().connect_anvil_with_wallet();
363    ///
364    ///     // Fill transaction with provider data
365    ///     let filled_tx = provider.fill(tx_request).await?;
366    ///
367    ///     // Build unsigned transaction
368    ///     let typed_tx =
369    ///         filled_tx.as_builder().expect("filled tx is a builder").clone().build_unsigned()?;
370    ///
371    ///     // Encode, e.g. for offline signing
372    ///     let mut encoded = Vec::new();
373    ///     typed_tx.encode_for_signing(&mut encoded);
374    ///
375    ///     // Decode unsigned transaction
376    ///     let decoded = TypedTransaction::decode_unsigned(&mut encoded.as_slice())?;
377    ///
378    ///     Ok(())
379    /// }
380    /// ```
381    pub async fn fill(&self, tx: N::TransactionRequest) -> TransportResult<SendableTx<N>> {
382        self.fill_inner(SendableTx::Builder(tx)).await
383    }
384
385    /// Prepares a transaction request for eth_call operations using the configured fillers
386    pub fn prepare_call(
387        &self,
388        mut tx: N::TransactionRequest,
389    ) -> TransportResult<N::TransactionRequest> {
390        self.filler.prepare_call_sync(&mut tx)?;
391        Ok(tx)
392    }
393}
394
395#[cfg_attr(target_family = "wasm", async_trait(?Send))]
396#[cfg_attr(not(target_family = "wasm"), async_trait)]
397impl<F, P, N> Provider<N> for FillProvider<F, P, N>
398where
399    F: TxFiller<N>,
400    P: Provider<N>,
401    N: Network,
402{
403    fn root(&self) -> &RootProvider<N> {
404        self.inner.root()
405    }
406
407    fn get_accounts(&self) -> ProviderCall<NoParams, Vec<Address>> {
408        self.inner.get_accounts()
409    }
410
411    fn get_blob_base_fee(&self) -> ProviderCall<NoParams, U128, u128> {
412        self.inner.get_blob_base_fee()
413    }
414
415    fn get_block_number(&self) -> ProviderCall<NoParams, U64, BlockNumber> {
416        self.inner.get_block_number()
417    }
418
419    fn call<'req>(&self, tx: N::TransactionRequest) -> EthCall<N, Bytes> {
420        let mut tx = tx;
421        let _ = self.filler.prepare_call_sync(&mut tx);
422        self.inner.call(tx)
423    }
424
425    fn call_many<'req>(
426        &self,
427        bundles: &'req [Bundle],
428    ) -> EthCallMany<'req, N, Vec<Vec<EthCallResponse>>> {
429        self.inner.call_many(bundles)
430    }
431
432    fn simulate<'req>(
433        &self,
434        payload: &'req SimulatePayload,
435    ) -> RpcWithBlock<&'req SimulatePayload, Vec<SimulatedBlock<N::BlockResponse>>> {
436        self.inner.simulate(payload)
437    }
438
439    fn get_chain_id(&self) -> ProviderCall<NoParams, U64, u64> {
440        self.inner.get_chain_id()
441    }
442
443    fn create_access_list<'a>(
444        &self,
445        request: &'a N::TransactionRequest,
446    ) -> RpcWithBlock<&'a N::TransactionRequest, AccessListResult> {
447        self.inner.create_access_list(request)
448    }
449
450    fn estimate_gas<'req>(&self, tx: N::TransactionRequest) -> EthCall<N, U64, u64> {
451        let mut tx = tx;
452        let _ = self.filler.prepare_call_sync(&mut tx);
453        self.inner.estimate_gas(tx)
454    }
455
456    async fn get_fee_history(
457        &self,
458        block_count: u64,
459        last_block: BlockNumberOrTag,
460        reward_percentiles: &[f64],
461    ) -> TransportResult<FeeHistory> {
462        self.inner.get_fee_history(block_count, last_block, reward_percentiles).await
463    }
464
465    fn get_gas_price(&self) -> ProviderCall<NoParams, U128, u128> {
466        self.inner.get_gas_price()
467    }
468
469    fn get_account_info(
470        &self,
471        address: Address,
472    ) -> RpcWithBlock<Address, alloy_rpc_types_eth::AccountInfo> {
473        self.inner.get_account_info(address)
474    }
475
476    fn get_account(&self, address: Address) -> RpcWithBlock<Address, alloy_consensus::TrieAccount> {
477        self.inner.get_account(address)
478    }
479
480    fn get_balance(&self, address: Address) -> RpcWithBlock<Address, U256, U256> {
481        self.inner.get_balance(address)
482    }
483
484    fn get_block(&self, block: BlockId) -> EthGetBlock<N::BlockResponse> {
485        self.inner.get_block(block)
486    }
487
488    fn get_block_by_hash(&self, hash: BlockHash) -> EthGetBlock<N::BlockResponse> {
489        self.inner.get_block_by_hash(hash)
490    }
491
492    fn get_block_by_number(&self, number: BlockNumberOrTag) -> EthGetBlock<N::BlockResponse> {
493        self.inner.get_block_by_number(number)
494    }
495
496    async fn get_block_transaction_count_by_hash(
497        &self,
498        hash: BlockHash,
499    ) -> TransportResult<Option<u64>> {
500        self.inner.get_block_transaction_count_by_hash(hash).await
501    }
502
503    async fn get_block_transaction_count_by_number(
504        &self,
505        block_number: BlockNumberOrTag,
506    ) -> TransportResult<Option<u64>> {
507        self.inner.get_block_transaction_count_by_number(block_number).await
508    }
509
510    fn get_block_receipts(
511        &self,
512        block: BlockId,
513    ) -> ProviderCall<(BlockId,), Option<Vec<N::ReceiptResponse>>> {
514        self.inner.get_block_receipts(block)
515    }
516
517    fn get_code_at(&self, address: Address) -> RpcWithBlock<Address, Bytes> {
518        self.inner.get_code_at(address)
519    }
520
521    async fn watch_blocks(&self) -> TransportResult<FilterPollerBuilder<B256>> {
522        self.inner.watch_blocks().await
523    }
524
525    async fn watch_pending_transactions(&self) -> TransportResult<FilterPollerBuilder<B256>> {
526        self.inner.watch_pending_transactions().await
527    }
528
529    async fn watch_logs(&self, filter: &Filter) -> TransportResult<FilterPollerBuilder<Log>> {
530        self.inner.watch_logs(filter).await
531    }
532
533    async fn watch_full_pending_transactions(
534        &self,
535    ) -> TransportResult<FilterPollerBuilder<N::TransactionResponse>> {
536        self.inner.watch_full_pending_transactions().await
537    }
538
539    async fn get_filter_changes_dyn(&self, id: U256) -> TransportResult<FilterChanges> {
540        self.inner.get_filter_changes_dyn(id).await
541    }
542
543    async fn get_filter_logs(&self, id: U256) -> TransportResult<Vec<Log>> {
544        self.inner.get_filter_logs(id).await
545    }
546
547    async fn uninstall_filter(&self, id: U256) -> TransportResult<bool> {
548        self.inner.uninstall_filter(id).await
549    }
550
551    async fn watch_pending_transaction(
552        &self,
553        config: PendingTransactionConfig,
554    ) -> Result<PendingTransaction, PendingTransactionError> {
555        self.inner.watch_pending_transaction(config).await
556    }
557
558    async fn get_logs(&self, filter: &Filter) -> TransportResult<Vec<Log>> {
559        self.inner.get_logs(filter).await
560    }
561
562    fn get_proof(
563        &self,
564        address: Address,
565        keys: Vec<StorageKey>,
566    ) -> RpcWithBlock<(Address, Vec<StorageKey>), EIP1186AccountProofResponse> {
567        self.inner.get_proof(address, keys)
568    }
569
570    fn get_storage_at(
571        &self,
572        address: Address,
573        key: U256,
574    ) -> RpcWithBlock<(Address, U256), StorageValue> {
575        self.inner.get_storage_at(address, key)
576    }
577
578    fn get_transaction_by_hash(
579        &self,
580        hash: TxHash,
581    ) -> ProviderCall<(TxHash,), Option<N::TransactionResponse>> {
582        self.inner.get_transaction_by_hash(hash)
583    }
584
585    fn get_transaction_by_sender_nonce(
586        &self,
587        sender: Address,
588        nonce: u64,
589    ) -> ProviderCall<(Address, U64), Option<N::TransactionResponse>> {
590        self.inner.get_transaction_by_sender_nonce(sender, nonce)
591    }
592
593    fn get_transaction_by_block_hash_and_index(
594        &self,
595        block_hash: B256,
596        index: usize,
597    ) -> ProviderCall<(B256, Index), Option<N::TransactionResponse>> {
598        self.inner.get_transaction_by_block_hash_and_index(block_hash, index)
599    }
600
601    fn get_raw_transaction_by_block_hash_and_index(
602        &self,
603        block_hash: B256,
604        index: usize,
605    ) -> ProviderCall<(B256, Index), Option<Bytes>> {
606        self.inner.get_raw_transaction_by_block_hash_and_index(block_hash, index)
607    }
608
609    fn get_transaction_by_block_number_and_index(
610        &self,
611        block_number: BlockNumberOrTag,
612        index: usize,
613    ) -> ProviderCall<(BlockNumberOrTag, Index), Option<N::TransactionResponse>> {
614        self.inner.get_transaction_by_block_number_and_index(block_number, index)
615    }
616
617    fn get_raw_transaction_by_block_number_and_index(
618        &self,
619        block_number: BlockNumberOrTag,
620        index: usize,
621    ) -> ProviderCall<(BlockNumberOrTag, Index), Option<Bytes>> {
622        self.inner.get_raw_transaction_by_block_number_and_index(block_number, index)
623    }
624
625    fn get_raw_transaction_by_hash(&self, hash: TxHash) -> ProviderCall<(TxHash,), Option<Bytes>> {
626        self.inner.get_raw_transaction_by_hash(hash)
627    }
628
629    fn get_transaction_count(
630        &self,
631        address: Address,
632    ) -> RpcWithBlock<Address, U64, u64, fn(U64) -> u64> {
633        self.inner.get_transaction_count(address)
634    }
635
636    fn get_transaction_receipt(
637        &self,
638        hash: TxHash,
639    ) -> ProviderCall<(TxHash,), Option<N::ReceiptResponse>> {
640        self.inner.get_transaction_receipt(hash)
641    }
642
643    async fn get_uncle(&self, tag: BlockId, idx: u64) -> TransportResult<Option<N::BlockResponse>> {
644        self.inner.get_uncle(tag, idx).await
645    }
646
647    async fn get_uncle_count(&self, tag: BlockId) -> TransportResult<u64> {
648        self.inner.get_uncle_count(tag).await
649    }
650
651    fn get_max_priority_fee_per_gas(&self) -> ProviderCall<NoParams, U128, u128> {
652        self.inner.get_max_priority_fee_per_gas()
653    }
654
655    async fn new_block_filter(&self) -> TransportResult<U256> {
656        self.inner.new_block_filter().await
657    }
658
659    async fn new_filter(&self, filter: &Filter) -> TransportResult<U256> {
660        self.inner.new_filter(filter).await
661    }
662
663    async fn new_pending_transactions_filter(&self, full: bool) -> TransportResult<U256> {
664        self.inner.new_pending_transactions_filter(full).await
665    }
666
667    async fn send_raw_transaction(
668        &self,
669        encoded_tx: &[u8],
670    ) -> TransportResult<PendingTransactionBuilder<N>> {
671        self.inner.send_raw_transaction(encoded_tx).await
672    }
673
674    async fn send_raw_transaction_conditional(
675        &self,
676        encoded_tx: &[u8],
677        conditional: TransactionConditional,
678    ) -> TransportResult<PendingTransactionBuilder<N>> {
679        self.inner.send_raw_transaction_conditional(encoded_tx, conditional).await
680    }
681
682    async fn send_transaction_internal(
683        &self,
684        mut tx: SendableTx<N>,
685    ) -> TransportResult<PendingTransactionBuilder<N>> {
686        tx = self.fill_inner(tx).await?;
687
688        if let Some(builder) = tx.as_builder() {
689            if let FillerControlFlow::Missing(missing) = self.filler.status(builder) {
690                // TODO: improve this.
691                // blocked by #431
692                let message = format!("missing properties: {missing:?}");
693                return Err(RpcError::local_usage_str(&message));
694            }
695        }
696
697        // Errors in tx building happen further down the stack.
698        self.inner.send_transaction_internal(tx).await
699    }
700
701    async fn send_transaction_sync_internal(
702        &self,
703        mut tx: SendableTx<N>,
704    ) -> TransportResult<N::ReceiptResponse> {
705        tx = self.fill_inner(tx).await?;
706
707        if let Some(builder) = tx.as_builder() {
708            if let FillerControlFlow::Missing(missing) = self.filler.status(builder) {
709                let message = format!("missing properties: {missing:?}");
710                return Err(RpcError::local_usage_str(&message));
711            }
712        }
713
714        // Errors in tx building happen further down the stack.
715        self.inner.send_transaction_sync_internal(tx).await
716    }
717
718    async fn sign_transaction(&self, tx: N::TransactionRequest) -> TransportResult<Bytes> {
719        let tx = self.fill(tx).await?;
720        let tx = tx.try_into_request().map_err(TransportError::local_usage)?;
721        self.inner.sign_transaction(tx).await
722    }
723
724    #[cfg(feature = "pubsub")]
725    fn subscribe_blocks(&self) -> GetSubscription<(SubscriptionKind,), N::HeaderResponse> {
726        self.inner.subscribe_blocks()
727    }
728
729    #[cfg(feature = "pubsub")]
730    fn subscribe_pending_transactions(&self) -> GetSubscription<(SubscriptionKind,), B256> {
731        self.inner.subscribe_pending_transactions()
732    }
733
734    #[cfg(feature = "pubsub")]
735    fn subscribe_full_pending_transactions(
736        &self,
737    ) -> GetSubscription<(SubscriptionKind, Params), N::TransactionResponse> {
738        self.inner.subscribe_full_pending_transactions()
739    }
740
741    #[cfg(feature = "pubsub")]
742    fn subscribe_logs(&self, filter: &Filter) -> GetSubscription<(SubscriptionKind, Params), Log> {
743        self.inner.subscribe_logs(filter)
744    }
745
746    #[cfg(feature = "pubsub")]
747    async fn unsubscribe(&self, id: B256) -> TransportResult<()> {
748        self.inner.unsubscribe(id).await
749    }
750
751    fn syncing(&self) -> ProviderCall<NoParams, SyncStatus> {
752        self.inner.syncing()
753    }
754
755    fn get_client_version(&self) -> ProviderCall<NoParams, String> {
756        self.inner.get_client_version()
757    }
758
759    fn get_sha3(&self, data: &[u8]) -> ProviderCall<(String,), B256> {
760        self.inner.get_sha3(data)
761    }
762
763    fn get_net_version(&self) -> ProviderCall<NoParams, U64, u64> {
764        self.inner.get_net_version()
765    }
766
767    async fn raw_request_dyn(
768        &self,
769        method: Cow<'static, str>,
770        params: &RawValue,
771    ) -> TransportResult<Box<RawValue>> {
772        self.inner.raw_request_dyn(method, params).await
773    }
774
775    fn transaction_request(&self) -> N::TransactionRequest {
776        self.inner.transaction_request()
777    }
778}
779
780/// A trait which may be used to configure default fillers for [Network] implementations.
781pub trait RecommendedFillers: Network {
782    /// Recommended fillers for this network.
783    type RecommendedFillers: TxFiller<Self>;
784
785    /// Returns the recommended filler for this provider.
786    fn recommended_fillers() -> Self::RecommendedFillers;
787}
788
789impl RecommendedFillers for Ethereum {
790    type RecommendedFillers =
791        JoinFill<GasFiller, JoinFill<BlobGasFiller, JoinFill<NonceFiller, ChainIdFiller>>>;
792
793    fn recommended_fillers() -> Self::RecommendedFillers {
794        Default::default()
795    }
796}
797
798impl RecommendedFillers for AnyNetwork {
799    type RecommendedFillers =
800        JoinFill<GasFiller, JoinFill<BlobGasFiller, JoinFill<NonceFiller, ChainIdFiller>>>;
801
802    fn recommended_fillers() -> Self::RecommendedFillers {
803        Default::default()
804    }
805}