본문으로 건너뛰기

Base WebSocket Guide

Stream real-time data from Base blockchain using BlockEden.xyz's WebSocket API. Subscribe to new blocks, pending transactions, smart contract events, and more with low-latency connections.

WebSocket Endpoint

wss://api.blockeden.xyz/base/<your-api-key>

Connection Example

JavaScript

const ws = new WebSocket('wss://api.blockeden.xyz/base/<your-api-key>');

ws.onopen = () => {
console.log('Connected to Base WebSocket');
};

ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Received:', data);
};

ws.onerror = (error) => {
console.error('WebSocket error:', error);
};

ws.onclose = () => {
console.log('WebSocket connection closed');
};

Node.js

const WebSocket = require('ws');

const ws = new WebSocket('wss://api.blockeden.xyz/base/<your-api-key>');

ws.on('open', () => {
console.log('Connected to Base WebSocket');
});

ws.on('message', (data) => {
const message = JSON.parse(data);
console.log('Received:', message);
});

ws.on('error', (error) => {
console.error('WebSocket error:', error);
});

Python

import asyncio
import websockets
import json

async def connect_to_base():
uri = "wss://api.blockeden.xyz/base/<your-api-key>"

async with websockets.connect(uri) as websocket:
print("Connected to Base WebSocket")

# Subscribe to new blocks
subscribe_msg = {
"jsonrpc": "2.0",
"method": "eth_subscribe",
"params": ["newHeads"],
"id": 1
}

await websocket.send(json.dumps(subscribe_msg))

async for message in websocket:
data = json.loads(message)
print(f"Received: {data}")

# Run the connection
asyncio.run(connect_to_base())

Subscription Methods

eth_subscribe

Subscribe to specific events on Base blockchain.

Subscription Types:

  • newHeads - New block headers
  • newPendingTransactions - Pending transactions
  • logs - Smart contract event logs
  • syncing - Node synchronization status

New Block Headers

Subscribe to new block headers as they are mined on Base.

JavaScript Example

const ws = new WebSocket('wss://api.blockeden.xyz/base/<your-api-key>');

ws.onopen = () => {
const subscribe = {
jsonrpc: '2.0',
method: 'eth_subscribe',
params: ['newHeads'],
id: 1
};

ws.send(JSON.stringify(subscribe));
};

ws.onmessage = (event) => {
const data = JSON.parse(event.data);

if (data.method === 'eth_subscription') {
const block = data.params.result;
console.log(`New block #${parseInt(block.number, 16)}`);
console.log(`Block hash: ${block.hash}`);
console.log(`Gas used: ${parseInt(block.gasUsed, 16)}`);
console.log(`Timestamp: ${new Date(parseInt(block.timestamp, 16) * 1000)}`);
}
};

Response Format

{
"jsonrpc": "2.0",
"method": "eth_subscription",
"params": {
"subscription": "0x...",
"result": {
"number": "0x1b4",
"hash": "0x...",
"parentHash": "0x...",
"timestamp": "0x...",
"gasLimit": "0x1c9c380",
"gasUsed": "0x...",
"baseFeePerGas": "0x...",
"difficulty": "0x0",
"mixHash": "0x...",
"nonce": "0x0000000000000000"
}
}
}

Pending Transactions

Monitor pending transactions in the Base mempool.

JavaScript Example

ws.onopen = () => {
const subscribe = {
jsonrpc: '2.0',
method: 'eth_subscribe',
params: ['newPendingTransactions'],
id: 2
};

ws.send(JSON.stringify(subscribe));
};

ws.onmessage = (event) => {
const data = JSON.parse(event.data);

if (data.method === 'eth_subscription') {
const txHash = data.params.result;
console.log(`New pending transaction: ${txHash}`);

// Optionally fetch full transaction details
fetchTransactionDetails(txHash);
}
};

async function fetchTransactionDetails(txHash) {
const response = await fetch('https://api.blockeden.xyz/base/<your-api-key>', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'eth_getTransactionByHash',
params: [txHash],
id: 1
})
});

const data = await response.json();
console.log('Transaction details:', data.result);
}

Smart Contract Event Logs

Subscribe to specific smart contract events.

JavaScript Example

