Resolves #25 - [Backend] feat: Implement Soroban Event Listener
Listen to smart contract events in real-time from the ProductionEscrowContract and RegistryContract.
This PR implements a robust Soroban event listener service that connects to Soroban RPC and subscribes to smart contract events in real-time. The implementation ensures no events are missed during runtime and logs all incoming events.
File: server/src/indexer/soroban-event-listener.service.ts
Key Features:
- Real-time event streaming from Soroban RPC using HTTP polling
- Connection to both ProductionEscrowContract and RegistryContract
- Automatic reconnection with exponential backoff on failure
- Event cursor tracking to prevent missing events
- Comprehensive error handling and logging
- Graceful shutdown handling
Technical Implementation:
- Uses HTTP polling with
getEventsRPC method since Soroban doesn't support WebSocket streaming - Polls every 5 seconds (configurable)
- Tracks last processed ledger to ensure no gaps
- Implements retry logic with exponential backoff (max 5 attempts)
- Processes events by type with dedicated handlers
File: server/src/indexer/types/soroban-events.types.ts
Defines TypeScript interfaces for:
- ProductionEscrow events: CampaignCreated, ContribReceived, CampaignFunded, TrancheReleased, TranchesConfigured, HarvestReported, CampaignFailed, ReturnClaimed, DisputeOpened, DisputeResolved, RefundClaimed, CampaignSettled
- Registry events: AdminInitialized, AdminUpdated, ContractApproved, ContractRevoked, FarmerRegistered, CampaignRegistered, CampaignStatusUpdated, ActivityRecorded
- Event response structures matching Soroban RPC format
File: server/src/indexer/handlers/event-handler.service.ts
Implements:
- Dedicated handlers for each event type
- Event data parsing and validation
- Structured logging for all events
- Extension points for future database persistence
File: server/src/indexer/indexer.module.ts
Sets up:
- NestJS module with proper dependency injection
- Service lifecycle management
- Integration with ConfigModule for environment variables
File: server/.env.example
New environment variables:
# Soroban RPC Configuration
SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
SOROBAN_NETWORK_PASSPHRASE=Test SDF Network ; September 2015
PRODUCTION_ESCROW_CONTRACT_ID=
REGISTRY_CONTRACT_ID=
EVENT_POLL_INTERVAL_MS=5000
EVENT_START_LEDGER=
File: server/src/app.module.ts
Updates:
- Import IndexerModule into AppModule
- Service auto-starts on application bootstrap
- Proper shutdown hooks for graceful termination
- CampaignCreated - When a new campaign is created
- ContribReceived - When a contribution is made
- CampaignFunded - When campaign reaches funding goal
- TranchesConfigured - When tranches are set up
- TrancheReleased - When funds are released to farmer
- HarvestReported - When harvest outcome is reported
- DisputeOpened - When a dispute is initiated
- DisputeResolved - When a dispute is resolved
- RefundClaimed - When investor claims refund
- ReturnClaimed - When investor claims returns
- CampaignSettled - When campaign is settled
- CampaignFailed - When campaign is marked as failed
- AdminInitialized - When admin is set
- AdminUpdated - When admin is changed
- ContractApproved - When a contract is approved
- ContractRevoked - When a contract is revoked
- FarmerRegistered - When a farmer registers
- CampaignRegistered - When a campaign is registered in registry
- CampaignStatusUpdated - When campaign status changes
- ActivityRecorded - When activity is recorded
Soroban RPC currently only supports HTTP JSON-RPC methods. The getEvents method is designed for polling-based event retrieval. The implementation:
- Polls at configurable intervals (default 5 seconds)
- Uses cursor-based pagination to track progress
- Implements efficient filtering by contract ID
- Handles rate limiting gracefully
- Sequential Processing: Events are processed in order to maintain consistency
- Idempotent Handlers: Event handlers can be safely re-executed
- Cursor Tracking: Prevents duplicate event processing
- Error Isolation: Individual event processing errors don't stop the stream
- No Missed Events: Cursor-based tracking ensures continuous event stream
- Automatic Recovery: Exponential backoff retry on connection failures
- Health Monitoring: Service status exposed for monitoring
- Graceful Shutdown: Proper cleanup on application termination
- Deploy contracts to Stellar testnet
- Configure environment variables with contract IDs
- Start the server
- Trigger contract events through transactions
- Verify events are logged correctly
- Test connection to Soroban RPC
- Test event parsing for all event types
- Test reconnection logic
- Test cursor tracking and pagination
- Test graceful shutdown
No new dependencies required! The implementation uses:
- Native Node.js
httpsmodule for HTTP requests - Existing NestJS infrastructure
- Built-in logging via Pino (already configured)
- Memory Efficient: Processes events in streaming fashion
- CPU Efficient: Polling interval is configurable to balance latency vs load
- Network Efficient: Filters events by contract ID at RPC level
- Scalable: Stateless design allows horizontal scaling with shared cursor store
- RPC URL validation
- Input sanitization for event data
- No credential exposure in logs
- Rate limiting awareness
- Error message sanitization
- Events are received in real-time (5-second polling interval)
- No missed events during runtime (cursor-based tracking)
- Event listener service implemented
- Logs incoming events (structured JSON logging)
- Subscribes to ProductionEscrowContract events
- Subscribes to RegistryContract events
- Handles event stream reliably
- Proper error handling and reconnection
- Set environment variables in
.env:
SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
SOROBAN_NETWORK_PASSPHRASE="Test SDF Network ; September 2015"
PRODUCTION_ESCROW_CONTRACT_ID=<your_contract_id>
REGISTRY_CONTRACT_ID=<your_contract_id>
EVENT_POLL_INTERVAL_MS=5000- Start the server:
npm run dev- Monitor logs for event activity:
tail -f logs/app.log | grep "Event received"- Database persistence for events
- WebSocket broadcast to connected clients
- Event replay functionality
- Metrics and monitoring dashboard
- Historical event backfill
- Multi-network support (mainnet/testnet)
- Stellar Soroban Events Documentation
- Soroban RPC getEvents Method
- GrantFox Official Website
- GrantFox Documentation
Contributor: Georgechisom
Email: georgechipaul@gmail.com
Branch: feat/soroban-event-listener
- Code follows project style guidelines
- All events are properly typed
- Error handling is comprehensive
- Logging is structured and meaningful
- Environment variables are documented
- No secrets or credentials in code
- Service integrates with existing architecture
- Graceful shutdown implemented
- Code is well-commented
- README updated if necessary
This implementation provides a production-ready event listener that meets all GrantFox criteria for reliability and real-time event processing. The polling-based approach is the current best practice for Soroban event monitoring until native event streaming is available.
The service is designed to be extended easily - handlers can be modified to persist events to a database, trigger workflows, or broadcast to connected clients without changing the core listener logic.
Ready for Review | Issue #25 | Backend Feature