Skip to content

Latest commit

 

History

History
263 lines (211 loc) · 10.4 KB

File metadata and controls

263 lines (211 loc) · 10.4 KB

Velodrome V2 & Aerodrome multi-chain indexer

A multi-chain blockchain indexer for Velodrome V2 (Optimism) and Aerodrome (Base) and their superchain deployments. It ingests on-chain events for pools, gauges, voting, veNFTs, concentrated-liquidity positions, automated liquidity management, pool launchers, and cross-chain swaps, and serves the derived state from a Postgres database.

Built in TypeScript on the Envio HyperIndex platform (v3 alpha).

Note: This is an Envio HyperIndex project — not a TheGraph subgraph.

Table of contents

Supported chains

Networks are defined in config.yaml:

Chain Chain ID Chain Chain ID
Optimism 10 Lisk 1135
Base 8453 Unichain 130
Celo 42220 Fraxtal 252
Soneium 1868 Metal 1750
Ink 57073 Superseed 5330
Mode 34443 Swell 1923

Getting started

Prerequisites

  • Node.js 22+ (see engines in package.json)
  • pnpm 9+
  • Dockerpnpm dev runs Postgres and the Envio runtime in containers

Install

pnpm install

Configure

Copy the example environment file and fill in the values:

cp .env.example .env

.env holds:

  • ENVIO_API_TOKEN — Envio API token
  • ENVIO_PG_MAX_CONNECTIONS — Postgres connection cap (recommended for v3)
  • ENVIO_<CHAIN>_RPC_URL — one RPC URL per chain, used for on-chain reads that fall outside HyperSync (e.g. ENVIO_OPTIMISM_RPC_URL, ENVIO_BASE_RPC_URL)

Run

# 1. Generate types from schema.graphql + config.yaml
#    (MUST be re-run after changing either file)
pnpm envio codegen

# 2a. Spin up Docker containers and start indexing
pnpm dev

# 2b. ...or start the indexer inside an already-running container
pnpm envio start

Stop the indexer:

pnpm envio stop

For headless / CI runs (no terminal UI):

TUI_OFF=true pnpm dev

Testing and QA

tsc --noEmit                          # Type-check (run after any TypeScript change)
pnpm test                             # Full test suite with coverage (Vitest)
pnpm test:file test/path/to/file.ts   # Run a single test file
pnpm test:grep "pattern"              # Run tests matching a name pattern
pnpm qa                               # Lint + format check (Biome); `pnpm qa --write` to apply fixes

Tests live under test/, mirroring the src/ layout (Aggregators/, Effects/, EventHandlers/, Snapshots/).

Architecture

Data flow

config.yaml declares the contracts and events to index per chain → Envio generates types from schema.graphql → handlers in src/EventHandlers/ process events → aggregators in src/Aggregators/ compute derived state → src/Snapshots/ captures hourly snapshots. External reads (RPC/API) are wrapped in Envio's Effect API (src/Effects/) so they stay correct across preload runs.

Repository layout

config.yaml        Contracts, events, and networks indexed per chain
schema.graphql     Entity (database) definitions
abis/              Contract ABIs referenced by config.yaml
src/               Indexer source (see below)
test/              Vitest suites mirroring src/
scripts/           One-off analysis, benchmarking, and doc-generation tooling
docs/              Schema reference (docs/schema.md) and agent workflow docs
generated/         Auto-generated by `pnpm envio codegen` (git-ignored)

src/ layout

Top-level modules:

  • Constants.ts — chain-specific constants, factory addresses, price connectors, RPC client setup, toChecksumAddress(), CHAIN_CONSTANTS
  • Helpers.ts — shared utilities (error handling, USD conversions, concentrated-liquidity position math via the Uniswap v3 SDK)
  • Maths.ts — fixed-point / BigInt math helpers
  • PriceOracle.ts — token price fetching with hourly refresh
  • PriceOverrides.ts — manual price pins and the token blacklist
  • PriceTrust.ts — price-trust gating used by USD valuation
  • PoolPriceRatio.ts — derives token0Price / token1Price from pool state
  • ChainBlockTime.ts — per-chain block-time helpers
  • CustomTypes.ts / EntityTypes.ts — shared TypeScript types

