Creating a subgraph for The Graph
The Graph lets you index data from your smart contracts and provides a nice GraphQL API on top of this data. My goal was to create a smart contract to share data with another person / ethereum address.
Smart Contract
My initial idea was to create a basic smart contract with 1 method, to share data. This method emits an event for The Graph to index. For The Graph to index an entity, it should always have an ID. So where to get this ID from?
The Gravity / Gravatar example used the ID from the Array that stored all Gravatars on the blockchain. I copied this approach, stored all shared data in my smart contract in an array and used the array index as ID for The Graph. It looked like this:
shares.push(Share(msg.sender, receiver, appId, shareType, data));
uint id = shares.length - 1;
But storing my data in the smart contract is not needed. It's never modified or deleted. You can share and that's it. It only needs to be index by The Graph.
Then I learned about Call Handlers. With Call handlers, you can index the method call and all parameters. https://thegraph.com/docs/define-a-subgraph#call-handlers
This is enough for my current setup. So I removed everything from my Smart Contract, because the call data is enough to index. With this setup, I discovered that you can use the transaction hash as unique ID for The Graph. It was only a day later that I read that call handlers should be avoided when possible. They will be indexed slower.
https://thegraph.com/docs/quick-start
4. Am I still able to create a subgraph if my smart contracts don't have events?
It is highly recommended that you structure your smart contracts to have events associated with data you are interested in querying. Event handlers in the subgraph are triggered by contract events, and are by far the fastest way to retrieve useful data.
If the contracts you are working with do not contain events, your subgraph can use call and block handlers to trigger indexing. Although this is not recommended as performance will be significantly slower.
So I reverted my setup back to events, but without storing the data on the blockchain. The Id is now only available during the mapping, I use the transaction hash as id.
let share = new Share(event.transaction.hash.toHex())
Result of my smart contract: https://github.com/michielpost/TheShareItNetwork/blob/master/Contracts/01_ShareIt.sol
Subgraph
Now that we have a smart contract, we can create a Subgraph!
graph init
walks you through the steps to initialize a repository.
- Give your subgraph a name
username/subgraphname
- Select the Ethereum network. I picked Kovan because I'm still developing and not ready to deploy to mainnet yet
- Supply the contract address
- Supply the ABI file
- Supply the contract name
I developed my Smart Contract using Remix http://remix.ethereum.org/ On the compilation tab, you can also get the ABI from your Smart Contract.
After the init is finished, you will have a repository with a lot of generated files. We need to change some files.
Open subgraph.yaml
Add startBlock: [block number]
below abi in source. This should be the block number of your contract deployment.
Schema
When creating a subgraph, the two most important things are the schema and mapping. The schema defines the GraphQL entities which you can query. If it's not in your schema, it won't be available in your subgraph.
Open schema.graphql
and create a schema for your custom entity.
More info about the GraphQL Schema can be found here: https://thegraph.com/docs/define-a-subgraph#the-graphql-schema
Run graph codegen
This updates the generated typescript files in the generated
directory.
Mapping
Mapping is the step to go from your smart contract events to data in your entity defined by your schema. You map the data from the event to properties of your entity.
Open src/mapping.ts
add the mapping to your custom entity.
Mapping documentation is located here: https://thegraph.com/docs/define-a-subgraph#writing-mappings
Run graph codegen
again.
Deploy
Make sure you are authorized for The Graph api:
graph auth https://api.thegraph.com/deploy/ [TOKEN]
Deploy your subgraph:
graph deploy --node https://api.thegraph.com/deploy/ --ipfs https://api.thegraph.com/ipfs/ [graph-name]
Code for my subgraph is on GitHub: https://github.com/michielpost/TheShareItNetwork Deployed to The Graph: https://thegraph.com/explorer/subgraph/michielpost/the-shareit-network