Skip to content

feat: Implement Contract Event Indexer for Soroban Events - #91

Merged
Wilfred007 merged 4 commits into
Protocol-Guild:mainfrom
meshackyaro:contract-event-indexer
Mar 6, 2026
Merged

feat: Implement Contract Event Indexer for Soroban Events#91
Wilfred007 merged 4 commits into
Protocol-Guild:mainfrom
meshackyaro:contract-event-indexer

Conversation

@meshackyaro

Copy link
Copy Markdown
Contributor

Overview

This PR implements a production-ready contract event indexer that streams Soroban contract events from the Stellar RPC and persists them to PostgreSQL, providing a reliable, queryable audit trail for the frontend.

Closes #78

Implementation Summary

✅ All Acceptance Criteria Met

  • Background worker polls or streams contract events from the Soroban RPC
  • Events stored in contract_events table with contract_id, event_type, payload, and ledger_sequence
  • REST endpoint GET /api/events/:contractId returns paginated events
  • Duplicate events idempotently skipped on re-indexing
  • Worker restarts gracefully from the last indexed ledger sequence on crash

Key Features

  • Background Service: Polls Soroban RPC every 10 seconds for new contract events
  • Multi-Contract Support: Indexes events from bulk_payment, vesting_escrow, and revenue_split contracts
  • Idempotent Processing: Automatic duplicate detection via unique constraints
  • Graceful Recovery: Resumes from last indexed ledger on restart/crash
  • REST API: Three endpoints with pagination and filtering
  • Organization Isolation: Multi-tenant support with JWT authentication
  • Comprehensive Testing: Full test coverage for service and controller
  • Production Ready: Error handling, logging, monitoring, and documentation

Files Changed (15 files, 2,484+ lines)

Core Implementation

  • src/services/contractEventIndexer.ts (306 lines) - Background indexer service
  • src/controllers/contractEventController.ts (200 lines) - REST API controller
  • src/routes/contractEventRoutes.ts (56 lines) - Express routes
  • src/types/contractEvent.ts (63 lines) - TypeScript types
  • src/db/migrations/016_create_contract_events.sql (50 lines) - Database schema

Tests

  • src/services/__tests__/contractEventIndexer.test.ts (229 lines)
  • src/controllers/__tests__/contractEventController.test.ts (228 lines)

Documentation

  • CONTRACT_EVENT_INDEXER.md (288 lines) - Complete technical documentation
  • CONTRACT_EVENT_INDEXER_QUICKSTART.md (177 lines) - Quick start guide
  • CONTRACT_EVENT_INDEXER_ARCHITECTURE.md (358 lines) - Architecture diagrams
  • IMPLEMENTATION_SUMMARY.md (200 lines) - Implementation overview
  • PR_CHECKLIST.md (312 lines) - Review checklist

Integration

  • Updated src/app.ts - Added route registration
  • Updated src/index.ts - Added indexer initialization and shutdown
  • Updated .env.example - Added configuration variables

API Endpoints

1. Get Events by Contract

GET /api/events/:contractId?page=1&limit=20&eventType=payment&fromLedger=100&toLedger=200

2. Get All Events

GET /api/events?page=1&limit=20

3. Get Indexer Status

GET /api/events/indexer/status

Database Schema

contract_events Table

  • id - Serial primary key
  • organization_id - Foreign key to organizations
  • contract_id - Stellar contract address (VARCHAR 56)
  • event_type - Event type extracted from topics (VARCHAR 100)
  • payload - Full event data (JSONB)
  • ledger_sequence - Blockchain ledger number (BIGINT)
  • transaction_hash - Transaction hash (VARCHAR 64)
  • event_index - Event index within transaction (INTEGER)
  • ledger_closed_at - Blockchain timestamp
  • indexed_at - Indexing timestamp
  • Unique constraint: (contract_id, transaction_hash, event_index)

indexer_state Table

  • Tracks last indexed ledger for graceful recovery
  • Records indexer status (active, paused, error)
  • Stores error messages for debugging

Configuration

Add to .env:

SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
BULK_PAYMENT_CONTRACT_ID=CXXX...
VESTING_ESCROW_CONTRACT_ID=CXXX...
REVENUE_SPLIT_CONTRACT_ID=CXXX...

Testing

Run tests:

npm test -- contractEventIndexer
npm test -- contractEventController

Deployment Steps

  1. Set environment variables in .env
  2. Run migration: npm run migrate
  3. Start server: npm run dev
  4. Verify indexer status: GET /api/events/indexer/status

Technical Highlights

  • Idempotent: ON CONFLICT DO NOTHING prevents duplicates
  • Transactional: All operations wrapped in database transactions
  • Performant: 6 indexes for efficient querying, JSONB with GIN index
  • Scalable: Configurable batch size and polling interval
  • Observable: Comprehensive logging with structured messages
  • Resilient: Graceful error handling and recovery

Documentation

Complete documentation provided:

  • Technical documentation with API reference
  • Quick start guide for setup
  • Architecture diagrams and data flow
  • Implementation summary
  • PR review checklist

Breaking Changes

None. This is a new feature with no impact on existing functionality.

Checklist

  • Code follows project conventions
  • Tests added and passing
  • Documentation complete
  • No TypeScript errors
  • Database migration included
  • Environment variables documented
  • Graceful shutdown implemented
  • Error handling comprehensive
  • Security considerations addressed

Screenshots/Examples

See CONTRACT_EVENT_INDEXER_QUICKSTART.md for API examples and testing instructions.

Related Issues

Closes #78

- Add background service to poll Soroban RPC for contract events
- Create contract_events and indexer_state database tables
- Implement REST API endpoints for querying indexed events
- Add idempotent event processing with duplicate detection
- Support graceful recovery from last indexed ledger
- Include comprehensive tests and documentation

Acceptance criteria met:
✓ Background worker polls/streams contract events from Soroban RPC
✓ Events stored in contract_events table with all required fields
✓ REST endpoint GET /api/events/:contractId returns paginated events
✓ Duplicate events idempotently skipped on re-indexing
✓ Worker restarts gracefully from last indexed ledger on crash
@Wilfred007
Wilfred007 merged commit 8bca159 into Protocol-Guild:main Mar 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

#077: Backend Contract Event Indexer

2 participants