Skip to content

feat: decode ICA calls and transaction routes#326

Draft
paulbalaji wants to merge 5 commits into
mainfrom
feat/ica-decode-multicall-calls
Draft

feat: decode ICA calls and transaction routes#326
paulbalaji wants to merge 5 commits into
mainfrom
feat/ica-decode-multicall-calls

Conversation

@paulbalaji
Copy link
Copy Markdown
Collaborator

@paulbalaji paulbalaji commented May 5, 2026

Summary

Final polish PR after #259/#261 landed. Adds deeper ICA calldata parsing and a tx-level Transaction Overview panel so superswap/metaswap txs read as one origin-token to destination-token route when that route can be decoded.

Changes

  • Decode common ICA call calldata:
    • ERC20 approve, transfer, transferFrom
    • Warp Route transferRemote
    • Universal Router execute route summaries
  • Decode Hyperlane Universal Router command plans using the router command mask (0x3f):
    • V2/V3 exact-in and exact-out swap paths
    • nested EXECUTE_SUB_PLAN command plans
    • packed-byte and V2 address-array paths
    • sweep/transfer/pay-portion token output steps
    • unwrap-to-native output steps
    • exact/minimum output amount hints where calldata exposes them
  • Resolve transaction overview output tokens via:
    • warp-route registry metadata when available
    • on-chain ERC20/TRC20 symbol, name, decimals fallback for decoded token addresses
    • destination chain native-token metadata for unwrap/native outputs
  • Resolve actual transaction overview output amounts from destination receipts when available:
    • wrapped-native Withdrawal logs for native outputs such as TRX unwraps
    • ERC20/TRC20 Transfer logs to decoded output recipients for token outputs
  • Decode Multicall3/batch targets into nested call rows
  • Split ICA decoding into focused modules for types, router detection, body parsing, calldata decoding, reveal fetching, multicall parsing, and hooks
  • Reuse multicall parsing for REVEAL destination mailbox.process(metadata, message) tx parsing
  • Add tx-page collapsed-row ICA summaries (ICA Calls, ICA Commitment, ICA Reveal)
  • Add a tx-level Transaction Overview panel that combines:
    • origin input token/amount from the warp message
    • destination output token/native token and amount from decoded ICA swap calldata/receipt logs when available
  • Hide the tx overview when no decoded net output is available, instead of showing a misleading warp-only fallback
  • Ensure the tx overview loads on direct /tx/[txHash] visits, not only client navigation
  • Stack tx-page panels vertically and keep the narrower tx-page layout
  • Keep decoded call info prominent and raw calldata expandable
  • Keep call/detail surfaces on the explorer off-white palette
  • Fix tx-page origin tooltip placement
  • Add tests for multicall decoding, calldata parsing, router command flags, native unwraps, sub-plan unwraps, token sweep outputs, exact output amounts, V2 address-array paths, and multi-swap route decoding

Stack

Notes

  • Direct ICA CALLS messages decode from the Hyperlane message body without RPC fetches
  • COMMIT/REVEAL calls are not in the REVEAL body; they are recovered from destination mailbox.process(metadata, message) tx metadata
  • Transaction overview is best-effort and only renders once a net destination output can be decoded
  • Actual output amounts come from destination tx receipts when the output log pattern is unambiguous; otherwise the UI falls back to exact/minimum calldata amounts or token-only output

Validation

  • pnpm run format
  • pnpm run typecheck
  • pnpm run lint
  • pnpm run test -- src/features/messages/ica.test.ts src/utils/useVisibleInterval.test.ts
  • pnpm run build

Note

Medium Risk
Adds new ICA calldata/multicall decoding and uses it to derive cross-chain swap routes and output amounts; correctness depends on on-chain log parsing and ABI decoding, so mis-decoding could lead to misleading UI summaries but does not change transaction execution.

Overview
Adds deeper ICA call decoding and surfaces it in the UI. ICA calls now attempt to decode common calldata (ERC20 actions, transferRemote, and Universal Router swap plans), show a prominent decoded summary banner, and expand multicall/batch calls into nested call rows with per-target explorer links.

