The Graph Protocol: The Secret Sauce Behind Decentralized Applications

Archief
Nybles
Published in
10 min readJan 27, 2024

In the rapidly evolving landscape of blockchain and decentralized applications (dApps), addressing the inherent challenges has become a pivotal endeavor. The Graph Protocol ✨ emerges as a transformative force, serving as a decentralized indexing solution that redefines the seamless operation of dApps. By leveraging GraphQL, a powerful query language designed with clients in mind, The Graph Protocol empowers developers and stakeholders within the ecosystem to overcome significant obstacles.

Traditional approaches to dApp development often involve the creation of separate servers to interface with Ethereum nodes, leading to complexities in communication between server and client. The Graph Protocol steps in as a comprehensive solution, streamlining the development process by offering an efficient indexing and querying layer for blockchain data.

The reliance on custom indexing servers is mitigated through the expressive capabilities of GraphQL, allowing clients to precisely request the data they need. This not only reduces the intricacies associated with server-client coupling but also significantly accelerates the development cycle ⚡.

In the rapidly evolving landscape of blockchain and decentralized applications (dApps), addressing the inherent challenges has become a pivotal endeavor. The Graph Protocol ✨ emerges as a transformative force, serving as a decentralized indexing solution that redefines the seamless operation of dApps. By leveraging GraphQL, a powerful query language designed with clients in mind, The Graph Protocol empowers developers and stakeholders within the ecosystem to overcome significant obstacles.

Traditional approaches to dApp development often involve the creation of separate servers to interface with Ethereum nodes, leading to complexities in communication between server and client. The Graph Protocol steps in as a comprehensive solution, streamlining the development process by offering an efficient indexing and querying layer for blockchain data.

The reliance on custom indexing servers is mitigated through the expressive capabilities of GraphQL, allowing clients to precisely request the data they need. This not only reduces the intricacies associated with server-client coupling but also significantly accelerates the development cycle ⚡️.

💡 In contrast to conventional server infrastructures, which may introduce bottlenecks, The Graph Protocol’s approach is rooted in decentralization. It envisions a future where businesses can create subgraphs tailored to query data from a multitude of networks supported on The Graph Protocol. This not only provides a more efficient and scalable solution but also contributes to the establishment of a decentralized web (Web3) ecosystem🌐.

As dApps continue to grow in scale and complexity, The Graph Protocol stands as a beacon of innovation, offering a decentralized API and query layer that reshapes the future of data access in the decentralized web. By fostering an interconnected ecosystem and providing tools for versatile data querying, The Graph Protocol plays a crucial role in driving the evolution of decentralized applications towards greater efficiency and autonomy.

Unveiling The Graph Protocol’s Stable Interfaces

One of the key features of The Graph Protocol is its commitment to stable interfaces. These interfaces play a crucial role in defining the schema, creating mappings, and facilitating GraphQL-based querying. Initially launched as a centralized service, The Graph Protocol aims to accelerate the development of robust design, efficient implementation, and sustainable economic incentives. This strategic approach allows for faster iterations, highlighting the importance of stability in the ever-changing world of decentralized applications.

Challenging the Centralization Paradigm

Web-based applications such as Google, Facebook, YouTube, LinkedIn, and Salesforce heavily rely on centralized data syndication👀. However, this centralization model concentrates significant power in the hands of a few entities, potentially limiting economic freedom and confidence for a larger population. The Graph Protocol aims to disrupt this paradigm by establishing a fair and open market😎. It provides tools to incentivize individuals to contribute to a larger, more inclusive public infrastructure. To achieve this vision, an interoperability layer for decentralized applications (dApps) becomes essential.

What is a subgraph? 🤔

A subgraph is a tool that extracts data from a blockchain, processes it, and stores it in a PostgreSQL database. This allows the data to be queried using GraphQL.

A subgraph consists of the following files: 📁

  1. Subgraph.yaml (subgraph manifest): This file informs the Graph Node about the smart contract to be indexed, the events to listen for, and how to map the event data to entities (structured data). All linked files are deployed to IPFS and hashed🕵️ to generate a subgraph ID, which is used to retrieve the queried data. A single subgraph can index data from multiple smart contracts by adding an entry for each contract in the datasources array.
  2. Schema.graphql: This file defines the type of information that will be extracted and stored in the Graph Node’s database. If you are unfamiliar with writing GraphQL schemas, please refer to the GraphQL Schema docs.
  3. AssemblyScript Mappings: These mappings🎞️ define how the events emitted on the blockchain should be formatted according to the GraphQL schema. This allows the Graph Node to store and organize the data more efficiently. 🗂️

