The complete guide to this tutorial can be found here
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:
version: 1.0.0
description: Greeter indexer
repository: https://github.com/PaulRBerg/hardhat-template
networks:
- id: 1337
rpc_url: http://localhost:8545
start_block: 0
contracts:
- name: Greeter
abi_file_path: abis/greeter-abi.json
address: ["0x2B502ab6F783c2Ae96A75dc68cf82a77ce2637c2"]
handler: src/EventHandlers.js
events:
- name: "NewGreeting"
requiredEntities:
- name: "Greeting"
labels:
- "greetingWithChanges"
- name: "ClearGreeting"
requiredEntities:
- name: "Greeting"
labels:
- "greetingWithChanges"
Field Descriptions
version
- Version of the config schema used by the indexerdescription
- Description of the projectrepository
- Repository of the projectnetworks
- Configuration of the blockchain networks that the project is deployed onid
- Chain identifier of the networkrpc_url
- RPC URL that will be used to subscribe to blockchain data on this networkstart_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.
- A
loader
function - A
handler
function
GreeterContract.NewGreeting.loader((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
NewGreeting.loader
follows a naming convention for all events:<EventName>.loader
. - 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
:
GreeterContract.NewGreeting.handler((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:
<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