Skip to content

feat(v0.2.0): Universal Multi-VM Execution Profiler, Atupa Studio, and Protocol Deep Audits - #12

Merged
intelliDean merged 37 commits into
One-Block-Org:mainfrom
intelliDean:main
Aug 29, 2026
Merged

feat(v0.2.0): Universal Multi-VM Execution Profiler, Atupa Studio, and Protocol Deep Audits#12
intelliDean merged 37 commits into
One-Block-Org:mainfrom
intelliDean:main

Conversation

@intelliDean

Copy link
Copy Markdown
Collaborator

🏮 Summary of Changes (v0.2.0 Release)

This pull request upgrades Atupa into a Universal Multi-VM Execution Profiler & Visual Analysis Suite, delivering native support for EVM, Arbitrum Stylus (Dual-VM), Solana (SVM), Starknet (Cairo), and Stellar (Soroban), alongside deep protocol-specific decoders, embedded local Studio visualization, and CI gas regression gating.


🌐 Multi-VM Execution Adapters & Unified Clock Stitching

  • Arbitrum Stylus (Dual-VM): Full clock synchronization between EVM struct logs and Stylus WASM HostIO calls (msg_sender, storage_load_bytes32, native_keccak256), with ranked HostIO Hot Paths analysis.
  • Solana (SVM): Sequential log parser and state machine reconstructing nested instruction trees, tracking Compute Unit (CU) consumption, SPL token transfers, and Raydium swap pool invariants.
  • Starknet (Cairo): Cairo function invocation flattener capturing recursive call hierarchies and builtin resource metrics (ECDSA verification, Pedersen hash, Range Check).
  • Stellar (Soroban): Diagnostic event parser tracking Host Function weights (get_contract_data, put_contract_data, compute_sha256) and state ledger updates.

🔬 Protocol-Specific Deep Auditing

  • Aave v3 / GHO: Semantic decoders for Pool.supply, ScaledBalance rebase indexing, real-time address label resolution, and GHOFlashMinter flash loan tracking.
  • Lido stETH: Full staking pipeline tracing (submit() -> stETH::mintShares rebase calculation -> Lido Oracle consensus reports -> Withdrawal Queue NFT minting).

💻 Modular Rust CLI & Project Scaffolding

  • Decomposed monolithic CLI into single-responsibility modules (profile, capture, audit, diff, studio, init).
  • atupa init: Auto-detects Foundry, Hardhat, and Stylus projects to scaffold atupa.toml and automated GitHub Actions workflows in one click.
  • atupa diff: Self-contained differential gas evaluator enforcing budget thresholds (--threshold) with automated markdown and SVG flamegraph generation.

🏮 Atupa Studio (Embedded Local-First Web UI)

  • Pure React 19 + TypeScript + Vite web app embedded directly in the CLI binary via rust-embed.
  • Chain-Adaptive UI: Dynamically adjusts metrics, badges, and units (CU, steps, gas-equiv, gas) according to the detected VM runtime.
  • Interactive zoomable SVG flamegraphs with hover tooltips, searchable trace inspector, and preloaded one-click presets for all 7 supported environments.

🛡️ CI/CD & Testing

  • Modernized GitHub Actions workflow matrix for formatting (rustfmt.toml), linting (clippy), and unit tests.
  • Gas regression test suite running on ephemeral Anvil nodes with sticky PR comments.
  • Cross-platform release builds (Linux x86_64, macOS Apple Silicon/Intel, Windows x86_64) with SHA-256 checksums.

✅ Verification

  • cargo test --workspace: 100% passed (all unit, integration, and doctests)
  • cargo clippy --workspace --all-targets: 0 warnings
  • cargo fmt --all -- --check: 100% clean
  • Studio linter: 0 errors

