openbroker 1.3.1 → 1.4.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 (171) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/SKILL.md +7 -4
  3. package/dist/auto/audit.d.ts +57 -0
  4. package/dist/auto/audit.d.ts.map +1 -0
  5. package/dist/auto/audit.js +407 -0
  6. package/dist/auto/cli.d.ts +2 -0
  7. package/dist/auto/cli.d.ts.map +1 -0
  8. package/dist/auto/cli.js +423 -0
  9. package/dist/auto/events.d.ts +11 -0
  10. package/dist/auto/events.d.ts.map +1 -0
  11. package/dist/auto/events.js +36 -0
  12. package/dist/auto/examples/dca.d.ts +4 -0
  13. package/dist/auto/examples/dca.d.ts.map +1 -0
  14. package/dist/auto/examples/dca.js +60 -0
  15. package/dist/auto/examples/funding-arb.d.ts +4 -0
  16. package/dist/auto/examples/funding-arb.d.ts.map +1 -0
  17. package/dist/auto/examples/funding-arb.js +81 -0
  18. package/dist/auto/examples/grid.d.ts +4 -0
  19. package/dist/auto/examples/grid.d.ts.map +1 -0
  20. package/dist/auto/examples/grid.js +114 -0
  21. package/dist/auto/examples/mm-maker.d.ts +4 -0
  22. package/dist/auto/examples/mm-maker.d.ts.map +1 -0
  23. package/dist/auto/examples/mm-maker.js +131 -0
  24. package/dist/auto/examples/mm-spread.d.ts +4 -0
  25. package/dist/auto/examples/mm-spread.d.ts.map +1 -0
  26. package/dist/auto/examples/mm-spread.js +119 -0
  27. package/dist/auto/examples/price-alert.d.ts +4 -0
  28. package/dist/auto/examples/price-alert.d.ts.map +1 -0
  29. package/dist/auto/examples/price-alert.js +85 -0
  30. package/dist/auto/keep-awake.d.ts +11 -0
  31. package/dist/auto/keep-awake.d.ts.map +1 -0
  32. package/dist/auto/keep-awake.js +70 -0
  33. package/dist/auto/loader.d.ts +22 -0
  34. package/dist/auto/loader.d.ts.map +1 -0
  35. package/dist/auto/loader.js +127 -0
  36. package/dist/auto/prune.d.ts +40 -0
  37. package/dist/auto/prune.d.ts.map +1 -0
  38. package/dist/auto/prune.js +204 -0
  39. package/dist/auto/registry.d.ts +24 -0
  40. package/dist/auto/registry.d.ts.map +1 -0
  41. package/dist/auto/registry.js +93 -0
  42. package/dist/auto/report.d.ts +3 -0
  43. package/dist/auto/report.d.ts.map +1 -0
  44. package/dist/auto/report.js +385 -0
  45. package/dist/auto/runtime.d.ts +33 -0
  46. package/dist/auto/runtime.d.ts.map +1 -0
  47. package/dist/auto/runtime.js +844 -0
  48. package/dist/auto/types.d.ts +236 -0
  49. package/dist/auto/types.d.ts.map +1 -0
  50. package/dist/auto/types.js +3 -0
  51. package/dist/core/client.d.ts +684 -0
  52. package/dist/core/client.d.ts.map +1 -0
  53. package/dist/core/client.js +2040 -0
  54. package/dist/core/config.d.ts +22 -0
  55. package/dist/core/config.d.ts.map +1 -0
  56. package/dist/core/config.js +143 -0
  57. package/dist/core/types.d.ts +221 -0
  58. package/dist/core/types.d.ts.map +1 -0
  59. package/dist/core/types.js +2 -0
  60. package/dist/core/utils.d.ts +61 -0
  61. package/dist/core/utils.d.ts.map +1 -0
  62. package/dist/core/utils.js +142 -0
  63. package/dist/core/ws.d.ts +121 -0
  64. package/dist/core/ws.d.ts.map +1 -0
  65. package/dist/core/ws.js +222 -0
  66. package/dist/info/account.d.ts +3 -0
  67. package/dist/info/account.d.ts.map +1 -0
  68. package/dist/info/account.js +198 -0
  69. package/dist/info/all-markets.d.ts +3 -0
  70. package/dist/info/all-markets.d.ts.map +1 -0
  71. package/dist/info/all-markets.js +272 -0
  72. package/dist/info/candles.d.ts +3 -0
  73. package/dist/info/candles.d.ts.map +1 -0
  74. package/dist/info/candles.js +120 -0
  75. package/dist/info/fees.d.ts +3 -0
  76. package/dist/info/fees.d.ts.map +1 -0
  77. package/dist/info/fees.js +87 -0
  78. package/dist/info/fills.d.ts +3 -0
  79. package/dist/info/fills.d.ts.map +1 -0
  80. package/dist/info/fills.js +105 -0
  81. package/dist/info/funding-history.d.ts +3 -0
  82. package/dist/info/funding-history.d.ts.map +1 -0
  83. package/dist/info/funding-history.js +98 -0
  84. package/dist/info/funding-scan.d.ts +3 -0
  85. package/dist/info/funding-scan.d.ts.map +1 -0
  86. package/dist/info/funding-scan.js +178 -0
  87. package/dist/info/funding.d.ts +3 -0
  88. package/dist/info/funding.d.ts.map +1 -0
  89. package/dist/info/funding.js +158 -0
  90. package/dist/info/markets.d.ts +3 -0
  91. package/dist/info/markets.d.ts.map +1 -0
  92. package/dist/info/markets.js +178 -0
  93. package/dist/info/order-status.d.ts +3 -0
  94. package/dist/info/order-status.d.ts.map +1 -0
  95. package/dist/info/order-status.js +85 -0
  96. package/dist/info/orders.d.ts +3 -0
  97. package/dist/info/orders.d.ts.map +1 -0
  98. package/dist/info/orders.js +162 -0
  99. package/dist/info/outcomes.d.ts +3 -0
  100. package/dist/info/outcomes.d.ts.map +1 -0
  101. package/dist/info/outcomes.js +175 -0
  102. package/dist/info/positions.d.ts +3 -0
  103. package/dist/info/positions.d.ts.map +1 -0
  104. package/dist/info/positions.js +127 -0
  105. package/dist/info/rate-limit.d.ts +3 -0
  106. package/dist/info/rate-limit.d.ts.map +1 -0
  107. package/dist/info/rate-limit.js +58 -0
  108. package/dist/info/search-markets.d.ts +3 -0
  109. package/dist/info/search-markets.d.ts.map +1 -0
  110. package/dist/info/search-markets.js +296 -0
  111. package/dist/info/spot.d.ts +3 -0
  112. package/dist/info/spot.d.ts.map +1 -0
  113. package/dist/info/spot.js +192 -0
  114. package/dist/info/trades.d.ts +3 -0
  115. package/dist/info/trades.d.ts.map +1 -0
  116. package/dist/info/trades.js +97 -0
  117. package/dist/lib.d.ts +14 -0
  118. package/dist/lib.d.ts.map +1 -0
  119. package/dist/lib.js +17 -0
  120. package/dist/operations/bracket.d.ts +28 -0
  121. package/dist/operations/bracket.d.ts.map +1 -0
  122. package/dist/operations/bracket.js +266 -0
  123. package/dist/operations/cancel.d.ts +3 -0
  124. package/dist/operations/cancel.d.ts.map +1 -0
  125. package/dist/operations/cancel.js +107 -0
  126. package/dist/operations/chase.d.ts +25 -0
  127. package/dist/operations/chase.d.ts.map +1 -0
  128. package/dist/operations/chase.js +215 -0
  129. package/dist/operations/limit-order.d.ts +3 -0
  130. package/dist/operations/limit-order.d.ts.map +1 -0
  131. package/dist/operations/limit-order.js +144 -0
  132. package/dist/operations/market-order.d.ts +3 -0
  133. package/dist/operations/market-order.d.ts.map +1 -0
  134. package/dist/operations/market-order.js +153 -0
  135. package/dist/operations/outcome-order.d.ts +3 -0
  136. package/dist/operations/outcome-order.d.ts.map +1 -0
  137. package/dist/operations/outcome-order.js +171 -0
  138. package/dist/operations/scale.d.ts +3 -0
  139. package/dist/operations/scale.d.ts.map +1 -0
  140. package/dist/operations/scale.js +212 -0
  141. package/dist/operations/set-tpsl.d.ts +3 -0
  142. package/dist/operations/set-tpsl.d.ts.map +1 -0
  143. package/dist/operations/set-tpsl.js +277 -0
  144. package/dist/operations/spot-order.d.ts +3 -0
  145. package/dist/operations/spot-order.d.ts.map +1 -0
  146. package/dist/operations/spot-order.js +173 -0
  147. package/dist/operations/trigger-order.d.ts +3 -0
  148. package/dist/operations/trigger-order.d.ts.map +1 -0
  149. package/dist/operations/trigger-order.js +177 -0
  150. package/dist/operations/twap-cancel.d.ts +3 -0
  151. package/dist/operations/twap-cancel.d.ts.map +1 -0
  152. package/dist/operations/twap-cancel.js +57 -0
  153. package/dist/operations/twap-status.d.ts +3 -0
  154. package/dist/operations/twap-status.d.ts.map +1 -0
  155. package/dist/operations/twap-status.js +81 -0
  156. package/dist/operations/twap.d.ts +3 -0
  157. package/dist/operations/twap.d.ts.map +1 -0
  158. package/dist/operations/twap.js +124 -0
  159. package/dist/setup/approve-builder.d.ts +3 -0
  160. package/dist/setup/approve-builder.d.ts.map +1 -0
  161. package/dist/setup/approve-builder.js +155 -0
  162. package/dist/setup/env.d.ts +4 -0
  163. package/dist/setup/env.d.ts.map +1 -0
  164. package/dist/setup/env.js +8 -0
  165. package/dist/setup/onboard.d.ts +10 -0
  166. package/dist/setup/onboard.d.ts.map +1 -0
  167. package/dist/setup/onboard.js +462 -0
  168. package/package.json +10 -4
  169. package/scripts/core/client.ts +13 -3
  170. package/scripts/info/all-markets.ts +18 -2
  171. package/scripts/info/search-markets.ts +18 -2
