Add full monorepo: virtual-banker, backend, frontend, docs, scripts, deployment
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
337
docs/specs/api/websocket-api.md
Normal file
337
docs/specs/api/websocket-api.md
Normal file
@@ -0,0 +1,337 @@
|
||||
# WebSocket API Specification
|
||||
|
||||
## Overview
|
||||
|
||||
This document specifies the WebSocket API for real-time blockchain data subscriptions, including new blocks, pending transactions, and address activity.
|
||||
|
||||
**Endpoint**: `wss://api.explorer.d-bis.org/ws`
|
||||
|
||||
## Connection Lifecycle
|
||||
|
||||
### Connection
|
||||
|
||||
**URL**: `wss://api.explorer.d-bis.org/ws?chain_id=138`
|
||||
|
||||
**Query Parameters**:
|
||||
- `chain_id` (optional): Default chain ID for subscriptions
|
||||
- `api_key` (optional): API key for authenticated connections
|
||||
|
||||
**Headers**:
|
||||
- `Authorization: Bearer <token>` (optional)
|
||||
|
||||
### Authentication
|
||||
|
||||
**Methods**:
|
||||
1. Query parameter: `?api_key=<key>`
|
||||
2. Header: `Authorization: Bearer <token>`
|
||||
3. Message: Send auth message after connection
|
||||
|
||||
**Auth Message**:
|
||||
```json
|
||||
{
|
||||
"type": "auth",
|
||||
"api_key": "your-api-key"
|
||||
}
|
||||
```
|
||||
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"type": "auth_success",
|
||||
"user_id": "uuid",
|
||||
"tier": "pro"
|
||||
}
|
||||
```
|
||||
|
||||
### Heartbeat
|
||||
|
||||
**Purpose**: Keep connection alive and detect disconnections.
|
||||
|
||||
**Client Ping**: Send every 30 seconds
|
||||
```json
|
||||
{
|
||||
"type": "ping"
|
||||
}
|
||||
```
|
||||
|
||||
**Server Pong**: Response within 1 second
|
||||
```json
|
||||
{
|
||||
"type": "pong",
|
||||
"timestamp": 1640995200
|
||||
}
|
||||
```
|
||||
|
||||
**Timeout**: Connection closed if no pong received within 60 seconds
|
||||
|
||||
## Subscription Model
|
||||
|
||||
### Subscribe to New Blocks
|
||||
|
||||
**Request**:
|
||||
```json
|
||||
{
|
||||
"type": "subscribe",
|
||||
"channel": "blocks",
|
||||
"chain_id": 138,
|
||||
"params": {
|
||||
"include_transactions": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"type": "subscribed",
|
||||
"subscription_id": "sub_123",
|
||||
"channel": "blocks"
|
||||
}
|
||||
```
|
||||
|
||||
**Updates**:
|
||||
```json
|
||||
{
|
||||
"type": "update",
|
||||
"subscription_id": "sub_123",
|
||||
"data": {
|
||||
"number": 12345,
|
||||
"hash": "0x...",
|
||||
"timestamp": "2024-01-01T00:00:00Z",
|
||||
"transaction_count": 100
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Subscribe to Pending Transactions
|
||||
|
||||
**Request**:
|
||||
```json
|
||||
{
|
||||
"type": "subscribe",
|
||||
"channel": "pending_transactions",
|
||||
"chain_id": 138,
|
||||
"params": {
|
||||
"from_address": "0x...", // Optional filter
|
||||
"min_value": "1000000000000000000" // Optional filter
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Updates**: Transaction objects as they enter mempool
|
||||
|
||||
### Subscribe to Address Activity
|
||||
|
||||
**Request**:
|
||||
```json
|
||||
{
|
||||
"type": "subscribe",
|
||||
"channel": "address",
|
||||
"chain_id": 138,
|
||||
"params": {
|
||||
"address": "0x..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Updates**: Transactions involving the address
|
||||
|
||||
### Subscribe to Logs/Events
|
||||
|
||||
**Request**:
|
||||
```json
|
||||
{
|
||||
"type": "subscribe",
|
||||
"channel": "logs",
|
||||
"chain_id": 138,
|
||||
"params": {
|
||||
"address": "0x...",
|
||||
"topics": ["0xddf252..."] // Event signatures
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Updates**: Matching log entries
|
||||
|
||||
### Unsubscribe
|
||||
|
||||
**Request**:
|
||||
```json
|
||||
{
|
||||
"type": "unsubscribe",
|
||||
"subscription_id": "sub_123"
|
||||
}
|
||||
```
|
||||
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"type": "unsubscribed",
|
||||
"subscription_id": "sub_123"
|
||||
}
|
||||
```
|
||||
|
||||
## Message Formats
|
||||
|
||||
### Client Messages
|
||||
|
||||
**Subscribe**:
|
||||
```json
|
||||
{
|
||||
"type": "subscribe",
|
||||
"channel": "<channel_name>",
|
||||
"chain_id": 138,
|
||||
"params": { ... }
|
||||
}
|
||||
```
|
||||
|
||||
**Unsubscribe**:
|
||||
```json
|
||||
{
|
||||
"type": "unsubscribe",
|
||||
"subscription_id": "<id>"
|
||||
}
|
||||
```
|
||||
|
||||
**Ping**:
|
||||
```json
|
||||
{
|
||||
"type": "ping"
|
||||
}
|
||||
```
|
||||
|
||||
### Server Messages
|
||||
|
||||
**Update**:
|
||||
```json
|
||||
{
|
||||
"type": "update",
|
||||
"subscription_id": "<id>",
|
||||
"data": { ... }
|
||||
}
|
||||
```
|
||||
|
||||
**Error**:
|
||||
```json
|
||||
{
|
||||
"type": "error",
|
||||
"code": "invalid_subscription",
|
||||
"message": "Invalid subscription parameters",
|
||||
"subscription_id": "<id>"
|
||||
}
|
||||
```
|
||||
|
||||
**Notification**:
|
||||
```json
|
||||
{
|
||||
"type": "notification",
|
||||
"level": "info", // info, warning, error
|
||||
"message": "Subscription limit reached"
|
||||
}
|
||||
```
|
||||
|
||||
## Subscription Limits
|
||||
|
||||
**Per Connection**:
|
||||
- Anonymous: 5 subscriptions
|
||||
- Free API Key: 20 subscriptions
|
||||
- Pro API Key: 100 subscriptions
|
||||
- Enterprise: Unlimited
|
||||
|
||||
**Per Chain**:
|
||||
- Limit subscriptions per chain to prevent abuse
|
||||
|
||||
## Reconnection Strategy
|
||||
|
||||
### Automatic Reconnection
|
||||
|
||||
**Strategy**: Exponential backoff
|
||||
|
||||
**Backoff Schedule**:
|
||||
- Initial: 1 second
|
||||
- Max: 60 seconds
|
||||
- Multiplier: 2x
|
||||
|
||||
**Behavior**:
|
||||
- Reconnect automatically
|
||||
- Resubscribe to all active subscriptions
|
||||
- Resume from last received update
|
||||
|
||||
### Manual Reconnection
|
||||
|
||||
**Steps**:
|
||||
1. Close connection gracefully
|
||||
2. Reconnect with same parameters
|
||||
3. Resubscribe to desired channels
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
**Limits**:
|
||||
- Message rate: 10 messages/second per connection
|
||||
- Subscription rate: 5 subscriptions/minute per connection
|
||||
- Update rate: Throttled per subscription type
|
||||
|
||||
**Throttling**: Server may batch or skip updates if client cannot keep up
|
||||
|
||||
## Error Codes
|
||||
|
||||
- `invalid_message`: Malformed message
|
||||
- `invalid_subscription`: Invalid subscription parameters
|
||||
- `subscription_limit`: Too many subscriptions
|
||||
- `rate_limit`: Rate limit exceeded
|
||||
- `unauthorized`: Authentication required
|
||||
- `chain_not_supported`: Chain ID not supported
|
||||
- `internal_error`: Server error
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Connection Security
|
||||
|
||||
- WSS (WebSocket Secure) required
|
||||
- TLS 1.2+ only
|
||||
- Certificate validation
|
||||
|
||||
### Authentication
|
||||
|
||||
- API key validation
|
||||
- User permission checks
|
||||
- Subscription authorization
|
||||
|
||||
### Message Validation
|
||||
|
||||
- Validate all incoming messages
|
||||
- Sanitize parameters
|
||||
- Reject invalid requests
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Message Batching
|
||||
|
||||
**Strategy**: Batch multiple updates into single message when possible
|
||||
|
||||
**Example**:
|
||||
```json
|
||||
{
|
||||
"type": "batch_update",
|
||||
"updates": [
|
||||
{ "subscription_id": "sub_1", "data": {...} },
|
||||
{ "subscription_id": "sub_2", "data": {...} }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Backpressure
|
||||
|
||||
**Strategy**: Drop updates if client cannot process them
|
||||
|
||||
**Indicators**:
|
||||
- Client buffer full
|
||||
- No ping/pong responses
|
||||
- Slow message processing
|
||||
|
||||
## References
|
||||
|
||||
- REST API: See `rest-api.md`
|
||||
- GraphQL API: See `graphql-api.md`
|
||||
- Mempool Service: See `../mempool/mempool-service.md`
|
||||
|
||||
Reference in New Issue
Block a user