ws.onopen = () => {
const subscribe = {
jsonrpc: '2.0',
method: 'eth_subscribe',
params: [
'logs',
{
address: '0xa0b86a33e6d4c3d0c4f74d08ba3c8b7c2d1e8b9f', // Contract address
topics: [
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' // Transfer event
]
}
],
id: 3
};

ws.send(JSON.stringify(subscribe));
};

ws.onmessage = (event) => {
const data = JSON.parse(event.data);

if (data.method === 'eth_subscription') {
const log = data.params.result;
console.log('Contract event:', log);

// Decode transfer event
if (log.topics[0] === '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef') {
const from = '0x' + log.topics[1].slice(26);
const to = '0x' + log.topics[2].slice(26);
const value = parseInt(log.data, 16);

console.log(`Transfer: ${from} -> ${to}, Amount: ${value}`);
}
}
};

Log Filter Parameters

{
address: "0x...", // Contract address (optional)
topics: [
"0x...", // Topic 0 (event signature)
"0x...", // Topic 1 (indexed parameter 1)
null, // Topic 2 (any value)
"0x..." // Topic 3 (indexed parameter 3)
]
}

Advanced Examples

Multi-Subscription Manager

class BaseWebSocketManager {
constructor(apiKey) {
this.apiKey = apiKey;
this.ws = null;
this.subscriptions = new Map();
this.nextId = 1;
}

connect() {
this.ws = new WebSocket(`wss://api.blockeden.xyz/base/${this.apiKey}`);

this.ws.onopen = () => {
console.log('Connected to Base WebSocket');
};

this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
this.handleMessage(data);
};

this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
};

this.ws.onclose = () => {
console.log('WebSocket closed, attempting to reconnect...');
setTimeout(() => this.connect(), 5000);
};
}

subscribe(type, params, callback) {
const id = this.nextId++;
const subscription = {
jsonrpc: '2.0',
method: 'eth_subscribe',
params: [type, ...(params || [])],
id: id
};

this.subscriptions.set(id, callback);
this.ws.send(JSON.stringify(subscription));

return id;
}

unsubscribe(subscriptionId) {
const unsubscribe = {
jsonrpc: '2.0',
method: 'eth_unsubscribe',
params: [subscriptionId],
id: this.nextId++
};

this.ws.send(JSON.stringify(unsubscribe));
}

handleMessage(data) {
if (data.method === 'eth_subscription') {
const subscriptionId = data.params.subscription;
const result = data.params.result;

// Find callback for this subscription
for (const [id, callback] of this.subscriptions) {
callback(result);
}
} else if (data.result) {
// Subscription confirmation
console.log(`Subscription ${data.id} confirmed:`, data.result);
}
}
}

// Usage
const manager = new BaseWebSocketManager('your-api-key');
manager.connect();

// Subscribe to new blocks
manager.subscribe('newHeads', [], (block) => {
console.log(`New block: ${parseInt(block.number, 16)}`);
});

// Subscribe to USDC transfers
manager.subscribe('logs', [{
address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base
topics: ['0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef']
}], (log) => {
console.log('USDC transfer:', log);
});

Real-time Price Monitor

class BasePriceMonitor {
constructor(apiKey, tokenAddress) {
this.apiKey = apiKey;
this.tokenAddress = tokenAddress;
this.ws = null;
this.prices = [];
}

async start() {
this.ws = new WebSocket(`wss://api.blockeden.xyz/base/${this.apiKey}`);

this.ws.onopen = () => {
console.log('Connected to Base for price monitoring');
this.subscribeToSwaps();
};

this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
this.handleSwapEvent(data);
};
}

subscribeToSwaps() {
// Subscribe to Uniswap V3 Swap events
const subscribe = {
jsonrpc: '2.0',
method: 'eth_subscribe',
params: [
'logs',
{
topics: [
'0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67' // Swap event
]
}
],
id: 1
};

this.ws.send(JSON.stringify(subscribe));
}

handleSwapEvent(data) {
if (data.method === 'eth_subscription') {
const log = data.params.result;

// Parse swap data
const blockNumber = parseInt(log.blockNumber, 16);
const txHash = log.transactionHash;

console.log(`Swap detected in block ${blockNumber}: ${txHash}`);

// Calculate price from swap data
this.calculatePrice(log);
}
}

calculatePrice(log) {
// Decode swap log data
const data = log.data;
const topics = log.topics;

// Implementation depends on the specific DEX/AMM
console.log('Processing swap for price calculation...');
}
}

