FORENSIAWeb3 forensicsOpen workspace

Matching an Across bridge transfer

How Forensia finds the other half of an Across deposit between Ethereum and Base, and how strict the match is.

4 min read · Tracing value

#Plain languageIn plain terms

For one bridge on one route, Forensia can look across the gap. Given a deposit into Across on Ethereum or Base, it searches the other network for the event that fills that deposit.

It does not match on "about the same amount, around the same time". All supported original relay-identity fields must match. Changed execution terms, such as an updated recipient or output amount, are shown separately; they must not be mistaken for the original deposit terms. Missing or conflicting correspondence stays unresolved.

#How it worksHow it works

  1. Read the deposit event from the transaction's receipt.
  2. Work out roughly which blocks on the other network correspond to that time.
  3. Search that window for fill events that name this deposit.
  4. Fetch each candidate's receipt and confirm the event is really in it.
  5. Compare the deposit and the fill field by field.

#Technical detailThe exact rules

NetworkSpokePool contract
Ethereum0x5c7bcd6e7de5423a257d81b442095a1a6ced35c5
Base0x09aea4b2242abc8bb4bb78d537a67a245a7bec64

The deposit event is FundsDeposited and the fill event is FilledRelay. Each is decoded strictly, then re-encoded and compared byte for byte with the original, which rejects any non-standard padding or trailing data.

Choosing where to search

Block numbers on two networks are unrelated, so the window is found by time. The lookup halves the destination chain's block range by timestamp, up to 16 times, until it is within 1,024 blocks of the deposit's time. The search then starts 128 blocks earlier, because a fill can be recorded slightly before its deposit, and covers at most 5,000 blocks.

LimitValue
Search window5,000 blocks
Fill events the source may return8
Receipts fetched4
Requests48
Total time25 seconds

The 48 requests and 25 seconds cover both networks together. If the source returns more than 8 fill events, or they sit in more than 4 transactions, the check stops at a limit. No partial list is used. On each network, every request after the first goes to the one endpoint that answered first.

What counts as a match

A fill matches a deposit only when all 13 of these are identical: origin network, destination network, deposit ID, depositor, recipient, exclusive relayer, input token, output token, input amount, output amount, fill deadline, exclusivity deadline, and message hash.

ResultMeaning
Matched eventsExactly one fill with an identical relay.
UnresolvedNo matching fill in the window searched.
AmbiguousMore than one fill, or a duplicate deposit.
Unsupported routeThe deposit targets a network other than Ethereum or Base.

A check can also end before any comparison: no supported deposit event in the transaction, a source that could not finish, a size, time or request limit, records that disagree about the network, transaction or block, or records that cannot be safely read. In each case no destination match is accepted.

When a match is found, the fill's execution terms are compared with the deposit's. If the recipient, message or output amount were updated before the fill, each change is shown side by side: what was requested, and what the destination reports. Amounts are compared as exact raw integers in the token's smallest unit, never as rounded decimals.

How the fill is described

Fill type in the eventWhat it means here
Fast fillA relayer filled the deposit. This says nothing about how long delivery took, and repayment of the relayer is not checked.
Fast fill replacing a slow-fill requestA relayer replaced a slow fill that had been requested. It is not a second delivery, and not evidence of a completed refund.
Slow fillThe protocol's slow-fill path. Its proof and settlement are not checked.

Checking the events against the calls

Where the operator has enabled call tracing for the source, the same check also asks the source for the transaction's call tree and lines the receipt's events up against it, in order. It is accepted only when every event in the receipt matches a call that did not fail, and the block is read again afterwards. That result is labelled as reported by the source, not as independently verified execution.

Call check resultMeaning
Matched to a provider-reported callEvery event in the receipt agrees with the source's call tree, in order.
Not enabledCall tracing is off for this source. No trace was requested.
Unavailable, limit, invalid or unsupportedNo call match was accepted. The event match above still stands on its own.
ConflictThe calls or the later block disagree with the receipt. Do not treat the event match as a verified path.

Some sources are used for analysis in the moment only. For those, the original response is not kept or exported: the record shows its fingerprint and says "raw response not included".

#LimitsWhat it does not tell you

  • No matching event in the window does not mean the bridge failed. The fill may be outside the 5,000 blocks.
  • Only Ethereum and Base, in either direction, are covered.
  • If a transaction contains several deposits, only one is checked, and the page says so.
  • Refunds are not checked. A fill type in the event is not proof that a refund or a relayer repayment happened.
  • Matching events is not a proof of finality or of the recipient's final balance.
  • The contract code behind the events at that time is not verified, and the transaction is not replayed. A call match is what the source reported, not an independent re-execution.
  • The check runs once per open result, with no retry. It is kept apart from the saved result and its report, and has its own "Save bridge check" button.