@elizaos/plugin-hyperliquid-app 2.0.3-beta.6 → 2.0.3-beta.7
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/HyperliquidAppView.d.ts +4 -0
- package/dist/HyperliquidAppView.d.ts.map +1 -0
- package/dist/HyperliquidAppView.interact.d.ts +10 -0
- package/dist/HyperliquidAppView.interact.d.ts.map +1 -0
- package/dist/HyperliquidAppView.interact.js +70 -0
- package/dist/HyperliquidAppView.interact.js.map +1 -0
- package/dist/HyperliquidAppView.js +199 -0
- package/dist/HyperliquidAppView.js.map +1 -0
- package/dist/HyperliquidPositionsPanel.d.ts +12 -0
- package/dist/HyperliquidPositionsPanel.d.ts.map +1 -0
- package/dist/HyperliquidPositionsPanel.js +194 -0
- package/dist/HyperliquidPositionsPanel.js.map +1 -0
- package/dist/HyperliquidView.d.ts +14 -0
- package/dist/HyperliquidView.d.ts.map +1 -0
- package/dist/HyperliquidView.js +56 -0
- package/dist/HyperliquidView.js.map +1 -0
- package/dist/__fixtures__/contract.d.ts +5 -0
- package/dist/__fixtures__/contract.d.ts.map +1 -0
- package/dist/__fixtures__/contract.js +87 -0
- package/dist/__fixtures__/contract.js.map +1 -0
- package/dist/actions/perpetual-market.d.ts +38 -0
- package/dist/actions/perpetual-market.d.ts.map +1 -0
- package/dist/actions/perpetual-market.js +653 -0
- package/dist/actions/perpetual-market.js.map +1 -0
- package/dist/client.d.ts +9 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +15 -0
- package/dist/client.js.map +1 -0
- package/dist/components/HyperliquidSpatialView.d.ts +46 -0
- package/dist/components/HyperliquidSpatialView.d.ts.map +1 -0
- package/dist/components/HyperliquidSpatialView.js +214 -0
- package/dist/components/HyperliquidSpatialView.js.map +1 -0
- package/dist/hyperliquid-app-view-bundle.d.ts +3 -0
- package/dist/hyperliquid-app-view-bundle.d.ts.map +1 -0
- package/dist/hyperliquid-app-view-bundle.js +7 -0
- package/dist/hyperliquid-app-view-bundle.js.map +1 -0
- package/dist/hyperliquid-app.d.ts +4 -0
- package/dist/hyperliquid-app.d.ts.map +1 -0
- package/dist/hyperliquid-app.js +18 -0
- package/dist/hyperliquid-app.js.map +1 -0
- package/dist/hyperliquid-contracts.d.ts +152 -0
- package/dist/hyperliquid-contracts.d.ts.map +1 -0
- package/dist/hyperliquid-contracts.js +17 -0
- package/dist/hyperliquid-contracts.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +3 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +130 -0
- package/dist/plugin.js.map +1 -0
- package/dist/register-routes.d.ts +2 -0
- package/dist/register-routes.d.ts.map +1 -0
- package/dist/register-routes.js +6 -0
- package/dist/register-routes.js.map +1 -0
- package/dist/register-terminal-view.d.ts +15 -0
- package/dist/register-terminal-view.d.ts.map +1 -0
- package/dist/register-terminal-view.js +34 -0
- package/dist/register-terminal-view.js.map +1 -0
- package/dist/register.d.ts +2 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +17 -0
- package/dist/register.js.map +1 -0
- package/dist/routes.d.ts +25 -0
- package/dist/routes.d.ts.map +1 -0
- package/dist/routes.js +485 -0
- package/dist/routes.js.map +1 -0
- package/dist/ui.d.ts +6 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +12 -0
- package/dist/ui.js.map +1 -0
- package/dist/useHyperliquidState.d.ts +20 -0
- package/dist/useHyperliquidState.d.ts.map +1 -0
- package/dist/useHyperliquidState.js +72 -0
- package/dist/useHyperliquidState.js.map +1 -0
- package/dist/views/bundle.js +463 -0
- package/dist/views/bundle.js.map +1 -0
- package/package.json +6 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HyperliquidAppView.d.ts","sourceRoot":"","sources":["../src/HyperliquidAppView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAa3D,OAAO,UAAU,CAAC;AAsDlB,wBAAgB,kBAAkB,CAAC,EAAE,UAAU,EAAE,EAAE,iBAAiB,2CAoEnE"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import "./client";
|
|
2
|
+
import type { HyperliquidMarketsResponse, HyperliquidOrdersResponse, HyperliquidPositionsResponse, HyperliquidStatusResponse } from "./hyperliquid-contracts";
|
|
3
|
+
export declare function loadHyperliquidTuiState(): Promise<{
|
|
4
|
+
status: HyperliquidStatusResponse;
|
|
5
|
+
markets: HyperliquidMarketsResponse | null;
|
|
6
|
+
positions: HyperliquidPositionsResponse | null;
|
|
7
|
+
orders: HyperliquidOrdersResponse | null;
|
|
8
|
+
}>;
|
|
9
|
+
export declare function interact(capability: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
10
|
+
//# sourceMappingURL=HyperliquidAppView.interact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HyperliquidAppView.interact.d.ts","sourceRoot":"","sources":["../src/HyperliquidAppView.interact.ts"],"names":[],"mappings":"AAOA,OAAO,UAAU,CAAC;AAElB,OAAO,KAAK,EACV,0BAA0B,EAC1B,yBAAyB,EACzB,4BAA4B,EAC5B,yBAAyB,EAC1B,MAAM,yBAAyB,CAAC;AAEjC,wBAAsB,uBAAuB,IAAI,OAAO,CAAC;IACvD,MAAM,EAAE,yBAAyB,CAAC;IAClC,OAAO,EAAE,0BAA0B,GAAG,IAAI,CAAC;IAC3C,SAAS,EAAE,4BAA4B,GAAG,IAAI,CAAC;IAC/C,MAAM,EAAE,yBAAyB,GAAG,IAAI,CAAC;CAC1C,CAAC,CAYD;AAyBD,wBAAsB,QAAQ,CAC5B,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC,OAAO,CAAC,CA0ClB"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { client } from "@elizaos/app-core";
|
|
2
|
+
import "./client.js";
|
|
3
|
+
async function loadHyperliquidTuiState() {
|
|
4
|
+
const hyperliquidClient = client;
|
|
5
|
+
const status = await hyperliquidClient.hyperliquidStatus();
|
|
6
|
+
if (!status.publicReadReady) {
|
|
7
|
+
return { status, markets: null, positions: null, orders: null };
|
|
8
|
+
}
|
|
9
|
+
const [markets, positions, orders] = await Promise.all([
|
|
10
|
+
hyperliquidClient.hyperliquidMarkets(),
|
|
11
|
+
hyperliquidClient.hyperliquidPositions(),
|
|
12
|
+
hyperliquidClient.hyperliquidOrders()
|
|
13
|
+
]);
|
|
14
|
+
return { status, markets, positions, orders };
|
|
15
|
+
}
|
|
16
|
+
async function postHyperliquidCommand(path, body) {
|
|
17
|
+
const response = await fetch(path, {
|
|
18
|
+
method: "POST",
|
|
19
|
+
headers: { "Content-Type": "application/json" },
|
|
20
|
+
body: JSON.stringify(body)
|
|
21
|
+
});
|
|
22
|
+
const data = await response.json().catch(() => ({}));
|
|
23
|
+
if (!response.ok) {
|
|
24
|
+
const message = typeof data === "object" && data !== null && "error" in data && typeof data.error === "string" ? data.error : `Hyperliquid request failed with ${response.status}`;
|
|
25
|
+
throw new Error(message);
|
|
26
|
+
}
|
|
27
|
+
return data;
|
|
28
|
+
}
|
|
29
|
+
async function interact(capability, params) {
|
|
30
|
+
if (capability === "terminal-hyperliquid-state") {
|
|
31
|
+
const state = await loadHyperliquidTuiState();
|
|
32
|
+
return {
|
|
33
|
+
viewType: "tui",
|
|
34
|
+
status: state.status,
|
|
35
|
+
markets: state.markets?.markets.slice(
|
|
36
|
+
0,
|
|
37
|
+
typeof params?.limit === "number" ? params.limit : 25
|
|
38
|
+
) ?? [],
|
|
39
|
+
positions: state.positions,
|
|
40
|
+
orders: state.orders
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (capability === "terminal-hyperliquid-market") {
|
|
44
|
+
const coin = typeof params?.coin === "string" ? params.coin.trim().toUpperCase() : "";
|
|
45
|
+
if (!coin) throw new Error("coin is required");
|
|
46
|
+
const state = await loadHyperliquidTuiState();
|
|
47
|
+
return {
|
|
48
|
+
viewType: "tui",
|
|
49
|
+
market: state.markets?.markets.find(
|
|
50
|
+
(market) => market.name.toUpperCase() === coin
|
|
51
|
+
) ?? null
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (capability === "terminal-hyperliquid-execution-check") {
|
|
55
|
+
return {
|
|
56
|
+
viewType: "tui",
|
|
57
|
+
result: await postHyperliquidCommand("/api/hyperliquid/orders/open", {
|
|
58
|
+
coin: typeof params?.coin === "string" ? params.coin : "BTC",
|
|
59
|
+
side: typeof params?.side === "string" ? params.side : "buy",
|
|
60
|
+
size: typeof params?.size === "string" ? params.size : "0"
|
|
61
|
+
})
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
throw new Error(`Unsupported capability "${capability}"`);
|
|
65
|
+
}
|
|
66
|
+
export {
|
|
67
|
+
interact,
|
|
68
|
+
loadHyperliquidTuiState
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=HyperliquidAppView.interact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/HyperliquidAppView.interact.ts"],"sourcesContent":["// View-bundle `interact` capability handler plus the TUI state loaders it shares\n// with HyperliquidTuiView, split out of HyperliquidAppView.tsx so that file\n// exports only React components and stays Fast-Refresh-compatible (Vite would\n// full-reload a component file that also exports a plain function). The view\n// bundle re-exports `interact` via ./hyperliquid-app-view-bundle.ts.\n\nimport { client } from \"@elizaos/app-core\";\nimport \"./client.js\";\nimport type { HyperliquidClient } from \"./client.js\";\nimport type {\n HyperliquidMarketsResponse,\n HyperliquidOrdersResponse,\n HyperliquidPositionsResponse,\n HyperliquidStatusResponse,\n} from \"./hyperliquid-contracts.js\";\n\nexport async function loadHyperliquidTuiState(): Promise<{\n status: HyperliquidStatusResponse;\n markets: HyperliquidMarketsResponse | null;\n positions: HyperliquidPositionsResponse | null;\n orders: HyperliquidOrdersResponse | null;\n}> {\n const hyperliquidClient = client as HyperliquidClient;\n const status = await hyperliquidClient.hyperliquidStatus();\n if (!status.publicReadReady) {\n return { status, markets: null, positions: null, orders: null };\n }\n const [markets, positions, orders] = await Promise.all([\n hyperliquidClient.hyperliquidMarkets(),\n hyperliquidClient.hyperliquidPositions(),\n hyperliquidClient.hyperliquidOrders(),\n ]);\n return { status, markets, positions, orders };\n}\n\nasync function postHyperliquidCommand(\n path: string,\n body: Record<string, unknown>,\n): Promise<unknown> {\n const response = await fetch(path, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n const data = await response.json().catch(() => ({}));\n if (!response.ok) {\n const message =\n typeof data === \"object\" &&\n data !== null &&\n \"error\" in data &&\n typeof data.error === \"string\"\n ? data.error\n : `Hyperliquid request failed with ${response.status}`;\n throw new Error(message);\n }\n return data;\n}\n\nexport async function interact(\n capability: string,\n params?: Record<string, unknown>,\n): Promise<unknown> {\n if (capability === \"terminal-hyperliquid-state\") {\n const state = await loadHyperliquidTuiState();\n return {\n viewType: \"tui\",\n status: state.status,\n markets:\n state.markets?.markets.slice(\n 0,\n typeof params?.limit === \"number\" ? params.limit : 25,\n ) ?? [],\n positions: state.positions,\n orders: state.orders,\n };\n }\n\n if (capability === \"terminal-hyperliquid-market\") {\n const coin =\n typeof params?.coin === \"string\" ? params.coin.trim().toUpperCase() : \"\";\n if (!coin) throw new Error(\"coin is required\");\n const state = await loadHyperliquidTuiState();\n return {\n viewType: \"tui\",\n market:\n state.markets?.markets.find(\n (market) => market.name.toUpperCase() === coin,\n ) ?? null,\n };\n }\n\n if (capability === \"terminal-hyperliquid-execution-check\") {\n return {\n viewType: \"tui\",\n result: await postHyperliquidCommand(\"/api/hyperliquid/orders/open\", {\n coin: typeof params?.coin === \"string\" ? params.coin : \"BTC\",\n side: typeof params?.side === \"string\" ? params.side : \"buy\",\n size: typeof params?.size === \"string\" ? params.size : \"0\",\n }),\n };\n }\n\n throw new Error(`Unsupported capability \"${capability}\"`);\n}\n"],"mappings":"AAMA,SAAS,cAAc;AACvB,OAAO;AASP,eAAsB,0BAKnB;AACD,QAAM,oBAAoB;AAC1B,QAAM,SAAS,MAAM,kBAAkB,kBAAkB;AACzD,MAAI,CAAC,OAAO,iBAAiB;AAC3B,WAAO,EAAE,QAAQ,SAAS,MAAM,WAAW,MAAM,QAAQ,KAAK;AAAA,EAChE;AACA,QAAM,CAAC,SAAS,WAAW,MAAM,IAAI,MAAM,QAAQ,IAAI;AAAA,IACrD,kBAAkB,mBAAmB;AAAA,IACrC,kBAAkB,qBAAqB;AAAA,IACvC,kBAAkB,kBAAkB;AAAA,EACtC,CAAC;AACD,SAAO,EAAE,QAAQ,SAAS,WAAW,OAAO;AAC9C;AAEA,eAAe,uBACb,MACA,MACkB;AAClB,QAAM,WAAW,MAAM,MAAM,MAAM;AAAA,IACjC,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,EAC3B,CAAC;AACD,QAAM,OAAO,MAAM,SAAS,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACnD,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,UACJ,OAAO,SAAS,YAChB,SAAS,QACT,WAAW,QACX,OAAO,KAAK,UAAU,WAClB,KAAK,QACL,mCAAmC,SAAS,MAAM;AACxD,UAAM,IAAI,MAAM,OAAO;AAAA,EACzB;AACA,SAAO;AACT;AAEA,eAAsB,SACpB,YACA,QACkB;AAClB,MAAI,eAAe,8BAA8B;AAC/C,UAAM,QAAQ,MAAM,wBAAwB;AAC5C,WAAO;AAAA,MACL,UAAU;AAAA,MACV,QAAQ,MAAM;AAAA,MACd,SACE,MAAM,SAAS,QAAQ;AAAA,QACrB;AAAA,QACA,OAAO,QAAQ,UAAU,WAAW,OAAO,QAAQ;AAAA,MACrD,KAAK,CAAC;AAAA,MACR,WAAW,MAAM;AAAA,MACjB,QAAQ,MAAM;AAAA,IAChB;AAAA,EACF;AAEA,MAAI,eAAe,+BAA+B;AAChD,UAAM,OACJ,OAAO,QAAQ,SAAS,WAAW,OAAO,KAAK,KAAK,EAAE,YAAY,IAAI;AACxE,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,kBAAkB;AAC7C,UAAM,QAAQ,MAAM,wBAAwB;AAC5C,WAAO;AAAA,MACL,UAAU;AAAA,MACV,QACE,MAAM,SAAS,QAAQ;AAAA,QACrB,CAAC,WAAW,OAAO,KAAK,YAAY,MAAM;AAAA,MAC5C,KAAK;AAAA,IACT;AAAA,EACF;AAEA,MAAI,eAAe,wCAAwC;AACzD,WAAO;AAAA,MACL,UAAU;AAAA,MACV,QAAQ,MAAM,uBAAuB,gCAAgC;AAAA,QACnE,MAAM,OAAO,QAAQ,SAAS,WAAW,OAAO,OAAO;AAAA,QACvD,MAAM,OAAO,QAAQ,SAAS,WAAW,OAAO,OAAO;AAAA,QACvD,MAAM,OAAO,QAAQ,SAAS,WAAW,OAAO,OAAO;AAAA,MACzD,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,2BAA2B,UAAU,GAAG;AAC1D;","names":[]}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, PagePanel, Spinner } from "@elizaos/app-core";
|
|
3
|
+
import { useAgentElement } from "@elizaos/ui/agent-surface";
|
|
4
|
+
import {
|
|
5
|
+
ArrowLeft,
|
|
6
|
+
BarChart3,
|
|
7
|
+
CircleAlert,
|
|
8
|
+
Cloud,
|
|
9
|
+
KeyRound,
|
|
10
|
+
Shield,
|
|
11
|
+
ShieldX
|
|
12
|
+
} from "lucide-react";
|
|
13
|
+
import "./client.js";
|
|
14
|
+
import { HyperliquidPositionsPanel } from "./HyperliquidPositionsPanel.js";
|
|
15
|
+
import { useHyperliquidState } from "./useHyperliquidState.js";
|
|
16
|
+
function BlockedPill({ label }) {
|
|
17
|
+
return /* @__PURE__ */ jsx(
|
|
18
|
+
"span",
|
|
19
|
+
{
|
|
20
|
+
className: "inline-flex items-center text-muted",
|
|
21
|
+
role: "status",
|
|
22
|
+
"aria-label": label,
|
|
23
|
+
title: label,
|
|
24
|
+
children: /* @__PURE__ */ jsx(ShieldX, { className: "h-4 w-4" })
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
function StatusItem({
|
|
29
|
+
icon: Icon,
|
|
30
|
+
label,
|
|
31
|
+
ready
|
|
32
|
+
}) {
|
|
33
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
34
|
+
/* @__PURE__ */ jsx(Icon, { className: `h-4 w-4 ${ready ? "text-ok" : "text-muted"}` }),
|
|
35
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-sm font-medium text-txt", children: label })
|
|
36
|
+
] });
|
|
37
|
+
}
|
|
38
|
+
function credentialModeLabel(mode) {
|
|
39
|
+
switch (mode) {
|
|
40
|
+
case "managed_vault":
|
|
41
|
+
return "Managed vault";
|
|
42
|
+
case "local_key":
|
|
43
|
+
return "Local key";
|
|
44
|
+
default:
|
|
45
|
+
return "Read-only";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function HyperliquidAppView({ exitToApps }) {
|
|
49
|
+
const { status, markets, positions, orders, loading, error, unavailable } = useHyperliquidState();
|
|
50
|
+
const publicReadReady = status?.publicReadReady ?? false;
|
|
51
|
+
const credentialMode = status?.credentialMode ?? "none";
|
|
52
|
+
const backButton = useAgentElement({
|
|
53
|
+
id: "action-back",
|
|
54
|
+
role: "button",
|
|
55
|
+
label: "Back to apps",
|
|
56
|
+
group: "hyperliquid-header",
|
|
57
|
+
description: "Exit the Hyperliquid view and return to the apps overlay"
|
|
58
|
+
});
|
|
59
|
+
return /* @__PURE__ */ jsxs(
|
|
60
|
+
"div",
|
|
61
|
+
{
|
|
62
|
+
"data-testid": "hyperliquid-shell",
|
|
63
|
+
className: "fixed inset-0 z-50 flex h-[100vh] flex-col overflow-hidden bg-bg supports-[height:100dvh]:h-[100dvh]",
|
|
64
|
+
children: [
|
|
65
|
+
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-3 px-3 py-2", children: [
|
|
66
|
+
/* @__PURE__ */ jsx(
|
|
67
|
+
Button,
|
|
68
|
+
{
|
|
69
|
+
ref: backButton.ref,
|
|
70
|
+
...backButton.agentProps,
|
|
71
|
+
variant: "ghost",
|
|
72
|
+
size: "icon",
|
|
73
|
+
className: "h-9 w-9 text-muted hover:text-txt",
|
|
74
|
+
onClick: exitToApps,
|
|
75
|
+
"aria-label": "Back",
|
|
76
|
+
children: /* @__PURE__ */ jsx(ArrowLeft, { className: "h-4 w-4" })
|
|
77
|
+
}
|
|
78
|
+
),
|
|
79
|
+
/* @__PURE__ */ jsx("div", { className: "min-w-0", children: /* @__PURE__ */ jsx("h1", { className: "text-base font-semibold text-txt", children: "Hyperliquid" }) }),
|
|
80
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1" })
|
|
81
|
+
] }),
|
|
82
|
+
/* @__PURE__ */ jsx("div", { className: "chat-native-scrollbar flex-1 overflow-y-auto px-3 py-2 sm:px-5", children: /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-5xl space-y-4", children: unavailable ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center gap-2 py-20 text-center", children: [
|
|
83
|
+
/* @__PURE__ */ jsx(ShieldX, { className: "h-8 w-8 text-muted" }),
|
|
84
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-txt", children: "Hyperliquid is unavailable on this device" }),
|
|
85
|
+
/* @__PURE__ */ jsx("p", { className: "sr-only", children: "Markets and account reads run on a desktop or cloud agent." })
|
|
86
|
+
] }) : /* @__PURE__ */ jsx(
|
|
87
|
+
HyperliquidReady,
|
|
88
|
+
{
|
|
89
|
+
status,
|
|
90
|
+
markets,
|
|
91
|
+
positions,
|
|
92
|
+
orders,
|
|
93
|
+
loading,
|
|
94
|
+
error,
|
|
95
|
+
publicReadReady,
|
|
96
|
+
credentialMode
|
|
97
|
+
}
|
|
98
|
+
) }) })
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
function HyperliquidReady({
|
|
104
|
+
status,
|
|
105
|
+
markets,
|
|
106
|
+
positions,
|
|
107
|
+
orders,
|
|
108
|
+
loading,
|
|
109
|
+
error,
|
|
110
|
+
publicReadReady,
|
|
111
|
+
credentialMode
|
|
112
|
+
}) {
|
|
113
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
114
|
+
error && /* @__PURE__ */ jsx(PagePanel.Notice, { tone: "danger", children: error }),
|
|
115
|
+
/* @__PURE__ */ jsxs("p", { className: "text-sm text-muted", children: [
|
|
116
|
+
publicReadReady ? "Read-only" : "Reads blocked",
|
|
117
|
+
" \xB7",
|
|
118
|
+
" ",
|
|
119
|
+
markets?.markets.length ?? 0,
|
|
120
|
+
" markets \xB7",
|
|
121
|
+
" ",
|
|
122
|
+
status?.account.address ? "account connected" : "no account"
|
|
123
|
+
] }),
|
|
124
|
+
/* @__PURE__ */ jsxs("section", { className: "flex flex-wrap items-center gap-x-6 gap-y-2", children: [
|
|
125
|
+
/* @__PURE__ */ jsx(StatusItem, { icon: BarChart3, label: "Reads", ready: publicReadReady }),
|
|
126
|
+
/* @__PURE__ */ jsx(
|
|
127
|
+
StatusItem,
|
|
128
|
+
{
|
|
129
|
+
icon: credentialMode === "managed_vault" ? Cloud : KeyRound,
|
|
130
|
+
label: credentialModeLabel(credentialMode),
|
|
131
|
+
ready: status?.signerReady ?? false
|
|
132
|
+
}
|
|
133
|
+
),
|
|
134
|
+
/* @__PURE__ */ jsx(
|
|
135
|
+
StatusItem,
|
|
136
|
+
{
|
|
137
|
+
icon: Shield,
|
|
138
|
+
label: "Account",
|
|
139
|
+
ready: Boolean(status?.account.address)
|
|
140
|
+
}
|
|
141
|
+
)
|
|
142
|
+
] }),
|
|
143
|
+
(status?.executionBlockedReason || status && !status.vault.ready && credentialMode !== "local_key") && /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 text-sm text-muted", children: [
|
|
144
|
+
/* @__PURE__ */ jsx(CircleAlert, { className: "mt-0.5 h-4 w-4 shrink-0" }),
|
|
145
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
146
|
+
status?.executionBlockedReason && /* @__PURE__ */ jsx("span", { className: "block", children: status.executionBlockedReason }),
|
|
147
|
+
status && !status.vault.ready && credentialMode !== "local_key" && /* @__PURE__ */ jsx("span", { className: "block", children: status.vault.guidance })
|
|
148
|
+
] })
|
|
149
|
+
] }),
|
|
150
|
+
loading && !markets ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center py-16 text-sm text-muted", children: [
|
|
151
|
+
/* @__PURE__ */ jsx(Spinner, { className: "mr-3 h-5 w-5" }),
|
|
152
|
+
"Loading"
|
|
153
|
+
] }) : /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
154
|
+
/* @__PURE__ */ jsxs("section", { children: [
|
|
155
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-1 py-2", children: [
|
|
156
|
+
/* @__PURE__ */ jsx(BarChart3, { className: "h-4 w-4 text-muted" }),
|
|
157
|
+
/* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-txt", children: "Markets" }),
|
|
158
|
+
/* @__PURE__ */ jsx("span", { className: "ml-auto text-xs text-muted", children: markets?.markets.length ?? 0 })
|
|
159
|
+
] }),
|
|
160
|
+
/* @__PURE__ */ jsx("div", { children: (markets?.markets ?? []).slice(0, 24).map((market) => /* @__PURE__ */ jsxs(
|
|
161
|
+
"div",
|
|
162
|
+
{
|
|
163
|
+
className: "grid grid-cols-[minmax(0,1fr)_auto_auto] items-center gap-3 px-1 py-2 text-sm",
|
|
164
|
+
children: [
|
|
165
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate font-medium text-txt", children: market.name }),
|
|
166
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted", children: market.maxLeverage ? `${market.maxLeverage}x` : "\u2014" }),
|
|
167
|
+
/* @__PURE__ */ jsxs("span", { className: "font-mono text-xs text-muted", children: [
|
|
168
|
+
"sz ",
|
|
169
|
+
market.szDecimals
|
|
170
|
+
] })
|
|
171
|
+
]
|
|
172
|
+
},
|
|
173
|
+
market.name
|
|
174
|
+
)) })
|
|
175
|
+
] }),
|
|
176
|
+
/* @__PURE__ */ jsxs("section", { children: [
|
|
177
|
+
/* @__PURE__ */ jsx(
|
|
178
|
+
HyperliquidPositionsPanel,
|
|
179
|
+
{
|
|
180
|
+
positions: positions?.positions ?? [],
|
|
181
|
+
summary: positions?.summary ?? null,
|
|
182
|
+
readBlockedReason: positions?.readBlockedReason ?? null
|
|
183
|
+
}
|
|
184
|
+
),
|
|
185
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 py-3", children: [
|
|
186
|
+
/* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-txt", children: "Orders" }),
|
|
187
|
+
orders?.readBlockedReason ? /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
188
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate text-xs text-muted", children: orders.readBlockedReason }),
|
|
189
|
+
/* @__PURE__ */ jsx(BlockedPill, { label: "Blocked" })
|
|
190
|
+
] }) : /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-txt", children: orders?.orders.length ?? 0 })
|
|
191
|
+
] })
|
|
192
|
+
] })
|
|
193
|
+
] })
|
|
194
|
+
] });
|
|
195
|
+
}
|
|
196
|
+
export {
|
|
197
|
+
HyperliquidAppView
|
|
198
|
+
};
|
|
199
|
+
//# sourceMappingURL=HyperliquidAppView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/HyperliquidAppView.tsx"],"sourcesContent":["import type { OverlayAppContext } from \"@elizaos/app-core\";\nimport { Button, PagePanel, Spinner } from \"@elizaos/app-core\";\nimport { useAgentElement } from \"@elizaos/ui/agent-surface\";\nimport {\n ArrowLeft,\n BarChart3,\n CircleAlert,\n Cloud,\n KeyRound,\n type LucideIcon,\n Shield,\n ShieldX,\n} from \"lucide-react\";\nimport \"./client.js\";\nimport { HyperliquidPositionsPanel } from \"./HyperliquidPositionsPanel.js\";\nimport type {\n HyperliquidCredentialMode,\n HyperliquidMarketsResponse,\n HyperliquidOrdersResponse,\n HyperliquidPositionsResponse,\n HyperliquidStatusResponse,\n} from \"./hyperliquid-contracts.js\";\nimport { useHyperliquidState } from \"./useHyperliquidState.js\";\n\nfunction BlockedPill({ label }: { label: string }) {\n return (\n <span\n className=\"inline-flex items-center text-muted\"\n role=\"status\"\n aria-label={label}\n title={label}\n >\n <ShieldX className=\"h-4 w-4\" />\n </span>\n );\n}\n\nfunction StatusItem({\n icon: Icon,\n label,\n ready,\n}: {\n icon: LucideIcon;\n label: string;\n ready: boolean;\n}) {\n return (\n <div className=\"flex items-center gap-2\">\n <Icon className={`h-4 w-4 ${ready ? \"text-ok\" : \"text-muted\"}`} />\n <span className=\"truncate text-sm font-medium text-txt\">{label}</span>\n </div>\n );\n}\n\nfunction credentialModeLabel(\n mode: \"managed_vault\" | \"local_key\" | \"none\" | undefined,\n): string {\n switch (mode) {\n case \"managed_vault\":\n return \"Managed vault\";\n case \"local_key\":\n return \"Local key\";\n default:\n return \"Read-only\";\n }\n}\n\nexport function HyperliquidAppView({ exitToApps }: OverlayAppContext) {\n const { status, markets, positions, orders, loading, error, unavailable } =\n useHyperliquidState();\n\n const publicReadReady = status?.publicReadReady ?? false;\n const credentialMode = status?.credentialMode ?? \"none\";\n\n const backButton = useAgentElement<HTMLButtonElement>({\n id: \"action-back\",\n role: \"button\",\n label: \"Back to apps\",\n group: \"hyperliquid-header\",\n description: \"Exit the Hyperliquid view and return to the apps overlay\",\n });\n\n return (\n <div\n data-testid=\"hyperliquid-shell\"\n className=\"fixed inset-0 z-50 flex h-[100vh] flex-col overflow-hidden bg-bg supports-[height:100dvh]:h-[100dvh]\"\n >\n <div className=\"flex shrink-0 items-center gap-3 px-3 py-2\">\n <Button\n ref={backButton.ref}\n {...backButton.agentProps}\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-9 w-9 text-muted hover:text-txt\"\n onClick={exitToApps}\n aria-label=\"Back\"\n >\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n\n <div className=\"min-w-0\">\n <h1 className=\"text-base font-semibold text-txt\">Hyperliquid</h1>\n </div>\n\n <div className=\"flex-1\" />\n </div>\n\n <div className=\"chat-native-scrollbar flex-1 overflow-y-auto px-3 py-2 sm:px-5\">\n <div className=\"mx-auto max-w-5xl space-y-4\">\n {unavailable ? (\n <div className=\"flex flex-col items-center justify-center gap-2 py-20 text-center\">\n <ShieldX className=\"h-8 w-8 text-muted\" />\n <p className=\"text-sm font-medium text-txt\">\n Hyperliquid is unavailable on this device\n </p>\n <p className=\"sr-only\">\n Markets and account reads run on a desktop or cloud agent.\n </p>\n </div>\n ) : (\n <HyperliquidReady\n status={status}\n markets={markets}\n positions={positions}\n orders={orders}\n loading={loading}\n error={error}\n publicReadReady={publicReadReady}\n credentialMode={credentialMode}\n />\n )}\n </div>\n </div>\n </div>\n );\n}\n\nfunction HyperliquidReady({\n status,\n markets,\n positions,\n orders,\n loading,\n error,\n publicReadReady,\n credentialMode,\n}: {\n status: HyperliquidStatusResponse | null;\n markets: HyperliquidMarketsResponse | null;\n positions: HyperliquidPositionsResponse | null;\n orders: HyperliquidOrdersResponse | null;\n loading: boolean;\n error: string | null;\n publicReadReady: boolean;\n credentialMode: HyperliquidCredentialMode;\n}) {\n return (\n <>\n {error && <PagePanel.Notice tone=\"danger\">{error}</PagePanel.Notice>}\n\n <p className=\"text-sm text-muted\">\n {publicReadReady ? \"Read-only\" : \"Reads blocked\"} ·{\" \"}\n {markets?.markets.length ?? 0} markets ·{\" \"}\n {status?.account.address ? \"account connected\" : \"no account\"}\n </p>\n\n <section className=\"flex flex-wrap items-center gap-x-6 gap-y-2\">\n <StatusItem icon={BarChart3} label=\"Reads\" ready={publicReadReady} />\n <StatusItem\n icon={credentialMode === \"managed_vault\" ? Cloud : KeyRound}\n label={credentialModeLabel(credentialMode)}\n ready={status?.signerReady ?? false}\n />\n <StatusItem\n icon={Shield}\n label=\"Account\"\n ready={Boolean(status?.account.address)}\n />\n </section>\n\n {(status?.executionBlockedReason ||\n (status && !status.vault.ready && credentialMode !== \"local_key\")) && (\n <div className=\"flex items-start gap-2 text-sm text-muted\">\n <CircleAlert className=\"mt-0.5 h-4 w-4 shrink-0\" />\n <div className=\"space-y-1\">\n {status?.executionBlockedReason && (\n <span className=\"block\">{status.executionBlockedReason}</span>\n )}\n {status &&\n !status.vault.ready &&\n credentialMode !== \"local_key\" && (\n <span className=\"block\">{status.vault.guidance}</span>\n )}\n </div>\n </div>\n )}\n\n {loading && !markets ? (\n <div className=\"flex items-center justify-center py-16 text-sm text-muted\">\n <Spinner className=\"mr-3 h-5 w-5\" />\n Loading\n </div>\n ) : (\n <div className=\"space-y-4\">\n <section>\n <div className=\"flex items-center gap-2 px-1 py-2\">\n <BarChart3 className=\"h-4 w-4 text-muted\" />\n <h2 className=\"text-sm font-semibold text-txt\">Markets</h2>\n <span className=\"ml-auto text-xs text-muted\">\n {markets?.markets.length ?? 0}\n </span>\n </div>\n <div>\n {(markets?.markets ?? []).slice(0, 24).map((market) => (\n <div\n key={market.name}\n className=\"grid grid-cols-[minmax(0,1fr)_auto_auto] items-center gap-3 px-1 py-2 text-sm\"\n >\n <span className=\"min-w-0 truncate font-medium text-txt\">\n {market.name}\n </span>\n <span className=\"text-xs text-muted\">\n {market.maxLeverage ? `${market.maxLeverage}x` : \"—\"}\n </span>\n <span className=\"font-mono text-xs text-muted\">\n sz {market.szDecimals}\n </span>\n </div>\n ))}\n </div>\n </section>\n\n <section>\n <HyperliquidPositionsPanel\n positions={positions?.positions ?? []}\n summary={positions?.summary ?? null}\n readBlockedReason={positions?.readBlockedReason ?? null}\n />\n\n <div className=\"flex items-center justify-between gap-3 py-3\">\n <h2 className=\"text-sm font-semibold text-txt\">Orders</h2>\n {orders?.readBlockedReason ? (\n <div className=\"flex min-w-0 items-center gap-2\">\n <span className=\"min-w-0 truncate text-xs text-muted\">\n {orders.readBlockedReason}\n </span>\n <BlockedPill label=\"Blocked\" />\n </div>\n ) : (\n <span className=\"text-sm font-semibold text-txt\">\n {orders?.orders.length ?? 0}\n </span>\n )}\n </div>\n </section>\n </div>\n )}\n </>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { HyperliquidAccountSummary, HyperliquidPosition } from "./hyperliquid-contracts";
|
|
2
|
+
export interface HyperliquidPositionsPanelProps {
|
|
3
|
+
positions: HyperliquidPosition[];
|
|
4
|
+
summary: HyperliquidAccountSummary | null;
|
|
5
|
+
readBlockedReason: string | null;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The live positions + PnL surface. Renders the account-health hero strip and a
|
|
9
|
+
* dense per-position table, or an honest empty/blocked state. Display only.
|
|
10
|
+
*/
|
|
11
|
+
export declare function HyperliquidPositionsPanel({ positions, summary, readBlockedReason, }: HyperliquidPositionsPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
//# sourceMappingURL=HyperliquidPositionsPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HyperliquidPositionsPanel.d.ts","sourceRoot":"","sources":["../src/HyperliquidPositionsPanel.tsx"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EACV,yBAAyB,EACzB,mBAAmB,EACpB,MAAM,yBAAyB,CAAC;AAwMjC,MAAM,WAAW,8BAA8B;IAC7C,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,OAAO,EAAE,yBAAyB,GAAG,IAAI,CAAC;IAC1C,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,EACxC,SAAS,EACT,OAAO,EACP,iBAAiB,GAClB,EAAE,8BAA8B,2CAwDhC"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import {
|
|
3
|
+
BarChart3,
|
|
4
|
+
ShieldCheck,
|
|
5
|
+
ShieldX,
|
|
6
|
+
TrendingDown,
|
|
7
|
+
TrendingUp
|
|
8
|
+
} from "lucide-react";
|
|
9
|
+
const EMPTY_CELL = "\xB7";
|
|
10
|
+
function toNumber(value) {
|
|
11
|
+
if (value === null || value === void 0) return null;
|
|
12
|
+
const parsed = Number(value);
|
|
13
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
14
|
+
}
|
|
15
|
+
function formatUsd(value, options = {}) {
|
|
16
|
+
if (value === null || !Number.isFinite(value)) return EMPTY_CELL;
|
|
17
|
+
const decimals = options.decimals ?? 2;
|
|
18
|
+
const sign = options.withSign && value > 0 ? "+" : value < 0 ? "-" : "";
|
|
19
|
+
const abs = Math.abs(value);
|
|
20
|
+
const body = abs >= 1e3 ? abs.toLocaleString("en-US", {
|
|
21
|
+
maximumFractionDigits: decimals,
|
|
22
|
+
minimumFractionDigits: decimals
|
|
23
|
+
}) : abs.toFixed(decimals);
|
|
24
|
+
return `${sign}$${body}`;
|
|
25
|
+
}
|
|
26
|
+
function formatUsdCompact(value, options = {}) {
|
|
27
|
+
if (value === null || !Number.isFinite(value)) return EMPTY_CELL;
|
|
28
|
+
const sign = options.withSign && value > 0 ? "+" : value < 0 ? "-" : "";
|
|
29
|
+
const abs = Math.abs(value);
|
|
30
|
+
if (abs >= 1e6) return `${sign}$${(abs / 1e6).toFixed(2)}m`;
|
|
31
|
+
if (abs >= 1e3)
|
|
32
|
+
return `${sign}$${(abs / 1e3).toFixed(abs >= 1e5 ? 0 : 1)}k`;
|
|
33
|
+
return `${sign}$${abs.toFixed(2)}`;
|
|
34
|
+
}
|
|
35
|
+
function formatPrice(value) {
|
|
36
|
+
if (value === null || !Number.isFinite(value)) return EMPTY_CELL;
|
|
37
|
+
const abs = Math.abs(value);
|
|
38
|
+
const decimals = abs >= 1e3 ? 1 : abs >= 1 ? 2 : 5;
|
|
39
|
+
return value.toLocaleString("en-US", {
|
|
40
|
+
maximumFractionDigits: decimals,
|
|
41
|
+
minimumFractionDigits: decimals
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function formatSize(value) {
|
|
45
|
+
const parsed = Number(value);
|
|
46
|
+
if (!Number.isFinite(parsed)) return value;
|
|
47
|
+
return Math.abs(parsed).toLocaleString("en-US", {
|
|
48
|
+
maximumFractionDigits: 4,
|
|
49
|
+
minimumFractionDigits: 0
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function pnlTone(value) {
|
|
53
|
+
if (value === null || value === 0) return "text-muted";
|
|
54
|
+
return value > 0 ? "text-ok" : "text-danger";
|
|
55
|
+
}
|
|
56
|
+
function ReadinessPill({ ready, label }) {
|
|
57
|
+
return /* @__PURE__ */ jsx(
|
|
58
|
+
"span",
|
|
59
|
+
{
|
|
60
|
+
className: `inline-flex h-8 w-8 items-center justify-center ${ready ? "text-ok" : "text-muted"}`,
|
|
61
|
+
role: "status",
|
|
62
|
+
"aria-label": label,
|
|
63
|
+
title: label,
|
|
64
|
+
children: ready ? /* @__PURE__ */ jsx(ShieldCheck, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ShieldX, { className: "h-4 w-4" })
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
function StatTile({
|
|
69
|
+
label,
|
|
70
|
+
value,
|
|
71
|
+
tone = "text-txt"
|
|
72
|
+
}) {
|
|
73
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 px-1 py-2", children: [
|
|
74
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium uppercase tracking-wide text-muted", children: label }),
|
|
75
|
+
/* @__PURE__ */ jsx("span", { className: `font-mono text-lg font-semibold tabular-nums ${tone}`, children: value })
|
|
76
|
+
] });
|
|
77
|
+
}
|
|
78
|
+
function AccountHealthStrip({
|
|
79
|
+
summary
|
|
80
|
+
}) {
|
|
81
|
+
const accountValue = toNumber(summary?.accountValue ?? null);
|
|
82
|
+
const withdrawable = toNumber(summary?.withdrawable ?? null);
|
|
83
|
+
const unrealizedPnl = toNumber(summary?.totalUnrealizedPnl ?? null);
|
|
84
|
+
const leverage = summary?.effectiveLeverage ?? null;
|
|
85
|
+
return /* @__PURE__ */ jsxs("section", { className: "grid grid-cols-2 gap-3 sm:grid-cols-4", children: [
|
|
86
|
+
/* @__PURE__ */ jsx(StatTile, { label: "Account value", value: formatUsdCompact(accountValue) }),
|
|
87
|
+
/* @__PURE__ */ jsx(
|
|
88
|
+
StatTile,
|
|
89
|
+
{
|
|
90
|
+
label: "Effective lev",
|
|
91
|
+
value: leverage === null ? EMPTY_CELL : `${leverage.toFixed(2)}x`
|
|
92
|
+
}
|
|
93
|
+
),
|
|
94
|
+
/* @__PURE__ */ jsx(StatTile, { label: "Withdrawable", value: formatUsdCompact(withdrawable) }),
|
|
95
|
+
/* @__PURE__ */ jsx(
|
|
96
|
+
StatTile,
|
|
97
|
+
{
|
|
98
|
+
label: "Unrealized PnL",
|
|
99
|
+
value: formatUsdCompact(unrealizedPnl, { withSign: true }),
|
|
100
|
+
tone: pnlTone(unrealizedPnl)
|
|
101
|
+
}
|
|
102
|
+
)
|
|
103
|
+
] });
|
|
104
|
+
}
|
|
105
|
+
function PositionRow({ position }) {
|
|
106
|
+
const size = Number(position.size);
|
|
107
|
+
const isLong = Number.isFinite(size) ? size >= 0 : true;
|
|
108
|
+
const unrealizedPnl = toNumber(position.unrealizedPnl);
|
|
109
|
+
const roe = toNumber(position.returnOnEquity);
|
|
110
|
+
const liqDistance = toNumber(position.distanceToLiquidationPct);
|
|
111
|
+
return /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[minmax(0,1.2fr)_repeat(4,minmax(0,1fr))] items-center gap-3 px-4 py-2.5 text-sm", children: [
|
|
112
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
113
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate font-semibold text-txt", children: position.coin }),
|
|
114
|
+
/* @__PURE__ */ jsx(
|
|
115
|
+
"span",
|
|
116
|
+
{
|
|
117
|
+
className: `px-1.5 py-0.5 text-[10px] font-semibold uppercase ${isLong ? "bg-ok/12 text-ok" : "bg-danger/12 text-danger"}`,
|
|
118
|
+
children: isLong ? "long" : "short"
|
|
119
|
+
}
|
|
120
|
+
),
|
|
121
|
+
position.leverageValue !== null && /* @__PURE__ */ jsxs("span", { className: "px-1.5 py-0.5 font-mono text-[10px] text-muted", children: [
|
|
122
|
+
position.leverageValue,
|
|
123
|
+
"x"
|
|
124
|
+
] })
|
|
125
|
+
] }),
|
|
126
|
+
/* @__PURE__ */ jsx("span", { className: "text-right font-mono text-xs tabular-nums text-muted", children: formatSize(position.size) }),
|
|
127
|
+
/* @__PURE__ */ jsx("span", { className: "text-right font-mono text-xs tabular-nums text-muted", children: formatUsd(toNumber(position.positionValue)) }),
|
|
128
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-end leading-tight", children: [
|
|
129
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono text-xs tabular-nums text-txt", children: formatPrice(toNumber(position.entryPx)) }),
|
|
130
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono text-[10px] tabular-nums text-muted", children: liqDistance === null ? EMPTY_CELL : `${liqDistance.toFixed(0)}% to liq` })
|
|
131
|
+
] }),
|
|
132
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-end leading-tight", children: [
|
|
133
|
+
/* @__PURE__ */ jsx(
|
|
134
|
+
"span",
|
|
135
|
+
{
|
|
136
|
+
className: `font-mono text-xs font-semibold tabular-nums ${pnlTone(unrealizedPnl)}`,
|
|
137
|
+
children: formatUsd(unrealizedPnl, { withSign: true })
|
|
138
|
+
}
|
|
139
|
+
),
|
|
140
|
+
roe !== null && /* @__PURE__ */ jsx(
|
|
141
|
+
"span",
|
|
142
|
+
{
|
|
143
|
+
className: `font-mono text-[10px] tabular-nums ${pnlTone(roe)}`,
|
|
144
|
+
children: `${roe > 0 ? "+" : ""}${(roe * 100).toFixed(1)}%`
|
|
145
|
+
}
|
|
146
|
+
)
|
|
147
|
+
] })
|
|
148
|
+
] });
|
|
149
|
+
}
|
|
150
|
+
function HyperliquidPositionsPanel({
|
|
151
|
+
positions,
|
|
152
|
+
summary,
|
|
153
|
+
readBlockedReason
|
|
154
|
+
}) {
|
|
155
|
+
const openPositions = positions.filter((position) => {
|
|
156
|
+
const size = Number(position.size);
|
|
157
|
+
return Number.isFinite(size) && size !== 0;
|
|
158
|
+
});
|
|
159
|
+
const totalPnl = toNumber(summary?.totalUnrealizedPnl ?? null);
|
|
160
|
+
return /* @__PURE__ */ jsxs("section", { className: "space-y-3", children: [
|
|
161
|
+
/* @__PURE__ */ jsx(AccountHealthStrip, { summary }),
|
|
162
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
163
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-1 py-2", children: [
|
|
164
|
+
totalPnl !== null && totalPnl < 0 ? /* @__PURE__ */ jsx(TrendingDown, { className: "h-4 w-4 text-danger" }) : /* @__PURE__ */ jsx(TrendingUp, { className: "h-4 w-4 text-muted" }),
|
|
165
|
+
/* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-txt", children: "Positions" }),
|
|
166
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted", children: openPositions.length }),
|
|
167
|
+
/* @__PURE__ */ jsx("div", { className: "ml-auto", children: /* @__PURE__ */ jsx(
|
|
168
|
+
ReadinessPill,
|
|
169
|
+
{
|
|
170
|
+
ready: !readBlockedReason,
|
|
171
|
+
label: readBlockedReason ? "Blocked" : "Positions readable"
|
|
172
|
+
}
|
|
173
|
+
) })
|
|
174
|
+
] }),
|
|
175
|
+
readBlockedReason ? /* @__PURE__ */ jsx("div", { className: "px-1 py-6 text-center text-xs text-muted", children: readBlockedReason }) : openPositions.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 px-4 py-8 text-center", children: [
|
|
176
|
+
/* @__PURE__ */ jsx(BarChart3, { className: "h-5 w-5 text-muted" }),
|
|
177
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted", children: "no open positions" })
|
|
178
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
179
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[minmax(0,1.2fr)_repeat(4,minmax(0,1fr))] gap-3 px-1 py-2 text-[10px] font-medium uppercase tracking-wide text-muted", children: [
|
|
180
|
+
/* @__PURE__ */ jsx("span", { children: "Asset" }),
|
|
181
|
+
/* @__PURE__ */ jsx("span", { className: "text-right", children: "Size" }),
|
|
182
|
+
/* @__PURE__ */ jsx("span", { className: "text-right", children: "Notional" }),
|
|
183
|
+
/* @__PURE__ */ jsx("span", { className: "text-right", children: "Entry" }),
|
|
184
|
+
/* @__PURE__ */ jsx("span", { className: "text-right", children: "uPnL" })
|
|
185
|
+
] }),
|
|
186
|
+
/* @__PURE__ */ jsx("div", { children: openPositions.map((position) => /* @__PURE__ */ jsx(PositionRow, { position }, position.coin)) })
|
|
187
|
+
] })
|
|
188
|
+
] })
|
|
189
|
+
] });
|
|
190
|
+
}
|
|
191
|
+
export {
|
|
192
|
+
HyperliquidPositionsPanel
|
|
193
|
+
};
|
|
194
|
+
//# sourceMappingURL=HyperliquidPositionsPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/HyperliquidPositionsPanel.tsx"],"sourcesContent":["// Live Hyperliquid positions + PnL surface for the native AppView.\n//\n// Phase 2 of moving a waifu agent's surfaces into its own ElizaOS web UI: this\n// replaces the broken waifu patron panels (active-positions.tsx + pnl-chart.tsx)\n// with a native ElizaOS view that reads the same data shape from the plugin's\n// `/api/hyperliquid/positions` route (which resolves the agent's HL address from\n// its managed vault / env account).\n//\n// It mirrors the waifu \"account health\" UX: a four-stat hero strip (account\n// value, effective leverage, withdrawable, unrealized pnl) over a dense\n// position table (asset/side, size, notional, entry, mark, per-position\n// leverage badge, distance-to-liquidation as a percent, unrealized pnl in\n// green/red). Read-only — no trade execution lives here.\n//\n// Visual language matches HyperliquidAppView exactly: app-core `PagePanel`\n// primitives are not needed for the table rows (static display), so we use the\n// same Tailwind theme tokens the AppView already uses (`text-txt`, `text-muted`,\n// `border-border`, `bg-card`, `text-ok`, `text-danger`). The single non-neutral\n// accents are `text-ok` (profit) and `text-danger` (loss), matching the waifu\n// panel's discipline of one green + one red and nothing else.\n\nimport {\n BarChart3,\n ShieldCheck,\n ShieldX,\n TrendingDown,\n TrendingUp,\n} from \"lucide-react\";\nimport type {\n HyperliquidAccountSummary,\n HyperliquidPosition,\n} from \"./hyperliquid-contracts.js\";\n\nconst EMPTY_CELL = \"·\";\n\nfunction toNumber(value: string | number | null | undefined): number | null {\n if (value === null || value === undefined) return null;\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : null;\n}\n\nfunction formatUsd(\n value: number | null,\n options: { withSign?: boolean; decimals?: number } = {},\n): string {\n if (value === null || !Number.isFinite(value)) return EMPTY_CELL;\n const decimals = options.decimals ?? 2;\n const sign = options.withSign && value > 0 ? \"+\" : value < 0 ? \"-\" : \"\";\n const abs = Math.abs(value);\n const body =\n abs >= 1000\n ? abs.toLocaleString(\"en-US\", {\n maximumFractionDigits: decimals,\n minimumFractionDigits: decimals,\n })\n : abs.toFixed(decimals);\n return `${sign}$${body}`;\n}\n\nfunction formatUsdCompact(\n value: number | null,\n options: { withSign?: boolean } = {},\n): string {\n if (value === null || !Number.isFinite(value)) return EMPTY_CELL;\n const sign = options.withSign && value > 0 ? \"+\" : value < 0 ? \"-\" : \"\";\n const abs = Math.abs(value);\n if (abs >= 1_000_000) return `${sign}$${(abs / 1_000_000).toFixed(2)}m`;\n if (abs >= 1_000)\n return `${sign}$${(abs / 1_000).toFixed(abs >= 100_000 ? 0 : 1)}k`;\n return `${sign}$${abs.toFixed(2)}`;\n}\n\nfunction formatPrice(value: number | null): string {\n if (value === null || !Number.isFinite(value)) return EMPTY_CELL;\n const abs = Math.abs(value);\n const decimals = abs >= 1000 ? 1 : abs >= 1 ? 2 : 5;\n return value.toLocaleString(\"en-US\", {\n maximumFractionDigits: decimals,\n minimumFractionDigits: decimals,\n });\n}\n\nfunction formatSize(value: string): string {\n const parsed = Number(value);\n if (!Number.isFinite(parsed)) return value;\n return Math.abs(parsed).toLocaleString(\"en-US\", {\n maximumFractionDigits: 4,\n minimumFractionDigits: 0,\n });\n}\n\nfunction pnlTone(value: number | null): string {\n if (value === null || value === 0) return \"text-muted\";\n return value > 0 ? \"text-ok\" : \"text-danger\";\n}\n\n// Effective leverage and distance-to-liquidation are computed server-side and\n// arrive as DTO fields (summary.effectiveLeverage, position.distanceToLiquidationPct);\n// the panel only displays them — no financial math lives here.\n\n// Mirrors HyperliquidAppView's ReadinessPill so the \"Blocked\"/readable status\n// language stays identical across the view.\nfunction ReadinessPill({ ready, label }: { ready: boolean; label: string }) {\n return (\n <span\n className={`inline-flex h-8 w-8 items-center justify-center ${ready ? \"text-ok\" : \"text-muted\"}`}\n role=\"status\"\n aria-label={label}\n title={label}\n >\n {ready ? (\n <ShieldCheck className=\"h-4 w-4\" />\n ) : (\n <ShieldX className=\"h-4 w-4\" />\n )}\n </span>\n );\n}\n\nfunction StatTile({\n label,\n value,\n tone = \"text-txt\",\n}: {\n label: string;\n value: string;\n tone?: string;\n}) {\n return (\n <div className=\"flex flex-col gap-1 px-1 py-2\">\n <span className=\"text-[11px] font-medium uppercase tracking-wide text-muted\">\n {label}\n </span>\n <span className={`font-mono text-lg font-semibold tabular-nums ${tone}`}>\n {value}\n </span>\n </div>\n );\n}\n\nfunction AccountHealthStrip({\n summary,\n}: {\n summary: HyperliquidAccountSummary | null;\n}) {\n const accountValue = toNumber(summary?.accountValue ?? null);\n const withdrawable = toNumber(summary?.withdrawable ?? null);\n const unrealizedPnl = toNumber(summary?.totalUnrealizedPnl ?? null);\n const leverage = summary?.effectiveLeverage ?? null;\n\n return (\n <section className=\"grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <StatTile label=\"Account value\" value={formatUsdCompact(accountValue)} />\n <StatTile\n label=\"Effective lev\"\n value={leverage === null ? EMPTY_CELL : `${leverage.toFixed(2)}x`}\n />\n <StatTile label=\"Withdrawable\" value={formatUsdCompact(withdrawable)} />\n <StatTile\n label=\"Unrealized PnL\"\n value={formatUsdCompact(unrealizedPnl, { withSign: true })}\n tone={pnlTone(unrealizedPnl)}\n />\n </section>\n );\n}\n\nfunction PositionRow({ position }: { position: HyperliquidPosition }) {\n const size = Number(position.size);\n const isLong = Number.isFinite(size) ? size >= 0 : true;\n const unrealizedPnl = toNumber(position.unrealizedPnl);\n const roe = toNumber(position.returnOnEquity);\n const liqDistance = toNumber(position.distanceToLiquidationPct);\n\n return (\n <div className=\"grid grid-cols-[minmax(0,1.2fr)_repeat(4,minmax(0,1fr))] items-center gap-3 px-4 py-2.5 text-sm\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <span className=\"min-w-0 truncate font-semibold text-txt\">\n {position.coin}\n </span>\n <span\n className={`px-1.5 py-0.5 text-[10px] font-semibold uppercase ${\n isLong ? \"bg-ok/12 text-ok\" : \"bg-danger/12 text-danger\"\n }`}\n >\n {isLong ? \"long\" : \"short\"}\n </span>\n {position.leverageValue !== null && (\n <span className=\"px-1.5 py-0.5 font-mono text-[10px] text-muted\">\n {position.leverageValue}x\n </span>\n )}\n </div>\n\n <span className=\"text-right font-mono text-xs tabular-nums text-muted\">\n {formatSize(position.size)}\n </span>\n\n <span className=\"text-right font-mono text-xs tabular-nums text-muted\">\n {formatUsd(toNumber(position.positionValue))}\n </span>\n\n <div className=\"flex flex-col items-end leading-tight\">\n <span className=\"font-mono text-xs tabular-nums text-txt\">\n {formatPrice(toNumber(position.entryPx))}\n </span>\n <span className=\"font-mono text-[10px] tabular-nums text-muted\">\n {liqDistance === null\n ? EMPTY_CELL\n : `${liqDistance.toFixed(0)}% to liq`}\n </span>\n </div>\n\n <div className=\"flex flex-col items-end leading-tight\">\n <span\n className={`font-mono text-xs font-semibold tabular-nums ${pnlTone(unrealizedPnl)}`}\n >\n {formatUsd(unrealizedPnl, { withSign: true })}\n </span>\n {roe !== null && (\n <span\n className={`font-mono text-[10px] tabular-nums ${pnlTone(roe)}`}\n >\n {`${roe > 0 ? \"+\" : \"\"}${(roe * 100).toFixed(1)}%`}\n </span>\n )}\n </div>\n </div>\n );\n}\n\nexport interface HyperliquidPositionsPanelProps {\n positions: HyperliquidPosition[];\n summary: HyperliquidAccountSummary | null;\n readBlockedReason: string | null;\n}\n\n/**\n * The live positions + PnL surface. Renders the account-health hero strip and a\n * dense per-position table, or an honest empty/blocked state. Display only.\n */\nexport function HyperliquidPositionsPanel({\n positions,\n summary,\n readBlockedReason,\n}: HyperliquidPositionsPanelProps) {\n const openPositions = positions.filter((position) => {\n const size = Number(position.size);\n return Number.isFinite(size) && size !== 0;\n });\n const totalPnl = toNumber(summary?.totalUnrealizedPnl ?? null);\n\n return (\n <section className=\"space-y-3\">\n <AccountHealthStrip summary={summary} />\n\n <div>\n <div className=\"flex items-center gap-2 px-1 py-2\">\n {totalPnl !== null && totalPnl < 0 ? (\n <TrendingDown className=\"h-4 w-4 text-danger\" />\n ) : (\n <TrendingUp className=\"h-4 w-4 text-muted\" />\n )}\n <h2 className=\"text-sm font-semibold text-txt\">Positions</h2>\n <span className=\"text-xs text-muted\">{openPositions.length}</span>\n <div className=\"ml-auto\">\n <ReadinessPill\n ready={!readBlockedReason}\n label={readBlockedReason ? \"Blocked\" : \"Positions readable\"}\n />\n </div>\n </div>\n\n {readBlockedReason ? (\n <div className=\"px-1 py-6 text-center text-xs text-muted\">\n {readBlockedReason}\n </div>\n ) : openPositions.length === 0 ? (\n <div className=\"flex flex-col items-center gap-2 px-4 py-8 text-center\">\n <BarChart3 className=\"h-5 w-5 text-muted\" />\n <span className=\"text-xs text-muted\">no open positions</span>\n </div>\n ) : (\n <>\n <div className=\"grid grid-cols-[minmax(0,1.2fr)_repeat(4,minmax(0,1fr))] gap-3 px-1 py-2 text-[10px] font-medium uppercase tracking-wide text-muted\">\n <span>Asset</span>\n <span className=\"text-right\">Size</span>\n <span className=\"text-right\">Notional</span>\n <span className=\"text-right\">Entry</span>\n <span className=\"text-right\">uPnL</span>\n </div>\n <div>\n {openPositions.map((position) => (\n <PositionRow key={position.coin} position={position} />\n ))}\n </div>\n </>\n )}\n </div>\n </section>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HyperliquidView — the single GUI/XR data wrapper for the Hyperliquid surface.
|
|
3
|
+
*
|
|
4
|
+
* It owns the live data (status + markets + the agent's own positions + open
|
|
5
|
+
* orders, plus a background poll via {@link useHyperliquidState}) and renders
|
|
6
|
+
* the one presentational {@link HyperliquidSpatialView} inside a
|
|
7
|
+
* {@link SpatialSurface}. Omitting the `modality` prop lets `SpatialSurface`
|
|
8
|
+
* auto-detect GUI vs XR via `window.__elizaXRContext`, so the SAME component
|
|
9
|
+
* serves both surfaces. The TUI surface renders the same
|
|
10
|
+
* `HyperliquidSpatialView` through the terminal registry (see
|
|
11
|
+
* `register-terminal-view.tsx`).
|
|
12
|
+
*/
|
|
13
|
+
export declare function HyperliquidView(): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
//# sourceMappingURL=HyperliquidView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HyperliquidView.d.ts","sourceRoot":"","sources":["../src/HyperliquidView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAoBH,wBAAgB,eAAe,4CA4C9B"}
|