open source · MIT · technical validation

Debug
cross-L1 apps
on Avalanche ICM.

A source transaction succeeding doesn't mean the operation did. ICM Trace follows the messageID across chains and reconstructs the full execution trace — including the exact Solidity error when the destination contract reverts.

icm-trace · 0x9f2a…c31b
source    Game L1  tx 0xab12…ef45  
event     SendCrossChainMessage
          ──────────────────────────────
relay     ICM relayer · delivered
          ──────────────────────────────
dest      Rewards L1  tx 0xcd34…gh67  
event     MessageExecutionFailed
          ──────────────────────────────
          TeleporterMessenger
          └─ RewardController.processReward
             └─ PlayerRegistry.getPlayer
                └─ REVERT
          ──────────────────────────────
error     PlayerNotRegistered(address player)

A successful source transaction doesn't mean the operation succeeded.

The source tx confirms. The relayer delivers. But the destination contract reverts — and you're left manually correlating two chains, parsing raw call trees, and decoding revert bytes by hand.

Source L1SendCrossChainMessage
success
ICM / WarpReceiveCrossChainMessage
delivered
Destination L1MessageExecutionFailed
reverted

Three systems. No shared view. No automatic correlation.

One messageID. One trace.

Teleporter emits a deterministic messageID on the source chain that also appears in the destination execution event. ICM Trace uses it as the correlation key.

correlation key
// source
SendCrossChainMessage
  messageID: 0x9f2a…c31b

// destination
MessageExecutionFailed
  messageID: 0x9f2a…c31b
×Not a block explorerIt follows a message, not all chain data.
×Not an ICM relayerIt observes delivery, doesn't perform it.
×Not a CLI replacementIt complements Avalanche CLI and Teleporter.
01

Multi-chain event ingestion

Subscribes to Teleporter event logs on both source and destination L1s.

02

messageID correlation

Links SendCrossChainMessage on the source to MessageExecuted or MessageExecutionFailed on the destination using the shared messageID.

03

Lifecycle reconstruction

Assembles all events — Send, Receive, Execute/Fail, Receipt — into one ordered trace.

04

Destination trace analysis

On failure, calls debug_traceTransaction and reconstructs the internal EVM call tree.

05

Solidity error decoding

Extracts the revert bytes from the failing call and ABI-decodes them using the contract interface.

06

Retry history

Tracks retry attempts and links them under the same messageID.

From a vague failure to a precise error.

A game on Game L1 sends a reward message to Rewards L1. The destination contract reverts with a custom Solidity error.

icm-trace · 0x9f2a…c31b
messageID  0x9f2a…c31b
           ────────────────────────────────────────
source     Game L1  0xab12…ef45  success
event      SendCrossChainMessage
           ────────────────────────────────────────
relay      ICM relayer · delivered
           ────────────────────────────────────────
dest       Rewards L1  0xcd34…gh67  reverted
event      MessageExecutionFailed
           ────────────────────────────────────────
call tree
  TeleporterMessenger
  └─ RewardController.receiveTeleporterMessage
     └─ RewardController.processReward
        └─ PlayerRegistry.getPlayer(0xA82…)
           └─ REVERT
           ────────────────────────────────────────
error      PlayerNotRegistered(address 0xA82f…3c91)

Five Teleporter events. One trace.

ICM Trace tracks these events across both chains, correlated by messageID.

SendCrossChainMessageSource L1

Fired when an application sends a cross-chain message. Contains the messageID and encoded payload.

messageIDdestinationChainIDpayload
ReceiveCrossChainMessageDestination L1

Fired by the destination TeleporterMessenger when the relayer delivers the Warp message.

messageIDsourceChainID
MessageExecutedDestination L1

Fired when the destination contract handles the message successfully.

messageID
MessageExecutionFailedDestination L1

Fired when the destination contract reverts. Triggers EVM trace analysis in ICM Trace.

messageID
ReceiptReceivedSource L1

Delivery receipt sent back to the source chain. Closes the lifecycle loop.

messageIDdelivered

What the initial MVP includes.

EVM-based Avalanche L1s using Teleporter. No speculative items.

Multi-L1 event ingestion

Teleporter lifecycle tracking

messageID correlation

Lifecycle reconstruction

Execution failure detection

EVM call tree analysis

Solidity error decoding

Retry history

Developer trace interface


Validating the core technical assumption.

Can a complete cross-L1 execution trace be reconstructed using messageID as the correlation key? The PoC answers this with an intentionally broken destination contract and a custom Solidity error.

PoC steps

  1. 01Deploy two local Avalanche L1s
  2. 02Send an ICM message from the first L1
  3. 03Intentionally revert the destination contract with a custom Solidity error
  4. 04Capture the source SendCrossChainMessage event and extract the messageID
  5. 05Correlate the destination execution failure using the same messageID
  6. 06Trace the destination transaction and find the reverting call
  7. 07Decode the custom Solidity error
  8. 08Produce one structured cross-L1 execution trace

Built in public. MIT license.

Currently in technical validation — proving the core mechanism works before building the full tool. Honest work on a real problem.

View on GitHubTechnical proposal

TeleporterICM Trace observes Teleporter events. Does not replace it.
ICM relayerThe relayer delivers. ICM Trace traces. Independent.
Avalanche CLICLI manages infrastructure. ICM Trace handles application debugging.