1mod 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
57pub type RecommendedFiller =
60 JoinFill<JoinFill<JoinFill<Identity, GasFiller>, NonceFiller>, ChainIdFiller>;
61
62#[derive(Debug, thiserror::Error)]
64pub enum FillEnvelopeError<T> {
65 #[error("transport error during filling: {0}")]
67 Transport(TransportError),
68
69 #[error("transaction not ready: {0}")]
71 NotReady(SendableTxErr<T>),
72}
73
74#[derive(Clone, Debug, PartialEq, Eq)]
76pub enum FillerControlFlow {
77 Missing(Vec<(&'static str, Vec<&'static str>)>),
84 Ready,
86 Finished,
88}
89
90impl FillerControlFlow {
91 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 pub fn missing(name: &'static str, missing: Vec<&'static str>) -> Self {
120 Self::Missing(vec![(name, missing)])
121 }
122
123 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 pub const fn is_missing(&self) -> bool {
134 matches!(self, Self::Missing(_))
135 }
136
137 pub const fn is_ready(&self) -> bool {
140 matches!(self, Self::Ready)
141 }
142
143 pub const fn is_finished(&self) -> bool {
146 matches!(self, Self::Finished)
147 }
148}
149
150#[doc(alias = "TransactionFiller")]
164pub trait TxFiller<N: Network = Ethereum>: Clone + Send + Sync + std::fmt::Debug {
165 type Fillable: Send + Sync + 'static;
168
169 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 fn status(&self, tx: &N::TransactionRequest) -> FillerControlFlow;
181
182 fn continue_filling(&self, tx: &SendableTx<N>) -> bool {
184 tx.as_builder().is_some_and(|tx| self.status(tx).is_ready())
185 }
186
187 fn ready(&self, tx: &N::TransactionRequest) -> bool {
189 self.status(tx).is_ready()
190 }
191
192 fn finished(&self, tx: &N::TransactionRequest) -> bool {
194 self.status(tx).is_finished()
195 }
196
197 fn fill_sync(&self, tx: &mut SendableTx<N>);
201
202 fn prepare<P: Provider<N>>(
204 &self,
205 provider: &P,
206 tx: &N::TransactionRequest,
207 ) -> impl_future!(<Output = TransportResult<Self::Fillable>>);
208
209 fn fill(
211 &self,
212 fillable: Self::Fillable,
213 tx: SendableTx<N>,
214 ) -> impl_future!(<Output = TransportResult<SendableTx<N>>>);
215
216 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 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 fn prepare_call(
254 &self,
255 tx: &mut N::TransactionRequest,
256 ) -> impl_future!(<Output = TransportResult<()>>) {
257 let _ = tx;
258 futures::future::ready(Ok(()))
260 }
261
262 fn prepare_call_sync(&self, tx: &mut N::TransactionRequest) -> TransportResult<()> {
265 let _ = tx;
266 Ok(())
268 }
269}
270
271#[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 pub fn new(inner: P, filler: F) -> Self {
302 Self { inner, filler, _pd: PhantomData }
303 }
304
305 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 pub async fn fill(&self, tx: N::TransactionRequest) -> TransportResult<SendableTx<N>> {
335 self.fill_inner(SendableTx::Builder(tx)).await
336 }
337
338 pub fn prepare_call(
340 &self,
341 mut tx: N::TransactionRequest,
342 ) -> TransportResult<N::TransactionRequest> {
343 self.filler.prepare_call_sync(&mut tx)?;
344 Ok(tx)
345 }
346}
347
348#[cfg_attr(target_family = "wasm", async_trait(?Send))]
349#[cfg_attr(not(target_family = "wasm"), async_trait)]
350impl<F, P, N> Provider<N> for FillProvider<F, P, N>
351where
352 F: TxFiller<N>,
353 P: Provider<N>,
354 N: Network,
355{
356 fn root(&self) -> &RootProvider<N> {
357 self.inner.root()
358 }
359
360 fn get_accounts(&self) -> ProviderCall<NoParams, Vec<Address>> {
361 self.inner.get_accounts()
362 }
363
364 fn get_blob_base_fee(&self) -> ProviderCall<NoParams, U128, u128> {
365 self.inner.get_blob_base_fee()
366 }
367
368 fn get_block_number(&self) -> ProviderCall<NoParams, U64, BlockNumber> {
369 self.inner.get_block_number()
370 }
371
372 fn call<'req>(&self, tx: N::TransactionRequest) -> EthCall<N, Bytes> {
373 let mut tx = tx;
374 let _ = self.filler.prepare_call_sync(&mut tx);
375 self.inner.call(tx)
376 }
377
378 fn call_many<'req>(
379 &self,
380 bundles: &'req [Bundle],
381 ) -> EthCallMany<'req, N, Vec<Vec<EthCallResponse>>> {
382 self.inner.call_many(bundles)
383 }
384
385 fn simulate<'req>(
386 &self,
387 payload: &'req SimulatePayload,
388 ) -> RpcWithBlock<&'req SimulatePayload, Vec<SimulatedBlock<N::BlockResponse>>> {
389 self.inner.simulate(payload)
390 }
391
392 fn get_chain_id(&self) -> ProviderCall<NoParams, U64, u64> {
393 self.inner.get_chain_id()
394 }
395
396 fn create_access_list<'a>(
397 &self,
398 request: &'a N::TransactionRequest,
399 ) -> RpcWithBlock<&'a N::TransactionRequest, AccessListResult> {
400 self.inner.create_access_list(request)
401 }
402
403 fn estimate_gas<'req>(&self, tx: N::TransactionRequest) -> EthCall<N, U64, u64> {
404 let mut tx = tx;
405 let _ = self.filler.prepare_call_sync(&mut tx);
406 self.inner.estimate_gas(tx)
407 }
408
409 async fn get_fee_history(
410 &self,
411 block_count: u64,
412 last_block: BlockNumberOrTag,
413 reward_percentiles: &[f64],
414 ) -> TransportResult<FeeHistory> {
415 self.inner.get_fee_history(block_count, last_block, reward_percentiles).await
416 }
417
418 fn get_gas_price(&self) -> ProviderCall<NoParams, U128, u128> {
419 self.inner.get_gas_price()
420 }
421
422 fn get_account_info(
423 &self,
424 address: Address,
425 ) -> RpcWithBlock<Address, alloy_rpc_types_eth::AccountInfo> {
426 self.inner.get_account_info(address)
427 }
428
429 fn get_account(&self, address: Address) -> RpcWithBlock<Address, alloy_consensus::Account> {
430 self.inner.get_account(address)
431 }
432
433 fn get_balance(&self, address: Address) -> RpcWithBlock<Address, U256, U256> {
434 self.inner.get_balance(address)
435 }
436
437 fn get_block(&self, block: BlockId) -> EthGetBlock<N::BlockResponse> {
438 self.inner.get_block(block)
439 }
440
441 fn get_block_by_hash(&self, hash: BlockHash) -> EthGetBlock<N::BlockResponse> {
442 self.inner.get_block_by_hash(hash)
443 }
444
445 fn get_block_by_number(&self, number: BlockNumberOrTag) -> EthGetBlock<N::BlockResponse> {
446 self.inner.get_block_by_number(number)
447 }
448
449 async fn get_block_transaction_count_by_hash(
450 &self,
451 hash: BlockHash,
452 ) -> TransportResult<Option<u64>> {
453 self.inner.get_block_transaction_count_by_hash(hash).await
454 }
455
456 async fn get_block_transaction_count_by_number(
457 &self,
458 block_number: BlockNumberOrTag,
459 ) -> TransportResult<Option<u64>> {
460 self.inner.get_block_transaction_count_by_number(block_number).await
461 }
462
463 fn get_block_receipts(
464 &self,
465 block: BlockId,
466 ) -> ProviderCall<(BlockId,), Option<Vec<N::ReceiptResponse>>> {
467 self.inner.get_block_receipts(block)
468 }
469
470 fn get_code_at(&self, address: Address) -> RpcWithBlock<Address, Bytes> {
471 self.inner.get_code_at(address)
472 }
473
474 async fn watch_blocks(&self) -> TransportResult<FilterPollerBuilder<B256>> {
475 self.inner.watch_blocks().await
476 }
477
478 async fn watch_pending_transactions(&self) -> TransportResult<FilterPollerBuilder<B256>> {
479 self.inner.watch_pending_transactions().await
480 }
481
482 async fn watch_logs(&self, filter: &Filter) -> TransportResult<FilterPollerBuilder<Log>> {
483 self.inner.watch_logs(filter).await
484 }
485
486 async fn watch_full_pending_transactions(
487 &self,
488 ) -> TransportResult<FilterPollerBuilder<N::TransactionResponse>> {
489 self.inner.watch_full_pending_transactions().await
490 }
491
492 async fn get_filter_changes_dyn(&self, id: U256) -> TransportResult<FilterChanges> {
493 self.inner.get_filter_changes_dyn(id).await
494 }
495
496 async fn get_filter_logs(&self, id: U256) -> TransportResult<Vec<Log>> {
497 self.inner.get_filter_logs(id).await
498 }
499
500 async fn uninstall_filter(&self, id: U256) -> TransportResult<bool> {
501 self.inner.uninstall_filter(id).await
502 }
503
504 async fn watch_pending_transaction(
505 &self,
506 config: PendingTransactionConfig,
507 ) -> Result<PendingTransaction, PendingTransactionError> {
508 self.inner.watch_pending_transaction(config).await
509 }
510
511 async fn get_logs(&self, filter: &Filter) -> TransportResult<Vec<Log>> {
512 self.inner.get_logs(filter).await
513 }
514
515 fn get_proof(
516 &self,
517 address: Address,
518 keys: Vec<StorageKey>,
519 ) -> RpcWithBlock<(Address, Vec<StorageKey>), EIP1186AccountProofResponse> {
520 self.inner.get_proof(address, keys)
521 }
522
523 fn get_storage_at(
524 &self,
525 address: Address,
526 key: U256,
527 ) -> RpcWithBlock<(Address, U256), StorageValue> {
528 self.inner.get_storage_at(address, key)
529 }
530
531 fn get_transaction_by_hash(
532 &self,
533 hash: TxHash,
534 ) -> ProviderCall<(TxHash,), Option<N::TransactionResponse>> {
535 self.inner.get_transaction_by_hash(hash)
536 }
537
538 fn get_transaction_by_sender_nonce(
539 &self,
540 sender: Address,
541 nonce: u64,
542 ) -> ProviderCall<(Address, U64), Option<N::TransactionResponse>> {
543 self.inner.get_transaction_by_sender_nonce(sender, nonce)
544 }
545
546 fn get_transaction_by_block_hash_and_index(
547 &self,
548 block_hash: B256,
549 index: usize,
550 ) -> ProviderCall<(B256, Index), Option<N::TransactionResponse>> {
551 self.inner.get_transaction_by_block_hash_and_index(block_hash, index)
552 }
553
554 fn get_raw_transaction_by_block_hash_and_index(
555 &self,
556 block_hash: B256,
557 index: usize,
558 ) -> ProviderCall<(B256, Index), Option<Bytes>> {
559 self.inner.get_raw_transaction_by_block_hash_and_index(block_hash, index)
560 }
561
562 fn get_transaction_by_block_number_and_index(
563 &self,
564 block_number: BlockNumberOrTag,
565 index: usize,
566 ) -> ProviderCall<(BlockNumberOrTag, Index), Option<N::TransactionResponse>> {
567 self.inner.get_transaction_by_block_number_and_index(block_number, index)
568 }
569
570 fn get_raw_transaction_by_block_number_and_index(
571 &self,
572 block_number: BlockNumberOrTag,
573 index: usize,
574 ) -> ProviderCall<(BlockNumberOrTag, Index), Option<Bytes>> {
575 self.inner.get_raw_transaction_by_block_number_and_index(block_number, index)
576 }
577
578 fn get_raw_transaction_by_hash(&self, hash: TxHash) -> ProviderCall<(TxHash,), Option<Bytes>> {
579 self.inner.get_raw_transaction_by_hash(hash)
580 }
581
582 fn get_transaction_count(
583 &self,
584 address: Address,
585 ) -> RpcWithBlock<Address, U64, u64, fn(U64) -> u64> {
586 self.inner.get_transaction_count(address)
587 }
588
589 fn get_transaction_receipt(
590 &self,
591 hash: TxHash,
592 ) -> ProviderCall<(TxHash,), Option<N::ReceiptResponse>> {
593 self.inner.get_transaction_receipt(hash)
594 }
595
596 async fn get_uncle(&self, tag: BlockId, idx: u64) -> TransportResult<Option<N::BlockResponse>> {
597 self.inner.get_uncle(tag, idx).await
598 }
599
600 async fn get_uncle_count(&self, tag: BlockId) -> TransportResult<u64> {
601 self.inner.get_uncle_count(tag).await
602 }
603
604 fn get_max_priority_fee_per_gas(&self) -> ProviderCall<NoParams, U128, u128> {
605 self.inner.get_max_priority_fee_per_gas()
606 }
607
608 async fn new_block_filter(&self) -> TransportResult<U256> {
609 self.inner.new_block_filter().await
610 }
611
612 async fn new_filter(&self, filter: &Filter) -> TransportResult<U256> {
613 self.inner.new_filter(filter).await
614 }
615
616 async fn new_pending_transactions_filter(&self, full: bool) -> TransportResult<U256> {
617 self.inner.new_pending_transactions_filter(full).await
618 }
619
620 async fn send_raw_transaction(
621 &self,
622 encoded_tx: &[u8],
623 ) -> TransportResult<PendingTransactionBuilder<N>> {
624 self.inner.send_raw_transaction(encoded_tx).await
625 }
626
627 async fn send_raw_transaction_conditional(
628 &self,
629 encoded_tx: &[u8],
630 conditional: TransactionConditional,
631 ) -> TransportResult<PendingTransactionBuilder<N>> {
632 self.inner.send_raw_transaction_conditional(encoded_tx, conditional).await
633 }
634
635 async fn send_transaction_internal(
636 &self,
637 mut tx: SendableTx<N>,
638 ) -> TransportResult<PendingTransactionBuilder<N>> {
639 tx = self.fill_inner(tx).await?;
640
641 if let Some(builder) = tx.as_builder() {
642 if let FillerControlFlow::Missing(missing) = self.filler.status(builder) {
643 let message = format!("missing properties: {missing:?}");
646 return Err(RpcError::local_usage_str(&message));
647 }
648 }
649
650 self.inner.send_transaction_internal(tx).await
652 }
653
654 async fn sign_transaction(&self, tx: N::TransactionRequest) -> TransportResult<Bytes> {
655 let tx = self.fill(tx).await?;
656 let tx = tx.try_into_request().map_err(TransportError::local_usage)?;
657 self.inner.sign_transaction(tx).await
658 }
659
660 #[cfg(feature = "pubsub")]
661 fn subscribe_blocks(&self) -> GetSubscription<(SubscriptionKind,), N::HeaderResponse> {
662 self.inner.subscribe_blocks()
663 }
664
665 #[cfg(feature = "pubsub")]
666 fn subscribe_pending_transactions(&self) -> GetSubscription<(SubscriptionKind,), B256> {
667 self.inner.subscribe_pending_transactions()
668 }
669
670 #[cfg(feature = "pubsub")]
671 fn subscribe_full_pending_transactions(
672 &self,
673 ) -> GetSubscription<(SubscriptionKind, Params), N::TransactionResponse> {
674 self.inner.subscribe_full_pending_transactions()
675 }
676
677 #[cfg(feature = "pubsub")]
678 fn subscribe_logs(&self, filter: &Filter) -> GetSubscription<(SubscriptionKind, Params), Log> {
679 self.inner.subscribe_logs(filter)
680 }
681
682 #[cfg(feature = "pubsub")]
683 async fn unsubscribe(&self, id: B256) -> TransportResult<()> {
684 self.inner.unsubscribe(id).await
685 }
686
687 fn syncing(&self) -> ProviderCall<NoParams, SyncStatus> {
688 self.inner.syncing()
689 }
690
691 fn get_client_version(&self) -> ProviderCall<NoParams, String> {
692 self.inner.get_client_version()
693 }
694
695 fn get_sha3(&self, data: &[u8]) -> ProviderCall<(String,), B256> {
696 self.inner.get_sha3(data)
697 }
698
699 fn get_net_version(&self) -> ProviderCall<NoParams, U64, u64> {
700 self.inner.get_net_version()
701 }
702
703 async fn raw_request_dyn(
704 &self,
705 method: Cow<'static, str>,
706 params: &RawValue,
707 ) -> TransportResult<Box<RawValue>> {
708 self.inner.raw_request_dyn(method, params).await
709 }
710
711 fn transaction_request(&self) -> N::TransactionRequest {
712 self.inner.transaction_request()
713 }
714}
715
716pub trait RecommendedFillers: Network {
718 type RecommendedFillers: TxFiller<Self>;
720
721 fn recommended_fillers() -> Self::RecommendedFillers;
723}
724
725impl RecommendedFillers for Ethereum {
726 type RecommendedFillers =
727 JoinFill<GasFiller, JoinFill<BlobGasFiller, JoinFill<NonceFiller, ChainIdFiller>>>;
728
729 fn recommended_fillers() -> Self::RecommendedFillers {
730 Default::default()
731 }
732}
733
734impl RecommendedFillers for AnyNetwork {
735 type RecommendedFillers =
736 JoinFill<GasFiller, JoinFill<BlobGasFiller, JoinFill<NonceFiller, ChainIdFiller>>>;
737
738 fn recommended_fillers() -> Self::RecommendedFillers {
739 Default::default()
740 }
741}