Following a token onward
How Forensia finds later transfers of the same token by the same recipient, and why it refuses partial answers.
#Plain languageIn plain terms
Someone receives a token. What happened to it next? Tokens make this easier than ETH in one way: every token transfer leaves a public event that can be searched by sender.
Forensia takes one exact token transfer and searches a window of later blocks for transfers of the same token sent by that recipient. Each one it reports has been checked against its own receipt.
#How it worksHow it works
- Re-confirm the starting event sits in its receipt at the position claimed.
- Ask the source for later transfer events of the same token contract, sent by the recipient.
- For each event returned, fetch that transaction's receipt and confirm the event is really in it.
- Read each block involved and confirm the transaction is in it.
- Read all blocks used a second time to confirm nothing changed.
#Technical detailThe exact rules
| Limit | Value |
|---|---|
| Search window | 2,000 blocks after the starting event, and never past the latest block of the original lookup |
| Events the source may return | 64 |
| Receipts fetched | 4 |
| Events reported | 16 |
| Requests | 24 |
| Total time | 22 seconds |
| Checks per open result, failures included | 4 |
| Hops | 2 |
| Entries in one trace | 65 |
The search is one eth_getLogs request: the token contract's address, the standard transfer signature, and the recipient in the sender position. The starting event is identified by transaction hash and log position, never by token symbol.
As with ETH, each check first confirms the source's network ID with eth_chainId, then sends every later request to that same endpoint.
If the source returns more than 64 events the whole step is abandoned. A partial list would hide the fact that later events were cut, so no prefix is used.
A returned event is only a pointer. It enters the result when the receipt for its transaction contains an identical event at the same position and that receipt reports success. Events with a zero amount, a zero-address recipient, or a self-transfer are counted as excluded.
| A branch stops when | Recorded as |
|---|---|
| The recipient, or the address that was just checked, is a known shared service, such as an exchange router | service-boundary |
| The window's edge is reached | boundary-limit |
| Two hops have been followed | depth-limit |
| Four checks have been used | check-limit |
The result lists every recipient with a sentence giving its stop reason, under "Token recipients and stop reasons". Unlike the ETH check, an address that appeared earlier on the path does not stop a branch. A later event to it is a distinct event and is queued like any other.
The service boundary matters. Once tokens enter a shared contract they are pooled with everyone else's. Following "the next transfer out" from a router would connect unrelated people.
#LimitsWhat it does not tell you
- Activity in the starting event's own block, and beyond the 2,000-block window, is not checked.
- A token is identified by its contract and network. Symbol and decimal scale are not inferred.
- Fee-on-transfer and rebasing tokens change balances in ways events do not show.
- A filtered log query can be incomplete on some providers. Missing records are not inactivity.
- Mint, burn and self-transfer events cannot start a trace.