app.ts
Overview
`app.ts` is the primary entry point for the Base API server within the ShapeShift Unchained ecosystem. It sets up an Express web server augmented with WebSocket support to handle real-time blockchain data related to Ethereum Virtual Machine (EVM) networks. The file initializes middleware, API routes, and integrates with external services such as a blockchain indexer via WebSocket. It also exposes health, metrics, and Swagger-based API documentation endpoints.
This server processes blockchain transactions by leveraging the `@shapeshiftoss/common-api` and `@shapeshiftoss/blockbook` packages, formats addresses, and maintains metrics via Prometheus. It orchestrates live transaction and block event handling, enabling downstream services or clients to consume processed blockchain data.
Detailed Explanation of Components
Constants and Environment Variables
Name | Description |
|---|---|
`PORT` | Server listening port, default to 3000 if not specified. |
`INDEXER_WS_URL` | WebSocket URL of the blockchain indexer service. Required. |
`INDEXER_API_KEY` | API key for authenticating with the indexer. Optional. |
**Important:** The app throws an error and halts startup if `INDEXER_WS_URL` is not set.
Logger
export const logger = new Logger({
namespace: ['unchained', 'coinstacks', 'base', 'api'],
level: process.env.LOG_LEVEL,
})
Purpose: Centralized logging facility scoped to the Base API.
Usage: Used throughout the app for info and error logs.
Configurable: Log level controlled by environment variable
LOG_LEVEL.
Prometheus Metrics
const prometheus = new Prometheus({ coinstack: 'base' })
Purpose: Collects and exposes metrics related to the API and blockchain data processed.
Usage: Middleware integrates Prometheus to monitor request and system metrics.
Exposed endpoint:
/metricsserves Prometheus metrics in the required format.
Express App Setup
const app = express()
Creates the Express application instance.
Middleware applied includes:
Common middleware from
@shapeshiftoss/common-apiwith Prometheus integration.Error handling and 404 not found middleware at the end.
HTTP Routes
Route | Method | Description |
|---|---|---|
`/health` | GET | Returns JSON health status with server status and active WS connections count. |
`/metrics` | GET | Exposes Prometheus metrics. |
`/public` | Static | Serves static assets related to API docs UI. |
`/swagger.json` | Static | Serves Swagger API definition JSON. |
`/docs` | GET | Serves Swagger UI documentation for the API. |
`/` | GET | Redirects to `/docs` for user convenience. |
Example usage:
curl http://localhost:3000/health
# Response: { "status": "up", "asset": "base", "connections": 0 }
Swagger UI Integration
Uses
swagger-ui-expressto serve interactive API documentation.Customizations:
Hides the topbar.
Custom site title and favicon.
Served under
/docs.API specification JSON served at
/swagger.json.
Route Registration
RegisterRoutes(app)
Registers all application-specific API routes.
Routes are defined externally in the
./routesmodule.This decouples route definitions from the main server setup.
Address Formatter
const addressFormatter: AddressFormatter = (address) => evm.formatAddress(address)
Formats blockchain addresses using EVM-specific formatting.
Used in the transaction registry to standardize address representation.
Transaction Handler
const transactionHandler: TransactionHandler<BlockbookTx, evm.Tx> = async (blockbookTx) => {
const tx = await service.handleTransactionWithInternalTrace(blockbookTx)
const internalAddresses = (tx.internalTxs ?? []).reduce<Array<string>>((prev, tx) => [...prev, tx.to, tx.from], [])
const addresses = [...new Set([...getAddresses(blockbookTx), ...internalAddresses])]
return { addresses, tx }
}
Parameters:
blockbookTx- a transaction object from Blockbook format.Returns:
An object with:addresses: a unique array of related addresses involved in the transaction, including internal transaction addresses.tx: the processed transaction object with internal traces.
Purpose:
Handles conversion and enrichment of raw blockchain transactions to the app's internal format, extracting all relevant addresses for tracking and indexing.Implementation Details:
Calls
service.handleTransactionWithInternalTraceto process internal transaction details.Aggregates external and internal addresses.
Uses
Setto ensure uniqueness.
Registry
const registry = new Registry({ addressFormatter, transactionHandler })
Manages transaction and address handling logic.
Uses provided
addressFormatterandtransactionHandler.Acts as a central registry for processing incoming blockchain transactions.
WebSocket Client (Blockbook)
const blockbook = new WebsocketClient(`${INDEXER_WS_URL}/api=${INDEXER_API_KEY}`, {
blockHandler: [gasOracle.onBlock.bind(gasOracle)],
transactionHandler: registry.onTransaction.bind(registry),
})
Connects to the blockchain indexer WebSocket endpoint.
Listens for:
New blocks via
gasOracle.onBlock.New transactions via
registry.onTransaction.
Enables real-time blockchain data streaming into the server.
HTTP and WebSocket Server Setup
const server = app.listen(PORT, () => logger.info('Server started'))
const wsServer = new Server({ server })
wsServer.on('connection', (connection) => {
ConnectionHandler.start(connection, registry, blockbook, prometheus, logger)
})
Starts the Express HTTP server on configured
PORT.Initializes a WebSocket server (
wsServer) on top of the HTTP server.For each new WebSocket connection:
Calls
ConnectionHandler.startto manage the connection lifecycle, passing key services:registryfor transaction handling.blockbookfor blockchain data.prometheusfor metrics.loggerfor logging.
Interaction with Other Parts of the System
@shapeshiftoss/common-api: Provides middleware, connection handler, registry, address formatting, transaction handling, and monitoring utilities.@shapeshiftoss/blockbook: Interfaces with the blockchain indexer to receive raw transactions and block data../controller: Contains business logic such as gas price oracle and transaction services../routes: Defines the REST API routes that expose various blockchain-related endpoints.Prometheus: Integrated for performance and usage monitoring.
Swagger UI: For interactive API documentation, aiding client developers.
Logger: Centralized structured logging.
The file acts as a coordinator, wiring these modules together to expose a cohesive API server that streams blockchain data in near real-time and serves RESTful endpoints.
Usage Example
Start the server with required environment variables:
export INDEXER_WS_URL=wss://indexer.example.com
export INDEXER_API_KEY=your_api_key
export PORT=3000
node dist/app.js
Then access:
Health:
GET http://localhost:3000/healthMetrics:
GET http://localhost:3000/metricsAPI Docs:
GET http://localhost:3000/docs
WebSocket clients can connect to the same server's WebSocket endpoint to receive live blockchain updates.
Important Implementation Details
Error Handling:
Environment validation at startup ensures critical variables are set, preventing silent failures.Transaction Processing:
Uses an asynchronous transaction handler that enriches transactions with internal traces before indexing.Address Deduplication:
UsesSetto avoid duplicate addresses, ensuring efficient tracking.Decoupled Design:
Routes and controllers are separated from server setup, improving maintainability.Real-time Streaming:
WebSocket client subscribes to blockchain events and pushes data to connected clients via the server's own WebSocket.
Mermaid Class Diagram
classDiagram
class App {
+express app
+Prometheus prometheus
+Logger logger
+Registry registry
+WebsocketClient blockbook
+Server httpServer
+Server wsServer
+start()
}
class Registry {
+addressFormatter: AddressFormatter
+transactionHandler: TransactionHandler
+onTransaction()
}
class WebsocketClient {
+constructor(url, handlers)
+blockHandler: function[]
+transactionHandler: function
+connect()
}
class ConnectionHandler {
+start(connection, registry, blockbook, prometheus, logger)
}
class Logger {
+info()
+error()
}
class Prometheus {
+register
+metrics()
}
App --> Registry : uses
App --> WebsocketClient : uses
App --> ConnectionHandler : manages WS connections
App --> Prometheus : collects metrics
App --> Logger : logs events
Registry ..> AddressFormatter : uses
Registry ..> TransactionHandler : uses
Summary
`app.ts` is a foundational file that configures and launches the Base API server. It integrates Express HTTP routing, WebSocket real-time blockchain event streaming, transaction processing, and monitoring. The file carefully composes external libraries and internal modules to provide a robust, maintainable, and observable blockchain API service within the ShapeShift ecosystem.