Migrate a Graph Protocol subgraph
Run the create-ponder
CLI tool
pnpm create ponder
Enter a project name, then select the Subgraph ID template option and paste in your subgraph's deployment ID:
MakerDAO's subgraph (opens in a new tab) on the Graph Protocol's hosted service.
The newly generated Ponder app will use your subgraph's schema.graphql
as well as the addresses, ABIs, and start blocks for each event source defined in subgraph.yaml
.
The tool will then create a project directory, install dependencies, and initialize a git repository.
Start the development server
Just like Next.js and Vite, Ponder has a development server that automatically reloads when you save changes in any project file. It also prints console.log
statements and errors encountered while running your code.
First, cd
into your project directory, then start the server.
pnpm dev
Add an RPC URL
Ponder fetches data using the standard Ethereum RPC API. To get started, you'll need an RPC URL from a provider like Alchemy or Infura.
Open up .env.local
and paste in RPC URLs for any networks that your project uses:
PONDER_RPC_URL_1 = "https://eth-mainnet.g.alchemy.com/v2/..."
Write event handler functions
Open an event handler file in the src/
directory. Ponder event handler functions are very similar to subgraph mapping functions, with some key differences. You will need to refactor your code, but because the local dev server has hot reloading, you'll get instant feedback on your changes.
See tips for migrating mapping functions for more details.
Query the GraphQL API
As you migrate your event handlers and start inserting entity data, open the GraphiQL interface at http://localhost:42069/graphql
to explore your GraphQL API locally. Any changes you make to your schema.graphql
file will be reflected here.
Tips for migrating mapping functions
Handlers run in Node.js, not WebAssembly
You can import NPM packages, debug with console.log
, and use normal JavaScript types like string
and number
.
Entities & contracts are injected, not imported
In a Graph Protocol subgraph mapping file, entity models and contract factories are imported:
import { Token, Wallet } from "../generated/schema";
import { MyNftContract } from "../generated/MyNftContract/MyNftContract";
export function handleTransfer(event) {
// Get an entity object
const token = Token.load(event.params.id);
// Bind and call a contract
const tokenUri = MyNftContract.bind("0x137...01a2").tokenUri(token.id);
// ...
}
With Ponder, entity models and contracts are injected as properties of context
.
The contract.contracts
objects are viem Contract Instances (opens in a new tab) that are already connected to the network specified in ponder.config.ts
. (You don't need to call Contract.bind(address)
.
import { ponder } from "@/generated";
ponder.on("MyNftContract:Transfer", async ({ event, context }) => {
const { Token } = context.entities;
const { MyNftContract } = context.contracts;
// Get an entity object
const token = await Token.findUnique({ id: event.params.id });
// Call a contract read function
const tokenUri = await MyNftContract.read.tokenUri(token.id);
// ...
});