@ironflowsh/mcp 0.8.3 → 0.11.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/README.md +37 -23
- package/build/api.d.ts +36 -9
- package/build/api.d.ts.map +1 -1
- package/build/api.js +120 -48
- package/build/api.js.map +1 -1
- package/build/http.js +28 -5
- package/build/http.js.map +1 -1
- package/build/index.js +4 -3
- package/build/index.js.map +1 -1
- package/build/notice.d.ts +10 -0
- package/build/notice.d.ts.map +1 -0
- package/build/notice.js +82 -0
- package/build/notice.js.map +1 -0
- package/build/query.d.ts +24 -0
- package/build/query.d.ts.map +1 -0
- package/build/query.js +117 -0
- package/build/query.js.map +1 -0
- package/build/schemas.d.ts.map +1 -1
- package/build/schemas.js +62 -5
- package/build/schemas.js.map +1 -1
- package/build/server.d.ts +9 -1
- package/build/server.d.ts.map +1 -1
- package/build/server.js +29 -10
- package/build/server.js.map +1 -1
- package/build/shape.d.ts +14 -3
- package/build/shape.d.ts.map +1 -1
- package/build/shape.js +28 -12
- package/build/shape.js.map +1 -1
- package/build/tools.d.ts +1 -0
- package/build/tools.d.ts.map +1 -1
- package/build/tools.js +235 -73
- package/build/tools.js.map +1 -1
- package/build/usage.d.ts +15 -0
- package/build/usage.d.ts.map +1 -0
- package/build/usage.js +66 -0
- package/build/usage.js.map +1 -0
- package/package.json +1 -1
package/build/tools.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// MCP tool definitions for Ironflow market data.
|
|
2
2
|
import { MAX_SUMMARY_MINUTES, summarizeLiquidations } from "./liquidations.js";
|
|
3
3
|
import { MAX_LIMIT, rankSnapshot, SORT_KEYS } from "./snapshot.js";
|
|
4
|
-
import {
|
|
4
|
+
import { BEHAVIOR_LABELS, BEHAVIOR_SORT_KEYS, behaviorSQL, MAX_BEHAVIOR_LIMIT, MAX_VAULT_LEADERBOARD_LIMIT, rowsToObjects, runQuery, VAULT_LEADERBOARD_DAYS, vaultLeaderboardSQL, } from "./query.js";
|
|
5
|
+
import { DEFAULT_FUNDING_ROWS, DEFAULT_MARKETS_LIMIT, MAX_MARKETS_LIMIT, shapeMarkets, shapeUserFunding, shapeWalletLabels } from "./shape.js";
|
|
5
6
|
// ─── Arg validation helpers ──────────────────────────────────────────────────
|
|
6
7
|
function requireString(args, key) {
|
|
7
8
|
const val = args[key];
|
|
@@ -29,15 +30,111 @@ function optionalString(args, key, defaultVal) {
|
|
|
29
30
|
}
|
|
30
31
|
return val;
|
|
31
32
|
}
|
|
33
|
+
function optionalBoolean(args, key) {
|
|
34
|
+
const val = args[key];
|
|
35
|
+
if (val === undefined || val === null)
|
|
36
|
+
return false;
|
|
37
|
+
if (typeof val === "boolean")
|
|
38
|
+
return val;
|
|
39
|
+
if (val === "true" || val === "false")
|
|
40
|
+
return val === "true";
|
|
41
|
+
throw new Error(`"${key}" must be true or false`);
|
|
42
|
+
}
|
|
43
|
+
// optionalTime reads a window bound and passes it on as the caller wrote it:
|
|
44
|
+
// the API takes Unix ms, Unix seconds and ISO 8601 (UTC when no zone is
|
|
45
|
+
// given), so nothing is converted here. "" means not set.
|
|
46
|
+
function optionalTime(args, key) {
|
|
47
|
+
const val = args[key];
|
|
48
|
+
if (val === undefined || val === null || val === 0)
|
|
49
|
+
return "";
|
|
50
|
+
const invalid = new Error(`"${key}" must be Unix ms, Unix seconds or an ISO 8601 date such as 2026-10-01T00:00:00Z`);
|
|
51
|
+
if (typeof val === "number") {
|
|
52
|
+
if (!Number.isFinite(val) || val < 0)
|
|
53
|
+
throw invalid;
|
|
54
|
+
return String(Math.floor(val));
|
|
55
|
+
}
|
|
56
|
+
if (typeof val !== "string")
|
|
57
|
+
throw invalid;
|
|
58
|
+
const text = val.trim();
|
|
59
|
+
if (/^\d*$/.test(text))
|
|
60
|
+
return Number(text) > 0 ? text : "";
|
|
61
|
+
// The API reads 2026-10-01, 2026-10-01T12:00 and RFC 3339 date-times.
|
|
62
|
+
if (!/^\d{4}-\d{2}-\d{2}(T|$)/.test(text) || Number.isNaN(Date.parse(text)))
|
|
63
|
+
throw invalid;
|
|
64
|
+
return text;
|
|
65
|
+
}
|
|
66
|
+
// Shared parameter descriptions. The API resolves Hyperliquid names itself.
|
|
67
|
+
const MARKET = "Market: BTC-PERP, xyz:NVDA-PERP, HYPE/USDC, or a Hyperliquid name (BTC, @107, xyz:NVDA)";
|
|
68
|
+
const MARKET_FILTER = "Optional market filter: BTC-PERP or a Hyperliquid name (BTC, xyz:NVDA)";
|
|
69
|
+
const time = (bound, extra = "") => `Window ${bound}: Unix ms or seconds, or ISO 8601 (2026-10-01T00:00:00Z)${extra ? `. ${extra}` : ""}`;
|
|
32
70
|
// ─── Tools ──────────────────────────────────────────────────────────────────
|
|
33
71
|
export const tools = [
|
|
72
|
+
{
|
|
73
|
+
name: "describe_data",
|
|
74
|
+
title: "Describe SQL tables",
|
|
75
|
+
description: "Start here for any Hyperliquid question the other tools do not answer directly. Returns the SQL tables you can query with run_query (every fill, per-wallet daily totals, wallet behaviour labels, funding, mark and oracle prices, open interest, liquidations, builder-code fills, transfers, vault flows), their columns, how far back each goes, query tips, worked examples and your own limits.",
|
|
76
|
+
inputSchema: { type: "object", properties: {}, required: [] },
|
|
77
|
+
handler: async (_args, api) => JSON.stringify(await api.get("/v1/query/schema")),
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "run_query",
|
|
81
|
+
title: "Run SQL query",
|
|
82
|
+
description: "Run one read-only ClickHouse SELECT over Ironflow's Hyperliquid tables (hl.fills, hl.wallet_daily, hl.wallet_behavior, hl.funding, hl.mark_prices, hl.oracle_prices, hl.open_interest, hl.liquidations, hl.builder_fills, hl.transfers, hl.vault_operations). Call describe_data first for columns and examples. Aggregate in SQL: results are capped (1,000 rows keyless). Keyless: last 24 hours, 5 s per query, 60 query seconds per hour per IP; a free key from https://ironflow.sh/key gives 30 days of history.",
|
|
83
|
+
inputSchema: {
|
|
84
|
+
type: "object",
|
|
85
|
+
properties: {
|
|
86
|
+
sql: { type: "string", description: "One ClickHouse SELECT (or WITH ... SELECT) over hl.* tables, without a FORMAT clause" },
|
|
87
|
+
max_rows: { type: "number", description: "Most rows to return (default 200, capped by your tier)" },
|
|
88
|
+
},
|
|
89
|
+
required: ["sql"],
|
|
90
|
+
},
|
|
91
|
+
handler: async (args, api) => {
|
|
92
|
+
const sql = requireString(args, "sql");
|
|
93
|
+
const maxRows = optionalNumber(args, "max_rows", 200);
|
|
94
|
+
return JSON.stringify(await runQuery(api, sql, maxRows));
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "get_wallet_behavior",
|
|
99
|
+
title: "Wallet behavior labels",
|
|
100
|
+
description: "How Hyperliquid wallets trade, from their last 30 days: labels (market_maker, high_frequency, whale, directional, consistent_winner, big_loser, revenge_sizing, often_liquidated, hip3_trader, spot_trader, prediction_trader) and the numbers behind them (maker share, buy/sell imbalance, fills per day, green-day share, profit factor, liquidations). Look up specific addresses, or list wallets with one label.",
|
|
101
|
+
inputSchema: {
|
|
102
|
+
type: "object",
|
|
103
|
+
properties: {
|
|
104
|
+
addresses: { type: "string", description: "Comma-separated wallet addresses (up to 50). Omit to list wallets instead." },
|
|
105
|
+
label: { type: "string", description: "Only wallets carrying this label", enum: [...BEHAVIOR_LABELS] },
|
|
106
|
+
sort_by: { type: "string", description: "Sort order when listing (default volume)", enum: [...BEHAVIOR_SORT_KEYS] },
|
|
107
|
+
min_volume_usd: { type: "number", description: "Only wallets with at least this 30-day volume" },
|
|
108
|
+
limit: { type: "number", description: `Wallets to return (default 20, max ${MAX_BEHAVIOR_LIMIT})` },
|
|
109
|
+
},
|
|
110
|
+
required: [],
|
|
111
|
+
},
|
|
112
|
+
handler: async (args, api) => {
|
|
113
|
+
const addresses = optionalString(args, "addresses", "")
|
|
114
|
+
.split(",")
|
|
115
|
+
.map((a) => a.trim())
|
|
116
|
+
.filter(Boolean);
|
|
117
|
+
const sortBy = optionalString(args, "sort_by", "volume");
|
|
118
|
+
const minVol = args.min_volume_usd === undefined ? 0 : Number(args.min_volume_usd);
|
|
119
|
+
const sql = behaviorSQL({
|
|
120
|
+
addresses,
|
|
121
|
+
label: optionalString(args, "label", ""),
|
|
122
|
+
sortBy,
|
|
123
|
+
limit: optionalNumber(args, "limit", addresses.length || 20),
|
|
124
|
+
minVolumeUsd: minVol,
|
|
125
|
+
});
|
|
126
|
+
const res = (await runQuery(api, sql, MAX_BEHAVIOR_LIMIT));
|
|
127
|
+
return JSON.stringify({ window_days: 30, wallets: rowsToObjects(res) });
|
|
128
|
+
},
|
|
129
|
+
},
|
|
34
130
|
{
|
|
35
131
|
name: "get_price",
|
|
132
|
+
title: "Market price",
|
|
36
133
|
description: "Latest mark price of a Hyperliquid market: native perps, HIP-3 builder perps (e.g. xyz:NVDA-PERP) and spot.",
|
|
37
134
|
inputSchema: {
|
|
38
135
|
type: "object",
|
|
39
136
|
properties: {
|
|
40
|
-
market: { type: "string", description:
|
|
137
|
+
market: { type: "string", description: MARKET },
|
|
41
138
|
},
|
|
42
139
|
required: ["market"],
|
|
43
140
|
},
|
|
@@ -49,11 +146,12 @@ export const tools = [
|
|
|
49
146
|
},
|
|
50
147
|
{
|
|
51
148
|
name: "get_recent_trades",
|
|
149
|
+
title: "Recent trades",
|
|
52
150
|
description: "Latest tick-level trades on a Hyperliquid market from our own nodes: price, size, side and block time. Covers native perps, HIP-3 builder markets, HIP-4 outcomes and spot.",
|
|
53
151
|
inputSchema: {
|
|
54
152
|
type: "object",
|
|
55
153
|
properties: {
|
|
56
|
-
market: { type: "string", description:
|
|
154
|
+
market: { type: "string", description: MARKET },
|
|
57
155
|
limit: { type: "number", description: "Number of trades to return (1-100, default 20)" },
|
|
58
156
|
},
|
|
59
157
|
required: ["market"],
|
|
@@ -67,11 +165,12 @@ export const tools = [
|
|
|
67
165
|
},
|
|
68
166
|
{
|
|
69
167
|
name: "get_candles",
|
|
168
|
+
title: "Candles (OHLCV)",
|
|
70
169
|
description: "OHLCV candles for a Hyperliquid market, computed from tick-level trades.",
|
|
71
170
|
inputSchema: {
|
|
72
171
|
type: "object",
|
|
73
172
|
properties: {
|
|
74
|
-
market: { type: "string", description:
|
|
173
|
+
market: { type: "string", description: MARKET },
|
|
75
174
|
interval: { type: "string", description: "Candle interval (1m, 5m, 15m, 1h, 4h, 1d). Default: 1h", enum: ["1m", "5m", "15m", "1h", "4h", "1d"] },
|
|
76
175
|
limit: { type: "number", description: "Number of candles to return (1-500, default 24)" },
|
|
77
176
|
},
|
|
@@ -87,11 +186,12 @@ export const tools = [
|
|
|
87
186
|
},
|
|
88
187
|
{
|
|
89
188
|
name: "get_funding_rates",
|
|
189
|
+
title: "Funding rate history",
|
|
90
190
|
description: "Hourly funding rate history for a Hyperliquid perp, including HIP-3 builder perps. A positive rate means longs pay shorts.",
|
|
91
191
|
inputSchema: {
|
|
92
192
|
type: "object",
|
|
93
193
|
properties: {
|
|
94
|
-
market: { type: "string", description:
|
|
194
|
+
market: { type: "string", description: MARKET },
|
|
95
195
|
limit: { type: "number", description: "Number of funding rate entries (1-100, default 10)" },
|
|
96
196
|
},
|
|
97
197
|
required: ["market"],
|
|
@@ -105,11 +205,12 @@ export const tools = [
|
|
|
105
205
|
},
|
|
106
206
|
{
|
|
107
207
|
name: "get_open_interest",
|
|
108
|
-
|
|
208
|
+
title: "Open interest",
|
|
209
|
+
description: "Latest open interest of a Hyperliquid perp, in base units, with its 24h volume in USD.",
|
|
109
210
|
inputSchema: {
|
|
110
211
|
type: "object",
|
|
111
212
|
properties: {
|
|
112
|
-
market: { type: "string", description:
|
|
213
|
+
market: { type: "string", description: MARKET },
|
|
113
214
|
},
|
|
114
215
|
required: ["market"],
|
|
115
216
|
},
|
|
@@ -121,11 +222,12 @@ export const tools = [
|
|
|
121
222
|
},
|
|
122
223
|
{
|
|
123
224
|
name: "get_liquidations",
|
|
225
|
+
title: "Liquidations",
|
|
124
226
|
description: "Liquidations on a Hyperliquid perp, read from our own nodes: price, size, side and the liquidated wallet. Hyperliquid's public API has no liquidation feed.",
|
|
125
227
|
inputSchema: {
|
|
126
228
|
type: "object",
|
|
127
229
|
properties: {
|
|
128
|
-
market: { type: "string", description:
|
|
230
|
+
market: { type: "string", description: MARKET },
|
|
129
231
|
limit: { type: "number", description: "Number of liquidation events (1-100, default 20)" },
|
|
130
232
|
},
|
|
131
233
|
required: ["market"],
|
|
@@ -140,12 +242,13 @@ export const tools = [
|
|
|
140
242
|
// ─── Additional Market Data ──────────────────────────────────────────
|
|
141
243
|
{
|
|
142
244
|
name: "get_liquidation_summary",
|
|
245
|
+
title: "Liquidation summary",
|
|
143
246
|
description: "Liquidations across every Hyperliquid market (or one market) over the last N minutes, totalled: count, notional, longs vs shorts liquidated, the top markets and the largest single liquidation. Use it for 'who got liquidated in the last hour?'. Keyless calls can look back 60 minutes, keyed calls up to 240.",
|
|
144
247
|
inputSchema: {
|
|
145
248
|
type: "object",
|
|
146
249
|
properties: {
|
|
147
250
|
minutes: { type: "number", description: "Lookback in minutes (default 60, max 240)" },
|
|
148
|
-
market: { type: "string", description:
|
|
251
|
+
market: { type: "string", description: MARKET_FILTER },
|
|
149
252
|
},
|
|
150
253
|
required: [],
|
|
151
254
|
},
|
|
@@ -160,12 +263,13 @@ export const tools = [
|
|
|
160
263
|
},
|
|
161
264
|
{
|
|
162
265
|
name: "get_fills",
|
|
266
|
+
title: "Wallet fills",
|
|
163
267
|
description: "Every fill for one Hyperliquid wallet, optionally for one market, from indexed history: price, size, side, fee and realized PnL. Hyperliquid's own userFills endpoints stop at the 10,000 most recent fills.",
|
|
164
268
|
inputSchema: {
|
|
165
269
|
type: "object",
|
|
166
270
|
properties: {
|
|
167
271
|
address: { type: "string", description: "Wallet address (e.g. 0x...)" },
|
|
168
|
-
market: { type: "string", description:
|
|
272
|
+
market: { type: "string", description: MARKET_FILTER },
|
|
169
273
|
limit: { type: "number", description: "Number of fills (1-100, default 20)" },
|
|
170
274
|
},
|
|
171
275
|
required: ["address"],
|
|
@@ -180,11 +284,12 @@ export const tools = [
|
|
|
180
284
|
},
|
|
181
285
|
{
|
|
182
286
|
name: "get_mark_prices",
|
|
183
|
-
|
|
287
|
+
title: "Mark and oracle price",
|
|
288
|
+
description: "Latest mark price, oracle price and hourly funding rate of a Hyperliquid perp.",
|
|
184
289
|
inputSchema: {
|
|
185
290
|
type: "object",
|
|
186
291
|
properties: {
|
|
187
|
-
market: { type: "string", description:
|
|
292
|
+
market: { type: "string", description: MARKET },
|
|
188
293
|
},
|
|
189
294
|
required: ["market"],
|
|
190
295
|
},
|
|
@@ -196,19 +301,25 @@ export const tools = [
|
|
|
196
301
|
},
|
|
197
302
|
{
|
|
198
303
|
name: "get_vault_operations",
|
|
199
|
-
|
|
304
|
+
title: "Vault deposits and withdrawals",
|
|
305
|
+
description: "Deposits into and withdrawals from one Hyperliquid vault or one depositor. Pass vault, address, or both; at least one is required (HLP is 0xdfc24b077bc1425ad1dea75bcb6f8158e10df303). For flows across all vaults use get_vault_leaderboard.",
|
|
200
306
|
inputSchema: {
|
|
201
307
|
type: "object",
|
|
202
308
|
properties: {
|
|
203
|
-
vault: { type: "string", description: "Vault address" },
|
|
204
|
-
address: { type: "string", description: "
|
|
309
|
+
vault: { type: "string", description: "Vault address (vault or address is required)" },
|
|
310
|
+
address: { type: "string", description: "Depositor address (vault or address is required)" },
|
|
205
311
|
limit: { type: "number", description: "Number of events (1-100, default 20)" },
|
|
206
312
|
},
|
|
207
313
|
required: [],
|
|
208
314
|
},
|
|
209
315
|
handler: async (args, api) => {
|
|
210
|
-
|
|
211
|
-
|
|
316
|
+
// The API stores addresses lowercase and answers 400 when neither
|
|
317
|
+
// filter is set, so check here and say what to pass.
|
|
318
|
+
const vault = optionalString(args, "vault", "").trim().toLowerCase();
|
|
319
|
+
const address = optionalString(args, "address", "").trim().toLowerCase();
|
|
320
|
+
if (!vault && !address) {
|
|
321
|
+
throw new Error('Pass "vault" (a vault address, e.g. HLP 0xdfc24b077bc1425ad1dea75bcb6f8158e10df303) or "address" (a depositor), or both. For flows across all vaults use get_vault_leaderboard.');
|
|
322
|
+
}
|
|
212
323
|
const limit = optionalNumber(args, "limit", 20);
|
|
213
324
|
const data = await api.getVaultOperations(vault, address, String(limit));
|
|
214
325
|
return JSON.stringify(data, null, 2);
|
|
@@ -217,11 +328,12 @@ export const tools = [
|
|
|
217
328
|
// ─── Analytics ───────────────────────────────────────────────────────
|
|
218
329
|
{
|
|
219
330
|
name: "get_liquidation_levels",
|
|
331
|
+
title: "Liquidation levels",
|
|
220
332
|
description: "Liquidated notional on a Hyperliquid perp bucketed by price: where longs and shorts were wiped out. Needs a Builder or Enterprise key; keyless and free-key calls return 403.",
|
|
221
333
|
inputSchema: {
|
|
222
334
|
type: "object",
|
|
223
335
|
properties: {
|
|
224
|
-
market: { type: "string", description:
|
|
336
|
+
market: { type: "string", description: MARKET },
|
|
225
337
|
bucket_size: { type: "string", description: "Price bucket size (1, 5, 10, 50, 100, 500, 1000, 5000). Default: 100" },
|
|
226
338
|
},
|
|
227
339
|
required: ["market"],
|
|
@@ -235,27 +347,45 @@ export const tools = [
|
|
|
235
347
|
},
|
|
236
348
|
{
|
|
237
349
|
name: "get_vault_leaderboard",
|
|
238
|
-
|
|
350
|
+
title: "Vault leaderboard",
|
|
351
|
+
description: `Hyperliquid vaults ranked by net deposits (deposits minus withdrawals) over the last ${VAULT_LEADERBOARD_DAYS} days, with depositor counts. Keyless calls see the last 24 hours; a free key from https://ironflow.sh/key gives the full ${VAULT_LEADERBOARD_DAYS} days.`,
|
|
239
352
|
inputSchema: {
|
|
240
353
|
type: "object",
|
|
241
354
|
properties: {
|
|
242
|
-
limit: { type: "number", description:
|
|
355
|
+
limit: { type: "number", description: `Number of vaults (default 10, max ${MAX_VAULT_LEADERBOARD_LIMIT})` },
|
|
243
356
|
},
|
|
244
357
|
required: [],
|
|
245
358
|
},
|
|
246
359
|
handler: async (args, api) => {
|
|
247
360
|
const limit = optionalNumber(args, "limit", 10);
|
|
248
|
-
|
|
249
|
-
|
|
361
|
+
// GET /v1/analytics/vault-leaderboard is Builder and Enterprise only
|
|
362
|
+
// (403 TIER_FORBIDDEN otherwise). Keyed callers try it first; everyone
|
|
363
|
+
// else, and keys below Builder, get the same ranking from SQL.
|
|
364
|
+
if (api.hasKey()) {
|
|
365
|
+
try {
|
|
366
|
+
return JSON.stringify(await api.getVaultLeaderboard(String(limit)), null, 2);
|
|
367
|
+
}
|
|
368
|
+
catch (err) {
|
|
369
|
+
if (!(err instanceof Error && err.message.includes("TIER_FORBIDDEN")))
|
|
370
|
+
throw err;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
const res = (await runQuery(api, vaultLeaderboardSQL(limit), MAX_VAULT_LEADERBOARD_LIMIT));
|
|
374
|
+
const historyDays = res.limits?.history_days;
|
|
375
|
+
return JSON.stringify({
|
|
376
|
+
window_days: historyDays ? Math.min(historyDays, VAULT_LEADERBOARD_DAYS) : VAULT_LEADERBOARD_DAYS,
|
|
377
|
+
data: rowsToObjects(res).map((row) => ({ source: "hyperliquid", ...row })),
|
|
378
|
+
});
|
|
250
379
|
},
|
|
251
380
|
},
|
|
252
381
|
{
|
|
253
382
|
name: "get_funding_stats",
|
|
383
|
+
title: "Funding statistics",
|
|
254
384
|
description: "Funding statistics per time bucket for a Hyperliquid perp: average, minimum, maximum and annualized rate.",
|
|
255
385
|
inputSchema: {
|
|
256
386
|
type: "object",
|
|
257
387
|
properties: {
|
|
258
|
-
market: { type: "string", description:
|
|
388
|
+
market: { type: "string", description: MARKET },
|
|
259
389
|
interval: { type: "string", description: "Time interval (1h, 4h, 8h, 1d, 7d). Default: 1d", enum: ["1h", "4h", "8h", "1d", "7d"] },
|
|
260
390
|
limit: { type: "number", description: "Number of data points (default 7)" },
|
|
261
391
|
},
|
|
@@ -278,6 +408,7 @@ export const tools = [
|
|
|
278
408
|
// JSON object the agent can reason over.
|
|
279
409
|
{
|
|
280
410
|
name: "get_user_state",
|
|
411
|
+
title: "Wallet positions",
|
|
281
412
|
description: "Open positions and unrealized PnL for a Hyperliquid wallet right now, across native and HIP-3 perps. Use it for questions like 'is this wallet long or short?'",
|
|
282
413
|
inputSchema: {
|
|
283
414
|
type: "object",
|
|
@@ -294,14 +425,15 @@ export const tools = [
|
|
|
294
425
|
},
|
|
295
426
|
{
|
|
296
427
|
name: "get_user_funding",
|
|
428
|
+
title: "Wallet funding payments",
|
|
297
429
|
description: "Funding a Hyperliquid wallet paid or received, per market per bucket. Positive means received, negative means paid. bucket=1d gives daily totals, 1h the raw hourly payments.",
|
|
298
430
|
inputSchema: {
|
|
299
431
|
type: "object",
|
|
300
432
|
properties: {
|
|
301
433
|
address: { type: "string", description: "0x-prefixed 20-byte hex address" },
|
|
302
|
-
market: { type: "string", description:
|
|
303
|
-
from: { type: "
|
|
304
|
-
to: { type: "
|
|
434
|
+
market: { type: "string", description: MARKET_FILTER },
|
|
435
|
+
from: { type: "string", description: time("start") },
|
|
436
|
+
to: { type: "string", description: time("end") },
|
|
305
437
|
bucket: { type: "string", enum: ["1h", "1d", "raw"], description: "Aggregation bucket; default 1d" },
|
|
306
438
|
limit: { type: "number", description: `Most recent rows to return (default ${DEFAULT_FUNDING_ROWS})` },
|
|
307
439
|
},
|
|
@@ -310,8 +442,8 @@ export const tools = [
|
|
|
310
442
|
handler: async (args, api) => {
|
|
311
443
|
const address = requireString(args, "address");
|
|
312
444
|
const market = optionalString(args, "market", "");
|
|
313
|
-
const from =
|
|
314
|
-
const to =
|
|
445
|
+
const from = optionalTime(args, "from");
|
|
446
|
+
const to = optionalTime(args, "to");
|
|
315
447
|
const bucket = optionalString(args, "bucket", "1d");
|
|
316
448
|
const data = (await api.getUserFunding(address, market, from, to, bucket));
|
|
317
449
|
return JSON.stringify(shapeUserFunding(data, optionalNumber(args, "limit", DEFAULT_FUNDING_ROWS)));
|
|
@@ -319,35 +451,37 @@ export const tools = [
|
|
|
319
451
|
},
|
|
320
452
|
{
|
|
321
453
|
name: "get_user_maker_taker",
|
|
454
|
+
title: "Wallet maker/taker split",
|
|
322
455
|
description: "Maker vs taker breakdown of a Hyperliquid wallet's fills per market: volume, fees and rebates. A high maker share with negative maker fees marks a market maker.",
|
|
323
456
|
inputSchema: {
|
|
324
457
|
type: "object",
|
|
325
458
|
properties: {
|
|
326
459
|
address: { type: "string", description: "0x-prefixed 20-byte hex address" },
|
|
327
|
-
market: { type: "string", description:
|
|
328
|
-
from: { type: "
|
|
329
|
-
to: { type: "
|
|
460
|
+
market: { type: "string", description: MARKET_FILTER },
|
|
461
|
+
from: { type: "string", description: time("start") },
|
|
462
|
+
to: { type: "string", description: time("end") },
|
|
330
463
|
},
|
|
331
464
|
required: ["address"],
|
|
332
465
|
},
|
|
333
466
|
handler: async (args, api) => {
|
|
334
467
|
const address = requireString(args, "address");
|
|
335
468
|
const market = optionalString(args, "market", "");
|
|
336
|
-
const from =
|
|
337
|
-
const to =
|
|
469
|
+
const from = optionalTime(args, "from");
|
|
470
|
+
const to = optionalTime(args, "to");
|
|
338
471
|
const data = await api.getUserMakerTaker(address, market, from, to);
|
|
339
472
|
return JSON.stringify(data, null, 2);
|
|
340
473
|
},
|
|
341
474
|
},
|
|
342
475
|
{
|
|
343
476
|
name: "get_user_ledger",
|
|
477
|
+
title: "Wallet ledger",
|
|
344
478
|
description: "Vault deposits, withdrawals and transfers for a Hyperliquid wallet. Positive amounts go into the account. Account deposits and withdrawals are recorded only up to 2026-06-06.",
|
|
345
479
|
inputSchema: {
|
|
346
480
|
type: "object",
|
|
347
481
|
properties: {
|
|
348
482
|
address: { type: "string", description: "0x-prefixed 20-byte hex address" },
|
|
349
|
-
from: { type: "
|
|
350
|
-
to: { type: "
|
|
483
|
+
from: { type: "string", description: time("start") },
|
|
484
|
+
to: { type: "string", description: time("end") },
|
|
351
485
|
event_types: { type: "string", description: "Comma-separated type filter (deposit,withdrawal,vault_deposit,vault_withdraw,vault_transfer_in,vault_transfer_out)" },
|
|
352
486
|
limit: { type: "number", description: "Max entries, default 1000, cap 10000" },
|
|
353
487
|
},
|
|
@@ -355,8 +489,8 @@ export const tools = [
|
|
|
355
489
|
},
|
|
356
490
|
handler: async (args, api) => {
|
|
357
491
|
const address = requireString(args, "address");
|
|
358
|
-
const from =
|
|
359
|
-
const to =
|
|
492
|
+
const from = optionalTime(args, "from");
|
|
493
|
+
const to = optionalTime(args, "to");
|
|
360
494
|
const eventTypes = optionalString(args, "event_types", "");
|
|
361
495
|
const limit = optionalNumber(args, "limit", 1000);
|
|
362
496
|
const data = await api.getUserLedger(address, from, to, eventTypes, limit);
|
|
@@ -366,12 +500,13 @@ export const tools = [
|
|
|
366
500
|
// ─── Cross-wallet ranking (v0.34+) ─────────────────────────────────────
|
|
367
501
|
{
|
|
368
502
|
name: "get_pnl_leaderboard",
|
|
503
|
+
title: "PnL leaderboard",
|
|
369
504
|
description: "Every Hyperliquid wallet ranked by realized PnL, biggest losses or volume over a window. Wallets with fewer than 5 fills in the window are left out.",
|
|
370
505
|
inputSchema: {
|
|
371
506
|
type: "object",
|
|
372
507
|
properties: {
|
|
373
|
-
from: { type: "
|
|
374
|
-
to: { type: "
|
|
508
|
+
from: { type: "string", description: time("start", "Default 30 days ago") },
|
|
509
|
+
to: { type: "string", description: time("end", "Default now") },
|
|
375
510
|
limit: { type: "number", description: "Number of rows, max 200, default 50" },
|
|
376
511
|
sort_by: {
|
|
377
512
|
type: "string",
|
|
@@ -382,8 +517,8 @@ export const tools = [
|
|
|
382
517
|
required: [],
|
|
383
518
|
},
|
|
384
519
|
handler: async (args, api) => {
|
|
385
|
-
const from =
|
|
386
|
-
const to =
|
|
520
|
+
const from = optionalTime(args, "from");
|
|
521
|
+
const to = optionalTime(args, "to");
|
|
387
522
|
const limit = optionalNumber(args, "limit", 50);
|
|
388
523
|
const sortBy = optionalString(args, "sort_by", "realized_pnl");
|
|
389
524
|
const data = await api.getPnLLeaderboard(from, to, limit, sortBy);
|
|
@@ -392,13 +527,14 @@ export const tools = [
|
|
|
392
527
|
},
|
|
393
528
|
{
|
|
394
529
|
name: "get_market_top_wallets",
|
|
530
|
+
title: "Top wallets in a market",
|
|
395
531
|
description: "Top wallets on one Hyperliquid market by volume or realized PnL, up to 200 rows.",
|
|
396
532
|
inputSchema: {
|
|
397
533
|
type: "object",
|
|
398
534
|
properties: {
|
|
399
|
-
market: { type: "string", description:
|
|
400
|
-
from: { type: "
|
|
401
|
-
to: { type: "
|
|
535
|
+
market: { type: "string", description: MARKET },
|
|
536
|
+
from: { type: "string", description: time("start", "Default 24 hours ago") },
|
|
537
|
+
to: { type: "string", description: time("end", "Default now") },
|
|
402
538
|
limit: { type: "number", description: "Number of rows, max 200, default 25" },
|
|
403
539
|
sort_by: {
|
|
404
540
|
type: "string",
|
|
@@ -410,8 +546,8 @@ export const tools = [
|
|
|
410
546
|
},
|
|
411
547
|
handler: async (args, api) => {
|
|
412
548
|
const market = requireString(args, "market");
|
|
413
|
-
const from =
|
|
414
|
-
const to =
|
|
549
|
+
const from = optionalTime(args, "from");
|
|
550
|
+
const to = optionalTime(args, "to");
|
|
415
551
|
const limit = optionalNumber(args, "limit", 25);
|
|
416
552
|
const sortBy = optionalString(args, "sort_by", "volume");
|
|
417
553
|
const data = await api.getMarketTopWallets(market, from, to, limit, sortBy);
|
|
@@ -420,6 +556,7 @@ export const tools = [
|
|
|
420
556
|
},
|
|
421
557
|
{
|
|
422
558
|
name: "get_markets_snapshot",
|
|
559
|
+
title: "Markets snapshot",
|
|
423
560
|
description: "Active Hyperliquid markets ranked in one call: mark price, 24h change, 24h volume, open interest and current hourly funding. Sort by abs_funding for the most extreme funding, abs_change_24h for the biggest movers, or volume (default). Use min_volume_usd to skip illiquid markets. Returns the top 25 unless limit is set.",
|
|
424
561
|
inputSchema: {
|
|
425
562
|
type: "object",
|
|
@@ -459,26 +596,28 @@ export const tools = [
|
|
|
459
596
|
},
|
|
460
597
|
{
|
|
461
598
|
name: "get_user_summary",
|
|
599
|
+
title: "Wallet summary",
|
|
462
600
|
description: "One Hyperliquid wallet's stats over a window: volume, realized PnL, fill count, win rate, maker share and markets traded.",
|
|
463
601
|
inputSchema: {
|
|
464
602
|
type: "object",
|
|
465
603
|
properties: {
|
|
466
604
|
address: { type: "string", description: "0x-prefixed 20-byte hex address" },
|
|
467
|
-
from: { type: "
|
|
468
|
-
to: { type: "
|
|
605
|
+
from: { type: "string", description: time("start", "Default 24 hours ago") },
|
|
606
|
+
to: { type: "string", description: time("end", "Default now") },
|
|
469
607
|
},
|
|
470
608
|
required: ["address"],
|
|
471
609
|
},
|
|
472
610
|
handler: async (args, api) => {
|
|
473
611
|
const address = requireString(args, "address");
|
|
474
|
-
const from =
|
|
475
|
-
const to =
|
|
612
|
+
const from = optionalTime(args, "from");
|
|
613
|
+
const to = optionalTime(args, "to");
|
|
476
614
|
const data = await api.getUserSummary(address, from, to);
|
|
477
615
|
return JSON.stringify(data, null, 2);
|
|
478
616
|
},
|
|
479
617
|
},
|
|
480
618
|
{
|
|
481
619
|
name: "get_wallet_labels",
|
|
620
|
+
title: "Wallet labels",
|
|
482
621
|
description: "Labels for notable Hyperliquid wallets: top whales by 24h volume, top traders by 30-day realized PnL, vaults and vault leaders. Pass addresses to check specific wallets; without them it lists the whales and smart money.",
|
|
483
622
|
inputSchema: {
|
|
484
623
|
type: "object",
|
|
@@ -502,21 +641,22 @@ export const tools = [
|
|
|
502
641
|
},
|
|
503
642
|
{
|
|
504
643
|
name: "get_user_pnl_series",
|
|
644
|
+
title: "Wallet PnL curve",
|
|
505
645
|
description: "Realized PnL curve of a Hyperliquid wallet over time, bucketed (for example hourly or daily).",
|
|
506
646
|
inputSchema: {
|
|
507
647
|
type: "object",
|
|
508
648
|
properties: {
|
|
509
649
|
address: { type: "string", description: "0x-prefixed 20-byte hex address" },
|
|
510
|
-
from: { type: "
|
|
511
|
-
to: { type: "
|
|
650
|
+
from: { type: "string", description: time("start") },
|
|
651
|
+
to: { type: "string", description: time("end", "Default now") },
|
|
512
652
|
bucket_ms: { type: "number", description: "Bucket size in ms (e.g. 3600000 for 1h)" },
|
|
513
653
|
},
|
|
514
654
|
required: ["address"],
|
|
515
655
|
},
|
|
516
656
|
handler: async (args, api) => {
|
|
517
657
|
const address = requireString(args, "address");
|
|
518
|
-
const from =
|
|
519
|
-
const to =
|
|
658
|
+
const from = optionalTime(args, "from");
|
|
659
|
+
const to = optionalTime(args, "to");
|
|
520
660
|
const bucketMs = optionalNumber(args, "bucket_ms", 0);
|
|
521
661
|
const data = await api.getUserPnLSeries(address, from, to, bucketMs);
|
|
522
662
|
return JSON.stringify(data, null, 2);
|
|
@@ -525,6 +665,7 @@ export const tools = [
|
|
|
525
665
|
// ─── Signals (public endpoints: 60 requests per minute per IP, no key) ──
|
|
526
666
|
{
|
|
527
667
|
name: "get_top_traders",
|
|
668
|
+
title: "Top traders",
|
|
528
669
|
description: "Hyperliquid traders ranked across all markets by results over 7, 30 or 90 days: win rate, profit factor, realized PnL, max drawdown and best markets. sort=top ranks by realized PnL, lowrisk by smallest max drawdown, new by most recently first seen.",
|
|
529
670
|
inputSchema: {
|
|
530
671
|
type: "object",
|
|
@@ -546,11 +687,12 @@ export const tools = [
|
|
|
546
687
|
},
|
|
547
688
|
{
|
|
548
689
|
name: "get_market_leaders",
|
|
690
|
+
title: "Market leaders",
|
|
549
691
|
description: "The best traders on one Hyperliquid market, ranked by profit factor then win rate, among wallets with at least 5 closed trades there.",
|
|
550
692
|
inputSchema: {
|
|
551
693
|
type: "object",
|
|
552
694
|
properties: {
|
|
553
|
-
market: { type: "string", description:
|
|
695
|
+
market: { type: "string", description: MARKET },
|
|
554
696
|
window: { type: "string", description: "Lookback window. Default 30d", enum: ["7d", "30d", "90d"] },
|
|
555
697
|
limit: { type: "number", description: "Number of traders (1-50, default 20)" },
|
|
556
698
|
},
|
|
@@ -567,11 +709,12 @@ export const tools = [
|
|
|
567
709
|
},
|
|
568
710
|
{
|
|
569
711
|
name: "get_early_movers",
|
|
712
|
+
title: "Early movers",
|
|
570
713
|
description: "Wallets whose large orders (at least $10k) on a Hyperliquid market were followed by a price move in their direction within 30 minutes. Returns a lead score in basis points and a hit rate per wallet. Past activity does not predict future results.",
|
|
571
714
|
inputSchema: {
|
|
572
715
|
type: "object",
|
|
573
716
|
properties: {
|
|
574
|
-
market: { type: "string", description:
|
|
717
|
+
market: { type: "string", description: MARKET },
|
|
575
718
|
window: { type: "string", description: "Lookback window. Default 30d", enum: ["7d", "30d"] },
|
|
576
719
|
limit: { type: "number", description: "Number of wallets (1-25, default 10)" },
|
|
577
720
|
},
|
|
@@ -588,6 +731,7 @@ export const tools = [
|
|
|
588
731
|
},
|
|
589
732
|
{
|
|
590
733
|
name: "get_trader_profile",
|
|
734
|
+
title: "Trader profile",
|
|
591
735
|
description: "A Hyperliquid wallet's trading record over 7, 30 or 90 days: win rate, profit factor, realized PnL, max drawdown and its best markets.",
|
|
592
736
|
inputSchema: {
|
|
593
737
|
type: "object",
|
|
@@ -608,6 +752,7 @@ export const tools = [
|
|
|
608
752
|
// ─── Cohorts ─────────────────────────────────────────────────────────
|
|
609
753
|
{
|
|
610
754
|
name: "list_cohorts",
|
|
755
|
+
title: "List cohorts",
|
|
611
756
|
description: "List available address cohorts: six predefined groups (top_pnl_30d, high_volume_30d, whale_fills, net_withdrawers_7d, liquidation_prone, vault_whales) plus any custom cohorts the caller has created",
|
|
612
757
|
inputSchema: { type: "object", properties: {}, required: [] },
|
|
613
758
|
handler: async (_args, api) => {
|
|
@@ -617,7 +762,8 @@ export const tools = [
|
|
|
617
762
|
},
|
|
618
763
|
{
|
|
619
764
|
name: "get_cohort_addresses",
|
|
620
|
-
|
|
765
|
+
title: "Cohort addresses",
|
|
766
|
+
description: "Wallet addresses in one cohort; list_cohorts gives the names.",
|
|
621
767
|
inputSchema: {
|
|
622
768
|
type: "object",
|
|
623
769
|
properties: {
|
|
@@ -634,7 +780,8 @@ export const tools = [
|
|
|
634
780
|
// ─── Account & Status ────────────────────────────────────────────────
|
|
635
781
|
{
|
|
636
782
|
name: "get_status",
|
|
637
|
-
|
|
783
|
+
title: "API status",
|
|
784
|
+
description: "Ironflow service status right now: overall state, data freshness per venue and component health.",
|
|
638
785
|
inputSchema: { type: "object", properties: {}, required: [] },
|
|
639
786
|
handler: async (_args, api) => {
|
|
640
787
|
const data = await api.getStatus();
|
|
@@ -643,7 +790,8 @@ export const tools = [
|
|
|
643
790
|
},
|
|
644
791
|
{
|
|
645
792
|
name: "get_status_metrics",
|
|
646
|
-
|
|
793
|
+
title: "API performance metrics",
|
|
794
|
+
description: "Ironflow performance over rolling windows: API latency and error rate, ingestion lag and synthetic probe timings.",
|
|
647
795
|
inputSchema: { type: "object", properties: {}, required: [] },
|
|
648
796
|
handler: async (_args, api) => {
|
|
649
797
|
const data = await api.getStatusMetrics();
|
|
@@ -652,7 +800,8 @@ export const tools = [
|
|
|
652
800
|
},
|
|
653
801
|
{
|
|
654
802
|
name: "get_status_history",
|
|
655
|
-
|
|
803
|
+
title: "API uptime history",
|
|
804
|
+
description: "Ironflow uptime and data freshness per hour over the last 24 hours (default) or 7 days.",
|
|
656
805
|
inputSchema: {
|
|
657
806
|
type: "object",
|
|
658
807
|
properties: {
|
|
@@ -672,34 +821,47 @@ export const tools = [
|
|
|
672
821
|
},
|
|
673
822
|
{
|
|
674
823
|
name: "list_markets",
|
|
675
|
-
|
|
824
|
+
title: "List markets",
|
|
825
|
+
description: "Find how a Hyperliquid market is named: perps (native and HIP-3), spot and live HIP-4 outcomes, with symbol, class, issuer, base asset and Hyperliquid coin. Search with q (q=nvda finds xyz:NVDA-PERP and the other NVDA perps). Pages of up to 100 rows; pass pagination.next_cursor as cursor for the next page.",
|
|
676
826
|
inputSchema: {
|
|
677
827
|
type: "object",
|
|
678
828
|
properties: {
|
|
679
|
-
|
|
829
|
+
q: { type: "string", description: "Case-insensitive search over symbol, base asset, Hyperliquid coin and issuer" },
|
|
680
830
|
market_class: {
|
|
681
831
|
type: "string",
|
|
682
|
-
description: "
|
|
832
|
+
description: "Only this class. 'prediction' is HIP-4 outcomes. Omit for all.",
|
|
683
833
|
enum: ["perp", "spot", "prediction", "option"],
|
|
684
834
|
},
|
|
685
835
|
issuer: {
|
|
686
836
|
type: "string",
|
|
687
|
-
description: "HIP-3 issuer code (e.g. '
|
|
837
|
+
description: "HIP-3 issuer code (e.g. 'xyz'). '' returns native markets only. Omit for every issuer.",
|
|
838
|
+
},
|
|
839
|
+
include_inactive: {
|
|
840
|
+
type: "boolean",
|
|
841
|
+
description: "Also return closed markets (delisted, settled HIP-4 outcomes), which carry active_to_ms. Default false.",
|
|
688
842
|
},
|
|
689
|
-
|
|
690
|
-
|
|
843
|
+
limit: { type: "number", description: `Rows per page (default ${DEFAULT_MARKETS_LIMIT}, max ${MAX_MARKETS_LIMIT})` },
|
|
844
|
+
cursor: { type: "string", description: "pagination.next_cursor from the previous page, with the same filters" },
|
|
845
|
+
source: { type: "string", description: "Venue. Default 'hyperliquid'." },
|
|
691
846
|
},
|
|
692
847
|
required: [],
|
|
693
848
|
},
|
|
694
849
|
handler: async (args, api) => {
|
|
695
|
-
const source = optionalString(args, "source", "");
|
|
696
|
-
const market_class = optionalString(args, "market_class", "");
|
|
697
850
|
// Tri-state: present-with-empty-string means "native only".
|
|
698
|
-
const issuer = Object.prototype.hasOwnProperty.call(args, "issuer")
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
const
|
|
702
|
-
|
|
851
|
+
const issuer = Object.prototype.hasOwnProperty.call(args, "issuer") ? optionalString(args, "issuer", "") : undefined;
|
|
852
|
+
// search was this tool's name for q before 0.11.0; still accepted.
|
|
853
|
+
const q = optionalString(args, "q", "").trim() || optionalString(args, "search", "").trim();
|
|
854
|
+
const limit = Math.min(optionalNumber(args, "limit", DEFAULT_MARKETS_LIMIT), MAX_MARKETS_LIMIT);
|
|
855
|
+
const data = (await api.listMarkets({
|
|
856
|
+
source: optionalString(args, "source", ""),
|
|
857
|
+
marketClass: optionalString(args, "market_class", ""),
|
|
858
|
+
issuer,
|
|
859
|
+
q,
|
|
860
|
+
includeInactive: optionalBoolean(args, "include_inactive"),
|
|
861
|
+
limit,
|
|
862
|
+
cursor: optionalString(args, "cursor", "").trim(),
|
|
863
|
+
}));
|
|
864
|
+
return JSON.stringify(shapeMarkets(data, { search: q, limit }));
|
|
703
865
|
},
|
|
704
866
|
},
|
|
705
867
|
];
|