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

# Indexing USDT on Tron

> Tutorial: index TRC-20 USDT transfers on Tron.

<Warning>
  V2 gateway requests require an API key and the latest `@subsquid/tron-processor`. The linked example's `0.0.x` dependency cannot forward `SQD_API_KEY` to the v2 gateway.
</Warning>

In this tutorial we will look into a squid that indexes USDT transfers on the [Tron Network](https://tron.network).

Pre-requisites: Node.js v20 or newer, Git, Docker.

## Download the project

<Steps>
  <Step title="Clone the example and install the latest processor">
    ```bash theme={"system"}
    git clone https://github.com/subsquid-labs/tron-example
    cd tron-example
    npm install
    npm install @subsquid/tron-processor@latest
    ```
  </Step>

  <Step title="Configure the v2 API key">
    Add the key to the example's `.env` file. `dotenv/config` loads it when the processor starts.

    ```dotenv theme={"system"}
    SQD_API_KEY=<YOUR_SQD_NETWORK_API_KEY>
    ```
  </Step>
</Steps>

## TronBatchProcessor configuration

[Squid processor](../reference/tron-processor/general) is a term with two meanings:

1. The process responsible for retrieving and transforming the data.

2. The main object implementing that process.

On Tron, [`TronBatchProcessor`](../reference/tron-processor/general) is the class that should be used for processor objects. Our first step is to create the processor and configure it to fetch USDT transfers data:

```typescript title="src/main.ts" theme={"system"}
// Note that the address is in lowercase hex and has no leading `0x`.
// This is the format used throughout the SQD Tron stack.
const USDT_ADDRESS = 'a614f803b6fd780986a42c78ec9c7f77e6ded13c'
const TRANSFER_TOPIC = 'ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

const processor = new TronBatchProcessor()
  // The SQD Network gateway URL - this is where the bulk of data will
  // be coming from.
  .setGateway({
    url: 'https://v2.archive.subsquid.io/network/tron-mainnet',
    apiKey: process.env.SQD_API_KEY,
  })
  // SQD Network is always about N blocks behind the head.
  // We must use regular HTTP API endpoint to get through the last mile
  // and stay on top of the chain.
  // This is a limitation, and we promise to lift it in the future!
  .setHttpApi({
    // Public endpoints are rate-limited. Use a private endpoint in production.
    url: 'https://api.trongrid.io',
    strideConcurrency: 1,
    strideSize: 1,
  })
  // We request data items via `.addXxx()` methods.
  // Each `.addXxx()` method accepts item selection criteria
  // and also allows to request related items.
  .addLog({
    // select logs
    where: {
      address: [USDT_ADDRESS],
      topic0: [TRANSFER_TOPIC]
    },
    // for each log selected above load related transactions
    include: {
      transaction: true
    }
  })
  // For each data item we can specify a set of fields we want to fetch.
  // Accurate selection of only the required fields can have a notable
  // positive impact on performance when data is sourced from SQD Network.
  .setFields({
    block: {
      timestamp: true,
    },
    transaction: {
      hash: true
    },
    log: {
      address: true,
      data: true,
      topics: true
    }
  })
```

See also the [`TronBatchProcessor` reference](../reference/tron-processor/general).

The next step is to configure data decoding and transformation.

## Processing the data

The other part of the squid processor configuration is the callback function used to process batches of filtered data, the [batch handler](../reference/tron-processor/context-interfaces). It is typically defined within a `processor.run()` call, like this:

```typescript theme={"system"}
processor.run(database, async ctx => {
  ...
}
```

Here,

* `processor` is the object described in the previous section
* `database` is a [`Database` implementation](../reference/data-stores/store-interface) specific to the target data sink. We want to store the data in a PostgreSQL database and present with a GraphQL API, so we provide a [`TypeormDatabase`](../guides/writing-to-postgres) object here.
* `ctx` is the [batch context](../reference/tron-processor/context-interfaces) object that exposes a batch of data (at `ctx.blocks`) and any data persistence facilities derived from `db` (at `ctx.store`). See [Block data for Tron](../reference/tron-processor/context-interfaces) for details on how the data batches are presented.

Batch handler is where the raw on-chain data is decoded, transformed and persisted. Here is our definition:

```typescript title="src/main.ts" theme={"system"}
processor.run(new TypeormDatabase(), async ctx => {
  let transfers: Transfer[] = []

  for (let block of ctx.blocks) {
    for (let log of block.logs) {
      if (log.address == USDT_ADDRESS &&
          log.topics?.[0] === TRANSFER_TOPIC) {
        assert(log.data, 'USDT transfers always carry data')
        let tx = log.getTransaction()
        // `0x` prefixes make log data compatible with EVM codec
        let event = {
          topics: log.topics.map(t => '0x' + t),
          data: '0x' + log.data
        }
        let {from, to, value} = erc20.events.Transfer.decode(event)

        transfers.push(new Transfer({
          id: log.id,
          blockNumber: block.header.height,
          timestamp: new Date(block.header.timestamp),
          tx: tx.hash,
          from,
          to,
          amount: value
        }))
      }
    }
  }

  await ctx.store.insert(transfers)
})
```

This goes through all the logs in the block, verifies that they originate from `USDT_ADDRESS` and have a `TRANSFER_TOPIC` as the first topic, decodes the log and saves a `Transfer` record with the obtained data to the database. See [Prepare the store](../guides/make-an-indexer#store) for more details on how the database interface works.

<Info>
  Notice that we used the SQD EVM codec and [`squid-evm-typegen`](/en/sdk/squid-sdk/evm/reference/evm-typegen/generating-utility-modules)-generated module to decode events. Since Tron events are fully EVM-compatible, this is the recommended way.

  This tooling requires that the hex values are prefixed with `0x`, as shown above.
</Info>

At this point the squid is ready for its first test run. Add a temporary block range after `new TronBatchProcessor()` so that the test is reproducible and exits:

```typescript title="src/main.ts" theme={"system"}
.setBlockRange({from: 70_000_000, to: 70_000_010})
```

Then build the project, start PostgreSQL, apply the migration, and run the processor:

```bash theme={"system"}
npm run build
docker compose up -d
npx squid-typeorm-migration apply
node -r dotenv/config lib/main.js
```

The processor should exit after block `70,000,010`. Verify that decoded transfers were stored:

```bash theme={"system"}
docker compose exec db psql -U postgres -c "SELECT * FROM transfer LIMIT 100"
```

Remove `setBlockRange()` when you are ready to continue indexing toward the chain head.

Full code can be found [here](https://github.com/subsquid-labs/tron-example).