@@ -0,0 +1,22 @@
1
+ import type { OpenBrokerConfig } from './types.js';
2
+ export declare const GLOBAL_CONFIG_DIR: string;
3
+ export declare const GLOBAL_ENV_PATH: string;
4
+ export declare const LOCAL_ENV_PATH: string;
5
+ export declare const PROJECT_ROOT: string;
6
+ export declare const OPEN_BROKER_BUILDER_ADDRESS = "0xbb67021fA3e62ab4DA985bb5a55c5c1884381068";
7
+ /**
8
+ * Ensure the global config directory exists
9
+ */
10
+ export declare function ensureConfigDir(): string;
11
+ /**
12
+ * Get the path where config was loaded from, or where it should be saved
13
+ */
14
+ export declare function getConfigPath(): string;
15
+ export declare function loadConfig(): OpenBrokerConfig;
16
+ /**
17
+ * Check if the current config is read-only (no trading capability)
18
+ */
19
+ export declare function isConfigured(): boolean;
20
+ export declare function getNetwork(): 'mainnet' | 'testnet';
21
+ export declare function isMainnet(): boolean;
22
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../scripts/core/config.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAOnD,eAAO,MAAM,iBAAiB,QAAiC,CAAC;AAChE,eAAO,MAAM,eAAe,QAAkC,CAAC;AAG/D,eAAO,MAAM,cAAc,QAA2B,CAAC;AAGvD,eAAO,MAAM,YAAY,QAAwC,CAAC;AAMlE,eAAO,MAAM,2BAA2B,+CAA+C,CAAC;AA0DxF;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAKxC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAgB,UAAU,IAAI,gBAAgB,CAyD7C;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAED,wBAAgB,UAAU,IAAI,SAAS,GAAG,SAAS,CAGlD;AAED,wBAAgB,SAAS,IAAI,OAAO,CAEnC"}
@@ -0,0 +1,143 @@
1
+ // Configuration loader for Open Broker
2
+ import { config as loadDotenv } from 'dotenv';
3
+ import { resolve, join } from 'path';
4
+ import { existsSync, mkdirSync } from 'fs';
5
+ import { homedir } from 'os';
6
+ import { privateKeyToAccount } from 'viem/accounts';
7
+ // Config locations (in order of priority)
8
+ // 1. Environment variables (always checked first by process.env)
9
+ // 2. Local .env in current working directory
10
+ // 3. Global config at ~/.openbroker/.env
11
+ export const GLOBAL_CONFIG_DIR = join(homedir(), '.openbroker');
12
+ export const GLOBAL_ENV_PATH = join(GLOBAL_CONFIG_DIR, '.env');
13
+ // Use OPENBROKER_CWD if set (from CLI wrapper), otherwise use process.cwd()
14
+ const userCwd = process.env.OPENBROKER_CWD || process.cwd();
15
+ export const LOCAL_ENV_PATH = resolve(userCwd, '.env');
16
+ // Package root (for reference, not config loading)
17
+ export const PROJECT_ROOT = resolve(import.meta.dirname, '../..');
18
+ const MAINNET_URL = 'https://api.hyperliquid.xyz';
19
+ const TESTNET_URL = 'https://api.hyperliquid-testnet.xyz';
20
+ // Open Broker builder address - receives builder fees on all trades
21
+ export const OPEN_BROKER_BUILDER_ADDRESS = '0xbb67021fA3e62ab4DA985bb5a55c5c1884381068';
22
+ // Default read-only key (for info commands that don't need authentication)
23
+ // This is a valid but essentially useless private key
24
+ const DEFAULT_READ_ONLY_KEY = '0x0000000000000000000000000000000000000000000000000000000000000001';
25
+ // Track if we've shown the read-only warning
26
+ let readOnlyWarningShown = false;
27
+ /**
28
+ * Find and load the config file from multiple locations
29
+ * Priority: env vars > local .env > global ~/.openbroker/.env > project .env
30
+ */
31
+ function loadEnvFile() {
32
+ const verbose = process.env.VERBOSE === '1' || process.env.VERBOSE === 'true';
33
+ process.env.DOTENV_CONFIG_QUIET = 'true';
34
+ // Explicit config path via -c / --config (highest priority — overrides shell env vars)
35
+ const explicitPath = process.env.OPENBROKER_CONFIG;
36
+ if (explicitPath) {
37
+ if (existsSync(explicitPath)) {
38
+ loadDotenv({ path: explicitPath, override: true });
39
+ if (verbose) {
40
+ console.log(`[DEBUG] Loaded config from -c flag: ${explicitPath}`);
41
+ }
42
+ return explicitPath;
43
+ }
44
+ console.error(`Config file not found: ${explicitPath}`);
45
+ process.exit(1);
46
+ }
47
+ // Check locations in order of priority
48
+ const locations = [
49
+ { path: LOCAL_ENV_PATH, name: 'local (.env)' },
50
+ { path: GLOBAL_ENV_PATH, name: 'global (~/.openbroker/.env)' },
51
+ ];
52
+ for (const { path, name } of locations) {
53
+ if (existsSync(path)) {
54
+ const result = loadDotenv({ path });
55
+ if (verbose) {
56
+ console.log(`[DEBUG] Loaded config from ${name}: ${path}`);
57
+ }
58
+ return path;
59
+ }
60
+ }
61
+ if (verbose) {
62
+ console.log('[DEBUG] No config file found in any location');
63
+ console.log('[DEBUG] Run "openbroker setup" to configure');
64
+ }
65
+ return null;
66
+ }
67
+ // Load config on module import
68
+ const loadedConfigPath = loadEnvFile();
69
+ /**
70
+ * Ensure the global config directory exists
71
+ */
72
+ export function ensureConfigDir() {
73
+ if (!existsSync(GLOBAL_CONFIG_DIR)) {
74
+ mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true, mode: 0o700 });
75
+ }
76
+ return GLOBAL_CONFIG_DIR;
77
+ }
78
+ /**
79
+ * Get the path where config was loaded from, or where it should be saved
80
+ */
81
+ export function getConfigPath() {
82
+ return loadedConfigPath || GLOBAL_ENV_PATH;
83
+ }
84
+ export function loadConfig() {
85
+ let privateKey = process.env.HYPERLIQUID_PRIVATE_KEY;
86
+ let isReadOnly = false;
87
+ if (!privateKey) {
88
+ // Use default read-only key for info commands
89
+ privateKey = DEFAULT_READ_ONLY_KEY;
90
+ isReadOnly = true;
91
+ // Show warning once
92
+ if (!readOnlyWarningShown) {
93
+ readOnlyWarningShown = true;
94
+ console.error('\x1b[33m⚠️ Not configured for trading. Run "openbroker setup" to enable trades.\x1b[0m\n');
95
+ }
96
+ }
97
+ if (!privateKey.startsWith('0x') || privateKey.length !== 66) {
98
+ throw new Error('HYPERLIQUID_PRIVATE_KEY must be a 64-character hex string with 0x prefix');
99
+ }
100
+ const network = process.env.HYPERLIQUID_NETWORK || 'mainnet';
101
+ const baseUrl = network === 'testnet' ? TESTNET_URL : MAINNET_URL;
102
+ // Builder fee is hardcoded — set by OpenBroker, not configurable by users
103
+ const builderAddress = OPEN_BROKER_BUILDER_ADDRESS.toLowerCase();
104
+ const builderFee = 10; // 10 tenths-of-bps = 1 bps = 0.01%
105
+ const slippageBps = parseInt(process.env.SLIPPAGE_BPS || '50', 10); // default 0.5%
106
+ // Derive the wallet address from private key
107
+ const wallet = privateKeyToAccount(privateKey);
108
+ const walletAddress = wallet.address.toLowerCase();
109
+ // Account address can be different if using an API wallet
110
+ const accountAddress = process.env.HYPERLIQUID_ACCOUNT_ADDRESS?.toLowerCase();
111
+ // Determine if this is an API wallet setup
112
+ const isApiWallet = accountAddress !== undefined && accountAddress !== walletAddress;
113
+ // Vault address — only for vault trading (ERC4626 contracts / native vaults via CoreWriter).
114
+ // Standard API wallets (approved via approveAgent) do NOT need this.
115
+ const vaultAddress = process.env.HYPERLIQUID_VAULT_ADDRESS?.toLowerCase();
116
+ const verbose = process.env.VERBOSE === '1' || process.env.VERBOSE === 'true';
117
+ return {
118
+ baseUrl,
119
+ privateKey: privateKey,
120
+ walletAddress,
121
+ accountAddress: accountAddress || walletAddress,
122
+ isApiWallet,
123
+ isReadOnly,
124
+ builderAddress,
125
+ builderFee,
126
+ slippageBps,
127
+ vaultAddress,
128
+ verbose,
129
+ };
130
+ }
131
+ /**
132
+ * Check if the current config is read-only (no trading capability)
133
+ */
134
+ export function isConfigured() {
135
+ return !!process.env.HYPERLIQUID_PRIVATE_KEY;
136
+ }
137
+ export function getNetwork() {
138
+ const network = process.env.HYPERLIQUID_NETWORK || 'mainnet';
139
+ return network === 'testnet' ? 'testnet' : 'mainnet';
140
+ }
141
+ export function isMainnet() {
142
+ return getNetwork() === 'mainnet';
143
+ }
@@ -0,0 +1,221 @@
1
+ export interface OpenBrokerConfig {
2
+ baseUrl: string;
3
+ privateKey: `0x${string}`;
4
+ walletAddress: string;
5
+ accountAddress: string;
6
+ isApiWallet: boolean;
7
+ isReadOnly: boolean;
8
+ builderAddress: string;
9
+ builderFee: number;
10
+ slippageBps: number;
11
+ vaultAddress?: string;
12
+ verbose: boolean;
13
+ }
14
+ export interface BuilderInfo {
15
+ b: string;
16
+ f: number;
17
+ }
18
+ export type OrderType = {
19
+ limit: {
20
+ tif: 'Gtc' | 'Ioc' | 'Alo';
21
+ };
22
+ } | {
23
+ trigger: {
24
+ triggerPx: string;
25
+ isMarket: boolean;
26
+ tpsl: 'tp' | 'sl';
27
+ };
28
+ };
29
+ export interface OrderRequest {
30
+ coin: string;
31
+ is_buy: boolean;
32
+ sz: number;
33
+ limit_px: number;
34
+ order_type: OrderType;
35
+ reduce_only?: boolean;
36
+ cloid?: string;
37
+ }
38
+ export interface OrderWire {
39
+ a: number;
40
+ b: boolean;
41
+ p: string;
42
+ s: string;
43
+ r: boolean;
44
+ t: OrderType;
45
+ c?: string;
46
+ }
47
+ export interface OrderResponse {
48
+ status: 'ok' | 'err';
49
+ response?: {
50
+ type: 'order';
51
+ data: {
52
+ statuses: Array<{
53
+ resting?: {
54
+ oid: number;
55
+ };
56
+ filled?: {
57
+ totalSz: string;
58
+ avgPx: string;
59
+ oid: number;
60
+ };
61
+ error?: string;
62
+ [key: string]: unknown;
63
+ }>;
64
+ };
65
+ } | string;
66
+ error?: string;
67
+ }
68
+ export interface CancelRequest {
69
+ coin: string;
70
+ oid: number;
71
+ }
72
+ export interface CancelResponse {
73
+ status: 'ok' | 'err';
74
+ response?: {
75
+ type: 'cancel';
76
+ data: {
77
+ statuses: string[];
78
+ };
79
+ };
80
+ }
81
+ export interface AssetMeta {
82
+ name: string;
83
+ szDecimals: number;
84
+ maxLeverage: number;
85
+ onlyIsolated?: boolean;
86
+ isDelisted?: boolean;
87
+ marginTableId?: number;
88
+ [key: string]: unknown;
89
+ }
90
+ export interface AssetCtx {
91
+ funding: string;
92
+ openInterest: string;
93
+ prevDayPx: string;
94
+ dayNtlVlm: string;
95
+ premium: string | null;
96
+ oraclePx: string;
97
+ markPx: string;
98
+ midPx?: string | null;
99
+ impactPxs?: [string, string] | string[] | null;
100
+ dayBaseVlm?: string;
101
+ [key: string]: unknown;
102
+ }
103
+ export interface Meta {
104
+ universe: AssetMeta[];
105
+ }
106
+ export interface MetaAndAssetCtxs {
107
+ meta: Meta;
108
+ assetCtxs: AssetCtx[];
109
+ }
110
+ export interface OutcomeSideSpec {
111
+ name: string;
112
+ token?: number;
113
+ }
114
+ export interface OutcomeMetaEntry {
115
+ outcome: number;
116
+ name: string;
117
+ description: string;
118
+ sideSpecs: OutcomeSideSpec[];
119
+ }
120
+ export interface OutcomeQuestion {
121
+ question: number;
122
+ name: string;
123
+ description: string;
124
+ fallbackOutcome: number;
125
+ namedOutcomes: number[];
126
+ settledNamedOutcomes?: number[];
127
+ }
128
+ export interface OutcomeMetaResponse {
129
+ outcomes: OutcomeMetaEntry[];
130
+ questions?: OutcomeQuestion[];
131
+ }
132
+ export interface OutcomeMarket {
133
+ outcome: number;
134
+ name: string;
135
+ description: string;
136
+ parsedDescription: Record<string, string>;
137
+ sides: Array<{
138
+ side: 0 | 1;
139
+ name: string;
140
+ encoding: number;
141
+ coin: string;
142
+ tokenName: string;
143
+ assetId: number;
144
+ token?: number;
145
+ szDecimals?: number;
146
+ midPx?: string;
147
+ markPx?: string;
148
+ prevDayPx?: string;
149
+ dayNtlVlm?: string;
150
+ }>;
151
+ question?: OutcomeQuestion;
152
+ }
153
+ export interface Position {
154
+ coin: string;
155
+ szi: string;
156
+ entryPx: string;
157
+ positionValue: string;
158
+ unrealizedPnl: string;
159
+ returnOnEquity: string;
160
+ liquidationPx: string | null;
161
+ leverage: {
162
+ type: 'cross' | 'isolated';
163
+ value: number;
164
+ rawUsd?: string;
165
+ };
166
+ marginUsed: string;
167
+ maxLeverage: number;
168
+ }
169
+ export interface AssetPosition {
170
+ position: Position;
171
+ type: 'oneWay';
172
+ }
173
+ export interface MarginSummary {
174
+ accountValue: string;
175
+ totalNtlPos: string;
176
+ totalRawUsd: string;
177
+ totalMarginUsed: string;
178
+ withdrawable: string;
179
+ }
180
+ export interface ClearinghouseState {
181
+ assetPositions: AssetPosition[];
182
+ crossMarginSummary: MarginSummary;
183
+ marginSummary: MarginSummary;
184
+ crossMaintenanceMarginUsed: string;
185
+ }
186
+ export interface FundingInfo {
187
+ coin: string;
188
+ fundingRate: string;
189
+ annualizedRate: number;
190
+ premium: string;
191
+ openInterest: string;
192
+ markPx: string;
193
+ oraclePx: string;
194
+ }
195
+ export interface OpenOrder {
196
+ coin: string;
197
+ oid: number;
198
+ cloid?: string;
199
+ side: 'B' | 'A';
200
+ sz: string;
201
+ limitPx: string;
202
+ orderType: string;
203
+ origSz: string;
204
+ timestamp: number;
205
+ }
206
+ export interface InfoRequest {
207
+ type: string;
208
+ user?: string;
209
+ [key: string]: unknown;
210
+ }
211
+ export interface ExchangeRequest {
212
+ action: Record<string, unknown>;
213
+ nonce: number;
214
+ signature: {
215
+ r: string;
216
+ s: string;
217
+ v: number;
218
+ };
219
+ vaultAddress?: string | null;
220
+ }
221
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../scripts/core/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ // Hyperliquid API Types for Open Broker
2
+ export {};
@@ -0,0 +1,61 @@
1
+ import type { OrderWire, OrderRequest } from './types.js';
2
+ /**
3
+ * Round price to 5 significant figures and appropriate decimals
4
+ * Perps: max 6 decimals, Spot: max 8 decimals
5
+ */
6
+ export declare function roundPrice(price: number, szDecimals: number, isSpot?: boolean): string;
7
+ /**
8
+ * Round size to asset's szDecimals
9
+ */
10
+ export declare function roundSize(size: number, szDecimals: number): string;
11
+ /**
12
+ * Calculate slippage-adjusted price for market orders
13
+ */
14
+ export declare function getSlippagePrice(midPrice: number, isBuy: boolean, slippageBps: number): number;
15
+ /**
16
+ * Convert order request to wire format
17
+ */
18
+ export declare function orderToWire(order: OrderRequest, assetIndex: number, szDecimals: number): OrderWire;
19
+ /**
20
+ * Get current timestamp in milliseconds
21
+ */
22
+ export declare function getTimestampMs(): number;
23
+ /**
24
+ * Format USD amount for display
25
+ */
26
+ export declare function formatUsd(amount: number | string): string;
27
+ /**
28
+ * Format percentage for display
29
+ */
30
+ export declare function formatPercent(value: number | string, decimals?: number): string;
31
+ /**
32
+ * Format funding rate (hourly to annualized)
33
+ */
34
+ export declare function annualizeFundingRate(hourlyRate: number | string): number;
35
+ /**
36
+ * Parse CLI arguments into key-value pairs
37
+ */
38
+ export declare function parseArgs(args: string[]): Record<string, string | boolean>;
39
+ /**
40
+ * Normalize a coin name: uppercase the asset, keep dex prefix lowercase.
41
+ * "eth" → "ETH", "xyz:cl" → "xyz:CL", "xyz:CL" → "xyz:CL"
42
+ */
43
+ export declare function normalizeCoin(coin: string): string;
44
+ /**
45
+ * Sleep for specified milliseconds
46
+ */
47
+ export declare function sleep(ms: number): Promise<void>;
48
+ /**
49
+ * Generate a random client order ID
50
+ */
51
+ export declare function generateCloid(): string;
52
+ /**
53
+ * Check if builder fee is approved and print warning if not
54
+ * Returns true if approved, false if not
55
+ */
56
+ export declare function checkBuilderFeeApproval(client: {
57
+ getMaxBuilderFee: () => Promise<string | null>;
58
+ builderAddress: string;
59
+ isTestnet: boolean;
60
+ }): Promise<boolean>;
61
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../scripts/core/utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAa,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAErE;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAE,OAAe,GAAG,MAAM,CAM7F;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,WAAW,EAAE,MAAM,GAClB,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,YAAY,EACnB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,SAAS,CAeX;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAQzD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,GAAE,MAAU,GAAG,MAAM,CAGlF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAGxE;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAmB1E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAOtC;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE;IAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,GACrG,OAAO,CAAC,OAAO,CAAC,CAYlB"}
@@ -0,0 +1,142 @@
1
+ // Utility functions for Open Broker
2
+ /**
3
+ * Round price to 5 significant figures and appropriate decimals
4
+ * Perps: max 6 decimals, Spot: max 8 decimals
5
+ */
6
+ export function roundPrice(price, szDecimals, isSpot = false) {
7
+ // Round to 5 significant figures first
8
+ const sigFigs = parseFloat(price.toPrecision(5));
9
+ // Then round to max decimals (6 for perps - szDecimals adjustment, 8 for spot)
10
+ const maxDecimals = isSpot ? 8 : Math.max(0, 6 - szDecimals);
11
+ return sigFigs.toFixed(maxDecimals);
12
+ }
13
+ /**
14
+ * Round size to asset's szDecimals
15
+ */
16
+ export function roundSize(size, szDecimals) {
17
+ return size.toFixed(szDecimals);
18
+ }
19
+ /**
20
+ * Calculate slippage-adjusted price for market orders
21
+ */
22
+ export function getSlippagePrice(midPrice, isBuy, slippageBps) {
23
+ const slippageMultiplier = slippageBps / 10000;
24
+ return isBuy
25
+ ? midPrice * (1 + slippageMultiplier)
26
+ : midPrice * (1 - slippageMultiplier);
27
+ }
28
+ /**
29
+ * Convert order request to wire format
30
+ */
31
+ export function orderToWire(order, assetIndex, szDecimals) {
32
+ const wire = {
33
+ a: assetIndex,
34
+ b: order.is_buy,
35
+ p: roundPrice(order.limit_px, szDecimals),
36
+ s: roundSize(order.sz, szDecimals),
37
+ r: order.reduce_only ?? false,
38
+ t: order.order_type,
39
+ };
40
+ if (order.cloid) {
41
+ wire.c = order.cloid;
42
+ }
43
+ return wire;
44
+ }
45
+ /**
46
+ * Get current timestamp in milliseconds
47
+ */
48
+ export function getTimestampMs() {
49
+ return Date.now();
50
+ }
51
+ /**
52
+ * Format USD amount for display
53
+ */
54
+ export function formatUsd(amount) {
55
+ const num = typeof amount === 'string' ? parseFloat(amount) : amount;
56
+ return new Intl.NumberFormat('en-US', {
57
+ style: 'currency',
58
+ currency: 'USD',
59
+ minimumFractionDigits: 2,
60
+ maximumFractionDigits: 2,
61
+ }).format(num);
62
+ }
63
+ /**
64
+ * Format percentage for display
65
+ */
66
+ export function formatPercent(value, decimals = 2) {
67
+ const num = typeof value === 'string' ? parseFloat(value) : value;
68
+ return `${(num * 100).toFixed(decimals)}%`;
69
+ }
70
+ /**
71
+ * Format funding rate (hourly to annualized)
72
+ */
73
+ export function annualizeFundingRate(hourlyRate) {
74
+ const rate = typeof hourlyRate === 'string' ? parseFloat(hourlyRate) : hourlyRate;
75
+ return rate * 8760; // 24 * 365 hours
76
+ }
77
+ /**
78
+ * Parse CLI arguments into key-value pairs
79
+ */
80
+ export function parseArgs(args) {
81
+ const result = {};
82
+ for (let i = 0; i < args.length; i++) {
83
+ const arg = args[i];
84
+ if (arg.startsWith('--')) {
85
+ const key = arg.slice(2);
86
+ const nextArg = args[i + 1];
87
+ if (nextArg && !nextArg.startsWith('--')) {
88
+ result[key] = nextArg;
89
+ i++;
90
+ }
91
+ else {
92
+ result[key] = true;
93
+ }
94
+ }
95
+ }
96
+ return result;
97
+ }
98
+ /**
99
+ * Normalize a coin name: uppercase the asset, keep dex prefix lowercase.
100
+ * "eth" → "ETH", "xyz:cl" → "xyz:CL", "xyz:CL" → "xyz:CL"
101
+ */
102
+ export function normalizeCoin(coin) {
103
+ const colonIdx = coin.indexOf(':');
104
+ if (colonIdx >= 0) {
105
+ return coin.slice(0, colonIdx).toLowerCase() + ':' + coin.slice(colonIdx + 1).toUpperCase();
106
+ }
107
+ return coin.toUpperCase();
108
+ }
109
+ /**
110
+ * Sleep for specified milliseconds
111
+ */
112
+ export function sleep(ms) {
113
+ return new Promise(resolve => setTimeout(resolve, ms));
114
+ }
115
+ /**
116
+ * Generate a random client order ID
117
+ */
118
+ export function generateCloid() {
119
+ const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
120
+ let result = '';
121
+ for (let i = 0; i < 16; i++) {
122
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
123
+ }
124
+ return result;
125
+ }
126
+ /**
127
+ * Check if builder fee is approved and print warning if not
128
+ * Returns true if approved, false if not
129
+ */
130
+ export async function checkBuilderFeeApproval(client) {
131
+ // Skip builder fee check on testnet — builder may not have balance
132
+ if (client.isTestnet)
133
+ return true;
134
+ const approval = await client.getMaxBuilderFee();
135
+ if (!approval) {
136
+ console.log('⚠️ Builder fee not approved!');
137
+ console.log(` Run: npx tsx scripts/setup/approve-builder.ts`);
138
+ console.log(` Builder: ${client.builderAddress}\n`);
139
+ return false;
140
+ }
141
+ return true;
142
+ }