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

# Stablecoin transfers

> Stream USDC, USDT, and other stablecoin transfers into your own database in real time

Goldsky's [ERC-20 transfers datasets](/turbo-pipelines/guides/token-transfers/ERC-20-transfers) are the starting point for stablecoin-specific streaming pipelines, for both app and analytics use cases.

In this guide, we'll walk through several examples of how to build these pipelines.

## What you'll need

1. A mapping of the stablecoin contract addresses on the chains that you are interested in. We include popular stablecoins on major chains [on a dedicated page](/turbo-pipelines/guides/token-transfers/stablecoin-addresses).
2. A basic understanding of SQL (optional but helpful); see the [Turbo SQL reference](/turbo-pipelines/transforms/sql).
3. A destination sink to write your data to.

## Examples

### One stablecoin on one chain

The ERC-20 transfers datasets do a lot of the heavy lifting for us, indexing all token transfers for a given chain. Building stablecoin-specific streams is therefore a matter of filtering the data to only include transfers for the stablecoin contracts of interest, using a source-level `filter`.

```yaml Example pipeline for USDC transfers on Ethereum expandable theme={"dark"}
name: usdc-transfers
resource_size: s

sources:
  usdc_transfers:
    type: dataset
    dataset_name: ethereum.erc20_transfers
    version: 1.2.0
    start_at: latest
    filter: address = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'

sinks:
  postgres_sink:
    type: postgres
    from: usdc_transfers
    table: usdc_transfers
    schema: public
    secret_name: <YOUR_SECRET>
    primary_key: id
```

This outputs a stream of all transfers for the stablecoin contract in the filter. Because the underlying stream has all addresses, the output schema includes an `address` column, which may not be needed given there's only one address in the filter. To remove it, add a transform that projects the columns you want:

```yaml Example pipeline for USDC transfers on Ethereum, with transform to remove address expandable theme={"dark"}
name: usdc-transfers
resource_size: s

sources:
  usdc_transfers:
    type: dataset
    dataset_name: ethereum.erc20_transfers
    version: 1.2.0
    start_at: latest
    filter: address = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'

transforms:
  usdc_transfers_without_address:
    type: sql
    primary_key: id
    sql: |
      SELECT id, sender, recipient, amount, transaction_hash,
        block_hash, block_number, block_timestamp,
        transaction_index, log_index
      FROM usdc_transfers

sinks:
  postgres_sink:
    type: postgres
    from: usdc_transfers_without_address
    table: usdc_transfers
    schema: public
    secret_name: <YOUR_SECRET>
    primary_key: id
```

### Many stablecoins on one chain

This is similar to the example above, just using an `in ()` filter to include multiple stablecoin contracts rather than only one.

```yaml Example pipeline for USDC, USDT, and DAI transfers on Ethereum expandable theme={"dark"}
name: stablecoin-transfers
resource_size: s

sources:
  stablecoin_transfers:
    type: dataset
    dataset_name: ethereum.erc20_transfers
    version: 1.2.0
    start_at: latest
    filter: >-
      address in
      ('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
      '0xdac17f958d2ee523a2206206994597c13d831ec7',
      '0x6b175474e89094c44da98b954eedeac495271d0f')

sinks:
  postgres_sink:
    type: postgres
    from: stablecoin_transfers
    table: stablecoin_transfers
    schema: public
    secret_name: <YOUR_SECRET>
    primary_key: id
```

The output includes an `address` column that can be used downstream to filter or aggregate on a specific stablecoin, though for ease of use you might prefer a transform that adds the stablecoin symbol as a column:

```yaml Example pipeline for USDC, USDT, and DAI transfers on Ethereum, adding symbols expandable theme={"dark"}
name: stablecoin-transfers
resource_size: s

sources:
  stablecoin_transfers:
    type: dataset
    dataset_name: ethereum.erc20_transfers
    version: 1.2.0
    start_at: latest
    filter: >-
      address in
      ('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
      '0xdac17f958d2ee523a2206206994597c13d831ec7',
      '0x6b175474e89094c44da98b954eedeac495271d0f')

transforms:
  stablecoin_transfers_with_symbol:
    type: sql
    primary_key: id
    sql: |
      SELECT id, sender, recipient, amount, transaction_hash,
        block_hash, block_number, block_timestamp,
        transaction_index, log_index, address,
        CASE
          WHEN address = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' THEN 'USDC'
          WHEN address = '0xdac17f958d2ee523a2206206994597c13d831ec7' THEN 'USDT'
          WHEN address = '0x6b175474e89094c44da98b954eedeac495271d0f' THEN 'DAI'
        END AS symbol
      FROM stablecoin_transfers

sinks:
  postgres_sink:
    type: postgres
    from: stablecoin_transfers_with_symbol
    table: stablecoin_transfers
    schema: public
    secret_name: <YOUR_SECRET>
    primary_key: id
```

