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