Skip to content

feat(tx): TX Analyser — call tree, state changes, and contract enrichment#281

Merged
AugustoL merged 18 commits intodevfrom
feat/tx-analyser
Mar 13, 2026
Merged

feat(tx): TX Analyser — call tree, state changes, and contract enrichment#281
AugustoL merged 18 commits intodevfrom
feat/tx-analyser

Conversation

@AugustoL
Copy link
Copy Markdown
Collaborator

@AugustoL AugustoL commented Mar 6, 2026

Description

Adds a TX Analyser panel to the transaction details page (visible in Super User mode). Inspired by tools like Tenderly, it provides a deep-dive into transaction execution without leaving OpenScan.

Related Issue

Closes #274

Type of Change

  • New feature

Changes Made

Adapters

  • Added getAnalyserCallTrace and getAnalyserPrestateTrace abstract methods to NetworkAdapter
  • Implemented in all network adapters (EVM, Arbitrum, Optimism, Base, BNB, Polygon) using debug_traceTransaction with callTracer / prestateTracer
  • Arbitrum tries Geth callTracer first, falls back to arbtrace_transaction (Parity flat format)

Utilities

  • callTreeUtils.ts — normalize Geth and Parity/arbtrace traces to a unified CallNode tree; helpers: countCalls, countReverts, countByType, collectAddresses, hexToGas
  • contractLookup.ts — fetch contract name + ABI from Sourcify (Etherscan V2 fallback when API key is configured); session-level cache keyed by chainId:address

Hooks

  • useCallTreeEnrichment — enriches all addresses in a call tree in parallel; aborts on tree/network change

UI (TxAnalyser.tsx)

  • Call Tree tab: expandable/collapsible node tree, call type badges (color-coded), from → to with contract names, decoded function calls (transfer(0x1234…, 100)), ETH value, gas used, error badges
  • State Changes tab: per-address balance/nonce/storage/code diffs with contract names
  • Summary bar: total gas, call count, per-type breakdown (e.g. 3× STATICCALL), revert count, enrichment loading indicator

Integration

  • TransactionDisplay.tsx — collapsible "TX Analyser ▼" section, shown only when isSuperUser is enabled
  • Translations: all 5 locales (en, es, ja, pt-BR, zh) with analyser.* keys
  • CSS: full styling for analyser tabs, call tree nodes, state change blocks

Screenshots (if applicable)

To be added — test with any mainnet transaction on a trace-enabled RPC (dRPC, Tenderly).

Checklist

  • I have run npm run format:fix and npm run lint:fix
  • I have run npm run typecheck with no errors
  • I have run tests with npm run test:run
  • I have tested my changes locally
  • I have updated documentation if needed
  • My code follows the project's architecture patterns

Additional Notes

  • Trace methods work on any RPC that supports debug_traceTransaction (dRPC free tier, Tenderly, Alchemy, Ankr with key). The UI shows a clear "not supported" message with provider suggestions when the RPC doesn't support traces.
  • Contract enrichment (Sourcify) works without any API key. Etherscan fallback activates only when settings.apiKeys.etherscan is set (opt-in).
  • etherscan field added to ApiKeys type in anticipation of PR feat(address): proxy contract detection + Etherscan verification source #279 (Etherscan as verification source).

… enrichment

Adds a TX Analyser panel (super user mode) to the transaction details page.

- Adds getAnalyserCallTrace / getAnalyserPrestateTrace to all network adapters (EVM, Arbitrum, Optimism, Base, BNB, Polygon) using debug_traceTransaction with callTracer / prestateTracer; Arbitrum falls back to arbtrace_transaction
- New CallNode / PrestateTrace types in NetworkAdapter
- New callTreeUtils: normalizeGethCallTrace, normalizeParityCallTrace, countCalls, countReverts, countByType, collectAddresses, hexToGas
- New contractLookup utility: fetches contract name + ABI from Sourcify (Etherscan fallback when key configured); session-level cache
- New useCallTreeEnrichment hook: enriches all call tree addresses in parallel, aborts on tree change
- TxAnalyser component: Call Tree tab with expandable nodes, decoded function calls, contract names, per-type summary; State Changes tab with balance/nonce/storage/code diffs and contract names
- Collapsible TX Analyser section in TransactionDisplay (super users only)
- Translations for all 5 locales (en, es, ja, pt-BR, zh)
- All CSS styles for analyser, call tree, and state change components
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 6, 2026

