{"id":30614582,"url":"https://github.com/morpho-org/pandvil","last_synced_at":"2025-08-30T07:15:42.010Z","repository":{"id":307926529,"uuid":"1026280413","full_name":"morpho-org/pandvil","owner":"morpho-org","description":"Testing infrastructure for Ponder apps","archived":false,"fork":false,"pushed_at":"2025-08-19T05:52:38.000Z","size":166,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-19T07:20:49.091Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/morpho-org.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-07-25T15:58:43.000Z","updated_at":"2025-08-19T05:52:17.000Z","dependencies_parsed_at":null,"dependency_job_id":"5248210d-6f6a-49ff-b4a0-a989518ca6d4","html_url":"https://github.com/morpho-org/pandvil","commit_stats":null,"previous_names":["morpho-org/pandvil"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/morpho-org/pandvil","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/morpho-org%2Fpandvil","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/morpho-org%2Fpandvil/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/morpho-org%2Fpandvil/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/morpho-org%2Fpandvil/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/morpho-org","download_url":"https://codeload.github.com/morpho-org/pandvil/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/morpho-org%2Fpandvil/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272817705,"owners_count":24998038,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-30T02:00:09.474Z","response_time":77,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-08-30T07:15:39.564Z","updated_at":"2025-08-30T07:15:42.001Z","avatar_url":"https://github.com/morpho-org.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Pandvil\n\nA testing infrastructure for Ponder applications that combines:\n\n- **Neon**: Ephemeral database branches\n- **Anvil**: Local blockchain forks for testing\n- **Ponder**: Blockchain indexing framework\n\n## Overview\n\nPandvil provides a Docker-based testing environment that:\n\n1. Creates an ephemeral Neon database branch for test isolation\n2. Spins up Anvil instances that fork each indexed chain at the latest indexed block\n3. Launches Ponder instances pointing at the local Anvil forks\n4. Prevents block finalization to allow multiple Ponder instances on the same database\n\n## Install\n\nWe haven't set up NPM yet, but you can download from GitHub like so:\n\n```bash\n# Replace v0.0.13 with whatever version you want\npnpm add -D https://github.com/morpho-org/pandvil/releases/download/v0.0.13/package.tgz\n```\n\n## Setup\n\n### Prerequisites\n\n- Docker\n- Neon account with API access\n- Environment variables:\n  - `NEON_API_KEY`: Your Neon API key for branch management (obtainable through Neon's web app)\n  - `NEON_PROJECT_ID`: Your Neon project ID\n  - `PONDER_RPC_URL_*`: RPC URLs for each chain you want to fork\n- Ponder app with a `ponder.config.ts` where:\n  - RPCs are of the form `PONDER_RPC_URL_*`\n  - `database: { kind: \"postgres\" }` (`connectionString` should be left unspecified)\n\n### Dockerfile\n\nPandvil's server runs in a Docker container, so your Ponder app needs to as well.\nYour Dockerfile should install/build your Ponder app in the `/workspace` directory\nsuch that `pnpm ponder start` would run successfully.\n\nFor most setups, you can use something like [this](./Dockerfile), or go even simpler\nif you don't care about Docker build speed and caching.\n\n### Building\n\n```bash\npnpm pandvil build \\\n  --name your-ponder-app-name \\\n  --ponder-app relative/path/where/ponder/should/run\n\n# For argument documentation:\npnpm pandvil build --help\n```\n\n### Running\n\n```bash\n\u003c\u003cDOC\nRun the Pandvil dev server for your app\n\nOptions:\n  --name \u003cname\u003e                The ponder app name\n  --parent-branch \u003cname\u003e       The name of the Neon branch to fork off of\n  --spawn \u003cN\u003e | \u003cname\u003e         Spawn N instances on startup (if integer), or spawn 1 instance of a given name (if string)\n  --prepare \u003cN\u003e                Spawn N instances and wait for backfill, preserving branch on exit for future use\n  --preserve-ephemeral-branch  Tells the server not to delete its Neon branch on shutdown\n  --preserve-schemas           Tells the server not to delete schemas when killing instances\n  --ponder-log-level \u003clevel\u003e   \"debug\" | \"trace\" | \"error\" | \"warn\" | \"info\" (default: \"warn\")\n  --anvil-interval-mining \u003cs\u003e  \"off\" or an integer indicating seconds per block\n  --port \u003cport\u003e                Port to connect to Pandvil dev server (default: \"3999\")\nDOC\n\npnpm pandvil run \\\n  --name your-ponder-app-name\n  --parent-branch some-neon-branch\n\n# Output (example):\nStarting Pandvil container...\n❇︎ Image: pandvil/curator-api:latest\n❇︎ Port: 3999\n\n🟩 Neon:\n ═╣ production\n  ╙─☑︎ production-pandvil-branch-name-123 (branch-id-456)\n\n⛓️ Chains:\n[\n  {\n    chainId: 8453,\n    blockNumber: 33169119,\n    rpcUrl: 'https://base-mainnet.g.alchemy.com/v2/key_789'\n  }\n]\n```\n\n\u003e [!TIP]\n\u003e Run `pandvil` in a directory with your `.env` or `.env.local` to automatically inject\n\u003e environment variables into the container.\n\n\u003e [!TIP]\n\u003e Use the following recipe for quick, repeatable tests against a specific block number:\n\u003e\n\u003e 1. Trim your main branch (fully synced) back to a specific block:  \n\u003e ```\n\u003e pnpm pandvil trim --parent-branch production --name your-ci-branch --block-numbers 8453:33730000\n\u003e ```\n\u003e 2. Take the load off your CI by backfilling in advance:\n\u003e ```\n\u003e pnpm pandvil run --name your-ponder-app-name --parent-branch your-ci-branch --prepare 10\n\u003e # This prepares 10 instances, but you can prepare more depending on how many independent tests you plan to run!\n\u003e ```\n\u003e 3. Use the Neon web app to rename the ephemeral branch to something meaningful, like your-ci-branch-bootstrap\n\u003e 4. Run your CI!\n\u003e ```\n\u003e pnpm pandvil run --name your-ponder-app-name --parent-branch your-ci-branch-bootstrap\n\u003e ```\n\n### Connecting Interactively\n\nThe server should only take a few seconds to start. Once it's up, POST to `/spawn` with `{ id: \"frontend\" }`.\nThe resulting URLs are deterministic:\n\n- `\"http://localhost:3999/proxy/frontend/rpc/:chainId/\"`\n- `\"http://localhost:3999/proxy/frontend/ponder/\"`\n\nRun your frontend dev server, create a new Chrome profile, and configure [enkrypt](https://www.enkrypt.com/)\n(in my testing this has been more amenable to altered RPCs than Rabby, which falls back to public ones too readily):\n\n- Seed: \"test test test test test test test test test test test junk\"\n- Custom RPC: http://localhost:3999/proxy/frontend/rpc/:chainId\n\nThe first wallet associated with that seed is funded by anvil automatically.\n\n\u003e [!IMPORTANT]\n\u003e After hitting `/spawn`, it'll take ~2 minutes for ponder to return 200's from its `/ready` endpoint.\n\u003e You can use it before that (e.g., playing with schema in GraphQL playground) but it won't have data.\n\n## API\n\nThe Pandvil server exposes the following endpoints:\n\n### `POST /spawn`\n\nCreates a new Ponder instance using its own set of new Anvil forks.\n\nRequest body:\n\n```json\n{\n  \"id\": \"optional-custom-id\"\n}\n```\n\nResponse:\n\n```json\n{\n  \"id\": \"abc123\",\n  \"rpcUrls\": {\n    \"1\": \"http://localhost:3999/proxy/abc123/rpc/1/\"\n  },\n  \"apiUrl\": \"http://localhost:3999/proxy/abc123/ponder/\",\n  \"status\": \"starting\"\n}\n```\n\n### `GET /instance/:id`\n\nGet the status of a Pandvil instance. The response is the same as above.\n\n### `DELETE /instance/:id`\n\nKill a Pandvil instance and clean up its database schema.\n\n### `POST /proxy/:id/ponder/*` and `POST /proxy/:id/rpc/:chainId/*`\n\nProxy requests to specific Ponder/anvil instances.\n\n## Architecture\n\n1. **Docker Container**: Provides isolated environment with all dependencies\n2. **Ephemeral Neon Branches**: Each run gets its own database branch\n3. **Anvil Instances**: Local blockchain forks with high `slotsInAnEpoch` to prevent finalization\n4. **Ponder Instances**: Each gets a unique schema in the run's database branch\n5. **Management Server**: Controls lifecycle of instances\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmorpho-org%2Fpandvil","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmorpho-org%2Fpandvil","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmorpho-org%2Fpandvil/lists"}