Skip to main content
This guide explains how to decode raw contract events on-the-fly using the Turbo SQL decoding functions within SQL transforms in Turbo pipelines.

What you’ll need

  1. A Goldsky account and the CLI installed
  1. Install the Goldsky CLI: For macOS/Linux:
    For Windows:
    Windows users need to have Node.js and npm installed first. Download from nodejs.org if not already installed.
  2. Log into your Project by running:
    This opens your browser to sign in (Google, GitHub, SSO, or email). Once you authenticate, the CLI is logged in automatically — there’s no API key to copy or paste.
    On a headless or remote machine (or in CI), create an API key on your Project Settings page and pass it directly with goldsky login --token <API_KEY>. Use goldsky login --no-browser to print the login URL instead of opening a browser.
  3. Now that you are logged in, run goldsky to get started:
  1. A basic understanding of Turbo pipelines
  2. A destination sink to write your data to. In this example, we will use the PostgreSQL sink

Preface

To get decoded contract data on EVM chains in a Turbo pipeline, you use the raw_logs dataset and decode inside a SQL transform. For common token events you can skip decoding entirely and use the curated erc20_transfers, erc721_transfers, and erc1155_transfers datasets; see EVM sources. In this guide we will use as example the Friendtech contract deployed on Base, but the same logic applies to any other contract and chain for which a raw logs dataset is available (see supported chains).

Pipeline definition

In the _gs_fetch_abi function call below, we pull from a gist. You can also pull from Basescan directly with an API key:

_gs_fetch_abi('<basescan-link>', 'etherscan')
event-decoding-pipeline.yaml
There are two important transforms in this pipeline definition which are responsible for decoding the contract; we’ll explain how they work in detail. If you copy and use this configuration file, make sure to update:
  1. Your secret_name. If you already created a secret, you can find it via the CLI command goldsky secret list.
  2. The schema and table you want the data written to. By default it writes to decoded_events.friendtech.
This pipeline starts at the chain tip (start_at: latest). If you want to decode the contract’s full history, use start_at: earliest and add a source-level filter on the contract address so fast scan can skip irrelevant blocks during the backfill.

Decoding transforms

Let’s start analyzing the first transform:
Transform: friendtech_decoded
Looking at the raw logs schema (EVM schemas) we see there are standard log columns such as id, block_number and transaction_hash. Since the columns topics and data are encoded, we need to make use of _gs_log_decode to decode the data. This function takes the following parameters:
  1. The contract ABI: rather than pasting the ABI directly into the SQL query, which would make the code considerably less legible, we use the _gs_fetch_abi function to fetch the ABI. You can fetch it from the Basescan API ('etherscan' type) or from an external public location like a GitHub gist ('raw' type).
  2. topics: as a second argument we pass the name of the column in our dataset that contains the topics as a comma-separated string.
  3. data: as a third argument we pass the name of the column in our dataset that contains the encoded event payload.
We store the decoding result in a new column called decoded, which is a struct with two fields:
  • event_signature (string): the event name, for example Trade
  • event_params (array of strings): the decoded parameter values in positional order
We create a second transform that reads from the result of this first SELECT query to access the decoded data:
Transform: friendtech_clean
Notice how we add a filter for decoded IS NOT NULL as a safety measure to discard potential issues in the decoding phase.
Decoded parameters are returned by position, not by name. To access the third parameter of an event, use decoded.event_params[3]; the array is 1-indexed.

Decode once, filter per event

The ABI we fetch contains every event the contract emits, so friendtech_decoded decodes all of them in a single pass. A useful pattern is to keep that one decode transform and add a downstream transform per event type, each filtering on decoded.event_signature and extracting the parameters it cares about:
Each of these transforms can feed its own sink (or table), so one pipeline can fan a single decoded stream out into per-event tables. This is more efficient than running a separate decode for every event type.

Deploying the pipeline

As a last step, to deploy this pipeline and start sinking decoded data into your database simply execute:
You can watch decoded events flow through each transform in real time with live inspect:

Conclusion

In this guide we have explored an example implementation of how we can use the Turbo SQL decoding functions to decode raw contract events and stream them into a PostgreSQL database. This same methodology can be applied to any contract of interest on any chain with raw_logs and raw_traces datasets available (see supported chains). Can’t find what you’re looking for? Reach out to us at support@goldsky.com for help.