🚀 Preview: https://pr-281--openscan.netlify.app
📝 Commit: 50a7c5df8198f3078d110d2f8bb0a02225eb7606

AugustoL added 12 commits March 12, 2026 16:55
Adds a Gas Profiler tab to the TX Analyser that shows how gas is
spent across all operations in a transaction. Flattens the call tree
into a sorted table with columns: type, contract, function, gas used
(with percentage bar). Reuses existing call tree data — no additional
RPC calls needed.

Translations added for all 5 locales (en, es, ja, pt-BR, zh).
…it for contract enrichment

Replace the table-based Gas Profiler with a Tenderly-style icicle/flame chart
with click-to-zoom and breakdown panel. All analyser tabs now wait for contract
ABI enrichment to complete before rendering, ensuring decoded function names
are displayed instead of raw selectors.
In super user mode, event logs are now displayed inside the TX Analyser
as a dedicated Events tab instead of a separate collapsible section.
The Events tab leverages enriched contract ABIs from the call tree
enrichment to decode events from all addresses, not just the tx recipient.
Non-super-user mode retains the original collapsible event logs section.
In super user mode, raw and decoded input data are now displayed inside
the TX Analyser as an Input Data tab. The tab also tries enriched ABIs
from call tree enrichment as a fallback for decoding. Non-super-user
mode retains the original input data rows in the transaction details.
Remove the collapsible toggle button — the TX Analyser section is now
always visible when super user mode is active.
Fix race condition where call tree tabs rendered with empty contracts
for one frame before the enrichment useEffect had a chance to run.
Track a pendingEnrichment state to bridge the gap between when the
call tree arrives and when the async enrichment effect fires.
Replace pendingEnrichment workaround with a simpler done-flag approach.
enrichmentLoading is now true from the moment a call tree exists until
all contract info has been fetched, eliminating any render gap.
Sourcify V2 API does not have a top-level 'name' field — the contract
name is nested under compilation.name. Changed the request from
?fields=abi,name (which returned a 400 error) to ?fields=abi,compilation
and extracted the name from compilation.name.
…Data tabs

The TX Analyser is now always visible on transaction pages. Base users
see Events and Input Data tabs. Super user mode unlocks Call Tree, Gas
Profiler, and State Changes tabs. Trace fetching is skipped in base
mode. Removed duplicate event logs and input data sections from
TransactionDisplay since TxAnalyser now handles them for all users.
Base user tabs (Events, Input Data) use --text-primary when active.
Super user tabs (Call Tree, Gas Profiler, State Changes) use
--color-accent to visually signal the user is viewing advanced data.
@AugustoL AugustoL requested a review from josealoha666 March 12, 2026 21:02
@AugustoL AugustoL self-assigned this Mar 12, 2026
@AugustoL AugustoL marked this pull request as ready for review March 12, 2026 21:03
@MatiasOS
Copy link
Copy Markdown
Member

This looks really really good!!

  • This headers should use full address. Is not necessary to shorttened
image
  • It will better if events and state changes headers are collapsed by default?

…fix links

- Make event logs and state changes collapsible by default with
  expand/collapse all buttons
- Show full addresses in call tree instead of shortened
- Fix all address links to use /{networkId}/address/{addr} path format
- Add expandAll/collapseAll i18n keys to all 5 locales
- Fetch contract info for event log addresses independently of call
  tree, so event decoding works for all users (not just super user)
- Resolve proxy contract implementations via Sourcify proxyResolution
  and merge implementation ABI for proper event/function decoding
- Stabilize usePersistentCache callbacks with refs so toggling
  isSuperUser doesn't recreate getCached/setCached identities
