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 codegenin 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
loaderfunction - A
handlerfunction
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.loaderfollows a naming convention for all events:<EventName>.loader. - Within the function that is being registered the user must define the criteria for loading the
greetingWithChangesentity 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
greetingWithChangesloads aGreetingentity 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
loadEntitiesfunction, they are then able to retrieve the loaded entity information via the labels defined in theconfig.yamlfile. - In the above example, if a
Greetingentity is found matching the load criteria in theloadEntitiesfunction, it will be available viagreetingWithChanges. - This is made available to the user through the handler context defined simply as
context. - This
contextis 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
Greetingentity in the database. - This is done via the
contextusing the update function (context.greeter.update(greetingObject)). - The user has access to a
greetingEntitytype 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