1mod builder;
2mod either;
3
4pub mod error;
5
6use alloy_consensus::TxEnvelope;
7use alloy_eips::{eip7702::SignedAuthorization, Typed2718};
8use alloy_primitives::{Bytes, ChainId, TxKind, B256, U256};
9pub use either::{AnyTxEnvelope, AnyTypedTransaction};
10use std::error::Error;
11
12mod unknowns;
13pub use unknowns::{AnyTxType, UnknownTxEnvelope, UnknownTypedTransaction};
14
15pub use alloy_consensus_any::{AnyHeader, AnyReceiptEnvelope};
16
17use crate::{any::error::AnyConversionError, Network};
18use alloy_consensus::{
19 error::ValueError,
20 transaction::{Either, Recovered},
21};
22use alloy_network_primitives::{BlockResponse, TransactionResponse};
23pub use alloy_rpc_types_any::{AnyRpcHeader, AnyTransactionReceipt};
24use alloy_rpc_types_eth::{AccessList, Block, BlockTransactions, Transaction, TransactionRequest};
25use alloy_serde::WithOtherFields;
26use derive_more::From;
27use serde::{Deserialize, Serialize};
28use std::ops::{Deref, DerefMut};
29
30#[derive(Clone, Copy, Debug)]
59pub struct AnyNetwork {
60 _private: (),
61}
62
63impl Network for AnyNetwork {
64 type TxType = AnyTxType;
65
66 type TxEnvelope = AnyTxEnvelope;
67
68 type UnsignedTx = AnyTypedTransaction;
69
70 type ReceiptEnvelope = AnyReceiptEnvelope;
71
72 type Header = AnyHeader;
73
74 type TransactionRequest = WithOtherFields<TransactionRequest>;
75
76 type TransactionResponse = AnyRpcTransaction;
77
78 type ReceiptResponse = AnyTransactionReceipt;
79
80 type HeaderResponse = AnyRpcHeader;
81
82 type BlockResponse = AnyRpcBlock;
83}
84
85#[derive(Clone, Debug, From, PartialEq, Eq, Deserialize, Serialize)]
91pub struct AnyRpcBlock(pub WithOtherFields<Block<AnyRpcTransaction, AnyRpcHeader>>);
92
93impl AnyRpcBlock {
94 pub const fn new(inner: WithOtherFields<Block<AnyRpcTransaction, AnyRpcHeader>>) -> Self {
96 Self(inner)
97 }
98
99 pub fn into_inner(self) -> Block<AnyRpcTransaction, AnyRpcHeader> {
101 self.0.into_inner()
102 }
103
104 pub fn try_into_consensus<T, H>(
108 self,
109 ) -> Result<alloy_consensus::Block<T, H>, AnyConversionError>
110 where
111 T: TryFrom<AnyRpcTransaction, Error: Error + Send + Sync + 'static>,
112 H: TryFrom<AnyHeader, Error: Error + Send + Sync + 'static>,
113 {
114 self.into_inner()
115 .map_header(|h| h.into_consensus())
116 .try_convert_header()
117 .map_err(AnyConversionError::new)?
118 .try_convert_transactions()
119 .map_err(AnyConversionError::new)
120 .map(Block::into_consensus_block)
121 }
122
123 pub fn try_into_transactions(
127 self,
128 ) -> Result<Vec<AnyRpcTransaction>, ValueError<BlockTransactions<AnyRpcTransaction>>> {
129 self.0.inner.try_into_transactions()
130 }
131
132 pub fn into_transactions_iter(self) -> impl Iterator<Item = AnyRpcTransaction> {
134 self.into_inner().transactions.into_transactions()
135 }
136}
137
138impl BlockResponse for AnyRpcBlock {
139 type Header = AnyRpcHeader;
140 type Transaction = AnyRpcTransaction;
141
142 fn header(&self) -> &Self::Header {
143 &self.0.inner.header
144 }
145
146 fn transactions(&self) -> &BlockTransactions<Self::Transaction> {
147 &self.0.inner.transactions
148 }
149
150 fn transactions_mut(&mut self) -> &mut BlockTransactions<Self::Transaction> {
151 &mut self.0.inner.transactions
152 }
153
154 fn other_fields(&self) -> Option<&alloy_serde::OtherFields> {
155 self.0.other_fields()
156 }
157}
158
159impl AsRef<WithOtherFields<Block<AnyRpcTransaction, AnyRpcHeader>>> for AnyRpcBlock {
160 fn as_ref(&self) -> &WithOtherFields<Block<AnyRpcTransaction, AnyRpcHeader>> {
161 &self.0
162 }
163}
164
165impl Deref for AnyRpcBlock {
166 type Target = WithOtherFields<Block<AnyRpcTransaction, AnyRpcHeader>>;
167
168 fn deref(&self) -> &Self::Target {
169 &self.0
170 }
171}
172
173impl DerefMut for AnyRpcBlock {
174 fn deref_mut(&mut self) -> &mut Self::Target {
175 &mut self.0
176 }
177}
178
179impl From<Block> for AnyRpcBlock {
180 fn from(value: Block) -> Self {
181 let block = value
182 .map_header(|h| h.map(|h| alloy_consensus_any::AnyHeader { ..h.into() }))
183 .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 try_into_either<T>(self) -> Result<Either<TxEnvelope, T>, T::Error>
253 where
254 T: TryFrom<Self>,
255 {
256 if self.0.inner.inner.inner().is_ethereum() {
257 Ok(Either::Left(self.0.inner.inner.into_inner().try_into_envelope().unwrap()))
258 } else {
259 T::try_from(self).map(Either::Right)
260 }
261 }
262
263 pub fn try_unknown_into_either<T>(self) -> Result<Either<TxEnvelope, T>, T::Error>
269 where
270 T: TryFrom<UnknownTxEnvelope>,
271 {
272 self.0.inner.inner.into_inner().try_into_either()
273 }
274
275 pub fn map<Tx>(self, f: impl FnOnce(AnyTxEnvelope) -> Tx) -> Transaction<Tx> {
280 self.into_inner().map(f)
281 }
282
283 pub fn try_map<Tx, E>(
287 self,
288 f: impl FnOnce(AnyTxEnvelope) -> Result<Tx, E>,
289 ) -> Result<Transaction<Tx>, E> {
290 self.into_inner().try_map(f)
291 }
292
293 pub fn convert<U>(self) -> Transaction<U>
297 where
298 U: From<AnyTxEnvelope>,
299 {
300 self.into_inner().map(U::from)
301 }
302
303 pub fn try_convert<U>(self) -> Result<Transaction<U>, U::Error>
309 where
310 U: TryFrom<AnyTxEnvelope>,
311 {
312 self.into_inner().try_map(U::try_from)
313 }
314}
315
316impl AsRef<AnyTxEnvelope> for AnyRpcTransaction {
317 fn as_ref(&self) -> &AnyTxEnvelope {
318 &self.0.inner.inner
319 }
320}
321
322impl Deref for AnyRpcTransaction {
323 type Target = WithOtherFields<Transaction<AnyTxEnvelope>>;
324
325 fn deref(&self) -> &Self::Target {
326 &self.0
327 }
328}
329
330impl DerefMut for AnyRpcTransaction {
331 fn deref_mut(&mut self) -> &mut Self::Target {
332 &mut self.0
333 }
334}
335
336impl From<Transaction<TxEnvelope>> for AnyRpcTransaction {
337 fn from(tx: Transaction<TxEnvelope>) -> Self {
338 let tx = tx.map(AnyTxEnvelope::Ethereum);
339 Self(WithOtherFields::new(tx))
340 }
341}
342
343impl From<AnyRpcTransaction> for AnyTxEnvelope {
344 fn from(tx: AnyRpcTransaction) -> Self {
345 tx.0.inner.into_inner()
346 }
347}
348
349impl From<AnyRpcTransaction> for Transaction<AnyTxEnvelope> {
350 fn from(tx: AnyRpcTransaction) -> Self {
351 tx.0.inner
352 }
353}
354
355impl From<AnyRpcTransaction> for WithOtherFields<Transaction<AnyTxEnvelope>> {
356 fn from(tx: AnyRpcTransaction) -> Self {
357 tx.0
358 }
359}
360
361impl From<AnyRpcTransaction> for Recovered<AnyTxEnvelope> {
362 fn from(tx: AnyRpcTransaction) -> Self {
363 tx.0.inner.inner
364 }
365}
366
367impl TryFrom<AnyRpcTransaction> for TxEnvelope {
368 type Error = ValueError<AnyTxEnvelope>;
369
370 fn try_from(value: AnyRpcTransaction) -> Result<Self, Self::Error> {
371 value.try_into_envelope()
372 }
373}
374
375impl alloy_consensus::Transaction for AnyRpcTransaction {
376 fn chain_id(&self) -> Option<ChainId> {
377 self.inner.chain_id()
378 }
379
380 fn nonce(&self) -> u64 {
381 self.inner.nonce()
382 }
383
384 fn gas_limit(&self) -> u64 {
385 self.inner.gas_limit()
386 }
387
388 fn gas_price(&self) -> Option<u128> {
389 alloy_consensus::Transaction::gas_price(&self.0.inner)
390 }
391
392 fn max_fee_per_gas(&self) -> u128 {
393 alloy_consensus::Transaction::max_fee_per_gas(&self.inner)
394 }
395
396 fn max_priority_fee_per_gas(&self) -> Option<u128> {
397 self.inner.max_priority_fee_per_gas()
398 }
399
400 fn max_fee_per_blob_gas(&self) -> Option<u128> {
401 self.inner.max_fee_per_blob_gas()
402 }
403
404 fn priority_fee_or_price(&self) -> u128 {
405 self.inner.priority_fee_or_price()
406 }
407
408 fn effective_gas_price(&self, base_fee: Option<u64>) -> u128 {
409 self.inner.effective_gas_price(base_fee)
410 }
411
412 fn is_dynamic_fee(&self) -> bool {
413 self.inner.is_dynamic_fee()
414 }
415
416 fn kind(&self) -> TxKind {
417 self.inner.kind()
418 }
419
420 fn is_create(&self) -> bool {
421 self.inner.is_create()
422 }
423
424 fn value(&self) -> U256 {
425 self.inner.value()
426 }
427
428 fn input(&self) -> &Bytes {
429 self.inner.input()
430 }
431
432 fn access_list(&self) -> Option<&AccessList> {
433 self.inner.access_list()
434 }
435
436 fn blob_versioned_hashes(&self) -> Option<&[B256]> {
437 self.inner.blob_versioned_hashes()
438 }
439
440 fn authorization_list(&self) -> Option<&[SignedAuthorization]> {
441 self.inner.authorization_list()
442 }
443}
444
445impl TransactionResponse for AnyRpcTransaction {
446 fn tx_hash(&self) -> alloy_primitives::TxHash {
447 self.inner.tx_hash()
448 }
449
450 fn block_hash(&self) -> Option<alloy_primitives::BlockHash> {
451 self.0.inner.block_hash
452 }
453
454 fn block_number(&self) -> Option<u64> {
455 self.inner.block_number
456 }
457
458 fn transaction_index(&self) -> Option<u64> {
459 self.inner.transaction_index
460 }
461
462 fn from(&self) -> alloy_primitives::Address {
463 self.inner.from()
464 }
465
466 fn gas_price(&self) -> Option<u128> {
467 self.inner.effective_gas_price
468 }
469}
470
471impl Typed2718 for AnyRpcTransaction {
472 fn ty(&self) -> u8 {
473 self.inner.ty()
474 }
475}
476
477#[cfg(test)]
478mod tests {
479 use super::*;
480 use alloy_primitives::B64;
481
482 #[test]
483 fn convert_any_block() {
484 let block = AnyRpcBlock::new(
485 Block::new(
486 AnyRpcHeader::from_sealed(
487 AnyHeader {
488 nonce: Some(B64::ZERO),
489 mix_hash: Some(B256::ZERO),
490 ..Default::default()
491 }
492 .seal(B256::ZERO),
493 ),
494 BlockTransactions::Full(vec![]),
495 )
496 .into(),
497 );
498
499 let _block: alloy_consensus::Block<TxEnvelope, alloy_consensus::Header> =
500 block.try_into().unwrap();
501 }
502}