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

<AgentInstructions>

## Submitting Feedback

If you encounter incorrect, outdated, or confusing documentation on this page, submit feedback:

POST https://docs.sqd.dev/feedback

```json
{
  "path": "/en/sdk/pipes-sdk/evm/guides/basic-development/handling-events",
  "feedback": "Description of the issue"
}
```

Only submit feedback when you have something specific and actionable to report.

</AgentInstructions>

# Handling contract events

> Fetching and decoding EVM event logs with evmDecoder

`evmDecoder()` bundles an EVM log query with a decoding transform into a single reusable module. Pass the result as an output to `evmPortalStream`:

```ts theme={"system"}
import { commonAbis, evmDecoder, evmPortalStream } from '@subsquid/pipes/evm'

const stream = evmPortalStream({
  portal: 'https://portal.sqd.dev/datasets/ethereum-mainnet',
  outputs: {
    transfers: evmDecoder({
      range: { from: '0' },
      contracts: ['0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'],
      events: { transfer: commonAbis.erc20.events.Transfer },
    }),
  },
})
```

`evmDecoder()` can:

* Fetch from **specific contracts** — pass an array of addresses to `contracts`. Omit it entirely to receive matching events from every contract on-chain.
* Filter by **indexed parameters** — instead of a bare event, supply `{ event, params }` to select only logs where specific indexed arguments match.
* Dynamically discover contracts via **factories** — pass a `contractFactory()` to `contracts` instead of a static list. See the [Factory guide](../advanced-topics/factory-transformers).
* Handle decode errors with a custom **`onError` callback** instead of letting them propagate.

See the [evmDecoder() reference](../../reference/utility-components/evm-decoder) for all parameters.

## Specifying events

The `events` parameter maps output field names to event specifications. There are three ways to obtain an event specification.

### `commonAbis`

`commonAbis` is a built-in collection of ABI modules for common token standards. Currently it ships one module, `erc20`:

```ts theme={"system"}
import { commonAbis, evmDecoder } from '@subsquid/pipes/evm'

evmDecoder({
  range: { from: 'latest' },
  contracts: ['0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'],
  events: {
    transfers: commonAbis.erc20.events.Transfer,
    approvals: commonAbis.erc20.events.Approval,
  },
})
```

See the [`commonAbis` reference](../../reference/utility-components/evm-decoder#commonabis) for the full list of available events and functions.

### Typegen modules

`@subsquid/evm-typegen` generates TypeScript ABI modules from JSON ABIs. Each generated module exports typed `events` and `functions` objects, translating Solidity types to TypeScript — event argument types are statically known at compile time, so you get precise type checking and IDE autocompletion across the entire pipeline.

**Install the tool:**

```bash theme={"system"}
npm install -D @subsquid/evm-typegen
```

**Generate a module from a local JSON ABI file:**

```bash theme={"system"}
npx squid-evm-typegen src/abi your-contract.json
```

This creates `src/abi/your-contract.ts`. The tool also accepts a contract address (requires specifying `--chain-id`) or an arbitrary URL.

Use events from a generated module exactly as with `commonAbis`:

```ts theme={"system"}
import * as usdcAbi from './abi/usdc'

evmDecoder({
  range: { from: 'latest' },
  contracts: ['0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'],
  events: {
    transfers: usdcAbi.events.Transfer,
    approvals: usdcAbi.events.Approval,
  },
})
```

### Raw JSON via `defineAbi()`

`defineAbi()` converts a JSON ABI array to a subsquid ABI module at runtime, with no code generation step. This is the quickest route — useful for one-off scripts or prototypes — but it comes at a cost: when the ABI is loaded from an external JSON file, event argument fields are typed as `any`, since TypeScript cannot inspect the runtime JSON value at compile time.

```ts theme={"system"}
import { defineAbi, evmDecoder } from '@subsquid/pipes/evm'
import erc20Json from './erc20.json'

const erc20 = defineAbi(erc20Json) // event args are `any`

evmDecoder({
  range: { from: 'latest' },
  contracts: ['0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'],
  events: { transfers: erc20.events.Transfer },
})
```

`defineAbi()` also accepts Hardhat and Foundry artifact objects — it reads the `abi` field automatically:

```ts theme={"system"}
import artifact from './artifacts/MyContract.json'

const myContract = defineAbi(artifact) // reads artifact.abi
```

If you define the ABI inline with `as const`, TypeScript can infer the exact decoded types for scalar fields:

```ts theme={"system"}
const erc20 = defineAbi([
  {
    type: 'event',
    name: 'Transfer',
    inputs: [
      { indexed: true,  name: 'from',  type: 'address' },
      { indexed: true,  name: 'to',    type: 'address' },
      { indexed: false, name: 'value', type: 'uint256' },
    ],
  },
] as const)

// erc20.events.Transfer.decode() returns { from: string, to: string, value: bigint }
```

For projects where full type safety matters end-to-end, prefer the [typegen route](#typegen-modules) instead.
