schema.graphql
:
schema.graphql
:
Transfer
entity will index data every time a Bored Ape NFT is transferred. It will log the transaction data, as well as the recipient and receiver addresses.BoredApe
entity will index all the major information about an ape, including the original creator and the current owner.Property
entity will index the IPFS metadata for all the apes. Each instance of this entity can be identified using the id
field, which is nothing but the tokenID
of the ape.subgraph.yaml
, and paste the following code:
subgraph.yaml
:
Transfer
event from the smart contract will suffice.ipfsOnEthereumContracts
must be declared under features.graph codegen
in your terminal. You must run this command every time you edit the schema or YAML file.
src/bayc.ts
and delete everything inside it. Paste the following code:
src/bayc.ts
:
handleTransfer
function. This function will be automatically triggered every time the Transfer
event is triggered in the BAYC smart contract. We configured this behavior inside the YAML file by creating the event-handler pair.Transfer
and BoredApe
entities straight from the logs emitted by the smart contract.[ipfs.cat](http://ipfs.cat)
method from the graph-ts library by passing it the IPFS hash and the token URI for a specific ape.graph build
to compile your subgraph. Technically, you can even deploy this code to Chainstack, and it will index data without failing explicitly.
When I tried querying this subgraph, however, I realized I could only query data for the Transfer
and BoredApe
entities. The Property
entity didn’t return any data at all.
But how do you know that the fault definitely lies with your subgraph? What if Chainstack is running a buggy indexer? Within your Chainstack Subgraphs console, you can query all 4 levels of logs that are defined in The Graph’s logging API. You can always refer to these to try and debug your subgraphs. You can use these logs to debug your subgraph, and then there is no need to set up a local Graph Node at all.
Let us recreate this entire scenario on our machine.
docker-compose.yaml
file in a code editor. Even the old and rusty Notepad++ will do. Docker will download the required dependencies using official images uploaded to it. Go to the image under IPFS, and change the line to the following:
.cat
method, we need to configure an extra environment variable. Inside the environment
object, add an environment variable like this:
ethereum
environment variable like this:
graph-node-local
running. This step might take a while to execute the first time.
See how powerful this is? We didn’t have to download or set up a single dependency, and Docker automatically set up everything on our local endpoints. You can stop this container, and hence the Graph Node, by simply halting your terminal.
Finally, make sure the latest_block_head
in your terminal corresponds to the latest block on Etherscan. Otherwise, it means your node is lagging behind.
graph init
, the graph-cli creates a few commands inside the package.json
file that can be executed using npm run
.
docker-compose up
command. It should now be indexing data by requesting data from the Ethereum archive node we passed to it.
While the subgraph won’t be able to show us data from the recently added blocks, we can still query it. The graph-cli
provides you with a UI interface URL and a GraphQL query endpoint in the terminal. Either one of those can be used to query the subgraph. In this tutorial, we will be using the UI interface. The Graph’s query API is discussed in detail in the beginner’s guide. Feel free to refer to that if you feel lost here.
In the next section, we will start debugging our subgraph.
http://localhost:8000/subgraphs/name/BAYC/graphql
. This URL may be different for you.
Property
entity had indexed no data, my first guess was that I passed the wrong IPFS path to the ipfs.cat()
method. To double-check that, I used The Graph’s logging API.
This is where the fun starts. Let us do this!
src/bayc.ts
in your subgraph code, and add this line to the file right before we invoke the ipfs.cat()
method:
docker-compose up
and re-deploy to the local node from the subgraph’s directory.
fullURI
every time the handler function runs. When I go to ipfs://<FULL_URI>
, I can see all the metadata for the specific NFT. So this is not it. We’re missing something else.
Back to square 1.
ipfs://<FULL_URI>
doesn’t work on your machine, try accessing IPFS with https://ipfs.io/ipfs/<FULL_URI>
.Property
entity wasn’t returning null
in the data fields. That would imply that the IPFS data is not being indexed correctly.
No. The Property
entity isn’t returning anything at all. As in, the entity doesn’t have a single instance in our subgraph’s data store. This means we aren’t correctly storing the new instances generated every time the handleTransfer
function is triggered.
I scan the code carefully once more, armed with this knowledge. And I finally catch it.
Check out the code for the src/bayc.ts
file again. Specifically, notice the save()
method. Every time we generate and fill out a new instance of an entity, we need to SAVE it to the subgraph’s data store. That is what the save()
method does.
While writing the mapping function, I never saved any instance of the Property
entity to the data store.
To solve this error, add the following expression to the handlerTransfer
right before it ends:
Property[0]
in the error log. This means that the very first instance of our entity failed to index. The field hat
apparently can’t be null
.
And again, it hit me.
Check out the code in the schema.graphql
file. All of our entities are suffixed by the !
symbol.
Each entity field marked by !
has to contain a value, it can’t be null
. Now, this makes sense for fields like blockNumber
and transactionHash
, since those values will never be null
.
It is, however, possible, that a particular ape might not have all the 7 traits. In my experience, this is true more often than not. The very first Bored Ape, with tokenID
0, does not have a “hat”. Quite literally, it doesn’t have a hat. Hence, the metadata for this NFT returns null
, when we try to query it for the value of the property hat
. Check it out on OpenSea.
Likewise, other apes will lack one or more of the properties that some other apes have. Thus, we need to edit the Property
entity to look like this:
Property
entity like this:
startBlock
in the YAML file. If you are confident that the changed code won’t cause the subgraph to fail on any of the blocks that were successfully indexed during the previous run, it makes sense to test out the subgraph on only the remaining blocks. This can save you time and resources.codegen
and build
commands as before. Instead of deploying the subgraph to the local node, copy the deployment command from your Chainstack Subgraph’s console, and run it in a terminal at the root of your subgraph project.
docker-compose.yaml
file.
Create an account on Chainstack today, to get access to super-fast, enterprise-grade blockchain indexers. Or maybe just hang around and check out our Web3 [De]Coded section for cool Web3 tutorials and expert-level articles.