Migrate a Graph Protocol subgraph

Migrate a Graph Protocol subgraph

The create-ponder CLI tool makes it easy to migrate a subgraph to Ponder.

Run the create-ponder CLI tool

This command creates a project folder called ponder in the current working directory. Include the --from-subgraph option with a path to a Graph Protocol subgraph repo on your local machine.

pnpm create ponder --from-subgraph <path>

Start the development server

The dev server is an important part of the Ponder development workflow. Just like Next.js, the dev server automatically reloads when you save changes in any project file. It also prints console.log statements and errors encountered while running your code.

cd ponder
pnpm dev

Add an RPC URL

Ponder fetches data using the 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 your RPC URL:

.env.local
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:

mapping.ts (Graph Protocol)
import { Token, Wallet } from "../generated/schema";
import { SomeNftContract } from "../generated/SomeNftContract/SomeNftContract";
 
export function handleTransfer(event) {
  // Get an entity object
  const token = Token.load(event.params.id);
 
  // Bind and call a contract
  const tokenUri = SomeNftContract.bind("0x137...01a2").tokenUri(token.id);
 
  // ...
}

With Ponder, entity models and contracts are injected as properties of context.

Contracts injected this way are ready-to-go using the address and network specified in ponder.config.ts. (You don't need to call Contract.bind(address). The contracts are normal ethers.Contract objects that are already connected to a provider.

src/SomeNftContract.ts
import { ponder } from "../generated";
 
ponder.on("SomeNftContract:Transfer", async ({ event, context }) => {
  const { Token } = context.entities;
  const { SomeNftContract } = context.contracts;
 
  // Get an entity object
  const token = await Token.get(event.params.id);
 
  // Call a contract read function
  const tokenUri = await SomeNftContract.tokenUri(token.id);
 
  // ...
});
Last updated on February 8, 2023