The Graph’s Role in Indexing Blockchain Data

At the heart of The Graph Protocol’s functionality lies the indexing of blockchain data through the use of subgraph manifests. These manifests serve as the blueprints for querying data, defining smart contracts of interest, specifying relevant events, and mapping event data to the Graph database. The process involves writing a subgraph manifest, storing it on IPFS using the Graph CLI and initiating the data indexing.

The working mechanism can be distilled into five straightforward steps:

  1. Dapp Transactions: A decentralized application (Dapp) initiates transactions, adding data to the blockchain.
  2. Smart Contract Events: Events are emitted by smart contracts during transaction execution.
  3. Graph Node Scanning: The Graph Node scans the blockchain for data defined in the subgraph manifest.
  4. Mapping Handlers: If the required data is found, mapping handlers are executed, storing the data in the Graph database.
  5. GraphQL Querying: Developers can then query the stored data using the GraphQL endpoint. ✨🔍🚀

The Graph Explorer and Graph Name Service: 💡

The Graph Explorer serves as a gateway for developers to discover valuable subgraphs, allowing them to effortlessly integrate data from various underlying protocols into their applications. At its core, the Graph Name Service (GNS) is an on-chain registry of subgraphs that plays a crucial role in enabling teams to attach human-readable names to subgraphs. This provides a meaningful and accessible way for developers to understand the purpose and utility of a subgraph.

💡 Developers navigate the Graph Explorer, which is envisioned as a decentralized application (dApp) built on a subgraph indexing the Graph Protocol smart contracts. This not only enhances the discoverability of subgraphs but also sets the stage for the upcoming subgraph composition feature within The Graph Network. Subgraph composition enables the creation of new subgraphs that reference entities from existing ones, promoting efficiency by reusing data across multiple dApps.

The Query Market and Decentralized Data Retrieval: 🌐

The Query Market within The Graph Protocol parallels the role of traditional APIs in cloud-based applications but with a decentralized twist. Instead of a single entity operating the API, The Graph’s Query Market consists of a decentralized network of Indexers competing to provide efficient and cost-effective services.

The typical flow involves service discovery, Indexer selection, query submission with conditional micropayment, and response with attestation. This decentralized approach empowers users to choose Indexers based on perceived quality and cost-effectiveness, fostering a competitive and dynamic ecosystem.

The Graph Protocol Stack

The Graph Protocol stack encompasses key components working in harmony:

  • GraphQL API: The primary interface for interacting with The Graph Protocol.
  • Indexer: Responsible for processing data from sources and storing it in a graph database.
  • Query Coordinator: Routes queries to the appropriate Indexer and returns results to the client.
  • Curation Subprotocol: Allows developers to stake Graph Tokens (GRT) to signal support for subgraphs.
  • Dispute Resolution Subprotocol: Addresses challenges to the curation signal of a subgraph. 🤝

Who Shapes The Graph Protocol Ecosystem? 💼

The success and decentralization of The Graph Protocol hinge on active participation from various roles within its ecosystem:

  1. Developers: They play a pivotal role in building subgraphs and publishing them to the network, contributing to the diversity and richness of available data. 👩‍💻👨‍💻
  2. Indexers: Serving as node operators, indexers stake Graph Tokens (GRT) to provide indexing and querying services. Their role is essential in responding to developers’ requests and charging fees for their services. 📊
  3. Delegators: Recognizing the financial barrier to setting up nodes, delegators stake GRT to indexers. In return, they earn a portion of the query fees and rewards, functioning as a vital bridge in the decentralized infrastructure. 🤝
  4. Curators: Armed with knowledge and expertise, curators use GRT to signal high-quality subgraphs to indexers. Their efforts are rewarded with a share of the query fees generated by the supported subgraphs. 🧐💡

Starter Subgraph ✨🚀

Defining entities in a subgraph is important because entities represent the data that will be queried and served by the GraphQL API. Entities define the structure and properties of the data that will be indexed from the blockchain and made available for querying. By defining entities, developers can specify the specific data they want to extract and make accessible to their frontend applications. This allows for efficient and targeted querying of the blockchain data, enabling developers to retrieve and display the relevant information to users. 🎯🔍