### One stablecoin on many chains

Streaming the same stablecoin on multiple chains uses multiple sources, one for each chain. Use a transform per chain to tag rows with a chain identifier, and write both to the same table:

```yaml Example pipeline for USDC transfers on Ethereum and Base expandable theme={"dark"}
name: usdc-transfers
resource_size: s

sources:
  usdc_transfers_ethereum:
    type: dataset
    dataset_name: ethereum.erc20_transfers
    version: 1.2.0
    start_at: latest
    filter: address = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
  usdc_transfers_base:
    type: dataset
    dataset_name: base.erc20_transfers
    version: 1.2.0
    start_at: latest
    filter: address = '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'

transforms:
  ethereum_with_chain:
    type: sql
    primary_key: id
    sql: |
      SELECT id, sender, recipient, amount, transaction_hash,
        block_hash, block_number, block_timestamp,
        transaction_index, log_index,
        'ethereum' AS chain_name
      FROM usdc_transfers_ethereum
  base_with_chain:
    type: sql
    primary_key: id
    sql: |
      SELECT id, sender, recipient, amount, transaction_hash,
        block_hash, block_number, block_timestamp,
        transaction_index, log_index,
        'base' AS chain_name
      FROM usdc_transfers_base

sinks:
  postgres_sink_ethereum:
    type: postgres
    from: ethereum_with_chain
    table: usdc_transfers
    schema: public
    secret_name: <YOUR_SECRET>
    primary_key: id
  postgres_sink_base:
    type: postgres
    from: base_with_chain
    table: usdc_transfers
    schema: public
    secret_name: <YOUR_SECRET>
    primary_key: id
```

<Note>
  The contract address for the same stablecoin usually differs between networks (as USDC does above); check the [stablecoin addresses page](/turbo-pipelines/guides/token-transfers/stablecoin-addresses). You may want to retain the `address` column in the sink for better inspection.
</Note>

### Many stablecoins on many chains

The most complex case combines all of the above in a single pipeline: an `in ()` filter per source and `CASE WHEN` logic per transform to add both `chain_name` and `symbol` columns.

```yaml Example pipeline for USDC and USDT transfers on Ethereum and Base expandable theme={"dark"}
name: stablecoin-transfers
resource_size: s

sources:
  stablecoin_transfers_ethereum:
    type: dataset
    dataset_name: ethereum.erc20_transfers
    version: 1.2.0
    start_at: latest
    filter: >-
      address in
      ('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
      '0xdac17f958d2ee523a2206206994597c13d831ec7')
  stablecoin_transfers_base:
    type: dataset
    dataset_name: base.erc20_transfers
    version: 1.2.0
    start_at: latest
    filter: >-
      address in
      ('0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
      '0xfde4c96c8593536e31f229ea8f37b2ada2699bb2')

transforms:
  ethereum_with_symbol:
    type: sql
    primary_key: id
    sql: |
      SELECT id, sender, recipient, amount, transaction_hash,
        block_hash, block_number, block_timestamp,
        transaction_index, log_index, address,
        'ethereum' AS chain_name,
        CASE
          WHEN address = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' THEN 'USDC'
          WHEN address = '0xdac17f958d2ee523a2206206994597c13d831ec7' THEN 'USDT'
        END AS symbol
      FROM stablecoin_transfers_ethereum
  base_with_symbol:
    type: sql
    primary_key: id
    sql: |
      SELECT id, sender, recipient, amount, transaction_hash,
        block_hash, block_number, block_timestamp,
        transaction_index, log_index, address,
        'base' AS chain_name,
        CASE
          WHEN address = '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913' THEN 'USDC'
          WHEN address = '0xfde4c96c8593536e31f229ea8f37b2ada2699bb2' THEN 'USDT'
        END AS symbol
      FROM stablecoin_transfers_base

sinks:
  postgres_sink_ethereum:
    type: postgres
    from: ethereum_with_symbol
    table: stablecoin_transfers
    schema: public
    secret_name: <YOUR_SECRET>
    primary_key: id
  postgres_sink_base:
    type: postgres
    from: base_with_symbol
    table: stablecoin_transfers
    schema: public
    secret_name: <YOUR_SECRET>
    primary_key: id
```

***

Can't find what you're looking for? Reach out to us at [support@goldsky.com](mailto:support@goldsky.com) for help.


## Related topics

- [Solana Stablecoin Transfers](/turbo-pipelines/sources/solana-stablecoin-transfers.md)
- [Stablecoin compliance & AML monitoring](/solutions/compliance-monitoring.md)
- [Solana sources for Turbo pipelines](/turbo-pipelines/sources/solana.md)
- [Real-time payment reconciliation](/solutions/real-time-reconciliation.md)
- [Stablecoin contract addresses](/turbo-pipelines/guides/token-transfers/stablecoin-addresses.md)
