DEV Community

Cover image for Creating an ERC721(NFT) Subgraph
cptMoh
cptMoh

Posted on • Updated on

Creating an ERC721(NFT) Subgraph

Introducing The Graph

The Graph is the indexing and querying protocol for web3. It is a key piece of infrastructure in the decentralised web3 stack. With The Graph and open APIs called "subgraphs", developers can build applications and create and publish subgraphs that query data from blockchains.

For example, developers commonly create applications that display data to the application's end users - such as trades, NFTs and DAOs. Using The Graph, developers can create applications that quickly and easily display data retrieved from blockchains. Subgraphs make it easier for developers to build on top of blockchains and enabling UIs to be highly performant with rich and dynamic data.

Subgraphs index data that is defined by the developers that create it, based on what information they'd like to present in their UIs. A network of Indexers (node operators) index the subgraphs and process queries for dapps, ensuring dapps don't rely on single centralised servers.

Subgraphs

Subgraphs are open APIs that are created and published by developers. In essence, a subgraph defines how to ingest, index, and serve data, and they are used by developers to build dapps.

Subgraphs allow developers to more easily query complex blockchain data. Developers use subgraphs to feed data to the front-end interface of their applications, such as displaying financial data or NFT marketplace information to their users.

Without The Graph, dapp developers would have to run their own centralised back-end infrastructure to query blockchain data. Furthermore, the time saved by using subgraphs enables developers to focus on building high-quality applications and front-end interfaces. Subgraphs make it easier to build on web3 protocols, reduce the need for centralised databases, and eliminate specialised engineering resources and hardware.

Building a Subgraph

In this guide, we are going to look at what building a subgraph looks like by building one that indexes an ERC721 NFT Token.

First Steps

  • For this guide, we are going to be using the hosted service. Head over there by clicking on this link and either create an account or login to your dashboard.

  • Once on your dashboard, click on the 'Add Subgraph' Button.

  • Fill in the required fields on the form. Make sure the name that you give to the subgraph is the same as the name you will give to your github repository for the subgraph.

  • Submit the form.

  • Next, You can click on the button to 'show commands' of how to install the graph CLI globally using either NPM or Yarn if you don't already have it installed. This is because you will need it to build and deploy subgraphs.

Initialising the Subgraph.

The Next step is to initialise the subgraph from your terminal. But before this, you need to cd into the directory/folder that you want to write your code in.

Once you're there, go on and run:

graph init subgraph-name
Enter fullscreen mode Exit fullscreen mode

Be sure to replace 'subgraph-name' with the name of the subgraph you are building. For example, since we're going to be making a bored apes subgraph, i'm going to run;

graph init boredapes
Enter fullscreen mode Exit fullscreen mode

Next, you'll be prompted to choose a protocol on the terminal. For this, we can go on and choose ethereum

  • Choose the hosted service.

  • Next, you will be prompted to choose the name of your subgraph. It should be ‘your-github-account/your-subgraph-name’. for example, my github account is 'mufasasa', and the name of the subgraph we're making is 'boredapes'. Therefore, i'm going to put in 'mufasasa/boredapes'.

  • You'll then be asked to choose the directory that you want the subgraph to be created in. you can leave it as the current directory that you are working on, so just hit the 'enter' key.

  • You'll be prompted to choose from the available networks. Choose mainnet.

  • Provide the contract address of the smart contract that you want to index. The smart contract address can be gotten from etherscan. We are indexing the bored apes smart contract, so you can copy and past in the address 0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D

  • You can leave the default contract name; Contract.

  • A new folder will be created for you with the name that you specified. Go on an cd into the folder, then open it up in your code editor.

  • Next, open the subgraph.yaml file and make the following edits;

specVersion: 0.0.4
schema:
  file: ./schema.graphql
dataSources:
  - kind: ethereum
    name: undefined
    network: mainnet
    source:
      address: "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D"
      abi: Contract
      startBlock: "12287507"
    mapping:
      kind: ethereum/events
      apiVersion: 0.0.5
      language: wasm/assemblyscript
      entities:
        - Approval
        - Transfer
      abis:
        - name: Contract
          file: ./abis/Contract.json
      eventHandlers:
        - event: Approval(indexed address,indexed address,indexed uint256)
          handler: handleApproval
        - event: Transfer(indexed address,indexed address,indexed uint256)
          handler: handleTransfer
      file: ./src/contract.ts
Enter fullscreen mode Exit fullscreen mode

