Skip to content

Commit ecae00f

Browse files
easeevclaude
andcommitted
chainplot: scoped onchain events to a reproducible dataset and dashboard
An agent-first toolkit. A project declares which contracts and events it cares about; chainplot indexes exactly that range, exports it to parquet, runs SQL over it, and builds a static dashboard that needs no server. How it holds together: - Plans are digest-bound. `plan` records the project digest and every job boundary; `apply` refuses a plan whose project changed underneath it, so a run either does what was reviewed or nothing at all. - Coverage is proven rather than assumed. Every ingested range is joined back to block hashes from the chain, and the promotion gate refuses to build a release over a range that cannot be shown complete. - Queries run sandboxed. The DuckDB worker reads its snapshots, then closes external access before any project-supplied SQL executes, and admits only statements that survive `json_serialize_sql` as read-only. - Amounts stay exact. A uint256 travels as a decimal string from parquet to the rendered cell; nothing but chart geometry ever touches a double. - Releases are content-addressed and forkable. `publish` writes a release under a digest of its own content; `fork` reconstructs the project from a published release and recomputes it offline. Three examples cover the surface, one per release mode: a year of USDC supply (1.43M mint/burn events), WETH wrap/unwrap flows, and transfer traffic. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent f924441 commit ecae00f

198 files changed

Lines changed: 22072 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.dockerignore‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
node_modules
2+
dist
3+
coverage
4+
.chainplot
5+
.env
6+
.env.*
7+
!.env.example
8+
.git
9+
scripts
10+
docs
11+
tests

‎.env.example‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Chainplot environment. Copy to .env and fill in. Never commit .env.
2+
# Scope: this file is for developing Chainplot itself (live tests read it).
3+
# For an analytics project, keep its own .env in the project directory —
4+
# the CLI loads .env from the directory you run it in.
5+
# All values stay local; tests and the CLI read them at runtime.
6+
7+
# --- Ingest (M2) ---------------------------------------------------------
8+
# The live suites read RPC_URL (Ethereum mainnet, archive-capable). Postgres
9+
# and rindexer come from compose, so there is no test database URL to set.
10+
# Real analytics projects keep their own .env with per-chain endpoints.
11+
RPC_URL=
12+
13+
# Postgres 16 for the rindexer adapter (compose.yaml provides one).
14+
DATABASE_URL=postgresql://chainplot:chainplot@localhost:5432/chainplot
15+
16+
# --- Publish to S3-compatible storage (M4) -------------------------------
17+
# Example: Cloudflare R2 endpoint (account-specific URL).
18+
CHAINPLOT_S3_ENDPOINT=
19+
CHAINPLOT_S3_BUCKET=
20+
CHAINPLOT_S3_REGION=auto
21+
AWS_ACCESS_KEY_ID=
22+
AWS_SECRET_ACCESS_KEY=
23+
24+
# --- Local overrides (optional) ------------------------------------------
25+
# rindexer binary (default: rindexer on PATH)
26+
# CHAINPLOT_RINDEXER_BIN=

