Build a Real-Time Robinhood Chain Whale Tracker in Python
Track whale trades on Robinhood Chain in real time. Subscribe to on-chain logs over Dwellir's WebSocket, decode large USDG and Stock Token transfers, and alert instantly.
Large trades move markets, and on Robinhood Chain they are all on-chain and public. Every Stock Token swap and every USDG settlement is an event log you can subscribe to in real time. In this tutorial you will build a whale tracker that streams those logs over a WebSocket, decodes the ones above a size threshold, and prints them the moment they land. It runs in about 150 lines of Python and works on any EVM chain, but Robinhood Chain is a good target because its tokenized stocks and USDG quote asset give you a clean, dollar-denominated view of whale activity.
Quick answer: Robinhood Chain is an EVM L2 (chain ID 4663), so you track whales the standard EVM way: open a WebSocket to an archive RPC,
eth_subscribetologsfor the tokens you care about, and decode ERC-20Transferevents. Filter for transfers above your threshold and you have a live whale feed. Dwellir provides the archive WebSocket endpoint this needs.
What Counts as a Whale Here
On a tokenized-stock chain, "whale" has a clean definition. USDG is the primary quote and settlement asset, so a large USDG transfer is a large trade in dollar terms. Watching USDG movement gives you a dollar-denominated whale feed without needing a price oracle. You can layer Stock Token transfers (NVDA, AAPL, and the rest) on top to see which assets the size is flowing into.
The approach generalizes. The same subscription that catches whale transfers is the foundation for a liquidation monitor, an arbitrage scanner, or a copy-trading bot. You are just changing which events you decode and what you do with them.
Prerequisites
- Python 3.10+
- A Robinhood Chain archive endpoint with WebSocket access. Sign up for Dwellir to get one, or use your own node.
- The
websocketsandweb3packages:pip install websockets web3 - Token contract addresses for USDG and any Stock Tokens you want to watch. Find these on the Robinhood Chain explorer.
How It Works
An ERC-20 transfer emits a Transfer(address indexed from, address indexed to, uint256 value) event. Every swap, deposit, and settlement produces one. Each log has:
topics[0]: the event signature hash, identical for every ERC-20Transfer.topics[1]andtopics[2]: the indexedfromandtoaddresses.data: the non-indexedvalue, a 32-byte integer.
Subscribe to logs filtered by the token address and that signature hash, decode the value, scale it by the token's decimals, and you have every transfer of that token in real time. Filter by size and you have whales.
Whale tracker data flow (left to right):
- Robinhood Chain (chain 4663)
- Dwellir WSS (eth_subscribe logs)
- Decode Transfer (value / decimals)
- Filter by size (> threshold)
- Whale alert (real-time)
Supporting: backfill history with the archive node via eth_getLogs.
Step 1: Connect and Subscribe
Open a WebSocket to the Dwellir endpoint and send an eth_subscribe request for logs. The filter restricts the stream to the tokens you care about and to the Transfer signature, so you are not decoding every log on the chain.
import asyncio
import json
import os
import websockets
from web3 import Web3
WSS_URL = os.environ["ROBINHOOD_WSS_URL"] # Dwellir Robinhood Chain WebSocket
# ERC-20 Transfer(address,address,uint256) signature hash
TRANSFER_TOPIC = Web3.keccak(text="Transfer(address,address,uint256)").hex()
# Tokens to watch. Fill in real Stock Token addresses from robinhoodchain.blockscout.com.
# Decimals differ per token: USDG uses 6, Stock Tokens use 18. Always confirm with a
# decimals() call rather than assuming, or a threshold check will be off by orders of magnitude.
TOKENS = {
"USDG": {"address": "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168", "decimals": 6, "threshold": 100_000},
"NVDA": {"address": "0x...", "decimals": 18, "threshold": 5_000},
"AAPL": {"address": "0x...", "decimals": 18, "threshold": 5_000},
}
# Reverse lookup by lowercased address
BY_ADDRESS = {t["address"].lower(): {"symbol": s, **t} for s, t in TOKENS.items()}
async def subscribe(ws):
request = {
"jsonrpc": "2.0",
"id": 1,
"method": "eth_subscribe",
"params": [
"logs",
{
"address": [t["address"] for t in TOKENS.values()],
"topics": [TRANSFER_TOPIC],
},
],
}
await ws.send(json.dumps(request))
ack = json.loads(await ws.recv())
print(f"Subscribed: {ack.get('result')}")The address array tells the node to only send logs from those contracts, and the single-element topics array matches any Transfer from them. This is far more efficient than streaming every log and filtering client-side.
Step 2: Decode Transfers and Flag Whales
Each incoming notification carries one log. Pull the token metadata by contract address, decode the from, to, and value, scale by decimals, and compare against that token's threshold.
def decode_transfer(log):
token = BY_ADDRESS.get(log["address"].lower())
if token is None:
return None
# topics[1] and topics[2] are 32-byte padded addresses
sender = "0x" + log["topics"][1][-40:]
recipient = "0x" + log["topics"][2][-40:]
raw_value = int(log["data"], 16)
amount = raw_value / (10 ** token["decimals"])
if amount < token["threshold"]:
return None
return {
"symbol": token["symbol"],
"amount": amount,
"from": Web3.to_checksum_address(sender),
"to": Web3.to_checksum_address(recipient),
"tx": log["transactionHash"],
"block": int(log["blockNumber"], 16),
}The threshold lives per token, so a $100,000 USDG move and a 5,000-share NVDA move can both count as whales even though the raw numbers differ by orders of magnitude. Scaling by decimals is what turns the on-chain integer into a human amount.
Step 3: The Main Loop
Connect, subscribe, then process notifications as they arrive. Each eth_subscription message contains one log.
async def track_whales():
async with websockets.connect(WSS_URL, max_size=None) as ws:
await subscribe(ws)
print("Watching for whales on Robinhood Chain...\n")
async for raw in ws:
message = json.loads(raw)
if message.get("method") != "eth_subscription":
continue
log = message["params"]["result"]
whale = decode_transfer(log)
if whale is None:
continue
print(
f"WHALE {whale['amount']:,.2f} {whale['symbol']} "
f"{whale['from'][:8]} -> {whale['to'][:8]} "
f"block {whale['block']} tx {whale['tx'][:12]}"
)
if __name__ == "__main__":
asyncio.run(track_whales())Run it, and every transfer above your thresholds prints the moment it is included in a block. Because Robinhood Chain has roughly 100ms preconfirmation latency, alerts arrive within a fraction of a second of the trade.
Backfilling History with the Archive Node
A live stream only sees new events. To chart whale activity over the past day or week, or to backtest a strategy, you need historical logs. This is where the archive node matters: it can serve eth_getLogs across old block ranges that a pruned node would reject.
from web3 import Web3
w3 = Web3(Web3.HTTPProvider(os.environ["ROBINHOOD_HTTP_URL"]))
logs = w3.eth.get_logs({
"fromBlock": 9_400_000,
"toBlock": "latest",
"address": Web3.to_checksum_address(TOKENS["USDG"]["address"]),
"topics": [TRANSFER_TOPIC],
})
print(f"Fetched {len(logs)} USDG transfers for analysis")Pair the live subscription with historical backfill and you have both a real-time feed and the dataset to put each whale trade in context.
Production Tips
- Reconnect on drop. WebSocket connections fail. Wrap the loop in a retry with backoff, and re-subscribe on reconnect. Track the last processed block so you can backfill the gap with
eth_getLogs. - Watch the DEX pools, not just tokens. To attribute a transfer to a specific venue like Arcus or Uniswap, add the pool and router addresses to your watch list and decode their
Swapevents for exact trade sides and prices. - Mind the pricing model. A busy backfill hammers
eth_getLogs, which is an expensive method under compute-unit pricing. Dwellir's flat per-request pricing keeps that cost predictable. - De-duplicate on reorgs. Even fast L2s can reorg. Key alerts on
(transactionHash, logIndex)and confirm a few blocks deep before treating an event as final.
Where to Take It Next
The same subscription pattern is the backbone of a whole class of tools:
- Liquidation tracker: decode lending-protocol liquidation events instead of transfers.
- Copy-trading bot: watch one target wallet's swaps and mirror them through the DEX router.
- Arbitrage scanner: subscribe to
Swapevents across multiple pools and compare prices.
Each is the same core loop with a different decoder and a different action.
Getting Started
You need two things to run this: the token addresses from the explorer, and an archive WebSocket endpoint. Sign up for Dwellir to get archive and WebSocket access to Robinhood Chain on flat pricing, or contact the team if you need dedicated nodes or colocated execution for a latency-sensitive strategy.
This content is for educational purposes only and does not constitute financial advice. Trading involves significant risk.
Polymarket API: The Complete Developer Guide
A developer's guide to the Polymarket API: discover markets with Gamma, read prices and place orders on the CLOB, stream fills, and read positions on Polygon.
How to Build a Copy Trading Bot on Arcus (Robinhood Chain)
Build a copy trading bot for Arcus on Robinhood Chain. Detect a target wallet's Stock Token trades on-chain over WebSocket, then mirror them through the Arcus spot flow.