The following files are required to use the Indexer:
- Configuration (defaults to
config.yaml
) - GraphQL Schema (defaults to
schema.graphql
) - Event Handlers (defaults to
src/EventHandlers.js
)
These files are auto-generated according to the Greeter template by running envio init
command.
Example config file from Greeter scenario:
name: Greeter
version: 0.0.0
description: Greeter indexer
networks:
- id: 137 # Polygon
rpc_config:
url: https://polygon.llamarpc.com # We recommend you change this to a dedicated RPC provider
start_block: 45336336
contracts:
- name: Greeter
abi_file_path: abis/greeter-abi.json
address: "0x9D02A17dE4E68545d3a58D3a20BbBE0399E05c9c"
handler: ./src/EventHandlers.js
events:
- event: "NewGreeting"
requiredEntities:
- name: "Greeting"
labels:
- "greetingWithChanges"
- event: "ClearGreeting"
requiredEntities:
- name: "Greeting"
labels:
- "greetingWithChanges"
Field Descriptions
name
- NameOfTheIndexerversion
- Version of the config schema used by the indexerdescription
- Description of the projectnetworks
- Configuration of the blockchain networks that the project is deployed onid
- Chain identifier of the network
rpc_config
- RPC Config that will be used to subscribe to blockchain data on this networkurl
- URL of the RPC endpointstart_block
- Initial block from which the indexer will start listening for eventscontracts
- Configuration for each contract deployed on the networkname
- User-defined contract nameabi_file_path
- File location of the contract ABIaddress
- An array of addresses that the contract is deployed to on the networkhandler
- Location of the file that handles the events emitted by this contractevents
- Configuration for each event emitted by this contract that the indexer will listen forname
- Name of the event (must match the name in the ABI)required_entities
- An array of entities that need to loaded and made accessible within the handler function (an empty array indicates that no entities are required)name
- The name of the required entity (must match an entity defined inschema.graphql
)label
- A user defined label that corresponds to this entity load
The schema.graphql
file contains the definitions of all user-defined entities. These entity types are then created/modified within the handler files.
Example schema definition for Greeter scenario:
type Greeting @entity {
id: ID!
latestGreeting: String!
numberOfGreetings: Int!
}
Once the configuration and graphQL schema files are in place, run
envio codegen
in the project directory.
The entity and event types will then be available in the handler files.
A user can specify a specific handler file per contract that processes events emitted by that contract. Each event handler requires two functions to be registered in order to enable full functionality within the indexer.
- An
<event>LoadEntities
function - An
<event>Handler
function
Example of registering a loadEntities
function for the NewGreeting
event from the above example config:
let { GreeterContract } = require("../generated/src/Handlers.bs.js");
GreeterContract.registerNewGreetingLoadEntities((event, context) => {
context.greeting.greetingWithChangesLoad(event.params.user.toString());
});
Inspecting the config of the NewGreeting
event from the above example config indicates that there is a defined requiredEntities
field of the following:
events:
- name: "NewGreeting"
requiredEntities:
- name: "Greeting"
labels:
- "greetingWithChanges"
- The register function
registerNewGreetingLoadEntities
follows a naming convention for all events:register<EventName>LoadEntities
. - Within the function that is being registered the user must define the criteria for loading the
greetingWithChanges
entity which corresponds to the label defined in the config. - This is made available to the user through the load entity context defined as
contextUpdator
. - In the case of the above example the
greetingWithChanges
loads aGreeting
entity that corresponds to the id received from the event.
Example of registering a Handler
function for the NewGreeting
event and using the loaded entity greetingWithChanges
:
let { GreeterContract } = require("../generated/src/Handlers.bs.js");
GreeterContract.registerNewGreetingHandler((event, context) => {
let existingGreeter = context.greeting.greetingWithChangesLoad;
if (existingGreeter != undefined) {
context.greeting.update({
id: event.params.user.toString(),
latestGreeting: event.params.greeting,
numberOfGreetings: existingGreeter.numberOfGreetings + 1,
});
} else {
context.greeting.insert({
id: event.params.user.toString(),
latestGreeting: event.params.greeting,
numberOfGreetings: 1,
});
}
});
- The handler functions also follow a naming convention for all events in the form of:
register<EventName>Handler
. - Once the user has defined their
loadEntities
function, they are then able to retrieve the loaded entity information via the labels defined in theconfig.yaml
file. - In the above example, if a
Greeting
entity is found matching the load criteria in theloadEntities
function, it will be available viagreetingWithChanges
. - This is made available to the user through the handler context defined simply as
context
. - This
context
is the gateway by which the user can interact with the indexer and the underlying database. - The user can then modify this retrieved entity and subsequently update the
Greeting
entity in the database. - This is done via the
context
using the update function (context.greeter.update(greetingObject)
). - The user has access to a
greetingEntity
type that has all the fields defined in the schema.
This context also provides the following functions per entity that can be used to interact with that entity:
- insert
- update
- delete