@raintree-technology/perps 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (316) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/LICENSE +21 -0
  3. package/README.md +175 -0
  4. package/dist/adapters/aevo.d.ts +64 -0
  5. package/dist/adapters/aevo.js +899 -0
  6. package/dist/adapters/certification.d.ts +33 -0
  7. package/dist/adapters/certification.js +99 -0
  8. package/dist/adapters/decibel/order-manager.d.ts +45 -0
  9. package/dist/adapters/decibel/order-manager.js +140 -0
  10. package/dist/adapters/decibel/rest-client.d.ts +176 -0
  11. package/dist/adapters/decibel/rest-client.js +155 -0
  12. package/dist/adapters/decibel/ws-feed.d.ts +28 -0
  13. package/dist/adapters/decibel/ws-feed.js +166 -0
  14. package/dist/adapters/decibel.d.ts +108 -0
  15. package/dist/adapters/decibel.js +1377 -0
  16. package/dist/adapters/hyperliquid.d.ts +63 -0
  17. package/dist/adapters/hyperliquid.js +797 -0
  18. package/dist/adapters/index.d.ts +11 -0
  19. package/dist/adapters/index.js +12 -0
  20. package/dist/adapters/interface.d.ts +310 -0
  21. package/dist/adapters/interface.js +15 -0
  22. package/dist/adapters/orderly.d.ts +70 -0
  23. package/dist/adapters/orderly.js +936 -0
  24. package/dist/adapters/paradex.d.ts +69 -0
  25. package/dist/adapters/paradex.js +862 -0
  26. package/dist/adapters/utils.d.ts +17 -0
  27. package/dist/adapters/utils.js +122 -0
  28. package/dist/cli/command-metadata.d.ts +2 -0
  29. package/dist/cli/command-metadata.js +44 -0
  30. package/dist/cli/context.d.ts +14 -0
  31. package/dist/cli/context.js +59 -0
  32. package/dist/cli/experience.d.ts +48 -0
  33. package/dist/cli/experience.js +243 -0
  34. package/dist/cli/ink/app/AppShell.d.ts +12 -0
  35. package/dist/cli/ink/app/AppShell.js +32 -0
  36. package/dist/cli/ink/app/MetricStrip.d.ts +6 -0
  37. package/dist/cli/ink/app/MetricStrip.js +14 -0
  38. package/dist/cli/ink/app/Panel.d.ts +9 -0
  39. package/dist/cli/ink/app/Panel.js +7 -0
  40. package/dist/cli/ink/app/ascii.d.ts +2 -0
  41. package/dist/cli/ink/app/ascii.js +46 -0
  42. package/dist/cli/ink/app/index.d.ts +5 -0
  43. package/dist/cli/ink/app/index.js +4 -0
  44. package/dist/cli/ink/app/types.d.ts +15 -0
  45. package/dist/cli/ink/app/types.js +1 -0
  46. package/dist/cli/ink/components/PnL.d.ts +12 -0
  47. package/dist/cli/ink/components/PnL.js +23 -0
  48. package/dist/cli/ink/components/Spinner.d.ts +13 -0
  49. package/dist/cli/ink/components/Spinner.js +13 -0
  50. package/dist/cli/ink/components/Table.d.ts +14 -0
  51. package/dist/cli/ink/components/Table.js +42 -0
  52. package/dist/cli/ink/components/WatchHeader.d.ts +10 -0
  53. package/dist/cli/ink/components/WatchHeader.js +18 -0
  54. package/dist/cli/ink/components/index.d.ts +4 -0
  55. package/dist/cli/ink/components/index.js +4 -0
  56. package/dist/cli/ink/index.d.ts +4 -0
  57. package/dist/cli/ink/index.js +4 -0
  58. package/dist/cli/ink/render.d.ts +12 -0
  59. package/dist/cli/ink/render.js +21 -0
  60. package/dist/cli/ink/theme.d.ts +29 -0
  61. package/dist/cli/ink/theme.js +40 -0
  62. package/dist/cli/network-defaults.d.ts +10 -0
  63. package/dist/cli/network-defaults.js +35 -0
  64. package/dist/cli/output.d.ts +11 -0
  65. package/dist/cli/output.js +115 -0
  66. package/dist/cli/program.d.ts +18 -0
  67. package/dist/cli/program.js +164 -0
  68. package/dist/cli/watch.d.ts +19 -0
  69. package/dist/cli/watch.js +35 -0
  70. package/dist/client/index.d.ts +55 -0
  71. package/dist/client/index.js +157 -0
  72. package/dist/commands/account/add.d.ts +2 -0
  73. package/dist/commands/account/add.js +510 -0
  74. package/dist/commands/account/balances-simple.d.ts +5 -0
  75. package/dist/commands/account/balances-simple.js +63 -0
  76. package/dist/commands/account/index.d.ts +2 -0
  77. package/dist/commands/account/index.js +17 -0
  78. package/dist/commands/account/ls.d.ts +2 -0
  79. package/dist/commands/account/ls.js +95 -0
  80. package/dist/commands/account/positions-simple.d.ts +5 -0
  81. package/dist/commands/account/positions-simple.js +77 -0
  82. package/dist/commands/account/remove.d.ts +2 -0
  83. package/dist/commands/account/remove.js +47 -0
  84. package/dist/commands/account/set-default.d.ts +2 -0
  85. package/dist/commands/account/set-default.js +47 -0
  86. package/dist/commands/agent/index.d.ts +2 -0
  87. package/dist/commands/agent/index.js +126 -0
  88. package/dist/commands/arb/alert.d.ts +6 -0
  89. package/dist/commands/arb/alert.js +88 -0
  90. package/dist/commands/arb/basis-execute.d.ts +6 -0
  91. package/dist/commands/arb/basis-execute.js +332 -0
  92. package/dist/commands/arb/basis.d.ts +6 -0
  93. package/dist/commands/arb/basis.js +181 -0
  94. package/dist/commands/arb/compare.d.ts +6 -0
  95. package/dist/commands/arb/compare.js +216 -0
  96. package/dist/commands/arb/execute.d.ts +6 -0
  97. package/dist/commands/arb/execute.js +467 -0
  98. package/dist/commands/arb/funding.d.ts +6 -0
  99. package/dist/commands/arb/funding.js +201 -0
  100. package/dist/commands/arb/history.d.ts +6 -0
  101. package/dist/commands/arb/history.js +153 -0
  102. package/dist/commands/arb/index.d.ts +6 -0
  103. package/dist/commands/arb/index.js +29 -0
  104. package/dist/commands/arb/positions.d.ts +6 -0
  105. package/dist/commands/arb/positions.js +158 -0
  106. package/dist/commands/arb/spread.d.ts +6 -0
  107. package/dist/commands/arb/spread.js +253 -0
  108. package/dist/commands/arb/track.d.ts +6 -0
  109. package/dist/commands/arb/track.js +259 -0
  110. package/dist/commands/asset/book-simple.d.ts +5 -0
  111. package/dist/commands/asset/book-simple.js +77 -0
  112. package/dist/commands/asset/index.d.ts +2 -0
  113. package/dist/commands/asset/index.js +5 -0
  114. package/dist/commands/completion.d.ts +2 -0
  115. package/dist/commands/completion.js +161 -0
  116. package/dist/commands/config/index.d.ts +5 -0
  117. package/dist/commands/config/index.js +109 -0
  118. package/dist/commands/data/index.d.ts +31 -0
  119. package/dist/commands/data/index.js +1466 -0
  120. package/dist/commands/doctor.d.ts +2 -0
  121. package/dist/commands/doctor.js +201 -0
  122. package/dist/commands/exchange/index.d.ts +2 -0
  123. package/dist/commands/exchange/index.js +107 -0
  124. package/dist/commands/index.d.ts +2 -0
  125. package/dist/commands/index.js +48 -0
  126. package/dist/commands/markets/index.d.ts +2 -0
  127. package/dist/commands/markets/index.js +5 -0
  128. package/dist/commands/markets/ls-simple.d.ts +7 -0
  129. package/dist/commands/markets/ls-simple.js +277 -0
  130. package/dist/commands/operator/index.d.ts +2 -0
  131. package/dist/commands/operator/index.js +146 -0
  132. package/dist/commands/order/cancel-simple.d.ts +5 -0
  133. package/dist/commands/order/cancel-simple.js +104 -0
  134. package/dist/commands/order/index.d.ts +2 -0
  135. package/dist/commands/order/index.js +13 -0
  136. package/dist/commands/order/limit-simple.d.ts +5 -0
  137. package/dist/commands/order/limit-simple.js +195 -0
  138. package/dist/commands/order/market-simple.d.ts +5 -0
  139. package/dist/commands/order/market-simple.js +190 -0
  140. package/dist/commands/order/shared.d.ts +17 -0
  141. package/dist/commands/order/shared.js +51 -0
  142. package/dist/commands/order/trigger-simple.d.ts +5 -0
  143. package/dist/commands/order/trigger-simple.js +246 -0
  144. package/dist/commands/referral/index.d.ts +2 -0
  145. package/dist/commands/referral/index.js +7 -0
  146. package/dist/commands/referral/set.d.ts +2 -0
  147. package/dist/commands/referral/set.js +26 -0
  148. package/dist/commands/referral/status.d.ts +2 -0
  149. package/dist/commands/referral/status.js +31 -0
  150. package/dist/commands/replay/index.d.ts +2 -0
  151. package/dist/commands/replay/index.js +152 -0
  152. package/dist/commands/risk/analytics.d.ts +2 -0
  153. package/dist/commands/risk/analytics.js +64 -0
  154. package/dist/commands/risk/audit.d.ts +2 -0
  155. package/dist/commands/risk/audit.js +52 -0
  156. package/dist/commands/risk/index.d.ts +2 -0
  157. package/dist/commands/risk/index.js +9 -0
  158. package/dist/commands/risk/rules.d.ts +2 -0
  159. package/dist/commands/risk/rules.js +102 -0
  160. package/dist/commands/server.d.ts +2 -0
  161. package/dist/commands/server.js +208 -0
  162. package/dist/commands/setup/index.d.ts +2 -0
  163. package/dist/commands/setup/index.js +478 -0
  164. package/dist/commands/signal/index.d.ts +2 -0
  165. package/dist/commands/signal/index.js +129 -0
  166. package/dist/commands/state/index.d.ts +2 -0
  167. package/dist/commands/state/index.js +5 -0
  168. package/dist/commands/state/show.d.ts +2 -0
  169. package/dist/commands/state/show.js +105 -0
  170. package/dist/commands/strategy/index.d.ts +4 -0
  171. package/dist/commands/strategy/index.js +73 -0
  172. package/dist/commands/traces/index.d.ts +2 -0
  173. package/dist/commands/traces/index.js +76 -0
  174. package/dist/commands/ui/demo.d.ts +9 -0
  175. package/dist/commands/ui/demo.js +195 -0
  176. package/dist/commands/ui/index.d.ts +2 -0
  177. package/dist/commands/ui/index.js +7 -0
  178. package/dist/commands/ui/terminal.d.ts +2 -0
  179. package/dist/commands/ui/terminal.js +255 -0
  180. package/dist/commands/upgrade.d.ts +2 -0
  181. package/dist/commands/upgrade.js +98 -0
  182. package/dist/index.d.ts +2 -0
  183. package/dist/index.js +4 -0
  184. package/dist/lib/agent/audit.d.ts +12 -0
  185. package/dist/lib/agent/audit.js +13 -0
  186. package/dist/lib/agent/gateway.d.ts +13 -0
  187. package/dist/lib/agent/gateway.js +598 -0
  188. package/dist/lib/agent/metrics.d.ts +33 -0
  189. package/dist/lib/agent/metrics.js +175 -0
  190. package/dist/lib/agent/signature.d.ts +8 -0
  191. package/dist/lib/agent/signature.js +28 -0
  192. package/dist/lib/agent/tools.d.ts +28 -0
  193. package/dist/lib/agent/tools.js +453 -0
  194. package/dist/lib/agent/x402.d.ts +23 -0
  195. package/dist/lib/agent/x402.js +62 -0
  196. package/dist/lib/api-wallet.d.ts +69 -0
  197. package/dist/lib/api-wallet.js +101 -0
  198. package/dist/lib/balance-watcher.d.ts +25 -0
  199. package/dist/lib/balance-watcher.js +83 -0
  200. package/dist/lib/book-watcher.d.ts +25 -0
  201. package/dist/lib/book-watcher.js +48 -0
  202. package/dist/lib/config.d.ts +88 -0
  203. package/dist/lib/config.js +427 -0
  204. package/dist/lib/constants.d.ts +50 -0
  205. package/dist/lib/constants.js +84 -0
  206. package/dist/lib/contracts.d.ts +7 -0
  207. package/dist/lib/contracts.js +8 -0
  208. package/dist/lib/credential-vault.d.ts +22 -0
  209. package/dist/lib/credential-vault.js +109 -0
  210. package/dist/lib/db/accounts.d.ts +83 -0
  211. package/dist/lib/db/accounts.js +203 -0
  212. package/dist/lib/db/funding-history.d.ts +69 -0
  213. package/dist/lib/db/funding-history.js +183 -0
  214. package/dist/lib/db/index.d.ts +11 -0
  215. package/dist/lib/db/index.js +272 -0
  216. package/dist/lib/events/bus.d.ts +10 -0
  217. package/dist/lib/events/bus.js +17 -0
  218. package/dist/lib/events/types.d.ts +51 -0
  219. package/dist/lib/events/types.js +1 -0
  220. package/dist/lib/exchange.d.ts +30 -0
  221. package/dist/lib/exchange.js +84 -0
  222. package/dist/lib/execution/journal.d.ts +25 -0
  223. package/dist/lib/execution/journal.js +158 -0
  224. package/dist/lib/execution/safety.d.ts +34 -0
  225. package/dist/lib/execution/safety.js +197 -0
  226. package/dist/lib/exit-codes.d.ts +18 -0
  227. package/dist/lib/exit-codes.js +60 -0
  228. package/dist/lib/fetch.d.ts +18 -0
  229. package/dist/lib/fetch.js +66 -0
  230. package/dist/lib/fs-security.d.ts +10 -0
  231. package/dist/lib/fs-security.js +26 -0
  232. package/dist/lib/funding-tracker.d.ts +40 -0
  233. package/dist/lib/funding-tracker.js +118 -0
  234. package/dist/lib/logger.d.ts +27 -0
  235. package/dist/lib/logger.js +82 -0
  236. package/dist/lib/network-model.d.ts +13 -0
  237. package/dist/lib/network-model.js +30 -0
  238. package/dist/lib/onboarding.d.ts +133 -0
  239. package/dist/lib/onboarding.js +1459 -0
  240. package/dist/lib/operator-state.d.ts +25 -0
  241. package/dist/lib/operator-state.js +82 -0
  242. package/dist/lib/orders-watcher.d.ts +24 -0
  243. package/dist/lib/orders-watcher.js +74 -0
  244. package/dist/lib/paths.d.ts +20 -0
  245. package/dist/lib/paths.js +23 -0
  246. package/dist/lib/portfolio-watcher.d.ts +33 -0
  247. package/dist/lib/portfolio-watcher.js +95 -0
  248. package/dist/lib/position-watcher.d.ts +16 -0
  249. package/dist/lib/position-watcher.js +44 -0
  250. package/dist/lib/price-watcher.d.ts +15 -0
  251. package/dist/lib/price-watcher.js +84 -0
  252. package/dist/lib/prompts.d.ts +32 -0
  253. package/dist/lib/prompts.js +105 -0
  254. package/dist/lib/rate-limit.d.ts +32 -0
  255. package/dist/lib/rate-limit.js +88 -0
  256. package/dist/lib/risk/analytics.d.ts +39 -0
  257. package/dist/lib/risk/analytics.js +98 -0
  258. package/dist/lib/risk/drawdown.d.ts +18 -0
  259. package/dist/lib/risk/drawdown.js +49 -0
  260. package/dist/lib/risk/evaluation-log.d.ts +29 -0
  261. package/dist/lib/risk/evaluation-log.js +61 -0
  262. package/dist/lib/risk/index.d.ts +4 -0
  263. package/dist/lib/risk/index.js +4 -0
  264. package/dist/lib/risk/limits.d.ts +23 -0
  265. package/dist/lib/risk/limits.js +27 -0
  266. package/dist/lib/risk/manager.d.ts +32 -0
  267. package/dist/lib/risk/manager.js +85 -0
  268. package/dist/lib/risk/policy-middleware.d.ts +33 -0
  269. package/dist/lib/risk/policy-middleware.js +267 -0
  270. package/dist/lib/risk/position-sizer.d.ts +9 -0
  271. package/dist/lib/risk/position-sizer.js +14 -0
  272. package/dist/lib/risk/rules-store.d.ts +16 -0
  273. package/dist/lib/risk/rules-store.js +47 -0
  274. package/dist/lib/schema.d.ts +254 -0
  275. package/dist/lib/schema.js +199 -0
  276. package/dist/lib/secrets.d.ts +3 -0
  277. package/dist/lib/secrets.js +62 -0
  278. package/dist/lib/settings.d.ts +24 -0
  279. package/dist/lib/settings.js +86 -0
  280. package/dist/lib/signals.d.ts +73 -0
  281. package/dist/lib/signals.js +136 -0
  282. package/dist/lib/stable-stringify.d.ts +6 -0
  283. package/dist/lib/stable-stringify.js +17 -0
  284. package/dist/lib/state-context.d.ts +44 -0
  285. package/dist/lib/state-context.js +133 -0
  286. package/dist/lib/strategy/basis-trade.d.ts +2 -0
  287. package/dist/lib/strategy/basis-trade.js +24 -0
  288. package/dist/lib/strategy/funding-arb.d.ts +2 -0
  289. package/dist/lib/strategy/funding-arb.js +23 -0
  290. package/dist/lib/strategy/interface.d.ts +23 -0
  291. package/dist/lib/strategy/interface.js +1 -0
  292. package/dist/lib/strategy/registry.d.ts +4 -0
  293. package/dist/lib/strategy/registry.js +10 -0
  294. package/dist/lib/telemetry.d.ts +25 -0
  295. package/dist/lib/telemetry.js +101 -0
  296. package/dist/lib/trace-queries.d.ts +20 -0
  297. package/dist/lib/trace-queries.js +133 -0
  298. package/dist/lib/trace.d.ts +1 -0
  299. package/dist/lib/trace.js +4 -0
  300. package/dist/lib/trade-reputation.d.ts +6 -0
  301. package/dist/lib/trade-reputation.js +99 -0
  302. package/dist/lib/ui-tokens.d.ts +21 -0
  303. package/dist/lib/ui-tokens.js +26 -0
  304. package/dist/lib/validate.d.ts +39 -0
  305. package/dist/lib/validate.js +108 -0
  306. package/dist/lib/validation.d.ts +9 -0
  307. package/dist/lib/validation.js +64 -0
  308. package/dist/server/cache.d.ts +38 -0
  309. package/dist/server/cache.js +56 -0
  310. package/dist/server/index.d.ts +2 -0
  311. package/dist/server/index.js +89 -0
  312. package/dist/server/ipc.d.ts +18 -0
  313. package/dist/server/ipc.js +159 -0
  314. package/dist/server/subscriptions.d.ts +18 -0
  315. package/dist/server/subscriptions.js +114 -0
  316. package/package.json +124 -0
