Using The Graph on REI Network

Checking Prerequisites

To use Graph on REI, you should run a local Graph Node against REI testnet and point your Subgraph to it. From the link below you can get information on how to run a nodeThe Bank Contract

pageRunning a Graph Node on REI Network

For this example, a simple Bank contract will be used. You can find the Solidity file in the

REIBank-subgraph repository

The contract contains a bank where users can deposit rei for themselves, or transfer their rei in bank to others. They can also withdraw their rei from bank.

The main functions of the contract are the following:

  • deposit() — function to send rei to the contract, then you can get your own proof of deposit in the bank

  • transfer(address to, uint256 amount) — transfer your rei in bank to others

  • whithdraw(unit256 amount) — redeem your money based on certificates of deposit

Events of the Bank Contract

The Graph uses the events emitted by the contract to index data. The bank contract emits three events:

  • Deposit(address indexed from, uint256 indexed amount) — in the deposit function. It provides information related to deposit entry, including account address and deposit rei amount

  • Transfer(address indexed from, address indexed to, uint256 indexed amount) — in the transfer function. It provides information on transaction between accounts in the bank, including accounts address and rei amount

  • Withdraw(address indexed from, uint256 indexed amount) — in the withdraw function. It provides information related to withdraw entry, including account address and withdraw rei amount

Creating a Subgraph

This section goes through the process of creating a Subgraph. For the Bank Subgraph, a GitHub repository was prepared with everything you need to help you get started. The repository also includes the Bank contract, as well as a Hardhat configuration file and deployment script. If you are not familiar with it, you can check our Hardhat integration guide to learn about the configuration file and how to deploy a contract using Hardhat.

To get started, first clone the repository and install the dependencies

git clone https://github.com/bijianing97/REIBank-subgraph && cd REIBank-subgraph
npm i

Now, you can create the TypeScript types for the Graph by running

npm run codegen

The types will in the src/types/

Creating the types requires you to have the ABI files specified in the subgraph.yaml file. This sample repository has the file already, but this is usually obtained after compiling the contract.

You also can use following command to specify the generated directory

npx graph codegen --output-dir xxxx

For this example, the contract was deployed to 0x1Ec9238A1c0adca222251e1f607a77237E8686a3. The README.md file in the project has the steps necessary to compile and deploy the contract if required.

Subgraphs Core Structure

In general terms, Subgraphs define the data that The Graph will index from the blockchain and the way it is stored. The subgraph definition consists of a few files:

  • subgraph.yaml — is a YAML file that contains the Subgraph's manifest

  • schema.graphql — a GraphQL schema that defines what data is stored for your subgraph, and how to query it via GraphQL

  • AssemblyScript mappingsAssemblyScript code that translates from the event data to the entities defined in your schema (e.g. bank.ts in this tutorial)

Schema.graphql

The schema for your subgraph is in the file schema.graphql. GraphQL schemas are defined using the GraphQL interface definition language. If you've never written a GraphQL schema, it is recommended that you check out this primer on the GraphQL type system. Reference documentation for GraphQL schemas can be found in the GraphQL API section.For this example, here one entry is defined for bank:

  • Account — Record the users in bank, about their account address and balance

So the schema.graphql should look like the following snippet:

type Account @entity {
  id: ID!
  balance: BigInt!
  operateTime: BigInt!
}

Subgraph Manifest

The subgraph manifest subgraph.yaml defines the smart contracts your subgraph indexes, which events from these contracts to pay attention to, and how to map event data to entities that Graph Node stores and allows to query. The full specification for subgraph manifests can be found here.

For the example subgraph, subgraph.yaml is:

Some of the most important parameters in the subgraph.yaml file are:

  • repository — Github repository of the subgraph

  • schema/file — location of the schema.graphql file

  • dataSources/name — the name of the Subgraph

  • network — refers to the network name. This value must be set to the local graph node name which you setted

  • dataSources/source/address — the address of the contract

  • dataSources/source/abi — refers to where the interface of the contract is stored inside the types folder created with the codegen command

  • dataSources/source/startBlock — refers to the start block from which the indexing will start

  • dataSources/mapping/file — refers to the location of the mapping file, eg bank.ts

  • dataSources/mapping/entities — definitions of the entities in the schema.graphql file

  • dataSources/abis/name — where the interface of the contract is stored inside the types/dataSources/name

  • dataSources/abis/file — refers to the location where the .json file with the contract's ABI is stored

  • dataSources/eventHandlers — no value needs to be defined here, but this section refers to all the events that The Graph will index

  • dataSources/eventHandlers/event — refers to the structure of an event to be tracked inside the contract. You need to provide the event name and its type of variables

  • dataSources/eventHandlers/handler — refers to the name of the function inside the mapping.ts file which handles the event data

