robinhood-chain-sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/stream.js ADDED
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Real-time WebSocket streaming client for Robinhood Chain (chain id 4663).
3
+ *
4
+ * Wraps the connect → token → subscribe → event loop with auto-reconnect,
5
+ * 24h-token auto-refresh, heartbeat liveness, and typed events, so consumers
6
+ * never hand-roll connection management. Obtain one via `client.stream.connect()`.
7
+ *
8
+ * Works in Node (global `WebSocket` on Node 22+, else lazily imports the
9
+ * optional `ws` package) and the browser (native WebSocket). Zero required deps.
10
+ */
11
+ async function resolveWebSocket(override) {
12
+ if (override)
13
+ return override;
14
+ // Prefer the `ws` package in Node: it exposes terminate() for an immediate
15
+ // socket teardown, so close() lets short-lived processes exit. The global
16
+ // (undici) WebSocket on Node 22+ keeps its TLS socket open after close() —
17
+ // it has no terminate() and no reachable socket handle — which hangs the
18
+ // event loop. In the browser this import rejects and we fall back to the
19
+ // platform's native WebSocket.
20
+ try {
21
+ const mod = (await import("ws"));
22
+ const impl = mod.default ?? mod.WebSocket;
23
+ if (impl)
24
+ return impl;
25
+ }
26
+ catch {
27
+ /* not Node, or `ws` not installed — fall back to the platform WebSocket */
28
+ }
29
+ const g = globalThis.WebSocket;
30
+ if (g)
31
+ return g;
32
+ throw new Error("No WebSocket implementation available. On Node < 22, install `ws` (npm i ws) or pass { WebSocketImpl }.");
33
+ }
34
+ const OPEN = 1;
35
+ export class RobinhoodStream {
36
+ constructor(opts) {
37
+ this.ws = null;
38
+ this.listeners = new Map();
39
+ this.desired = { channels: new Set(), filters: {} };
40
+ this.closedByUser = false;
41
+ this.attempt = 0;
42
+ this.hbTimer = null;
43
+ this.reconnectTimer = null;
44
+ this.connecting = false;
45
+ this.opts = {
46
+ getToken: opts.getToken,
47
+ autoReconnect: opts.autoReconnect ?? true,
48
+ maxBackoffMs: opts.maxBackoffMs ?? 30000,
49
+ heartbeatTimeoutMs: opts.heartbeatTimeoutMs ?? 90000,
50
+ WebSocketImpl: opts.WebSocketImpl,
51
+ };
52
+ }
53
+ /** Register a handler. Use an event name, `"*"` for every event, or a lifecycle event. */
54
+ on(event, fn) {
55
+ if (!this.listeners.has(event))
56
+ this.listeners.set(event, new Set());
57
+ this.listeners.get(event).add(fn);
58
+ return this;
59
+ }
60
+ /** Remove a handler (or all handlers for an event when `fn` is omitted). */
61
+ off(event, fn) {
62
+ if (!fn)
63
+ this.listeners.delete(event);
64
+ else
65
+ this.listeners.get(event)?.delete(fn);
66
+ return this;
67
+ }
68
+ emit(event, data, evt) {
69
+ const set = this.listeners.get(event);
70
+ if (set)
71
+ for (const fn of set) {
72
+ try {
73
+ fn(data, evt);
74
+ }
75
+ catch { /* user handler */ }
76
+ }
77
+ }
78
+ /** Subscribe to one or more channels (connects on first call). Optional server-side filters. */
79
+ subscribe(channels, filters) {
80
+ for (const c of channels)
81
+ this.desired.channels.add(c);
82
+ if (filters)
83
+ this.desired.filters = { ...this.desired.filters, ...filters };
84
+ if (this.ws && this.ws.readyState === OPEN)
85
+ this.sendSubscribe();
86
+ else
87
+ void this.connect();
88
+ return this;
89
+ }
90
+ /** Stop receiving the given channels. */
91
+ unsubscribe(channels) {
92
+ for (const c of channels)
93
+ this.desired.channels.delete(c);
94
+ if (this.ws && this.ws.readyState === OPEN) {
95
+ this.ws.send(JSON.stringify({ type: "unsubscribe", channels }));
96
+ }
97
+ return this;
98
+ }
99
+ /** Open the connection (also called implicitly by subscribe). */
100
+ async connect() {
101
+ if (this.connecting || (this.ws && this.ws.readyState === OPEN))
102
+ return;
103
+ this.closedByUser = false;
104
+ this.connecting = true;
105
+ try {
106
+ const [WS, token] = await Promise.all([
107
+ resolveWebSocket(this.opts.WebSocketImpl),
108
+ this.opts.getToken(),
109
+ ]);
110
+ const url = `${token.ws_url}?token=${encodeURIComponent(token.token)}`;
111
+ const ws = new WS(url);
112
+ this.ws = ws;
113
+ ws.onopen = () => {
114
+ this.attempt = 0;
115
+ this.resetHeartbeat();
116
+ if (this.desired.channels.size > 0)
117
+ this.sendSubscribe();
118
+ this.emit("open", undefined);
119
+ };
120
+ ws.onmessage = (ev) => this.handleMessage(ev.data);
121
+ ws.onerror = (err) => this.emit("error", err instanceof Error ? err : new Error("WebSocket error"));
122
+ ws.onclose = (ev) => {
123
+ this.clearHeartbeat();
124
+ this.ws = null;
125
+ this.emit("close", { code: ev?.code, reason: ev?.reason });
126
+ if (!this.closedByUser && this.opts.autoReconnect)
127
+ this.scheduleReconnect();
128
+ };
129
+ }
130
+ catch (err) {
131
+ this.emit("error", err);
132
+ if (!this.closedByUser && this.opts.autoReconnect)
133
+ this.scheduleReconnect();
134
+ }
135
+ finally {
136
+ this.connecting = false;
137
+ }
138
+ }
139
+ /** Close the connection and stop reconnecting. */
140
+ close() {
141
+ this.closedByUser = true;
142
+ if (this.reconnectTimer) {
143
+ clearTimeout(this.reconnectTimer);
144
+ this.reconnectTimer = null;
145
+ }
146
+ this.clearHeartbeat();
147
+ const sock = this.ws;
148
+ this.ws = null;
149
+ try {
150
+ // `ws` package: terminate() destroys the underlying socket immediately so
151
+ // the process can exit. Native/undici WebSocket has no terminate() — fall
152
+ // back to a graceful close().
153
+ if (typeof sock?.terminate === "function")
154
+ sock.terminate();
155
+ else
156
+ sock?.close(1000, "client closed");
157
+ }
158
+ catch { /* ignore */ }
159
+ }
160
+ sendSubscribe() {
161
+ const channels = Array.from(this.desired.channels);
162
+ if (channels.length === 0)
163
+ return;
164
+ const msg = { type: "subscribe", channels };
165
+ if (Object.keys(this.desired.filters).length > 0)
166
+ msg.filters = this.desired.filters;
167
+ this.ws?.send(JSON.stringify(msg));
168
+ }
169
+ handleMessage(raw) {
170
+ let msg;
171
+ try {
172
+ const text = typeof raw === "string" ? raw : String(raw);
173
+ msg = JSON.parse(text);
174
+ }
175
+ catch {
176
+ this.emit("error", new Error("Failed to parse stream message"));
177
+ return;
178
+ }
179
+ if (msg.type === "heartbeat") {
180
+ this.resetHeartbeat();
181
+ this.emit("heartbeat", msg.ts);
182
+ return;
183
+ }
184
+ if (msg.type === "connected") {
185
+ return;
186
+ }
187
+ if (msg.type === "subscribed") {
188
+ this.emit("subscribed", msg.channels);
189
+ return;
190
+ }
191
+ if (msg.channel && msg.event) {
192
+ const evt = msg;
193
+ this.emit(evt.event, evt.data, evt);
194
+ this.emit("*", evt.data, evt);
195
+ }
196
+ }
197
+ scheduleReconnect() {
198
+ if (this.reconnectTimer)
199
+ return;
200
+ const base = Math.min(1000 * 2 ** this.attempt, this.opts.maxBackoffMs);
201
+ const delay = base / 2 + Math.floor((base / 2) * Math.random());
202
+ this.attempt++;
203
+ this.emit("reconnect", { attempt: this.attempt, delayMs: delay });
204
+ this.reconnectTimer = setTimeout(() => {
205
+ this.reconnectTimer = null;
206
+ void this.connect();
207
+ }, delay);
208
+ }
209
+ resetHeartbeat() {
210
+ this.clearHeartbeat();
211
+ this.hbTimer = setTimeout(() => {
212
+ try {
213
+ this.ws?.close(4000, "heartbeat timeout");
214
+ }
215
+ catch { /* ignore */ }
216
+ }, this.opts.heartbeatTimeoutMs);
217
+ }
218
+ clearHeartbeat() {
219
+ if (this.hbTimer) {
220
+ clearTimeout(this.hbTimer);
221
+ this.hbTimer = null;
222
+ }
223
+ }
224
+ }
225
+ //# sourceMappingURL=stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const VERSION = "0.1.0";
2
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,OAAO,UAAU,CAAC"}
@@ -0,0 +1,4 @@
1
+ // AUTO-GENERATED by scripts/gen-version.mjs — do not edit by hand.
2
+ // Regenerated from package.json on every `npm run build` (prebuild hook).
3
+ export const VERSION = "0.1.0";
4
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,0EAA0E;AAC1E,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
package/llms.txt ADDED
@@ -0,0 +1,71 @@
1
+ # robinhood-chain-sdk
2
+
3
+ > Official TypeScript SDK for the Robinhood Chain (chain id 4663) API — EVM-native on-chain trading intelligence.
4
+
5
+ ## What is Robinhood Chain?
6
+
7
+ Robinhood Chain (RHC) is an Arbitrum Orbit L2, chain id 4663. MadeOnSol (https://madeonsol.com/robinhood) runs a self-hosted node and exposes EVM-native intelligence over the same paid v1 API and the same `msk_` API key as the Solana product — bundled into every tier at no extra cost. All addresses are lowercase `0x`, amounts are `eth_amount`, transactions are `tx_hash`, and blocks are `block_number`.
8
+
9
+ - **KOL Trades**: live buy/sell feed from tracked Solana KOLs' verified EVM wallets, a KOL activity leaderboard, consensus "hot tokens" (2+ KOLs), and per-KOL profiles.
10
+ - **Tokens**: token discovery, per-token snapshot (price/MC/FDV/peak/drawdown, deployer reputation, KOL activity, pools), 1-minute OHLC candles, KOL consensus (`net_flow_eth`), early-buyer quality (0–100), and same-block launch-bundle detection.
11
+ - **DEX Trade Tape**: every Uniswap v2/v3/v4 swap with the real trader EOA (tx.from), gas/ordering for MEV analysis, and KOL/deployer flags.
12
+ - **Deployer Hunter**: reputation leaderboard + per-deployer profiles (graduation = $40K peak MC, runner = $100K).
13
+ - **Alpha Wallets**: smart-money ranking by realized on-chain performance (net ETH, win rate, memecoin share), with bot-fleet flagging.
14
+ - **Streaming**: managed WebSocket for `rhc:kol_trades` and `rhc:trades`.
15
+
16
+ ## Installation
17
+
18
+ ```
19
+ npm install robinhood-chain-sdk
20
+ ```
21
+
22
+ ## Authentication
23
+
24
+ Get a free API key at https://madeonsol.com/developer (starts with `msk_`).
25
+
26
+ ```typescript
27
+ import { RobinhoodClient } from "robinhood-chain-sdk";
28
+ const client = new RobinhoodClient({ apiKey: "msk_your_api_key_here" });
29
+ ```
30
+
31
+ ## Methods (all 14 endpoints)
32
+
33
+ ### KOL (client.kol) — BASIC
34
+ - `client.kol.feed(params?)` — GET /rhc/kol/feed — live KOL trade feed
35
+ - `client.kol.leaderboard(params?)` — GET /rhc/kol/leaderboard — KOL activity leaderboard
36
+ - `client.kol.hotTokens(params?)` — GET /rhc/kol/hot-tokens — tokens bought by 2+ KOLs
37
+ - `client.kol.wallet(wallet)` — GET /rhc/kol/{wallet} — single KOL profile
38
+
39
+ ### DEX tape (client.trades) — PRO+
40
+ - `client.trades(params?)` — GET /rhc/trades — Uniswap v2/v3/v4 trade tape
41
+
42
+ ### Tokens (client.tokens)
43
+ - `client.tokens.list(params?)` — GET /rhc/tokens — token discovery (PRO+)
44
+ - `client.tokens.get(address)` — GET /rhc/tokens/{address} — token snapshot (BASIC)
45
+ - `client.tokens.candles(address, params?)` — GET /rhc/tokens/{address}/candles — 1m OHLC (PRO+)
46
+ - `client.tokens.kolConsensus(address)` — GET /rhc/tokens/{address}/kol-consensus (PRO+)
47
+ - `client.tokens.buyerQuality(address)` — GET /rhc/tokens/{address}/buyer-quality (BASIC)
48
+ - `client.tokens.bundle(address)` — GET /rhc/tokens/{address}/bundle — launch-bundle detection (BASIC)
49
+
50
+ ### Deployer Hunter (client.deployerHunter) — BASIC
51
+ - `client.deployerHunter.leaderboard(params?)` — GET /rhc/deployer-hunter/leaderboard
52
+ - `client.deployerHunter.profile(address)` — GET /rhc/deployer-hunter/{address}
53
+
54
+ ### Alpha Wallets (client.alphaWallets) — PRO+
55
+ - `client.alphaWallets(params?)` — GET /rhc/alpha-wallets — smart-money ranking
56
+
57
+ ### Streaming (client.stream) — PRO+
58
+ - `client.stream.getToken()` — POST /stream/token — 24h WS token
59
+ - `client.stream.connect()` — managed WebSocket (channels: rhc:kol_trades, rhc:trades)
60
+
61
+ ## Error handling
62
+
63
+ All methods throw `RobinhoodError` with `.message`, `.status`, `.body`, and `.requestId` (`_rid`). 429 and 5xx responses are retried automatically with backoff.
64
+
65
+ ## Links
66
+
67
+ - Robinhood Chain: https://madeonsol.com/robinhood
68
+ - Pricing: https://madeonsol.com/pricing
69
+ - API docs: https://madeonsol.com/api-docs
70
+ - npm: https://www.npmjs.com/package/robinhood-chain-sdk
71
+ - GitHub: https://github.com/madeonsol/robinhood-chain-sdk
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "robinhood-chain-sdk",
3
+ "version": "0.1.0",
4
+ "description": "Official TypeScript SDK for the Robinhood Chain (chain id 4663) API — EVM-native on-chain trading intelligence: live KOL trades, token discovery & bundles, the DEX trade tape, OHLC candles, deployer reputation, and smart-money wallets. Zero dependencies.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "llms.txt"
17
+ ],
18
+ "scripts": {
19
+ "gen-version": "node scripts/gen-version.mjs",
20
+ "prebuild": "node scripts/gen-version.mjs",
21
+ "build": "tsc",
22
+ "test": "tsc -p examples/tsconfig.json",
23
+ "route-parity": "node scripts/route-parity-check.mjs",
24
+ "preflight": "bash ./scripts/preflight-publish.sh",
25
+ "prepublishOnly": "npm run preflight && npm run build"
26
+ },
27
+ "keywords": [
28
+ "robinhood chain",
29
+ "robinhood-chain",
30
+ "rhc",
31
+ "robinhood chain api",
32
+ "robinhood chain sdk",
33
+ "robinhood-chain-sdk",
34
+ "chain-4663",
35
+ "chain-id-4663",
36
+ "evm",
37
+ "arbitrum-orbit",
38
+ "kol",
39
+ "kol-tracker",
40
+ "deployer-hunter",
41
+ "smart-money",
42
+ "alpha-wallets",
43
+ "memecoin",
44
+ "memecoin-tracker",
45
+ "defi",
46
+ "web3",
47
+ "trading",
48
+ "trade-stream",
49
+ "dex",
50
+ "sdk",
51
+ "api",
52
+ "madeonsol"
53
+ ],
54
+ "license": "MIT",
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "https://github.com/madeonsol/robinhood-chain-sdk.git"
58
+ },
59
+ "homepage": "https://madeonsol.com/robinhood",
60
+ "bugs": {
61
+ "url": "https://github.com/madeonsol/robinhood-chain-sdk/issues"
62
+ },
63
+ "engines": {
64
+ "node": ">=18"
65
+ },
66
+ "optionalDependencies": {
67
+ "ws": "^8.0.0"
68
+ },
69
+ "devDependencies": {
70
+ "@types/node": "^20.0.0",
71
+ "typescript": "^5.4.0"
72
+ },
73
+ "funding": "https://madeonsol.com"
74
+ }