1use alloy_consensus::{
4 BlockHeader, Eip658Value, Signed, Transaction as TxTrait, TxEip1559, TxEip2930,
5 TxEip4844Variant, TxEip7702, TxEnvelope, TxLegacy, TxReceipt, Typed2718,
6 transaction::TxHashRef,
7};
8use alloy_network::{
9 AnyRpcBlock, AnyRpcHeader, AnyRpcTransaction, AnyTransactionReceipt, AnyTxEnvelope,
10 BlockResponse, Network, ReceiptResponse, primitives::HeaderResponse,
11};
12use alloy_primitives::{
13 Address, Bloom, Bytes, FixedBytes, I256, Signature, U8, U64, U256, Uint, hex,
14};
15use alloy_rpc_types::{
16 AccessListItem, Block, BlockTransactions, Header, Log, Transaction, TransactionReceipt,
17};
18use alloy_serde::{OtherFields, WithOtherFields};
19use revm::context_interface::transaction::SignedAuthorization;
20use serde::{Deserialize, Serialize};
21use std::num::NonZeroU64;
22use tempo_alloy::{
23 primitives::{
24 AASigned, TempoSignature, TempoTransaction, TempoTxEnvelope,
25 transaction::{Call, PrimitiveSignature},
26 },
27 rpc::{TempoHeaderResponse, TempoTransactionReceipt},
28};
29
30#[cfg(feature = "base")]
31use base_common_consensus::{
32 BaseReceipt, BaseTxEnvelope, Eip8130Signed, TxDeposit as BaseTxDeposit,
33};
34#[cfg(feature = "base")]
35use base_common_rpc_types::{BaseTransactionReceipt, Transaction as BaseRpcTransaction};
36
37#[cfg(feature = "optimism")]
38use op_alloy_consensus::{OpTxEnvelope, TxDeposit, TxPostExec};
39
40const NAME_COLUMN_LEN: usize = 20usize;
42
43pub trait UIfmt {
54 fn pretty(&self) -> String;
56}
57
58impl<T: UIfmt> UIfmt for &T {
59 fn pretty(&self) -> String {
60 (*self).pretty()
61 }
62}
63
64impl<T: UIfmt> UIfmt for Option<T> {
65 fn pretty(&self) -> String {
66 if let Some(inner) = self { inner.pretty() } else { String::new() }
67 }
68}
69
70impl<T: UIfmt> UIfmt for [T] {
71 fn pretty(&self) -> String {
72 if self.is_empty() {
73 "[]".to_string()
74 } else {
75 let mut s = String::with_capacity(self.len() * 64);
76 s.push_str("[\n");
77 for item in self {
78 for line in item.pretty().lines() {
79 s.push('\t');
80 s.push_str(line);
81 s.push('\n');
82 }
83 }
84 s.push(']');
85 s
86 }
87 }
88}
89
90impl UIfmt for String {
91 fn pretty(&self) -> String {
92 self.clone()
93 }
94}
95
96impl UIfmt for u64 {
97 fn pretty(&self) -> String {
98 self.to_string()
99 }
100}
101
102impl UIfmt for NonZeroU64 {
103 fn pretty(&self) -> String {
104 self.get().pretty()
105 }
106}
107
108impl UIfmt for u128 {
109 fn pretty(&self) -> String {
110 self.to_string()
111 }
112}
113
114impl UIfmt for bool {
115 fn pretty(&self) -> String {
116 self.to_string()
117 }
118}
119
120impl<const BITS: usize, const LIMBS: usize> UIfmt for Uint<BITS, LIMBS> {
121 fn pretty(&self) -> String {
122 self.to_string()
123 }
124}
125
126impl UIfmt for I256 {
127 fn pretty(&self) -> String {
128 self.to_string()
129 }
130}
131
132impl UIfmt for Address {
133 fn pretty(&self) -> String {
134 self.to_string()
135 }
136}
137
138impl UIfmt for Bloom {
139 fn pretty(&self) -> String {
140 self.to_string()
141 }
142}
143
144impl UIfmt for Vec<u8> {
145 fn pretty(&self) -> String {
146 self[..].pretty()
147 }
148}
149
150impl UIfmt for Bytes {
151 fn pretty(&self) -> String {
152 self[..].pretty()
153 }
154}
155
156impl<const N: usize> UIfmt for [u8; N] {
157 fn pretty(&self) -> String {
158 self[..].pretty()
159 }
160}
161
162impl<const N: usize> UIfmt for FixedBytes<N> {
163 fn pretty(&self) -> String {
164 self[..].pretty()
165 }
166}
167
168impl UIfmt for [u8] {
169 fn pretty(&self) -> String {
170 hex::encode_prefixed(self)
171 }
172}
173
174impl UIfmt for Eip658Value {
175 fn pretty(&self) -> String {
176 match self {
177 Self::Eip658(status) => if *status { "1 (success)" } else { "0 (failed)" }.to_string(),
178 Self::PostState(state) => state.pretty(),
179 }
180 }
181}
182
183impl UIfmt for Signature {
184 fn pretty(&self) -> String {
185 format!("[r: {}, s: {}, y_parity: {}]", self.r(), self.s(), self.v())
186 }
187}
188
189fn pretty_receipt<T: TxReceipt>(receipt: &TransactionReceipt<T>, tx_type: u8) -> String
191where
192 T::Log: Serialize,
193{
194 let mut pretty = format!(
195 "
196blockHash {}
197blockNumber {}
198contractAddress {}
199cumulativeGasUsed {}
200effectiveGasPrice {}
201from {}
202gasUsed {}
203logs {}
204logsBloom {}
205root {}
206status {}
207transactionHash {}
208transactionIndex {}
209type {}
210blobGasPrice {}
211blobGasUsed {}",
212 receipt.block_hash.pretty(),
213 receipt.block_number.pretty(),
214 receipt.contract_address.pretty(),
215 receipt.inner.cumulative_gas_used().pretty(),
216 receipt.effective_gas_price.pretty(),
217 receipt.from.pretty(),
218 receipt.gas_used.pretty(),
219 serde_json::to_string(receipt.inner.logs()).unwrap(),
220 receipt.inner.bloom().pretty(),
221 receipt.inner.status_or_post_state().as_post_state().pretty(),
222 receipt.inner.status_or_post_state().pretty(),
223 receipt.transaction_hash.pretty(),
224 receipt.transaction_index.pretty(),
225 tx_type,
226 receipt.blob_gas_price.pretty(),
227 receipt.blob_gas_used.pretty()
228 );
229
230 if let Some(to) = receipt.to {
231 pretty.push_str(&format!("\nto {}", to.pretty()));
232 }
233
234 pretty
235}
236
237impl UIfmt for TransactionReceipt {
238 fn pretty(&self) -> String {
239 pretty_receipt(self, self.transaction_type() as u8)
240 }
241}
242
243#[cfg(feature = "base")]
244impl UIfmt for BaseTransactionReceipt {
245 fn pretty(&self) -> String {
246 let (deposit_nonce, deposit_receipt_version) = match &self.inner.inner.receipt {
247 BaseReceipt::Deposit(receipt) => {
248 (receipt.deposit_nonce, receipt.deposit_receipt_version)
249 }
250 _ => (None, None),
251 };
252 format!(
253 "{}
254l1GasPrice {}
255l1GasUsed {}
256l1Fee {}
257l1FeeScalar {}
258l1BaseFeeScalar {}
259l1BlobBaseFee {}
260l1BlobBaseFeeScalar {}
261operatorFeeScalar {}
262operatorFeeConstant {}
263daFootprintGasScalar {}
264depositNonce {}
265depositReceiptVersion {}
266payer {}
267phaseStatuses {}
268metadata {}",
269 pretty_receipt(&self.inner, self.inner.inner.receipt.tx_type() as u8).trim_end(),
270 self.l1_block_info.l1_gas_price.pretty(),
271 self.l1_block_info.l1_gas_used.pretty(),
272 self.l1_block_info.l1_fee.pretty(),
273 self.l1_block_info.l1_fee_scalar.map(|value| value.to_string()).unwrap_or_default(),
274 self.l1_block_info.l1_base_fee_scalar.pretty(),
275 self.l1_block_info.l1_blob_base_fee.pretty(),
276 self.l1_block_info.l1_blob_base_fee_scalar.pretty(),
277 self.l1_block_info.operator_fee_scalar.pretty(),
278 self.l1_block_info.operator_fee_constant.pretty(),
279 self.l1_block_info
280 .da_footprint_gas_scalar
281 .map(|value| value.to_string())
282 .unwrap_or_default(),
283 deposit_nonce.pretty(),
284 deposit_receipt_version.pretty(),
285 self.payer.pretty(),
286 self.phase_statuses.pretty(),
287 self.metadata.pretty(),
288 )
289 }
290}
291
292impl UIfmt for AnyTransactionReceipt {
293 fn pretty(&self) -> String {
294 let mut pretty = pretty_receipt(&self.inner, self.inner.inner.r#type);
295 pretty.push_str(&self.other.pretty());
296 pretty
297 }
298}
299
300impl UIfmt for Log {
301 fn pretty(&self) -> String {
302 format!(
303 "
304address: {}
305blockHash: {}
306blockNumber: {}
307data: {}
308logIndex: {}
309removed: {}
310topics: {}
311transactionHash: {}
312transactionIndex: {}",
313 self.address().pretty(),
314 self.block_hash.pretty(),
315 self.block_number.pretty(),
316 self.data().data.pretty(),
317 self.log_index.pretty(),
318 self.removed.pretty(),
319 self.topics().pretty(),
320 self.transaction_hash.pretty(),
321 self.transaction_index.pretty(),
322 )
323 }
324}
325
326impl<T: UIfmt, H: HeaderResponse + UIfmtHeaderExt> UIfmt for Block<T, H> {
327 fn pretty(&self) -> String {
328 format!(
329 "
330{}
331transactions: {}",
332 pretty_generic_header_response(&self.header),
333 self.transactions.pretty()
334 )
335 }
336}
337
338impl<T: UIfmt> UIfmt for BlockTransactions<T> {
339 fn pretty(&self) -> String {
340 match self {
341 Self::Hashes(hashes) => hashes.pretty(),
342 Self::Full(transactions) => transactions.pretty(),
343 Self::Uncle => String::new(),
344 }
345 }
346}
347
348impl UIfmt for OtherFields {
349 fn pretty(&self) -> String {
350 let mut s = String::with_capacity(self.len() * 30);
351 if !self.is_empty() {
352 s.push('\n');
353 }
354 for (key, value) in self {
355 let val = EthValue::from(value.clone()).pretty();
356 let offset = NAME_COLUMN_LEN.saturating_sub(key.len());
357 s.push_str(key);
358 s.extend(std::iter::repeat_n(' ', offset + 1));
359 s.push_str(&val);
360 s.push('\n');
361 }
362 s
363 }
364}
365
366impl UIfmt for AccessListItem {
367 fn pretty(&self) -> String {
368 let mut s = String::with_capacity(42 + self.storage_keys.len() * 66);
369 s.push_str(self.address.pretty().as_str());
370 s.push_str(" => ");
371 s.push_str(self.storage_keys.pretty().as_str());
372 s
373 }
374}
375
376impl UIfmt for TxLegacy {
377 fn pretty(&self) -> String {
378 format!(
379 "
380chainId {}
381nonce {}
382gasPrice {}
383gasLimit {}
384to {}
385value {}
386input {}",
387 self.chain_id.pretty(),
388 self.nonce.pretty(),
389 self.gas_price.pretty(),
390 self.gas_limit.pretty(),
391 self.to().pretty(),
392 self.value.pretty(),
393 self.input.pretty(),
394 )
395 }
396}
397
398impl UIfmt for TxEip2930 {
399 fn pretty(&self) -> String {
400 format!(
401 "
402chainId {}
403nonce {}
404gasPrice {}
405gasLimit {}
406to {}
407value {}
408accessList {}
409input {}",
410 self.chain_id.pretty(),
411 self.nonce.pretty(),
412 self.gas_price.pretty(),
413 self.gas_limit.pretty(),
414 self.to().pretty(),
415 self.value.pretty(),
416 self.access_list.pretty(),
417 self.input.pretty(),
418 )
419 }
420}
421
422impl UIfmt for TxEip1559 {
423 fn pretty(&self) -> String {
424 format!(
425 "
426chainId {}
427nonce {}
428gasLimit {}
429maxFeePerGas {}
430maxPriorityFeePerGas {}
431to {}
432value {}
433accessList {}
434input {}",
435 self.chain_id.pretty(),
436 self.nonce.pretty(),
437 self.gas_limit.pretty(),
438 self.max_fee_per_gas.pretty(),
439 self.max_priority_fee_per_gas.pretty(),
440 self.to().pretty(),
441 self.value.pretty(),
442 self.access_list.pretty(),
443 self.input.pretty(),
444 )
445 }
446}
447
448impl UIfmt for TxEip4844Variant {
449 fn pretty(&self) -> String {
450 use alloy_consensus::TxEip4844;
451 let tx: &TxEip4844 = match self {
452 Self::TxEip4844(tx) => tx,
453 Self::TxEip4844WithSidecar(tx) => tx.tx(),
454 };
455 format!(
456 "
457chainId {}
458nonce {}
459gasLimit {}
460maxFeePerGas {}
461maxPriorityFeePerGas {}
462to {}
463value {}
464accessList {}
465blobVersionedHashes {}
466maxFeePerBlobGas {}
467input {}",
468 tx.chain_id.pretty(),
469 tx.nonce.pretty(),
470 tx.gas_limit.pretty(),
471 tx.max_fee_per_gas.pretty(),
472 tx.max_priority_fee_per_gas.pretty(),
473 tx.to.pretty(),
474 tx.value.pretty(),
475 tx.access_list.pretty(),
476 tx.blob_versioned_hashes.pretty(),
477 tx.max_fee_per_blob_gas.pretty(),
478 tx.input.pretty(),
479 )
480 }
481}
482
483impl UIfmt for TxEip7702 {
484 fn pretty(&self) -> String {
485 format!(
486 "
487chainId {}
488nonce {}
489gasLimit {}
490maxFeePerGas {}
491maxPriorityFeePerGas {}
492to {}
493value {}
494accessList {}
495authorizationList {}
496input {}",
497 self.chain_id.pretty(),
498 self.nonce.pretty(),
499 self.gas_limit.pretty(),
500 self.max_fee_per_gas.pretty(),
501 self.max_priority_fee_per_gas.pretty(),
502 self.to.pretty(),
503 self.value.pretty(),
504 self.access_list.pretty(),
505 self.authorization_list.pretty(),
506 self.input.pretty(),
507 )
508 }
509}
510
511#[cfg(feature = "optimism")]
512impl UIfmt for TxDeposit {
513 fn pretty(&self) -> String {
514 format!(
515 "
516sourceHash {}
517from {}
518to {}
519mint {}
520value {}
521gasLimit {}
522isSystemTransaction {}
523input {}",
524 self.source_hash.pretty(),
525 self.from.pretty(),
526 self.to().pretty(),
527 self.mint.pretty(),
528 self.value.pretty(),
529 self.gas_limit.pretty(),
530 self.is_system_transaction,
531 self.input.pretty(),
532 )
533 }
534}
535
536#[cfg(feature = "base")]
537impl UIfmt for BaseTxDeposit {
538 fn pretty(&self) -> String {
539 format!(
540 "
541sourceHash {}
542from {}
543to {}
544mint {}
545value {}
546gasLimit {}
547isSystemTransaction {}
548input {}",
549 self.source_hash.pretty(),
550 self.from.pretty(),
551 self.to().pretty(),
552 self.mint.pretty(),
553 self.value.pretty(),
554 self.gas_limit.pretty(),
555 self.is_system_transaction,
556 self.input.pretty(),
557 )
558 }
559}
560
561#[cfg(feature = "base")]
562impl UIfmt for Eip8130Signed {
563 fn pretty(&self) -> String {
564 let tx = self.tx();
565 format!(
568 "
569chainId {}
570sender {}
571payer {}
572nonceKey {}
573nonceSequence {}
574validAfter {}
575validBefore {}
576maxFeePerGas {}
577maxPriorityFeePerGas {}
578gasLimit {}
579accountChanges {}
580callPhases {}
581calls {}
582metadata {}
583senderAuth {}
584payerAuth {}",
585 tx.chain_id.pretty(),
586 tx.sender.pretty(),
587 tx.payer.pretty(),
588 tx.nonce_key.pretty(),
589 tx.nonce_sequence.pretty(),
590 tx.valid_after.pretty(),
591 tx.valid_before.pretty(),
592 tx.max_fee_per_gas.pretty(),
593 tx.max_priority_fee_per_gas.pretty(),
594 tx.gas_limit.pretty(),
595 tx.account_changes.len(),
596 tx.calls.len(),
597 tx.calls.iter().map(Vec::len).sum::<usize>(),
598 tx.metadata.pretty(),
599 self.sender_auth().pretty(),
600 self.payer_auth().pretty(),
601 )
602 }
603}
604
605#[cfg(feature = "optimism")]
606impl UIfmt for TxPostExec {
607 fn pretty(&self) -> String {
608 format!(
609 "
610blockNumber {}
611gasRefundEntries {:?}
612input {}",
613 self.payload.block_number.pretty(),
614 self.payload.gas_refund_entries,
615 self.input.pretty(),
616 )
617 }
618}
619
620impl UIfmt for Call {
621 fn pretty(&self) -> String {
622 format!(
623 "to: {}, value: {}, input: {}",
624 self.to.into_to().pretty(),
625 self.value.pretty(),
626 self.input.pretty(),
627 )
628 }
629}
630
631impl UIfmt for TempoTransaction {
632 fn pretty(&self) -> String {
633 format!(
634 "
635chainId {}
636feeToken {}
637maxPriorityFeePerGas {}
638maxFeePerGas {}
639gasLimit {}
640calls {}
641accessList {}
642nonceKey {}
643nonce {}
644feePayerSignature {}
645validBefore {}
646validAfter {}",
647 self.chain_id.pretty(),
648 self.fee_token.pretty(),
649 self.max_priority_fee_per_gas.pretty(),
650 self.max_fee_per_gas.pretty(),
651 self.gas_limit.pretty(),
652 self.calls.pretty(),
653 self.access_list.pretty(),
654 self.nonce_key.pretty(),
655 self.nonce.pretty(),
656 self.fee_payer_signature.pretty(),
657 self.valid_before.pretty(),
658 self.valid_after.pretty(),
659 )
660 }
661}
662
663impl UIfmt for TempoSignature {
664 fn pretty(&self) -> String {
665 serde_json::to_string(self).unwrap_or_default()
666 }
667}
668
669impl UIfmt for AASigned {
670 fn pretty(&self) -> String {
671 format!(
672 "
673hash {}
674type {}
675{}
676tempoSignature {}",
677 self.hash().pretty(),
678 self.tx().ty(),
679 self.tx().pretty().trim_start(),
680 self.signature().pretty(),
681 )
682 }
683}
684
685impl<T: UIfmt + Typed2718> UIfmt for Signed<T>
686where
687 Self: TxHashRef,
688{
689 fn pretty(&self) -> String {
690 format!(
691 "
692hash {}
693type {}
694{}
695r {}
696s {}
697yParity {}",
698 self.tx_hash().pretty(),
699 self.ty(),
700 self.tx().pretty().trim_start(),
701 FixedBytes::from(self.signature().r()).pretty(),
702 FixedBytes::from(self.signature().s()).pretty(),
703 (if self.signature().v() { 1u64 } else { 0 }).pretty(),
704 )
705 }
706}
707
708impl UIfmt for TxEnvelope {
709 fn pretty(&self) -> String {
710 match self {
711 Self::Legacy(tx) => tx.pretty(),
712 Self::Eip2930(tx) => tx.pretty(),
713 Self::Eip1559(tx) => tx.pretty(),
714 Self::Eip4844(tx) => tx.pretty(),
715 Self::Eip7702(tx) => tx.pretty(),
716 }
717 }
718}
719
720#[cfg(feature = "base")]
721impl UIfmt for BaseTxEnvelope {
722 fn pretty(&self) -> String {
723 match self {
724 Self::Legacy(tx) => tx.pretty(),
725 Self::Eip2930(tx) => tx.pretty(),
726 Self::Eip1559(tx) => tx.pretty(),
727 Self::Eip7702(tx) => tx.pretty(),
728 Self::Deposit(tx) => tx.inner().pretty(),
729 Self::Eip8130(tx) => tx.pretty(),
730 }
731 }
732}
733
734impl UIfmt for AnyTxEnvelope {
735 fn pretty(&self) -> String {
736 match self {
737 Self::Ethereum(envelop) => envelop.pretty(),
738 Self::Unknown(tx) => {
739 format!(
740 "
741hash {}
742type {:#x}
743{}
744 ",
745 tx.hash.pretty(),
746 tx.ty(),
747 tx.inner.fields.pretty().trim_start(),
748 )
749 }
750 }
751 }
752}
753
754#[cfg(feature = "optimism")]
755impl UIfmt for OpTxEnvelope {
756 fn pretty(&self) -> String {
757 match self {
758 Self::Legacy(tx) => tx.pretty(),
759 Self::Eip2930(tx) => tx.pretty(),
760 Self::Eip1559(tx) => tx.pretty(),
761 Self::Eip7702(tx) => tx.pretty(),
762 Self::Deposit(tx) => tx.pretty(),
763 Self::PostExec(tx) => tx.pretty(),
764 }
765 }
766}
767
768impl UIfmt for TempoTxEnvelope {
769 fn pretty(&self) -> String {
770 match self {
771 Self::Legacy(tx) => tx.pretty(),
772 Self::Eip2930(tx) => tx.pretty(),
773 Self::Eip1559(tx) => tx.pretty(),
774 Self::Eip7702(tx) => tx.pretty(),
775 Self::AA(tx) => tx.pretty(),
776 }
777 }
778}
779
780impl<T: UIfmt> UIfmt for Transaction<T> {
781 fn pretty(&self) -> String {
782 format!(
783 "
784blockHash {}
785blockNumber {}
786from {}
787transactionIndex {}
788effectiveGasPrice {}
789{}",
790 self.block_hash.pretty(),
791 self.block_number.pretty(),
792 self.inner.signer().pretty(),
793 self.transaction_index.pretty(),
794 self.effective_gas_price.pretty(),
795 self.inner.inner().pretty().trim_start(),
796 )
797 }
798}
799
800#[cfg(feature = "base")]
801impl UIfmt for BaseRpcTransaction {
802 fn pretty(&self) -> String {
803 format!(
804 "
805depositNonce {}
806depositReceiptVersion {}
807{}",
808 self.deposit_nonce.pretty(),
809 self.deposit_receipt_version.pretty(),
810 self.inner.pretty().trim_start(),
811 )
812 }
813}
814
815#[cfg(feature = "optimism")]
816impl<T: UIfmt> UIfmt for op_alloy_rpc_types::Transaction<T> {
817 fn pretty(&self) -> String {
818 format!(
819 "
820depositNonce {}
821depositReceiptVersion {}
822{}",
823 self.deposit_nonce.pretty(),
824 self.deposit_receipt_version.pretty(),
825 self.inner.pretty().trim_start(),
826 )
827 }
828}
829
830impl UIfmt for AnyRpcBlock {
831 fn pretty(&self) -> String {
832 self.0.pretty()
833 }
834}
835
836impl UIfmt for AnyRpcTransaction {
837 fn pretty(&self) -> String {
838 self.0.pretty()
839 }
840}
841
842impl<T: UIfmt> UIfmt for WithOtherFields<T> {
843 fn pretty(&self) -> String {
844 format!("{}{}", self.inner.pretty(), self.other.pretty())
845 }
846}
847
848#[derive(Clone, Debug, Deserialize)]
850#[serde(untagged)]
851#[expect(missing_docs)]
852pub enum EthValue {
853 U64(U64),
854 Address(Address),
855 U256(U256),
856 U64Array(Vec<U64>),
857 U256Array(Vec<U256>),
858 Other(serde_json::Value),
859}
860
861impl From<serde_json::Value> for EthValue {
862 fn from(val: serde_json::Value) -> Self {
863 serde_json::from_value(val).expect("infallible")
864 }
865}
866
867impl UIfmt for EthValue {
868 fn pretty(&self) -> String {
869 match self {
870 Self::U64(num) => num.pretty(),
871 Self::U256(num) => num.pretty(),
872 Self::Address(addr) => addr.pretty(),
873 Self::U64Array(arr) => arr.pretty(),
874 Self::U256Array(arr) => arr.pretty(),
875 Self::Other(val) => val.to_string().trim_matches('"').to_string(),
876 }
877 }
878}
879
880impl UIfmt for SignedAuthorization {
881 fn pretty(&self) -> String {
882 let signed_authorization = serde_json::to_string(self).unwrap_or("<invalid>".to_string());
883
884 match self.recover_authority() {
885 Ok(authority) => format!(
886 "{{recoveredAuthority: {authority}, signedAuthority: {signed_authorization}}}",
887 ),
888 Err(e) => format!(
889 "{{recoveredAuthority: <error: {e}>, signedAuthority: {signed_authorization}}}",
890 ),
891 }
892 }
893}
894
895pub trait UIfmtHeaderExt {
896 fn size_pretty(&self) -> String;
897 fn total_difficulty_pretty(&self) -> String;
898}
899
900impl UIfmtHeaderExt for Header {
901 fn size_pretty(&self) -> String {
902 self.size.pretty()
903 }
904
905 fn total_difficulty_pretty(&self) -> String {
906 self.total_difficulty.unwrap_or_else(|| self.difficulty()).pretty()
907 }
908}
909
910impl UIfmtHeaderExt for AnyRpcHeader {
911 fn size_pretty(&self) -> String {
912 self.size.pretty()
913 }
914
915 fn total_difficulty_pretty(&self) -> String {
916 self.total_difficulty.unwrap_or_else(|| self.difficulty()).pretty()
917 }
918}
919
920impl UIfmtHeaderExt for TempoHeaderResponse {
921 fn size_pretty(&self) -> String {
922 self.inner.size.pretty()
923 }
924
925 fn total_difficulty_pretty(&self) -> String {
926 self.inner.total_difficulty.unwrap_or_else(|| self.inner.difficulty()).pretty()
927 }
928}
929
930pub trait UIfmtSignatureExt {
931 fn signature_pretty(&self) -> Option<(String, String, String)>;
932}
933
934impl UIfmtSignatureExt for TxEnvelope {
935 fn signature_pretty(&self) -> Option<(String, String, String)> {
936 Some(pretty_signature_fields(self.signature()))
937 }
938}
939
940impl UIfmtSignatureExt for AnyTxEnvelope {
941 fn signature_pretty(&self) -> Option<(String, String, String)> {
942 self.as_envelope().and_then(|envelope| envelope.signature_pretty())
943 }
944}
945
946#[cfg(feature = "base")]
947impl UIfmtSignatureExt for BaseTxEnvelope {
948 fn signature_pretty(&self) -> Option<(String, String, String)> {
949 self.signature().map(pretty_signature_fields)
950 }
951}
952
953#[cfg(feature = "optimism")]
954impl UIfmtSignatureExt for OpTxEnvelope {
955 fn signature_pretty(&self) -> Option<(String, String, String)> {
956 self.signature().map(pretty_signature_fields)
957 }
958}
959
960impl UIfmtSignatureExt for TempoTxEnvelope {
961 fn signature_pretty(&self) -> Option<(String, String, String)> {
962 let sig = match self {
963 Self::Legacy(tx) => Some(tx.signature()),
964 Self::Eip2930(tx) => Some(tx.signature()),
965 Self::Eip1559(tx) => Some(tx.signature()),
966 Self::Eip7702(tx) => Some(tx.signature()),
967 Self::AA(tempo_tx) => {
968 if let TempoSignature::Primitive(PrimitiveSignature::Secp256k1(sig)) =
969 tempo_tx.signature()
970 {
971 Some(sig)
972 } else {
973 None
974 }
975 }
976 }?;
977 Some(pretty_signature_fields(sig))
978 }
979}
980
981fn pretty_signature_fields(signature: &Signature) -> (String, String, String) {
982 (
983 FixedBytes::from(signature.r()).pretty(),
984 FixedBytes::from(signature.s()).pretty(),
985 U8::from_le_slice(&signature.as_bytes()[64..]).pretty(),
986 )
987}
988
989pub trait UIfmtReceiptExt {
990 fn logs_pretty(&self) -> String;
991 fn logs_bloom_pretty(&self) -> String;
992 fn tx_type_pretty(&self) -> String;
993}
994
995fn receipt_logs_pretty<T: TxReceipt>(receipt: &TransactionReceipt<T>) -> String
996where
997 T::Log: Serialize,
998{
999 serde_json::to_string(receipt.inner.logs()).unwrap_or_default()
1000}
1001
1002fn receipt_logs_bloom_pretty<T: TxReceipt>(receipt: &TransactionReceipt<T>) -> String {
1003 receipt.inner.bloom().pretty()
1004}
1005
1006impl UIfmtReceiptExt for TransactionReceipt {
1007 fn logs_pretty(&self) -> String {
1008 receipt_logs_pretty(self)
1009 }
1010
1011 fn logs_bloom_pretty(&self) -> String {
1012 receipt_logs_bloom_pretty(self)
1013 }
1014
1015 fn tx_type_pretty(&self) -> String {
1016 self.transaction_type().to_string()
1017 }
1018}
1019
1020#[cfg(feature = "base")]
1021impl UIfmtReceiptExt for BaseTransactionReceipt {
1022 fn logs_pretty(&self) -> String {
1023 receipt_logs_pretty(&self.inner)
1024 }
1025
1026 fn logs_bloom_pretty(&self) -> String {
1027 receipt_logs_bloom_pretty(&self.inner)
1028 }
1029
1030 fn tx_type_pretty(&self) -> String {
1031 self.inner.inner.receipt.tx_type().to_string()
1032 }
1033}
1034
1035impl UIfmtReceiptExt for AnyTransactionReceipt {
1036 fn logs_pretty(&self) -> String {
1037 receipt_logs_pretty(&self.inner)
1038 }
1039
1040 fn logs_bloom_pretty(&self) -> String {
1041 receipt_logs_bloom_pretty(&self.inner)
1042 }
1043
1044 fn tx_type_pretty(&self) -> String {
1045 self.inner.inner.r#type.to_string()
1046 }
1047}
1048
1049impl UIfmt for TempoTransactionReceipt {
1050 fn pretty(&self) -> String {
1051 let receipt = &self.inner;
1052
1053 let mut pretty = format!(
1054 "
1055blockHash {}
1056blockNumber {}
1057contractAddress {}
1058cumulativeGasUsed {}
1059effectiveGasPrice {}
1060from {}
1061gasUsed {}
1062logs {}
1063logsBloom {}
1064root {}
1065status {}
1066transactionHash {}
1067transactionIndex {}
1068type {}
1069feePayer {}
1070feeToken {}",
1071 receipt.block_hash().pretty(),
1072 receipt.block_number().pretty(),
1073 receipt.contract_address().pretty(),
1074 receipt.cumulative_gas_used().pretty(),
1075 receipt.effective_gas_price().pretty(),
1076 receipt.from().pretty(),
1077 receipt.gas_used().pretty(),
1078 serde_json::to_string(receipt.inner.logs()).unwrap(),
1079 receipt.inner.logs_bloom.pretty(),
1080 self.state_root().pretty(),
1081 receipt.status().pretty(),
1082 receipt.transaction_hash().pretty(),
1083 receipt.transaction_index().pretty(),
1084 receipt.inner.receipt.tx_type as u8,
1085 self.fee_payer.pretty(),
1086 self.fee_token.pretty(),
1087 );
1088
1089 if let Some(to) = receipt.to() {
1090 pretty.push_str(&format!("\nto {}", to.pretty()));
1091 }
1092
1093 pretty
1094 }
1095}
1096
1097impl UIfmtReceiptExt for TempoTransactionReceipt {
1098 fn logs_pretty(&self) -> String {
1099 serde_json::to_string(self.inner.inner.logs()).unwrap_or_default()
1100 }
1101
1102 fn logs_bloom_pretty(&self) -> String {
1103 self.inner.inner.logs_bloom.pretty()
1104 }
1105
1106 fn tx_type_pretty(&self) -> String {
1107 (self.inner.inner.receipt.tx_type as u8).to_string()
1108 }
1109}
1110
1111pub fn get_pretty_tx_attr<N>(transaction: &N::TransactionResponse, attr: &str) -> Option<String>
1113where
1114 N: Network,
1115 N::TxEnvelope: UIfmtSignatureExt,
1116{
1117 let (r, s, v) = transaction.as_ref().signature_pretty().unwrap_or_default();
1118 match attr {
1119 "blockHash" | "block_hash" => {
1120 Some(alloy_network::TransactionResponse::block_hash(transaction).pretty())
1121 }
1122 "blockNumber" | "block_number" => {
1123 Some(alloy_network::TransactionResponse::block_number(transaction).pretty())
1124 }
1125 "from" => Some(alloy_network::TransactionResponse::from(transaction).pretty()),
1126 "gas" => Some(TxTrait::gas_limit(transaction).pretty()),
1127 "gasPrice" | "gas_price" => Some(TxTrait::max_fee_per_gas(transaction).pretty()),
1128 "hash" => Some(alloy_network::TransactionResponse::tx_hash(transaction).pretty()),
1129 "input" => Some(TxTrait::input(transaction).pretty()),
1130 "nonce" => Some(TxTrait::nonce(transaction).to_string()),
1131 "s" => Some(s),
1132 "r" => Some(r),
1133 "to" => Some(TxTrait::to(transaction).pretty()),
1134 "transactionIndex" | "transaction_index" => {
1135 Some(alloy_network::TransactionResponse::transaction_index(transaction).pretty())
1136 }
1137 "v" => Some(v),
1138 "value" => Some(TxTrait::value(transaction).pretty()),
1139 _ => None,
1140 }
1141}
1142
1143pub fn get_pretty_block_attr<N>(block: &N::BlockResponse, attr: &str) -> Option<String>
1144where
1145 N: Network,
1146 N::BlockResponse: BlockResponse<Header = N::HeaderResponse>,
1147 N::HeaderResponse: UIfmtHeaderExt,
1148{
1149 match attr {
1150 "baseFeePerGas" | "base_fee_per_gas" => Some(block.header().base_fee_per_gas().pretty()),
1151 "difficulty" => Some(block.header().difficulty().pretty()),
1152 "extraData" | "extra_data" => Some(block.header().extra_data().pretty()),
1153 "gasLimit" | "gas_limit" => Some(block.header().gas_limit().pretty()),
1154 "gasUsed" | "gas_used" => Some(block.header().gas_used().pretty()),
1155 "hash" => Some(block.header().hash().pretty()),
1156 "logsBloom" | "logs_bloom" => Some(block.header().logs_bloom().pretty()),
1157 "miner" | "author" => Some(block.header().beneficiary().pretty()),
1158 "mixHash" | "mix_hash" => Some(block.header().mix_hash().pretty()),
1159 "nonce" => Some(block.header().nonce().pretty()),
1160 "number" => Some(block.header().number().pretty()),
1161 "parentHash" | "parent_hash" => Some(block.header().parent_hash().pretty()),
1162 "transactionsRoot" | "transactions_root" => {
1163 Some(block.header().transactions_root().pretty())
1164 }
1165 "receiptsRoot" | "receipts_root" => Some(block.header().receipts_root().pretty()),
1166 "sha3Uncles" | "sha_3_uncles" => Some(block.header().ommers_hash().pretty()),
1167 "size" => Some(block.header().size_pretty()),
1168 "stateRoot" | "state_root" => Some(block.header().state_root().pretty()),
1169 "timestamp" => Some(block.header().timestamp().pretty()),
1170 "totalDifficulty" | "total_difficulty" => Some(block.header().total_difficulty_pretty()),
1171 "blobGasUsed" | "blob_gas_used" => Some(block.header().blob_gas_used().pretty()),
1172 "excessBlobGas" | "excess_blob_gas" => Some(block.header().excess_blob_gas().pretty()),
1173 "requestsHash" | "requests_hash" => Some(block.header().requests_hash().pretty()),
1174 other => {
1175 if let Some(value) = block.other_fields().and_then(|fields| fields.get(other)) {
1176 let val = EthValue::from(value.clone());
1177 return Some(val.pretty());
1178 }
1179 None
1180 }
1181 }
1182}
1183
1184pub fn get_pretty_receipt_attr<N>(receipt: &N::ReceiptResponse, attr: &str) -> Option<String>
1185where
1186 N: Network,
1187 N::ReceiptResponse: ReceiptResponse + UIfmtReceiptExt,
1188{
1189 match attr {
1190 "blockHash" | "block_hash" => Some(receipt.block_hash().pretty()),
1191 "blockNumber" | "block_number" => Some(receipt.block_number().pretty()),
1192 "contractAddress" | "contract_address" => Some(receipt.contract_address().pretty()),
1193 "cumulativeGasUsed" | "cumulative_gas_used" => Some(receipt.cumulative_gas_used().pretty()),
1194 "effectiveGasPrice" | "effective_gas_price" => Some(receipt.effective_gas_price().pretty()),
1195 "from" => Some(receipt.from().pretty()),
1196 "gasUsed" | "gas_used" => Some(receipt.gas_used().pretty()),
1197 "logs" => Some(receipt.logs_pretty()),
1198 "logsBloom" | "logs_bloom" => Some(receipt.logs_bloom_pretty()),
1199 "root" | "stateRoot" | "state_root" => Some(receipt.state_root().pretty()),
1200 "status" | "statusCode" | "status_code" => Some(receipt.status().pretty()),
1201 "transactionHash" | "transaction_hash" => Some(receipt.transaction_hash().pretty()),
1202 "transactionIndex" | "transaction_index" => Some(receipt.transaction_index().pretty()),
1203 "to" => Some(receipt.to().pretty()),
1204 "type" | "transaction_type" => Some(receipt.tx_type_pretty()),
1205 "blobGasPrice" | "blob_gas_price" => Some(receipt.blob_gas_price().pretty()),
1206 "blobGasUsed" | "blob_gas_used" => Some(receipt.blob_gas_used().pretty()),
1207 _ => None,
1208 }
1209}
1210
1211fn pretty_generic_header_response<H: HeaderResponse + UIfmtHeaderExt>(header: &H) -> String {
1212 format!(
1213 "
1214baseFeePerGas {}
1215difficulty {}
1216extraData {}
1217gasLimit {}
1218gasUsed {}
1219hash {}
1220logsBloom {}
1221miner {}
1222mixHash {}
1223nonce {}
1224number {}
1225parentHash {}
1226parentBeaconRoot {}
1227transactionsRoot {}
1228receiptsRoot {}
1229sha3Uncles {}
1230size {}
1231stateRoot {}
1232timestamp {} ({})
1233withdrawalsRoot {}
1234totalDifficulty {}
1235blobGasUsed {}
1236excessBlobGas {}
1237requestsHash {}",
1238 header.base_fee_per_gas().pretty(),
1239 header.difficulty().pretty(),
1240 header.extra_data().pretty(),
1241 header.gas_limit().pretty(),
1242 header.gas_used().pretty(),
1243 header.hash().pretty(),
1244 header.logs_bloom().pretty(),
1245 header.beneficiary().pretty(),
1246 header.mix_hash().pretty(),
1247 header.nonce().pretty(),
1248 header.number().pretty(),
1249 header.parent_hash().pretty(),
1250 header.parent_beacon_block_root().pretty(),
1251 header.transactions_root().pretty(),
1252 header.receipts_root().pretty(),
1253 header.ommers_hash().pretty(),
1254 header.size_pretty(),
1255 header.state_root().pretty(),
1256 header.timestamp().pretty(),
1257 fmt_timestamp(header.timestamp()),
1258 header.withdrawals_root().pretty(),
1259 header.total_difficulty_pretty(),
1260 header.blob_gas_used().pretty(),
1261 header.excess_blob_gas().pretty(),
1262 header.requests_hash().pretty(),
1263 )
1264}
1265
1266fn fmt_timestamp(timestamp: u64) -> String {
1270 if timestamp > 2147483647 {
1272 chrono::DateTime::from_timestamp_millis(timestamp as i64)
1274 .expect("block timestamp in range")
1275 .to_rfc3339()
1276 } else {
1277 chrono::DateTime::from_timestamp(timestamp as i64, 0)
1279 .expect("block timestamp in range")
1280 .to_rfc2822()
1281 }
1282}
1283
1284#[cfg(test)]
1285mod tests {
1286 use super::*;
1287 use alloy_network::Ethereum;
1288 use alloy_primitives::B256;
1289 use alloy_rpc_types::Authorization;
1290 use similar_asserts::assert_eq;
1291 use std::str::FromStr;
1292
1293 #[cfg(feature = "base")]
1294 use base_common_consensus::{Call as BaseCall, TxEip8130};
1295
1296 #[test]
1297 fn format_date_time() {
1298 let timestamp = 1756454738u64;
1300
1301 let datetime = fmt_timestamp(timestamp);
1302 assert_eq!(datetime, "Fri, 29 Aug 2025 08:05:38 +0000");
1303 let datetime = fmt_timestamp(timestamp * 1000);
1304 assert_eq!(datetime, "2025-08-29T08:05:38+00:00");
1305 }
1306
1307 #[test]
1308 fn can_format_bytes32() {
1309 let val = hex::decode("7465737400000000000000000000000000000000000000000000000000000000")
1310 .unwrap();
1311 let mut b32 = [0u8; 32];
1312 b32.copy_from_slice(&val);
1313
1314 assert_eq!(
1315 b32.pretty(),
1316 "0x7465737400000000000000000000000000000000000000000000000000000000"
1317 );
1318 let b: Bytes = val.into();
1319 assert_eq!(b.pretty(), b32.pretty());
1320 }
1321
1322 #[cfg(feature = "base")]
1323 #[test]
1324 fn can_pretty_print_eip8130_transaction() {
1325 let base_call = BaseCall { to: Address::ZERO, data: Bytes::new() };
1326 let tx = TxEip8130 {
1327 chain_id: 8453,
1328 sender: Some(Address::with_last_byte(0x11)),
1329 payer: Some(Address::with_last_byte(0x22)),
1330 nonce_key: U256::from(7),
1331 nonce_sequence: 3,
1332 valid_after: 100,
1333 valid_before: 200,
1334 max_fee_per_gas: 1_000,
1335 max_priority_fee_per_gas: 10,
1336 gas_limit: 21_000,
1337 metadata: Bytes::from_static(&[0xab]),
1338 calls: vec![vec![base_call.clone(), base_call.clone()], vec![base_call]],
1339 ..Default::default()
1340 };
1341 let signed =
1342 Eip8130Signed::new(tx, Bytes::from_static(&[0x01]), Bytes::from_static(&[0x02]));
1343
1344 assert_eq!(
1345 signed.pretty().trim(),
1346 r"chainId 8453
1347sender 0x0000000000000000000000000000000000000011
1348payer 0x0000000000000000000000000000000000000022
1349nonceKey 7
1350nonceSequence 3
1351validAfter 100
1352validBefore 200
1353maxFeePerGas 1000
1354maxPriorityFeePerGas 10
1355gasLimit 21000
1356accountChanges 0
1357callPhases 2
1358calls 3
1359metadata 0xab
1360senderAuth 0x01
1361payerAuth 0x02"
1362 );
1363 }
1364
1365 #[cfg(feature = "base")]
1366 #[test]
1367 fn can_pretty_print_base_deposit_receipt_fields() {
1368 let receipt: BaseTransactionReceipt = serde_json::from_value(serde_json::json!({
1369 "blockHash": "0x9e6a0fb7e22159d943d760608cc36a0fb596d1ab3c997146f5b7c55c8c718c67",
1370 "blockNumber": "0x6cfef89",
1371 "contractAddress": null,
1372 "cumulativeGasUsed": "0xfa0d",
1373 "depositNonce": "0x8a2d11",
1374 "depositReceiptVersion": "0x1",
1375 "effectiveGasPrice": "0x0",
1376 "from": "0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001",
1377 "gasUsed": "0xfa0d",
1378 "logs": [{
1379 "address": "0x4200000000000000000000000000000000000015",
1380 "topics": [],
1381 "data": "0x",
1382 "removed": false,
1383 "blockTimestampMs": "0x18bcfe568c8",
1384 "blockNumber": "0x6cfef89",
1385 "blockHash": null,
1386 "transactionHash": null,
1387 "transactionIndex": null,
1388 "logIndex": null
1389 }],
1390 "logsBloom": format!("0x{}", "00".repeat(256)),
1391 "status": "0x1",
1392 "to": "0x4200000000000000000000000000000000000015",
1393 "transactionHash": "0xb7c74afdeb7c89fb9de2c312f49b38cb7a850ba36e064734c5223a477e83fdc9",
1394 "transactionIndex": "0x0",
1395 "type": "0x7e",
1396 "l1GasPrice": "0x3ef12787",
1397 "l1GasUsed": "0x1177",
1398 "l1Fee": "0x5bf1ab43d",
1399 "l1BaseFeeScalar": "0x1",
1400 "l1BlobBaseFee": "0x600ab8f05e64",
1401 "l1BlobBaseFeeScalar": "0x1",
1402 "operatorFeeScalar": "0x1",
1403 "operatorFeeConstant": "0x1",
1404 "daFootprintGasScalar": "0x1"
1405 }))
1406 .unwrap();
1407
1408 let pretty = receipt.pretty();
1409 let logs = receipt.logs_pretty();
1410 assert_eq!(
1411 serde_json::from_str::<serde_json::Value>(&logs).unwrap()[0]["blockTimestampMs"],
1412 "0x18bcfe568c8"
1413 );
1414 assert!(pretty.contains(&format!("logs {logs}")), "{pretty}");
1415 assert_eq!(receipt.logs_bloom_pretty(), receipt.inner.inner.bloom().pretty());
1416 assert!(pretty.contains("l1Fee 24681034813"), "{pretty}");
1417 assert!(pretty.contains("operatorFeeScalar 1"), "{pretty}");
1418 assert!(pretty.contains("depositNonce 9055505"), "{pretty}");
1419 assert!(pretty.contains("depositReceiptVersion 1"), "{pretty}");
1420 }
1421
1422 #[cfg(feature = "optimism")]
1423 #[test]
1424 fn can_pretty_print_optimism_tx() {
1425 let s = r#"
1426 {
1427 "blockHash": "0x02b853cf50bc1c335b70790f93d5a390a35a166bea9c895e685cc866e4961cae",
1428 "blockNumber": "0x1b4",
1429 "from": "0x3b179DcfC5fAa677044c27dCe958e4BC0ad696A6",
1430 "gas": "0x11cbbdc",
1431 "gasPrice": "0x0",
1432 "hash": "0x2642e960d3150244e298d52b5b0f024782253e6d0b2c9a01dd4858f7b4665a3f",
1433 "input": "0xd294f093",
1434 "nonce": "0xa2",
1435 "to": "0x4a16A42407AA491564643E1dfc1fd50af29794eF",
1436 "transactionIndex": "0x0",
1437 "value": "0x0",
1438 "v": "0x38",
1439 "r": "0x6fca94073a0cf3381978662d46cf890602d3e9ccf6a31e4b69e8ecbd995e2bee",
1440 "s": "0xe804161a2b56a37ca1f6f4c4b8bce926587afa0d9b1acc5165e6556c959d583",
1441 "depositNonce": "",
1442 "depositReceiptVersion": "0x1"
1443 }
1444 "#;
1445
1446 let tx: op_alloy_rpc_types::Transaction<OpTxEnvelope> = serde_json::from_str(s).unwrap();
1447 assert_eq!(
1448 tx.pretty().trim(),
1449 r"
1450depositNonce
1451depositReceiptVersion 1
1452blockHash 0x02b853cf50bc1c335b70790f93d5a390a35a166bea9c895e685cc866e4961cae
1453blockNumber 436
1454from 0x3b179DcfC5fAa677044c27dCe958e4BC0ad696A6
1455transactionIndex 0
1456effectiveGasPrice 0
1457hash 0x2642e960d3150244e298d52b5b0f024782253e6d0b2c9a01dd4858f7b4665a3f
1458type 0
1459chainId 10
1460nonce 162
1461gasPrice 0
1462gasLimit 18660316
1463to 0x4a16A42407AA491564643E1dfc1fd50af29794eF
1464value 0
1465input 0xd294f093
1466r 0x6fca94073a0cf3381978662d46cf890602d3e9ccf6a31e4b69e8ecbd995e2bee
1467s 0x0e804161a2b56a37ca1f6f4c4b8bce926587afa0d9b1acc5165e6556c959d583
1468yParity 1
1469"
1470 .trim()
1471 );
1472 }
1473
1474 #[cfg(feature = "optimism")]
1475 #[test]
1476 fn can_pretty_print_optimism_tx_through_any() {
1477 let s = r#"
1478 {
1479 "blockHash": "0x02b853cf50bc1c335b70790f93d5a390a35a166bea9c895e685cc866e4961cae",
1480 "blockNumber": "0x1b4",
1481 "from": "0x3b179DcfC5fAa677044c27dCe958e4BC0ad696A6",
1482 "gas": "0x11cbbdc",
1483 "gasPrice": "0x0",
1484 "hash": "0x2642e960d3150244e298d52b5b0f024782253e6d0b2c9a01dd4858f7b4665a3f",
1485 "input": "0xd294f093",
1486 "nonce": "0xa2",
1487 "to": "0x4a16A42407AA491564643E1dfc1fd50af29794eF",
1488 "transactionIndex": "0x0",
1489 "value": "0x0",
1490 "v": "0x38",
1491 "r": "0x6fca94073a0cf3381978662d46cf890602d3e9ccf6a31e4b69e8ecbd995e2bee",
1492 "s": "0xe804161a2b56a37ca1f6f4c4b8bce926587afa0d9b1acc5165e6556c959d583",
1493 "queueOrigin": "sequencer",
1494 "txType": "",
1495 "l1TxOrigin": null,
1496 "l1BlockNumber": "0xc1a65c",
1497 "l1Timestamp": "0x60d34b60",
1498 "index": "0x1b3",
1499 "queueIndex": null,
1500 "rawTransaction": "0xf86681a28084011cbbdc944a16a42407aa491564643e1dfc1fd50af29794ef8084d294f09338a06fca94073a0cf3381978662d46cf890602d3e9ccf6a31e4b69e8ecbd995e2beea00e804161a2b56a37ca1f6f4c4b8bce926587afa0d9b1acc5165e6556c959d583"
1501 }
1502 "#;
1503
1504 let tx: WithOtherFields<Transaction<AnyTxEnvelope>> = serde_json::from_str(s).unwrap();
1505 assert_eq!(tx.pretty().trim(),
1506 r"
1507blockHash 0x02b853cf50bc1c335b70790f93d5a390a35a166bea9c895e685cc866e4961cae
1508blockNumber 436
1509from 0x3b179DcfC5fAa677044c27dCe958e4BC0ad696A6
1510transactionIndex 0
1511effectiveGasPrice 0
1512hash 0x2642e960d3150244e298d52b5b0f024782253e6d0b2c9a01dd4858f7b4665a3f
1513type 0
1514chainId 10
1515nonce 162
1516gasPrice 0
1517gasLimit 18660316
1518to 0x4a16A42407AA491564643E1dfc1fd50af29794eF
1519value 0
1520input 0xd294f093
1521r 0x6fca94073a0cf3381978662d46cf890602d3e9ccf6a31e4b69e8ecbd995e2bee
1522s 0x0e804161a2b56a37ca1f6f4c4b8bce926587afa0d9b1acc5165e6556c959d583
1523yParity 1
1524index 435
1525l1BlockNumber 12691036
1526l1Timestamp 1624460128
1527l1TxOrigin null
1528queueIndex null
1529queueOrigin sequencer
1530rawTransaction 0xf86681a28084011cbbdc944a16a42407aa491564643e1dfc1fd50af29794ef8084d294f09338a06fca94073a0cf3381978662d46cf890602d3e9ccf6a31e4b69e8ecbd995e2beea00e804161a2b56a37ca1f6f4c4b8bce926587afa0d9b1acc5165e6556c959d583
1531txType 0
1532".trim()
1533 );
1534 }
1535
1536 #[test]
1537 fn can_pretty_print_eip2930() {
1538 let s = r#"{
1539 "type": "0x1",
1540 "blockHash": "0x2b27fe2bbc8ce01ac7ae8bf74f793a197cf7edbe82727588811fa9a2c4776f81",
1541 "blockNumber": "0x12b1d",
1542 "from": "0x2b371c0262ceab27face32fbb5270ddc6aa01ba4",
1543 "gas": "0x6bdf",
1544 "gasPrice": "0x3b9aca00",
1545 "hash": "0xbddbb685774d8a3df036ed9fb920b48f876090a57e9e90ee60921e0510ef7090",
1546 "input": "0x9c0e3f7a0000000000000000000000000000000000000000000000000000000000000078000000000000000000000000000000000000000000000000000000000000002a",
1547 "nonce": "0x1c",
1548 "to": "0x8e730df7c70d33118d9e5f79ab81aed0be6f6635",
1549 "transactionIndex": "0x2",
1550 "value": "0x0",
1551 "v": "0x1",
1552 "r": "0x2a98c51c2782f664d3ce571fef0491b48f5ebbc5845fa513192e6e6b24ecdaa1",
1553 "s": "0x29b8e0c67aa9c11327e16556c591dc84a7aac2f6fc57c7f93901be8ee867aebc",
1554 "chainId": "0x66a",
1555 "accessList": [
1556 { "address": "0x2b371c0262ceab27face32fbb5270ddc6aa01ba4", "storageKeys": ["0x1122334455667788990011223344556677889900112233445566778899001122", "0x0000000000000000000000000000000000000000000000000000000000000000"] },
1557 { "address": "0x8e730df7c70d33118d9e5f79ab81aed0be6f6635", "storageKeys": [] }
1558 ]
1559 }
1560 "#;
1561 let tx: Transaction = serde_json::from_str(s).unwrap();
1562 assert_eq!(tx.pretty().trim(),
1563 r"
1564blockHash 0x2b27fe2bbc8ce01ac7ae8bf74f793a197cf7edbe82727588811fa9a2c4776f81
1565blockNumber 76573
1566from 0x2b371c0262CEAb27fAcE32FBB5270dDc6Aa01ba4
1567transactionIndex 2
1568effectiveGasPrice 1000000000
1569hash 0xbddbb685774d8a3df036ed9fb920b48f876090a57e9e90ee60921e0510ef7090
1570type 1
1571chainId 1642
1572nonce 28
1573gasPrice 1000000000
1574gasLimit 27615
1575to 0x8E730Df7C70D33118D9e5F79ab81aEd0bE6F6635
1576value 0
1577accessList [
1578 0x2b371c0262CEAb27fAcE32FBB5270dDc6Aa01ba4 => [
1579 0x1122334455667788990011223344556677889900112233445566778899001122
1580 0x0000000000000000000000000000000000000000000000000000000000000000
1581 ]
1582 0x8E730Df7C70D33118D9e5F79ab81aEd0bE6F6635 => []
1583]
1584input 0x9c0e3f7a0000000000000000000000000000000000000000000000000000000000000078000000000000000000000000000000000000000000000000000000000000002a
1585r 0x2a98c51c2782f664d3ce571fef0491b48f5ebbc5845fa513192e6e6b24ecdaa1
1586s 0x29b8e0c67aa9c11327e16556c591dc84a7aac2f6fc57c7f93901be8ee867aebc
1587yParity 1
1588".trim()
1589 );
1590 }
1591
1592 #[test]
1593 fn can_pretty_print_eip1559() {
1594 let s = r#"{
1595 "type": "0x2",
1596 "blockHash": "0x61abbe5e22738de0462046f5a5d6c4cd6bc1f3a6398e4457d5e293590e721125",
1597 "blockNumber": "0x7647",
1598 "from": "0xbaadf00d42264eeb3fafe6799d0b56cf55df0f00",
1599 "gas": "0x186a0",
1600 "hash": "0xa7231d4da0576fade5d3b9481f4cd52459ec59b9bbdbf4f60d6cd726b2a3a244",
1601 "input": "0x48600055323160015500",
1602 "nonce": "0x12c",
1603 "to": null,
1604 "transactionIndex": "0x41",
1605 "value": "0x0",
1606 "v": "0x1",
1607 "yParity": "0x1",
1608 "r": "0x396864e5f9132327defdb1449504252e1fa6bce73feb8cd6f348a342b198af34",
1609 "s": "0x44dbba72e6d3304104848277143252ee43627c82f02d1ef8e404e1bf97c70158",
1610 "gasPrice": "0x4a817c800",
1611 "maxFeePerGas": "0x4a817c800",
1612 "maxPriorityFeePerGas": "0x4a817c800",
1613 "chainId": "0x66a",
1614 "accessList": [
1615 {
1616 "address": "0xc141a9a7463e6c4716d9fc0c056c054f46bb2993",
1617 "storageKeys": [
1618 "0x0000000000000000000000000000000000000000000000000000000000000000"
1619 ]
1620 }
1621 ]
1622 }
1623"#;
1624 let tx: Transaction = serde_json::from_str(s).unwrap();
1625 assert_eq!(
1626 tx.pretty().trim(),
1627 r"
1628blockHash 0x61abbe5e22738de0462046f5a5d6c4cd6bc1f3a6398e4457d5e293590e721125
1629blockNumber 30279
1630from 0xBaaDF00d42264eEb3FAFe6799d0b56cf55DF0F00
1631transactionIndex 65
1632effectiveGasPrice 20000000000
1633hash 0xa7231d4da0576fade5d3b9481f4cd52459ec59b9bbdbf4f60d6cd726b2a3a244
1634type 2
1635chainId 1642
1636nonce 300
1637gasLimit 100000
1638maxFeePerGas 20000000000
1639maxPriorityFeePerGas 20000000000
1640to
1641value 0
1642accessList [
1643 0xC141a9A7463e6C4716d9FC0C056C054F46Bb2993 => [
1644 0x0000000000000000000000000000000000000000000000000000000000000000
1645 ]
1646]
1647input 0x48600055323160015500
1648r 0x396864e5f9132327defdb1449504252e1fa6bce73feb8cd6f348a342b198af34
1649s 0x44dbba72e6d3304104848277143252ee43627c82f02d1ef8e404e1bf97c70158
1650yParity 1
1651"
1652 .trim()
1653 );
1654 }
1655
1656 #[test]
1657 fn can_pretty_print_eip4884() {
1658 let s = r#"{
1659 "blockHash": "0xfc2715ff196e23ae613ed6f837abd9035329a720a1f4e8dce3b0694c867ba052",
1660 "blockNumber": "0x2a1cb",
1661 "from": "0xad01b55d7c3448b8899862eb335fbb17075d8de2",
1662 "gas": "0x5208",
1663 "gasPrice": "0x1d1a94a201c",
1664 "maxFeePerGas": "0x1d1a94a201c",
1665 "maxPriorityFeePerGas": "0x1d1a94a201c",
1666 "maxFeePerBlobGas": "0x3e8",
1667 "hash": "0x5ceec39b631763ae0b45a8fb55c373f38b8fab308336ca1dc90ecd2b3cf06d00",
1668 "input": "0x",
1669 "nonce": "0x1b483",
1670 "to": "0x000000000000000000000000000000000000f1c1",
1671 "transactionIndex": "0x0",
1672 "value": "0x0",
1673 "type": "0x3",
1674 "accessList": [],
1675 "chainId": "0x1a1f0ff42",
1676 "blobVersionedHashes": [
1677 "0x01a128c46fc61395706686d6284f83c6c86dfc15769b9363171ea9d8566e6e76"
1678 ],
1679 "v": "0x0",
1680 "r": "0x343c6239323a81ef61293cb4a4d37b6df47fbf68114adb5dd41581151a077da1",
1681 "s": "0x48c21f6872feaf181d37cc4f9bbb356d3f10b352ceb38d1c3b190d749f95a11b",
1682 "yParity": "0x0"
1683 }
1684"#;
1685 let tx: Transaction = serde_json::from_str(s).unwrap();
1686 assert_eq!(
1687 tx.pretty().trim(),
1688 r"
1689blockHash 0xfc2715ff196e23ae613ed6f837abd9035329a720a1f4e8dce3b0694c867ba052
1690blockNumber 172491
1691from 0xAD01b55d7c3448B8899862eb335FBb17075d8DE2
1692transactionIndex 0
1693effectiveGasPrice 2000000000028
1694hash 0x5ceec39b631763ae0b45a8fb55c373f38b8fab308336ca1dc90ecd2b3cf06d00
1695type 3
1696chainId 7011893058
1697nonce 111747
1698gasLimit 21000
1699maxFeePerGas 2000000000028
1700maxPriorityFeePerGas 2000000000028
1701to 0x000000000000000000000000000000000000f1C1
1702value 0
1703accessList []
1704blobVersionedHashes [
1705 0x01a128c46fc61395706686d6284f83c6c86dfc15769b9363171ea9d8566e6e76
1706]
1707maxFeePerBlobGas 1000
1708input 0x
1709r 0x343c6239323a81ef61293cb4a4d37b6df47fbf68114adb5dd41581151a077da1
1710s 0x48c21f6872feaf181d37cc4f9bbb356d3f10b352ceb38d1c3b190d749f95a11b
1711yParity 0
1712"
1713 .trim()
1714 );
1715 }
1716
1717 #[test]
1718 fn print_block_w_txs() {
1719 let block = r#"{"number":"0x3","hash":"0xda53da08ef6a3cbde84c33e51c04f68c3853b6a3731f10baa2324968eee63972","parentHash":"0x689c70c080ca22bc0e681694fa803c1aba16a69c8b6368fed5311d279eb9de90","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x7270c1c4440180f2bd5215809ee3d545df042b67329499e1ab97eb759d31610d","stateRoot":"0x29f32984517a7d25607da485b23cefabfd443751422ca7e603395e1de9bc8a4b","receiptsRoot":"0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2","miner":"0x0000000000000000000000000000000000000000","difficulty":"0x0","totalDifficulty":"0x0","extraData":"0x","size":"0x3e8","gasLimit":"0x6691b7","gasUsed":"0x5208","timestamp":"0x5ecedbb9","transactions":[{"hash":"0xc3c5f700243de37ae986082fd2af88d2a7c2752a0c0f7b9d6ac47c729d45e067","nonce":"0x2","blockHash":"0xda53da08ef6a3cbde84c33e51c04f68c3853b6a3731f10baa2324968eee63972","blockNumber":"0x3","transactionIndex":"0x0","from":"0xfdcedc3bfca10ecb0890337fbdd1977aba84807a","to":"0xdca8ce283150ab773bcbeb8d38289bdb5661de1e","value":"0x0","gas":"0x15f90","gasPrice":"0x4a817c800","input":"0x","v":"0x25","r":"0x19f2694eb9113656dbea0b925e2e7ceb43df83e601c4116aee9c0dd99130be88","s":"0x73e5764b324a4f7679d890a198ba658ba1c8cd36983ff9797e10b1b89dbb448e"}],"uncles":[]}"#;
1720 let block: Block = serde_json::from_str(block).unwrap();
1721 let output = "
1722blockHash 0xda53da08ef6a3cbde84c33e51c04f68c3853b6a3731f10baa2324968eee63972
1723blockNumber 3
1724from 0xFdCeDC3bFca10eCb0890337fbdD1977aba84807a
1725transactionIndex 0
1726effectiveGasPrice 20000000000
1727hash 0xc3c5f700243de37ae986082fd2af88d2a7c2752a0c0f7b9d6ac47c729d45e067
1728type 0
1729chainId 1
1730nonce 2
1731gasPrice 20000000000
1732gasLimit 90000
1733to 0xdca8ce283150AB773BCbeB8d38289bdB5661dE1e
1734value 0
1735input 0x
1736r 0x19f2694eb9113656dbea0b925e2e7ceb43df83e601c4116aee9c0dd99130be88
1737s 0x73e5764b324a4f7679d890a198ba658ba1c8cd36983ff9797e10b1b89dbb448e
1738yParity 0"
1739 .to_string();
1740 let txs = match block.transactions() {
1741 BlockTransactions::Full(txs) => txs,
1742 _ => panic!("not full transactions"),
1743 };
1744 let generated = txs[0].pretty();
1745 assert_eq!(generated.as_str(), output.as_str());
1746 }
1747
1748 #[test]
1749 fn uifmt_option_u64() {
1750 assert_eq!(None::<U64>.pretty(), "");
1751 assert_eq!(U64::from(100).pretty(), "100");
1752 assert_eq!(Some(U64::from(100)).pretty(), "100");
1753 }
1754
1755 #[test]
1756 fn uifmt_option_h64() {
1757 assert_eq!(None::<B256>.pretty(), "");
1758 assert_eq!(
1759 B256::with_last_byte(100).pretty(),
1760 "0x0000000000000000000000000000000000000000000000000000000000000064",
1761 );
1762 assert_eq!(
1763 Some(B256::with_last_byte(100)).pretty(),
1764 "0x0000000000000000000000000000000000000000000000000000000000000064",
1765 );
1766 }
1767
1768 #[test]
1769 fn uifmt_option_bytes() {
1770 assert_eq!(None::<Bytes>.pretty(), "");
1771 assert_eq!(
1772 Bytes::from_str("0x0000000000000000000000000000000000000000000000000000000000000064")
1773 .unwrap()
1774 .pretty(),
1775 "0x0000000000000000000000000000000000000000000000000000000000000064",
1776 );
1777 assert_eq!(
1778 Some(
1779 Bytes::from_str(
1780 "0x0000000000000000000000000000000000000000000000000000000000000064"
1781 )
1782 .unwrap()
1783 )
1784 .pretty(),
1785 "0x0000000000000000000000000000000000000000000000000000000000000064",
1786 );
1787 }
1788
1789 #[test]
1790 fn test_pretty_tx_attr() {
1791 let block = r#"{"number":"0x3","hash":"0xda53da08ef6a3cbde84c33e51c04f68c3853b6a3731f10baa2324968eee63972","parentHash":"0x689c70c080ca22bc0e681694fa803c1aba16a69c8b6368fed5311d279eb9de90","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x7270c1c4440180f2bd5215809ee3d545df042b67329499e1ab97eb759d31610d","stateRoot":"0x29f32984517a7d25607da485b23cefabfd443751422ca7e603395e1de9bc8a4b","receiptsRoot":"0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2","miner":"0x0000000000000000000000000000000000000000","difficulty":"0x0","totalDifficulty":"0x0","extraData":"0x","size":"0x3e8","gasLimit":"0x6691b7","gasUsed":"0x5208","timestamp":"0x5ecedbb9","transactions":[{"hash":"0xc3c5f700243de37ae986082fd2af88d2a7c2752a0c0f7b9d6ac47c729d45e067","nonce":"0x2","blockHash":"0xda53da08ef6a3cbde84c33e51c04f68c3853b6a3731f10baa2324968eee63972","blockNumber":"0x3","transactionIndex":"0x0","from":"0xfdcedc3bfca10ecb0890337fbdd1977aba84807a","to":"0xdca8ce283150ab773bcbeb8d38289bdb5661de1e","value":"0x0","gas":"0x15f90","gasPrice":"0x4a817c800","input":"0x","v":"0x25","r":"0x19f2694eb9113656dbea0b925e2e7ceb43df83e601c4116aee9c0dd99130be88","s":"0x73e5764b324a4f7679d890a198ba658ba1c8cd36983ff9797e10b1b89dbb448e"}],"uncles":[]}"#;
1792 let block: <Ethereum as Network>::BlockResponse = serde_json::from_str(block).unwrap();
1793 let txs = match block.transactions() {
1794 BlockTransactions::Full(txes) => txes,
1795 _ => panic!("not full transactions"),
1796 };
1797
1798 assert_eq!(None, get_pretty_tx_attr::<Ethereum>(&txs[0], ""));
1799 assert_eq!(Some("3".to_string()), get_pretty_tx_attr::<Ethereum>(&txs[0], "blockNumber"));
1800 assert_eq!(
1801 Some("0xFdCeDC3bFca10eCb0890337fbdD1977aba84807a".to_string()),
1802 get_pretty_tx_attr::<Ethereum>(&txs[0], "from")
1803 );
1804 assert_eq!(Some("90000".to_string()), get_pretty_tx_attr::<Ethereum>(&txs[0], "gas"));
1805 assert_eq!(
1806 Some("20000000000".to_string()),
1807 get_pretty_tx_attr::<Ethereum>(&txs[0], "gasPrice")
1808 );
1809 assert_eq!(
1810 Some("0xc3c5f700243de37ae986082fd2af88d2a7c2752a0c0f7b9d6ac47c729d45e067".to_string()),
1811 get_pretty_tx_attr::<Ethereum>(&txs[0], "hash")
1812 );
1813 assert_eq!(Some("0x".to_string()), get_pretty_tx_attr::<Ethereum>(&txs[0], "input"));
1814 assert_eq!(Some("2".to_string()), get_pretty_tx_attr::<Ethereum>(&txs[0], "nonce"));
1815 assert_eq!(
1816 Some("0x19f2694eb9113656dbea0b925e2e7ceb43df83e601c4116aee9c0dd99130be88".to_string()),
1817 get_pretty_tx_attr::<Ethereum>(&txs[0], "r")
1818 );
1819 assert_eq!(
1820 Some("0x73e5764b324a4f7679d890a198ba658ba1c8cd36983ff9797e10b1b89dbb448e".to_string()),
1821 get_pretty_tx_attr::<Ethereum>(&txs[0], "s")
1822 );
1823 assert_eq!(
1824 Some("0xdca8ce283150AB773BCbeB8d38289bdB5661dE1e".into()),
1825 get_pretty_tx_attr::<Ethereum>(&txs[0], "to")
1826 );
1827 assert_eq!(
1828 Some("0".to_string()),
1829 get_pretty_tx_attr::<Ethereum>(&txs[0], "transactionIndex")
1830 );
1831 assert_eq!(Some("27".to_string()), get_pretty_tx_attr::<Ethereum>(&txs[0], "v"));
1832 assert_eq!(Some("0".to_string()), get_pretty_tx_attr::<Ethereum>(&txs[0], "value"));
1833 }
1834
1835 #[test]
1836 fn test_pretty_block_attr() {
1837 let json = serde_json::json!(
1838 {
1839 "baseFeePerGas": "0x7",
1840 "miner": "0x0000000000000000000000000000000000000001",
1841 "number": "0x1b4",
1842 "hash": "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
1843 "parentHash": "0x9646252be9520f6e71339a8df9c55e4d7619deeb018d2a3f2d21fc165dde5eb5",
1844 "mixHash": "0x1010101010101010101010101010101010101010101010101010101010101010",
1845 "nonce": "0x0000000000000000",
1846 "sealFields": [
1847 "0xe04d296d2460cfb8472af2c5fd05b5a214109c25688d3704aed5484f9a7792f2",
1848 "0x0000000000000042"
1849 ],
1850 "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
1851 "logsBloom": "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
1852 "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
1853 "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
1854 "stateRoot": "0xd5855eb08b3387c0af375e9cdb6acfc05eb8f519e419b874b6ff2ffda7ed1dff",
1855 "difficulty": "0x1",
1856 "totalDifficulty": "0x27f07",
1857 "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
1858 "size": "0x27f07",
1859 "gasLimit": "0x9f759",
1860 "minGasPrice": "0x9f759",
1861 "gasUsed": "0x9f759",
1862 "timestamp": "0x54e34e8e",
1863 "transactions": [],
1864 "uncles": [],
1865 }
1866 );
1867
1868 let block: <Ethereum as Network>::BlockResponse = serde_json::from_value(json).unwrap();
1869
1870 assert_eq!(None, get_pretty_block_attr::<Ethereum>(&block, ""));
1871 assert_eq!(
1872 Some("7".to_string()),
1873 get_pretty_block_attr::<Ethereum>(&block, "baseFeePerGas")
1874 );
1875 assert_eq!(Some("1".to_string()), get_pretty_block_attr::<Ethereum>(&block, "difficulty"));
1876 assert_eq!(
1877 Some("0x0000000000000000000000000000000000000000000000000000000000000000".to_string()),
1878 get_pretty_block_attr::<Ethereum>(&block, "extraData")
1879 );
1880 assert_eq!(
1881 Some("653145".to_string()),
1882 get_pretty_block_attr::<Ethereum>(&block, "gasLimit")
1883 );
1884 assert_eq!(
1885 Some("653145".to_string()),
1886 get_pretty_block_attr::<Ethereum>(&block, "gasUsed")
1887 );
1888 assert_eq!(
1889 Some("0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331".to_string()),
1890 get_pretty_block_attr::<Ethereum>(&block, "hash")
1891 );
1892 assert_eq!(Some("0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331".to_string()), get_pretty_block_attr::<Ethereum>(&block, "logsBloom"));
1893 assert_eq!(
1894 Some("0x0000000000000000000000000000000000000001".to_string()),
1895 get_pretty_block_attr::<Ethereum>(&block, "miner")
1896 );
1897 assert_eq!(
1898 Some("0x1010101010101010101010101010101010101010101010101010101010101010".to_string()),
1899 get_pretty_block_attr::<Ethereum>(&block, "mixHash")
1900 );
1901 assert_eq!(
1902 Some("0x0000000000000000".to_string()),
1903 get_pretty_block_attr::<Ethereum>(&block, "nonce")
1904 );
1905 assert_eq!(Some("436".to_string()), get_pretty_block_attr::<Ethereum>(&block, "number"));
1906 assert_eq!(
1907 Some("0x9646252be9520f6e71339a8df9c55e4d7619deeb018d2a3f2d21fc165dde5eb5".to_string()),
1908 get_pretty_block_attr::<Ethereum>(&block, "parentHash")
1909 );
1910 assert_eq!(
1911 Some("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421".to_string()),
1912 get_pretty_block_attr::<Ethereum>(&block, "transactionsRoot")
1913 );
1914 assert_eq!(
1915 Some("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421".to_string()),
1916 get_pretty_block_attr::<Ethereum>(&block, "receiptsRoot")
1917 );
1918 assert_eq!(
1919 Some("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347".to_string()),
1920 get_pretty_block_attr::<Ethereum>(&block, "sha3Uncles")
1921 );
1922 assert_eq!(Some("163591".to_string()), get_pretty_block_attr::<Ethereum>(&block, "size"));
1923 assert_eq!(
1924 Some("0xd5855eb08b3387c0af375e9cdb6acfc05eb8f519e419b874b6ff2ffda7ed1dff".to_string()),
1925 get_pretty_block_attr::<Ethereum>(&block, "stateRoot")
1926 );
1927 assert_eq!(
1928 Some("1424182926".to_string()),
1929 get_pretty_block_attr::<Ethereum>(&block, "timestamp")
1930 );
1931 assert_eq!(
1932 Some("163591".to_string()),
1933 get_pretty_block_attr::<Ethereum>(&block, "totalDifficulty")
1934 );
1935
1936 let pretty = pretty_generic_header_response(block.header());
1937 assert!(pretty.contains("difficulty 1"), "{pretty}");
1938 assert!(pretty.contains("totalDifficulty 163591"), "{pretty}");
1939 }
1940
1941 #[test]
1942 fn test_receipt_other_fields_alignment() {
1943 let receipt_json = serde_json::json!(
1944 {
1945 "status": "0x1",
1946 "cumulativeGasUsed": "0x74e483",
1947 "logs": [],
1948 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
1949 "type": "0x2",
1950 "transactionHash": "0x91181b0dca3b29aa136eeb2f536be5ce7b0aebc949be1c44b5509093c516097d",
1951 "transactionIndex": "0x10",
1952 "blockHash": "0x54bafb12e8cea9bb355fbf03a4ac49e42a2a1a80fa6cf4364b342e2de6432b5d",
1953 "blockNumber": "0x7b1ab93",
1954 "gasUsed": "0xc222",
1955 "effectiveGasPrice": "0x18961",
1956 "from": "0x2d815240a61731c75fa01b2793e1d3ed09f289d0",
1957 "to": "0x4200000000000000000000000000000000000000",
1958 "contractAddress": null,
1959 "l1BaseFeeScalar": "0x146b",
1960 "l1BlobBaseFee": "0x6a83078",
1961 "l1BlobBaseFeeScalar": "0xf79c5",
1962 "l1Fee": "0x51a9af7fd3",
1963 "l1GasPrice": "0x972fe4acc",
1964 "l1GasUsed": "0x640"
1965 });
1966
1967 let receipt: AnyTransactionReceipt = serde_json::from_value(receipt_json).unwrap();
1968 let formatted = receipt.pretty();
1969
1970 let expected = r#"
1971blockHash 0x54bafb12e8cea9bb355fbf03a4ac49e42a2a1a80fa6cf4364b342e2de6432b5d
1972blockNumber 129084307
1973contractAddress
1974cumulativeGasUsed 7660675
1975effectiveGasPrice 100705
1976from 0x2D815240A61731c75Fa01b2793E1D3eD09F289d0
1977gasUsed 49698
1978logs []
1979logsBloom 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
1980root
1981status 1 (success)
1982transactionHash 0x91181b0dca3b29aa136eeb2f536be5ce7b0aebc949be1c44b5509093c516097d
1983transactionIndex 16
1984type 2
1985blobGasPrice
1986blobGasUsed
1987to 0x4200000000000000000000000000000000000000
1988l1BaseFeeScalar 5227
1989l1BlobBaseFee 111685752
1990l1BlobBaseFeeScalar 1014213
1991l1Fee 350739202003
1992l1GasPrice 40583973580
1993l1GasUsed 1600
1994"#;
1995
1996 assert_eq!(formatted.trim(), expected.trim());
1997 }
1998
1999 #[test]
2000 fn test_uifmt_for_signed_authorization() {
2001 let inner = Authorization {
2002 chain_id: U256::from(1),
2003 address: "0x000000000000000000000000000000000000dead".parse::<Address>().unwrap(),
2004 nonce: 42,
2005 };
2006 let signed_authorization =
2007 SignedAuthorization::new_unchecked(inner, 1, U256::from(20), U256::from(30));
2008
2009 assert_eq!(
2010 signed_authorization.pretty(),
2011 r#"{recoveredAuthority: 0xf3eaBD0de6Ca1aE7fC4D81FfD6C9a40e5D5D7e30, signedAuthority: {"chainId":"0x1","address":"0x000000000000000000000000000000000000dead","nonce":"0x2a","yParity":"0x1","r":"0x14","s":"0x1e"}}"#
2012 );
2013 }
2014
2015 #[test]
2016 fn can_pretty_print_tempo_tx() {
2017 let s = r#"{
2018 "type":"0x76",
2019 "chainId":"0xa5bd",
2020 "feeToken":"0x20c0000000000000000000000000000000000001",
2021 "maxPriorityFeePerGas":"0x0",
2022 "maxFeePerGas":"0x2cb417800",
2023 "gas":"0x2d178",
2024 "calls":[
2025 {
2026 "data":null,
2027 "input":"0x095ea7b3000000000000000000000000dec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000989680",
2028 "to":"0x20c0000000000000000000000000000000000000",
2029 "value":"0x0"
2030 },
2031 {
2032 "data":null,
2033 "input":"0xf8856c0f00000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020c00000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000989680000000000000000000000000000000000000000000000000000000000097d330",
2034 "to":"0xdec0000000000000000000000000000000000000",
2035 "value":"0x0"
2036 }
2037 ],
2038 "accessList":[],
2039 "nonceKey":"0x0",
2040 "nonce":"0x0",
2041 "feePayerSignature":null,
2042 "validBefore":null,
2043 "validAfter":null,
2044 "keyAuthorization":null,
2045 "aaAuthorizationList":[],
2046 "signature":{
2047 "pubKeyX":"0xaacc80b21e45fb11f349424dce3a2f23547f60c0ff2f8bcaede2a247545ce8dd",
2048 "pubKeyY":"0x87abf0dbb7a5c9507efae2e43833356651b45ac576c2e61cec4e9c0f41fcbf6e",
2049 "r":"0xcfd45c3b19745a42f80b134dcb02a8ba099a0e4e7be1984da54734aa81d8f29f",
2050 "s":"0x74bb9170ae6d25bd510c83fe35895ee5712efe13980a5edc8094c534e23af85e",
2051 "type":"webAuthn",
2052 "webauthnData":"0x7b98b7a8e6c68d7eac741a52e6fdae0560ce3c16ef5427ad46d7a54d0ed86dd41d000000007b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a2238453071464a7a50585167546e645473643649456659457776323173516e626966374c4741776e4b43626b222c226f726967696e223a2268747470733a2f2f74656d706f2d6465782e76657263656c2e617070222c2263726f73734f726967696e223a66616c73657d"
2053 },
2054 "hash":"0x6d6d8c102064e6dee44abad2024a8b1d37959230baab80e70efbf9b0c739c4fd",
2055 "blockHash":"0xc82b23589ceef5341ed307d33554714db6f9eefd4187a9ca8abc910a325b4689",
2056 "blockNumber":"0x321fde",
2057 "transactionIndex":"0x0",
2058 "from":"0x566ff0f4a6114f8072ecdc8a7a8a13d8d0c6b45f",
2059 "gasPrice":"0x2540be400"
2060 }"#;
2061
2062 let tx: Transaction<TempoTxEnvelope> = serde_json::from_str(s).unwrap();
2063
2064 assert_eq!(
2065 tx.pretty().trim(),
2066 r#"
2067blockHash 0xc82b23589ceef5341ed307d33554714db6f9eefd4187a9ca8abc910a325b4689
2068blockNumber 3284958
2069from 0x566Ff0f4a6114F8072ecDC8A7A8A13d8d0C6B45F
2070transactionIndex 0
2071effectiveGasPrice 10000000000
2072hash 0x6d6d8c102064e6dee44abad2024a8b1d37959230baab80e70efbf9b0c739c4fd
2073type 118
2074chainId 42429
2075feeToken 0x20C0000000000000000000000000000000000001
2076maxPriorityFeePerGas 0
2077maxFeePerGas 12000000000
2078gasLimit 184696
2079calls [
2080 to: 0x20C0000000000000000000000000000000000000, value: 0, input: 0x095ea7b3000000000000000000000000dec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000989680
2081 to: 0xDEc0000000000000000000000000000000000000, value: 0, input: 0xf8856c0f00000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020c00000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000989680000000000000000000000000000000000000000000000000000000000097d330
2082]
2083accessList []
2084nonceKey 0
2085nonce 0
2086feePayerSignature
2087validBefore
2088validAfter
2089tempoSignature {"type":"webAuthn","r":"0xcfd45c3b19745a42f80b134dcb02a8ba099a0e4e7be1984da54734aa81d8f29f","s":"0x74bb9170ae6d25bd510c83fe35895ee5712efe13980a5edc8094c534e23af85e","pubKeyX":"0xaacc80b21e45fb11f349424dce3a2f23547f60c0ff2f8bcaede2a247545ce8dd","pubKeyY":"0x87abf0dbb7a5c9507efae2e43833356651b45ac576c2e61cec4e9c0f41fcbf6e","webauthnData":"0x7b98b7a8e6c68d7eac741a52e6fdae0560ce3c16ef5427ad46d7a54d0ed86dd41d000000007b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a2238453071464a7a50585167546e645473643649456659457776323173516e626966374c4741776e4b43626b222c226f726967696e223a2268747470733a2f2f74656d706f2d6465782e76657263656c2e617070222c2263726f73734f726967696e223a66616c73657d"}
2090"#
2091 .trim()
2092 );
2093 }
2094
2095 #[test]
2096 fn can_pretty_print_tempo_receipt() {
2097 let s = r#"{"type":"0x76","status":"0x1","cumulativeGasUsed":"0x176d7f4","logs":[{"address":"0x20c0000000000000000000000000000000000000","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000a70ab0448e66cd77995bfbba5c5b64b41a85f3fd","0x0000000000000000000000000000000000000000000000000000000000000001"],"data":"0x00000000000000000000000000000000000000000000000000000000000003e8","blockHash":"0x860f788b251ece768e63b0d3906d156f652d843848b71c7fe81faacd49139d66","blockNumber":"0x69a1d7","blockTimestamp":"0x69a5d790","transactionHash":"0x04548a0ea27e2cccc1479af3c2ff02da4d4d3ea46af8e8d7edaa49f6ea27073f","transactionIndex":"0x63","logIndex":"0xb8","removed":false},{"address":"0x20c0000000000000000000000000000000000003","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000a70ab0448e66cd77995bfbba5c5b64b41a85f3fd","0x000000000000000000000000feec000000000000000000000000000000000000"],"data":"0x0000000000000000000000000000000000000000000000000000000000000417","blockHash":"0x860f788b251ece768e63b0d3906d156f652d843848b71c7fe81faacd49139d66","blockNumber":"0x69a1d7","blockTimestamp":"0x69a5d790","transactionHash":"0x04548a0ea27e2cccc1479af3c2ff02da4d4d3ea46af8e8d7edaa49f6ea27073f","transactionIndex":"0x63","logIndex":"0xb9","removed":false}],"logsBloom":"0x00000000000000000000000000000000000000000000010000000000000000000000000000000000000000000100000000000000000000000000000000040008000004200000000000000008000000000000000000040000000000000400000000000002000000000000000000000000000000000000000000000010000000000000000000000000000000000020000000000000800000000000000000000000000020000000000000000000000000000000000400000000000000000000000000000002000000000000000400000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000","transactionHash":"0x04548a0ea27e2cccc1479af3c2ff02da4d4d3ea46af8e8d7edaa49f6ea27073f","transactionIndex":"0x63","blockHash":"0x860f788b251ece768e63b0d3906d156f652d843848b71c7fe81faacd49139d66","blockNumber":"0x69a1d7","gasUsed":"0xcc6a","effectiveGasPrice":"0x4a817c802","from":"0xa70ab0448e66cd77995bfbba5c5b64b41a85f3fd","to":"0x20c0000000000000000000000000000000000000","contractAddress":null,"feeToken":"0x20c0000000000000000000000000000000000003","feePayer":"0xa70ab0448e66cd77995bfbba5c5b64b41a85f3fd"}"#;
2098
2099 let tx: TempoTransactionReceipt = serde_json::from_str(s).unwrap();
2100
2101 assert_eq!(
2102 tx.pretty().trim(),
2103 r#"
2104blockHash 0x860f788b251ece768e63b0d3906d156f652d843848b71c7fe81faacd49139d66
2105blockNumber 6922711
2106contractAddress
2107cumulativeGasUsed 24565748
2108effectiveGasPrice 20000000002
2109from 0xa70ab0448e66cD77995bfBBa5c5b64B41a85F3fd
2110gasUsed 52330
2111logs [{"address":"0x20c0000000000000000000000000000000000000","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000a70ab0448e66cd77995bfbba5c5b64b41a85f3fd","0x0000000000000000000000000000000000000000000000000000000000000001"],"data":"0x00000000000000000000000000000000000000000000000000000000000003e8","blockHash":"0x860f788b251ece768e63b0d3906d156f652d843848b71c7fe81faacd49139d66","blockNumber":"0x69a1d7","blockTimestamp":"0x69a5d790","transactionHash":"0x04548a0ea27e2cccc1479af3c2ff02da4d4d3ea46af8e8d7edaa49f6ea27073f","transactionIndex":"0x63","logIndex":"0xb8","removed":false},{"address":"0x20c0000000000000000000000000000000000003","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000a70ab0448e66cd77995bfbba5c5b64b41a85f3fd","0x000000000000000000000000feec000000000000000000000000000000000000"],"data":"0x0000000000000000000000000000000000000000000000000000000000000417","blockHash":"0x860f788b251ece768e63b0d3906d156f652d843848b71c7fe81faacd49139d66","blockNumber":"0x69a1d7","blockTimestamp":"0x69a5d790","transactionHash":"0x04548a0ea27e2cccc1479af3c2ff02da4d4d3ea46af8e8d7edaa49f6ea27073f","transactionIndex":"0x63","logIndex":"0xb9","removed":false}]
2112logsBloom 0x00000000000000000000000000000000000000000000010000000000000000000000000000000000000000000100000000000000000000000000000000040008000004200000000000000008000000000000000000040000000000000400000000000002000000000000000000000000000000000000000000000010000000000000000000000000000000000020000000000000800000000000000000000000000020000000000000000000000000000000000400000000000000000000000000000002000000000000000400000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000
2113root
2114status true
2115transactionHash 0x04548a0ea27e2cccc1479af3c2ff02da4d4d3ea46af8e8d7edaa49f6ea27073f
2116transactionIndex 99
2117type 118
2118feePayer 0xa70ab0448e66cD77995bfBBa5c5b64B41a85F3fd
2119feeToken 0x20C0000000000000000000000000000000000003
2120to 0x20C0000000000000000000000000000000000000
2121"#
2122 .trim()
2123 );
2124 }
2125
2126 #[test]
2127 fn test_ethereum_receipt_uifmt() {
2128 let s = r#"{"type":"0x2","status":"0x1","cumulativeGasUsed":"0x5208","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","transactionHash":"0x1234567890123456789012345678901234567890123456789012345678901234","transactionIndex":"0x0","blockHash":"0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd","blockNumber":"0x1","gasUsed":"0x5208","effectiveGasPrice":"0x3b9aca00","from":"0x1234567890123456789012345678901234567890","to":"0x0987654321098765432109876543210987654321","contractAddress":null}"#;
2129 let receipt: TransactionReceipt = serde_json::from_str(s).unwrap();
2130
2131 let pretty_output = receipt.pretty();
2132
2133 assert!(pretty_output.contains("blockHash"));
2134 assert!(pretty_output.contains("blockNumber"));
2135 assert!(pretty_output.contains("status"));
2136 assert!(pretty_output.contains("gasUsed"));
2137 assert!(pretty_output.contains("transactionHash"));
2138 assert!(pretty_output.contains("type"));
2139 assert!(
2140 pretty_output
2141 .contains("0x1234567890123456789012345678901234567890123456789012345678901234")
2142 );
2143 assert!(pretty_output.contains("1 (success)"));
2144 assert!(pretty_output.contains("0x0987654321098765432109876543210987654321"));
2145 }
2146
2147 #[test]
2148 fn test_get_pretty_receipt_attr() {
2149 let receipt_json = serde_json::json!({
2150 "type": "0x2",
2151 "status": "0x1",
2152 "cumulativeGasUsed": "0x5208",
2153 "logs": [],
2154 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
2155 "transactionHash": "0x1234567890123456789012345678901234567890123456789012345678901234",
2156 "transactionIndex": "0x0",
2157 "blockHash": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd",
2158 "blockNumber": "0x1",
2159 "gasUsed": "0x5208",
2160 "effectiveGasPrice": "0x3b9aca00",
2161 "from": "0x1234567890123456789012345678901234567890",
2162 "to": "0x0987654321098765432109876543210987654321",
2163 "contractAddress": null
2164 });
2165
2166 let receipt: <Ethereum as Network>::ReceiptResponse =
2167 serde_json::from_value(receipt_json).unwrap();
2168
2169 assert_eq!(
2171 Some("0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd".to_string()),
2172 get_pretty_receipt_attr::<Ethereum>(&receipt, "blockHash")
2173 );
2174 assert_eq!(
2175 Some("1".to_string()),
2176 get_pretty_receipt_attr::<Ethereum>(&receipt, "blockNumber")
2177 );
2178 assert_eq!(
2179 Some("0x1234567890123456789012345678901234567890123456789012345678901234".to_string()),
2180 get_pretty_receipt_attr::<Ethereum>(&receipt, "transactionHash")
2181 );
2182 assert_eq!(
2183 Some("21000".to_string()),
2184 get_pretty_receipt_attr::<Ethereum>(&receipt, "gasUsed")
2185 );
2186 assert_eq!(
2187 Some("true".to_string()),
2188 get_pretty_receipt_attr::<Ethereum>(&receipt, "status")
2189 );
2190 assert_eq!(
2191 Some("EIP-1559".to_string()),
2192 get_pretty_receipt_attr::<Ethereum>(&receipt, "type")
2193 );
2194 assert_eq!(Some("[]".to_string()), get_pretty_receipt_attr::<Ethereum>(&receipt, "logs"));
2195 assert!(get_pretty_receipt_attr::<Ethereum>(&receipt, "logsBloom").is_some());
2196 }
2197}