StreamMiscEvents - Real-time Miscellaneous Event Streaming
Stream non-fill balance-affecting events from Hyperliquid L1 Gateway via gRPC. Monitor deposits, withdrawals, transfers, staking, and validator rewards in real-time.
Stream miscellaneous L1 events starting from a position, providing real-time access to every non-fill balance-affecting action on Hyperliquid: deposits, withdrawals, transfers, staking delegations, and validator rewards.
Full Code Examples
Clone our gRPC Code Examples Repository for complete, runnable implementations in Go, Python, and Node.js.
When to Use This Method
StreamMiscEvents is essential for:
- Deposit & Withdrawal Monitoring - Track funds entering and leaving accounts in real-time
- Treasury & Transfer Tracking - Follow spot transfers and internal
sendmovements - Staking & Delegation Analytics - Observe delegations, undelegations, and staking withdrawals
- Validator Reward Accounting - Reconcile per-epoch validator reward distributions
- Compliance & Audit Trails - Build a complete record of balance-affecting activity
Completes the Balance Picture
StreamMiscEvents covers everything StreamFills does not. Fills are trades; misc events are every other action that moves funds. Consume both streams together for a complete view of all balance-affecting activity.
Method Signature
rpc StreamMiscEvents(Position) returns (stream BlockMiscEvents) {}Response Stream
message BlockMiscEvents {
// JSON-encoded block envelope from "misc_events_by_block".
bytes data = 1;
}The data field contains a JSON-encoded block envelope with:
- Block reference (
local_time,block_time,block_number) - An
eventsarray of miscellaneous L1 event objects (empty for most blocks)
Per-Block Delivery
StreamMiscEvents emits exactly one message per block, including blocks with an empty events array. Most blocks contain no miscellaneous events, so the empty envelope doubles as a per-block heartbeat: consumers always know the stream is live and exactly which block was last processed, with no extra bookkeeping.
Messages arrive in strictly increasing block_number order with no gaps and no duplicates. The stream is stateless: reconnect by passing the next block_height (or a timestamp_ms) in the Position and resume exactly where you left off. Both are inclusive; an empty or zero Position targets the latest data.
Full Misc Events Spec
StreamMiscEvents emits a JSON payload matching Hyperliquid's misc_events_by_block format, passed through byte-for-byte from the node with no normalization. Below is the exact structure.
Top-level keys (always present):
{
"local_time": "2026-07-02T11:10:49.483839100", // ISO-8601 timestamp when node processed the block (nanosecond precision)
"block_time": "2026-07-02T11:10:47.023075863", // ISO-8601 timestamp from block consensus
"block_number": 1057659853, // Block height containing these events
"events": [] // Array of miscellaneous event objects (empty for most blocks)
}Each entry in events is a raw upstream Hyperliquid L1 event object:
| Field | Type | Description |
|---|---|---|
time | string | ISO-8601 timestamp of the event |
hash | string | Transaction hash. An all-zeros hash indicates a system-generated event (e.g. validator rewards) rather than a user transaction |
inner | object | Single-key object whose key is the event type discriminator (e.g. "LedgerUpdate", "Delegation", "CWithdrawal", "ValidatorRewards") |
Branch on the single key inside inner to determine the event type. The sections below cover the event types observed on mainnet; the upstream schema defines additional types, so treat these as examples rather than an exhaustive list. The authoritative schema reference is Hyperliquid's L1 data schemas documentation.
Guarantees and alignment:
eventscontains all miscellaneous events from the block, across all users.- Messages arrive in strictly increasing
block_number, one per block (including empty blocks). block_numbercorresponds toabci_block.roundin StreamBlocks;block_timealigns withabci_block.time.
Developer tips:
- Branch on the key inside
innerand handle unknown event types defensively — the upstream set can grow. - Track the last processed
block_numberso you can resume cleanly after a reconnect. - Normalize amount fields (strings) to numeric types as appropriate.
- Treat the all-zeros
hashas the marker for system-generated events.
Event Types
LedgerUpdate
LedgerUpdate is the most common event type. It carries a users array (the involved addresses) and a delta object whose type field discriminates the specific ledger action.
{
"time": "2026-07-02T11:10:47.023075863",
"hash": "0xae740acbd26e0108afed043f0a9bcd02022d00b16d611fda523cb61e9161daf3",
"inner": {
"LedgerUpdate": {
"users": [
"0x2000000000000000000000000000000000000000",
"0x0a82a35f3e54aede3a20931f446836e6c69cae0b"
],
"delta": {
"type": "spotTransfer",
"token": "USDC",
"amount": "100.058362",
"usdcValue": "100.058362",
"user": "0x2000000000000000000000000000000000000000",
"destination": "0x0a82a35f3e54aede3a20931f446836e6c69cae0b",
"fee": "0.0",
"nativeTokenFee": "0.0",
"nonce": 2053915,
"feeToken": ""
}
}
}
}The delta.type discriminator determines the remaining fields. Observed types on mainnet include:
delta.type | Meaning | Notable fields |
|---|---|---|
send | Internal transfer between accounts | user, destination, token, amount, usdcValue, fee |
spotTransfer | Spot balance transfer | user, destination, token, amount, usdcValue, fee |
deposit | Funds deposited into an account | usdc |
withdraw | Funds withdrawn from an account | usdc, nonce, fee |
rewardsClaim | Rewards claimed | token, amount |
borrowLend | Borrow/lend operation | token, operation, amount, interestAmount |
More delta.type values exist upstream; branch defensively on delta.type and treat this table as examples, not an exhaustive list. Example deltas:
{ "type": "deposit", "usdc": "3494.915745" }
{ "type": "withdraw", "usdc": "89.15", "nonce": 1782990425200000, "fee": "1.0" }
{ "type": "rewardsClaim", "amount": "1.097128", "token": "USDC" }
{ "type": "borrowLend", "token": "USDC", "operation": "supply", "amount": "0.23068", "interestAmount": "0.0" }Delegation
Staking delegation and undelegation. The is_undelegate flag distinguishes the two directions.
{
"time": "2026-07-02T11:11:06.583481947",
"hash": "0xfa0716eba98e39b0fb80043f0a9cec02029400d1448158839dcfc23e6882139b",
"inner": {
"Delegation": {
"user": "0xd5a5ae523080973946ac67e34f5fc70671bd8667",
"validator": "0x5ac99df645f3414876c816caa18b2d234024b487",
"amount": "20.65611502",
"is_undelegate": true
}
}
}CWithdrawal
A staking withdrawal, which enters a pending state until finalization. The is_finalized flag reflects whether the withdrawal has completed.
{
"time": "2026-07-02T11:11:07.283636968",
"hash": "0xae4f651df8ef488eafc9043f0a9cf6021348000393e2676052181070b7e32279",
"inner": {
"CWithdrawal": {
"user": "0xd5a5ae523080973946ac67e34f5fc70671bd8667",
"amount": "20.65611502",
"is_finalized": false
}
}
}ValidatorRewards
Per-epoch validator reward distributions. These are system-generated, so they carry an all-zeros hash. The validator_to_reward array holds [validator_address, amount] pairs.
{
"time": "2026-07-02T11:11:00.042812129",
"hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"inner": {
"ValidatorRewards": {
"validator_to_reward": [
["0x000000000056f99d36b6f2e0c51fd41496bbacb8", "0.2806444"],
["0x15458aed3c7a49b215fbfa863c6ff550c31e1a31", "0.22056816"],
["0x30c66ebc7f5ef4f340b424a26e4d944f60129815", "0.34709989"]
]
}
}
}Common Use Cases
1. Deposit and Withdrawal Monitor
def classify_event(event):
"""Return a (kind, detail) tuple for a misc event."""
inner = event['inner']
kind = next(iter(inner)) # the single discriminator key
body = inner[kind]
if kind == 'LedgerUpdate':
delta = body['delta']
return (delta['type'], delta) # e.g. ('deposit', {...})
return (kind, body) # e.g. ('Delegation', {...})
def watch_flows(client, metadata):
request = hyperliquid_pb2.Position() # latest
for response in client.StreamMiscEvents(request, metadata=metadata):
block = json.loads(response.data)
for event in block.get('events', []):
kind, detail = classify_event(event)
if kind in ('deposit', 'withdraw'):
print(f"block {block['block_number']}: {kind} {detail.get('usdc')} USDC")2. Streaming Misc Events in Python
import grpc
import json
import os
import hyperliquid_pb2
import hyperliquid_pb2_grpc
def stream_misc_events():
endpoint = os.getenv('HYPERLIQUID_ENDPOINT')
api_key = os.getenv('API_KEY')
credentials = grpc.ssl_channel_credentials()
options = [('grpc.max_receive_message_length', 150 * 1024 * 1024)] # 150MB max
metadata = [('x-api-key', api_key)]
with grpc.secure_channel(endpoint, credentials, options=options) as channel:
client = hyperliquid_pb2_grpc.HyperliquidL1GatewayStub(channel)
# Empty Position means latest; set block_height or timestamp_ms to backfill
request = hyperliquid_pb2.Position()
for response in client.StreamMiscEvents(request, metadata=metadata):
block = json.loads(response.data)
events = block.get('events', [])
if events:
print(f"block {block['block_number']}: {len(events)} misc events")Error Handling and Reconnection
Reconnect by replaying from the last processed block. Pass the next block_height in the Position so no events are skipped or double-counted.
def stream_with_resume(client, metadata, start_block):
next_block = start_block
while True:
request = hyperliquid_pb2.Position(block_height=next_block)
try:
for response in client.StreamMiscEvents(request, metadata=metadata):
block = json.loads(response.data)
process(block)
next_block = block['block_number'] + 1
except grpc.RpcError as e:
print(f"stream error, resuming from {next_block}: {e}")Best Practices
- Connection Management: Implement robust reconnection logic with exponential backoff
- Resumable State: Track the last processed
block_numberso you can resume from the next block - Defensive Parsing: Branch on the key inside
inner(anddelta.typeforLedgerUpdate) and handle unknown types gracefully - Heartbeat Awareness: Use the per-block empty envelope to confirm liveness without extra polling
- Performance: Process events asynchronously to avoid blocking the stream
- Resource Cleanup: Properly close streams and connections on shutdown
Current Limitations
- Data Retention: The node maintains only 24 hours of historical data
- Schema Coverage: The upstream event set can grow; treat the documented event and delta types as examples, not an exhaustive list
- Backpressure: High-volume periods may require careful handling to avoid overwhelming downstream systems
Resources
- GitHub: gRPC Code Examples - Complete working examples
- GetMiscEvents - Point-in-time miscellaneous event retrieval
- StreamFills - The sibling stream for trade executions; pair with misc events for complete balance coverage
- Hyperliquid L1 Data Schemas - Authoritative upstream event schema reference
Need help? Contact our support team or check the Hyperliquid gRPC documentation.
StreamFills - Real-time Fill Streaming
Stream continuous fill data from Hyperliquid L1 Gateway via gRPC. Monitor order executions in real-time.
StreamOrderStatuses - Real-time Order Status Streaming
Stream order lifecycle events from Hyperliquid L1 Gateway via gRPC. Track opens, fills, cancellations, and rejections per block in real time.