Cover photo

Quickest Tutorial of The Graph Indexing Protocol

As promised, I am writing a condensed tutorial for da devs about making a subgraph.

If you’re not sure what this is all about, please read my previous post on why this is so important.

Ok, now we got that sorted out, here’s the tech we’ll use for the tutorial. If you don’t know some of these, that’s okay because I don’t either. The code is pretty easy to read and as long as you can figure what’s going on, then hop in coz dis is gonna be fun:

  1. Graph CLI

  2. AssemblyScript (a variant of Typescript)

  3. GraphQL

Step 1. Install Graph CLI

Before we do this, you would need to connect your wallet to the Subgraph Studio so you can interface with your subgraphs.

Once done, let’s install the Graph CLI by running the following command:

npm install -g @graphprotocol/graph-cli

Step 2. Add a Subgraph

Go to your Subgraph Studio and click ‘Create Subgraph’.

Fill in the details for your subgraph. Once it’s created you will be given a slug and a deploy key for your undeployed subgraph. It will look like dis:

post image

These info will be used to initiate and deploy the subgraph later.

Step 3. Initialize the Subgraph

The Gravity contract that we’re using in this tutorial is already deployed in the Ethereum mainnet. You can see the contract source code, ABI, and address here.

We can now initialize its subgraph through the following command:

graph init --studio gravity

The Graph CLI will then ask you for some inputs. In this case, our contract is deployed in Ethereum Mainnet with its address at 0x2E645469f354BB4F5c8a05B3b30A929361cf77eC

So our prompt should look like this now:

✔ Protocol · ethereum
✔ Subgraph slug · gravity
✔ Directory to create the subgraph in · gravity
✔ Ethereum network · mainnet
✔ Contract address · 0x2E645469f354BB4F5c8a05B3b30A929361cf77eC
✔ Fetching ABI from Etherscan
✔ Contract Name · Gravity

Sometimes your ABI will not readily be available on Etherscan. If that happens, you need to provide the file path to the ABI of your contract.

Oh, and additional tip:

If you also want to index the events emitted through your contract, add in the --index-events flag in your init prompt.

Step 4. Configure the Subgraph

Once your subgraph is initialized, your directory will now have a bunch of auto-generated files. Here are the ones we’ll edit:

  1. subgraph.yaml : This is where we make our source configurations. In this example, we’ll configure the subgraph to use our deployed Gravity.sol contract as our data source.

    So it should look like this:

    specVersion: 0.0.4
    description: Gravatar for Ethereum
    repository: https://github.com/graphprotocol/example-subgraph
    schema:
      file: ./schema.graphql
    dataSources:
      - kind: ethereum/contract
        name: Gravity
        network: mainnet
        source:
          address: '0x2E645469f354BB4F5c8a05B3b30A929361cf77eC'
          abi: Gravity
          startBlock: 6175244
        mapping:
          kind: ethereum/events
          apiVersion: 0.0.6
          language: wasm/assemblyscript
          entities:
            - Gravatar
          abis:
            - name: Gravity
              file: ./abis/Gravity.json
          eventHandlers:
            - event: NewGravatar(uint256,address,string,string)
              handler: handleNewGravatar
            - event: UpdatedGravatar(uint256,address,string,string)
              handler: handleUpdatedGravatar
          file: ./src/mapping.ts
    
  2. schema.graphql : Is used to define your entities. If you want a detailed explanation on this, check out GraphQL’s crash course here. But basically, entities are ‘objects’ you can query. They are the heart of your subgraph.

    This file is where we’ll model these entities and their properties that we want to be available for querying. In the subgraph.yaml, we configured our eventHandlers to handle when a new gravatar is created (event: NewGravatar) and when an exisiting gravatar is updated (event: UpdatedGravatar). These event data should go and make changes to an entity somewhere. So how do we configure these entities?

    type Gravatar @entity {
      id: ID!
      owner: Bytes
      displayName: String
      imageUrl: String
    }
    

    And frens, dats how simple we design our schema. Because I want to be able to query information about the name, image, and owner of a Gravatar, we'll create a Gravatar entity that has all these properties.

    Another tip: You can also define relationships between entities just like in database tables. Check this out.

Step 5. Generate Mappings

Now run the following command:

This updates our mappings.ts file to generate some types that correspond to our recently added entities. It also updates the mappings that correspond to our edited subgraph.yaml.

The mappings.ts file is written in AssemblyScript and is used to convert blockchain data into an entity or a property of an entity.

Now we have to edit it to add the event handlers so that the events in the blockchain can also affect the Gravatar:

// Import event classes
import {
  NewGravatar,
  UpdatedGravatar
} from "../generated/Gravity/Gravity";

// Import entity class
import { Gravatar } from "../generated/schema";

export function handleNewGravatar(event: NewGravatar): void {
  // Use id field from emitted event as unique id for the entity
  const id = event.params.id.toHex();

  // Create a new Gravatar Entity with unique id
  const gravatar = new Gravatar(id);

  // Set Gravatar Entity fields
  gravatar.owner = event.params.owner;
  gravatar.displayName = event.params.displayName;
  gravatar.imageUrl = event.params.imageUrl;

  // Save entity to store
  gravatar.save();
}

export function handleUpdatedGravatar(event: UpdatedGravatar): void {
  // Use proper id to load an entity from store
  const id = event.params.id.toHex();

  // Load the entity to be updated
  let gravatar = Gravatar.load(id);

  // Create the entity if it doesn't already exist
  if (!gravatar) {
    gravatar = new Gravatar(id);
  }

  // Set updated fields to entity
  gravatar.owner = event.params.owner;
  gravatar.displayName = event.params.displayName;
  gravatar.imageUrl = event.params.imageUrl;

  // Save updated entity to store
  gravatar.save();
}

Finally, check if the code is working by running the command:

This compiles the subgraph into WebAssembly. If the build is successful, then congrats fren! Your subgraph is now ready to deploy 😀

Step 6. Deploy the Subgraph

Finally, we can deploy the subgraph in two simple commands:

Authenticate the deployer

graph auth --studio <DEPLOY KEY>

And deploooy!

graph deploy --studio gravity

Wait, but this is not in production yet…

Once the subgraph is deployed, you can now play with it in the Subgraph Studio. Go write some queries in the Graph dashboard and if all is well, you can now hit ‘Publish’ to bring it to production.

When you publish, you’ll get an API endpoint which you can at last connect to your dApp so that your users can query it.

And… that’s all folks. Hope this technology makes better UX for dApps in the coming years. And if you’re actively deving in the space, all danki asks of you is to share this indexing magic to other devs too. This way we’ll all have better querying functionalities in web3.

So long, and thanks for all the fish 🐎✨


Anyway I’m giving out a free-to-mint nft for my first few subscribers. Catch it while u can mah frens:

https://opensea.io/assets/ethereum/0x7674b264817b17BBCf6D983ee39391D4C851ED62/0