Skip to main content

Architecture Overview

Code Structure

The watch-tower project is organized as follows:
src/
├── commands/          # CLI command implementations
├── domain/            # Business logic and domain models
│   ├── events/        # Event processing
│   └── polling/       # Order polling and filtering
├── services/          # External service integrations
├── types/             # TypeScript type definitions
│   └── generated/     # Auto-generated contract types
└── utils/             # Utility functions and helpers

Main 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 ConditionalOrderCreated events
    • Indexes new conditional orders in registry
    • Processes events atomically per block

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 operation
  • dumpDb.ts: Database inspection utility

Domain (src/domain/)

Contains core business logic:
  • events/: Event processing logic
  • polling/: Order polling and placement
    • poll.ts: Main polling loop
    • filtering/: 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 types
  • types.d.ts: Global type declarations

Utils (src/utils/)

Shared utilities:
  • logging.ts: Logging configuration
  • metrics.ts: Prometheus metrics
  • contracts.ts: Contract helper functions
  • context.ts: Execution context utilities

Execution Context

The watch-tower uses a context pattern for dependency management:
interface ExecutionContext {
  registry: Registry;          // State management
  notificationsEnabled: boolean;
  slack?: Slack;               // Optional notifications
  storage: DBService;          // Database access
}

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
Last modified on March 4, 2026