1mod 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::{
41 BlobGasEstimator, BlobGasEstimatorFn, BlobGasEstimatorFunction, BlobGasFiller, GasFillable,
42 GasFiller,
43};
44
45mod join_fill;
46pub use join_fill::JoinFill;
47use tracing::error;
48
49#[cfg(feature = "pubsub")]
50use crate::GetSubscription;
51use crate::{
52 provider::SendableTx, EthCall, EthCallMany, EthGetBlock, FilterPollerBuilder, Identity,
53 PendingTransaction, PendingTransactionBuilder, PendingTransactionConfig,
54 PendingTransactionError, Provider, ProviderCall, ProviderLayer, RootProvider, RpcWithBlock,
55 SendableTxErr,
56};
57use alloy_json_rpc::RpcError;
58use alloy_network::{AnyNetwork, Ethereum, Network};
59use alloy_primitives::{Bytes, U64};
60use alloy_rpc_types_eth::{
61 erc4337::TransactionConditional,
62 simulate::{SimulatePayload, SimulatedBlock},
63 AccessListResult, EIP1186AccountProofResponse, EthCallResponse, FeeHistory, Filter,
64 FilterChanges, Log,
65};
66use alloy_transport::{TransportError, TransportResult};
67use async_trait::async_trait;
68use futures_utils_wasm::impl_future;
69use serde_json::value::RawValue;
70use std::marker::PhantomData;
71
72pub type RecommendedFiller =
75 JoinFill<JoinFill<JoinFill<Identity, GasFiller>, NonceFiller>, ChainIdFiller>;
76
77#[derive(Debug, thiserror::Error)]
79pub enum FillEnvelopeError<T> {
80 #[error("transport error during filling: {0}")]
82 Transport(TransportError),
83
84 #[error("transaction not ready: {0}")]
86 NotReady(SendableTxErr<T>),
87}
88
89#[derive(Clone, Debug, PartialEq, Eq)]
91pub enum FillerControlFlow {
92 Missing(Vec<(&'static str, Vec<&'static str>)>),
99 Ready,
101 Finished,
103}
104
105impl FillerControlFlow {
106 pub fn absorb(self, other: Self) -> Self {
113 if other.is_finished() {
114 return self;
115 }
116
117 if self.is_finished() {
118 return other;
119 }
120
121 if other.is_ready() || self.is_ready() {
122 return Self::Ready;
123 }
124
125 if let (Self::Missing(mut a), Self::Missing(b)) = (self, other) {
126 a.extend(b);
127 return Self::Missing(a);
128 }
129
130 unreachable!()
131 }
132
133 pub fn missing(name: &'static str, missing: Vec<&'static str>) -> Self {
135 Self::Missing(vec![(name, missing)])
136 }
137
138 pub fn as_missing(&self) -> Option<&[(&'static str, Vec<&'static str>)]> {
140 match self {
141 Self::Missing(missing) => Some(missing),
142 _ => None,
143 }
144 }
145
146 pub const fn is_missing(&self) -> bool {
149 matches!(self, Self::Missing(_))
150 }
151
152 pub const fn is_ready(&self) -> bool {
155 matches!(self, Self::Ready)
156 }
157
158 pub const fn is_finished(&self) -> bool {
161 matches!(self, Self::Finished)
162 }
163}
164
165#[doc(alias = "TransactionFiller")]
179pub trait TxFiller<N: Network = Ethereum>: Clone + Send + Sync + std::fmt::Debug {
180 type Fillable: Send + Sync + 'static;
183
184 fn join_with<T>(self, other: T) -> JoinFill<Self, T>
186 where
187 T: TxFiller<N>,
188 {
189 JoinFill::new(self, other)
190 }
191
192 fn status(&self, tx: &N::TransactionRequest) -> FillerControlFlow;
196
197 fn continue_filling(&self, tx: &SendableTx<N>) -> bool {
199 tx.as_builder().is_some_and(|tx| self.status(tx).is_ready())
200 }
201
202 fn ready(&self, tx: &N::TransactionRequest) -> bool {
204 self.status(tx).is_ready()
205 }
206
207 fn finished(&self, tx: &N::TransactionRequest) -> bool {
209 self.status(tx).is_finished()
210 }
211
212 fn fill_sync(&self, tx: &mut SendableTx<N>);
216
217 fn prepare<P: Provider<N>>(
219 &self,
220 provider: &P,
221 tx: &N::TransactionRequest,
222 ) -> impl_future!(<Output = TransportResult<Self::Fillable>>);
223
224 fn fill(
226 &self,
227 fillable: Self::Fillable,
228 tx: SendableTx<N>,
229 ) -> impl_future!(<Output = TransportResult<SendableTx<N>>>);
230
231 fn fill_envelope(
233 &self,
234 fillable: Self::Fillable,
235 tx: SendableTx<N>,
236 ) -> impl_future!(<Output = Result<N::TxEnvelope, FillEnvelopeError<N::TransactionRequest>>>)
237 {
238 async move {
239 let tx = self.fill(fillable, tx).await.map_err(FillEnvelopeError::Transport)?;
240 let envelope = tx.try_into_envelope().map_err(FillEnvelopeError::NotReady)?;
241 Ok(envelope)
242 }
243 }
244
245 fn prepare_and_fill<P>(
247 &self,
248 provider: &P,
249 tx: SendableTx<N>,
250 ) -> impl_future!(<Output = TransportResult<SendableTx<N>>>)
251 where
252 P: Provider<N>,
253 {
254 async move {
255 if tx.is_envelope() {
256 return Ok(tx);
257 }
258
259 let fillable =
260 self.prepare(provider, tx.as_builder().expect("checked by is_envelope")).await?;
261
262 self.fill(fillable, tx).await
263 }
264 }
265
266 fn prepare_call(
269 &self,
270 tx: &mut N::TransactionRequest,
271 ) -> impl_future!(<Output = TransportResult<()>>) {
272 let _ = tx;
273 futures::future::ready(Ok(()))
275 }
276
277 fn prepare_call_sync(&self, tx: &mut N::TransactionRequest) -> TransportResult<()> {
280 let _ = tx;
281 Ok(())
283 }
284}
285
286#[derive(Clone, Debug)]
298pub struct FillProvider<F, P, N = Ethereum>
299where
300 F: TxFiller<N>,
301 P: Provider<N>,
302 N: Network,
303{
304 pub(crate) inner: P,
305 pub(crate) filler: F,
306 _pd: PhantomData<fn() -> N>,
307}
308
309impl<F, P, N> FillProvider<F, P, N>
310where
311 F: TxFiller<N>,
312 P: Provider<N>,
313 N: Network,
314{
315 pub fn new(inner: P, filler: F) -> Self {
317 Self { inner, filler, _pd: PhantomData }
318 }
319
320 pub const fn filler(&self) -> &F {
322 &self.filler
323 }
324
325 pub const fn filler_mut(&mut self) -> &mut F {
327 &mut self.filler
328 }
329
330 pub fn join_with<Other: TxFiller<N>>(
332 self,
333 other: Other,
334 ) -> FillProvider<JoinFill<F, Other>, P, N> {
335 self.filler.join_with(other).layer(self.inner)
336 }
337
338 async fn fill_inner(&self, mut tx: SendableTx<N>) -> TransportResult<SendableTx<N>> {
339 let mut count = 0;
340
341 while self.filler.continue_filling(&tx) {
342 self.filler.fill_sync(&mut tx);
343 tx = self.filler.prepare_and_fill(&self.inner, tx).await?;
344
345 count += 1;
346 if count >= 20 {
347 const ERROR: &str = "Tx filler loop detected. This indicates a bug in some filler implementation. Please file an issue containing this message.";
348 error!(
349 ?tx, ?self.filler,
350 ERROR
351 );
352 panic!("{}, {:?}, {:?}", ERROR, &tx, &self.filler);
353 }
354 }
355 Ok(tx)
356 }
357
358 pub async fn fill(&self, tx: N::TransactionRequest) -> TransportResult<SendableTx<N>> {
395 self.fill_inner(SendableTx::Builder(tx)).await
396 }
397
398 pub fn prepare_call(
400 &self,
401 mut tx: N::TransactionRequest,
402 ) -> TransportResult<N::TransactionRequest> {
403 self.filler.prepare_call_sync(&mut tx)?;
404 Ok(tx)
405 }
406}
407
408#[cfg_attr(target_family = "wasm", async_trait(?Send))]
409#[cfg_attr(not(target_family = "wasm"), async_trait)]
410impl<F, P, N> Provider<N> for FillProvider<F, P, N>
411where
412 F: TxFiller<N>,
413 P: Provider<N>,
414 N: Network,
415{
416 fn root(&self) -> &RootProvider<N> {
417 self.inner.root()
418 }
419
420 fn get_accounts(&self) -> ProviderCall<NoParams, Vec<Address>> {
421 self.inner.get_accounts()
422 }
423
424 fn get_blob_base_fee(&self) -> ProviderCall<NoParams, U128, u128> {
425 self.inner.get_blob_base_fee()
426 }
427
428 fn get_block_number(&self) -> ProviderCall<NoParams, U64, BlockNumber> {
429 self.inner.get_block_number()
430 }
431
432 fn call<'req>(&self, tx: N::TransactionRequest) -> EthCall<N, Bytes> {
433 let mut tx = tx;
434 let _ = self.filler.prepare_call_sync(&mut tx);
435 self.inner.call(tx)
436 }
437
438 fn call_many<'req>(
439 &self,
440 bundles: &'req [Bundle],
441 ) -> EthCallMany<'req, N, Vec<Vec<EthCallResponse>>> {
442 self.inner.call_many(bundles)
443 }
444
445 fn simulate<'req>(
446 &self,
447 payload: &'req SimulatePayload,
448 ) -> RpcWithBlock<&'req SimulatePayload, Vec<SimulatedBlock<N::BlockResponse>>> {
449 self.inner.simulate(payload)
450 }
451
452 fn get_chain_id(&self) -> ProviderCall<NoParams, U64, u64> {
453 self.inner.get_chain_id()
454 }
455
456 fn create_access_list<'a>(
457 &self,
458 request: &'a N::TransactionRequest,
459 ) -> RpcWithBlock<&'a N::TransactionRequest, AccessListResult> {
460 self.inner.create_access_list(request)
461 }
462
463 fn estimate_gas<'req>(&self, tx: N::TransactionRequest) -> EthCall<N, U64, u64> {
464 let mut tx = tx;
465 let _ = self.filler.prepare_call_sync(&mut tx);
466 self.inner.estimate_gas(tx)
467 }
468
469 async fn get_fee_history(
470 &self,
471 block_count: u64,
472 last_block: BlockNumberOrTag,
473 reward_percentiles: &[f64],
474 ) -> TransportResult<FeeHistory> {
475 self.inner.get_fee_history(block_count, last_block, reward_percentiles).await
476 }
477
478 fn get_gas_price(&self) -> ProviderCall<NoParams, U128, u128> {
479 self.inner.get_gas_price()
480 }
481
482 fn get_account_info(
483 &self,
484 address: Address,
485 ) -> RpcWithBlock<Address, alloy_rpc_types_eth::AccountInfo> {
486 self.inner.get_account_info(address)
487 }
488
489 fn get_account(&self, address: Address) -> RpcWithBlock<Address, alloy_consensus::TrieAccount> {
490 self.inner.get_account(address)
491 }
492
493 fn get_balance(&self, address: Address) -> RpcWithBlock<Address, U256, U256> {
494 self.inner.get_balance(address)
495 }
496
497 fn get_block(&self, block: BlockId) -> EthGetBlock<N::BlockResponse> {
498 self.inner.get_block(block)
499 }
500
501 fn get_block_by_hash(&self, hash: BlockHash) -> EthGetBlock<N::BlockResponse> {
502 self.inner.get_block_by_hash(hash)
503 }
504
505 fn get_block_by_number(&self, number: BlockNumberOrTag) -> EthGetBlock<N::BlockResponse> {
506 self.inner.get_block_by_number(number)
507 }
508
509 async fn get_block_transaction_count_by_hash(
510 &self,
511 hash: BlockHash,
512 ) -> TransportResult<Option<u64>> {
513 self.inner.get_block_transaction_count_by_hash(hash).await
514 }
515
516 async fn get_block_transaction_count_by_number(
517 &self,
518 block_number: BlockNumberOrTag,
519 ) -> TransportResult<Option<u64>> {
520 self.inner.get_block_transaction_count_by_number(block_number).await
521 }
522
523 fn get_block_receipts(
524 &self,
525 block: BlockId,
526 ) -> ProviderCall<(BlockId,), Option<Vec<N::ReceiptResponse>>> {
527 self.inner.get_block_receipts(block)
528 }
529
530 fn get_code_at(&self, address: Address) -> RpcWithBlock<Address, Bytes> {
531 self.inner.get_code_at(address)
532 }
533
534 async fn watch_blocks(&self) -> TransportResult<FilterPollerBuilder<B256>> {
535 self.inner.watch_blocks().await
536 }
537
538 async fn watch_pending_transactions(&self) -> TransportResult<FilterPollerBuilder<B256>> {
539 self.inner.watch_pending_transactions().await
540 }
541
542 async fn watch_logs(&self, filter: &Filter) -> TransportResult<FilterPollerBuilder<Log>> {
543 self.inner.watch_logs(filter).await
544 }
545
546 async fn watch_full_pending_transactions(
547 &self,
548 ) -> TransportResult<FilterPollerBuilder<N::TransactionResponse>> {
549 self.inner.watch_full_pending_transactions().await
550 }
551
552 async fn get_filter_changes_dyn(&self, id: U256) -> TransportResult<FilterChanges> {
553 self.inner.get_filter_changes_dyn(id).await
554 }
555
556 async fn get_filter_logs(&self, id: U256) -> TransportResult<Vec<Log>> {
557 self.inner.get_filter_logs(id).await
558 }
559
560 async fn uninstall_filter(&self, id: U256) -> TransportResult<bool> {
561 self.inner.uninstall_filter(id).await
562 }
563
564 async fn watch_pending_transaction(
565 &self,
566 config: PendingTransactionConfig,
567 ) -> Result<PendingTransaction, PendingTransactionError> {
568 self.inner.watch_pending_transaction(config).await
569 }
570
571 async fn get_logs(&self, filter: &Filter) -> TransportResult<Vec<Log>> {
572 self.inner.get_logs(filter).await
573 }
574
575 fn get_proof(
576 &self,
577 address: Address,
578 keys: Vec<StorageKey>,
579 ) -> RpcWithBlock<(Address, Vec<StorageKey>), EIP1186AccountProofResponse> {
580 self.inner.get_proof(address, keys)
581 }
582
583 fn get_storage_at(
584 &self,
585 address: Address,
586 key: U256,
587 ) -> RpcWithBlock<(Address, U256), StorageValue> {
588 self.inner.get_storage_at(address, key)
589 }
590
591 fn get_transaction_by_hash(
592 &self,
593 hash: TxHash,
594 ) -> ProviderCall<(TxHash,), Option<N::TransactionResponse>> {
595 self.inner.get_transaction_by_hash(hash)
596 }
597
598 fn get_transaction_by_sender_nonce(
599 &self,
600 sender: Address,
601 nonce: u64,
602 ) -> ProviderCall<(Address, U64), Option<N::TransactionResponse>> {
603 self.inner.get_transaction_by_sender_nonce(sender, nonce)
604 }
605
606 fn get_transaction_by_block_hash_and_index(
607 &self,
608 block_hash: B256,
609 index: usize,
610 ) -> ProviderCall<(B256, Index), Option<N::TransactionResponse>> {
611 self.inner.get_transaction_by_block_hash_and_index(block_hash, index)
612 }
613
614 fn get_raw_transaction_by_block_hash_and_index(
615 &self,
616 block_hash: B256,
617 index: usize,
618 ) -> ProviderCall<(B256, Index), Option<Bytes>> {
619 self.inner.get_raw_transaction_by_block_hash_and_index(block_hash, index)
620 }
621
622 fn get_transaction_by_block_number_and_index(
623 &self,
624 block_number: BlockNumberOrTag,
625 index: usize,
626 ) -> ProviderCall<(BlockNumberOrTag, Index), Option<N::TransactionResponse>> {
627 self.inner.get_transaction_by_block_number_and_index(block_number, index)
628 }
629
630 fn get_raw_transaction_by_block_number_and_index(
631 &self,
632 block_number: BlockNumberOrTag,
633 index: usize,
634 ) -> ProviderCall<(BlockNumberOrTag, Index), Option<Bytes>> {
635 self.inner.get_raw_transaction_by_block_number_and_index(block_number, index)
636 }
637
638 fn get_raw_transaction_by_hash(&self, hash: TxHash) -> ProviderCall<(TxHash,), Option<Bytes>> {
639 self.inner.get_raw_transaction_by_hash(hash)
640 }
641
642 fn get_transaction_count(
643 &self,
644 address: Address,
645 ) -> RpcWithBlock<Address, U64, u64, fn(U64) -> u64> {
646 self.inner.get_transaction_count(address)
647 }
648
649 fn get_transaction_receipt(
650 &self,
651 hash: TxHash,
652 ) -> ProviderCall<(TxHash,), Option<N::ReceiptResponse>> {
653 self.inner.get_transaction_receipt(hash)
654 }
655
656 async fn get_uncle(&self, tag: BlockId, idx: u64) -> TransportResult<Option<N::BlockResponse>> {
657 self.inner.get_uncle(tag, idx).await
658 }
659
660 async fn get_uncle_count(&self, tag: BlockId) -> TransportResult<u64> {
661 self.inner.get_uncle_count(tag).await
662 }
663
664 fn get_max_priority_fee_per_gas(&self) -> ProviderCall<NoParams, U128, u128> {
665 self.inner.get_max_priority_fee_per_gas()
666 }
667
668 async fn new_block_filter(&self) -> TransportResult<U256> {
669 self.inner.new_block_filter().await
670 }
671
672 async fn new_filter(&self, filter: &Filter) -> TransportResult<U256> {
673 self.inner.new_filter(filter).await
674 }
675
676 async fn new_pending_transactions_filter(&self, full: bool) -> TransportResult<U256> {
677 self.inner.new_pending_transactions_filter(full).await
678 }
679
680 async fn send_raw_transaction(
681 &self,
682 encoded_tx: &[u8],
683 ) -> TransportResult<PendingTransactionBuilder<N>> {
684 self.inner.send_raw_transaction(encoded_tx).await
685 }
686
687 async fn send_raw_transaction_conditional(
688 &self,
689 encoded_tx: &[u8],
690 conditional: TransactionConditional,
691 ) -> TransportResult<PendingTransactionBuilder<N>> {
692 self.inner.send_raw_transaction_conditional(encoded_tx, conditional).await
693 }
694
695 async fn send_transaction_internal(
696 &self,
697 mut tx: SendableTx<N>,
698 ) -> TransportResult<PendingTransactionBuilder<N>> {
699 tx = self.fill_inner(tx).await?;
700
701 if let Some(builder) = tx.as_builder() {
702 if let FillerControlFlow::Missing(missing) = self.filler.status(builder) {
703 let message = format!("missing properties: {missing:?}");
706 return Err(RpcError::local_usage_str(&message));
707 }
708 }
709
710 self.inner.send_transaction_internal(tx).await
712 }
713
714 async fn send_transaction_sync_internal(
715 &self,
716 mut tx: SendableTx<N>,
717 ) -> TransportResult<N::ReceiptResponse> {
718 tx = self.fill_inner(tx).await?;
719
720 if let Some(builder) = tx.as_builder() {
721 if let FillerControlFlow::Missing(missing) = self.filler.status(builder) {
722 let message = format!("missing properties: {missing:?}");
723 return Err(RpcError::local_usage_str(&message));
724 }
725 }
726
727 self.inner.send_transaction_sync_internal(tx).await
729 }
730
731 async fn sign_transaction(&self, tx: N::TransactionRequest) -> TransportResult<Bytes> {
732 let tx = self.fill(tx).await?;
733 let tx = tx.try_into_request().map_err(TransportError::local_usage)?;
734 self.inner.sign_transaction(tx).await
735 }
736
737 #[cfg(feature = "pubsub")]
738 fn subscribe_blocks(&self) -> GetSubscription<(SubscriptionKind,), N::HeaderResponse> {
739 self.inner.subscribe_blocks()
740 }
741
742 #[cfg(feature = "pubsub")]
743 fn subscribe_pending_transactions(&self) -> GetSubscription<(SubscriptionKind,), B256> {
744 self.inner.subscribe_pending_transactions()
745 }
746
747 #[cfg(feature = "pubsub")]
748 fn subscribe_full_pending_transactions(
749 &self,
750 ) -> GetSubscription<(SubscriptionKind, Params), N::TransactionResponse> {
751 self.inner.subscribe_full_pending_transactions()
752 }
753
754 #[cfg(feature = "pubsub")]
755 fn subscribe_logs(&self, filter: &Filter) -> GetSubscription<(SubscriptionKind, Params), Log> {
756 self.inner.subscribe_logs(filter)
757 }
758
759 #[cfg(feature = "pubsub")]
760 async fn unsubscribe(&self, id: B256) -> TransportResult<()> {
761 self.inner.unsubscribe(id).await
762 }
763
764 fn syncing(&self) -> ProviderCall<NoParams, SyncStatus> {
765 self.inner.syncing()
766 }
767
768 fn get_client_version(&self) -> ProviderCall<NoParams, String> {
769 self.inner.get_client_version()
770 }
771
772 fn get_sha3(&self, data: &[u8]) -> ProviderCall<(String,), B256> {
773 self.inner.get_sha3(data)
774 }
775
776 fn get_net_version(&self) -> ProviderCall<NoParams, U64, u64> {
777 self.inner.get_net_version()
778 }
779
780 async fn raw_request_dyn(
781 &self,
782 method: Cow<'static, str>,
783 params: &RawValue,
784 ) -> TransportResult<Box<RawValue>> {
785 self.inner.raw_request_dyn(method, params).await
786 }
787
788 fn transaction_request(&self) -> N::TransactionRequest {
789 self.inner.transaction_request()
790 }
791}
792
793pub trait RecommendedFillers: Network {
795 type RecommendedFillers: TxFiller<Self>;
797
798 fn recommended_fillers() -> Self::RecommendedFillers;
800}
801
802impl RecommendedFillers for Ethereum {
803 type RecommendedFillers =
804 JoinFill<GasFiller, JoinFill<BlobGasFiller, JoinFill<NonceFiller, ChainIdFiller>>>;
805
806 fn recommended_fillers() -> Self::RecommendedFillers {
807 Default::default()
808 }
809}
810
811impl RecommendedFillers for AnyNetwork {
812 type RecommendedFillers =
813 JoinFill<GasFiller, JoinFill<BlobGasFiller, JoinFill<NonceFiller, ChainIdFiller>>>;
814
815 fn recommended_fillers() -> Self::RecommendedFillers {
816 Default::default()
817 }
818}