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

# Decode contract events

> Sync contract events to a database with the contract ABI using Mirror.

This guide explains how to decode raw contract events on-the-fly using [Mirror Decoding Functions](/mirror/reference/mirror-functions/decoding-functions) within transforms in Mirror pipelines.

## What you'll need

1. A Goldky account and the CLI installed

<Accordion title="Install Goldsky's CLI and log in">
  1) Install the Goldsky CLI:

     **For macOS/Linux:**

     ```shell theme={null}
     curl https://goldsky.com | sh
     ```

     **For Windows:**

     ```shell theme={null}
     npm install -g @goldskycom/cli
     ```

     <Note>Windows users need to have Node.js and npm installed first. Download from [nodejs.org](https://nodejs.org) if not already installed.</Note>
  2) Go to your [Project Settings](https://app.goldsky.com/dashboard/settings) page and create an API key.
  3) Back in your Goldsky CLI, log into your Project by running the command `goldsky login` and paste your API key.
  4) Now that you are logged in, run `goldsky` to get started:
     ```shell theme={null}
     goldsky
     ```
</Accordion>

1. A basic understanding of the [Mirror product](/mirror)
2. A destination sink to write your data to. In this example, we will use [PostgresSQL Sink](/mirror/sinks/postgres)

## Preface

To get decoded contract data on EVM chains in a Mirror pipeline, there are two options:

1. Decode data with a subgraph, then use a [subgraph entity source](/mirror/sources/subgraphs).
2. Use the `raw_logs` dataset and decode inside a pipeline [transform](/reference/config-file/pipeline).

In this guide we are going to focus on the third method. We will use as example the [Friendtech contract](https://basescan.org/address/0xcf205808ed36593aa40a44f10c7f7c2f67d4a4d4) deployed in Base but the same logic applies to any other contract and chain for which there's an availabe Raw Log Direct Indexing dataset as per [this list](/mirror/sources/direct-indexing).

## Pipeline definition

<Tip>
  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'), `
</Tip>

```yaml event-decoding-pipeline.yaml expandable theme={null}
name: decoding-contract-events
apiVersion: 3
sources:
  my_base_raw_logs:
    type: dataset
    dataset_name: base.raw_logs
    version: 1.0.0
transforms:
  friendtech_decoded:
    primary_key: id
    # Fetch the ABI from a gist (raw)
    sql: >
      SELECT 
        `id`,
        _gs_log_decode(
         	_gs_fetch_abi('https://gist.githubusercontent.com/jeffling/0320808b7f3cc0e8d9cc6c3b113e8156/raw/99bde70acecd4dc339b5a81aae39954973f5d178/gistfile1.txt', 'raw'), 
            `topics`, 
            `data`
        ) AS `decoded`, 
        block_number, 
        transaction_hash 
      FROM my_base_raw_logs
      WHERE address='0xcf205808ed36593aa40a44f10c7f7c2f67d4a4d4'
  friendtech_clean:
    primary_key: id
    # Clean up the previous transform, unnest the values from the `decoded` object. 
    sql: >
      SELECT 
        `id`, 
        decoded.event_params AS `event_params`, 
        decoded.event_signature AS `event_signature`,
        block_number,
        transaction_hash
        FROM friendtech_decoded 
        WHERE decoded IS NOT NULL
sinks:
  friendtech_events:
    secret_name: EXAMPLE_SECRET
    type: postgres
    from: friendtech_clean
    schema: decoded_events
    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`. If you already [created a secret](/mirror/manage-secrets), you can find it via the [CLI command](/reference/cli#secret) `goldsky secret list`.
2. The schema and table you want the data written to, by default it writes to `decoded_events.friendtech`.

### Decoding transforms

Let's start analyzing the first transform:

```sql Transform: friendtech_decoded theme={null}
SELECT 
    `id`,
    _gs_log_decode(
        _gs_fetch_abi('https://api.basescan.org/api?module=contract&action=getabi&address=0xcf205808ed36593aa40a44f10c7f7c2f67d4a4d4&apikey=YOUR_KEY', 'etherscan'), 
        `topics`, 
        `data`
    ) AS `decoded`, 
    block_number, 
    transaction_hash 
    FROM base.raw_logs
    WHERE address='0xcf205808ed36593aa40a44f10c7f7c2f67d4a4d4'
```

Looking at the [Raw Logs schema](/reference/schema/EVM-schemas#raw-logs) we see there are standard log columns such as `id`, `block_number` and `transaction_hash`. Since its columns
`topics` and `data` are encoded we need to make use of the [\_gs\_log\_decode](/mirror/reference/mirror-functions/decoding-functions#gs-log-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](/mirror/reference/mirror-functions/decoding-functions#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. `topics`: as a second argument to the decode function we pass in the name of the column in our dataset that contains the topics as comma-separated string.
3. `data`: as a third argument to the decode function we pass in the name of the column in our dataset that contains the encoded data.

   <Note>
     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](https://nightlies.apache.org/flink/flink-docs-release-1.17/docs/dev/table/sql/overview/#reserved-keywords).
   </Note>

We are storing the decoding result in a new column called `decoded` which is a [nested ROW](https://nightlies.apache.org/flink/flink-docs-stable/docs/dev/table/types/#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:

```sql Transform: friendtech_clean theme={null}
SELECT 
    `id`, 
    decoded.event_params AS `event_params`, 
    decoded.event_signature AS `event_signature`,
    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 apply <yaml_file>`

## Conclusion

In this guide we have explored an example implementation of how we can use [Mirror Decoding Functions](/mirror/reference/mirror-functions/decoding-functions) to decode raw contract events 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](/mirror/sources/direct-indexing)).

Goldsky also provides alternative decoding methods:

* [Subgraphs entity sources](/mirror/sources/subgraphs) to your pipelines.

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](mailto:support@goldsky.com) for help.
