How activity is collected
Where the rows in the Activity view come from, and why they are a sample.
#Plain languageIn plain terms
The Activity view lists what an address did: payments, token movements, contract calls. Blockchains do not offer a simple "give me everything for this address" request. That list has to be assembled from several narrower questions.
Forensia asks those questions inside its budget, merges the answers, and shows a balanced sample of the newest records. It tells you how much ground each question covered.
#How it worksHow it works
- Read the newest full blocks and pick out transactions the address sent or received.
- Ask for token transfer events that name the address as sender or recipient, across a window of recent blocks.
- Ask for approval events the address granted.
- If the provider has a transfer index, ask it for the newest and oldest transfers too.
- Merge everything, remove duplicates, and keep a balanced sample.
- For the newest few transactions, fetch the receipt to confirm they succeeded.
#Technical detailThe exact rules
Recent blocks
Each of the newest blocks is fetched in full with eth_getBlockByNumber. A transaction is kept when its sender or recipient is the address. It is labelled a contract call when it carries call data, otherwise a native transfer. Transfers made inside another contract's execution are not visible on this path. This scan does not run on the public deployment.
Token events
Token movements are found with eth_getLogs, filtered by the standard transfer event and by the address in the sender or recipient position. Approvals use the same request with the approval event. Events are de-duplicated by transaction hash and log index.
Indexed transfers
Where the provider offers a transfer index, four queries run: newest outgoing, newest incoming, earliest funding, and earliest outgoing. The earliest funding query asks for a single native transfer; the other three return up to 20 rows each. The index is asked to leave out zero-value transfers. One further page is fetched for newest outgoing and for newest incoming, and only when at least 16 requests remain in the budget.
Deployments other than the public one can also be configured with a separate address-history index that the operator is authorised to use. It is asked for one page, from which at most two candidate blocks are taken. Those are hints only: each block is fetched from the network's own source, and only transactions in it that match the address become rows.
Finding an older transaction without an index
For a wallet with no index available and a sequence counter above zero, the lookup can locate one earlier transaction by that counter. This does not run on the public deployment. It reads the counter at older and older blocks, at distances of 64, 4,096 and 262,144 blocks and finally at the first block, until it sees a lower value. It then halves the gap repeatedly until it lands on the block where the counter changed, and reads that block. This is limited to one transaction, 30 requests and 15 seconds.
The sample
All rows are sorted newest first. The view takes the first 12 native or call rows, the first 12 token rows and the first 8 contract-event rows, then fills any remaining space up to 32.
Token names
For the first 4 token contracts seen, the lookup calls name() and symbol(), and decimals() where the contract was seen emitting ERC-20-shaped transfers. A contract seen only through ERC-1155 events is not asked. The answers are whatever the contract returns. Names are capped at 80 characters.
#LimitsWhat it does not tell you
- A gap between the newest and the oldest indexed rows is unread history, not inactivity.
- A token's name and symbol come from the token itself and can be anything.
- A change in the sequence counter can come from a delegation, not only from a payment.
- Incoming ERC-1155 transfers are not queried directly.
- Rows from an index are marked unknown for execution status until a receipt confirms them.