> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sqd.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Traces

> Retrieve EVM internal call traces with addTrace() — track calls, creates, suicides and rewards.

<Tip>
  Traces are [available](/en/data/evm) from [SQD Network](/en/network) Portals on the same basis as all other data served there: for free, including real-time blocks. There are no surcharges for traces or state diffs.
</Tip>

<h4 id="add-trace">
  `addTrace(options)`
</h4>

Subscribe to [execution traces](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-debug#debugtraceblockbyhash). This allows for tracking internal calls. The `options` object has the following structure:

```typescript theme={"system"}
{
  // item filters
  where?: {
    type?: string[]
    callTo?: string[]
    callFrom?: string[]
    callSighash?: string[]
    createFrom?: string[]
    suicideRefundAddress?: string[]
    rewardAuthor?: string[]
  }

  // related data retrieval
  include?: {
    transaction?: boolean
    transactionLogs?: boolean
    subtraces?: boolean
    parents?: boolean
  }

  // block range override
  range?: {from: number, to?: number}
}
```

Item filters (`where`):

* `type`: get traces of types from this set. Allowed types are `'create' | 'call' | 'suicide' | 'reward'`.
* `callTo`: get `call` traces *to* the addresses in this set.
* `callFrom`: get `call` traces *from* the addresses in this set.
* `callSighash`: get `call` traces with signature hashes in this set.
* `createFrom`: get `create` traces *from* the addresses in this set.
* `suicideRefundAddress`: get `suicide` traces where refund addresses are in this set.
* `rewardAuthor`: get `reward` traces where block authors are in this set.

<Warning>
  Filter values are matched as exact strings by the Portal — always pass addresses and sighashes as lowercase hex strings. `@subsquid/evm-stream` does not normalize the case for you.
</Warning>

Related data retrieval (`include`):

* `transaction = true`: retrieve the transactions that the matching traces belong to.
* `transactionLogs = true`: retrieve all logs emitted by transactions that the matching traces belong to.
* `subtraces = true`: retrieve downstream traces in addition to those that matched the filters.
* `parents = true`: retrieve upstream traces in addition to those that matched the filters.

These extra data items are added to the appropriate flat iterables within the [block data](./context-interfaces). Call `augmentBlock()` from `@subsquid/evm-objects` to navigate between the related items conveniently (e.g. `trace.transaction`, `trace.parent`, `trace.children`).

`range` overrides the global [`setBlockRange()`](../evm-stream) for this particular request.

Note that traces can also be requested by the [`addTransaction()`](./transactions) and [`addLog()`](./logs) methods as related data.

Selection of the exact fields to be retrieved for each trace item is done with the `setFields()` method documented on the [Field selection](./field-selection) page. Be aware that field selectors for traces do not share their names with the fields of trace data items, unlike field selectors for other data item types: the `action` and `result` subfields are requested with prefixed selectors such as `callTo`, `callSighash` or `createResultAddress`. This is due to traces varying their structure depending on the value of the `type` field — see the [traces section of Field selection](./field-selection#traces).

## Examples

### Exploring internal calls of a given transaction

For a [`mint` call to Uniswap V3 Positions NFT](https://etherscan.io/tx/0xf178718219151463aa773deaf7d9367b8408e35a624550af975e089ca6e015ca). Since the block range is bounded from above, `run()` terminates the process with exit code 0 once the range is exhausted.

```ts theme={"system"}
import {run} from '@subsquid/batch-processor'
import {DataSourceBuilder} from '@subsquid/evm-stream'
import {augmentBlock} from '@subsquid/evm-objects'
import {TypeormDatabase} from '@subsquid/typeorm-store'

const TARGET_TRANSACTION = '0xf178718219151463aa773deaf7d9367b8408e35a624550af975e089ca6e015ca'
const TO_CONTRACT = '0xc36442b4a4522e871399cd717abdd847ab11fe88' // Uniswap v3 Positions NFT
const METHOD_SIGHASH = '0x88316456' // mint

const dataSource = new DataSourceBuilder()
  .setPortal('https://portal.sqd.dev/datasets/ethereum-mainnet')
  .setBlockRange({from: 16962349, to: 16962349})
  .addTransaction({
    where: {
      to: [TO_CONTRACT],
      sighash: [METHOD_SIGHASH]
    },
    include: {
      traces: true
    }
  })
  .setFields({
    transaction: {hash: true},
    trace: {callTo: true}
  })
  .build()

run(dataSource, new TypeormDatabase({supportHotBlocks: true}), async ctx => {
  let involvedContracts = new Set<string>()
  let traceCount = 0

  for (let block of ctx.blocks.map(augmentBlock)) {
    for (let trc of block.traces) {
      if (trc.type === 'call' && trc.transaction?.hash === TARGET_TRANSACTION) {
        involvedContracts.add(trc.action.to)
        traceCount += 1
      }
    }
  }

  console.log(`txn ${TARGET_TRANSACTION} had ${traceCount - 1} internal transactions`)
  console.log(`${involvedContracts.size} contracts were involved in txn ${TARGET_TRANSACTION}:`)
  involvedContracts.forEach(c => { console.log(c) })
})
```

### Grabbing addresses of all contracts ever created on Ethereum

Requesting the `error` field lets us skip the traces of `create` operations that failed. Note that a successful `create` trace can still be discarded if an upstream call reverts, so a small share of the collected addresses may not correspond to live contracts.

```ts theme={"system"}
import {run} from '@subsquid/batch-processor'
import {DataSourceBuilder} from '@subsquid/evm-stream'
import {TypeormDatabase} from '@subsquid/typeorm-store'
import {CreatedContract} from './model'

const dataSource = new DataSourceBuilder()
  .setPortal('https://portal.sqd.dev/datasets/ethereum-mainnet')
  .addTrace({
    where: {type: ['create']}
  })
  .setFields({
    trace: {
      createResultAddress: true,
      error: true
    }
  })
  .build()

run(dataSource, new TypeormDatabase({supportHotBlocks: true}), async (ctx) => {
  const contracts: Map<string, CreatedContract> = new Map()
  for (let block of ctx.blocks) {
    for (let trc of block.traces) {
      if (trc.type === 'create' &&
          trc.error === null &&
          trc.result?.address != null) {
        contracts.set(trc.result.address, new CreatedContract({id: trc.result.address}))
      }
    }
  }
  await ctx.store.upsert([...contracts.values()])
})
```
