Skip to content

The Graph

The Graph Overview

The Graph is a decentralized blockchain data indexing and querying protocol designed to solve the challenge of blockchain data access. It provides developers with an efficient way to index, organize, and query blockchain data, making it simple and efficient to build data-intensive decentralized applications (DApps). The Graph provides data services through GraphQL APIs and has become a vital component of Web3 infrastructure, often referred to as "the Google of blockchains."

Core Concepts

1. Subgraphs

Subgraphs are the core component of The Graph:

  • Data Definition: Defines smart contracts and events to index
  • Schema: Uses GraphQL Schema to define data structures
  • Mapping: Writes data transformation logic
  • Deployment: Deploys to the decentralized network
  • Querying: Queries indexed data via GraphQL

2. Graph Node

Nodes that run the indexing service:

  • Event Listening: Monitors blockchain events
  • Data Extraction: Extracts relevant data from the blockchain
  • Data Transformation: Executes Mapping to transform data
  • Data Storage: Stores data to a database
  • Query Service: Responds to GraphQL query requests

3. Decentralized Network

Participants in The Graph network:

  • Indexers: Run nodes to index data and earn rewards
  • Curators: Identify high-quality subgraphs and earn rewards
  • Delegators: Delegate GRT to indexers
  • Developers: Create subgraphs and pay query fees
  • Consumers: Applications and users that use subgraph data

4. GRT Token

The Graph's native token:

  • Query Fees: Pay data query fees
  • Indexing Rewards: Reward indexers and curators
  • Governance: Participate in protocol governance
  • Staking: Indexers stake GRT to participate in the network

How The Graph Works

Data Indexing Flow

  1. Define Subgraph: Developer defines contracts and events to index
  2. Deploy Subgraph: Deploy the subgraph to The Graph network
  3. Index Data: Graph Node monitors the blockchain and indexes data
  4. Data Transformation: Mapping functions transform raw data
  5. Store Data: Transformed data is stored in a database
  6. Serve Queries: Query service provided via GraphQL API

GraphQL Queries

The Graph uses GraphQL as its query language:

Advantages: - Precise Queries: Request only the fields you need - Single Request: Get multiple resources in one request - Type Safety: Strong type system reduces errors - Live Documentation: Automatically generated API docs - Flexible and Efficient: Avoids over-fetching and under-fetching

Query Example:

{
  tokens(first: 10, orderBy: totalSupply, orderDirection: desc) {
    id
    name
    symbol
    totalSupply
    decimals
  }
}

Creating a Subgraph

1. Install Graph CLI

npm install -g @graphprotocol/graph-cli

2. Initialize Subgraph

graph init --product hosted-service username/subgraph-name

3. Define Schema

schema.graphql:

type Token @entity {
  id: ID!
  name: String!
  symbol: String!
  decimals: Int!
  totalSupply: BigInt!
  holders: [Holder!]! @derivedFrom(field: "token")
}

type Holder @entity {
  id: ID!
  address: Bytes!
  balance: BigInt!
  token: Token!
}

4. Write Mapping

src/mapping.ts:

import { Transfer } from "../generated/Token/Token"
import { Token, Holder } from "../generated/schema"

export function handleTransfer(event: Transfer): void {
  let token = Token.load(event.address.toHex())

  if (token == null) {
    token = new Token(event.address.toHex())
    token.name = "Token Name"
    token.symbol = "TKN"
    token.decimals = 18
    token.totalSupply = BigInt.fromI32(0)
  }

  // Update sender balance
  let sender = Holder.load(event.params.from.toHex())
  if (sender != null) {
    sender.balance = sender.balance.minus(event.params.value)
    sender.save()
  }

  // Update receiver balance
  let receiver = Holder.load(event.params.to.toHex())
  if (receiver == null) {
    receiver = new Holder(event.params.to.toHex())
    receiver.address = event.params.to
    receiver.balance = BigInt.fromI32(0)
    receiver.token = token.id
  }
  receiver.balance = receiver.balance.plus(event.params.value)
  receiver.save()

  token.save()
}

5. Configure Subgraph Manifest

subgraph.yaml:

specVersion: 0.0.4
schema:
  file: ./schema.graphql
dataSources:
  - kind: ethereum
    name: Token
    network: mainnet
    source:
      address: "0x..."
      abi: Token
      startBlock: 12000000
    mapping:
      kind: ethereum/events
      apiVersion: 0.0.6
      language: wasm/assemblyscript
      entities:
        - Token
        - Holder
      abis:
        - name: Token
          file: ./abis/Token.json
      eventHandlers:
        - event: Transfer(indexed address,indexed address,uint256)
          handler: handleTransfer
      file: ./src/mapping.ts

6. Deploy Subgraph

# Code generation
graph codegen

# Build
graph build

# Deploy to Hosted Service
graph deploy --product hosted-service username/subgraph-name