In short, the subgraph.yaml should look like the following snippet:

specVersion: 0.0.2
schema:
  file: ./schema.graphql
dataSources:
  - kind: ethereum
    name: Bank
    network: reidev
    source:
      address: "0x1Ec9238A1c0adca222251e1f607a77237E8686a3"
      abi: Bank
    mapping:
      kind: ethereum/events
      apiVersion: 0.0.6
      language: wasm/assemblyscript
      entities:
        - Account
      abis:
        - name: Bank
          file: ./abis/Bank.json
      eventHandlers:
        - event: Deposit(indexed address,indexed uint256)
          handler: handleDeposit
        - event: Transfer(indexed address,indexed address,indexed uint256)
          handler: handleTransfer
        - event: Withdraw(indexed address,indexed uint256)
          handler: handleWithdraw
      file: ./src/Bank.ts

Mappings

The mappings transform the Ethereum data your mappings are sourcing into entities defined in your schema. Mappings are written in a subset of TypeScript called AssemblyScript which can be compiled to WASM (WebAssembly). AssemblyScript is stricter than normal TypeScript, yet provides a familiar syntax.

The mapping file used for the Bank example can be found in the project:

export function handleDeposit(event: Deposit): void {
    const address = event.params.from
    const amount = event.params.amount
    const id = `${address.toHex()}`
    let instance = Account.load(id)
    if (!instance) {
        instance = new Account(id)
        instance.balance = amount
        instance.operateTime = BigInt.fromU32(1)
    } else {
        instance.balance = instance.balance.plus(amount)
        instance.operateTime = instance.operateTime.plus(BigInt.fromU32(1))
    }
    instance.save()
}

Deploying a Subgraph

With your local Graph Node, you can create your Subgraph executing the following code:

npx graph create <username>/<subgraph-name> --node <graph-node>

Where:

  • username — refers to the username related to the Subgraph being created

  • subgraph-name — the Subgraph name

  • graph-node — refers to the URL of the hosted service to use. Typically, for a local Graph Node is http://127.0.0.1:8020

Once created, you can deploy your Subgraph by running the following command with the same parameters as before:

npx graph deploy <username>/<subgraph-name> \
--ipfs <ipfs-url> \
--node <graph-node> \

Where:

  • username — refers to the username used when creating the Subgraph

  • subraph-name — refers to the Subgraph name defined when creating the Subgraph

  • ipfs-url — refers to the URL for IPFS. For your local Graph Node, the default value is http://localhost:5001

  • graph-node — refers to the URL of the hosted service to use. For your local Graph Node, the default value is http://localhost:8020

The logs for the sucessful deployed should look like:

DApps can now use the Subgraph endpoints to fetch the data indexed by The Graph protocol.

If there has existed call record for contract, you can call the Graph node to get the data, just like this:

curl -X POST -d '{ "query": "{accounts{id,balance,operateTime}}"}' http://localhost:8000/subgraphs/name/bank| json_pp
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   366  100   318  100    48  26500   4000 --:--:-- --:--:-- --:--:-- 33272
{
   "data" : {
      "accounts" : [
         {
            "balance" : "199999999999999922243",
            "id" : "0x809fae291f79c9953577ee9007342cff84014b1c",
            "operateTime" : "3"
         },
         {
            "balance" : "15000000000000000000",
            "id" : "0x898b84b6a6430eed36a6cfc14a1cb7da326c91c4",
            "operateTime" : "1"
         },
         {
            "balance" : "77777",
            "id" : "0x8dd89ed567ac41866babddeb8931af2a695106af",
            "operateTime" : "0"
         }
      ]
   }
}

References

Last updated