Data Source Templates: Seamlessly Track Newly Deployed Contract Data in Your Subgraphs

Tired of upgrading your subgraphs every time a contract is upgraded or deployed? Leveraging Data Source Templates eliminates this hassle and takes subgraphs to the next level. These templates allow subgraphs built on The Graph to dynamically track and index newly deployed contracts, ensuring that no data is left behind.

Whether developers are using factory deployment patterns or dealing with complex interactions, Data Source Templates provide the flexibility needed to maintain a comprehensive view of blockchain data without constant subgraph upgrades.

Data Source Templates work by allowing subgraphs to dynamically add data sources during runtime. Instead of hardcoding all potential contracts in a subgraph.yaml manifest, developers can define a template that serves as a blueprint. When new contracts matching certain criteria are deployed, The Graph subgraph can instantiate a new data source from this template, automatically tracking the contracts’ events and state changes.

This dynamic capability is particularly useful for protocols and dapps that create multiple contracts over time, such as token deployments, NFT creation, or in the case of Perpetual Organization Architect (Poa), deploying new DAOs. It also allows for easy integration with common proxy upgrade patterns. Subgraphs leveraging Data Source Templates require minimal maintenance, reducing downtime and allowing developers to focus on adding new features to their protocol or dapp rather than managing infrastructure.

Data Source Templates can be used to track newly deployed DAOs from factory contracts. The example below is from Poa, the Perpetual Organization Architect. Check out the repo here to follow along and see a complex Data Source Template implementation.

Data Source Templates with Factory Pattern

The Factory Pattern is a common smart contract design pattern where a central contract (the factory) is used to deploy new contracts based on parameters passed into the factory. With a traditional subgraph setup, developers would need to manually update the subgraph to include each new contract, which is not scalable for protocols that deploy contracts dynamically. By utilizing Data Source Templates, a template is defined that describes how to track these new contracts and automatically index them.

In the case of Poa, the master deploy factory (masterDeployFactory.sol) deploys multiple contracts responsible for the DAO’s operation and leverages Data Source Templates to track them. This approach ensures users can easily query data and build their own frontends on top of the subgraph if they choose, enhancing customization and accessibility.

Implementation of Data Source Templates

Let's break down how to implement Data Source Templates in a subgraph, using Poa's DAO deployment as an example.

Here is a step-by-step example of how Poa uses Data Source Templates:

  1. Defining and linking entities in schema.graphql
  2. Implementing Data Source Templates in subgraph.yaml
  3. Triggering Data Source Templates in mappings.ts

1. Defining and Linking Entities in schema.graphql

The first step is to define the custom entities we want to track. In this example, there’s a simplified PerpetualOrganization entity, a DirectDemocracyToken entity, and an entity to track the minting of direct democracy tokens on the new contract. We can model a custom implementation off of this:

type PerpetualOrganization @entity {
id: ID!
name: String!
directDemocracyToken: DDToken
}
type DDToken @entity {
id: ID!
tokenAddress: Bytes!
name: String!
symbol: String!
pOName: String!
mintEvents: [DDTokenMintEvent!]! @derivedFrom(field: "token")
}
type DDTokenMintEvent @entity {
id: ID!
token: DDToken!
to: Bytes!
amount: BigInt!
}
schema.graphql

This schema is set up so that the PerpetualOrganization does not require a directDemocracyToken to exist when it's created (note the missing ! that marks it as nullable). This allows us to handle the creation of the PerpetualOrganization entity before the corresponding DDToken entity is created.

It’s also important to note that entity relationships are defined by directly associating entities like PerpetualOrganization and DDToken through their fields, allowing for seamless access between them. Meanwhile, @derivedFrom is used for reverse lookups, enabling efficient retrieval of related data like mintEvents for a specific DDToken. This is particularly useful because while each organization has only one DDToken, that token can have multiple mint events.

2. Implementing Data Source Definitions in subgraph.yaml

When defining data sources the first step is to define all of the subgraphs’ static sources as usual and make sure to include your factory contract similar to below. The only entity that will be created by the factory in this instance is a new DDToken.

- kind: ethereum/contract
name: DirectDemocracyTokenFactory
network: polygon-amoy
source:
address: "0x2F0f89dc567A9147e43008141496e0703870C057"
abi: DirectDemocracyTokenFactory
startBlock: 9480000
mapping:
kind: ethereum/events
apiVersion: 0.0.7
language: wasm/assemblyscript
entities:
- DDToken
abis:
- name: DirectDemocracyTokenFactory
file: ../abi/DirectDemocracyTokenFactory.json
eventHandlers:
- event: TokenCreated(address,string,string,string[],string)
handler: handleTokenCreated
file: ./mappings/ddToken/ddTokenFactoryMapping.ts
subgraph.yaml

Next, define your templates for the DirectDemocracyToken itself. The main difference here is that instead of being defined under dataSources like normal, we define it under the templates category, and the source only includes the abi because the address and startBlock are unknown. We still need to define what entities and eventHandlers will be needed as normal.

templates:
- kind: ethereum/contract
name: DirectDemocracyToken
network: polygon-amoy
source:
abi: DirectDemocracyToken
mapping:
kind: ethereum/events
apiVersion: 0.0.7
language: wasm/assemblyscript
entities:
- DDToken
- DDTokenMintEvent
abis:
- name: DirectDemocracyToken
file: ../abi/DirectDemocracyToken.json
eventHandlers:
- event: Mint(indexed address,uint256)
handler: handleTokenMint
file: ./mappings/ddToken/ddTokenMapping.ts
subgraph.yaml

