Indexes Snapshot Pro ("turbo") payments and exposes them over GraphQL. Two
payment paths feed the same Payment / Space tables, so billing and turbo
enforcement don't care where the money came from:
- Onchain (EVM) — the
Schnapscontract on Ethereum (Sepolia for testnet). - Stripe — card subscriptions for Snapshot Pro.
Both run on @snapshot-labs/checkpoint.
Each indexer is a config + writers pair registered with checkpoint.addIndexer
(see src/index.ts). The config's sources[].events map an event to a writer
fn; checkpoint validates every fn against the indexer's handlers and calls it
per matching event.
- EVM (
src/config.ts,src/writers.ts) — the built-inevm.EvmIndexermatches contract logs tohandlePaymentReceived, which writes thePaymentand extendsSpace.turbo_expiration. - Stripe (
src/stripe/) — same shape.config.tsdeclares the sources (charge→indexPayment,refund→refundPayment,customer.subscription.deleted→cancelSubscription);writers.tsexports them viacreateStripeWriters. Stripe has no blocks, soindexer.tsmaps each 1h window to a "block" and polls the durable Stripe resources (charges, refunds, events) for that window — no webhook, and replay stays correct on every boot. A charge grants/extends turbo, a full refund removes the period, a cancellation only notifies (the paid period stands).
Payments and expirations are announced to Discord. A background monitor
(src/expirationMonitor.ts) posts spaces that are expiring or recently expired.
POST /stripe/create—{ space, plan, success_url, cancel_url }→ a Stripe Checkout URL (planismonthlyoryearly).GET /stripe/portal— the Stripe Customer Portal login URL./— the GraphQL API for indexed payments and spaces.
yarn # install
yarn codegen # generate models from src/schema.gql
yarn dev # watch mode (runs codegen first)yarn build compiles to dist/, yarn start runs it. Requires a PostgreSQL
database (DATABASE_URL); the DB is reset and replayed on every boot.
Copy .env.example to .env:
DATABASE_URL— PostgreSQL connection string (required).STRIPE_SECRET_KEY— enables the Stripe indexer and endpoints; omit to disable.DISCORD_WEBHOOK_URL— payment notifications.DISCORD_EXPIRATION_WEBHOOK_URL— expiration monitor notifications.ADMIN_ADDRESS— address whose zero-amount payments set expiration directly.INDEX_TESTNET— index Sepolia instead of Ethereum.