1mod builder;
2mod either;
3
4pub mod error;
5
6use alloy_consensus::{
7    Signed, TxEip1559, TxEip2930, TxEip4844Variant, TxEip7702, TxEnvelope, TxLegacy,
8};
9use alloy_eips::{eip7702::SignedAuthorization, Typed2718};
10use alloy_primitives::{Bytes, ChainId, TxKind, B256, U256};
11pub use either::{AnyTxEnvelope, AnyTypedTransaction};
12use std::error::Error;
13
14mod unknowns;
15pub use unknowns::{AnyTxType, UnknownTxEnvelope, UnknownTypedTransaction};
16
17pub use alloy_consensus_any::{AnyHeader, AnyReceiptEnvelope};
18
19use crate::{any::error::AnyConversionError, Network};
20use alloy_consensus::{
21    error::ValueError,
22    transaction::{Either, Recovered},
23};
24use alloy_network_primitives::{BlockResponse, TransactionResponse};
25pub use alloy_rpc_types_any::{AnyRpcHeader, AnyTransactionReceipt};
26use alloy_rpc_types_eth::{AccessList, Block, BlockTransactions, Transaction, TransactionRequest};
27use alloy_serde::WithOtherFields;
28use derive_more::From;
29use serde::{Deserialize, Serialize};
30use std::ops::{Deref, DerefMut};
31
32#[derive(Clone, Copy, Debug)]
61pub struct AnyNetwork {
62    _private: (),
63}
64
65impl Network for AnyNetwork {
66    type TxType = AnyTxType;
67
68    type TxEnvelope = AnyTxEnvelope;
69
70    type UnsignedTx = AnyTypedTransaction;
71
72    type ReceiptEnvelope = AnyReceiptEnvelope;
73
74    type Header = AnyHeader;
75
76    type TransactionRequest = WithOtherFields<TransactionRequest>;
77
78    type TransactionResponse = AnyRpcTransaction;
79
80    type ReceiptResponse = AnyTransactionReceipt;
81
82    type HeaderResponse = AnyRpcHeader;
83
84    type BlockResponse = AnyRpcBlock;
85}
86
87#[derive(Clone, Debug, From, PartialEq, Eq, Deserialize, Serialize)]
93pub struct AnyRpcBlock(pub WithOtherFields<Block<AnyRpcTransaction, AnyRpcHeader>>);
94
95impl AnyRpcBlock {
96    pub const fn new(inner: WithOtherFields<Block<AnyRpcTransaction, AnyRpcHeader>>) -> Self {
98        Self(inner)
99    }
100
101    pub fn into_inner(self) -> Block<AnyRpcTransaction, AnyRpcHeader> {
103        self.0.into_inner()
104    }
105
106    pub fn try_into_consensus<T, H>(
110        self,
111    ) -> Result<alloy_consensus::Block<T, H>, AnyConversionError>
112    where
113        T: TryFrom<AnyRpcTransaction, Error: Error + Send + Sync + 'static>,
114        H: TryFrom<AnyHeader, Error: Error + Send + Sync + 'static>,
115    {
116        self.into_inner()
117            .map_header(|h| h.into_consensus())
118            .try_convert_header()
119            .map_err(AnyConversionError::new)?
120            .try_convert_transactions()
121            .map_err(AnyConversionError::new)
122            .map(Block::into_consensus_block)
123    }
124
125    pub fn try_into_transactions(
129        self,
130    ) -> Result<Vec<AnyRpcTransaction>, ValueError<BlockTransactions<AnyRpcTransaction>>> {
131        self.0.inner.try_into_transactions()
132    }
133
134    pub fn into_transactions_iter(self) -> impl Iterator<Item = AnyRpcTransaction> {
136        self.into_inner().transactions.into_transactions()
137    }
138}
139
140impl BlockResponse for AnyRpcBlock {
141    type Header = AnyRpcHeader;
142    type Transaction = AnyRpcTransaction;
143
144    fn header(&self) -> &Self::Header {
145        &self.0.inner.header
146    }
147
148    fn transactions(&self) -> &BlockTransactions<Self::Transaction> {
149        &self.0.inner.transactions
150    }
151
152    fn transactions_mut(&mut self) -> &mut BlockTransactions<Self::Transaction> {
153        &mut self.0.inner.transactions
154    }
155
156    fn other_fields(&self) -> Option<&alloy_serde::OtherFields> {
157        self.0.other_fields()
158    }
159}
160
161impl AsRef<WithOtherFields<Block<AnyRpcTransaction, AnyRpcHeader>>> for AnyRpcBlock {
162    fn as_ref(&self) -> &WithOtherFields<Block<AnyRpcTransaction, AnyRpcHeader>> {
163        &self.0
164    }
165}
166
167impl Deref for AnyRpcBlock {
168    type Target = WithOtherFields<Block<AnyRpcTransaction, AnyRpcHeader>>;
169
170    fn deref(&self) -> &Self::Target {
171        &self.0
172    }
173}
174
175impl DerefMut for AnyRpcBlock {
176    fn deref_mut(&mut self) -> &mut Self::Target {
177        &mut self.0
178    }
179}
180
181impl From<Block> for AnyRpcBlock {
182    fn from(value: Block) -> Self {
183        let block = value.map_header(|h| h.map(|h| h.into())).map_transactions(|tx| {
184            AnyRpcTransaction::new(WithOtherFields::new(tx.map(AnyTxEnvelope::Ethereum)))
185        });
186
187        Self(WithOtherFields::new(block))
188    }
189}
190
191impl From<AnyRpcBlock> for Block<AnyRpcTransaction, AnyRpcHeader> {
192    fn from(value: AnyRpcBlock) -> Self {
193        value.into_inner()
194    }
195}
196impl From<AnyRpcBlock> for WithOtherFields<Block<AnyRpcTransaction, AnyRpcHeader>> {
197    fn from(value: AnyRpcBlock) -> Self {
198        value.0
199    }
200}
201
202impl<T, H> TryFrom<AnyRpcBlock> for alloy_consensus::Block<T, H>
203where
204    T: TryFrom<AnyRpcTransaction, Error: Error + Send + Sync + 'static>,
205    H: TryFrom<AnyHeader, Error: Error + Send + Sync + 'static>,
206{
207    type Error = AnyConversionError;
208
209    fn try_from(value: AnyRpcBlock) -> Result<Self, Self::Error> {
210        value.try_into_consensus()
211    }
212}
213
214#[derive(Clone, Debug, From, PartialEq, Eq, Deserialize, Serialize)]
216pub struct AnyRpcTransaction(pub WithOtherFields<Transaction<AnyTxEnvelope>>);
217
218impl AnyRpcTransaction {
219    pub const fn new(inner: WithOtherFields<Transaction<AnyTxEnvelope>>) -> Self {
221        Self(inner)
222    }
223
224    pub fn into_parts(self) -> (Transaction<AnyTxEnvelope>, alloy_serde::OtherFields) {
226        let WithOtherFields { inner, other } = self.0;
227        (inner, other)
228    }
229
230    pub fn into_inner(self) -> Transaction<AnyTxEnvelope> {
232        self.0.into_inner()
233    }
234
235    pub fn as_envelope(&self) -> Option<&TxEnvelope> {
238        self.inner.inner.as_envelope()
239    }
240
241    pub fn try_into_envelope(self) -> Result<TxEnvelope, ValueError<AnyTxEnvelope>> {
244        self.0.inner.inner.into_inner().try_into_envelope()
245    }
246
247    pub fn as_legacy(&self) -> Option<&Signed<TxLegacy>> {
249        self.0.inner().inner.as_legacy()
250    }
251
252    pub fn as_eip2930(&self) -> Option<&Signed<TxEip2930>> {
254        self.0.inner().inner.as_eip2930()
255    }
256
257    pub fn as_eip1559(&self) -> Option<&Signed<TxEip1559>> {
259        self.0.inner().inner.as_eip1559()
260    }
261
262    pub fn as_eip4844(&self) -> Option<&Signed<TxEip4844Variant>> {
264        self.0.inner().inner.as_eip4844()
265    }
266
267    pub fn as_eip7702(&self) -> Option<&Signed<TxEip7702>> {
269        self.0.inner().inner.as_eip7702()
270    }
271
272    #[inline]
274    pub fn is_legacy(&self) -> bool {
275        self.0.inner().inner.is_legacy()
276    }
277
278    #[inline]
280    pub fn is_eip2930(&self) -> bool {
281        self.0.inner().inner.is_eip2930()
282    }
283
284    #[inline]
286    pub fn is_eip1559(&self) -> bool {
287        self.0.inner().inner.is_eip1559()
288    }
289
290    #[inline]
292    pub fn is_eip4844(&self) -> bool {
293        self.0.inner().inner.is_eip4844()
294    }
295
296    #[inline]
298    pub fn is_eip7702(&self) -> bool {
299        self.0.inner().inner.is_eip7702()
300    }
301
302    pub fn try_into_either<T>(self) -> Result<Either<TxEnvelope, T>, T::Error>
308    where
309        T: TryFrom<Self>,
310    {
311        if self.0.inner.inner.inner().is_ethereum() {
312            Ok(Either::Left(self.0.inner.inner.into_inner().try_into_envelope().unwrap()))
313        } else {
314            T::try_from(self).map(Either::Right)
315        }
316    }
317
318    pub fn try_unknown_into_either<T>(self) -> Result<Either<TxEnvelope, T>, T::Error>
324    where
325        T: TryFrom<UnknownTxEnvelope>,
326    {
327        self.0.inner.inner.into_inner().try_into_either()
328    }
329
330    pub fn map<Tx>(self, f: impl FnOnce(AnyTxEnvelope) -> Tx) -> Transaction<Tx> {
335        self.into_inner().map(f)
336    }
337
338    pub fn try_map<Tx, E>(
342        self,
343        f: impl FnOnce(AnyTxEnvelope) -> Result<Tx, E>,
344    ) -> Result<Transaction<Tx>, E> {
345        self.into_inner().try_map(f)
346    }
347
348    pub fn convert<U>(self) -> Transaction<U>
352    where
353        U: From<AnyTxEnvelope>,
354    {
355        self.into_inner().map(U::from)
356    }
357
358    pub fn try_convert<U>(self) -> Result<Transaction<U>, U::Error>
364    where
365        U: TryFrom<AnyTxEnvelope>,
366    {
367        self.into_inner().try_map(U::try_from)
368    }
369}
370
371impl AsRef<AnyTxEnvelope> for AnyRpcTransaction {
372    fn as_ref(&self) -> &AnyTxEnvelope {
373        &self.0.inner.inner
374    }
375}
376
377impl Deref for AnyRpcTransaction {
378    type Target = WithOtherFields<Transaction<AnyTxEnvelope>>;
379
380    fn deref(&self) -> &Self::Target {
381        &self.0
382    }
383}
384
385impl DerefMut for AnyRpcTransaction {
386    fn deref_mut(&mut self) -> &mut Self::Target {
387        &mut self.0
388    }
389}
390
391impl From<Transaction<TxEnvelope>> for AnyRpcTransaction {
392    fn from(tx: Transaction<TxEnvelope>) -> Self {
393        let tx = tx.map(AnyTxEnvelope::Ethereum);
394        Self(WithOtherFields::new(tx))
395    }
396}
397
398impl From<AnyRpcTransaction> for AnyTxEnvelope {
399    fn from(tx: AnyRpcTransaction) -> Self {
400        tx.0.inner.into_inner()
401    }
402}
403
404impl From<AnyRpcTransaction> for Transaction<AnyTxEnvelope> {
405    fn from(tx: AnyRpcTransaction) -> Self {
406        tx.0.inner
407    }
408}
409
410impl From<AnyRpcTransaction> for WithOtherFields<Transaction<AnyTxEnvelope>> {
411    fn from(tx: AnyRpcTransaction) -> Self {
412        tx.0
413    }
414}
415
416impl From<AnyRpcTransaction> for Recovered<AnyTxEnvelope> {
417    fn from(tx: AnyRpcTransaction) -> Self {
418        tx.0.inner.inner
419    }
420}
421
422impl TryFrom<AnyRpcTransaction> for TxEnvelope {
423    type Error = ValueError<AnyTxEnvelope>;
424
425    fn try_from(value: AnyRpcTransaction) -> Result<Self, Self::Error> {
426        value.try_into_envelope()
427    }
428}
429
430impl alloy_consensus::Transaction for AnyRpcTransaction {
431    fn chain_id(&self) -> Option<ChainId> {
432        self.inner.chain_id()
433    }
434
435    fn nonce(&self) -> u64 {
436        self.inner.nonce()
437    }
438
439    fn gas_limit(&self) -> u64 {
440        self.inner.gas_limit()
441    }
442
443    fn gas_price(&self) -> Option<u128> {
444        alloy_consensus::Transaction::gas_price(&self.0.inner)
445    }
446
447    fn max_fee_per_gas(&self) -> u128 {
448        alloy_consensus::Transaction::max_fee_per_gas(&self.inner)
449    }
450
451    fn max_priority_fee_per_gas(&self) -> Option<u128> {
452        self.inner.max_priority_fee_per_gas()
453    }
454
455    fn max_fee_per_blob_gas(&self) -> Option<u128> {
456        self.inner.max_fee_per_blob_gas()
457    }
458
459    fn priority_fee_or_price(&self) -> u128 {
460        self.inner.priority_fee_or_price()
461    }
462
463    fn effective_gas_price(&self, base_fee: Option<u64>) -> u128 {
464        self.inner.effective_gas_price(base_fee)
465    }
466
467    fn is_dynamic_fee(&self) -> bool {
468        self.inner.is_dynamic_fee()
469    }
470
471    fn kind(&self) -> TxKind {
472        self.inner.kind()
473    }
474
475    fn is_create(&self) -> bool {
476        self.inner.is_create()
477    }
478
479    fn value(&self) -> U256 {
480        self.inner.value()
481    }
482
483    fn input(&self) -> &Bytes {
484        self.inner.input()
485    }
486
487    fn access_list(&self) -> Option<&AccessList> {
488        self.inner.access_list()
489    }
490
491    fn blob_versioned_hashes(&self) -> Option<&[B256]> {
492        self.inner.blob_versioned_hashes()
493    }
494
495    fn authorization_list(&self) -> Option<&[SignedAuthorization]> {
496        self.inner.authorization_list()
497    }
498}
499
500impl TransactionResponse for AnyRpcTransaction {
501    fn tx_hash(&self) -> alloy_primitives::TxHash {
502        self.inner.tx_hash()
503    }
504
505    fn block_hash(&self) -> Option<alloy_primitives::BlockHash> {
506        self.0.inner.block_hash
507    }
508
509    fn block_number(&self) -> Option<u64> {
510        self.inner.block_number
511    }
512
513    fn transaction_index(&self) -> Option<u64> {
514        self.inner.transaction_index
515    }
516
517    fn from(&self) -> alloy_primitives::Address {
518        self.inner.from()
519    }
520
521    fn gas_price(&self) -> Option<u128> {
522        self.inner.effective_gas_price
523    }
524}
525
526impl Typed2718 for AnyRpcTransaction {
527    fn ty(&self) -> u8 {
528        self.inner.ty()
529    }
530}
531
532#[cfg(test)]
533mod tests {
534    use super::*;
535    use alloy_primitives::B64;
536
537    #[test]
538    fn convert_any_block() {
539        let block = AnyRpcBlock::new(
540            Block::new(
541                AnyRpcHeader::from_sealed(
542                    AnyHeader {
543                        nonce: Some(B64::ZERO),
544                        mix_hash: Some(B256::ZERO),
545                        ..Default::default()
546                    }
547                    .seal(B256::ZERO),
548                ),
549                BlockTransactions::Full(vec![]),
550            )
551            .into(),
552        );
553
554        let _block: alloy_consensus::Block<TxEnvelope, alloy_consensus::Header> =
555            block.try_into().unwrap();
556    }
557}