Refactors ICA utilities into a modular src/features/messages/ica/ package (body, calldata, multicall, reveal parsing, routers, hooks, types) and adds a comprehensive Jest suite covering multicall decoding and Universal Router edge cases.

Introduces a tx-level Transaction Overview panel that combines warp-transfer inputs with decoded ICA swap outputs (token/native), optionally resolving token metadata (registry or on-chain) and best-effort actual output amounts from destination receipts. The /tx/[txHash] page layout is updated to load required metadata on direct visits, improve ICA row titles/summaries, and tweak styling/tooltip placement.

Reviewed by Cursor Bugbot for commit 79628d9. Bugbot is set up for automated code reviews on this repo. Configure here.

@paulbalaji paulbalaji requested a review from Xaroz as a code owner May 5, 2026 20:49
@vercel
Copy link
Copy Markdown

vercel Bot commented May 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hyperlane-explorer Ready Ready Preview, Comment May 11, 2026 9:56pm

Request Review

@paulbalaji paulbalaji force-pushed the feat/ica-decode-multicall-calls branch from 6f16e5e to c2e736a Compare May 5, 2026 20:50
@paulbalaji paulbalaji marked this pull request as draft May 5, 2026 20:51
@paulbalaji paulbalaji force-pushed the feat/ica-decoding branch from 428e5f4 to 40b58f9 Compare May 5, 2026 20:56
@paulbalaji paulbalaji force-pushed the feat/ica-decode-multicall-calls branch from c2e736a to 244d022 Compare May 5, 2026 20:57
@paulbalaji paulbalaji changed the title feat: decode nested ICA multicalls feat: decode ICA call calldata May 5, 2026
@paulbalaji paulbalaji force-pushed the feat/ica-decode-multicall-calls branch from 244d022 to b1b5b9f Compare May 5, 2026 21:00
@paulbalaji paulbalaji force-pushed the feat/ica-decoding branch from 40b58f9 to abff71b Compare May 5, 2026 21:05
@paulbalaji paulbalaji force-pushed the feat/ica-decode-multicall-calls branch from b1b5b9f to a9e7399 Compare May 5, 2026 21:07
@paulbalaji paulbalaji force-pushed the feat/ica-decode-multicall-calls branch from a9e7399 to e9aace2 Compare May 5, 2026 21:09
@paulbalaji paulbalaji force-pushed the feat/ica-decode-multicall-calls branch from e9aace2 to 7ddda1e Compare May 5, 2026 21:12
Comment thread src/features/transactions/MessageSummaryRow.tsx
Comment thread src/features/messages/ica.ts Outdated
Comment thread src/features/transactions/TransactionRouteSummaryCard.tsx
@paulbalaji paulbalaji force-pushed the feat/ica-decode-multicall-calls branch from 42243f9 to d6f7874 Compare May 5, 2026 21:39
@paulbalaji paulbalaji changed the title feat: decode ICA call calldata feat: decode ICA calls and net swap routes May 5, 2026
@paulbalaji paulbalaji force-pushed the feat/ica-decode-multicall-calls branch from d6f7874 to 7bb5c1c Compare May 5, 2026 21:46
Comment thread src/features/messages/ica.ts Outdated
Comment thread src/styles/global.css
Comment thread src/features/transactions/TransactionRouteSummaryCard.tsx Outdated
@Xaroz
Copy link
Copy Markdown
Contributor

Xaroz commented May 11, 2026

@claude review

@claude
Copy link
Copy Markdown

claude Bot commented May 11, 2026

Claude finished @Xaroz's task in 5m 57s —— View job


Claude PR Review

  • Gather PR diff context vs origin/feat/ica-decoding
  • Run /claude-review analysis
  • Post consolidated inline PR review via /inline-pr-comments

Consolidated review posted: Review #4265119846.

