> ## 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.

# EVM Portal stream

> Use @subsquid/evm-stream with Portal and the unified batch processor to index EVM blocks, transactions, logs, traces, and state diffs.

`@subsquid/evm-stream` is the Portal-native EVM data source for Squid SDK. It replaces the gateway and RPC ingestion layer of `EvmBatchProcessor` with a `DataSourceBuilder`. Pass the built source to [`run()` or `Processor`](/en/sdk/squid-sdk/reference/processors/batch-processor), or consume its stream directly.

<Info>
  Portal is public and does not use the `SQD_API_KEY` required by v2 gateways. To migrate an existing `EvmBatchProcessor` project, follow [Migrate a squid to Portal](/en/sdk/migration/gateway-to-portal).
</Info>

## Install

```bash theme={"system"}
npm i @subsquid/evm-stream @subsquid/evm-objects @subsquid/batch-processor @subsquid/logger @subsquid/typeorm-store
```

## Complete example

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

const USDC = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
const TRANSFER = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

const fields = {
  block: {timestamp: true},
  log: {
    address: true,
    topics: true,
    data: true,
    transactionHash: true,
  },
} satisfies FieldSelection

const dataSource = new DataSourceBuilder()
  .setPortal('https://portal.sqd.dev/datasets/ethereum-mainnet')
  .setFields(fields)
  .setBlockRange({from: 18_000_000})
  .addLog({
    where: {address: [USDC], topic0: [TRANSFER]},
  })
  .build()

const log = createLogger('sqd:processor:mapping')
const db = new TypeormDatabase({supportHotBlocks: true})

run(dataSource, db, async (simpleCtx) => {
  const blocks = simpleCtx.blocks.map(augmentBlock)
  log.info({blocks: blocks.length}, 'received batch')
  // Decode and persist data here with simpleCtx.store.
})
```

`DataHandlerContext` from `@subsquid/batch-processor` contains `{store, blocks, isHead}`. It does not inject `ctx.log` or `ctx._chain`. Create a logger explicitly, as above, and add an RPC client only when your handler makes direct RPC calls.

## `DataSourceBuilder`

All builder methods return the same builder unless noted.

### `setPortal(portal)`

Required. Accepts a Portal URL, `PortalClientOptions`, or an existing `PortalClient`.

```ts theme={"system"}
.setPortal('https://portal.sqd.dev/datasets/ethereum-mainnet')
```

### `setBlockRange({from, to?})`

Applies a global range to all requests. EVM ranges use block heights.

### `setFields(fields)`

Selects fetched fields and narrows the inferred block type. There are no default optional fields. List every field the handler reads. Required identifiers such as `header.number`, `header.hash`, `transactionIndex`, `logIndex`, `traceAddress`, and state-diff `kind/address/key` remain available.

The selectors are `block`, `transaction`, `log`, `trace`, and `stateDiff`. Trace action and result fields use prefixes such as `callTo`, `callCallType`, `callResultOutput`, and `createResultAddress`.

### `addLog(options)`

```ts theme={"system"}
.addLog({
  range: {from: 18_000_000},
  where: {
    address: [USDC],
    topic0: [TRANSFER],
    topic1: [],
    topic2: [],
    topic3: [],
  },
  include: {
    transaction: true,
    transactionLogs: true,
    transactionTraces: true,
    transactionStateDiffs: true,
  },
})
```

### `addTransaction(options)`

Filters support `from`, `to`, `sighash`, and `type`. Relations support `logs`, `traces`, and `stateDiffs`.

```ts theme={"system"}
.addTransaction({
  where: {to: [USDC], type: [2, 4]},
  include: {logs: true},
})
```

### `addTrace(options)`

Filters support `type`, `createFrom`, `callTo`, `callFrom`, `callSighash`, `suicideRefundAddress`, and `rewardAuthor`. Relations support `transaction`, `transactionLogs`, `subtraces`, and `parents`.

### `addStateDiff(options)`

Filters support `address`, `key`, and `kind`. Set `include.transaction` to include parent transactions.

### `includeAllBlocks(range?)`

Includes blocks without matching items. Without it, Portal may omit empty blocks.

### `addQuery(query)`

Adds a `Query` or `QueryBuilder` when several filters should share one range:

```ts theme={"system"}
import {QueryBuilder} from '@subsquid/evm-stream'

source.addQuery(
  new QueryBuilder()
    .setRange({from: 18_000_000})
    .includeAllBlocks()
    .addLog({where: {address: [USDC]}})
    .addTransaction({where: {to: [USDC]}, include: {logs: true}})
)
```

`QueryBuilder` also has `addTrace()`, `addStateDiff()`, and `build()`.

### `build()`

Returns an `EVMDataSource`. It throws `Portal settings not set` if `setPortal()` was not called.

Pass the result to `run()` or `Processor` for restart-safe processing. You can also call `getHead()`, `getFinalizedHead()`, `getStream()`, `getFinalizedStream()`, and the optional `getBlocksCountInRange()` helper directly. See [Read a data source directly](/en/sdk/squid-sdk/reference/processors/batch-processor#read-a-data-source-directly).

## Raw and augmented block types

The data source returns raw blocks from `@subsquid/evm-stream`. `augmentBlock()` from `@subsquid/evm-objects` adds IDs and navigation helpers such as `log.getTransaction()`, `trace.getParent()`, and transaction `logs`, `traces`, and `stateDiffs` collections.

Use `header.number` for the block height. `header.height` remains available only as a deprecated alias.
