Who created a contract
How contract creation is read from a transaction, including contracts created by other contracts.
#Plain languageIn plain terms
Contracts do not appear from nowhere. Each one is created by a transaction. Sometimes a person's wallet creates it directly. Often another contract, called a factory, creates it as part of a larger transaction.
When you look up a transaction, Forensia lists every contract it created and which address created each one. The creating address is a fact on the chain. Who is behind that address is not.
#How it worksHow it works
- Fetch the transaction, its receipt and the block that contains it, and confirm all three agree.
- If the transaction has no recipient and the receipt reports a new contract address, the sender created that contract.
- Ask the node for a call trace, the step-by-step record of what ran inside the transaction.
- Walk the trace and list every successful creation step, with the contract that performed it.
#Technical detailThe exact rules
A top-level creation requires all of: the transaction's to is empty, the receipt carries a contractAddress, and the receipt status is success. The created address is taken from the receipt.
Internal creations come from debug_traceTransaction with the callTracer. A frame counts when its type is CREATE or CREATE2, it succeeded, and it has a destination address.
| Limit | Value |
|---|---|
| Trace depth read | 6 levels |
| Call frames kept | 64 |
| Frames inspected, including malformed ones that are skipped | 257 |
| Tracer timeout | 5 seconds at the node, 7 seconds at the client |
| Kind | Meaning |
|---|---|
top-level-create | The transaction itself created the contract. The creator is the sender. |
internal-create | A contract created it with the CREATE instruction. |
internal-create2 | A contract created it with CREATE2, which makes the address predictable in advance. |
Before any of this is reported, the transaction, receipt and block must agree. The receipt must name this transaction, the same sender and recipient, and the same block hash and number. The transaction and receipt must report the same index, and the block's transaction list must hold this hash at that index and nowhere else. The transaction type and chain id must fit the network. Every receipt log must belong to this transaction and block, in increasing log order. If any check fails the lookup stops with an inconsistency error.
A returned trace is read only when its root call matches the transaction's sender, recipient, input, value and receipt status. Otherwise it is treated as unavailable.
Results are the findings finding:deployment and finding:factory-deployments, both class observed.
#LimitsWhat it does not tell you
- This works on a transaction you look up. Looking up a contract address does not search for the transaction that created it.
- If the node does not offer tracing, internal creations cannot be listed and the page says the trace was unavailable.
- The immediate creator of a factory-made contract is the factory, not the person who called it.
- CREATE2 addresses are not recomputed from the salt and init code.
- Creations deeper than the trace limits are not shown. Nor are creations inside a branch the trace reader skipped as malformed.