intelliDean added 30 commits May 4, 2026 18:14
- Extracted network-specific handlers from monolithic routers (cmd_capture, cmd_diff).
- Modularized Nitro diff processing (calculate, print, render markdown, svg).
- Modularized generic diff processing and rendering terminal summaries.
- Fixed Clippy warnings (too_many_arguments, collapsible if).
- Fully formatted the codebase.
…tput format

Previously, finalize_report() unconditionally wrote the 'rendered' string to
the .json artifact file. When --output=summary (the default), rendered contained
ANSI terminal escape codes, making the file unreadable by Studio, CI tooling,
and any downstream JSON parser.

Fix: introduce a separate json_for_disk parameter that always holds the full
serde_json-serialised report. The terminal-rendered string (with ANSI codes,
short summaries, metric values) is printed to stdout only.

All four capture handlers (nitro, starknet, solana, stellar) updated.
render_nitro_report now returns (terminal_text, json) as a tuple.
…dio compatibility

Starknet, Solana and Stellar capture handlers previously wrote a raw
Vec<TraceStep> array to disk. The Studio's App.tsx and reportToTree.ts
expect a StitchedReport object (tx_hash, steps: UnifiedStep[], totals).
Loading non-Nitro reports in Studio would crash.

Changes:
- atupa-nitro VmKind: add Starknet / Solana / Stellar variants (From impl updated)
- main.rs: add trace_steps_to_report() helper that wraps Vec<TraceStep>
  into a proper StitchedReport with chain-specific VmKind on each step
- All three handlers use trace_steps_to_report() so every .json artifact
  is a uniform StitchedReport — loadable by Studio, diff, audit commands
- Split monolithic lib.rs into vm.rs, gas.rs, types.rs, diff.rs, config.rs
- VmKind: add #[non_exhaustive], Display, TryFrom<&str> (with 'soroban' alias),
  and ParseVmKindError
- GasCategory: exhaustive EVM match, unified classify_by_keyword() helper for
  Stylus/Starknet/Solana/Stellar, GasCategory::from_step now takes &VmKind
- TraceStep: add TraceStep::evm() test-fixture constructor and is_call() helper
- Profile: introduce ProfileBuilder with injectable generated_at timestamp for
  deterministic snapshot testing
- DiffRow: add is_regression(), is_improvement(), is_neutral() predicates
- ProtocolDiffReport: add has_regressions(), regressions(), improvements() helpers
- AtupaConfig: add validate(), extract build_figment() helper, replace silent
  unwrap_or_else with log::warn!, use ENV_LOCK Mutex in tests for safe env mutation
- lib.rs is now a thin re-export facade — all downstream import paths unchanged
- 35 unit tests + 4 doc-tests all passing; clippy -D warnings clean
…nd tests

- Extract LiquidationAccumulator to hold per-step state, removing the 60-line
  monolith from analyze_liquidation
- Extract private helpers: resolve_address(), resolve_selector(), is_call_opcode(),
  selector_from_stack(), classify_gho_label(), build_diff_rows() — each with a
  single clear responsibility
- Merge the duplicated selector-lookup logic from resolve_label and
  resolve_selector_label into one shared resolve_selector() function
- is_call_opcode() predicate shared by both analyze_liquidation and
  extract_gho_metrics, eliminating the duplicated guard
- Fix bogus oracle addresses (placeholder '0xD81E9938...?' and oversized address)
  with real Ethereum Mainnet values; store all addresses lowercase for O(1) compare
- Add LIQUIDATION_EFFICIENCY_BASE named constant replacing the magic 100_000.0
- Fix summary() panic on short hashes by using .get(..10).unwrap_or()
- Add #[derive(PartialEq)] to LiquidationReport, LabeledCall, GhoSupplyMetrics
- Remove unused thiserror and serde_json from Cargo.toml
- Expand tests from 5 → 15, covering: facilitator/oracle address resolution,
  resolve_selector_label, summary() short-hash safety, zero-efficiency edge case,
  reverted-flag propagation, GHO non-call filter, and diff regression detection
Mirrors the same pattern applied to atupa-core.

