This guide explains how to decode traces on-the-fly using Mirror Decoding Functions within transforms in Mirror pipelines.

What you’ll need

  1. A Goldky account and the CLI installed
  1. A basic understanding of the Mirror product
  2. A destination sink to write your data to. In this example, we will use PostgresSQL Sink

Preface

In this guide we are going to show how to decode traces of a contract with Goldsky Mirror. We will use as example the Friendtech contract deployed in Base but the same logic applies to any other contract and chain for which there’s an availabe Raw Traces Direct Indexing dataset as per this list.

Pipeline definition

traces-decoding-pipeline.yaml
name: decoding-traces
apiVersion: 3
sources:
  my_base_raw_traces:
    type: dataset
    dataset_name: base.raw_traces
    version: 1.0.0
transforms:
  friendtech_decoded:
    primary_key: id
    # Fetch the ABI from basescan, then use it to decode from the friendtech address.
    sql: >
      SELECT 
        `id`,
        _gs_tx_decode(
            _gs_fetch_abi('https://api.basescan.org/api?module=contract&action=getabi&address=0xcf205808ed36593aa40a44f10c7f7c2f67d4a4d4', 'etherscan'), 
            `input`, 
            `output`
        ) AS `decoded`, 
        block_number, 
        transaction_hash 
      FROM my_base_raw_traces
      WHERE address='0xcf205808ed36593aa40a44f10c7f7c2f67d4a4d4'
  friendtech_clean:
    primary_key: id
    # Clean up the previous transform, unnest the values from the `decoded` object.
    sql: >
      SELECT 
        `id`, 
        decoded.function AS `function_name`,
        decoded.decoded_inputs AS `decoded_inputs`,
        decoded.decoded_outputs AS `decoded_outputs`,
        block_number,
        transaction_hash
        FROM friendtech_decoded 
        WHERE decoded IS NOT NULL
sinks:
  friendtech_logs:
    secret_name: EXAMPLE_SECRET
    type: postgres
    from: friendtech_clean
    schema: decoded_logs
    table: friendtech

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 (v2: secretName). 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_logs.friendtech.

Decoding transforms

Let’s start analyzing the first transform:

Transform: friendtech_decoded
SELECT 
    `id`,
    _gs_tx_decode(
        _gs_fetch_abi('https://api.basescan.org/api?module=contract&action=getabi&address=0xcf205808ed36593aa40a44f10c7f7c2f67d4a4d4', 'etherscan'), 
        `input`, 
        `output`
    ) AS `decoded`, 
    block_number, 
    transaction_hash 
    FROM base.raw_traces
    WHERE address='0xcf205808ed36593aa40a44f10c7f7c2f67d4a4d4'

Looking at the Raw Traces schema we see there are standard traces columns such as id, block_number and transaction_hash. Since the columns input and output are encoded we need to make use of the _gs_tx_decode to decode the data. This function takes the following parameters:

  1. The contract ABI: rather than specifying ABI directly into the SQL query, which would made the code considerably less legible, we have decided to make use of the _gs_fetch_abi function to fetch the ABI from the BaseScan API but you could also fetch it from an external public repository like Github Gist if you preferred.
  2. input: as a second argument which refer to the data sent along with the message call.
  3. output: as a third argument which refer to the data returned by the message call.
    Some columns are surrounded by backticks, this is because they are reserved words in Flink SQL. Common columns that need backticks are: data, output, value, and a full list can be found here.

We are storing the decoding result in a new column called decoded which is a nested ROW with the properties event_param::TEXT[] and event_signature::TEXT. We create a second transform that reads from the resulting dataset of this first SELECT query to access the decoded data:

Transform: friendtech_clean
SELECT 
    `id`, 
    decoded.function AS `function_name`,
    decoded.decoded_inputs AS `decoded_inputs`,
    decoded.decoded_outputs AS `decoded_outputs`,
    block_number,
    transaction_hash
    FROM friendtech_decoded 
    WHERE decoded IS NOT NULL

Notice how we add a filter for decoded IS NOT NULL as a safety measure to discard processing potential issues in the decoding phase.

Deploying the pipeline

As a last step, to deploy this pipeline and start sinking decoded data into your database simply execute:

goldsky pipeline create <pipeline_name> --definition-path <yaml_file>

Conclusion

In this guide we have explored an example implementation of how we can use Mirror Decoding Functions to decode raw logs and stream them into our PostgreSQL database. This same methodology can be applied to any contract of interest for any chain with raw_log and raw_traces Direct Indexing datasets available (see list).

Goldsky also provides alternative decoding methods:

Decoding contracts on the flight is a very powerful way of understanding onchain data and making it usable for your users.

Can't find what you're looking for? Reach out to us at support@goldsky.com for help.