The Graph: How to create your own subgraph for Keep Network and tBTC

gnran
4 min readSep 30, 2020

--

Since many people wanted to create their own subgrahs, I’ve decided to create this post that provides step-by-step guide on how to create Keep Network and tBTC subgraphs on The Graph.

Installation

Before we begin, you need npm or yarn installed and a basic knowledge of GraphQL and Docker. Additionally, to proceed further succesfully, it is strongly recommended to read Quick Start guide to have an overview of how Graph Node works and how to deploy a subgraph.

First thing, that you need to do is to install Graph CLI by running

yarn global add @graphprotocol/graph-cli

Secondly, we need to create a Subraph Project:

graph init \
--from-contract 0x85eee30c52b0b379b046fb0f85f4f3dc3009afec\
--network mainnet\
<GITHUB_USER>/<SUBGRAPH_NAME>

Creating the subgraph

After initialization your project directory will look like this

Here are several imporant files which you’ll need to create your subgraph:

  1. The subgraph manifest subgraph.yamldefines 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.

Every manifest starts with the following code:

specVersion: 0.0.2
schema:
file: ./schema.graphql
dataSources:

The following code is specific for each contract. Here I will provide some example manifests for Keep contract, Staking contract and TBTC Token Contract, so you could use in your own subgraph:

Keep Contract manifest:

- kind: ethereum/contract
name: Contract
network: mainnet
source:
address: "0x85eee30c52b0b379b046fb0f85f4f3dc3009afec"
abi: Contract
startBlock: 9958363
mapping:
kind: ethereum/events
apiVersion: 0.0.4
language: wasm/assemblyscript
entities:
- Approval
- Transfer
- TokenInfo
- User
abis:
- name: Contract
file: ./abis/Contract.json
eventHandlers:
- event: Approval(indexed address,indexed address,uint256)
handler: handleApproval
- event: Transfer(indexed address,indexed address,uint256)
handler: handleTransfer
file: ./src/mapping.ts

Staking Contract manifest:

- kind: ethereum/contract
name: StakingContract
network: mainnet
source:
address: "0x1293a54e160d1cd7075487898d65266081a15458"
abi: StakingContract
startBlock : 10834080
mapping:
kind: ethereum/events
apiVersion: 0.0.4
language: wasm/assemblyscript
entities:
- ExpiredLockReleased
- LockReleased
- OperatorStaked
- RecoveredStake
- StakeDelegated
- StakeLocked
- StakeOwnershipTransferred
- TokensSeized
- TokensSlashed
abis:
- name: StakingContract
file: ./abis/StakingContract.json
- name: Contract
file: ./abis/Contract.json
eventHandlers:
- event: ExpiredLockReleased(indexed address,address)
handler: handleExpiredLockReleased
- event: LockReleased(indexed address,address)
handler: handleLockReleased
- event: OperatorStaked(indexed address,indexed address,indexed address,uint256)
handler: handleOperatorStaked
- event: RecoveredStake(address)
handler: handleRecoveredStake
- event: StakeDelegated(indexed address,indexed address)
handler: handleStakeDelegated
- event: StakeLocked(indexed address,address,uint256)
handler: handleStakeLocked
- event: StakeOwnershipTransferred(indexed address,indexed address)
handler: handleStakeOwnershipTransferred
- event: TokensSeized(indexed address,uint256)
handler: handleTokensSeized
- event: TokensSlashed(indexed address,uint256)
handler: handleTokensSlashed
- event: Transfer(indexed address,indexed address,indexed uint256)
handler: handleMintTBTCDepositToken
file: ./src/Staking.ts

TBTC Token Contract manifest:

- kind: ethereum/contract
name: TBTCTokenContract
network: mainnet
source:
address: "0x8dAEBADE922dF735c38C80C7eBD708Af50815fAa"
abi: TBTCTokenContract
startBlock: 10867840
mapping:
kind: ethereum/events
apiVersion: 0.0.4
language: wasm/assemblyscript
entities:
- Approval
- Transfer
abis:
- name: TBTCTokenContract
file: ./abis/TBTCTokenContract.json
eventHandlers:
- event: Transfer(indexed address,indexed address,uint256)
handler: handleTransfer
file: ./src/TBTCToken.ts

These are just example manifests, but you can create your own entities and eventHandlers, which you need.

2. The second file is schema.graphql. GraphQL schemas are defined using the GraphQL interface definition language. Our next step is to define some entities. I’ll show you a simle example of how to create an entity for tBTC subgraph, so you can create other entities by your own.

type TBTCToken @entity {
id: ID!
owner: Bytes!
amount: BigInt!
mintedAt: BigInt!
burnedAt: BigInt
isBurned: Boolean!
}

TBTCToken entity contains some information about token such as total owner, amount, minted at etc. You can modify this entity by addingother properties, for example: total supply, max supply and etc.

3. The third file important file is mapping.ts which is automatically created in the src folder. Now we’ll make some changes to the mapping.ts file. We need to tell Graph Node what we want to happen each time a block is processed.

import { Transfer as TBTCTransfer } from "../generated/TBTCToken/TBTCToken";import { TBTCToken } from "../generated/schema";export function handleMintTBTCToken(event: TBTCTransfer): void {
if (event.params.from.toHexString() == ZERO_ADDRESS) {
let tbtc = new TBTCToken(
event.transaction.hash.toHex() + "-" + event.logIndex.toString() );
tbtc.amount = event.params.value;
tbtc.owner = event.params.to;
tbtc.mintedAt = event.block.timestamp;
tbtc.isBurned = false;
tbtc.save();
} else {
log.info("Not minted", []);
}
}

Here we defined a handleMintTBTCToken handler that is called each time TBTCTransfer event happens.

Deploying the subgraph to Graph Node

At the last step, we need to create our subgraph on the local Graph Node and deploy it. We can do it with the following commands:

yarn create-local
yarn deploy-local

After a while, when Graph Node starts indexing the subgraph, you can query minted TBTC at a given day.

{
tbtctokens(first: 3, where: {mintedAt_gt: "1589587200", mintedAt_lt: "1589673600"}) {
id
mintedAt
amount
owner
}
}

This query will show first 3 entities.

You can create entities for any contract. I’ve already given you some templates, so all you need to do is to create your own handler for your own needs.

As you can see, creating your subgrah is not some kind of a difficult thing. Hopefully, this guide will answer many of your questions

--

--