// Monitor ETH/USDC price
const priceMonitor = new BasePriceMonitor(
'your-api-key',
'0x4200000000000000000000000000000000000006' // WETH on Base
);

priceMonitor.start();

Transaction Pool Monitor

class BaseTransactionMonitor {
constructor(apiKey) {
this.apiKey = apiKey;
this.ws = null;
this.pendingTxs = new Set();
this.confirmedTxs = new Set();
}

start() {
this.ws = new WebSocket(`wss://api.blockeden.xyz/base/${this.apiKey}`);

this.ws.onopen = () => {
this.subscribeToBlocks();
this.subscribeToPendingTxs();
};

this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
this.handleMessage(data);
};
}

subscribeToBlocks() {
const subscribe = {
jsonrpc: '2.0',
method: 'eth_subscribe',
params: ['newHeads'],
id: 1
};
this.ws.send(JSON.stringify(subscribe));
}

subscribeToPendingTxs() {
const subscribe = {
jsonrpc: '2.0',
method: 'eth_subscribe',
params: ['newPendingTransactions'],
id: 2
};
this.ws.send(JSON.stringify(subscribe));
}

handleMessage(data) {
if (data.method === 'eth_subscription') {
const result = data.params.result;

if (typeof result === 'string') {
// Pending transaction hash
this.handlePendingTransaction(result);
} else if (result.number) {
// New block
this.handleNewBlock(result);
}
}
}

handlePendingTransaction(txHash) {
this.pendingTxs.add(txHash);
console.log(`Pending: ${txHash} (${this.pendingTxs.size} pending)`);
}

handleNewBlock(block) {
const blockNumber = parseInt(block.number, 16);
console.log(`New block #${blockNumber} with ${block.transactions?.length || 0} txs`);

// Fetch full block to see which pending txs were confirmed
this.checkConfirmedTransactions(blockNumber);
}

async checkConfirmedTransactions(blockNumber) {
try {
const response = await fetch(`https://api.blockeden.xyz/base/${this.apiKey}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'eth_getBlockByNumber',
params: [`0x${blockNumber.toString(16)}`, true],
id: 1
})
});

const data = await response.json();
const block = data.result;

if (block && block.transactions) {
block.transactions.forEach(tx => {
if (this.pendingTxs.has(tx.hash)) {
this.pendingTxs.delete(tx.hash);
this.confirmedTxs.add(tx.hash);
console.log(`Confirmed: ${tx.hash}`);
}
});
}
} catch (error) {
console.error('Error fetching block:', error);
}
}
}

// Start monitoring
const txMonitor = new BaseTransactionMonitor('your-api-key');
txMonitor.start();

Subscription Management

eth_unsubscribe

Cancel an active subscription.

// Unsubscribe from a subscription
const unsubscribe = {
jsonrpc: '2.0',
method: 'eth_unsubscribe',
params: ['0x...'], // Subscription ID
id: 4
};

ws.send(JSON.stringify(unsubscribe));

Managing Multiple Subscriptions

class SubscriptionManager {
constructor(ws) {
this.ws = ws;
this.activeSubscriptions = new Map();
this.idCounter = 1;
}

subscribe(type, params, callback) {
const id = this.idCounter++;
const subscriptionRequest = {
jsonrpc: '2.0',
method: 'eth_subscribe',
params: [type, ...(params || [])],
id: id
};

this.ws.send(JSON.stringify(subscriptionRequest));

// Store callback for this subscription ID
this.activeSubscriptions.set(id, {
type,
params,
callback,
subscriptionId: null // Will be set when confirmation is received
});

return id;
}

handleMessage(data) {
if (data.id && data.result) {
// Subscription confirmation
const subscription = this.activeSubscriptions.get(data.id);
if (subscription) {
subscription.subscriptionId = data.result;
console.log(`Subscription ${data.id} active: ${data.result}`);
}
} else if (data.method === 'eth_subscription') {
// Subscription data
const subscriptionId = data.params.subscription;

// Find the subscription and call its callback
for (const [id, sub] of this.activeSubscriptions) {
if (sub.subscriptionId === subscriptionId) {
sub.callback(data.params.result);
break;
}
}
}
}

unsubscribe(subscriptionId) {
const unsubscribeRequest = {
jsonrpc: '2.0',
method: 'eth_unsubscribe',
params: [subscriptionId],
id: this.idCounter++
};

this.ws.send(JSON.stringify(unsubscribeRequest));

// Remove from active subscriptions
for (const [id, sub] of this.activeSubscriptions) {
if (sub.subscriptionId === subscriptionId) {
this.activeSubscriptions.delete(id);
break;
}
}
}

unsubscribeAll() {
for (const [id, sub] of this.activeSubscriptions) {
if (sub.subscriptionId) {
this.unsubscribe(sub.subscriptionId);
}
}
}
}

Error Handling

Connection Management

class RobustWebSocketConnection {
constructor(apiKey) {
this.apiKey = apiKey;
this.ws = null;
this.reconnectAttempts = 0;
this.maxReconnectAttempts = 5;
this.reconnectDelay = 1000;
this.subscriptions = [];
}

connect() {
try {
this.ws = new WebSocket(`wss://api.blockeden.xyz/base/${this.apiKey}`);

this.ws.onopen = () => {
console.log('WebSocket connected');
this.reconnectAttempts = 0;
this.resubscribe();
};

this.ws.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
this.handleMessage(data);
} catch (error) {
console.error('Error parsing message:', error);
}
};

this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
};