To configure a subgraph using The Graph, follow these steps:

  1. Install the Graph CLI: You can install the Graph CLI by using the command: npm install -g @graphprotocol/graph-cli
  2. Initialize your subgraph: If you already have a deployed contract, you can bootstrap your subgraph with autogenerated entities for each event. Run the following command and answer the questions: graph init --index-events
  3. Configure your subgraph: In the subgraph.yaml file, define the following fields such as data source, start block, entities, and event handlers.
  4. Define the entities: In the schema.graphql file, define the entities that you want to query in your GraphQL API.
  5. Run the codegen command: Execute the following command to generate the necessary code: graph codegen
  6. Update AssemblyScript Mappings: Configure the AssemblyScript mappings in the src/mapping.ts file to handle the events defined in subgraph.yaml.
  7. Deploy your subgraph: Deploy your subgraph using the following command: graph deploy --studio <subgraph-slug>
  8. Authenticate your subgraph: Authenticate your subgraph using the following command: graph auth --studio
  9. Test your subgraph: Test a sample query in the GraphQL playground in your subgraph dashboard to ensure everything is working correctly.

Please note that the above steps provide a general overview of the process. For more detailed information and specific instructions, refer to the official documentation of The Graph.

Datasource: Smart contract address

Start block: Smart contract start block

Entities: Data to be defined in schema.graphql

Event Handlers: Event handlers to be defined in mapping.ts

Building a Decentralized Finance Tracker with The Graph: Extending a Starter Subgraph

We will explore how to deploy a starter subgraph using The Graph Protocol, specifically focusing on tracking gas-related data for Ethereum transactions. We’ll use the popular Cryptopunks contract as an example and extend the functionality by adding a new entity to store account information. ✨🚀

Prerequisites

  1. Install Miniscan to gather information about the Cryptopunks contract on Etherscan.
  2. Access Subgraph Studio to create a new subgraph on your local computer using graph-cli.

Deploying a starter subgraph

Gather Information: Use Miniscan to find relevant details such as the Cryptopunks contract name, ABI, and start block.

Create a New Subgraph: Follow the instructions in Subgraph Studio to create a new subgraph on your local machine using graph-cli. Enter the gathered information when prompted and choose to index events as entities.

graph deploy..

Review Key Files:

  1. subgraph.yaml (Subgraph Manifest): Defines the subgraph and its properties.
  2. src/mappings.ts (Subgraph Logic): Contains the logic to handle events and update entities.
  3. schema.graphql (Presented Subgraph Data): Describes the structure of the subgraph’s data.

Understand the Transfer Entity: In schema.graphql, a Transfer entity is defined to capture Ethereum transfer events:

type Transfer @entity(immutable: true) {
id: Bytes!
from: Bytes!
to: Bytes!
value: BigInt!
blockNumber: BigInt!
blockTimestamp: BigInt!
transactionHash: Bytes!
}

Extending the Transfer Entity

  1. Add gasPrice Property: Extend the Transfer entity in schema.graphql by adding a gasPrice property:
type Transfer @entity(immutable: true) {
id: Bytes!
from: Bytes!
to: Bytes!
value: BigInt!
blockNumber: BigInt!
blockTimestamp: BigInt!
transactionHash: Bytes!
gasPrice: BigInt! ## ADDED HERE
}

Update mappings.ts: Modify mappings.ts to populate the new gasPrice property in the Transfer entity:

// mappings.ts
export function handleTransfer(event: TransferEvent): void {
let entity = new Transfer(
event.transaction.hash.concatI32(event.logIndex.toI32())
);
// Existing properties...
entity.gasPrice = event.transaction.gasPrice;
entity.save();
}

Add a New Entity — Account: In schema.graphql, add a new Account entity to store account information:

type Account @entity {
id: Bytes!
gasSpent: BigInt!
}

Update mappings.ts for Account Entity: Update mappings.ts to populate the new Account entity:

// mappings.ts
export function handleTransfer(event: TransferEvent): void {
// Existing logic...

// Load account from store. If account does not exist, create an account and set the gasSpent to 0.
let account = Account.load(
event.transaction.hash.concatI32(event.block.hash.toI32())
);
if (account == null) {
account = new Account(
event.transaction.hash.concatI32(event.block.hash.toI32())
);
account.gasSpent = BigInt.fromI32(0);
}

// Add the gas price of the current transaction to the total gas spent
account.gasSpent = account.gasSpent.plus(event.transaction.gasPrice);

account.save();
}

With this, I would like to end this blog. Thank you and hats off! if you read it till the end 😁.

About Me:

Hi guys, My name is Aryan Gautam. I am a sophomore at IIIT-Allahabad & member of the Blockchain wing at GeekHaven, IIIT-A.

You can contact and connect with me on Linkedin. Don’t forget to 👏 if this blog gave you some insights and clarity regarding the Graph protocol.

References:

--

--