eth-etl-core 0.1.0

Core types and utilities for Ethereum ETL
Documentation
use serde::{Deserialize, Serialize};

/// Transaction receipt with L1 fee data (Optimism) and blob gas
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct EthReceipt {
    #[serde(rename = "type", default = "default_receipt_type")]
    pub item_type: String,
    pub transaction_hash: String,
    pub transaction_index: u64,
    pub block_hash: String,
    pub block_number: u64,
    pub cumulative_gas_used: u64,
    pub gas_used: u64,
    pub contract_address: Option<String>,
    pub root: Option<String>,
    pub status: Option<u64>,
    pub effective_gas_price: Option<u64>,
    /// L1 fee (Optimism)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub l1_fee: Option<String>,
    /// L1 gas used (Optimism)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub l1_gas_used: Option<String>,
    /// L1 gas price (Optimism)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub l1_gas_price: Option<String>,
    /// L1 fee scalar (Optimism)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub l1_fee_scalar: Option<f64>,
    /// EIP-4844 blob gas used
    #[serde(skip_serializing_if = "Option::is_none")]
    pub blob_gas_used: Option<u64>,
    /// EIP-4844 blob gas price
    #[serde(skip_serializing_if = "Option::is_none")]
    pub blob_gas_price: Option<u64>,
}

fn default_receipt_type() -> String {
    "receipt".to_string()
}

impl EthReceipt {
    /// Get CSV headers for receipt export
    pub fn csv_headers() -> &'static [&'static str] {
        &[
            "transaction_hash",
            "transaction_index",
            "block_hash",
            "block_number",
            "cumulative_gas_used",
            "gas_used",
            "contract_address",
            "root",
            "status",
            "effective_gas_price",
            "l1_fee",
            "l1_gas_used",
            "l1_gas_price",
            "l1_fee_scalar",
            "blob_gas_used",
            "blob_gas_price",
        ]
    }

    /// Convert to CSV row
    pub fn to_csv_row(&self) -> Vec<String> {
        vec![
            self.transaction_hash.clone(),
            self.transaction_index.to_string(),
            self.block_hash.clone(),
            self.block_number.to_string(),
            self.cumulative_gas_used.to_string(),
            self.gas_used.to_string(),
            self.contract_address.clone().unwrap_or_default(),
            self.root.clone().unwrap_or_default(),
            self.status.map(|v| v.to_string()).unwrap_or_default(),
            self.effective_gas_price
                .map(|v| v.to_string())
                .unwrap_or_default(),
            self.l1_fee.clone().unwrap_or_default(),
            self.l1_gas_used.clone().unwrap_or_default(),
            self.l1_gas_price.clone().unwrap_or_default(),
            self.l1_fee_scalar
                .map(|v| v.to_string())
                .unwrap_or_default(),
            self.blob_gas_used
                .map(|v| v.to_string())
                .unwrap_or_default(),
            self.blob_gas_price
                .map(|v| v.to_string())
                .unwrap_or_default(),
        ]
    }
}