@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,39 @@
1
+ /**
2
+ * Input Validation Utilities
3
+ * Validates and sanitizes CLI inputs
4
+ */
5
+ export declare class ValidationError extends Error {
6
+ constructor(message: string);
7
+ }
8
+ /**
9
+ * Validate and parse a positive number
10
+ */
11
+ export declare function parsePositiveNumber(value: string | undefined, name: string, defaultValue?: number): number;
12
+ /**
13
+ * Validate and parse a positive integer
14
+ */
15
+ export declare function parsePositiveInt(value: string | undefined, name: string, defaultValue?: number): number;
16
+ /**
17
+ * Validate and parse a number within a range
18
+ */
19
+ export declare function parseNumberInRange(value: string | undefined, name: string, min: number, max: number, defaultValue?: number): number;
20
+ /**
21
+ * Validate asset symbol
22
+ */
23
+ export declare function validateAsset(asset: string | undefined, defaultAsset?: string): string;
24
+ /**
25
+ * Validate market symbol
26
+ */
27
+ export declare function validateMarket(market: string | undefined, defaultMarket?: string): string;
28
+ /**
29
+ * Parse comma-separated list of assets
30
+ */
31
+ export declare function parseAssetList(value: string | undefined, defaultAssets: readonly string[]): string[];
32
+ /**
33
+ * Validate exchange ID
34
+ */
35
+ export declare function validateExchange(exchangeId: string, validExchanges: string[]): string;
36
+ /**
37
+ * Validate USD size
38
+ */
39
+ export declare function validateSize(value: string | undefined, defaultSize?: number): number;
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Input Validation Utilities
3
+ * Validates and sanitizes CLI inputs
4
+ */
5
+ export class ValidationError extends Error {
6
+ constructor(message) {
7
+ super(message);
8
+ this.name = "ValidationError";
9
+ }
10
+ }
11
+ /**
12
+ * Validate and parse a positive number
13
+ */
14
+ export function parsePositiveNumber(value, name, defaultValue) {
15
+ if (value === undefined || value === "") {
16
+ if (defaultValue !== undefined)
17
+ return defaultValue;
18
+ throw new ValidationError(`${name} is required`);
19
+ }
20
+ const num = parseFloat(value);
21
+ if (isNaN(num)) {
22
+ throw new ValidationError(`${name} must be a valid number, got: ${value}`);
23
+ }
24
+ if (num <= 0) {
25
+ throw new ValidationError(`${name} must be positive, got: ${num}`);
26
+ }
27
+ return num;
28
+ }
29
+ /**
30
+ * Validate and parse a positive integer
31
+ */
32
+ export function parsePositiveInt(value, name, defaultValue) {
33
+ const num = parsePositiveNumber(value, name, defaultValue);
34
+ if (!Number.isInteger(num)) {
35
+ throw new ValidationError(`${name} must be an integer, got: ${num}`);
36
+ }
37
+ return num;
38
+ }
39
+ /**
40
+ * Validate and parse a number within a range
41
+ */
42
+ export function parseNumberInRange(value, name, min, max, defaultValue) {
43
+ const num = parsePositiveNumber(value, name, defaultValue);
44
+ if (num < min || num > max) {
45
+ throw new ValidationError(`${name} must be between ${min} and ${max}, got: ${num}`);
46
+ }
47
+ return num;
48
+ }
49
+ /**
50
+ * Validate asset symbol
51
+ */
52
+ export function validateAsset(asset, defaultAsset = "BTC") {
53
+ if (!asset)
54
+ return defaultAsset;
55
+ const normalized = asset.toUpperCase().trim();
56
+ // Basic validation: 1-10 alphanumeric characters
57
+ if (!/^[A-Z0-9]{1,10}$/.test(normalized)) {
58
+ throw new ValidationError(`Invalid asset symbol: ${asset}`);
59
+ }
60
+ return normalized;
61
+ }
62
+ /**
63
+ * Validate market symbol
64
+ */
65
+ export function validateMarket(market, defaultMarket = "BTC-PERP") {
66
+ if (!market)
67
+ return defaultMarket;
68
+ const normalized = market.toUpperCase().trim();
69
+ // Format: ASSET-PERP or ASSET-USD-PERP
70
+ if (!/^[A-Z0-9]{1,10}(-USD)?-PERP$/.test(normalized)) {
71
+ throw new ValidationError(`Invalid market symbol: ${market}. Expected format: ASSET-PERP`);
72
+ }
73
+ return normalized;
74
+ }
75
+ /**
76
+ * Parse comma-separated list of assets
77
+ */
78
+ export function parseAssetList(value, defaultAssets) {
79
+ if (!value)
80
+ return [...defaultAssets];
81
+ return value
82
+ .split(",")
83
+ .map(a => validateAsset(a.trim()))
84
+ .filter((a, i, arr) => arr.indexOf(a) === i); // dedupe
85
+ }
86
+ /**
87
+ * Validate exchange ID
88
+ */
89
+ export function validateExchange(exchangeId, validExchanges) {
90
+ const normalized = exchangeId.toLowerCase().trim();
91
+ if (!validExchanges.includes(normalized)) {
92
+ throw new ValidationError(`Invalid exchange: ${exchangeId}. Valid options: ${validExchanges.join(", ")}`);
93
+ }
94
+ return normalized;
95
+ }
96
+ /**
97
+ * Validate USD size
98
+ */
99
+ export function validateSize(value, defaultSize = 1000) {
100
+ const size = parsePositiveNumber(value, "size", defaultSize);
101
+ if (size < 10) {
102
+ throw new ValidationError("Position size must be at least $10");
103
+ }
104
+ if (size > 10_000_000) {
105
+ throw new ValidationError("Position size cannot exceed $10M");
106
+ }
107
+ return size;
108
+ }
@@ -0,0 +1,9 @@
1
+ import type { Address, Hex } from "viem";
2
+ export declare function validateAddress(value: string): Address;
3
+ export declare function validateAptosLikeAddress(value: string): string;
4
+ export declare function validateAddressForExchange(value: string, exchangeId: string): string;
5
+ export declare function validatePrivateKey(value: string): Hex;
6
+ export declare function validatePositiveNumber(value: string, name: string): number;
7
+ export declare function validatePositiveInteger(value: string, name: string): number;
8
+ export declare function validateSide(value: string): "buy" | "sell";
9
+ export declare function validateTif(value: string): "Gtc" | "Ioc" | "Alo";
@@ -0,0 +1,64 @@
1
+ export function validateAddress(value) {
2
+ if (!/^0x[a-fA-F0-9]{40}$/.test(value)) {
3
+ throw new Error(`Invalid address: ${value}`);
4
+ }
5
+ return value;
6
+ }
7
+ export function validateAptosLikeAddress(value) {
8
+ if (!/^0x[a-fA-F0-9]{1,64}$/.test(value)) {
9
+ throw new Error(`Invalid address: ${value}`);
10
+ }
11
+ return value;
12
+ }
13
+ export function validateAddressForExchange(value, exchangeId) {
14
+ const normalized = exchangeId.trim().toLowerCase();
15
+ if (normalized === "decibel" || normalized === "paradex") {
16
+ return validateAptosLikeAddress(value);
17
+ }
18
+ if (normalized === "orderly") {
19
+ if (!value.trim()) {
20
+ throw new Error("Invalid account identifier: value cannot be empty");
21
+ }
22
+ return value.trim();
23
+ }
24
+ return validateAddress(value);
25
+ }
26
+ export function validatePrivateKey(value) {
27
+ if (!/^0x[a-fA-F0-9]{64}$/.test(value)) {
28
+ throw new Error("Invalid private key format");
29
+ }
30
+ return value;
31
+ }
32
+ export function validatePositiveNumber(value, name) {
33
+ const num = parseFloat(value);
34
+ if (isNaN(num) || num <= 0) {
35
+ throw new Error(`${name} must be a positive number`);
36
+ }
37
+ return num;
38
+ }
39
+ export function validatePositiveInteger(value, name) {
40
+ const num = parseInt(value, 10);
41
+ if (isNaN(num) || num <= 0) {
42
+ throw new Error(`${name} must be a positive integer`);
43
+ }
44
+ return num;
45
+ }
46
+ export function validateSide(value) {
47
+ const lower = value.toLowerCase();
48
+ if (lower !== "buy" && lower !== "sell") {
49
+ throw new Error('Side must be "buy" or "sell"');
50
+ }
51
+ return lower;
52
+ }
53
+ export function validateTif(value) {
54
+ const mapping = {
55
+ gtc: "Gtc",
56
+ ioc: "Ioc",
57
+ alo: "Alo",
58
+ };
59
+ const result = mapping[value.toLowerCase()];
60
+ if (!result) {
61
+ throw new Error('Time-in-force must be "Gtc", "Ioc", or "Alo"');
62
+ }
63
+ return result;
64
+ }
@@ -0,0 +1,38 @@
1
+ import { AllPerpMetasResponse, SpotMetaResponse } from "@nktkas/hyperliquid";
2
+ import { AllDexsAssetCtxsEvent, SpotAssetCtxsEvent } from "@nktkas/hyperliquid/api/subscription";
3
+ export interface CacheEntry<T> {
4
+ data: T;
5
+ updatedAt: number;
6
+ }
7
+ export interface AllMidsData {
8
+ [coin: string]: string;
9
+ }
10
+ export declare class ServerCache {
11
+ private allMids;
12
+ private allDexsAssetCtxs;
13
+ private allPerpMetas;
14
+ private spotMeta;
15
+ private spotAssetCtxs;
16
+ setAllMids(data: AllMidsData): void;
17
+ setAllDexsAssetCtxs(data: AllDexsAssetCtxsEvent): void;
18
+ setAllPerpMetas(data: AllPerpMetasResponse): void;
19
+ setSpotMeta(data: SpotMetaResponse): void;
20
+ setSpotAssetCtxs(data: SpotAssetCtxsEvent): void;
21
+ getAllMids(): CacheEntry<AllMidsData> | null;
22
+ getAllDexsAssetCtxs(): CacheEntry<AllDexsAssetCtxsEvent> | null;
23
+ getAllPerpMetas(): CacheEntry<AllPerpMetasResponse> | null;
24
+ getSpotMeta(): CacheEntry<SpotMetaResponse> | null;
25
+ getSpotAssetCtxs(): CacheEntry<SpotAssetCtxsEvent> | null;
26
+ getStatus(): {
27
+ hasMids: boolean;
28
+ hasAssetCtxs: boolean;
29
+ hasPerpMetas: boolean;
30
+ hasSpotMeta: boolean;
31
+ hasSpotAssetCtxs: boolean;
32
+ midsAge?: number;
33
+ assetCtxsAge?: number;
34
+ perpMetasAge?: number;
35
+ spotMetaAge?: number;
36
+ spotAssetCtxsAge?: number;
37
+ };
38
+ }
@@ -0,0 +1,56 @@
1
+ // In-memory cache for real-time data from WebSocket subscriptions
2
+ export class ServerCache {
3
+ allMids = null;
4
+ allDexsAssetCtxs = null;
5
+ allPerpMetas = null;
6
+ spotMeta = null;
7
+ spotAssetCtxs = null;
8
+ // Update methods - called from subscription handlers
9
+ setAllMids(data) {
10
+ this.allMids = { data, updatedAt: Date.now() };
11
+ }
12
+ setAllDexsAssetCtxs(data) {
13
+ this.allDexsAssetCtxs = { data, updatedAt: Date.now() };
14
+ }
15
+ setAllPerpMetas(data) {
16
+ this.allPerpMetas = { data, updatedAt: Date.now() };
17
+ }
18
+ setSpotMeta(data) {
19
+ this.spotMeta = { data, updatedAt: Date.now() };
20
+ }
21
+ setSpotAssetCtxs(data) {
22
+ this.spotAssetCtxs = { data, updatedAt: Date.now() };
23
+ }
24
+ // Get methods - return data with cache timestamp
25
+ getAllMids() {
26
+ return this.allMids;
27
+ }
28
+ getAllDexsAssetCtxs() {
29
+ return this.allDexsAssetCtxs;
30
+ }
31
+ getAllPerpMetas() {
32
+ return this.allPerpMetas;
33
+ }
34
+ getSpotMeta() {
35
+ return this.spotMeta;
36
+ }
37
+ getSpotAssetCtxs() {
38
+ return this.spotAssetCtxs;
39
+ }
40
+ // Get status info
41
+ getStatus() {
42
+ const now = Date.now();
43
+ return {
44
+ hasMids: this.allMids !== null,
45
+ hasAssetCtxs: this.allDexsAssetCtxs !== null,
46
+ hasPerpMetas: this.allPerpMetas !== null,
47
+ hasSpotMeta: this.spotMeta !== null,
48
+ hasSpotAssetCtxs: this.spotAssetCtxs !== null,
49
+ midsAge: this.allMids ? now - this.allMids.updatedAt : undefined,
50
+ assetCtxsAge: this.allDexsAssetCtxs ? now - this.allDexsAssetCtxs.updatedAt : undefined,
51
+ perpMetasAge: this.allPerpMetas ? now - this.allPerpMetas.updatedAt : undefined,
52
+ spotMetaAge: this.spotMeta ? now - this.spotMeta.updatedAt : undefined,
53
+ spotAssetCtxsAge: this.spotAssetCtxs ? now - this.spotAssetCtxs.updatedAt : undefined,
54
+ };
55
+ }
56
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+ import { writeFileSync, appendFileSync, unlinkSync, existsSync } from "node:fs";
3
+ import { HL_DIR, SERVER_PID_PATH, SERVER_LOG_PATH, SERVER_CONFIG_PATH, SERVER_SOCKET_PATH, } from "../lib/paths.js";
4
+ import { ServerCache } from "./cache.js";
5
+ import { SubscriptionManager } from "./subscriptions.js";
6
+ import { IPCServer } from "./ipc.js";
7
+ import { ensurePrivateDir, hardenPrivateFile, PRIVATE_FILE_MODE, } from "../lib/fs-security.js";
8
+ // Parse command line args
9
+ const args = process.argv.slice(2);
10
+ const isTestnet = args.includes("--testnet");
11
+ // Ensure runtime directory exists and remains owner-only.
12
+ ensurePrivateDir(HL_DIR);
13
+ // Logging
14
+ function log(msg) {
15
+ const timestamp = new Date().toISOString();
16
+ const line = `[${timestamp}] ${msg}\n`;
17
+ appendFileSync(SERVER_LOG_PATH, line);
18
+ hardenPrivateFile(SERVER_LOG_PATH);
19
+ }
20
+ // Initialize
21
+ const startedAt = Date.now();
22
+ log(`Starting server (testnet: ${isTestnet}, pid: ${process.pid})`);
23
+ // Write PID file
24
+ writeFileSync(SERVER_PID_PATH, String(process.pid), { mode: PRIVATE_FILE_MODE });
25
+ hardenPrivateFile(SERVER_PID_PATH);
26
+ // Write config file
27
+ const config = { testnet: isTestnet, startedAt };
28
+ writeFileSync(SERVER_CONFIG_PATH, JSON.stringify(config, null, 2));
29
+ hardenPrivateFile(SERVER_CONFIG_PATH);
30
+ // Create cache and managers
31
+ const cache = new ServerCache();
32
+ const subscriptions = new SubscriptionManager(cache, isTestnet, log);
33
+ let ipcServer = null;
34
+ // Graceful shutdown
35
+ async function shutdown(reason) {
36
+ log(`Shutting down: ${reason}`);
37
+ try {
38
+ // Stop IPC server first
39
+ if (ipcServer) {
40
+ await ipcServer.stop();
41
+ }
42
+ // Stop subscriptions
43
+ await subscriptions.stop();
44
+ // Clean up files
45
+ if (existsSync(SERVER_PID_PATH)) {
46
+ unlinkSync(SERVER_PID_PATH);
47
+ }
48
+ if (existsSync(SERVER_SOCKET_PATH)) {
49
+ unlinkSync(SERVER_SOCKET_PATH);
50
+ }
51
+ if (existsSync(SERVER_CONFIG_PATH)) {
52
+ unlinkSync(SERVER_CONFIG_PATH);
53
+ }
54
+ log("Shutdown complete");
55
+ }
56
+ catch (err) {
57
+ log(`Shutdown error: ${err}`);
58
+ }
59
+ process.exit(0);
60
+ }
61
+ // Signal handlers
62
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
63
+ process.on("SIGINT", () => shutdown("SIGINT"));
64
+ process.on("uncaughtException", (err) => {
65
+ log(`Uncaught exception: ${err.message}`);
66
+ shutdown("uncaught exception").catch(() => process.exit(1));
67
+ });
68
+ process.on("unhandledRejection", (reason) => {
69
+ log(`Unhandled rejection: ${reason}`);
70
+ shutdown("unhandled rejection").catch(() => process.exit(1));
71
+ });
72
+ // Start server
73
+ async function start() {
74
+ try {
75
+ // Start WebSocket subscriptions
76
+ await subscriptions.start();
77
+ // Start IPC server
78
+ ipcServer = new IPCServer(cache, subscriptions, isTestnet, startedAt, log, () => {
79
+ shutdown("shutdown request");
80
+ });
81
+ await ipcServer.start();
82
+ log("Server started successfully");
83
+ }
84
+ catch (err) {
85
+ log(`Failed to start server: ${err}`);
86
+ await shutdown("startup error");
87
+ }
88
+ }
89
+ start();
@@ -0,0 +1,18 @@
1
+ import type { ServerCache } from "./cache.js";
2
+ import type { SubscriptionManager } from "./subscriptions.js";
3
+ export declare class IPCServer {
4
+ private server;
5
+ private cache;
6
+ private subscriptions;
7
+ private isTestnet;
8
+ private startedAt;
9
+ private log;
10
+ private onShutdown;
11
+ constructor(cache: ServerCache, subscriptions: SubscriptionManager, isTestnet: boolean, startedAt: number, log: (msg: string) => void, onShutdown: () => void);
12
+ start(): Promise<void>;
13
+ private handleConnection;
14
+ private handleMessage;
15
+ private handleRequest;
16
+ private sendResponse;
17
+ stop(): Promise<void>;
18
+ }
@@ -0,0 +1,159 @@
1
+ import { createServer } from "node:net";
2
+ import { existsSync, unlinkSync } from "node:fs";
3
+ import { SERVER_SOCKET_PATH } from "../lib/paths.js";
4
+ export class IPCServer {
5
+ server = null;
6
+ cache;
7
+ subscriptions;
8
+ isTestnet;
9
+ startedAt;
10
+ log;
11
+ onShutdown;
12
+ constructor(cache, subscriptions, isTestnet, startedAt, log, onShutdown) {
13
+ this.cache = cache;
14
+ this.subscriptions = subscriptions;
15
+ this.isTestnet = isTestnet;
16
+ this.startedAt = startedAt;
17
+ this.log = log;
18
+ this.onShutdown = onShutdown;
19
+ }
20
+ async start() {
21
+ // Remove existing socket file if it exists
22
+ if (existsSync(SERVER_SOCKET_PATH)) {
23
+ unlinkSync(SERVER_SOCKET_PATH);
24
+ }
25
+ return new Promise((resolve, reject) => {
26
+ this.server = createServer((socket) => {
27
+ this.handleConnection(socket);
28
+ });
29
+ this.server.on("error", (err) => {
30
+ this.log(`IPC server error: ${err.message}`);
31
+ reject(err);
32
+ });
33
+ this.server.listen(SERVER_SOCKET_PATH, () => {
34
+ this.log(`IPC server listening on ${SERVER_SOCKET_PATH}`);
35
+ resolve();
36
+ });
37
+ });
38
+ }
39
+ handleConnection(socket) {
40
+ let buffer = "";
41
+ socket.on("data", (data) => {
42
+ buffer += data.toString();
43
+ // Process complete messages (newline-delimited)
44
+ const lines = buffer.split("\n");
45
+ buffer = lines.pop() || "";
46
+ for (const line of lines) {
47
+ if (line.trim()) {
48
+ this.handleMessage(socket, line);
49
+ }
50
+ }
51
+ });
52
+ socket.on("error", (err) => {
53
+ this.log(`Socket error: ${err.message}`);
54
+ });
55
+ }
56
+ handleMessage(socket, message) {
57
+ let request;
58
+ try {
59
+ request = JSON.parse(message);
60
+ }
61
+ catch {
62
+ this.sendResponse(socket, { id: "0", error: "Invalid JSON" });
63
+ return;
64
+ }
65
+ const response = this.handleRequest(request);
66
+ this.sendResponse(socket, response);
67
+ }
68
+ handleRequest(request) {
69
+ const { id, method, params } = request;
70
+ switch (method) {
71
+ case "getPrices": {
72
+ const entry = this.cache.getAllMids();
73
+ if (!entry) {
74
+ return { id, error: "No data available" };
75
+ }
76
+ const coin = params?.coin;
77
+ if (coin) {
78
+ const normalizedCoin = coin.trim().toUpperCase();
79
+ const price = entry.data[normalizedCoin];
80
+ if (price === undefined) {
81
+ return { id, error: `Coin not found: ${normalizedCoin}` };
82
+ }
83
+ return { id, result: { [normalizedCoin]: price }, cached_at: entry.updatedAt };
84
+ }
85
+ return { id, result: entry.data, cached_at: entry.updatedAt };
86
+ }
87
+ case "getAssetCtxs": {
88
+ const entry = this.cache.getAllDexsAssetCtxs();
89
+ if (!entry) {
90
+ return { id, error: "No data available" };
91
+ }
92
+ return { id, result: entry.data, cached_at: entry.updatedAt };
93
+ }
94
+ case "getPerpMeta": {
95
+ const entry = this.cache.getAllPerpMetas();
96
+ if (!entry) {
97
+ return { id, error: "No data available" };
98
+ }
99
+ return { id, result: entry.data, cached_at: entry.updatedAt };
100
+ }
101
+ case "getSpotMeta": {
102
+ const entry = this.cache.getSpotMeta();
103
+ if (!entry) {
104
+ return { id, error: "No data available" };
105
+ }
106
+ return { id, result: entry.data, cached_at: entry.updatedAt };
107
+ }
108
+ case "getSpotAssetCtxs": {
109
+ const entry = this.cache.getSpotAssetCtxs();
110
+ if (!entry) {
111
+ return { id, error: "No data available" };
112
+ }
113
+ return { id, result: entry.data, cached_at: entry.updatedAt };
114
+ }
115
+ case "getStatus": {
116
+ const cacheStatus = this.cache.getStatus();
117
+ return {
118
+ id,
119
+ result: {
120
+ running: true,
121
+ testnet: this.isTestnet,
122
+ connected: this.subscriptions.isConnected(),
123
+ startedAt: this.startedAt,
124
+ uptime: Date.now() - this.startedAt,
125
+ cache: cacheStatus,
126
+ },
127
+ };
128
+ }
129
+ case "shutdown": {
130
+ // Respond first, then shutdown
131
+ setTimeout(() => this.onShutdown(), 100);
132
+ return { id, result: { ok: true } };
133
+ }
134
+ default:
135
+ return { id, error: `Unknown method: ${method}` };
136
+ }
137
+ }
138
+ sendResponse(socket, response) {
139
+ try {
140
+ socket.write(JSON.stringify(response) + "\n");
141
+ }
142
+ catch {
143
+ // Socket may have closed
144
+ }
145
+ }
146
+ async stop() {
147
+ return new Promise((resolve) => {
148
+ if (this.server) {
149
+ this.server.close(() => {
150
+ this.log("IPC server stopped");
151
+ resolve();
152
+ });
153
+ }
154
+ else {
155
+ resolve();
156
+ }
157
+ });
158
+ }
159
+ }
@@ -0,0 +1,18 @@
1
+ import type { ServerCache } from "./cache.js";
2
+ export declare class SubscriptionManager {
3
+ private wsTransport;
4
+ private subscriptionClient;
5
+ private infoClient;
6
+ private cache;
7
+ private subscriptions;
8
+ private perpMetaInterval;
9
+ private spotMetaInterval;
10
+ private isTestnet;
11
+ private log;
12
+ constructor(cache: ServerCache, isTestnet: boolean, log: (msg: string) => void);
13
+ start(): Promise<void>;
14
+ private fetchPerpMetas;
15
+ private fetchSpotMeta;
16
+ stop(): Promise<void>;
17
+ isConnected(): boolean;
18
+ }