Envio-powered blockchain indexer for the Floor Markets DeFi platform. Indexes bonding curve markets, credit facilities, presales, staking, and treasury events.
- Envio - High-performance blockchain indexer
- Node.js 18+ - Runtime
- pnpm - Package manager
- Docker - Database infrastructure
- TypeScript - Type-safe handlers
- GraphQL - Query interface
indexer/
├── abis/ # Contract ABIs
├── config.yaml # Envio configuration
├── schema.graphql # GraphQL schema
├── src/
│ ├── index.ts # Handler exports
│ ├── factory-handlers.ts # Factory events
│ ├── market-handlers.ts # Buy/Sell/Floor events
│ ├── credit-handlers.ts # Loan events
│ ├── presale-handlers.ts # Presale events
│ ├── treasury-handlers.ts # Fee distribution events
│ ├── staking-handlers.ts # Staking events
│ ├── authorizer-handlers.ts # Role/permission events
│ ├── rpc-client.ts # Viem RPC client
│ └── helpers/ # Shared utilities
├── generated/ # Auto-generated Envio types
├── test/ # Handler tests
└── scripts/
└── select_rpc.sh # RPC selector script
# Install dependencies
pnpm install
# Start the indexer (interactive RPC selection)
pnpm devVisit http://localhost:8080 to access the GraphQL Playground (password: testing).
| Command | Description |
|---|---|
pnpm dev |
Start indexer in development mode |
pnpm codegen |
Regenerate types from config.yaml/schema.graphql |
pnpm start |
Start indexer in production mode |
pnpm test |
Run handler tests |
pnpm db-up |
Start database containers |
pnpm db-down |
Stop database containers |
pnpm db-setup |
Reset and setup database |
pnpm build |
Compile TypeScript |
pnpm lint |
Lint and fix TypeScript files |
The indexer supports both local and remote RPC endpoints. When running pnpm dev, you'll be prompted to select:
Select RPC source ([l]ocal/[r]emote, default remote):
Alternatively, set environment variables:
# Use local Anvil
RPC_SOURCE=local pnpm dev
# Use remote devnet
RPC_SOURCE=remote pnpm dev
# Override RPC URL directly
RPC_URL_31337=http://127.0.0.1:8545 pnpm dev| Variable | Description | Default |
|---|---|---|
RPC_URL_31337 |
RPC endpoint for network 31337 | Remote devnet URL |
RPC_SOURCE |
local or remote |
remote |
FLOOR_FACTORY |
FloorFactory contract address | From config.yaml |
LOG_LEVEL |
Console log level | trace |
LOG_STRATEGY |
Log format (console-pretty, json) |
console-pretty |
TUI_OFF |
Disable terminal UI for plain logs | true |
Edit config.yaml under the networks section:
networks:
- id: 31337
start_block: 73900000
contracts:
- name: FloorFactory
address: '0x...'
- name: ModuleFactory
address: '0x...'
# Dynamic discovery for remaining contracts
- name: FloorMarket
address:Note: FloorFactory and ModuleFactory require explicit addresses. Other contracts (FloorMarket, CreditFacility, etc.) are discovered dynamically from factory events.
After modifying schema.graphql:
# Regenerate Envio types
pnpm codegen
# Compile GraphQL SDK (from project root)
bun indexer:compileAfter modifying event handlers in src/:
# Restart the indexer
pnpm dev- Add event to contract in
config.yaml - Add handler in appropriate
*-handlers.tsfile - Export handler from
src/index.ts - Run
pnpm codegen
For a fresh re-index from the configured start block:
# Remove persisted state
rm -f generated/persisted_state.envio.json
# Restart database
pnpm db-down && pnpm db-up
# Start indexer
pnpm dev- Market - Bonding curve markets with price, supply, and fee data
- Trade - Buy/sell transactions
- FloorElevation - Floor price increase events
- Loan - Credit facility loans
- Stake - Staking positions
- PresaleParticipation - Presale deposits
- GlobalRegistry - Factory addresses
- ModuleRegistry - Per-market module addresses
- Account - User accounts with positions
- MarketSnapshot - Periodic market state snapshots
- PriceCandle - OHLCV price candles (1h, 4h, 1d)
- GlobalStats / GlobalStatsSnapshot - Platform-wide metrics
Example queries for the GraphQL Playground:
# Get all markets
query Markets {
Market {
id
currentPriceFormatted
floorPriceFormatted
totalSupplyFormatted
status
}
}
# Get recent trades
query RecentTrades {
Trade(order_by: { timestamp: desc }, limit: 20) {
id
tradeType
tokenAmountFormatted
reserveAmountFormatted
timestamp
}
}
# Get user positions
query UserPositions($userId: ID!) {
UserMarketPosition(where: { user_id: { _eq: $userId } }) {
market_id
netFTokenChangeFormatted
totalDebtFormatted
stakedAmountFormatted
}
}LOG_LEVEL=debug LOG_STRATEGY=console-pretty TUI_OFF=true pnpm devAll handlers log on entry:
context.log.info(`TokensBought handler called: market=${event.srcAddress}`)| Issue | Solution |
|---|---|
| Port 8080 in use | Stop other Docker containers or use pnpm db-down |
| No events indexed | Check contract addresses in config.yaml |
| Stale data | Delete generated/persisted_state.envio.json |
| Handler not called | Verify event is listed in config.yaml and exported from index.ts |