# Deploy to decentralized network
graph deploy --node https://api.thegraph.com/deploy/ subgraph-name

Querying Subgraph Data

Using GraphQL Playground

Access the subgraph URL in a browser:

https://api.thegraph.com/subgraphs/name/username/subgraph-name

Integrating in Applications

Using Apollo Client:

import { ApolloClient, InMemoryCache, gql } from '@apollo/client'

const client = new ApolloClient({
  uri: 'https://api.thegraph.com/subgraphs/name/username/subgraph-name',
  cache: new InMemoryCache()
})

const GET_TOKENS = gql`
  query GetTokens {
    tokens(first: 10, orderBy: totalSupply, orderDirection: desc) {
      id
      name
      symbol
      totalSupply
    }
  }
`

const { data } = await client.query({ query: GET_TOKENS })

Using fetch:

const query = `
  {
    tokens(first: 10) {
      id
      name
      symbol
    }
  }
`

const response = await fetch('https://api.thegraph.com/subgraphs/name/username/subgraph-name', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ query })
})

const data = await response.json()

The Graph Network

Decentralized Network vs Hosted Service

Feature Decentralized Network Hosted Service
Decentralization Fully decentralized Centralized service
Fees Requires GRT payment Free (no new subgraphs)
Reliability Higher Depends on single point
Censorship Resistance Yes No
Migration Recommended Being phased out

Network Participants

Indexers: - Run Graph Node - Stake GRT - Index subgraph data - Earn query fees and indexing rewards

Curators: - Identify quality subgraphs - Stake GRT as signal - Earn query fee share

Delegators: - Delegate GRT to indexers - No need to run nodes - Earn portion of indexing rewards

Supported Blockchains

The Graph supports multiple blockchains:

  • Ethereum: Mainnet, Goerli, Sepolia
  • Polygon: Mainnet, Mumbai
  • Arbitrum: One, Nova
  • Optimism: Mainnet
  • Avalanche: C-Chain
  • Celo: Mainnet
  • BNB Chain: Mainnet
  • Gnosis Chain: Mainnet

Advanced Features

1. Entity Relationships

Define relationships between entities:

type User @entity {
  id: ID!
  posts: [Post!]! @derivedFrom(field: "author")
}

type Post @entity {
  id: ID!
  author: User!
  content: String!
}

Add full-text search capabilities:

type Article @entity {
  id: ID!
  title: String! @fulltext(name: "articleSearch", language: en)
  content: String! @fulltext(name: "articleSearch", language: en)
}

Query:

{
  articleSearch(text: "blockchain") {
    id
    title
  }
}

3. Time Travel Queries

Query historical state:

{
  tokens(block: { number: 15000000 }) {
    id
    totalSupply
  }
}

4. Subscriptions

Real-time data updates:

subscription {
  transfers(orderBy: blockNumber, orderDirection: desc) {
    from
    to
    value
  }
}

Best Practices

1. Schema Design

  • Normalization: Avoid data redundancy
  • Indexing: Add indexes for frequently queried fields
  • Naming: Use clear entity and field names
  • Types: Choose appropriate data types

2. Mapping Optimization

  • Batch Processing: Reduce database operations
  • Conditional Checks: Avoid unnecessary operations
  • Error Handling: Properly handle exceptions
  • Gas Optimization: Optimize on-chain data reads

3. Query Optimization

  • Pagination: Use first and skip for pagination
  • Filtering: Reduce returned data volume
  • Sorting: Use orderBy judiciously
  • Caching: Leverage client-side caching

Monitoring and Debugging

Graph Explorer

  • Query Statistics: View query counts and fees
  • Indexing Status: Monitor indexing progress
  • Error Logs: View error messages
  • Performance Analysis: Analyze query performance

Local Development

Develop locally using Graph Node:

git clone https://github.com/graphprotocol/graph-node
cd graph-node/docker
docker-compose up

Use Cases

  • DeFi: Transaction history, liquidity data, price information
  • NFT: Ownership tracking, transaction history, rarity analysis
  • DAO: Proposals, votes, governance data
  • Gaming: Game assets, player data, leaderboards
  • Analytics: On-chain data analysis and visualization
  • GraphQL: The query language used by The Graph
  • Ethereum: Primary supported blockchain
  • IPFS: Decentralized storage, also supported by The Graph
  • Dune Analytics: Another blockchain data analytics platform

Summary

The Graph solves the pain points of data access in DApp development by providing efficient blockchain data indexing and query services. Its decentralized architecture, flexible GraphQL queries, and rich ecosystem make it a key component of Web3 infrastructure. Whether for DeFi protocols, NFT marketplaces, or on-chain analytics tools, The Graph provides powerful data support. As more blockchains are integrated and the network continues to improve, The Graph will continue to play an important role in the Web3 data layer.