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.
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.
Before going through this tutorial, make sure you have the prerequisites installed.
Prerequisites
- Node.js (we recommend using something like fnm or nvm to install Node)
- pnpm
- 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!
Let’s open the indexer in an IDE (e.g. VS Code) and start adjusting it for our farm.
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 thesway-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
, andSellItem
. 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
andLog
receipts. Join our Discord channel to make sure you catch all new releases. We haveTransfer
,TransferOut
,Mint
,Burn
, andCall
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.
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
Make sure you have docker open
The following commands will start the docker and create databases for indexed data. Make sure to re-runpnpm 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.
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.
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:
- Spark Orderbook Indexer
github
- Thunder NFT Marketplace Indexer
github