this.ws.onclose = (event) => {
console.log('WebSocket closed:', event.code, event.reason);
this.handleReconnection();
};

} catch (error) {
console.error('Error creating WebSocket:', error);
this.handleReconnection();
}
}

handleReconnection() {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1);

console.log(`Attempting to reconnect in ${delay}ms (attempt ${this.reconnectAttempts})`);

setTimeout(() => {
this.connect();
}, delay);
} else {
console.error('Max reconnection attempts reached');
}
}

resubscribe() {
// Re-establish all subscriptions after reconnection
this.subscriptions.forEach(sub => {
this.ws.send(JSON.stringify(sub.request));
});
}

subscribe(type, params, callback) {
const subscription = {
request: {
jsonrpc: '2.0',
method: 'eth_subscribe',
params: [type, ...(params || [])],
id: Date.now()
},
callback: callback
};

this.subscriptions.push(subscription);

if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(subscription.request));
}

return subscription.request.id;
}

handleMessage(data) {
if (data.method === 'eth_subscription') {
// Find the appropriate callback
const subscription = this.subscriptions.find(sub =>
sub.subscriptionId === data.params.subscription
);

if (subscription) {
subscription.callback(data.params.result);
}
} else if (data.result) {
// Subscription confirmation
const subscription = this.subscriptions.find(sub =>
sub.request.id === data.id
);

if (subscription) {
subscription.subscriptionId = data.result;
}
}
}
}

Performance Optimization

Batch Processing

class BatchProcessor {
constructor(ws, batchSize = 100, flushInterval = 1000) {
this.ws = ws;
this.batchSize = batchSize;
this.flushInterval = flushInterval;
this.buffer = [];

setInterval(() => this.flush(), flushInterval);
}

addToBuffer(data) {
this.buffer.push(data);

if (this.buffer.length >= this.batchSize) {
this.flush();
}
}

flush() {
if (this.buffer.length > 0) {
this.processBatch([...this.buffer]);
this.buffer = [];
}
}

processBatch(items) {
console.log(`Processing batch of ${items.length} items`);
// Process all items in the batch
items.forEach(item => {
// Your processing logic here
});
}
}

Best Practices

  1. Connection Management

    • Implement automatic reconnection
    • Handle connection errors gracefully
    • Store subscription state for reconnection
  2. Resource Management

    • Unsubscribe from unused subscriptions
    • Implement connection pooling for multiple streams
    • Monitor memory usage
  3. Error Handling

    • Validate incoming data
    • Implement retry logic
    • Log errors for debugging
  4. Performance

    • Batch process events when possible
    • Use appropriate buffer sizes
    • Implement backpressure handling

Rate Limits

WebSocket connections have the same rate limits as HTTP requests:

  • Free Tier: 100 messages/second
  • Pro Tier: 1,000 messages/second
  • Enterprise: Custom limits

Next Steps

  • Learn about Base L2 Features Guide for Layer 2 specific functionality
  • Explore the Base JSON-RPC API Reference for HTTP endpoints
  • Visit BlockEden.xyz Dashboard to monitor usage