- Reset active analyser tab to a base tab when leaving super user mode
- Add collapse/expand button on the tab bar with text and arrow
- Clicking active tab toggles collapse; clicking other tab expands to it
- Base user mode starts collapsed; super user mode starts expanded
- Switching to super user auto-expands the analyser
- Add expand/collapse i18n keys to all 5 locales
@josealoha666
Copy link
Copy Markdown
Collaborator

@AugustoL a few things I noticed during review:

1. collectAddresses misses from addresses in call tree

In callTreeUtils.ts, collectAddresses only traverses to addresses:

if (n.to) addrs.add(n.to.toLowerCase());

Contracts acting as callers in DELEGATECALL chains won't be enriched (no name, no ABI). Simple fix:

if (n.from) addrs.add(n.from.toLowerCase());
if (n.to)   addrs.add(n.to.toLowerCase());

2. TxAnalyser.tsx — 1,272 lines, 7+ components in a single file

CallTreeNode, CallTreeTab, StateChangesTab, GasProfilerTab, FlameRow, InputDataTab, EventLogsTab and TxAnalyser itself all live together. Hard to navigate and harder to maintain. Suggest splitting into a tx-analyser/ directory — not a blocker, but worth a follow-up before this grows further.


3. Log enrichment runs on mount regardless of active tab

The useEffect that fetches contract info for event logs fires immediately, even if the user is on Call Tree or Gas Profiler and never opens Events. For txs with many logs this is unnecessary network traffic. Lazy-loading (trigger fetch only when the Events tab becomes active) would be a cleaner pattern — same approach already used for the prestate trace.


4. "monospace" with quotes in CSS

In a few .call-tree-node and .state-change-row rules, font-family uses the quoted string "monospace" — this is treated as a specific named font, not the CSS generic family. Should be unquoted: font-family: monospace;

@AugustoL
Copy link
Copy Markdown
Collaborator Author

Thanks for the review! Here's the status:

1. collectAddresses misses from addresses — Fixed. Now collects both from and to.

2. TxAnalyser.tsx too large — Fixed. Split into 6 files under analyser/ directory (types.ts, CallTreeTab.tsx, StateChangesTab.tsx, GasProfilerTab.tsx, InputDataTab.tsx, EventLogsTab.tsx). Main TxAnalyser.tsx is now ~270 lines.

3. Log enrichment runs on mount — Keeping as-is. We need to start fetching contract data (names + ABIs) as soon as the component mounts so it's ready by the time the user opens the Events tab. Waiting until tab activation would add a visible loading delay since Sourcify lookups take time, especially for txs with many unique contracts.

4. "monospace" with quotes — Fixed. Unquoted across all occurrences.

- Split TxAnalyser.tsx (1,272 lines) into 6 files under analyser/ directory
- Fix collectAddresses to collect both from and to addresses (DELEGATECALL enrichment)
- Fix CSS "monospace" to unquoted generic family name
@josealoha666
Copy link
Copy Markdown
Collaborator

@MatiasOS Thanks for the feedback! Fixed both items:

  1. Full addresses in headers — Removed address truncation in trace and event log headers. Now displaying complete addresses.
  2. Collapsed by default — Events and state changes sections now start collapsed by default, users can expand on demand.

Pushed to feat/tx-analyser.

@AugustoL AugustoL merged commit 315d089 into dev Mar 13, 2026
5 of 8 checks passed
@AugustoL AugustoL mentioned this pull request Mar 16, 2026
10 tasks
Copy link
Copy Markdown
Collaborator

@josealoha666 josealoha666 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the current head SHA. I don’t see anything obviously blocking from a quick pass, but I’m leaving this as a comment rather than approval so a human can confirm intent and coverage.

Copy link
Copy Markdown
Collaborator

@josealoha666 josealoha666 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of things to address before merge:

  • src/components/pages/evm/tx/TransactionDisplay.tsx still contains TODO/FIXME markers in the diff.

Copy link
Copy Markdown
Collaborator

@josealoha666 josealoha666 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked the current head and I do not see an obvious blocking issue from the diff/API view. If CI is green, this looks fine from my side.

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.

3 participants