anvil_zksync_core/formatter/transaction/
summary.rs

1//! Summarizes transaction effects and pretty prints them.
2//!
3//! This module provides utilities for creating detailed summaries of transaction
4//! execution, including gas usage, costs, storage changes, and execution status.
5
6use std::fmt::Display;
7
8use anvil_zksync_common::utils::cost::{format_eth, format_gwei};
9use zksync_multivm::interface::VmExecutionResultAndLogs;
10use zksync_types::{Address, Transaction, H256, U256};
11
12use crate::utils::to_human_size;
13
14use super::{
15    balance_diff::{BalanceDiff, BalanceDiffRepr},
16    status::TransactionStatus,
17};
18
19///
20/// Part of the transaction summary describing the chain-level context.
21/// Contains information about the environment where the transaction was executed.
22///
23struct TransactionContext {
24    /// Gas price on L2 in wei
25    l2_gas_price: u64,
26}
27
28///
29/// Part of the transaction summary describing the gas consumption details.
30///
31///
32/// Details of gas usage for transaction execution.
33///
34struct GasDetails {
35    limit: U256,
36    used: U256,
37    refunded: u64,
38}
39
40///
41/// A comprehensive summary of transaction execution results.
42/// Contains all details about transaction status, participants,
43/// resources consumed, and costs.
44///
45pub struct TransactionSummary {
46    /// Execution outcome
47    status: TransactionStatus,
48    /// Transaction hash
49    tx_hash: H256,
50    /// Address that initiated the transaction
51    initiator: Address,
52    /// Address that paid for the transaction
53    payer: Address,
54    /// Execution context information
55    context: TransactionContext,
56    /// Gas consumption details
57    gas: GasDetails,
58    /// Changes in balances.
59    balance_diffs: Option<Vec<BalanceDiff>>,
60}
61
62impl TransactionSummary {
63    /// Creates a new transaction summary from execution results.
64    ///
65    /// # Arguments
66    ///
67    /// * `l2_gas_price` - The gas price on L2 in wei
68    /// * `tx` - The executed transaction
69    /// * `tx_result` - The execution results and logs
70    pub fn new(
71        l2_gas_price: u64,
72        tx: &Transaction,
73        tx_result: &VmExecutionResultAndLogs,
74        balance_diffs: Option<Vec<BalanceDiff>>,
75    ) -> Self {
76        let status: TransactionStatus = (&tx_result.result).into();
77        let tx_hash = tx.hash();
78        let initiator = tx.initiator_account();
79        let payer = tx.payer();
80
81        let used = tx.gas_limit() - tx_result.refunds.gas_refunded;
82        let limit = tx.gas_limit();
83        let refunded = tx_result.refunds.gas_refunded;
84
85        Self {
86            status,
87            tx_hash,
88            initiator,
89            payer,
90            context: TransactionContext { l2_gas_price },
91            gas: GasDetails {
92                limit,
93                used,
94                refunded,
95            },
96            balance_diffs,
97        }
98    }
99}
100
101impl Display for TransactionSummary {
102    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103        let Self {
104            status,
105            tx_hash,
106            initiator,
107            payer,
108            context: TransactionContext { l2_gas_price },
109            gas,
110            balance_diffs,
111        } = self;
112
113        // Calculate gas costs in ETH
114        let paid = U256::from(*l2_gas_price) * gas.used;
115        let refunded = U256::from(*l2_gas_price) * gas.refunded;
116
117        // Format human-readable values
118        let gas_used = gas.used;
119        let gas_limit_human = to_human_size(gas.limit);
120        let gas_used_human = to_human_size(gas.used);
121        let gas_refunded_human = to_human_size(gas.refunded.into());
122        let emoji = self.status.emoji();
123        let l2_gas_price_human = format_gwei(self.context.l2_gas_price.into());
124
125        // Basic transaction information
126        write!(
127            f,
128            r#"
129{emoji} [{status}] Hash: {tx_hash:?}
130Initiator: {initiator:?}
131Payer: {payer:?}
132Gas Limit: {gas_limit_human} | Used: {gas_used_human} | Refunded: {gas_refunded_human}
133Paid: {paid_in_eth} ({gas_used} gas * {l2_gas_price_human})
134Refunded: {refunded_in_eth}
135"#,
136            paid_in_eth = format_eth(paid),
137            refunded_in_eth = format_eth(refunded),
138        )?;
139
140        if let Some(balance_diffs) = balance_diffs {
141            if !balance_diffs.is_empty() {
142                let mut balance_diffs_formatted_table = tabled::Table::new(
143                    balance_diffs
144                        .iter()
145                        .map(Into::<BalanceDiffRepr>::into)
146                        .collect::<Vec<_>>(),
147                );
148                balance_diffs_formatted_table.with(tabled::settings::Style::modern());
149
150                write!(f, "\n{balance_diffs_formatted_table}")?;
151            }
152        }
153        Ok(())
154    }
155}