fix(fx-tunnel-relayer): relay all MessageSent events in a transaction - #4963
fix(fx-tunnel-relayer): relay all MessageSent events in a transaction#4963droplet-rl wants to merge 1 commit into
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
A Polygon transaction bridging multiple price requests emits multiple MessageSent events, but the exit proof was always built for the first matching log (matic.js buildPayloadForExit defaults to index 0). Every event in such a transaction produced a proof for message #1; the first relay succeeded and the rest reverted with EXIT_ALREADY_PROCESSED, which was swallowed silently, so the remaining messages never reached the DVM. Compute each event's position among the MessageSent logs in its transaction receipt and prove exactly that log, and log skips caused by EXIT_ALREADY_PROCESSED at debug level instead of returning silently. Fixes #4962 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: droplet-rl <284132418+droplet-rl@users.noreply.github.com>
85cc3fe to
480f744
Compare
|
Noting for reviewers: the Codex automated review was skipped on this PR because the Codex account hit its usage limit — no review feedback was produced. No code changes needed in response. Once the quota resets, a re-review can be requested by commenting |
|
You have reached your Codex usage limits. You can see your limits in the Codex usage dashboard. |
|
Duplicate quota notification — my previous comment inadvertently re-triggered Codex by spelling out the re-review command, and it failed on the same usage limit. Nothing actionable here; ignore both bot messages. Once the Codex quota resets, a re-review can be requested with the usual mention command (not spelled out here to avoid re-triggering it). Human review of this PR can proceed in the meantime. |
Motivation
When a single Polygon transaction emits multiple
MessageSentevents from theOracleChildTunnel(e.g. two OO disputes bridged atomically in one transaction), the relayer only ever relays the first message. matic.jsbuildPayloadForExit(burnTxHash, logEventSig, isFast, index = 0)proves the index-th log matching the event signature within the transaction, and the relayer never passes an index — so every event in the same transaction produces an identical proof for message #1. The first submission succeeds and the rest revert withFxRootTunnel: EXIT_ALREADY_PROCESSED, which is swallowed silently. The unrelayed price requests never reach the DVM and the corresponding OO requests stay stuck inDisputedwith bonds locked.This happened in production on 2026-07-22/23: 0x0874d7b0… and 0xc6d74727… each bridged two disputes; in both cases the second dispute never reached the DVM. Both stuck messages have since been relayed manually with proofs built at
tokenIndex=1(0x37ba42b6…, 0xeaf7b45c…).Summary
MessageSentevent, compute its position among all logs matching theMessageSentsignature in its transaction receipt (fetched once per transaction) and pass that index tobuildPayloadForExit, so every message in a multi-message transaction is proven and relayed.EXIT_ALREADY_PROCESSED, so legitimate skips remain visible.Details
The index is computed against all logs in the receipt with the
MessageSenttopic (matching matic.jsgetAllLogIndicessemantics, which filters by topic only, not emitter) rather than just this contract's events, so the proof index stays correct even if another fx-tunnel contract emittedMessageSentin the same transaction.Testing
New test bundles two
requestPricecalls into one transaction viaMulticall3and asserts both messages are proven at indices 0 and 1 and both relays are submitted.yarn workspace @uma/fx-tunnel-relayer testpasses locally.Issue(s)
Fixes #4962
🤖 Generated with Claude Code