import { useLatestTransactions } from '../../hooks/useLatestTransactions'; import { explorerTxUrl, explorerAddressUrl, type ExplorerTx } from '../../services/explorer'; import { formatEther } from 'ethers'; import { Activity } from 'lucide-react'; const shortHash = (h: string) => `${h.slice(0, 10)}…${h.slice(-6)}`; const shortAddr = (a: string) => `${a.slice(0, 6)}…${a.slice(-4)}`; const formatMETA = (wei: string) => { try { return `${Number(formatEther(BigInt(wei))).toFixed(4)} META`; } catch { return `${wei} wei`; } }; const relativeTime = (iso: string) => { const then = new Date(iso).getTime(); const dt = Date.now() - then; if (dt < 60_000) return `${Math.max(1, Math.round(dt / 1000))}s ago`; if (dt < 3_600_000) return `${Math.round(dt / 60_000)}m ago`; return `${Math.round(dt / 3_600_000)}h ago`; }; interface Props { /** Max rows to show (default 10). */ limit?: number; /** Custom card header label — defaults to "Live Chain-138 Transactions". */ title?: string; } /** * Renders the most recent on-chain transactions from SolaceScan. * Degraded state shows the error message; empty state shows a one-liner. * Links every hash/address to the explorer. */ export default function LiveTransactionsPanel({ limit = 10, title = 'Live Chain-138 Transactions' }: Props) { const { transactions, loading, error, lastUpdated } = useLatestTransactions(limit); return (

{title}

{error ? RPC degraded · {error} : loading ? 'loading…' : `${transactions.length} tx · ${lastUpdated ? lastUpdated.toLocaleTimeString() : '—'}`}
{!loading && transactions.length === 0 && !error && (
No transactions returned yet — SolaceScan may be indexing.
)} {transactions.map((tx: ExplorerTx) => (
{shortHash(tx.hash)} {shortAddr(tx.from.hash)} {tx.to ? shortAddr(tx.to.hash) : '— contract create —'} {formatMETA(tx.value)} {relativeTime(tx.timestamp)} {tx.status ?? 'pending'}
))}
Source: SolaceScan Explorer {' · polls every 15s · Blockscout v2 /transactions'}
); }