Checking what an ETH recipient sent next, within fixed bounds
An optional check looks for a recipient’s next native transfers and confirms them against receipts. It inspects one candidate block per check, with four checks and two hops at most.
You have a transfer of ETH from one address to another, and the obvious next question is what the recipient did afterwards. The lookup you already ran may not contain the answer, because it only captured a bounded slice of history.
Forensia has an optional follow-up for this. You pick a captured native transfer, press a button, and the workspace asks the network source a small, fixed set of questions about the recipient. If it finds later outgoing transfers of the native asset, it shows them only after their receipts confirm they succeeded.
This is a bounded check and it is important to say so early. Each check inspects one candidate block, not the recipient’s full history. You get four checks per open result and two hops beyond the starting transfer. It is a feature that is still being extended, and one successful live run does not establish that it works on every configured network or provider.
#Plain languageOne question to the ledger, not a full audit
Picture asking a bank clerk a narrow question: after this deposit arrived, what is the first day this account sent anything out, and what left on that day. The clerk answers for that one day. They do not read you the whole statement, and they do not claim the money that left is the same money that came in.
That is the shape of this check. Forensia finds the first later block in which the recipient’s account did something, looks at the positive native transfers the recipient sent in that block, and confirms each one against its receipt. A receipt is the network’s own record of whether a transaction succeeded or failed. Failed transactions are not shown as onward value.
The result is kept apart from your original lookup. It has its own capture time and its own source records, and the original result, its digest and its timestamp do not change.
#How it worksRunning a recipient check from the captured trail
- On Overview, open Follow captured transfers and choose a native transfer under Starting transfer.
- Below the trail, press Check recipient’s later transfers. The status line says it is checking the starting receipt, a bounded history window and matching outbound receipts, and that this may take up to 30 seconds.
- Read the result. It is dated as a separate check and either lists transfers from the recipient or says No qualifying transfer returned.
- To go further, press Check next recipient. The workspace shows which recipient is next before you commit.
- Open Recipients and stop reasons to see every recorded transfer and why each one was or was not followed.
- Open Check limits and captured sources for each RPC response, its host and its SHA-256 digest.
- Press Save EVM trace to keep completed checks in this browser, or Prepare trace backup and then Download trace JSON.
The counter reads as a number of 4 checks used across this open result, and failures count. A check is charged when it starts, so a cancelled or failed check still uses one. Cancelling stops the workspace from accepting a late answer. A request that already reached the server may still consume its upstream budget.
Save EVM trace is separate from Save result. After you save a trace, each later attempt is recorded before its request is sent and its result is saved automatically. If you reload mid-check, reopening it from Saved EVM traces shows One check needs review and blocks further requests until you decide. Mark check interrupted keeps the attempt counted and claims no result.
#Technical detailThe RPC sequence behind one check
The browser sends one POST to the existing investigation route with the mode evm-native-branch. The body must carry the exact starting transaction hash, the sender, the recipient, a positive raw amount, the block number and a later block boundary. No endpoint URL is accepted, and unknown fields are rejected. The route keeps its usual source-policy, verification, lease and concurrency gates.
The server first calls eth_chainId and requires it to equal the configured chain. Fallback providers may be tried for that first call only. The endpoint that answers is then pinned, and every later request goes to it. Archive answers from different providers are never blended.
eth_chainId pin one endpoint
eth_getTransactionByHash(start) must match hash, parties, value, block
eth_getTransactionReceipt(start) status must be 0x1
eth_getBlockByNumber(startBlock, false) hash and transactions[index] must match
eth_getBlockByNumber(upperBound, false) timestamp must be later than start
eth_getTransactionCount(recipient, startBlock)
eth_getTransactionCount(recipient, upperBound)
eth_getTransactionCount(recipient, middle) binary search, repeated
eth_getBlockByNumber(candidate, true) full transactions
eth_getTransactionReceipt(next) up to four
eth_getBlockByNumber(start / upper / candidate, false) recheckThe nonce is a locator, not evidence
The upper bound is the smaller of the original capture boundary and the starting block plus 15,000. It is always a numbered block, never the moving latest tag. The code reads the recipient’s transaction count at the starting block and at the upper bound. If the count did not increase, the status is no-nonce-increase and the check ends. If it decreased, the code refuses to interpret the history.
If it increased, a binary search over block heights finds the first block where the count is above its starting value. Any sample outside the range already observed is treated as a contradiction and the check fails. The count only tells Forensia where to look. It is never presented as a transfer.
What is accepted from the candidate block
The candidate block is fetched with full transaction objects and rejected if it holds more than 4,096 transactions. The code keeps transactions whose from field equals the recipient, verifies that each one’s transactionIndex equals its position in the array and that its block number and block hash match the block, and rejects duplicate hashes or positions.
From those it keeps transactions with a value above zero, a recipient that is not the zero address and not the sender, sorted by transaction index. The first four get a receipt check. A receipt is accepted only if its transactionHash, blockHash, blockNumber, transactionIndex, from and to all match the transaction and its status is 0x1 or 0x0. Only 0x1 is emitted as a transfer. Positive transactions beyond the four are reported as an omitted count.
Finally the starting block, the upper bound and the candidate block are read again. If any hash or timestamp changed during the run, nothing is accepted.
| Limit in EVM_NATIVE_BRANCH_LIMITS | Value |
|---|---|
| blocks after the start | 15,000 |
| upstream requests per check, including fallback attempts | 32 |
| candidate receipts checked | 4 |
| bytes per upstream response | 1,048,576 (1 MiB) |
| acquisition deadline | 22,000 ms |
The queue across checks
EVM_NATIVE_TRACE_LIMITS sets 4 checks and 2 hops. The block horizon is fixed once, from the root, for the whole sequence. Later hops cannot slide it forward. Order is breadth-first. Transfers returned by one check are queued in transaction-hash order, which is a deterministic tie-break for navigation and says nothing about execution order.
| Node status | Meaning |
|---|---|
| queued | Recorded, recipient not checked yet |
| checked | A check ran. It may have returned nothing |
| failed | The attempt failed or was cancelled, and was charged |
| cycle | The recipient already appeared on this path, so it is not followed again |
| boundary-limit | The transfer sits at the fixed block horizon |
| depth-limit | Two hops reached. The transfer is shown, its recipient is not checked |
| check-limit | Four checks used before this recipient was reached |
Each new page is revalidated on the client and compared with what earlier pages recorded: the anchor block hash and timestamp must equal the prior observation of that transaction, and the upper-bound block hash must equal the one from the first check. A contradiction rejects the continuation. The client reads at most 262,144 bytes of response. Saved traces allow five records, 10 MiB combined and 3 MiB per import, and the queue is always rebuilt from the ordered journal, never from flags in a file.
#LimitsWhat a returned transfer does and does not establish
- It establishes that the source reported a later successful native transfer sent by the recipient. It does not establish that the same funds moved, who benefits, who owns either address, or that anything illicit happened.
- One block is inspected per check. Later blocks in which the recipient was active are not covered, and neither is the remainder of the starting block.
- No nonce increase is not inactivity. An account can receive value, or have value moved by internal calls, without its count changing.
- A nonce can change through delegation, failed transactions or calls that carry no payment, so the located block may contain no eligible transfer.
- Inbound transfers, internal calls and tokens are outside this check.
- If a matching transaction in the candidate block is a contract creation or is malformed, the page abstains instead of inventing an address-to-address step.
- The search assumes the count only moves upward between samples. It rejects contradictions it sees, but cannot prove that for blocks it did not sample.
- Results are source-reported from one pinned RPC endpoint. This is not independent consensus validation, and it does not establish finality.
- Saved traces are unsigned, browser-only metadata without raw response bodies. Their digests show consistency, not authenticity.
The notes record a live run from the starting transaction 0x351035eb60de36d50a6d491308a03971a0b8d68975610177de908e4eb96b555f at block 25,994,464. The check located candidate block 25,994,727 and returned one receipt-confirmed transfer of 0.04934358043399044 ETH from the recipient, using 27 upstream requests. That is one later action by the recipient. It is not a statement about where the original ETH went.