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.
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 |
- Node.js 22+ (see
enginesinpackage.json) - pnpm 9+
- Docker —
pnpm devruns Postgres and the Envio runtime in containers
pnpm installCopy the example environment file and fill in the values:
cp .env.example .env.env holds:
ENVIO_API_TOKEN— Envio API tokenENVIO_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)
# 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 startStop the indexer:
pnpm envio stopFor headless / CI runs (no terminal UI):
TUI_OFF=true pnpm devtsc --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 fixesTests live under test/, mirroring the src/ layout
(Aggregators/, Effects/, EventHandlers/, Snapshots/).
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.
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)
Top-level modules:
Constants.ts— chain-specific constants, factory addresses, price connectors, RPC client setup,toChecksumAddress(),CHAIN_CONSTANTSHelpers.ts— shared utilities (error handling, USD conversions, concentrated-liquidity position math via the Uniswap v3 SDK)Maths.ts— fixed-point / BigInt math helpersPriceOracle.ts— token price fetching with hourly refreshPriceOverrides.ts— manual price pins and the token blacklistPriceTrust.ts— price-trust gating used by USD valuationPoolPriceRatio.ts— derivestoken0Price/token1Pricefrom pool stateChainBlockTime.ts— per-chain block-time helpersCustomTypes.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.tsis the central aggregator (TVL, volume, fees, votes, emissions); others coverUserStatsPerPool,NonFungiblePosition,VeNFTState,VeNFTPoolVote,ALMLPWrapper,CLStakedLiquidity,OUSDTSwapsSnapshots/— hourly snapshot creation for aggregated entities, with epoch-alignment logic inShared.tsEffects/— external calls (RPC/API) behind Envio's Effect API.RpcGateway.tshandles multi-chain RPC;Token.ts,SwapFee.ts,Bytecode.ts,RootPool.ts,Voter.tswrap specific readsconstants/— static reference data (whitelisted-token lists, price connectors, stablecoins)
- Pools — V2 AMM (
Pool) and concentrated liquidity (CLPool) - Factories —
PoolFactory,CLFactory,RootCLPoolFactory,FactoryRegistry - Gauges —
Gauge(V2) andCLGauge(CL), plusCLGaugeFactoryV2/V3 - Voting —
Voter,SuperchainLeafVoter, and the fee/bribe/incentiveVotingRewardcontracts (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 launchers —
CLPoolLauncher,V2PoolLauncher - Swap-fee modules —
DynamicSwapFeeModule,CustomSwapFeeModule,UnstakedFeeModule,CustomUnstakedFeeModule - Superswaps / Hyperlane — cross-chain swap tracking
(
VelodromeUniversalRouter,Mailbox) - Redistributor
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.
- Entity IDs are deterministic strings: pools
{chainId}-{poolAddress}, tokens{chainId}-{tokenAddress}, snapshots{entityId}-{epochMs}. Each entity's exactidformat is documented on itsidfield. BigIntfields are fixed-point integers (no JS float precision loss). Divide by the token'sdecimalsfor token amounts, or by10^18for USD/WAD-scaled values.- Snapshots are hourly, epoch-aligned copies of a "latest-state" aggregate,
enabling historical / time-series queries (
PoolSnapshot,UserStatsPerPoolSnapshot, …). @indexmarks fields that are efficient to filter on;@derivedFrommarks reverse-relation fields that are computed, not stored.- Addresses are stored checksummed (
toChecksumAddress()fromsrc/Constants.ts).
- Core aggregates — latest-state, headline metrics:
Pool,Token,UserStatsPerPool,NonFungiblePosition,VeNFTState,VeNFTPoolVote,ALM_LP_Wrapper - Snapshots — hourly historical copies of the core aggregates (full list)
- Config & registry — chain-wide config and cross-chain mapping tables (full list)
- Pool launcher — emerging-token pools (full list)
- Cross-chain superswaps (Hyperlane) — oUSDT-bridged swaps and their dispatch/process correlation (full list)
- Internal buffers & deferred state — short-lived bookkeeping entities that correlate events across log indices/blocks; mostly deleted once consumed (full list)
- Linting/formatting uses Biome (not Prettier/ESLint)
— space indentation, double quotes, organized imports. Run
pnpm qabefore committing. - See
CLAUDE.mdfor the full set of Envio-specific patterns (immutable entity updates, the Effect API, dynamically registered contracts, amount normalization) and file-naming conventions.
- Envio HyperIndex docs
- Event handlers
- Dynamic contracts
docs/querying.md— consumer's guide: querying the GraphQL API, value scaling, and example queriesdocs/schema.md— complete entity & field referenceCLAUDE.md— in-repo architecture and contributor guidedocs/agents/— issue-tracker, triage-label, and domain workflow docs