//! System transaction for the `MegaETH` EVM.
//!
//! The mega system transaction is a special protocol-maintenance transaction with minimal
//! side effects:
//! - no transaction fee (no L2 gas fee, no L1 data fee, no base fee, etc.), thus no state change to
//!   the block beneficiary or any fee vaults.
//! - system address's nonce still bumps as normal transactions
//!
//! This module contains constants, types, and utilities related to mega system transactions.

use alloy_primitives::{address, b256, Address, TxKind, B256};
use op_revm::transaction::deposit::DEPOSIT_TRANSACTION_TYPE;
use revm::context::Transaction;

use crate::{types::MegaTransaction, ORACLE_CONTRACT_ADDRESS};

/// The `MegaETH` system address for deposit-like transaction processing.
/// Normal transactions sent from this address are processed as deposit transactions,
/// bypassing signature validation, nonce verification, and fee deduction.
///
/// It can only call whitelisted addresses.
pub const MEGA_SYSTEM_ADDRESS: Address = address!("0xA887dCB9D5f39Ef79272801d05Abdf707CFBbD1d");

/// The whitelist of addresses that are allowed to be called by the `MegaETH` system address.
pub const MEGA_SYSTEM_TX_WHITELIST: &[Address] = &[ORACLE_CONTRACT_ADDRESS];

/// The source hash of the `MegaETH` system transaction, used to set the `source_hash` field of the
/// op deposit info. The value is `keccak256("MEGA_SYSTEM_TRANSACTION")`.
pub const MEGA_SYSTEM_TRANSACTION_SOURCE_HASH: B256 =
    b256!("852c082c0faff590c6300c2c34815d1f79882552fa95ba413cd5aeb1dba84957");

/// The source hash of the `MegaETH` keyless-deploy sandbox transaction. Used to set the
/// `source_hash` field of the op deposit info so the sandbox tx is treated as a deposit-like
/// transaction (bypasses L1/operator fee, validation, fee distribution). The value is
/// `keccak256("MEGA_SANDBOX_TRANSACTION")`.
pub const SANDBOX_TX_SOURCE_HASH: B256 =
    b256!("3bc757a39ecb6dc5b5e5715352016c2b6fd38968a78cc57e878d9be249bc62f4");

/// Checks if a transaction is sent from the given system address.
pub fn sent_from_system_address(tx: &MegaTransaction, system_address: Address) -> bool {
    tx.caller() == system_address
}

/// Checks if a transaction is a mega system transaction using the given system address.
/// A mega system transaction is a legacy transaction that is submitted by the system address
/// and calls a whitelisted address in `MEGA_SYSTEM_TX_WHITELIST`.
pub fn is_mega_system_transaction_with(tx: &MegaTransaction, system_address: Address) -> bool {
    check_if_mega_system_transaction(tx.caller(), tx.tx_type(), tx.kind(), system_address)
}

/// Checks if a transaction is a mega system transaction.
///
/// # Arguments
///
/// * `tx_signer` - The signer of the transaction
/// * `tx_type` - The type of the transaction
/// * `tx_kind` - The kind of the transaction
/// * `system_address` - The current system address for this block
///
/// # Returns
///
/// Returns `true` if the transaction is a mega system transaction, `false` otherwise.
pub fn check_if_mega_system_transaction(
    tx_signer: Address,
    tx_type: u8,
    tx_kind: TxKind,
    system_address: Address,
) -> bool {
    if tx_type == 0x0 && tx_signer == system_address {
        // a mega system transaction must be a legacy transaction
        match tx_kind {
            TxKind::Create => false,
            TxKind::Call(address) => MEGA_SYSTEM_TX_WHITELIST.contains(&address),
        }
    } else {
        false
    }
}

/// Checks if a transaction should be processed as a deposit-like transaction.
///
/// This includes both actual deposit transactions (`DEPOSIT_TRANSACTION_TYPE`) and normal
/// transactions from the `MegaETH` system address (mega system transactions).
///
/// # Arguments
///
/// * `tx` - The transaction to check
///
/// # Returns
///
/// Returns `true` if the transaction should be processed as deposit-like, `false` otherwise.
pub fn is_deposit_like_transaction(tx: &MegaTransaction, system_address: Address) -> bool {
    // Check if it's an actual deposit transaction
    if tx.tx_type() == DEPOSIT_TRANSACTION_TYPE {
        return true;
    }

    // Check if it's from the mega system address
    is_mega_system_transaction_with(tx, system_address)
}