‎.github/workflows/ci.yml‎

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
name: Build & Test
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v7
15+
16+
- uses: pnpm/action-setup@v6
17+
with:
18+
version: 11.24.0
19+
20+
- uses: actions/setup-node@v7
21+
with:
22+
node-version: 22
23+
cache: pnpm
24+
25+
- name: Install dependencies
26+
run: pnpm install --frozen-lockfile
27+
28+
# The viewer is a separate project with its own lockfile. Typecheck it
29+
# explicitly: `vite build` does not, so a type error here would
30+
# otherwise ship in the bundle every release embeds.
31+
- name: Install viewer dependencies
32+
run: pnpm --dir viewer install --frozen-lockfile
33+
34+
- name: Typecheck viewer
35+
run: pnpm --dir viewer run typecheck
36+
37+
- name: Build CLI and viewer
38+
run: pnpm build
39+
40+
- name: Run tests
41+
run: pnpm vitest run
42+
43+
template-smoke:
44+
name: Scaffolded template runs
45+
runs-on: ubuntu-latest
46+
steps:
47+
- uses: actions/checkout@v7
48+
49+
- uses: pnpm/action-setup@v6
50+
with:
51+
version: 11.24.0
52+
53+
- uses: actions/setup-node@v7
54+
with:
55+
node-version: 22
56+
cache: pnpm
57+
58+
- name: Install dependencies
59+
run: |
60+
pnpm install --frozen-lockfile
61+
pnpm --dir viewer install --frozen-lockfile
62+
63+
- name: Build CLI and viewer
64+
run: pnpm build
65+
66+
# The producer image is the CLI plus rindexer, which ships linux/amd64
67+
# only. Every step below is what a user does from the template README;
68+
# each of them was broken at some point and none was covered by a test.
69+
- name: Build the producer image
70+
run: |
71+
docker build --platform linux/amd64 -t chainplot:local \
72+
-f docker/producer.Dockerfile .
73+
74+
- name: Scaffold the template
75+
run: |
76+
node dist/cli/main.js init --template ingest-transfers \
77+
--output "$RUNNER_TEMP/proj" --json
78+
79+
# No RPC is needed to prove the stack comes up and the CLI is reachable.
80+
- name: Bring the stack up and drive the CLI
81+
working-directory: ${{ runner.temp }}/proj
82+
run: |
83+
printf 'RPC_URL=http://127.0.0.1:1\n' > .env
84+
docker compose up -d
85+
docker compose ps
86+
docker compose exec -T producer chainplot capabilities --json
87+
docker compose exec -T producer chainplot validate --json
88+
89+
- name: Tear down
90+
if: always()
91+
working-directory: ${{ runner.temp }}/proj
92+
run: docker compose down -v

‎.gitignore‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
node_modules/
2+
/dist/
3+
examples/**/dist/
4+
.chainplot/
5+
.worktrees/
6+
.superpowers/
7+
.env
8+
.env.*
9+
!.env.example
10+
*.log
11+
.DS_Store
12+
coverage/
13+
.pnpm-store/
14+
.vitest/
15+
viewer/node_modules
16+
# Built from viewer/src by `pnpm build`; committing it lets the two drift.
17+
viewer/dist/

‎LICENSE‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Chainstack Labs
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

‎NOTICES.md‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Upstream notices
2+
3+
Chainplot is MIT-licensed (see `LICENSE`). It bundles or depends on the
4+
following upstream software at runtime; their licenses govern those
5+
components, not the datasets you publish.
6+
7+
| Component | License | Use |
8+
|---|---|---|
9+
| [rindexer](https://github.com/joshstevens19/rindexer) | MIT (pinned binary from the upstream image) | EVM event indexing |
10+
| [DuckDB](https://duckdb.org) via `@duckdb/node-api` | MIT | Snapshot queries and Parquet export |
11+
| [React](https://react.dev) | MIT | Viewer |
12+
| [ECharts](https://echarts.apache.org) | Apache-2.0 | Viewer charts |
13+
| [AWS SDK for JavaScript v3](https://github.com/aws/aws-sdk-js-v3) | Apache-2.0 | S3-compatible publish |
14+
| [pg](https://github.com/brianc/node-postgres) | MIT | Advisory lock, coverage cursor reads |
15+
| [ajv](https://github.com/ajv-validator/ajv), [yaml](https://github.com/eemeli/yaml), [commander](https://github.com/tj/commander.js), [Vite](https://vitejs.dev) | MIT | Schema validation, YAML, CLI, viewer build |
16+
17+
## Dataset licenses are separate
18+
19+
The software license (MIT) does not cover the data you publish. Every publish
20+
target requires an explicit `dataset_license` field; it is recorded with the
21+
release. Choose and document the license that applies to your dataset.

0 commit comments

Comments
 (0)