app.ts
Overview
`app.ts` is the main entry point for the ShapeShift Gnosis API server application. It sets up an Express-based HTTP server integrated with WebSocket support for real-time blockchain event handling. The file configures REST API routes, middleware, metrics collection, Swagger API documentation, and the essential blockchain data processing pipelines for Gnosis chain transactions and blocks.
The primary functionality includes:
Serving HTTP endpoints for health checks, metrics, and API documentation.
Establishing WebSocket connections to an external blockchain indexer.
Processing incoming blockchain blocks and transactions to extract relevant information.
Integrating with a registry to manage blockchain event handlers (blocks & transactions).
Emitting metrics via Prometheus for monitoring.
Handling errors and unmatched routes gracefully.
This file acts as the orchestrator connecting network, API, blockchain event processing, and monitoring layers for the Gnosis blockchain stack.
Classes, Functions, and Key Elements
1. Express Application Setup
const app = express()
Creates an Express server instance.
Applies common middleware (logging, metrics, request parsing).
Defines routes for health checks, metrics (
/metrics), static files, Swagger UI (/docs), and API endpoints (registered dynamically).Redirects root
/to/docs.Adds error and "not found" handlers.
2. Prometheus Metrics Instance
const prometheus = new Prometheus({ coinstack: 'gnosis' })
Initializes Prometheus client instance scoped to the "gnosis" coinstack.
Used throughout middleware and handlers to collect metrics.
3. HTTP Endpoints
GET
/health
Responds with service health status and current WebSocket client count.app.get('/health', async (_, res) => res.json({ status: 'up', asset: 'gnosis', connections: wsServer.clients.size }))GET
/metrics
Returns Prometheus metrics in the correct content type.app.get('/metrics', async (_, res) => { res.setHeader('Content-Type', prometheus.register.contentType) res.send(await prometheus.register.metrics()) })Static File Serving and Swagger UI
Serves static assets and Swagger API docs.
4. Blockchain Event Handlers
These handlers process blockchain data received from the WebSocket connection to the blockchain indexer.
blockHandler
const blockHandler: BlockHandler<NewBlock, Array<{ addresses: Array<string>; tx: evm.Tx }>> = async (block) => { ... }
Purpose: Processes a new block event.
Parameters:
block: aNewBlockobject representing the block data.
Returns:
An object containing an array of transactions with their related addresses.
Process:
Concurrently fetches:
Block transactions from the service.
Internal transactions by trace for the block.
Maps over each transaction to:
Handle and parse it into an
evm.Txtransaction object.Attach internal transactions.
Extract and deduplicate involved addresses.
Usage: Invoked when a new block is received from the WebSocket client.
transactionHandler
const transactionHandler: TransactionHandler<BlockbookTx, evm.Tx> = async (blockbookTx) => { ... }
Purpose: Processes a single transaction event.
Parameters:
blockbookTx: a transaction object from Blockbook.
Returns:
An object containing addresses involved and the parsed
evm.Txtransaction.
Process:
Handles the transaction with internal trace data.
Extracts and deduplicates involved addresses.
Usage: Invoked when individual transactions are received.
5. Registry Initialization
const registry = new Registry({
addressFormatter: evm.formatAddress,
blockHandler,
transactionHandler,
})
Manages the registration and handling of blockchain events.
Uses provided formatters and handlers.
Acts as the central dispatcher for block and transaction processing.
6. WebSocket Client Setup
const blockbook = new WebsocketClient(INDEXER_WS_URL, {
blockHandler: [registry.onBlock.bind(registry), gasOracle.onBlock.bind(gasOracle)],
transactionHandler: registry.onTransaction.bind(registry),
})
Connects to the blockchain indexer WebSocket URL.
Registers multiple handlers for block events (registry and gasOracle).
Uses registry to handle transaction events.
7. HTTP and WebSocket Server
const server = app.listen(PORT, () => logger.info('Server started'))
const wsServer = new Server({ server })
Starts the HTTP server on the configured port.
Creates a WebSocket server attached to the HTTP server.
Handles new WebSocket connections by invoking
ConnectionHandler.start.
8. WebSocket Connection Handler
wsServer.on('connection', (connection) => {
ConnectionHandler.start(connection, registry, blockbook, prometheus, logger)
})
For each new WebSocket client connection:
Starts connection handling logic.
Passes references to the registry, blockbook client, Prometheus, and logger.
Manages subscription and messaging for real-time updates.
Important Implementation Details
Concurrency in Block Processing:
TheblockHandlerperforms two asynchronous operations in parallel to fetch block transactions and internal transaction traces, improving throughput.Address Extraction and Deduplication:
Both handlers extract addresses from transactions and internal transactions, usingSetto remove duplicates to optimize handling of address-based subscriptions or indexing.Use of External Libraries:
@shapeshiftoss/common-apiprovides blockchain-related abstractions (e.g.,evm,Registry, middleware).@shapeshiftoss/blockbookoffers WebSocket client and transaction types.swagger-ui-expressenables API documentation UI.prometheusintegration enables rich metrics collection.
Error Handling and Middleware:
The app uses centralized error and not-found middleware to ensure robust API responses and logging.Environment Variables:
INDEXER_WS_URLis mandatory and must be set, defining the blockchain indexer WebSocket endpoint.PORTdefaults to 3000 if unset.LOG_LEVELcontrols the verbosity of the logger.
Interaction with Other System Components
Controller Layer (
./controller)
Provides business logic for handling blocks, transactions, and gas oracle updates.Routes (
./routes)
Defines REST API routes registered on the Express app.Registry & Handlers
TheRegistryclass orchestrates event handling and interacts with the service layer to parse and enrich blockchain data.WebSocket Indexer
Receives live blockchain events from an external indexer via WebSocket and processes them through handlers.Prometheus Monitoring
Middleware and handlers update Prometheus metrics to track API usage, blockchain event processing, and system health.Logger
Provides structured logging scoped to Gnosis coinstack, aiding observability and debugging.
Usage Example
Starting the server after setting the environment variables:
export INDEXER_WS_URL=wss://gnosis-indexer.example.com/ws
export PORT=3000
export LOG_LEVEL=info
node dist/app.js
Visit
http://localhost:3000/healthto check service health.Visit
http://localhost:3000/docsto access Swagger API documentation.Connect a WebSocket client to the server to receive real-time blockchain event updates.
Monitor Prometheus metrics at
http://localhost:3000/metrics.
Mermaid Diagram - Structure of app.ts
classDiagram
class App {
+app: express.Application
+prometheus: Prometheus
+logger: Logger
+blockHandler(block: NewBlock): Promise<{txs: Array}>
+transactionHandler(tx: BlockbookTx): Promise<{addresses: Array, tx: evm.Tx}>
}
class Registry {
+onBlock(block: NewBlock)
+onTransaction(tx: BlockbookTx)
}
class WebsocketClient {
+connect()
+blockHandler
+transactionHandler
}
class Server {
+listen(port: number)
+on(event: string, handler: Function)
}
class ConnectionHandler {
+start(connection: WebSocket, registry: Registry, blockbook: WebsocketClient, prometheus: Prometheus, logger: Logger)
}
App "1" *-- "1" Registry : uses
App "1" *-- "1" Prometheus : uses
App "1" *-- "1" Logger : uses
App "1" *-- "1" WebsocketClient : creates
App "1" *-- "1" Server : creates
Server "1" *-- "*" WebSocketConnection : manages
Server "1" o-- ConnectionHandler : uses on connection
WebsocketClient "1" ..> Registry : calls handlers
Summary
`app.ts` is a critical integration point that bootstraps the Gnosis API server, combining HTTP serving, real-time WebSocket blockchain event processing, metrics collection, and API documentation. It leverages modular components like Registry and WebsocketClient to efficiently handle blockchain data streams and exposes RESTful endpoints for external clients. The file ensures observability via Prometheus and logging while maintaining extensibility through middleware and dynamic route registration.