@2oolkit/hyperliquid-cli
Advanced tools
+89
-45
@@ -532,7 +532,11 @@ #!/usr/bin/env node | ||
| } | ||
| async getMeta() { | ||
| return this.info({ type: "meta" }); | ||
| async getMeta(dex) { | ||
| const body = { type: "meta" }; | ||
| if (dex) body.dex = dex; | ||
| return this.info(body); | ||
| } | ||
| async getMetaAndAssetCtxs() { | ||
| return this.info({ type: "metaAndAssetCtxs" }); | ||
| async getMetaAndAssetCtxs(dex) { | ||
| const body = { type: "metaAndAssetCtxs" }; | ||
| if (dex) body.dex = dex; | ||
| return this.info(body); | ||
| } | ||
@@ -542,13 +546,17 @@ async getSpotMeta() { | ||
| } | ||
| async getPerpDexs() { | ||
| return this.info({ type: "perpDexs" }); | ||
| } | ||
| async getSpotMetaAndAssetCtxs() { | ||
| return this.info({ type: "spotMetaAndAssetCtxs" }); | ||
| } | ||
| async getL2Book(coin, nSigFigs, mantissa) { | ||
| async getL2Book(coin, nSigFigs, mantissa, dex) { | ||
| const body = { type: "l2Book", coin }; | ||
| if (nSigFigs !== void 0) body.nSigFigs = nSigFigs; | ||
| if (mantissa !== void 0) body.mantissa = mantissa; | ||
| if (dex) body.dex = dex; | ||
| return this.info(body); | ||
| } | ||
| async getCandleSnapshot(coin, interval, startTime, endTime) { | ||
| return this.info({ | ||
| async getCandleSnapshot(coin, interval, startTime, endTime, dex) { | ||
| const body = { | ||
| type: "candleSnapshot", | ||
@@ -561,6 +569,8 @@ req: { | ||
| } | ||
| }); | ||
| }; | ||
| if (dex) body.dex = dex; | ||
| return this.info(body); | ||
| } | ||
| async getFundingHistory(coin, startTime, endTime) { | ||
| return this.info({ | ||
| async getFundingHistory(coin, startTime, endTime, dex) { | ||
| const body = { | ||
| type: "fundingHistory", | ||
@@ -570,3 +580,5 @@ coin, | ||
| endTime: endTime ?? nowMs() | ||
| }); | ||
| }; | ||
| if (dex) body.dex = dex; | ||
| return this.info(body); | ||
| } | ||
@@ -576,4 +588,6 @@ async getPredictedFundings() { | ||
| } | ||
| async getRecentTrades(coin) { | ||
| return this.info({ type: "recentTrades", coin }); | ||
| async getRecentTrades(coin, dex) { | ||
| const body = { type: "recentTrades", coin }; | ||
| if (dex) body.dex = dex; | ||
| return this.info(body); | ||
| } | ||
@@ -1012,2 +1026,41 @@ // ─── User Info ────────────────────────────────────────────────────── | ||
| // src/utils/asset.ts | ||
| function parseCoinDex(coin) { | ||
| const colonIdx = coin.indexOf(":"); | ||
| if (colonIdx === -1) return { dex: void 0, coin }; | ||
| const dex = coin.slice(0, colonIdx); | ||
| return { dex, coin }; | ||
| } | ||
| async function resolveDexOffset(dex, client) { | ||
| const dexes = await client.getPerpDexs(); | ||
| for (let i = 1; i < dexes.length; i++) { | ||
| if (dexes[i]?.name === dex) { | ||
| return 11e4 + (i - 1) * 1e4; | ||
| } | ||
| } | ||
| throw new Error(`Perp dex "${dex}" not found. Check available dexes.`); | ||
| } | ||
| async function resolveAssetIndex(coin, client) { | ||
| const { dex } = parseCoinDex(coin); | ||
| const meta = await client.getMeta(dex); | ||
| const idx = meta.universe.findIndex( | ||
| (u) => u.name.toUpperCase() === coin.toUpperCase() | ||
| ); | ||
| if (idx !== -1) { | ||
| if (dex) { | ||
| const offset = await resolveDexOffset(dex, client); | ||
| return offset + idx; | ||
| } | ||
| return idx; | ||
| } | ||
| if (!dex) { | ||
| const spotMeta = await client.getSpotMeta(); | ||
| const spotIdx = spotMeta.universe.findIndex( | ||
| (u) => u.name.toUpperCase() === coin.toUpperCase() | ||
| ); | ||
| if (spotIdx !== -1) return 1e4 + spotIdx; | ||
| } | ||
| throw new Error(`Asset "${coin}" not found in perpetuals or spot markets.`); | ||
| } | ||
| // src/mcp/tools/market.ts | ||
@@ -1027,7 +1080,10 @@ function registerMarketTools(server2) { | ||
| "get_meta", | ||
| "Get perpetual market metadata (instruments, max leverage, decimals)", | ||
| { spot: import_zod.z.boolean().optional().describe("Get spot metadata instead") }, | ||
| async ({ spot }) => withErrorHandling(async () => { | ||
| 'Get perpetual market metadata (instruments, max leverage, decimals). Use dex param for HIP-3 builder-deployed perps (e.g., "xyz")', | ||
| { | ||
| spot: import_zod.z.boolean().optional().describe("Get spot metadata instead"), | ||
| dex: import_zod.z.string().optional().describe("HIP-3 dex name (e.g., xyz) for builder-deployed perps") | ||
| }, | ||
| async ({ spot, dex }) => withErrorHandling(async () => { | ||
| const client = createPublicClient(); | ||
| const data = spot ? await client.getSpotMeta() : await client.getMeta(); | ||
| const data = spot ? await client.getSpotMeta() : await client.getMeta(dex); | ||
| return mcpText(JSON.stringify(data, null, 2)); | ||
@@ -1038,5 +1094,5 @@ }) | ||
| "get_ticker", | ||
| "Get ticker data for a specific coin including price, volume, funding", | ||
| "Get ticker data for a specific coin including price, volume, funding. Use dex:coin format for HIP-3 (e.g., xyz:CL)", | ||
| { | ||
| coin: import_zod.z.string().describe("Coin name (e.g., BTC, ETH)"), | ||
| coin: import_zod.z.string().describe("Coin name (e.g., BTC, ETH, xyz:CL for HIP-3)"), | ||
| spot: import_zod.z.boolean().optional().describe("Get spot ticker") | ||
@@ -1046,3 +1102,4 @@ }, | ||
| const client = createPublicClient(); | ||
| const data = spot ? await client.getSpotMetaAndAssetCtxs() : await client.getMetaAndAssetCtxs(); | ||
| const { dex } = parseCoinDex(coin); | ||
| const data = spot ? await client.getSpotMetaAndAssetCtxs() : await client.getMetaAndAssetCtxs(dex); | ||
| const arr = data; | ||
@@ -1062,3 +1119,3 @@ const idx = arr[0].universe.findIndex( | ||
| { | ||
| coin: import_zod.z.string().describe("Coin name (e.g., BTC, ETH)"), | ||
| coin: import_zod.z.string().describe("Coin name (e.g., BTC, ETH, xyz:CL for HIP-3)"), | ||
| depth: import_zod.z.number().min(2).max(5).optional().describe("Significant figures (2-5)") | ||
@@ -1068,3 +1125,4 @@ }, | ||
| const client = createPublicClient(); | ||
| const data = await client.getL2Book(coin, depth); | ||
| const { dex } = parseCoinDex(coin); | ||
| const data = await client.getL2Book(coin, depth, void 0, dex); | ||
| return mcpText(JSON.stringify(data, null, 2)); | ||
@@ -1077,3 +1135,3 @@ }) | ||
| { | ||
| coin: import_zod.z.string().describe("Coin name"), | ||
| coin: import_zod.z.string().describe("Coin name (e.g., BTC, ETH, xyz:CL for HIP-3)"), | ||
| interval: import_zod.z.string().describe("Candle interval (1m, 5m, 15m, 1h, 4h, 1d, etc.)"), | ||
@@ -1087,6 +1145,7 @@ count: import_zod.z.number().min(1).max(5e3).optional().describe("Number of candles (default 50)") | ||
| const client = createPublicClient(); | ||
| const { dex } = parseCoinDex(coin); | ||
| const n = count ?? 50; | ||
| const endTime = Date.now(); | ||
| const startTime = endTime - n * (INTERVAL_MS[interval] ?? 36e5); | ||
| const data = await client.getCandleSnapshot(coin, interval, startTime, endTime); | ||
| const data = await client.getCandleSnapshot(coin, interval, startTime, endTime, dex); | ||
| return mcpText(JSON.stringify(data, null, 2)); | ||
@@ -1099,3 +1158,3 @@ }) | ||
| { | ||
| coin: import_zod.z.string().describe("Coin name"), | ||
| coin: import_zod.z.string().describe("Coin name (e.g., BTC, ETH, xyz:CL for HIP-3)"), | ||
| hours: import_zod.z.number().optional().describe("Hours to look back (default 24)"), | ||
@@ -1110,6 +1169,7 @@ predicted: import_zod.z.boolean().optional().describe("Get predicted funding instead") | ||
| } | ||
| const { dex } = parseCoinDex(coin); | ||
| const h = hours ?? 24; | ||
| const endTime = Date.now(); | ||
| const startTime = endTime - h * 36e5; | ||
| const data = await client.getFundingHistory(coin, startTime, endTime); | ||
| const data = await client.getFundingHistory(coin, startTime, endTime, dex); | ||
| return mcpText(JSON.stringify(data, null, 2)); | ||
@@ -1121,6 +1181,7 @@ }) | ||
| "Get recent trades for a coin", | ||
| { coin: import_zod.z.string().describe("Coin name") }, | ||
| { coin: import_zod.z.string().describe("Coin name (e.g., BTC, ETH, xyz:CL for HIP-3)") }, | ||
| async ({ coin }) => withErrorHandling(async () => { | ||
| const client = createPublicClient(); | ||
| const data = await client.getRecentTrades(coin); | ||
| const { dex } = parseCoinDex(coin); | ||
| const data = await client.getRecentTrades(coin, dex); | ||
| return mcpText(JSON.stringify(data, null, 2)); | ||
@@ -1133,19 +1194,2 @@ }) | ||
| var import_zod2 = require("zod"); | ||
| // src/utils/asset.ts | ||
| async function resolveAssetIndex(coin, client) { | ||
| const meta = await client.getMeta(); | ||
| const idx = meta.universe.findIndex( | ||
| (u) => u.name.toUpperCase() === coin.toUpperCase() | ||
| ); | ||
| if (idx !== -1) return idx; | ||
| const spotMeta = await client.getSpotMeta(); | ||
| const spotIdx = spotMeta.universe.findIndex( | ||
| (u) => u.name.toUpperCase() === coin.toUpperCase() | ||
| ); | ||
| if (spotIdx !== -1) return 1e4 + spotIdx; | ||
| throw new Error(`Asset "${coin}" not found in perpetuals or spot markets.`); | ||
| } | ||
| // src/mcp/tools/order.ts | ||
| function registerOrderTools(server2) { | ||
@@ -1152,0 +1196,0 @@ server2.tool( |
+2
-1
| { | ||
| "name": "@2oolkit/hyperliquid-cli", | ||
| "version": "0.2.1", | ||
| "version": "0.2.2", | ||
| "description": "CLI & MCP server for Hyperliquid DEX — trade perpetuals & spot, manage orders, and query market data", | ||
@@ -66,2 +66,3 @@ "author": "haeminmoon", | ||
| "devDependencies": { | ||
| "@types/jest": "^30.0.0", | ||
| "@types/node": "^22.10.0", | ||
@@ -68,0 +69,0 @@ "jest": "^29.7.0", |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
376795
2.92%3378
2.77%7
16.67%