Subdirectories:

  • EventHandlers/ — handler registrations and business logic. Top-level files (e.g. Pool.ts, CLPool.ts) register handlers; domain subdirectories hold the logic (Pool/, CLPool/, Gauges/, Voter/, VotingReward/, VeNFT/, NFPM/, ALM/, PoolLauncher/, SwapFeeModule/, SuperswapsHyperlane/, Redistributor/, CLFactory/, CLGaugeFactory/)
  • Aggregators/ — derived-entity computation. Pool.ts is the central aggregator (TVL, volume, fees, votes, emissions); others cover UserStatsPerPool, NonFungiblePosition, VeNFTState, VeNFTPoolVote, ALMLPWrapper, CLStakedLiquidity, OUSDTSwaps
  • Snapshots/ — hourly snapshot creation for aggregated entities, with epoch-alignment logic in Shared.ts
  • Effects/ — external calls (RPC/API) behind Envio's Effect API. RpcGateway.ts handles multi-chain RPC; Token.ts, SwapFee.ts, Bytecode.ts, RootPool.ts, Voter.ts wrap specific reads
  • constants/ — static reference data (whitelisted-token lists, price connectors, stablecoins)

Indexed contract domains

  • Pools — V2 AMM (Pool) and concentrated liquidity (CLPool)
  • FactoriesPoolFactory, CLFactory, RootCLPoolFactory, FactoryRegistry
  • GaugesGauge (V2) and CLGauge (CL), plus CLGaugeFactoryV2/V3
  • VotingVoter, SuperchainLeafVoter, and the fee/bribe/incentive VotingReward contracts (FeesVotingReward, BribesVotingReward, SuperchainIncentiveVotingReward)
  • veNFT — vote-escrowed NFT tracking (deposits, withdrawals, merges, splits)
  • NFPM — Non-Fungible Position Manager for CL positions
  • ALM — Automated Liquidity Management (ALMDeployFactoryV1/V2, ALMCore, ALMLPWrapperV1/V2)
  • Pool launchersCLPoolLauncher, V2PoolLauncher
  • Swap-fee modulesDynamicSwapFeeModule, CustomSwapFeeModule, UnstakedFeeModule, CustomUnstakedFeeModule
  • Superswaps / Hyperlane — cross-chain swap tracking (VelodromeUniversalRouter, Mailbox)
  • Redistributor

Data model

The database schema is defined in schema.graphql (39 entity types). The full, field-by-field reference — types, nullability, indexes, and descriptions for every field — is in docs/schema.md, which is generated from the schema by scripts/generate-schema-docs.ts (pnpm tsx scripts/generate-schema-docs.ts to regenerate).

Consumers who want to query the data rather than build the indexer should start with docs/querying.md, the consumer's guide to the GraphQL API, the value-scaling rules, and example queries.

Conventions

  • Entity IDs are deterministic strings: pools {chainId}-{poolAddress}, tokens {chainId}-{tokenAddress}, snapshots {entityId}-{epochMs}. Each entity's exact id format is documented on its id field.
  • BigInt fields are fixed-point integers (no JS float precision loss). Divide by the token's decimals for token amounts, or by 10^18 for USD/WAD-scaled values.
  • Snapshots are hourly, epoch-aligned copies of a "latest-state" aggregate, enabling historical / time-series queries (PoolSnapshot, UserStatsPerPoolSnapshot, …).
  • @index marks fields that are efficient to filter on; @derivedFrom marks reverse-relation fields that are computed, not stored.
  • Addresses are stored checksummed (toChecksumAddress() from src/Constants.ts).

Entities by category

Conventions

  • Linting/formatting uses Biome (not Prettier/ESLint) — space indentation, double quotes, organized imports. Run pnpm qa before committing.
  • See CLAUDE.md for the full set of Envio-specific patterns (immutable entity updates, the Effect API, dynamically registered contracts, amount normalization) and file-naming conventions.

Documentation