I added the StartBlock under the 'source subsection'. This is the Transaction Block of when the contract was deployed, and can be gotten from etherscan.

  • I also deleted 'approval for all' in the entities and event handlers subsection. Note Whenever you want to index a smart contract, be sure to check the contract code and see what event(s) the contract is emitting, and then proceed accordingly.

Defining our Schema.

we are now going to proceed to the schema.graphql file to define our schemas.

  • The very first thing that we'll do here is delete the example schema that we were given there.

  • Next, we'll define the schema of our entities in this file. A prior knowledge of graphql will come in handy here. But even if you don't know graphql, then that's okay too. You can just paste the following inside your schema.graphql file.

type TransferEvent @entity{

id: ID! 

" Id of the transferred token "
tokenId: BigInt!

"address of the sender "
sender: Bytes!

"address of the receiver "
destination: Bytes!

"event timestamp"
timestamp: BigInt!

"transaction hash"
transaction: Bytes!

}


type ApprovalEvent @entity{

id: ID!

" Id of the approved token "
tokenId: BigInt!

"address of the owner"
owner: Bytes!

"address of the approved"
approved: Bytes!

"event timestamp"
timestamp: BigInt!

"transaction hash"
transaction: Bytes!

}
Enter fullscreen mode Exit fullscreen mode

What we're trying to do is defining the format that our entities are going to take. Kind of like defining our data models. I'll breakdown the models below so that we can have an idea of what is going on.

type TransferEvent @entity{

id: ID! 

" Id of the transferred token "
tokenId: BigInt!

"address of the sender "
sender: Bytes!

"address of the receiver "
destination: Bytes!

"event timestamp"
timestamp: BigInt!

"transaction hash"
transaction: Bytes!

}

Enter fullscreen mode Exit fullscreen mode

At the very beginning we are declaring the 'TransferEvent' type, and we're saying it is an entity.The fields that we want inside the transfer event are then specified inside the curly brackets.

  • The first field there is the 'id' field. We then put a colon and 'ID' after it, meaning it is of type 'ID'. the exclamation mark means the field is required.

  • The second field is 'tokenId' which is of type 'BigInt' and is going to be holding the id of the NFT.

  • The third field, 'sender' is of type 'Bytes', and is also required. We are using the 'Bytes' type because we are going to be storing the wallet address of the sender in the field.

The fourth field is just like the third field, but storing the address of the receiver of the NFT. The fifth field stores the event time stamp and the sixth field stores the transaction hash.

Once you are done with the schema.graphql file, head on over to the 'src' directory, and open the 'contract.ts' file. This is where we are going to define our mappings. What we are going to be doing here is directing how an emitted event from the dapp is going to be mapped and saved in our database.

You can delete the automatically generated code there and paste the following code into the file;

import { Transfer, Approval } from "../generated/undefined/Contract";
import { TransferEvent, ApprovalEvent } from "../generated/schema";


export function handleTransfer(event:Transfer): void {
    let transferEvent = new TransferEvent(event.transaction.hash.toHex()+"-"+event.logIndex.toString());

    transferEvent.tokenId = event.params.tokenId;

    transferEvent.sender = event.params.from;

    transferEvent.destination = event.params.to;

    transferEvent.timestamp = event.block.timestamp;

    transferEvent.transaction = event.transaction.hash;
    transferEvent.save();
}


export function handleApproval(event:Approval): void {
    let approvalEvent = new ApprovalEvent(event.transaction.hash.toHex()+"-"+event.logIndex.toString());

    approvalEvent.tokenId = event.params.tokenId;

    approvalEvent.owner = event.params.owner;

    approvalEvent.approved = event.params.approved;

    approvalEvent.timestamp = event.block.timestamp;

    approvalEvent.transaction = event.transaction.hash;
    approvalEvent.save();
}
Enter fullscreen mode Exit fullscreen mode

The two functions are going to be called whenever either a transfer or an approval event is emitted from the dapp.

Our subgraph is now ready to be deployed!!

To deploy, run graph auth on your terminal

  • Choose the hosted service

  • It will ask you to enter the deploy key. Head to your dashboard, copy your access token, and then paste it.

  • Finally, run npm run deploy

  • Wait for it to compile your subgraph and deploy it.

If you head to your dashboard, you will see that your Subgraph is deployed and syncing.

Congratulations!!!

for more information about building subgraphs and the graph protocol in general, go to the graph academy

Top comments (0)