Headline findings (none blocking):

  1. ica.ts:522-532formatTokenAmount 6-decimal fallback misformats small 18-dec amounts. An 18-decimal token amount of 1e11 wei (0.0000001) trips the < 0.000001 branch and renders as 100,000 tokens instead of 0.0000001. The decoder can't actually know the token's decimals — recommend dropping the 6-dec fallback or showing raw units.
  2. TransactionRouteSummaryCard.tsx:404-423 — token-output summation can double-count. outputRecipients includes both intermediate swap recipients (often the router itself) and final sweep recipients; summing every Transfer to any of them inflates the output when funds flow router→user. Native path is already conservative — recommend mirroring that pattern (or restrict to the final sweep recipient).
  3. ica.ts:652-746decodeUniversalRouterPlan complexity. ~95 lines / 6 mutable state slots / 5 command branches. Several prior bugbot threads landed exactly on this function's per-branch invariants. Extracting per-command handlers would make future Universal Router commands safer to add.

Minor:

  • tokenOut = 'native' (ica.ts:736) — magic string; named sentinel or undefined + tokenOutType branch would be cleaner.
  • Add a Commands.sol reference next to UNIVERSAL_ROUTER_COMMAND_TYPE_MASK = 0x3f (ica.ts:535) to head off the next reviewer asking why it diverges from upstream Uniswap (0x7f).
  • useStore is imported via both ../../store and ../../metadataStore across new files; pick one path.
  • TransactionRouteSummaryCard.tsx (~595 lines) bundles candidate selection, route synthesis, metadata resolution, receipt parsing, and presentation — non-blocking, but a future split-out into a useTransactionRoute hook would help.

All prior bugbot threads (V2 path reversal, command-mask, ?? vs ||, stale tokenOutType, withdrawal source mismatch) verified resolved. The acknowledged IcaCallDetails / NestedIcaCallDetails duplication was respected and not re-raised.
· branch feat/ica-decode-multicall-calls

Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

Review Summary

Nice polish on top of #259. The Universal Router plan walker is the most subtle bit and the test suite covers the path/version/sub-plan permutations well. The new Transaction Overview panel is a clean addition; tests cover the decoding pipeline, and the conservative single-Withdrawal-log gate for native outputs is the right call after the earlier topics[1] mix-up.

A handful of remaining concerns below — none of them blocking. Most are edge-case correctness or maintainability nits, all in the diff. Prior bugbot threads (V2 reversal, command-mask, ?? vs ||, stale tokenOutType, withdrawal source mismatch) all look resolved.

Main things I'd want a second look at:

  1. formatTokenAmount's 6-decimal fallback can misformat small 18-decimal amounts by 12 orders of magnitude (see ica.ts:526).
  2. ERC20 actual-output summation in fetchActualOutputAmount is not as conservative as the native path — when an intermediate swap recipient is the router itself it can double-count via router→user transfers (see TransactionRouteSummaryCard.tsx:407).
  3. decodeUniversalRouterPlan is long enough (~95 lines, 5 command branches + sub-plan recursion + state overwrite per command) that extracting per-command handlers would help future maintenance, especially as more Universal Router commands get added.

Minor:

  • tokenOut = 'native' (ica.ts:736) is a magic string that downstream code has to special-case alongside tokenOutType. A named sentinel or leaving tokenOut undefined + relying solely on tokenOutType would make the contract more explicit.
  • useStore is reached via both ../../store (re-export) and ../../metadataStore across the new files. Both resolve to the same store; pick one import path for consistency.

The acknowledged IcaCallDetails / NestedIcaCallDetails duplication is fine for this PR — agreed it's not worth the abstraction during final polish.

Comment thread src/features/messages/ica.ts Outdated
Comment thread src/features/transactions/TransactionRouteSummaryCard.tsx
Comment thread src/features/messages/ica.ts Outdated
Comment thread src/features/messages/ica.ts Outdated
Comment thread src/features/messages/ica.ts Outdated
Comment thread src/features/transactions/TransactionRouteSummaryCard.tsx Outdated
Comment thread src/features/messages/ica.ts Outdated
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 877e316. Configure here.

Comment thread src/features/messages/ica.ts Outdated
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.

2 participants