A real-time blockchain indexer for TeachLink Soroban smart contracts built with NestJS and Stellar Horizon API.
The TeachLink Indexer monitors the Stellar blockchain for TeachLink contract events and indexes them into a PostgreSQL database, enabling efficient querying and analytics of on-chain data.
- Real-time Event Monitoring: Continuously streams events from Stellar Horizon API
- Comprehensive Event Coverage: Indexes all 18+ TeachLink contract event types
- Persistent State: Tracks indexing progress with automatic resume capability
- Historical Backfill: Support for indexing historical blockchain data
- Health Monitoring: Built-in health checks and error tracking
- Type-Safe: Full TypeScript implementation with comprehensive type definitions
- Well-Tested: Extensive unit and integration test coverage
- Production-Ready: Docker support with multi-stage builds
1. Horizon Service (horizon.service.ts)
- Interfaces with Stellar Horizon API
- Streams real-time blockchain operations
- Fetches historical ledger data
- Parses Soroban contract events
2. Event Processor (event-processor.service.ts)
- Processes 18+ event types from TeachLink contracts
- Transforms blockchain events into database entities
- Handles event-specific business logic
3. Indexer Service (indexer.service.ts)
- Orchestrates the indexing process
- Manages indexer lifecycle and state
- Implements health checks and error recovery
- Supports historical data backfill
- TypeORM entities for all contract data types
- PostgreSQL for persistent storage
- Indexed columns for optimized queries
Bridge Events:
- DepositEvent
- ReleaseEvent
- BridgeInitiatedEvent
- BridgeCompletedEvent
Reward Events:
- RewardIssuedEvent
- RewardClaimedEvent
- RewardPoolFundedEvent
Escrow Events:
- EscrowCreatedEvent
- EscrowApprovedEvent
- EscrowReleasedEvent
- EscrowRefundedEvent
- EscrowDisputedEvent
- EscrowResolvedEvent
Tokenization Events:
- ContentMintedEvent
- OwnershipTransferredEvent
- ProvenanceRecordedEvent
- MetadataUpdatedEvent
Scoring Events:
- CreditScoreUpdatedEvent
- CourseCompletedEvent
- ContributionRecordedEvent
Backup and DR Events:
- BackupCreatedEvent
- BackupVerifiedEvent
- RecoveryExecutedEvent
- Node.js 20+
- PostgreSQL 16+
- Docker & Docker Compose (optional)
- Clone the repository:
cd indexer- Install dependencies:
npm install- Configure environment:
cp .env.example .env
# Edit .env with your configuration- Set up the database:
# Create PostgreSQL database
createdb teachlink_indexer
# Run migrations (auto-sync enabled in development)
npm run start:dev- Configure environment:
cp .env.example .env
# Edit .env with your configuration- Start services:
# Development mode
docker-compose up indexer
# Production mode
docker-compose --profile production up indexer-prodConfigure the indexer via environment variables in .env:
STELLAR_NETWORK: Network to use (testnet, mainnet)HORIZON_URL: Horizon API endpointSOROBAN_RPC_URL: Soroban RPC endpoint
TEACHLINK_CONTRACT_ID: TeachLink contract address
DB_TYPE: Database type (postgres)DB_HOST: Database hostDB_PORT: Database portDB_USERNAME: Database usernameDB_PASSWORD: Database passwordDB_DATABASE: Database nameDB_SYNCHRONIZE: Auto-sync schema (true for dev, false for prod)DB_LOGGING: Enable SQL logging
INDEXER_POLL_INTERVAL: Polling interval in ms (default: 5000)INDEXER_START_LEDGER: Starting ledger (latest or specific number)INDEXER_BATCH_SIZE: Batch size for backfill (default: 100)
# Start in development mode with hot reload
npm run start:dev
# Run tests
npm run test
# Run integration tests
npm run test:e2e
# Generate test coverage
npm run test:cov
# Lint code
npm run lint
# Format code
npm run format# Build the application
npm run build
# Start in production mode
npm run start:prod# Development
docker-compose up indexer
# Production
docker-compose --profile production up indexer-prod
# View logs
docker-compose logs -f indexer
# Stop services
docker-compose downbridge_transactions: Cross-chain bridge operationsrewards: Reward issuance and claimsescrows: Multi-signature escrow recordscontent_tokens: Educational content NFTsprovenance_records: Token ownership historycredit_scores: User credit scorescourse_completions: Course completion recordscontributions: User contribution trackingreward_pool: Reward pool stateindexer_state: Indexer progress tracking
All tables include proper indexes for efficient querying.
The indexer exposes the following programmatic interfaces:
// Get current indexer status
const status = await indexerService.getStatus();
// Backfill historical data
await indexerService.backfillHistoricalData(startLedger, endLedger);
// Start/stop indexing
await indexerService.startIndexing();
await indexerService.stopIndexing();GET /backup/manifestsGET /backup/verificationsGET /backup/integrity-metricsGET /backup/recoveriesGET /backup/rto-metricsGET /backup/audit-trail
npm run testTest coverage includes:
- Horizon service event streaming
- Event processor for all event types
- Indexer service lifecycle
- Database entity operations
npm run test:e2eIntegration tests verify:
- End-to-end indexing flow
- Database schema creation
- Service initialization
npm run test:covBaseline observability is now included for the production compose stack.
Endpoints exposed by the application:
GET /health: structured readiness with database, Horizon, and indexer-state freshness checksGET /metrics: Prometheus metricsGET /metrics/json: lightweight JSON snapshot for quick inspection
The compose stack can also start:
- Prometheus
- Alertmanager
- Grafana
- PostgreSQL Exporter
- Blackbox Exporter
- a local webhook sink for alert delivery testing
Quick start:
docker compose --profile production --profile observability up -dFull setup, dashboards, alert list, validation steps, and the alert test procedure are documented in MONITORING.md.
- Check database connection:
psql -h localhost -U teachlink -d teachlink_indexer- Verify contract ID is set:
echo $TEACHLINK_CONTRACT_ID- Check Horizon API connectivity:
curl https://horizon-testnet.stellar.org- Check indexer status:
const status = await indexerService.getStatus();
console.log(status);- Backfill missing ledgers:
await indexerService.backfillHistoricalData(startLedger, endLedger);- Increase batch size:
INDEXER_BATCH_SIZE=200-
Add database indexes (already configured)
-
Scale horizontally with multiple indexers (advanced)
indexer/
├── src/
│ ├── config/ # Configuration
│ ├── database/ # Database entities & module
│ │ └── entities/ # TypeORM entities
│ ├── events/ # Event processing
│ │ └── event-types/ # Event type definitions
│ ├── horizon/ # Horizon API integration
│ ├── indexer/ # Main indexer service
│ ├── app.module.ts # Root module
│ └── main.ts # Application entry point
├── test/ # Integration tests
├── docker-compose.yml # Docker services
├── Dockerfile # Multi-stage build
└── package.json # Dependencies & scripts
- Define event type in src/events/event-types/
- Create database entity in src/database/entities/
- Add event handler in event-processor.service.ts
- Write tests
- Fork the repository
- Create a feature branch
- Make your changes
- Write/update tests
- Run linting and tests
- Submit a pull request
MIT
For issues and questions:
- Create an issue in the repository
- Check existing documentation
- Review test files for usage examples