A framework for building blockchain-enabled web services

Overview

NOTE: Not ready for public use. Please reach out via twitter dm or email with any questions.

Ponder

A framework for building blockchain-enabled web services

Features

  • Support for ~80% of Graph Protocol subgraph features
  • Event handlers run in Node.js (import packages, send HTTP requests, etc)
  • Local development server with hot reloading
  • Support for any EVM-based blockchain (just need an RPC URL)

Quickstart

I'm replacing a Graph Protocol subgraph

1. Run npx create-ponder-app

Include the --from-subgraph option to bootstrap using an existing Graph Protocol subgraph.

npx create-ponder-app path/to/ponder-app --from-subgraph path/to/subgraph

2. Start the development server

cd path/to/ponder-app
npm run dev

The dev server process will print logs to help you handle any configuration issues or errors.

3. Add event sources

The ponder.config.js file defines the event sources (EVM smart contracts) that Ponder will index. You can include contracts across multiple chains. You can also use any environment variables defined in .env.local.

4. Write event handler functions

The handlers/ directory contains a file for each source defined in ponder.config.js. The index.ts file must export an object that maps event names to event handler functions.

Event handler files run in Node.js (not WebAssembly), so you can import NPM packages, send HTTP requests, and so on. While migrating your handlers from AssemblyScript to Typescript, you should consider updating your schema.graphql to use String instead of Bytes, and Int instead of BigInt (in some cases).

Event handler functions receive two arguments - event and context. The event object contains params, block, transaction, and other useful log fields. The context object contains a small ORM-style object for each entity defined in your schema.graphql. Use these entity objects to insert, and update the entities that will be served via GraphQL, just like in your subgraph.

That's it! The development server should reload and reindex whenever you save changes in any project file. Keep an eye on the dev server process and handle any errors that appear.

I'm starting a new project

Coming soon!

Deploying to production

Ponder apps can be deployed on any cloud provider that offers a Node.js web service runtime.

Render

Coming soon!

Railway

Coming soon!

Docs

Project files

1. ponder.config.js

This file contains contract addresses, paths to ABIs, and RPC URLs for each of your sources. It is analogous to a subgraph's subgraph.yaml file.

2. schema.graphql

This file works exactly like a subgraph's schema.graphql. It supports the @entity and @derivedFrom("field") directives.

3. handlers/

This directory contains your event handler functions. Ponder uses these functions to process blockchain events. Event handlers can create and update Entities, which are served by the autogenerated GraphQL API.

4. abis/

This directory contains the ABIs for your contracts. You can download these files from Etherscan, or (more likely) generate them from a local smart contract development tool like Hardhat or Foundry.

5. generated/

This gitignored directory stores autogenerated Typescript types for your handler files to import. It also contains the final schema that is served by the GraphQL API.

6. .ponder/

This gitignored directory stores ponder's internal cache store and the compiled handler code. You shouldn't need to worry about it, but if you delete it, ponder will need to refetch any cached logs from the RPC.

Packages

  • @ponder/ponder
  • create-ponder-app

About

Goals

  • Be the best tool for building blockchain app backends
  • Work seamlessly alongside best-in-class frameworks like Foundry and Next.js

Non-goals

  • Efficiently index massive amounts of data
  • Serve analytics queries/workloads
