perpl-cli 0.2.4

Perpl DEX CLI
Documentation
use alloy::{eips::BlockId, providers::Provider, sol_types::SolEventInterface};
use colored::Colorize;
use perpl_sdk::{
    Chain,
    abi::dex::Exchange::ExchangeEvents,
    error::{DexError, ProviderError},
    stream::RawEvent,
};

use crate::highlight::Highlights;

pub(crate) async fn render<P: Provider + Clone>(
    chain: &Chain,
    provider: P,
    block_number: u64,
    highlights: &Highlights,
) -> anyhow::Result<()> {
    let exchange = chain.exchange();
    let receipts = provider
        .get_block_receipts(BlockId::number(block_number))
        .await
        .map_err(|err| DexError::Provider(err.into()))?
        .ok_or(DexError::Provider(ProviderError::InvalidRequest("Block not found".to_string())))?;

    let mut events = Vec::with_capacity(receipts.iter().map(|r| r.inner.logs().len()).sum());
    for receipt in receipts {
        for log in receipt
            .inner
            .logs()
            .iter()
            .filter(|log| log.address() == exchange)
        {
            events.push(RawEvent::new(
                log.transaction_hash.unwrap_or_default(),
                log.transaction_index.unwrap_or_default(),
                log.log_index.unwrap_or_default(),
                ExchangeEvents::decode_log(&log.inner)
                    .map_err(|err| DexError::Provider(err.into()))?
                    .data,
            ));
        }
    }

    println!("\n{}\n", format!("**** Block #{}", block_number).bold().purple());

    let mut prev_tx = None;
    let mut order_request = false;

    for event in events {
        if prev_tx.is_none_or(|tx| tx < event.tx_index()) {
            println!(
                "\n{}\n",
                format!("**** Tx #{} ({})", event.tx_index(), event.tx_hash()).bright_blue()
            );
            order_request = false;
        }
        prev_tx = Some(event.tx_index());

        let line = match event.event() {
            ExchangeEvents::OrderRequest { .. } => {
                order_request = true;
                format!("  {}: {:?}", event.log_index(), event.event())
                    .cyan()
                    .to_string()
            },
            ExchangeEvents::OrderBatchCompleted { .. } => {
                order_request = false;
                format!("  {}: {:?}", event.log_index(), event.event())
                    .cyan()
                    .to_string()
            },
            _ => format!(
                "  {}{}: {:?}",
                if order_request { "" } else { "" },
                event.log_index(),
                event.event()
            )
            .bright_cyan()
            .to_string(),
        };
        println!("{}", highlights.raw_event(event.event(), line));
    }

    println!();

    Ok(())
}