app.ts
Overview
`app.ts` is the main entry point for the **ShapeShift BNB Smart Chain API** server application. It sets up an Express-based HTTP REST API augmented with WebSocket support to serve blockchain data related to Binance Smart Chain (BNB Smart Chain). The file orchestrates:
Initialization of the Express server with middleware, health checks, metrics, and API documentation.
Integration with a WebSocket client that subscribes to blockchain events (new blocks and transactions) from a remote indexer service.
Processing and handling of blockchain data via registered handlers for blocks and transactions, including internal transactions.
Prometheus metrics collection for monitoring.
WebSocket server for real-time client connections and event push notifications.
This file acts as the glue between the HTTP interface, WebSocket event listening, blockchain data processing services, and monitoring infrastructure.
Classes, Functions, and Methods
Express App Setup
app: An instance of Express application configured with:Common middleware (e.g., logging, request parsing) injected from
@shapeshiftoss/common-api.REST endpoints:
GET /health: Returns service health status and active WebSocket connections.GET /metrics: Serves Prometheus metrics.GET /docs: Serves Swagger UI API documentation.Static file serving for public assets and swagger JSON.
Usage Example:
// Start server const server = app.listen(PORT, () => logger.info('Server started'))
blockHandler
const blockHandler: BlockHandler<NewBlock, Array<{ addresses: Array<string>; tx: evm.Tx }>> = async (block) => { ... }
Purpose: Processes a new blockchain block event.
Parameters:
block: Object of typeNewBlockrepresenting a newly indexed blockchain block.
Returns: An object containing an array of transaction objects, each with addresses involved and the parsed transaction (
evm.Tx).Implementation Details:
Fetches block transactions using
service.handleBlock(block.hash).Fetches internal transactions for the block
service.fetchInternalTxsByBlockDebug(block.hash).For each transaction:
Parses it with
service.handleTransaction.Attaches internal transactions.
Extracts all unique addresses involved (from both external and internal transactions).
Usage: Registered as the block handler in the blockchain event registry.
transactionHandler
const transactionHandler: TransactionHandler<BlockbookTx, evm.Tx> = async (blockbookTx) => { ... }
Purpose: Processes individual blockchain transactions.
Parameters:
blockbookTx: Transaction object from Blockbook API (BlockbookTx).
Returns: Object containing transaction details (
evm.Tx) and all unique involved addresses.Implementation Details:
Handles transaction with internal tracing (
service.handleTransactionWithInternalTrace).Extracts all addresses involved including internal transactions.
Usage: Registered as the transaction handler in the event registry.
Registry
const registry = new Registry({ addressFormatter: evm.formatAddress, blockHandler, transactionHandler })
Purpose: Core component that manages subscription to blockchain events and dispatches them to handlers.
Parameters:
addressFormatter: A function to format blockchain addresses (fromevm.formatAddress).blockHandler: Function to process blocks.transactionHandler: Function to process individual transactions.
Usage: Provides methods
onBlockandonTransactionused as callbacks for the WebSocket client.
WebSocket Client Setup
const blockbook = new WebsocketClient(INDEXER_WS_URL, {
apiKey: INDEXER_API_KEY,
blockHandler: [registry.onBlock.bind(registry), gasOracle.onBlock.bind(gasOracle)],
transactionHandler: registry.onTransaction.bind(registry),
})
Purpose: Connects to an external blockchain indexer WebSocket service.
Parameters:
INDEXER_WS_URL: WebSocket URL for the indexer service.apiKey: API key for authentication.blockHandler: Array of functions to invoke on new block events.transactionHandler: Function to invoke on new transaction events.
Integration: Uses handlers from the registry and a
gasOraclecontroller.Functionality: Listens to blockchain updates and triggers registered handlers.
WebSocket Server Setup
const wsServer = new Server({ server })
wsServer.on('connection', (connection) => {
ConnectionHandler.start(connection, registry, blockbook, prometheus, logger)
})
Purpose: Creates a WebSocket server on top of the HTTP server to serve real-time blockchain updates to connected clients.
On Connection: Calls
ConnectionHandler.startwhich manages client lifecycle and subscriptions.Parameters: Passes the connection object along with registry, blockbook client, metrics collector, and logger for coordinated operation.
Logger
export const logger = new Logger({
namespace: ['unchained', 'coinstacks', 'bnbsmartchain', 'api'],
level: process.env.LOG_LEVEL,
})
Purpose: Provides namespaced logging with configurable log levels.
Usage: Used throughout for informational logs and error reporting.
Prometheus Metrics
const prometheus = new Prometheus({ coinstack: 'bnbsmartchain' })
Purpose: Collects and exposes metrics for monitoring blockchain events and server health.
Endpoints:
/metrics: HTTP endpoint serving Prometheus metrics in the required format.
Important Implementation Details and Algorithms
Parallel Fetching of Block Data:
TheblockHandlerusesPromise.allto concurrently fetch main block transactions and internal transactions, improving performance.Address Aggregation:
Both handlers extract addresses from external and internal transactions and merge them into a unique set. This ensures comprehensive tracking of all involved addresses per transaction or block.Usage of
Registry:
TheRegistryabstracts the logic to format addresses and route blockchain events to appropriate handlers, centralizing event processing.WebSocket Client and Server Coordination:
The file establishes a bi-directional real-time data flow:Incoming: Listens to blockchain events from the indexer WebSocket.
Outgoing: Pushes updates to connected clients via the WebSocket server.
Middleware Integration:
Common middleware for logging, error handling, and monitoring are applied uniformly, ensuring robustness.
Interaction with Other Parts of the System
@shapeshiftoss/common-api:
Provides common middleware, logger, Prometheus, and blockchain event handler abstractions (Registry,BlockHandler,TransactionHandler).@shapeshiftoss/blockbook:
Supplies the WebSocket client (WebsocketClient), data types, and utility functions for working with the blockchain indexer../controller:
Implements business logic inserviceandgasOracle, which handle detailed transaction/block processing and gas price analytics../routes:
Defines REST API endpoints registered viaRegisterRoutes(app).External Environment:
Relies on environment variablesINDEXER_WS_URL,INDEXER_API_KEY, and optionallyPORTandLOG_LEVEL.
Usage Example
To start the BNB Smart Chain API server:
INDEXER_WS_URL=wss://indexer.example.com/ws \
INDEXER_API_KEY=yourapikey \
PORT=3000 \
LOG_LEVEL=info \
node dist/app.js
Then:
Access health check:
GET http://localhost:3000/healthView metrics:
GET http://localhost:3000/metricsBrowse API docs:
GET http://localhost:3000/docsConnect WebSocket clients to the server's WebSocket endpoint to receive real-time blockchain events.
Mermaid Diagram: Class Diagram of Key Components
classDiagram
class app {
+use(middleware)
+get(route, handler)
+listen(port, callback)
}
class Registry {
+onBlock(block)
+onTransaction(tx)
-addressFormatter
-blockHandler
-transactionHandler
}
class WebsocketClient {
+constructor(url, options)
+connect()
+blockHandler
+transactionHandler
}
class Server {
+constructor(options)
+on(event, callback)
}
class ConnectionHandler {
+start(connection, registry, blockbook, prometheus, logger)
}
class Prometheus {
+register
+constructor(options)
}
class Logger {
+info(message)
+error(message)
}
app --> Registry : uses
app --> Server : creates
Server --> ConnectionHandler : on connection calls start
WebsocketClient --> Registry : calls onBlock, onTransaction
app --> Prometheus : uses for metrics
app --> Logger : logs info/errors
Summary
This file acts as the core runtime for the BNB Smart Chain API service, bridging HTTP REST, WebSocket blockchain event streaming, transaction processing, and monitoring. It leverages external libraries and internal controllers to provide a scalable, observable, and real-time blockchain data API tailored for ShapeShift's ecosystem.