@@ -0,0 +1,25 @@
1
+ export interface OperatorHeartbeatSnapshot {
2
+ exchange: string;
3
+ market?: string;
4
+ equity: number;
5
+ exposureUsd: number;
6
+ drawdownPct: number;
7
+ peakEquity: number;
8
+ halted: boolean;
9
+ haltReason?: string;
10
+ updatedAt: number;
11
+ }
12
+ export interface KillSwitchState {
13
+ enabled: boolean;
14
+ reason?: string;
15
+ updatedAt: number;
16
+ }
17
+ export interface OperatorState {
18
+ heartbeat: OperatorHeartbeatSnapshot | null;
19
+ killSwitch: KillSwitchState;
20
+ }
21
+ export declare function readOperatorState(): OperatorState;
22
+ export declare function writeOperatorState(state: OperatorState): void;
23
+ export declare function updateOperatorHeartbeat(heartbeat: OperatorHeartbeatSnapshot): OperatorState;
24
+ export declare function setKillSwitch(enabled: boolean, reason?: string): OperatorState;
25
+ export declare function resetOperatorState(): void;
@@ -0,0 +1,82 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { eventBus } from "./events/bus.js";
3
+ import { HL_DIR, OPERATOR_STATE_PATH } from "./paths.js";
4
+ import { ensurePrivateDir, hardenPrivateFile, PRIVATE_FILE_MODE } from "./fs-security.js";
5
+ const DEFAULT_OPERATOR_STATE = {
6
+ heartbeat: null,
7
+ killSwitch: {
8
+ enabled: false,
9
+ updatedAt: 0,
10
+ },
11
+ };
12
+ function ensureOperatorStateDir() {
13
+ ensurePrivateDir(HL_DIR);
14
+ }
15
+ export function readOperatorState() {
16
+ ensureOperatorStateDir();
17
+ if (!existsSync(OPERATOR_STATE_PATH)) {
18
+ return { ...DEFAULT_OPERATOR_STATE };
19
+ }
20
+ try {
21
+ const raw = readFileSync(OPERATOR_STATE_PATH, "utf-8");
22
+ const parsed = JSON.parse(raw);
23
+ return {
24
+ heartbeat: parsed.heartbeat ?? null,
25
+ killSwitch: {
26
+ enabled: parsed.killSwitch?.enabled ?? false,
27
+ reason: parsed.killSwitch?.reason,
28
+ updatedAt: parsed.killSwitch?.updatedAt ?? 0,
29
+ },
30
+ };
31
+ }
32
+ catch {
33
+ return { ...DEFAULT_OPERATOR_STATE };
34
+ }
35
+ }
36
+ export function writeOperatorState(state) {
37
+ ensureOperatorStateDir();
38
+ writeFileSync(OPERATOR_STATE_PATH, `${JSON.stringify(state, null, 2)}\n`, {
39
+ encoding: "utf-8",
40
+ mode: PRIVATE_FILE_MODE,
41
+ });
42
+ hardenPrivateFile(OPERATOR_STATE_PATH);
43
+ }
44
+ export function updateOperatorHeartbeat(heartbeat) {
45
+ const state = readOperatorState();
46
+ const next = {
47
+ ...state,
48
+ heartbeat,
49
+ };
50
+ writeOperatorState(next);
51
+ return next;
52
+ }
53
+ export function setKillSwitch(enabled, reason) {
54
+ const state = readOperatorState();
55
+ const next = {
56
+ ...state,
57
+ killSwitch: {
58
+ enabled,
59
+ reason,
60
+ updatedAt: Date.now(),
61
+ },
62
+ };
63
+ writeOperatorState(next);
64
+ if (enabled) {
65
+ eventBus.emit("operator.halt", {
66
+ reason: reason ?? "Manual kill switch",
67
+ source: "manual",
68
+ timestamp: Date.now(),
69
+ });
70
+ }
71
+ else {
72
+ eventBus.emit("operator.resume", {
73
+ timestamp: Date.now(),
74
+ });
75
+ }
76
+ return next;
77
+ }
78
+ export function resetOperatorState() {
79
+ writeOperatorState({
80
+ ...DEFAULT_OPERATOR_STATE,
81
+ });
82
+ }
@@ -0,0 +1,24 @@
1
+ import type { Address } from "viem";
2
+ export interface OrderData {
3
+ oid: number;
4
+ coin: string;
5
+ side: string;
6
+ sz: string;
7
+ limitPx: string;
8
+ timestamp: number;
9
+ }
10
+ export interface OrdersWatcher {
11
+ start(): Promise<void>;
12
+ stop(): Promise<void>;
13
+ }
14
+ export interface OrdersWatcherConfig {
15
+ user: Address;
16
+ isTestnet: boolean;
17
+ onUpdate: (orders: OrderData[]) => void;
18
+ onError: (error: Error) => void;
19
+ }
20
+ /**
21
+ * Creates an orders watcher that subscribes to orderUpdates
22
+ * and polls open orders on each update
23
+ */
24
+ export declare function createOrdersWatcher(config: OrdersWatcherConfig): OrdersWatcher;
@@ -0,0 +1,74 @@
1
+ import { WebSocketTransport, SubscriptionClient, HttpTransport, InfoClient, } from "@nktkas/hyperliquid";
2
+ import WebSocket from "ws";
3
+ /**
4
+ * Creates an orders watcher that subscribes to orderUpdates
5
+ * and polls open orders on each update
6
+ */
7
+ export function createOrdersWatcher(config) {
8
+ let wsTransport = null;
9
+ let subscriptionClient = null;
10
+ let subscription = null;
11
+ let httpClient = null;
12
+ const fetchOrders = async () => {
13
+ if (!httpClient)
14
+ return [];
15
+ const orders = await httpClient.openOrders({ user: config.user, dex: "ALL_DEXS" });
16
+ return orders.map((o) => ({
17
+ oid: o.oid,
18
+ coin: o.coin,
19
+ side: o.side,
20
+ sz: o.sz,
21
+ limitPx: o.limitPx,
22
+ timestamp: o.timestamp,
23
+ }));
24
+ };
25
+ return {
26
+ async start() {
27
+ // Create HTTP client for polling open orders
28
+ const httpTransport = new HttpTransport({ isTestnet: config.isTestnet });
29
+ httpClient = new InfoClient({ transport: httpTransport });
30
+ // Fetch initial orders
31
+ const initialOrders = await fetchOrders();
32
+ config.onUpdate(initialOrders);
33
+ wsTransport = new WebSocketTransport({
34
+ isTestnet: config.isTestnet,
35
+ reconnect: { WebSocket: WebSocket },
36
+ });
37
+ subscriptionClient = new SubscriptionClient({ transport: wsTransport });
38
+ await wsTransport.ready();
39
+ // Subscribe to order updates
40
+ subscription = await subscriptionClient.orderUpdates({ user: config.user }, async () => {
41
+ // Re-fetch orders on any update
42
+ try {
43
+ const orders = await fetchOrders();
44
+ config.onUpdate(orders);
45
+ }
46
+ catch (err) {
47
+ config.onError(err instanceof Error ? err : new Error(String(err)));
48
+ }
49
+ });
50
+ },
51
+ async stop() {
52
+ if (subscription) {
53
+ try {
54
+ await subscription.unsubscribe();
55
+ }
56
+ catch {
57
+ // Ignore errors during unsubscribe
58
+ }
59
+ subscription = null;
60
+ }
61
+ if (wsTransport) {
62
+ try {
63
+ await wsTransport.close();
64
+ }
65
+ catch {
66
+ // Ignore errors during close
67
+ }
68
+ wsTransport = null;
69
+ }
70
+ subscriptionClient = null;
71
+ httpClient = null;
72
+ },
73
+ };
74
+ }
@@ -0,0 +1,20 @@
1
+ export declare const PERP_DIR: string;
2
+ export declare const LEGACY_HL_DIR: string;
3
+ export declare const HL_DIR: string;
4
+ export declare const SERVER_SOCKET_PATH: string;
5
+ export declare const SERVER_PID_PATH: string;
6
+ export declare const SERVER_LOG_PATH: string;
7
+ export declare const SERVER_CONFIG_PATH: string;
8
+ export declare const OPERATOR_STATE_PATH: string;
9
+ export declare const TELEMETRY_PATH: string;
10
+ export declare const CREDENTIAL_VAULT_PATH: string;
11
+ export declare const ONBOARDING_STATE_DIR: string;
12
+ export declare const AGENT_AUDIT_LOG_PATH: string;
13
+ export declare const AGENT_METRICS_PATH: string;
14
+ export declare const DB_PATH: string;
15
+ export declare const LEGACY_DB_PATH: string;
16
+ export declare const MASTER_KEY_PATH: string;
17
+ export interface ServerConfig {
18
+ testnet: boolean;
19
+ startedAt: number;
20
+ }
@@ -0,0 +1,23 @@
1
+ import { homedir } from "node:os";
2
+ import { join } from "node:path";
3
+ // Base directory for all perps runtime files
4
+ export const PERP_DIR = join(homedir(), ".perp");
5
+ // Legacy path retained for one-way migration helpers
6
+ export const LEGACY_HL_DIR = join(homedir(), ".hl");
7
+ // Backward-compatible alias for older imports
8
+ export const HL_DIR = PERP_DIR;
9
+ // Server files
10
+ export const SERVER_SOCKET_PATH = join(PERP_DIR, "server.sock");
11
+ export const SERVER_PID_PATH = join(PERP_DIR, "server.pid");
12
+ export const SERVER_LOG_PATH = join(PERP_DIR, "server.log");
13
+ export const SERVER_CONFIG_PATH = join(PERP_DIR, "server.json");
14
+ export const OPERATOR_STATE_PATH = join(PERP_DIR, "operator-state.json");
15
+ export const TELEMETRY_PATH = join(PERP_DIR, "telemetry.json");
16
+ export const CREDENTIAL_VAULT_PATH = join(PERP_DIR, "credentials-vault.json");
17
+ export const ONBOARDING_STATE_DIR = join(PERP_DIR, "onboarding");
18
+ export const AGENT_AUDIT_LOG_PATH = join(PERP_DIR, "agent-audit.log");
19
+ export const AGENT_METRICS_PATH = join(PERP_DIR, "agent-metrics.json");
20
+ // Database files
21
+ export const DB_PATH = join(PERP_DIR, "perp.db");
22
+ export const LEGACY_DB_PATH = join(LEGACY_HL_DIR, "hl.db");
23
+ export const MASTER_KEY_PATH = join(PERP_DIR, "master.key");
@@ -0,0 +1,33 @@
1
+ import type { Address } from "viem";
2
+ export interface PortfolioData {
3
+ positions: Array<{
4
+ coin: string;
5
+ size: string;
6
+ entryPx: string;
7
+ positionValue: string;
8
+ unrealizedPnl: string;
9
+ leverage: string;
10
+ }>;
11
+ spotBalances: Array<{
12
+ token: string;
13
+ total: string;
14
+ hold: string;
15
+ }>;
16
+ accountValue: string;
17
+ totalMarginUsed: string;
18
+ }
19
+ export interface PortfolioWatcher {
20
+ start(): Promise<void>;
21
+ stop(): Promise<void>;
22
+ }
23
+ export interface PortfolioWatcherConfig {
24
+ user: Address;
25
+ isTestnet: boolean;
26
+ onUpdate: (data: PortfolioData) => void;
27
+ onError: (error: Error) => void;
28
+ }
29
+ /**
30
+ * Creates a portfolio watcher that subscribes to perp state updates
31
+ * and polls spot balances on each update
32
+ */
33
+ export declare function createPortfolioWatcher(config: PortfolioWatcherConfig): PortfolioWatcher;
@@ -0,0 +1,95 @@
1
+ import { WebSocketTransport, SubscriptionClient, HttpTransport, InfoClient } from "@nktkas/hyperliquid";
2
+ import WebSocket from "ws";
3
+ /**
4
+ * Creates a portfolio watcher that subscribes to perp state updates
5
+ * and polls spot balances on each update
6
+ */
7
+ export function createPortfolioWatcher(config) {
8
+ let wsTransport = null;
9
+ let subscriptionClient = null;
10
+ let perpSubscription = null;
11
+ let httpClient = null;
12
+ return {
13
+ async start() {
14
+ // Create HTTP client for spot balance polling
15
+ const httpTransport = new HttpTransport({ isTestnet: config.isTestnet });
16
+ httpClient = new InfoClient({ transport: httpTransport });
17
+ // Fetch initial spot state
18
+ const spotState = await httpClient.spotClearinghouseState({ user: config.user });
19
+ let currentSpotBalances = spotState.balances
20
+ .filter((b) => parseFloat(b.total) !== 0)
21
+ .map((b) => ({
22
+ token: b.coin,
23
+ total: b.total,
24
+ hold: b.hold,
25
+ }));
26
+ wsTransport = new WebSocketTransport({
27
+ isTestnet: config.isTestnet,
28
+ reconnect: { WebSocket: WebSocket },
29
+ });
30
+ subscriptionClient = new SubscriptionClient({ transport: wsTransport });
31
+ await wsTransport.ready();
32
+ // Subscribe to perp clearinghouse state
33
+ perpSubscription = await subscriptionClient.allDexsClearinghouseState({ user: config.user }, async (state) => {
34
+ const clearinghouseState = state.clearinghouseStates[0]?.[1];
35
+ const accountValue = clearinghouseState?.marginSummary.accountValue || "0";
36
+ const totalMarginUsed = clearinghouseState?.marginSummary.totalMarginUsed || "0";
37
+ const positions = state.clearinghouseStates
38
+ .flatMap((c) => c[1].assetPositions)
39
+ .filter((p) => parseFloat(p.position.szi) !== 0)
40
+ .map((p) => ({
41
+ coin: p.position.coin,
42
+ size: p.position.szi,
43
+ entryPx: p.position.entryPx,
44
+ positionValue: p.position.positionValue,
45
+ unrealizedPnl: p.position.unrealizedPnl,
46
+ leverage: `${p.position.leverage.value}x ${p.position.leverage.type}`,
47
+ }));
48
+ // Refresh spot balances on each perp update
49
+ if (httpClient) {
50
+ try {
51
+ const freshSpotState = await httpClient.spotClearinghouseState({ user: config.user });
52
+ currentSpotBalances = freshSpotState.balances
53
+ .filter((b) => parseFloat(b.total) !== 0)
54
+ .map((b) => ({
55
+ token: b.coin,
56
+ total: b.total,
57
+ hold: b.hold,
58
+ }));
59
+ }
60
+ catch {
61
+ // Keep previous spot balances on error
62
+ }
63
+ }
64
+ config.onUpdate({
65
+ positions,
66
+ spotBalances: currentSpotBalances,
67
+ accountValue,
68
+ totalMarginUsed,
69
+ });
70
+ });
71
+ },
72
+ async stop() {
73
+ if (perpSubscription) {
74
+ try {
75
+ await perpSubscription.unsubscribe();
76
+ }
77
+ catch {
78
+ // Ignore errors during unsubscribe
79
+ }
80
+ perpSubscription = null;
81
+ }
82
+ if (wsTransport) {
83
+ try {
84
+ await wsTransport.close();
85
+ }
86
+ catch {
87
+ // Ignore errors during close
88
+ }
89
+ wsTransport = null;
90
+ }
91
+ subscriptionClient = null;
92
+ httpClient = null;
93
+ },
94
+ };
95
+ }
@@ -0,0 +1,16 @@
1
+ import type { Address } from "viem";
2
+ import { AllDexsClearinghouseStateEvent } from "@nktkas/hyperliquid/api/subscription";
3
+ export interface PositionWatcher {
4
+ start(): Promise<void>;
5
+ stop(): Promise<void>;
6
+ }
7
+ export interface PositionWatcherConfig {
8
+ user: Address;
9
+ isTestnet: boolean;
10
+ onUpdate: (state: AllDexsClearinghouseStateEvent) => void;
11
+ onError: (error: Error) => void;
12
+ }
13
+ /**
14
+ * Creates a position watcher that subscribes to clearinghouseState updates via WebSocket
15
+ */
16
+ export declare function createPositionWatcher(config: PositionWatcherConfig): PositionWatcher;
@@ -0,0 +1,44 @@
1
+ import { WebSocketTransport, SubscriptionClient } from "@nktkas/hyperliquid";
2
+ import WebSocket from "ws";
3
+ /**
4
+ * Creates a position watcher that subscribes to clearinghouseState updates via WebSocket
5
+ */
6
+ export function createPositionWatcher(config) {
7
+ let wsTransport = null;
8
+ let subscriptionClient = null;
9
+ let subscription = null;
10
+ return {
11
+ async start() {
12
+ wsTransport = new WebSocketTransport({
13
+ isTestnet: config.isTestnet,
14
+ reconnect: { WebSocket: WebSocket },
15
+ });
16
+ subscriptionClient = new SubscriptionClient({ transport: wsTransport });
17
+ await wsTransport.ready();
18
+ subscription = await subscriptionClient.allDexsClearinghouseState({ user: config.user }, (state) => {
19
+ config.onUpdate(state);
20
+ });
21
+ },
22
+ async stop() {
23
+ if (subscription) {
24
+ try {
25
+ await subscription.unsubscribe();
26
+ }
27
+ catch {
28
+ // Ignore errors during unsubscribe
29
+ }
30
+ subscription = null;
31
+ }
32
+ if (wsTransport) {
33
+ try {
34
+ await wsTransport.close();
35
+ }
36
+ catch {
37
+ // Ignore errors during close
38
+ }
39
+ wsTransport = null;
40
+ }
41
+ subscriptionClient = null;
42
+ },
43
+ };
44
+ }
@@ -0,0 +1,15 @@
1
+ export interface PriceWatcher {
2
+ start(): Promise<void>;
3
+ stop(): Promise<void>;
4
+ }
5
+ export interface PriceWatcherConfig {
6
+ coin: string;
7
+ isTestnet: boolean;
8
+ onUpdate: (price: string) => void;
9
+ onError: (error: Error) => void;
10
+ }
11
+ /**
12
+ * Creates a price watcher that uses server cache polling if available,
13
+ * otherwise falls back to direct WebSocket subscription
14
+ */
15
+ export declare function createPriceWatcher(config: PriceWatcherConfig): PriceWatcher;
@@ -0,0 +1,84 @@
1
+ import { tryConnectToServer } from "../client/index.js";
2
+ import { WebSocketTransport, SubscriptionClient } from "@nktkas/hyperliquid";
3
+ import WebSocket from "ws";
4
+ /**
5
+ * Creates a price watcher that uses server cache polling if available,
6
+ * otherwise falls back to direct WebSocket subscription
7
+ */
8
+ export function createPriceWatcher(config) {
9
+ let serverClient = null;
10
+ let pollInterval = null;
11
+ let wsTransport = null;
12
+ let subscription = null;
13
+ let stopped = false;
14
+ const pollServerPrice = async () => {
15
+ if (stopped || !serverClient)
16
+ return;
17
+ try {
18
+ const { data } = await serverClient.getPrices();
19
+ const price = data[config.coin];
20
+ if (price !== undefined) {
21
+ config.onUpdate(price);
22
+ }
23
+ }
24
+ catch (err) {
25
+ config.onError(err instanceof Error ? err : new Error(String(err)));
26
+ }
27
+ };
28
+ return {
29
+ async start() {
30
+ stopped = false;
31
+ // Try to use server cache first
32
+ serverClient = await tryConnectToServer();
33
+ if (serverClient) {
34
+ // Poll server every 500ms for price updates
35
+ await pollServerPrice();
36
+ pollInterval = setInterval(pollServerPrice, 500);
37
+ }
38
+ else {
39
+ // No server, use direct WebSocket subscription
40
+ wsTransport = new WebSocketTransport({
41
+ isTestnet: config.isTestnet,
42
+ reconnect: { WebSocket: WebSocket },
43
+ });
44
+ const subscriptionClient = new SubscriptionClient({ transport: wsTransport });
45
+ await wsTransport.ready();
46
+ subscription = await subscriptionClient.allMids({ dex: "ALL_DEXS" }, (event) => {
47
+ const price = event.mids[config.coin];
48
+ if (price !== undefined) {
49
+ config.onUpdate(price);
50
+ }
51
+ });
52
+ }
53
+ },
54
+ async stop() {
55
+ stopped = true;
56
+ if (pollInterval) {
57
+ clearInterval(pollInterval);
58
+ pollInterval = null;
59
+ }
60
+ if (serverClient) {
61
+ serverClient.close();
62
+ serverClient = null;
63
+ }
64
+ if (subscription) {
65
+ try {
66
+ await subscription.unsubscribe();
67
+ }
68
+ catch {
69
+ // Ignore errors during unsubscribe
70
+ }
71
+ subscription = null;
72
+ }
73
+ if (wsTransport) {
74
+ try {
75
+ await wsTransport.close();
76
+ }
77
+ catch {
78
+ // Ignore errors during close
79
+ }
80
+ wsTransport = null;
81
+ }
82
+ },
83
+ };
84
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Prompt for text input
3
+ */
4
+ export declare function prompt(question: string): Promise<string>;
5
+ /**
6
+ * Prompt for selection from a list of options with arrow key navigation
7
+ */
8
+ export declare function select<T extends string>(question: string, options: {
9
+ value: T;
10
+ label: string;
11
+ description?: string;
12
+ }[]): Promise<T>;
13
+ /**
14
+ * Prompt for multiple selections with checkboxes
15
+ */
16
+ export declare function multiSelect<T extends string>(question: string, options: {
17
+ value: T;
18
+ label: string;
19
+ description?: string;
20
+ }[]): Promise<T[]>;
21
+ /**
22
+ * Prompt for yes/no confirmation
23
+ */
24
+ export declare function confirm(question: string, defaultValue?: boolean): Promise<boolean>;
25
+ /**
26
+ * Wait for user to press Enter
27
+ */
28
+ export declare function waitForEnter(message?: string): Promise<void>;
29
+ /**
30
+ * Wait for user to press Enter (returns true) or Escape (returns false)
31
+ */
32
+ export declare function pressEnterOrEsc(message: string): Promise<boolean>;
@@ -0,0 +1,105 @@
1
+ import { input, select as inquirerSelect, confirm as inquirerConfirm, checkbox, } from "@inquirer/prompts";
2
+ import { inquirerTheme, highlighter } from "./ui-tokens.js";
3
+ /**
4
+ * Prompt for text input
5
+ */
6
+ export async function prompt(question) {
7
+ const answer = await input({
8
+ message: question,
9
+ theme: inquirerTheme,
10
+ });
11
+ return answer.trim();
12
+ }
13
+ /**
14
+ * Prompt for selection from a list of options with arrow key navigation
15
+ */
16
+ export async function select(question, options) {
17
+ const result = await inquirerSelect({
18
+ message: question,
19
+ choices: options.map((opt) => ({
20
+ value: opt.value,
21
+ name: opt.label,
22
+ description: opt.description,
23
+ })),
24
+ theme: inquirerTheme,
25
+ });
26
+ return result;
27
+ }
28
+ /**
29
+ * Prompt for multiple selections with checkboxes
30
+ */
31
+ export async function multiSelect(question, options) {
32
+ const results = await checkbox({
33
+ message: question,
34
+ choices: options.map((opt) => ({
35
+ value: opt.value,
36
+ name: opt.label,
37
+ description: opt.description,
38
+ })),
39
+ theme: inquirerTheme,
40
+ });
41
+ return results;
42
+ }
43
+ /**
44
+ * Prompt for yes/no confirmation
45
+ */
46
+ export async function confirm(question, defaultValue = false) {
47
+ return inquirerConfirm({
48
+ message: question,
49
+ default: defaultValue,
50
+ theme: inquirerTheme,
51
+ });
52
+ }
53
+ /**
54
+ * Wait for user to press Enter
55
+ */
56
+ export async function waitForEnter(message = "Press Enter to continue...") {
57
+ await input({
58
+ message,
59
+ theme: {
60
+ ...inquirerTheme,
61
+ prefix: {
62
+ idle: highlighter.warn("→"),
63
+ done: highlighter.success("✔"),
64
+ },
65
+ },
66
+ });
67
+ }
68
+ /**
69
+ * Wait for user to press Enter (returns true) or Escape (returns false)
70
+ */
71
+ export async function pressEnterOrEsc(message) {
72
+ return new Promise((resolve) => {
73
+ console.log(`${highlighter.warn("→")} ${message}`);
74
+ const stdin = process.stdin;
75
+ const wasRaw = stdin.isRaw;
76
+ stdin.setRawMode(true);
77
+ stdin.resume();
78
+ const onData = (key) => {
79
+ const char = key.toString();
80
+ // Enter key
81
+ if (char === "\r" || char === "\n") {
82
+ cleanup();
83
+ console.log(`${highlighter.success("✔")} Opening browser...`);
84
+ resolve(true);
85
+ }
86
+ // Escape key
87
+ else if (char === "\x1b") {
88
+ cleanup();
89
+ console.log(`${highlighter.dimWhite("✔")} Skipped`);
90
+ resolve(false);
91
+ }
92
+ // Ctrl+C
93
+ else if (char === "\x03") {
94
+ cleanup();
95
+ process.exit(0);
96
+ }
97
+ };
98
+ const cleanup = () => {
99
+ stdin.removeListener("data", onData);
100
+ stdin.setRawMode(wasRaw);
101
+ stdin.pause();
102
+ };
103
+ stdin.on("data", onData);
104
+ });
105
+ }