We’ve successfully implemented the data source template definition in subgraph.yaml, so it's time to move on to how the event handlers work with templates.

3. Triggering Data Source Templates in mapping.ts

The mappings section is the biggest difference between implementing a static and dynamic data source in our subgraph. We will first go over the static mapping file for the direct democracy token factory. It’s important to note again that in this example the PerpetualOrganization entity has already been made. This mapping function creates new entities and populates existing entities with new info in the same way as a classic subgraph.

However, we also import the tokenTemplate from our generated templates and call the create function passing in the new token address. This signals that we are initializing a new data source based on the template we defined earlier. A common issue with Data Source Templates is errors with duplicate names. To counter this, I imported my DirectDemocracyToken template as tokenTemplate. This step isn’t required, but it may fix unknown errors.

import { TokenCreated } from "../generated/DirectDemocracyTokenFactory/DirectDemocracyTokenFactory";
import { DDToken, PerpetualOrganization } from "../generated/schema";
import { tokenTemplate } from "../generated/templates";
import { log } from "@graphprotocol/graph-ts";
export function handleTokenCreated(event: TokenCreated): void {
log.info("Triggered handleTokenCreated", []);
// Create and save the new DDToken entity
let newToken = new DDToken(event.params.tokenAddress.toHex());
newToken.tokenAddress = event.params.tokenAddress;
newToken.name = event.params.name;
newToken.symbol = event.params.symbol;
newToken.POname = event.params.POname;
newToken.save();
// Update the associated PerpetualOrganization entity if it exists
let po = PerpetualOrganization.load(event.params.POname);
if (po != null) {
po.DirectDemocracyToken = event.params.tokenAddress.toHex();
po.save();
}
// Create a new instance of the token template
tokenTemplate.create(event.params.tokenAddress);
}
ddTokenFactoryMapping.ts

Now, we implement the handler for the new DirectDemocracyToken so we can properly create new entities based on events from the newly created contract. Nothing extra is needed in this mapping file for the entity to be created and updated properly, as long as the template is defined properly in the subgraph.yaml.

import { log } from "@graphprotocol/graph-ts";
import { Mint as MintEvent } from "../../generated/templates/DirectDemocracyToken/DirectDemocracyToken";
import { DDTokenMintEvent, DDToken } from "../../generated/schema";
export function handleTokenMint(event: MintEvent): void {
log.info("Triggered handleTokenMint", []);
// Load the corresponding DDToken entity
let token = DDToken.load(event.address.toHex());
if (token == null) {
// Return if token not found
log.error("DDToken not found: {}", [event.address.toHex()]);
return;
}
// Create and save a new DDTokenMintEvent entity
let entity = new DDTokenMintEvent(
event.transaction.hash.toHex() + "-" + event.logIndex.toString()
);
entity.to = event.params.to;
entity.token = event.address.toHex();
entity.amount = event.params.amount;
entity.save();
}
ddTokenMint.ts

After we implement our templates mapping functions, we have successfully made our first subgraph leveraging Data Source Templates!

Conclusion

We’ve seen how Data Source Templates can significantly enhance the process of tracking newly deployed contracts in our subgraph, using Poa's DAO deployment as a practical example. We've explored how these templates streamline the management of dynamic contract environments, offering a scalable solution for maintaining accurate and cohesive data from new contracts.

This demonstrates the potential of Data Source Templates as a key tool for developers and especially for protocol engineers working with The Graph, allowing for seamless integration and reduced maintenance overhead.

To see Data Source Templates in action and learn more about how Poa utilizes them to power its platform, check out the Poa repository and our website to explore how this innovative approach can benefit our own projects.

About Poa

Poa, the Perpetual Organization Architect, is a no-code DAO builder designed to empower communities by putting control in the hands of contributors, not capital. With Poa, organizations can distribute voting power through active participation, using an on-chain task manager combined with custom voting methods instead of traditional token sales. This ensures that governance is driven by those who are truly invested in the community’s success. Whether you’re forming a student organization, a grassroots advocacy group, or a worker-owned cooperative, Poa provides the tools to build and manage innovative, people-first governance structures that prioritize community ownership and collaboration.

About The Graph

The Graph is the source of data and information for the decentralized internet. As the original decentralized data marketplace that introduced and standardized subgraphs, The Graph has become web3’s method of indexing and accessing blockchain data. Since its launch in 2018, tens of thousands of developers have built subgraphs for dapps across 90+ blockchains - including  Ethereum, Solana, Arbitrum, Optimism, Base, Polygon, Celo, Fantom, Gnosis, and Avalanche.

As demand for data in web3 continues to grow, The Graph enters a New Era with a more expansive vision including new data services and query languages, ensuring the decentralized protocol can serve any use case - now and into the future.

Discover more about how The Graph is shaping the future of decentralized physical infrastructure networks (DePIN) and stay connected with the community. Follow The Graph on X, LinkedIn, Instagram, Facebook, Reddit, Farcaster and Medium. Join the community on The Graph’s Telegram, join technical discussions on The Graph’s Discord.

The Graph Foundation oversees The Graph Network. The Graph Foundation is overseen by the Technical Council. Edge & Node, StreamingFast, Semiotic Labs, Messari, GraphOps, Pinax and Geo are eight of the many organizations within The Graph ecosystem.


Categories
RecommendedDeveloper Corner
Published
December 23, 2024

Hudson Headley

View all blog posts