New modules:
- selectors.rs : const tables (POOL_SELECTORS, GHO_SELECTORS, GHO_FACILITATORS,
                 AAVE_ORACLES), resolve_address(), resolve_selector(),
                 is_call_opcode(), selector_from_stack(), LIQUIDATION_EFFICIENCY_BASE
- adapter.rs   : AaveV3Adapter + ProtocolAdapter impl + static resolve_selector_label
- gho.rs       : GhoSupplyMetrics + classify_gho_label()
- report.rs    : LiquidationReport, LabeledCall, LiquidationAccumulator
- tracer.rs    : AaveDeepTracer, build_diff_rows()
- lib.rs       : thin pub mod + pub use re-export facade (all paths unchanged)

Tests: 35 tests across all 5 modules (selectors: 10, adapter: 7, gho: 5,
report: 5, tracer: 8) — all passing, clippy -D warnings clean
…ilder and ERC-20 adapter

- Split monolithic lib.rs into traits.rs, registry.rs, uniswap_v4.rs, erc20.rs
- ProtocolAdapter: add Send + Sync bounds, default helper methods (resolve_selector,
  resolve_address, matches_address, matches_selector)
- AdapterRegistry: add with_adapter/with_boxed_adapter builder chaining, register_typed,
  clear, contains, len, is_empty, iter, and resolve_selector/resolve_address helpers
- UniswapV4Adapter: static resolve_hook_selector helper, case-insensitive matching
- Erc20Adapter: new standard ERC-20/ERC-721/permit built-in adapter
- Clean up unused dependencies from Cargo.toml
- Add 18 unit tests + doc tests (previously 0 unit tests), clippy clean
…nd comprehensive test suite

- Split monolithic lib.rs into selectors.rs, adapter.rs, report.rs, tracer.rs
- selectors.rs: exact/prefixed/case-insensitive selector matching, lowercase address constants
- adapter.rs: LidoAdapter + ProtocolAdapter implementation with static resolve_selector_label
- report.rs: LidoReport, LabeledCall, LidoAccumulator step processor, summary() with safe slice
- tracer.rs: LidoDeepTracer, build_diff_rows()
- lib.rs: thin re-export facade
- Clean up unused dependencies (serde_json, log) from Cargo.toml
- Add 19 unit tests (previously 0 unit tests), clippy clean
…itcher, client, and types

- Split monolithic lib.rs into error.rs, types.rs, stitcher.rs, client.rs
- error.rs: NitroError enum with Network, Rpc, Serialization, Stitch variants, NitroResult alias
- types.rs: StylusHostIO (cost calculations), VmKind (Display + conversion), UnifiedStep (to_trace_step, is_evm, is_stylus), StitchedReport (queries, summary with bounds check)
- stitcher.rs: MixedTraceStitcher decomposed into clean helpers (extract_target_address, drain_wasm_window, drain_trailing_stylus_steps, aggregate_category_costs)
- client.rs: NitroClient with concurrent dual-tracing and extracted is_nitro_chain helper
- Clean up unused anyhow dependency from Cargo.toml
- Expanded unit tests to 15 tests, full workspace clippy clean
…or, and diff renderer

- Split monolithic lib.rs into common.rs, flamegraph.rs, diff.rs
- common.rs: layout constants (canvas width, bar height, padding), shared truncate_label(), stack_leaf(), and render_empty_svg()
- flamegraph.rs: SvgGenerator with decomposed layout_depth_lanes(), layout_wasm_section(), make_bar_label(), build_tooltip(), get_stack_css_class()
- diff.rs: generate_diff_flamegraph using shared common layout helpers and cleaner bar/legend rendering
- lib.rs: thin module facade re-exporting SvgGenerator and generate_diff_flamegraph
- Cargo.toml: cleaned unused serde, serde_json, log dependencies
- Expanded unit tests across common, flamegraph, and diff modules (13 tests total), clippy clean
… modules

