feat: add ICA message decoding and visualization#259
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
eb7f097 to
c83c7ec
Compare
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughDebugger and UI were updated to treat ICA messages as structured entities: decoding ICA bodies, deriving ICA addresses from registry routers, extracting REVEAL/COMMITMENT details and per-call payloads, running inter-call gas/value checks, and surfacing structured debug results to an enhanced ICA details card with cross-chain lookups. ChangesICA Debugging Infrastructure
ICA Message Types and Utilities
ICA UI Components
Sequence Diagram(s)sequenceDiagram
participant App as Message Layer
participant Debugger as Debug Processor
participant ICA as ICA Utilities
participant Chain as Destination Chain
participant UI as IcaDetailsCard
App->>Debugger: Send message for debugging
Debugger->>ICA: decodeIcaBody(body)
ICA-->>Debugger: DecodedIcaMessage (CALLS/REVEAL/COMMITMENT)
Debugger->>ICA: computeIcaAddress(owner, ism, salt)
ICA->>Chain: Call router/contract to derive account
Chain-->>ICA: Derived ICA address
ICA-->>Debugger: Address result
Debugger->>Debugger: tryCheckIcaCall(each call with value)
Debugger-->>App: IcaDebugResult (or null) with icaDetails on failure
App->>UI: Render message + debugResult
UI->>ICA: useRelatedIcaMessage / useRevealCalls (if REVEAL)
ICA->>Chain: Fetch destination tx / router routes / ISM urls
Chain-->>ICA: Reveal calls, ISM urls, related message data
ICA-->>UI: Calls + gateway URLs
UI-->>App: Display enriched ICA details and failed-call highlight
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Fix all issues with AI agents
In `@src/features/debugger/debugMessage.ts`:
- Around line 418-426: The loop in debugMessage.ts calls tryCheckIcaCall using
recipient (the ICA router) which leads to misleading gas estimates; instead,
skip ICA call checks until the actual derived ICA address is available—update
the loop that iterates over calls to detect ICA-targeted calls (using recipient
and call.to context) and bypass calling tryCheckIcaCall for those, emitting a
clear debug/info message like "Skipping ICA call check until derived ICA address
is implemented" rather than performing estimateGas with the router address; keep
tryCheckIcaCall intact for future use once proper derivation is added.
In `@src/features/messages/cards/IcaDetailsCard.tsx`:
- Around line 612-613: Wrap the BigNumber conversion for call.value in defensive
handling: validate or try-catch around BigNumber.from(call.value) used to
compute hasValue and formattedValue, and fall back to safe defaults (hasValue =
false and formattedValue = '0') when parsing fails; update the logic in the
block that defines hasValue and formattedValue (referencing BigNumber.from,
call.value, hasValue, formattedValue, and fromWei) so malformed inputs don't
throw and the component can render safely.
In `@src/features/messages/ica.ts`:
- Around line 559-566: The current fallback in the message-matching logic
decodes reveal metadata from processCalls[0] and returns revealData.calls, which
can return data for the wrong message when multiple messages are batched; change
the fallback to return null instead of decoding/returning processCalls[0] so
callers receive a clear "unavailable" signal (update the code path that
references decodeRevealMetadata, processCalls, and revealData to return null
here and ensure callers handle a null result appropriately).
- Around line 136-138: The empty-body/malformed input check in decodeIcaBody is
unsafe because BigNumber.from(body) will throw on non-numeric or non-hex
strings; wrap the conversion in a safe validation or try/catch so malformed
input returns null instead of crashing. Specifically, in decodeIcaBody validate
that body is a non-empty numeric/hex string (or call ethers/utils.isHexString or
similar) before calling BigNumber.from(body), or catch errors from
BigNumber.from and return null; update the logic around BigNumber.from(body) to
perform this safe check so decodeIcaBody never throws on malformed body values.
In `@src/store.ts`:
- Around line 44-45: The store exposes icaRouterAddressMap and
setIcaRouterAddressMap but they are never populated or read; remove the unused
slice to avoid dead state. Delete the icaRouterAddressMap property and
setIcaRouterAddressMap setter from the store type and initialization (references
to icaRouterAddressMap and setIcaRouterAddressMap in store creation), and remove
any tests/consumers that reference them; alternatively, if you prefer
centralizing state, refactor callers that currently read the module-level
ICA_ROUTER_MAP (from buildIcaRouterAddressMap / ICA_ROUTER_MAP) to instead read
from and update the store via setIcaRouterAddressMap and
icaRouterAddressMap—pick one approach and apply consistently so only one source
of truth remains.
In `@src/types.ts`:
- Around line 75-91: Remove the unused IcaMessageDetails type declaration and
its export: delete the IcaMessageDetails interface (keeping IcaCall and
IcaRouterAddressMap intact), then search for any lingering imports/usages and
replace them with the actual DecodedIcaMessage type returned by
decodeIcaBody/parseIcaMessageDetails where appropriate; ensure no other modules
reference IcaMessageDetails and run the typecheck/build to confirm no remaining
references.
🧹 Nitpick comments (3)
src/features/messages/cards/IcaDetailsCard.tsx (2)
143-210: Async explorer URL fetching could be simplifiedThis callback recreates on every render when dependencies change, and the effect triggers the fetch. It's like walkin' through the swamp the long way. Consider using
useQueryfrom tanstack (already imported in ica.ts) for consistency with other data fetching in this PR, or at minimum add cleanup to prevent setting state on unmounted components.♻️ Consider adding cleanup for unmount safety
useEffect(() => { - getExplorerUrls().catch(() => setExplorerUrls({})); - }, [getExplorerUrls]); + let cancelled = false; + getExplorerUrls() + .then((urls) => { + if (!cancelled) setExplorerUrls(urls || {}); + }) + .catch(() => { + if (!cancelled) setExplorerUrls({}); + }); + return () => { + cancelled = true; + }; + }, [getExplorerUrls]);This would require modifying
getExplorerUrlsto return the urls object instead of setting state directly.
513-527: IIFE pattern works but extraction would be cleanerThis works fine, but usin' an IIFE inside JSX is a bit like buildin' a house in a swamp - technically possible but makes folks scratch their heads. Could extract to a tiny component or move the logic above the return.
src/features/messages/ica.ts (1)
494-499: Avoidanytype for multiProviderUsin'
anyhere is like leavin' the door to my swamp wide open - anything could wander in. TheMultiProtocolProvidertype is already imported in the store and used elsewhere.♻️ Proposed type fix
+import { MultiProtocolProvider } from '@hyperlane-xyz/sdk'; + export async function fetchRevealCalls( destinationChainName: string, processTxHash: string, messageId: string, - multiProvider: any, + multiProvider: MultiProtocolProvider, ): Promise<IcaCall[] | null> {
- Add /tx/[txHash] page showing all messages dispatched in a transaction - Add auto-redirect from search: single result → message page, tx hash match → tx page - Add 'View all messages in tx' link on message detail page when tx has multiple messages - Add SearchRedirecting state for smoother UX during redirects - Add useTransactionMessageCount hook for efficient message count queries - Make TransactionCard and KeyValueRow more responsive
- P1: Fix ICA decode crash for payloads >32 bytes by moving zero check inside try block and using safe regex instead of BigNumber.isZero() - P2: Prevent auto-redirect on homepage when latest messages has 1 result - P2: Gate tx page redirect on GraphQL results (not PI) since tx page only queries GraphQL - P3: Increase message count query limit from 10 to 1000 for accurate 'View all N messages' link - P3: Increase related ICA message lookup limit from 10 to 1000 to find related COMMITMENT/REVEAL in large fan-out transactions
b54ebb9 to
2d7b7b0
Compare
7aeba02 to
209e8a1
Compare
209e8a1 to
edd6476
Compare
Add support for decoding and displaying Interchain Account (ICA) messages: - Decode all 3 ICA message types: CALLS, COMMITMENT, REVEAL - Detect ICA messages by checking sender/recipient against known ICA routers - Compute derived ICA addresses using the SDK - Fetch CCIP Read ISM URLs for REVEAL messages - Link related COMMITMENT and REVEAL messages bidirectionally - Add IcaDetailsCard component with: - Status sections (delivered/pending) with commitment hash - Owner, Account, ISM, Salt, User fields - CCIP Read Gateway info for pending REVEAL messages - Call details with execution status - Update debugger to use new ICA decoding API
- Fix P1: Wrap BigNumber.from() in try/catch to prevent crashes on invalid data - Fix P2: Remove risky fallback to first process call, return null instead - Cleanup: Remove unused IcaMessageDetails type and icaRouterAddressMap store - UI: Fix link icon alignment in KeyValueRow - Add computeIcaAddress() to get real ICA address for accurate debugging - Include call.value in gas estimation for ICA calls - Add failed call indicator (red/amber) in IcaDetailsCard UI - Return structured IcaDebugResult with failedCallIndex from debugger
Why: useComputeIcaAddress, useRevealCalls, and useCcipReadIsmUrls were gated on `!== ProtocolType.Ethereum`, so ICA messages to Tron skipped address derivation, reveal-call fetching, and CCIP-Read ISM lookup even though Tron is EVM-compatible. Switched to `isEVMLike` to match the helper already used by warp-fee fetching. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Why: isAddressIcaRouter compared lowercased strings against the registry map, but Tron messages have their recipient decoded to base58 (T...) while registry entries are EVM-style 0x hex. The strings never matched, so isIcaMessage returned false and IcaDetailsCard never rendered for Arbitrum -> Tron messages. Canonicalize both sides to bytes32 hex, matching the warp-route Tron fix in #321. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ails Why: ICA messages need to show their decoded contents front and centre just like warp routes do. Removed the show/hide toggle (the card was just collapsed by default), aligned the header with the WarpRouteIsmDetailsCard / WarpRouteVisualizationCard pattern (no gray header bar, primary-800 title, no out-of-theme blue toggle link), and moved the card to render right after the timeline, ahead of message content / gas / ISM details. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Match the Message Details / Gas Details / Content Details visual treatment (gray header bar with purple dot + gray title) instead of the ad-hoc primary-800 heading. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- getFormattedCallValue now takes nativeDecimals and pulls them from the destination chain's nativeToken (falls back to 18). Hardcoded 18 was wrong for Tron native (6 decimals) and any other non-EVM destination ICA might support. - tryDecodeMulticall takes the mailbox address and skips inner calls whose target isn't the mailbox before parsing, so heterogeneous multicall payloads can't accidentally decode non-process calldata via selector collisions. - Replaced string-concat classNames in IcaCallDetails with clsx() to match the repo standard. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Drop rounded-md (3px) for default rounded (2px) on status/call panels - Replace vibrant bg-green-50 (#00C467) with muted bg-green-100/40 so the Done state matches the visual weight of the amber Pending state Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edd6476 to
5562fbc
Compare
Summary
Adds basic ICA message detection, decoding, visualization, and debugger support. This PR is stacked on #261 so ICA details are available both on message pages and inside expanded
/tx/[txHash]rows.Changes
InterchainAccountMessage.sol:CALLS: owner/ISM/salt + calls arrayCOMMITMENT: owner/ISM/salt + commitment hashREVEAL: ISM + commitment hashIcaDetailsCardabove message details for ICA messagesmailbox.process(metadata, message)tx metadata, including multicall process txsStack
feat/tx-page)Validation
pnpm run formatpnpm run typecheckpnpm run lintTest messages
0x36c5352103a884f6fce67c05e4811a37b3c6adc81745edbce8369aa56fb7d3a80x5ba4ee8907dc80572c8bfb782d918d0b82755463a361f2667f44a010ba85900b0xe89b32c5f63f0f62ffea080f3050d4a2acb9e5e39ac21b2ed3573a1c0c41ec1d