Skip to content

Latest commit

 

History

History
267 lines (187 loc) · 8.71 KB

File metadata and controls

267 lines (187 loc) · 8.71 KB

Pull Request: Soroban Event Listener Implementation

Issue Reference

Resolves #25 - [Backend] feat: Implement Soroban Event Listener

Objective

Listen to smart contract events in real-time from the ProductionEscrowContract and RegistryContract.

Summary of Changes

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.

Implementation Details

1. Core Event Listener Service

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 getEvents RPC 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

2. Event Types and Interfaces

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

3. Event Handlers

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

4. Module Configuration

File: server/src/indexer/indexer.module.ts

Sets up:

  • NestJS module with proper dependency injection
  • Service lifecycle management
  • Integration with ConfigModule for environment variables

5. Environment Configuration

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=

6. Integration with Main Application

File: server/src/app.module.ts

Updates:

  • Import IndexerModule into AppModule
  • Service auto-starts on application bootstrap
  • Proper shutdown hooks for graceful termination

Contract Events Monitored

ProductionEscrowContract Events:

  1. CampaignCreated - When a new campaign is created
  2. ContribReceived - When a contribution is made
  3. CampaignFunded - When campaign reaches funding goal
  4. TranchesConfigured - When tranches are set up
  5. TrancheReleased - When funds are released to farmer
  6. HarvestReported - When harvest outcome is reported
  7. DisputeOpened - When a dispute is initiated
  8. DisputeResolved - When a dispute is resolved
  9. RefundClaimed - When investor claims refund
  10. ReturnClaimed - When investor claims returns
  11. CampaignSettled - When campaign is settled
  12. CampaignFailed - When campaign is marked as failed

RegistryContract Events:

  1. AdminInitialized - When admin is set
  2. AdminUpdated - When admin is changed
  3. ContractApproved - When a contract is approved
  4. ContractRevoked - When a contract is revoked
  5. FarmerRegistered - When a farmer registers
  6. CampaignRegistered - When a campaign is registered in registry
  7. CampaignStatusUpdated - When campaign status changes
  8. ActivityRecorded - When activity is recorded

Architecture Decisions

Why HTTP Polling Instead of WebSocket?

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

Event Processing Strategy

  • 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

Reliability Measures

  1. No Missed Events: Cursor-based tracking ensures continuous event stream
  2. Automatic Recovery: Exponential backoff retry on connection failures
  3. Health Monitoring: Service status exposed for monitoring
  4. Graceful Shutdown: Proper cleanup on application termination

Testing Strategy

Manual Testing:

  1. Deploy contracts to Stellar testnet
  2. Configure environment variables with contract IDs
  3. Start the server
  4. Trigger contract events through transactions
  5. Verify events are logged correctly

Integration Testing:

  • Test connection to Soroban RPC
  • Test event parsing for all event types
  • Test reconnection logic
  • Test cursor tracking and pagination
  • Test graceful shutdown

Dependencies Added

No new dependencies required! The implementation uses:

  • Native Node.js https module for HTTP requests
  • Existing NestJS infrastructure
  • Built-in logging via Pino (already configured)

Performance Considerations

  • 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

Security Considerations

  • RPC URL validation
  • Input sanitization for event data
  • No credential exposure in logs
  • Rate limiting awareness
  • Error message sanitization

Acceptance Criteria Met

  • 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

Deployment Instructions

  1. 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
  1. Start the server:
npm run dev
  1. Monitor logs for event activity:
tail -f logs/app.log | grep "Event received"

Future Enhancements

  • Database persistence for events
  • WebSocket broadcast to connected clients
  • Event replay functionality
  • Metrics and monitoring dashboard
  • Historical event backfill
  • Multi-network support (mainnet/testnet)

References

Author

Contributor: Georgechisom
Email: georgechipaul@gmail.com
Branch: feat/soroban-event-listener

Review Checklist

  • 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

Notes for Reviewers

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