Code structure
The watch-tower codebase is organized into several key directories:Main execution flow
The watch-tower follows this execution flow:1. Initialization
- Entry point:
src/index.ts - Parses CLI arguments using Commander.js
- Validates configuration against JSON schema
- Initializes logging system
2. Command execution
- Run command:
src/commands/run.ts- Opens database connection
- Starts REST API server (unless disabled)
- Initializes chain contexts for each configured network
- Sets up signal handlers for graceful shutdown
3. Chain monitoring
- Chain context:
src/services/chain.ts- Creates provider connection (WebSocket or HTTP)
- Loads registry from database
- Warms up by syncing historical blocks
- Subscribes to new blocks
4. Event processing
- Event handling:
src/domain/events/- Monitors for
ConditionalOrderCreatedevents - Indexes new conditional orders in registry
- Processes events atomically per block
- Monitors for
5. Order polling
- Polling logic:
src/domain/polling/- Checks each registered conditional order
- Determines if discrete orders should be created
- Filters orders based on configured policies
- Posts valid orders to OrderBook API
6. Persistence
- Storage:
src/services/storage.ts- Writes registry state to LevelDB
- Tracks last processed block
- Maintains ACID guarantees via atomic batching
Key modules
Commands (src/commands/)
Implements CLI commands:
run.ts: Main watch-tower operationdumpDb.ts: Database inspection utility
Domain (src/domain/)
Contains core business logic:
events/: Event processing logicpolling/: Order polling and placementpoll.ts: Main polling loopfiltering/: Order filtering policies
Services (src/services/)
External service integrations:
api.ts: REST API server (Express)chain.ts: Blockchain interaction (ethers.js)storage.ts: Database operations (LevelDB)
Types (src/types/)
Type definitions:
model.ts: Domain models (Registry, ConditionalOrder)generated/: TypeChain-generated contract typestypes.d.ts: Global type declarations
Utils (src/utils/)
Shared utilities:
logging.ts: Logging configurationmetrics.ts: Prometheus metricscontracts.ts: Contract helper functionscontext.ts: Execution context utilities
Execution context
The watch-tower uses a context pattern to pass dependencies:Concurrency model
- Single-threaded: Node.js event loop
- Async/await: For I/O operations
- Block-level sequencing: Processes blocks in order
- Event batching: Groups events within blocks
- Atomic writes: Database operations batched per block
Error handling
- Graceful degradation: Continues on non-critical errors
- Block retry: Re-processes blocks on error
- Exit on critical failure: Database write failures
- Watchdog timer: Monitors block processing health