Comments
  • Improve backfill progress ui

    Improve backfill progress ui

    This PR improvers the ponder dev progress bars and ETA calculations. Fixes #18. Also updates the Ponder class to use a type-safe event emitter and renames those events.

    opened by 0xOlias 1
  • Improve dev server error handling

    Improve dev server error handling

    Changes:

    • Create notSoFastQueue which doesn't hog the event loop quite as much as fastq, and use that for the log handler queue
    • Refactors some of the database code to fix a bug where better-sqlite3 errors would cause the process to exit instead of getting caught by the user error handler
    • Capture esbuild errors + stack traces and send to user error handler
    opened by 0xOlias 1
  • Fix `create-ponder` cli logs

    Fix `create-ponder` cli logs

    When create-ponder runs ponder codegen, it should not print the configuration error (due to the RPC).

    Couple ways to handle this:

    • Silence logs while running ponder codegen
    • Refactor the config error handling thing (i don't really like it...)
    • Update ponder codegen so it somehow doesn't run the config validations
    opened by 0xOlias 1
  • Fix handler error catching

    Fix handler error catching

    When an error occurs while running a user handler, the development server should catch the error, stop processing logs, and display the error in the terminal UI. Then, on the next hot reload, Ponder should clear the error and begin processing logs again.

    I'm not exactly sure how to do this. Also, the stack trace almost always points to some weird yoga prebuilt thing instead of the actual line with the error. Some errors will originate downstream of user code, like in the entity store (SQLite/Postgres).

    opened by 0xOlias 1
  • Initialize `stats` in `LogQueue` to avoid silent crash

    Initialize `stats` in `LogQueue` to avoid silent crash

    Currently the logWorker is silently crashing. This is happening because the stats.sourceStats[source.name] object is uninitialized. When trying to access a field of this undefined object the worker silently fails

    opened by cjpais 1
  • Improve `ponder dev` UI

    Improve `ponder dev` UI

    The current UI for ponder dev displays the backfill progress, and the log handler progress. It's confusing and not intuitive. "Dev mode" only makes this worse. The handler progress bar should not say "up to date" unless the backfill is also complete.

    Ideas

    • Remove the backfill progress bar entirely
    • Remove the log handler progress bar if its complete
    • Change "up to date" to "up to {lastLogProcessedTimestamp}"
    • Change 31/31 to 31/???
    opened by 0xOlias 0
  • tests!

    tests!

    Changes:

    • Create a test dir in packages/core and add a basic test
    • Add two options to the ponder CLI
      • rootDir?: string -> path to the root directory of the Ponder project to be ran
      • configFile?: string -> path to the config file to be used
    • Change how the Ponder class is configured (to make testing a bit more ergonomic)
    • Move some shared async logic into the Ponder.setup() method (migrating the stores, loading handlers) and load the schema in the constructor

    Minor changes / notes:

    • Fix examples to use latest public APIs
    • Replace commander dep with cac
    • Fix backfill ETA bug
    • Make some of the Ponder methods private
    opened by 0xOlias 0
  • Use `abitype` to add autocomplete for contract methods

    Use `abitype` to add autocomplete for contract methods

    Within event handler functions, the context.contracts object contains an ethers.Contract for each source defined in ponder.config.js. These contracts can be used to make contract calls within event handler functions. These contract objects are connected to a special provider that caches contract calls to reduce the number of RPC requests that need to be made while syncing your project.

    While running event handler functions, the ponder runtime injects an ethers.Contract object for each contract defined in ponder.config.js. Originally, I used typechain to generate TypeScript types for these contract objects. Typechain proved to be a bit slow and bulky. The abitype library seems to offer an alternative that avoids generating lots of files. We already have every contracts abi as a JSON file, so it should be easy to use abitype to type these contract objects.

    opened by 0xOlias 0
  • update cache metadata after fetching live logs/blocks/txs

    update cache metadata after fetching live logs/blocks/txs

    the cache metadata gets updated when the historical sync is complete. however, when fetching "live" logs/blocks/txns, they get added to the cache but the metadata never gets updated.

    so, when the app rebuilds, it fetches all logs/blocks/txns since the end of the last historical sync despite the fact that the cache store already has all of the data.

    this might require a slight remodel for how the cache metadata table(s). worth doing some research on this.

    opened by 0xOlias 0
  • consider package separation

    consider package separation

    it might make sense to move graphql and sqlite to separate packages. these packages could be imported and "plugged in" to the @ponder/core package that contains the core indexing code (and probably also the CLI and dev server?).

    this would make it easier to write tests against the indexer.

    also, separating out the graphql bits as a plugin would make it easier to allow users to customize the Express server that backs the GraphQL API (add authn, logging, etc).

    likewise on the database side. i'm sure many users will prefer to use postgres for GP-like experience.

    opened by 0xOlias 0
  • Proxy contracts are not well-supported

    Proxy contracts are not well-supported

    basically, if you have an proxy contract that upgrades its implementation, that basically means its ABI changes over time. a user ran into a bug where the ABI provided for the proxy included only the "latest" implementation contract ABI, and when ponder tried to decode events emitted by an earlier implementation contract, those events weren't found in the new ABI, so ponder threw an error.

    it seems like the easiest workaround is to merge the ABIs of all implementation contracts that have ever existing for this proxy. another solution would be to add a source to ponder.config.js for each version of the proxy, and use startBlock and endBlock (NOTE: endBlock doesn't currently exist).

    opened by 0xOlias 0
  • Ponder fetches & indexes more logs than necessary

    Ponder fetches & indexes more logs than necessary

    This issue has two related parts.

    1. Ponder currently fetches all events emitted by contracts included in ponder.config.js, regardless of which events the user has provided handlers for. We could significantly reduce the backfill load for certain projects by lazily fetching event data, e.g. only fetch events for handlers the user has provided. Example: I want to index the ownership changes (OwnershipTransferred) for an ERC20 contract without indexing every Transfer event.

    2. Ponder currently adds all events available for a contract to the indexing queue, regardless of which events the user has provided handlers for. In the indexing task function, if a handler is not found for the given event log, it just does nothing and returns early. Instead, when adding logs to the indexing queue, we could filter to only include logs for events that the user has provided handlers for.

    Part 2 is much easier to implement than part 1. The parts can be implemented independently.

    opened by 0xOlias 0
  • Redeploys cause downtime in production

    Redeploys cause downtime in production

    When using a cloud platform that uses git deployments (like Render or Railway), a new deployment will be created for each new commit. Then, once the new deployment is deemed healthy by the platform (by responding to the health check path with a 2XX), the platform will start serving traffic to the new deployment and then shut down the old deployment. Cloud platforms normally will wait between 5 and 15 minutes for a healthy response, after which they will consider the deployment failed and shut it down.

    Ponder currently sends a healthy response as soon as the GraphQL server starts up, which happens immediately on ponder start. This is problematic because the backfill (and/or the handler processing) will not NOT be done yet, so the entity tables are not up-to-date but the service is saying its healthy.

    Solution (for now):

    • If the backfill + indexing will take >4 minutes (not sure what heuristic to use for this yet), enter a "backfilling" state, where the service responds as healthy, but requests to /graphql respond with an error message describing that the backfill is in progress.
    • If the backfill + indexing will take <4 minutes, enter a "reloading" state, where the service does not respond as healthy until the backfill + indexing are complete. This should enable zero downtime deploys for deployments after the first one.

    The reason to use ~4 minutes as the cutoff is to play nice with the common cloud platform behavior of giving new deployments ~5 minutes to become healthy.

    Drawbacks with this approach:

    • I'm not sure what heuristic to use to estimate the backfill + indexing time.
    • If a user makes a change to an existing service that adds a large backfilling load (such as adding a new contract to ponder.config.js), the service will enter the "backfilling" state and the production server will stop responding to requests.
    opened by 0xOlias 0
  • GraphQL `{field}_in: string[]` filter throws SQLite error

    GraphQL `{field}_in: string[]` filter throws SQLite error

    Pseudo example:

    // schema
    type Terraform @entity {
      mode: String!
    }
    
    // query
    {
      terraforms (where: { mode_in: ["Daydream", "Origin Daydream"] }) {
        id
      }
    }
    

    Throws the error Handler error: SqliteError: no such column: Daydream when resolving the query.

    opened by 0xOlias 0
  • update Entity methods & instance types to use `ethers.BigNumber` for `BigInt` scalar fields

    update Entity methods & instance types to use `ethers.BigNumber` for `BigInt` scalar fields

    improves experience of writing handler functions because it matches with types coming from ethers event log params. goal is to avoid needing to use BigNumber.from(...) and BigNumber.toString() everywhere

    opened by 0xOlias 0
Owner
Olias
web engineer
Olias
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Calculates maximum composite SLA for a list of sequentially provided cloud services or your custom-defined services.

SlaMax Calculates maximum composite SLA for a list of sequentially provided cloud services or your custom-defined services. Here are a few use-cases y

Mikael Vesavuori 4 Sep 19, 2022
This repository demonstrates how to integrate your Dialogflow agent with 3rd-party services services using a Node.JS backend service

This repository demonstrates how to integrate your Dialogflow agent with 3rd-party services services using a Node.JS backend service. Integrating your service allows you to take actions based on end-user expressions and send dynamic responses back to the end-user.

ddayto 10 Jul 21, 2022
HackMIT 2022. 2nd Place in Blockchain for Society sponsored by Jump Crypto. A revolutionary web application that leverages machine learning and blockchain technology to improve the crowdsourcing experience!

?? Wikisafe ?? Wikisafe is a revolutionary new crowdsourcing web application that innovates the process of crowdsourcing information. This application

Benson Liu 5 Dec 8, 2022
It is a very basic implementation of how blockchain works, mainly how the bitcoin blockchain.

How to run this program npm install node core/blockchain.js What is this It is a very basic implementation of how blockchain works, mainly how the bit

Anish Jain 12 May 9, 2022
Spiner bot to buy and sell tokens on ETH and ERC compatible chains as soon as liquidity is added and trade is enabled.

An open-source defi sniper. open-sniper is free to download. Premium Services Now Available While open-sniper is free and open-source, if you want the

spacemonk 4 Apr 21, 2022
On-chain query batcher for CosmWasm-enabled chains

multiquery On-chain query batcher for CosmWasm. Similar to SCB 10X's multicall contract, but supports any serializable query request, not limited to W

null 7 Dec 6, 2022
Ethereum chain sniperbot for tokens. This bot sniffs the mempool for pending transactions for trading enabled and also liquidity add functions.

Ethereum chain sniperbot for tokens. This bot sniffs the mempool for pending transactions for trading enabled and also liquidity add functions.

null 12 Dec 5, 2022
Digitally enabled cafe for students to order drinks, socialize, and study hard.

Coffee Shop Full Stack Full Stack Nano - IAM Final Project Udacity has decided to open a new digitally enabled cafe for students to order drinks, soci

Samuel Nzubechi Chukwuma 25 Nov 20, 2022
Touch enabled selectable plugin inspired by the jQuery UI widget.

Inspired by the jQuery UI Selectable plugin. Functionality and options are identical to the jQuery UI version with some additions and performance enha

Karl 135 Nov 24, 2022
Responsive, CSS3, touch-enabled jQuery Coverflow plugin.

jQuery.Flipster Flipster is a CSS3 3D transform-based jQuery plugin built to replicate the familiar 'cover flow' effect, but also supports a variety o

Adrien Delessert 704 Dec 28, 2022
infiniteScrollWithTemplate - JQuery plugin for ajax-enabled infinite page scroll / auto paging with template

jQuery Infinite With Template Plugin JQuery plugin for ajax-enabled infinite page scroll with template. If you like jQuery until now, this little libr

이삼구 2 Mar 19, 2021
Chat app using Azure Web PubSub, Static Web Apps and other Azure services

Chatr - Azure Web PubSub Sample App This is a demonstration & sample application designed to be a simple multi-user web based chat system. It provides

Ben Coleman 55 Dec 31, 2022
A simple implementation example (framework) of Deso Protocol's Smart Services.

This project serves as a simple implementation example (framework) of Deso Protocol's Smart Services. This framework comes with out-of-the-box SSL, MongoDB, dev/stage/prod environments, and modularity.

Hunter Paulson 5 Sep 22, 2022
Smart Territory Framework Core using NEC Scorpio 2.0 and AWS serverless services

Smart Territory Framework Core - STF Core using NEC Scorpio Broker ⚠️ This stack is for demonstration purposes only. The nested stack deploying the NE

AWS Samples 9 Sep 30, 2022
T3 is a client-side JavaScript framework for building large-scale web applications

Box has migrated using react, webpack, and the latest version of ECMAScript for our frontend projects as of 2018. We no longer support chan

Box 1.6k Dec 8, 2022
This project is a web application for a company that provides commercial and scientific space travel services

Space Traveler's Hub This project is a web application for a company that provides commercial and scientific space travel services.

Selma Belhadj 5 Jun 8, 2022
A web application for a company that provides commercial and scientific space travel services. The application will allow users to book rockets and join selected space missions.

Space Travelers A web application for a company that provides commercial and scientific space travel services. The application will allow users to boo

Hector Torres 2 Apr 6, 2022