- Split monolithic files into decoder.rs, normalize.rs, aggregator.rs
- decoder.rs: extract_target_address() with 20-byte formatting, extract_memory_selector() with single/cross-word boundary memory parsing
- normalize.rs: Parser struct with normalize() and normalize_raw()
- aggregator.rs: Aggregator decomposing call context decoding from stack aggregation
- lib.rs: clean re-export facade
- Cargo.toml: remove unused dependencies (serde, serde_json, anyhow)
- Expanded unit tests across decoder, normalize, and aggregator (13 tests total), clippy clean
…odules

- Split monolithic lib.rs into error.rs, types.rs, client.rs, etherscan.rs
- error.rs: RpcError enum with Network, Json, Node variants, RpcResult alias
- types.rs: RawStructLog (is_reverted, is_call helpers), TraceResult, internal RpcResponse envelope
- client.rs: EthClient with debug_traceTransaction, eth_chainId, eth_getTransactionReceipt, and static selector_from_input()
- etherscan.rs: EtherscanResolver with async background warming and thread-safe flush
- Cargo.toml: clean unused anyhow dependency
- Expanded unit tests across all modules (8 tests total), clippy clean
- Split monolithic lib.rs into registry.rs, profile.rs, and thin lib.rs facade
- registry.rs: build_default_registry() pre-loading Uniswap v4, ERC-20, Aave v3 / GHO, Lido stETH
- profile.rs: VmHint enum, detect_vm() heuristics, execute_profile() decomposed into clean handlers (fetch_starknet_stacks, fetch_solana_stacks, fetch_stellar_stacks, fetch_evm_nitro_stacks, render_and_save_flamegraph), get_network_name(), demo_stacks()
- lib.rs: public module and re-export facade
- Added comprehensive unit tests across registry and profile modules (5 tests total), clippy clean
- Split monolithic lib.rs into error.rs, client.rs, parser.rs, and thin lib.rs facade
- error.rs: SolanaError enum with Network, Rpc, Parse, Timeout variants, SolanaResult alias
- client.rs: SolanaClient with get_transaction_logs, SolanaTransactionResponse, SolanaMeta
- parser.rs: SolanaLogStitcher with decomposed handle_invoke, handle_consumed, handle_return, OnceLock regex compilation
- Cargo.toml: clean unused anyhow, log, tokio dependencies
- Expanded unit tests across error, client, and parser modules (6 tests total), clippy clean
…ent modules

- Split monolithic lib.rs into error.rs, types.rs, flattener.rs, client.rs, and thin lib.rs facade
- error.rs: StarknetError enum with Network, Rpc, Serialization, Process variants, StarknetResult alias
- types.rs: ExecutionResources (has_builtins helper), FunctionInvocation, StarknetTransactionTrace
- flattener.rs: flatten_invocation, flatten_trace, explicit builtin gas-equivalent weights table (Pedersen, Range Check, Bitwise, Poseidon, EC OP, ECDSA)
- client.rs: StarknetClient with starknet_traceTransaction querying and profile_transaction
- Cargo.toml: clean unused anyhow, log, tokio dependencies
- Expanded unit tests across all modules (6 tests total), clippy clean
…modules

- Split monolithic lib.rs into error.rs, types.rs, parser.rs, client.rs, and thin lib.rs facade
- error.rs: StellarError enum with Network, Rpc, Parse, Timeout variants, StellarResult alias
- types.rs: SorobanDiagnosticEvent, StellarTransactionResponse data models
- parser.rs: StellarTraceParser with estimate_host_fn_gas_cost, cost constants (put_contract_data, get_contract_data, crypto, invoke), depth tracking
- client.rs: StellarClient with get_transaction_trace querying
- Cargo.toml: clean unused anyhow, log, tokio dependencies
- Expanded unit tests across all modules (7 tests total), clippy clean
@intelliDean
intelliDean merged commit 46a61cc into One-Block-Org:main Aug 29, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant