How to Index Data on the Fuel Network using Envio (SwayFarm example)

Data indexers are vital to the success of many blockchain applications, facilitating streamlined and timely access to on-chain data. In this step-by-step tutorial, we will create a data indexer for Sway Farm using Envio.

Sway Farm is an onchain farming game and for the sake of a real-world example, let’s create an indexer for a leaderboard of all farmers. :farmer:

HyperIndex by Envio is a feature-rich indexing solution that provides developers with a seamless and efficient way to index and aggregate real-time or historical blockchain data. The indexed data is easily accessible through custom GraphQL queries, giving developers the flexibility and power to retrieve specific information.

:warning: Before going through this tutorial, make sure you have the prerequisites installed.

Prerequisites

  1. Node.js (we recommend using something like fnm or nvm to install Node)
  2. pnpm
  3. Docker Desktop

Initialize the project

Now that you have installed the prerequisite packages let’s begin the practical steps of setting up the indexer.

Open your terminal in an empty directory and initialize a new indexer by running the command:

npx envio@1.2 init

In the following prompt, let’s name our indexer sway-farm-indexer:

? Name your indexer: sway-farm-indexer

Then, choose the directory where you want to set up your project. The default is the current directory, but in the tutorial, we’ll use the indexer name:

? Specify a folder name (ENTER to skip): sway-farm-indexer

Next, choose a language of your choice for the event handlers. TypeScript is the most popular one, so we’ll stick with it:

? Which language would you like to use?  
  JavaScript
> TypeScript  
  ReScript
[↑↓ to move, enter to select, type to filter]

Next, we have a new prompt to select the blockchain ecosystem.

? Choose blockchain ecosystem  
  Evm
> Fuel
[↑↓ to move, enter to select, type to filter]

The contract import feature has not yet been released for the Fuel network, so let’s choose Template, and then select Greeter.

After the project is finished initializing, you should see the following line in your terminal:

Please run `cd sway-farm-indexer` to run the rest of the envio commands

We are already halfway through! :raised_hands:

Let’s open the indexer in an IDE (e.g. VS Code) and start adjusting it for our farm. :tomato:

Adjusting the Indexer for Sway Farm

Currently, the Greeter template is the fastest way to create project scaffolding for a Fuel indexer. Still, we must admit that the Greeter indexer is not quite what we want. So, let’s start by adjusting its parts to make it work for Sway Farm.

It’s done by modifying the 3 files below:

(* depending on the language chosen for the indexer)

Updating config.yaml

In the file, we need to change a few configurations:

  • Rename indexer to Sway Farm Indexer.
  • Change the contract name to SwayFarm.
  • Set an address for the deployed contract.
  • Update ABI and the path to the location. You can get ABI by building the contract using forc build. For this use case, the latest version of the ABI can be found in the sway-farm GitHub repo.
  • Lastly, we need to list the events we want to index. For the purpose of this tutorial, we are creating a player leaderboard. Therefore, we are only interested in the events which update player information, i.e. NewPlayer, LevelUp, and SellItem. To see the list of logged events you can view the contract file.

After these changes, your config.yaml file should like this:

- name: Fuel Greeter Indexer
+ name: Sway Farm Indexer
networks:
  - id: 0
    start_block: 0
    contracts:
-     - name: Greeter
-       address: 0xb9bc445e5696c966dcf7e5d1237bd03c04e3ba6929bdaedfeebc7aae784c3a0b
-       abi_file_path: abis/greeter-abi.json
+     - name: SwayFarm
+       address: 0xf5b08689ada97df7fd2fbd67bee7dea6d219f117c1dc9345245da16fe4e99111
+       abi_file_path: abis/sway-farm-abi.json
        handler: ./src/EventHandlers.ts
        events:
-         - name: NewGreeting
-         - name: ClearGreeting
+         - name: NewPlayer
+         - name: SellItem
+         - name: LevelUp

You can notice that we use Sway struct names for the events configuration. Envio will automatically find LogData receipts containing data of the desired struct type. In case you log non-struct data, you can set the log id from ABI explicitly:

- name: MyEvent  logId: "1515152261580153489"

The current version supports indexing only LogData and Log receipts. Join our Discord channel to make sure you catch all new releases. We have Transfer, TransferOut, Mint, Burn, and Call receipts support on our roadmap.

Updating schema.graphql

The schema.graphql file serves as a representation of your application’s data model. It defines entity types that directly correspond to database tables, and the event handlers you create are responsible for creating and updating records within those tables. Additionally, the GraphQL API is automatically generated based on the entity types specified in the schema.graphql file, to allow access to the indexed data.

:brain: A separate Guide page provides more details about the schema.graphql file.

For the leaderboard, we need only one entity representing the player. Let’s create it:

type Player {
  id: ID!
  farmingSkill: BigInt!
  totalValueSold: BigInt!
}

We will use the user address as an ID. The fields farmingSkill and totalValueSold are u64 in Sway, so to safely map them to JavaScript value, we’ll use BigInt.

Updating EventHandlers.ts

Before we start writing our first event handlers, let’s run a codegen script. It’ll use config.yaml and schema.graphql to generate code for the indexer and types we will use in the event handler.

pnpm codegen

Now, if you open EventHandlers.ts, you should see some TypeScript errors. That’s fine, let’s delete all the Greeter indexer code and write our first Sway Farm event handler.

import { SwayFarmContract } from "generated";

/**
Registers a handler that processes NewPlayer event
on the SwayFarm contract and stores the players in the DB
*/
SwayFarmContract.NewPlayer.handlerAsync(async ({ event, context }) => {
  // Set the Player entity in the DB with the intial values
  context.Player.set({
    // The address in Sway is a union type of user Address and ContractID. Envio supports most of the Sway types, and the address value was decoded as a discriminated union 100% typesafe
    id: event.data.address.payload.bits,
    // Initial values taken from the contract logic
    farmingSkill: 1n,
    totalValueSold: 0n,
  });
});

Actually, this is already enough to start the indexer and get the list of all players, but let’s spend a few more seconds and add the rest of the event handlers, so we have synced farmingSkill and totalValueSold data in our DB.

// Code from above ...

SwayFarmContract.LevelUp.handlerAsync(async ({ event, context }) => {
  const playerInfo = event.data.player_info;
  context.Player.set({
    id: event.data.address.payload.bits,
    farmingSkill: playerInfo.farming_skill,
    totalValueSold: playerInfo.total_value_sold,
  });
});

SwayFarmContract.SellItem.handlerAsync(async ({ event, context }) => {
  const playerInfo = event.data.player_info;
  context.Player.set({
    id: event.data.address.payload.bits,
    farmingSkill: playerInfo.farming_skill,
    totalValueSold: playerInfo.total_value_sold,
  });
});

Without overengineering, simply set the player data into the database. What’s nice is that whenever your ABI or entities in graphql.schema change, Envio regenerates types and shows the compilation error.

Starting the Indexer

:loudspeaker: Make sure you have docker open
The following commands will start the docker and create databases for indexed data. Make sure to re-run pnpm dev if you’ve made some changes.

pnpm dev

Nice, we indexed 1,721,352 blocks containing 58,784 events in 10 seconds, and they continue coming in.

View the indexed results

Let’s check indexed players on the local Hasura server.

open http://localhost:8080

The Hasura admin-secret / password is testing, and the tables can be viewed in the data tab or queried from the playground.

Now, we can easily get the top 5 players, the number of inactive and active players, and the average sold value. What’s left is a nice UI for the Sway Farm leaderboard, but that’s not the tutorial’s topic.

:brain: A separate Guide page provides more details about navigating Hasura.

Deploy the indexer onto the hosted service

Once you have verified that the indexer is working for your contracts, then you are ready to deploy the indexer onto the hosted service.

Deploying an indexer onto the hosted service allows you to extract information via graphQL queries into your front-end or some back-end application.

Navigate to the hosted service to start deploying your indexer and refer to this documentation for more information on deploying your indexer.

:loudspeaker: Self-hosting your indexer is also an option.

What’s next?

Once you have successfully finished the tutorial, you are ready to become a blockchain indexing wizard!

Join the Envio Discord channel to make sure you catch all new releases and for any support-related queries.

Or gain inspiration from already running indexers built by other developers on Fuel:

7 Likes

This is excellent! Thanks @Svennooo

3 Likes