@madeinusmate/grvt-cli 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.
package/dist/index.js ADDED
@@ -0,0 +1,700 @@
1
+ // src/core/config/store.ts
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from "fs";
3
+ import { join } from "path";
4
+ import { homedir } from "os";
5
+ import { parse as parseTOML, stringify as stringifyTOML } from "smol-toml";
6
+
7
+ // src/core/config/schema.ts
8
+ import { z } from "zod";
9
+ var environmentSchema = z.enum(["dev", "staging", "testnet", "prod"]);
10
+ var httpConfigSchema = z.object({
11
+ timeoutMs: z.number().int().positive().default(1e4),
12
+ retries: z.number().int().min(0).default(3),
13
+ backoffMs: z.number().int().positive().default(200),
14
+ maxBackoffMs: z.number().int().positive().default(1e4)
15
+ });
16
+ var outputDefaultsSchema = z.object({
17
+ output: z.enum(["json", "ndjson", "table", "raw"]).default("table"),
18
+ pretty: z.boolean().default(false),
19
+ silent: z.boolean().default(false)
20
+ });
21
+ var configSchema = z.object({
22
+ env: environmentSchema.default("prod"),
23
+ apiKey: z.string().optional(),
24
+ privateKey: z.string().optional(),
25
+ subAccountId: z.string().optional(),
26
+ accountId: z.string().optional(),
27
+ cookie: z.string().optional(),
28
+ outputDefaults: outputDefaultsSchema.default({}),
29
+ http: httpConfigSchema.default({})
30
+ });
31
+ var DEFAULT_CONFIG = configSchema.parse({});
32
+
33
+ // src/core/config/store.ts
34
+ var getConfigDir = () => {
35
+ const xdgConfig = process.env["XDG_CONFIG_HOME"];
36
+ const base = xdgConfig || join(homedir(), ".config");
37
+ return join(base, "grvt");
38
+ };
39
+ var getConfigPath = () => join(getConfigDir(), "config.toml");
40
+ var loadConfig = () => {
41
+ const path = getConfigPath();
42
+ if (!existsSync(path)) {
43
+ return DEFAULT_CONFIG;
44
+ }
45
+ const raw = readFileSync(path, "utf-8");
46
+ const parsed = parseTOML(raw);
47
+ return configSchema.parse(parsed);
48
+ };
49
+ var saveConfig = (config) => {
50
+ const dir = getConfigDir();
51
+ if (!existsSync(dir)) {
52
+ mkdirSync(dir, { recursive: true });
53
+ }
54
+ const path = getConfigPath();
55
+ const toml = stringifyTOML(config);
56
+ writeFileSync(path, toml, { mode: 384 });
57
+ try {
58
+ chmodSync(path, 384);
59
+ } catch {
60
+ }
61
+ };
62
+
63
+ // src/core/client/endpoints.ts
64
+ var BASE_URLS = {
65
+ dev: {
66
+ edge: "https://edge.dev.gravitymarkets.io",
67
+ marketData: "https://market-data.dev.gravitymarkets.io",
68
+ trading: "https://trades.dev.gravitymarkets.io"
69
+ },
70
+ staging: {
71
+ edge: "https://edge.staging.gravitymarkets.io",
72
+ marketData: "https://market-data.staging.gravitymarkets.io",
73
+ trading: "https://trades.staging.gravitymarkets.io"
74
+ },
75
+ testnet: {
76
+ edge: "https://edge.testnet.grvt.io",
77
+ marketData: "https://market-data.testnet.grvt.io",
78
+ trading: "https://trades.testnet.grvt.io"
79
+ },
80
+ prod: {
81
+ edge: "https://edge.grvt.io",
82
+ marketData: "https://market-data.grvt.io",
83
+ trading: "https://trades.grvt.io"
84
+ }
85
+ };
86
+ var CHAIN_IDS = {
87
+ dev: { l1: 11155111, l2: 327 },
88
+ staging: { l1: 11155111, l2: 327 },
89
+ testnet: { l1: 11155111, l2: 326 },
90
+ prod: { l1: 1, l2: 325 }
91
+ };
92
+ var ENDPOINTS = {
93
+ auth: {
94
+ login: "/auth/api_key/login"
95
+ },
96
+ marketData: {
97
+ instrument: "/full/v1/instrument",
98
+ allInstruments: "/full/v1/all_instruments",
99
+ instruments: "/full/v1/instruments",
100
+ currency: "/full/v1/currency",
101
+ marginRules: "/full/v1/margin_rules",
102
+ mini: "/full/v1/mini",
103
+ ticker: "/full/v1/ticker",
104
+ tradeHistory: "/full/v1/trade_history",
105
+ kline: "/full/v1/kline",
106
+ funding: "/full/v1/funding",
107
+ book: "/full/v1/book"
108
+ },
109
+ trading: {
110
+ createOrder: "/full/v1/create_order",
111
+ cancelOrder: "/full/v1/cancel_order",
112
+ cancelAllOrders: "/full/v1/cancel_all_orders",
113
+ getOrder: "/full/v1/order",
114
+ openOrders: "/full/v1/open_orders",
115
+ orderHistory: "/full/v1/order_history",
116
+ cancelOnDisconnect: "/full/v1/cancel_on_disconnect",
117
+ fillHistory: "/full/v1/fill_history",
118
+ positions: "/full/v1/positions",
119
+ fundingPaymentHistory: "/full/v1/funding_payment_history",
120
+ getAllInitialLeverage: "/full/v1/get_all_initial_leverage",
121
+ setInitialLeverage: "/full/v1/set_initial_leverage",
122
+ setDeriskMmRatio: "/full/v1/set_derisk_mm_ratio"
123
+ },
124
+ account: {
125
+ accountSummary: "/full/v1/account_summary",
126
+ accountHistory: "/full/v1/account_history",
127
+ fundingAccountSummary: "/full/v1/funding_account_summary",
128
+ aggregatedAccountSummary: "/full/v1/aggregated_account_summary"
129
+ },
130
+ funds: {
131
+ depositHistory: "/full/v1/deposit_history",
132
+ transfer: "/full/v1/transfer",
133
+ transferHistory: "/full/v1/transfer_history",
134
+ withdrawal: "/full/v1/withdrawal",
135
+ withdrawalHistory: "/full/v1/withdrawal_history"
136
+ }
137
+ };
138
+ var getBaseUrls = (env) => BASE_URLS[env];
139
+ var getChainIds = (env) => CHAIN_IDS[env];
140
+
141
+ // src/core/client/http.ts
142
+ var createHttpClient = (options) => {
143
+ const {
144
+ env,
145
+ cookie,
146
+ accountId,
147
+ timeoutMs = 1e4,
148
+ retries = 3,
149
+ backoffMs = 200,
150
+ maxBackoffMs = 1e4
151
+ } = options;
152
+ const urls = getBaseUrls(env);
153
+ const post = async (baseType, path, body) => {
154
+ const url = `${urls[baseType]}${path}`;
155
+ const headers = {
156
+ "Content-Type": "application/json"
157
+ };
158
+ if (cookie) {
159
+ headers["Cookie"] = cookie;
160
+ }
161
+ if (accountId) {
162
+ headers["X-Grvt-Account-Id"] = accountId;
163
+ }
164
+ let lastError;
165
+ for (let attempt = 0; attempt <= retries; attempt++) {
166
+ try {
167
+ const controller = new AbortController();
168
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
169
+ const response = await fetch(url, {
170
+ method: "POST",
171
+ headers,
172
+ body: body !== void 0 ? JSON.stringify(body) : void 0,
173
+ signal: controller.signal
174
+ });
175
+ clearTimeout(timer);
176
+ if (response.status === 429 || response.status >= 500) {
177
+ const err = new Error(`HTTP ${response.status}: ${response.statusText}`);
178
+ err.statusCode = response.status;
179
+ throw err;
180
+ }
181
+ if (!response.ok) {
182
+ const text = await response.text().catch(() => "");
183
+ const err = new Error(`HTTP ${response.status}: ${text || response.statusText}`);
184
+ err.statusCode = response.status;
185
+ throw err;
186
+ }
187
+ return await response.json();
188
+ } catch (error) {
189
+ lastError = error instanceof Error ? error : new Error(String(error));
190
+ const isRetryable = lastError.statusCode === 429 || (lastError.statusCode ?? 0) >= 500 || lastError.name === "AbortError";
191
+ if (!isRetryable || attempt >= retries) {
192
+ throw lastError;
193
+ }
194
+ const delay = Math.min(backoffMs * Math.pow(2, attempt), maxBackoffMs);
195
+ await sleep(delay);
196
+ }
197
+ }
198
+ throw lastError ?? new Error("Request failed");
199
+ };
200
+ return { post };
201
+ };
202
+ var extractAuthFromResponse = async (env, apiKey) => {
203
+ const urls = getBaseUrls(env);
204
+ const url = `${urls.edge}/auth/api_key/login`;
205
+ const response = await fetch(url, {
206
+ method: "POST",
207
+ headers: {
208
+ "Content-Type": "application/json",
209
+ Cookie: "rm=true;"
210
+ },
211
+ body: JSON.stringify({ api_key: apiKey }),
212
+ redirect: "manual"
213
+ });
214
+ const bodyText = await response.text().catch(() => "");
215
+ if (!response.ok && response.status !== 302) {
216
+ throw new Error(`Auth failed (HTTP ${response.status}): ${bodyText || response.statusText}`);
217
+ }
218
+ if (bodyText) {
219
+ try {
220
+ const bodyJson = JSON.parse(bodyText);
221
+ if (bodyJson["status"] === "failure" || bodyJson["error"]) {
222
+ throw new Error(`Auth failed: ${bodyJson["error"] ?? bodyJson["message"] ?? "unknown error"}`);
223
+ }
224
+ } catch (e) {
225
+ if (e instanceof Error && e.message.startsWith("Auth failed")) throw e;
226
+ }
227
+ }
228
+ const setCookies = response.headers.getSetCookie?.() ?? [];
229
+ let gravityCookie = setCookies.map((c2) => c2.split(";")[0]).find((c2) => c2?.startsWith("gravity="));
230
+ if (!gravityCookie) {
231
+ const rawSetCookie = response.headers.get("set-cookie");
232
+ if (rawSetCookie) {
233
+ const match = rawSetCookie.match(/gravity=[^;]+/);
234
+ if (match) {
235
+ gravityCookie = match[0];
236
+ }
237
+ }
238
+ }
239
+ if (!gravityCookie) {
240
+ throw new Error("Auth response did not contain gravity session cookie. Verify your API key is valid.");
241
+ }
242
+ const accountId = response.headers.get("x-grvt-account-id");
243
+ if (!accountId) {
244
+ throw new Error("Auth response did not contain X-Grvt-Account-Id header");
245
+ }
246
+ return { cookie: gravityCookie, accountId: accountId.trim() };
247
+ };
248
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
249
+
250
+ // src/core/auth/login.ts
251
+ var performLogin = async (options) => {
252
+ const config = loadConfig();
253
+ const env = options.env ?? config.env;
254
+ const { cookie, accountId } = await extractAuthFromResponse(env, options.apiKey);
255
+ saveConfig({
256
+ ...config,
257
+ env,
258
+ apiKey: options.apiKey,
259
+ cookie,
260
+ accountId,
261
+ ...options.privateKey ? { privateKey: options.privateKey } : {}
262
+ });
263
+ return { accountId, env };
264
+ };
265
+
266
+ // src/core/auth/session.ts
267
+ var login = async (options) => performLogin(options);
268
+ var logout = () => {
269
+ const config = loadConfig();
270
+ saveConfig({
271
+ ...config,
272
+ apiKey: void 0,
273
+ privateKey: void 0,
274
+ cookie: void 0,
275
+ accountId: void 0
276
+ });
277
+ };
278
+ var verifySession = async () => {
279
+ const config = loadConfig();
280
+ if (!config.cookie || !config.accountId) {
281
+ return { valid: false, env: config.env };
282
+ }
283
+ try {
284
+ const client = createHttpClient({
285
+ env: config.env,
286
+ cookie: config.cookie,
287
+ accountId: config.accountId,
288
+ timeoutMs: config.http.timeoutMs
289
+ });
290
+ await client.post("trading", ENDPOINTS.account.fundingAccountSummary, {});
291
+ return { valid: true, env: config.env, accountId: config.accountId };
292
+ } catch {
293
+ return { valid: false, env: config.env, accountId: config.accountId };
294
+ }
295
+ };
296
+
297
+ // src/commands/trade/orders.ts
298
+ import { randomBytes } from "crypto";
299
+
300
+ // src/core/output/table.ts
301
+ import Table from "cli-table3";
302
+
303
+ // src/core/output/colors.ts
304
+ import chalk from "chalk";
305
+ var _disabled = false;
306
+ var c = () => {
307
+ if (_disabled) {
308
+ return {
309
+ red: (s) => s,
310
+ green: (s) => s,
311
+ yellow: (s) => s,
312
+ cyan: { bold: (s) => s }
313
+ };
314
+ }
315
+ return chalk;
316
+ };
317
+
318
+ // src/core/output/table.ts
319
+ var renderTable = (data) => {
320
+ if (data.length === 0) return "No data";
321
+ const keys = Object.keys(data[0]);
322
+ const table = new Table({
323
+ head: keys.map((k) => c().cyan.bold(k)),
324
+ style: { head: [], border: [] }
325
+ });
326
+ for (const row of data) {
327
+ table.push(keys.map((k) => formatCell(row[k])));
328
+ }
329
+ return table.toString();
330
+ };
331
+ var renderVerticalTable = (data) => {
332
+ const table = new Table({
333
+ style: { head: [], border: [] }
334
+ });
335
+ for (const [key, value] of Object.entries(data)) {
336
+ table.push({ [c().cyan.bold(key)]: formatCell(value) });
337
+ }
338
+ return table.toString();
339
+ };
340
+ var formatCell = (value) => {
341
+ if (value === null || value === void 0) return "";
342
+ if (typeof value === "object") return JSON.stringify(value);
343
+ return String(value);
344
+ };
345
+
346
+ // src/core/output/format.ts
347
+ var formatOutput = (data, options) => {
348
+ switch (options.output) {
349
+ case "json":
350
+ return options.pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
351
+ case "ndjson":
352
+ if (Array.isArray(data)) {
353
+ return data.map((item) => JSON.stringify(item)).join("\n");
354
+ }
355
+ return JSON.stringify(data);
356
+ case "raw":
357
+ if (typeof data === "string") return data;
358
+ return JSON.stringify(data);
359
+ case "table":
360
+ if (Array.isArray(data)) {
361
+ if (data.length === 0) return "No data";
362
+ if (typeof data[0] === "object" && data[0] !== null) {
363
+ return renderTable(data);
364
+ }
365
+ return data.map(String).join("\n");
366
+ }
367
+ if (typeof data === "object" && data !== null) {
368
+ return renderVerticalTable(data);
369
+ }
370
+ return String(data);
371
+ }
372
+ };
373
+
374
+ // src/core/pagination/cursor.ts
375
+ var paginateCursor = async (options) => {
376
+ const { fetchPage, all, outputOptions } = options;
377
+ let { cursor } = options;
378
+ if (!all) {
379
+ const page = await fetchPage(cursor);
380
+ return page.result;
381
+ }
382
+ const isStreaming = outputOptions.output === "ndjson";
383
+ const collected = [];
384
+ while (true) {
385
+ const page = await fetchPage(cursor);
386
+ if (isStreaming) {
387
+ for (const item of page.result) {
388
+ process.stdout.write(formatOutput(item, outputOptions) + "\n");
389
+ }
390
+ } else {
391
+ collected.push(...page.result);
392
+ }
393
+ if (!page.next || page.result.length === 0) {
394
+ break;
395
+ }
396
+ cursor = page.next;
397
+ }
398
+ return collected;
399
+ };
400
+
401
+ // src/core/safety/confirm.ts
402
+ import { createInterface } from "readline";
403
+
404
+ // src/core/safety/validate.ts
405
+ import { readFileSync as readFileSync2, readSync } from "fs";
406
+
407
+ // src/core/instruments/cache.ts
408
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
409
+ import { join as join2 } from "path";
410
+ import { homedir as homedir2 } from "os";
411
+ var CACHE_TTL_MS = 60 * 60 * 1e3;
412
+
413
+ // src/core/signing/eip712.ts
414
+ var PRICE_MULTIPLIER = 1000000000n;
415
+ var decimalToBigInt = (value, multiplier) => {
416
+ const parts = value.split(".");
417
+ const whole = parts[0] ?? "0";
418
+ const frac = parts[1] ?? "";
419
+ const multiplierDigits = multiplier.toString().length - 1;
420
+ const paddedFrac = frac.padEnd(multiplierDigits, "0").slice(0, multiplierDigits);
421
+ return BigInt(whole) * multiplier + BigInt(paddedFrac);
422
+ };
423
+ var buildTransferTypedData = (payload, env) => {
424
+ const chainIds = getChainIds(env);
425
+ const domain = {
426
+ name: "GRVT Exchange",
427
+ version: "0",
428
+ chainId: BigInt(chainIds.l2)
429
+ };
430
+ const types = {
431
+ Transfer: [
432
+ { name: "fromAccount", type: "address" },
433
+ { name: "fromSubAccount", type: "uint64" },
434
+ { name: "toAccount", type: "address" },
435
+ { name: "toSubAccount", type: "uint64" },
436
+ { name: "tokenCurrency", type: "uint8" },
437
+ { name: "numTokens", type: "uint64" },
438
+ { name: "nonce", type: "uint32" },
439
+ { name: "expiration", type: "int64" }
440
+ ]
441
+ };
442
+ const tokenMultiplier = BigInt(10) ** BigInt(payload.balanceDecimals);
443
+ const message = {
444
+ fromAccount: payload.fromAccount,
445
+ fromSubAccount: BigInt(payload.fromSubAccount),
446
+ toAccount: payload.toAccount,
447
+ toSubAccount: BigInt(payload.toSubAccount),
448
+ tokenCurrency: payload.tokenCurrency,
449
+ numTokens: decimalToBigInt(payload.numTokens, tokenMultiplier),
450
+ nonce: payload.nonce,
451
+ expiration: BigInt(payload.expiration)
452
+ };
453
+ return { domain, types, primaryType: "Transfer", message };
454
+ };
455
+ var buildWithdrawalTypedData = (payload, env) => {
456
+ const chainIds = getChainIds(env);
457
+ const domain = {
458
+ name: "GRVT Exchange",
459
+ version: "0",
460
+ chainId: BigInt(chainIds.l2)
461
+ };
462
+ const types = {
463
+ Withdrawal: [
464
+ { name: "fromAccount", type: "address" },
465
+ { name: "toEthAddress", type: "address" },
466
+ { name: "tokenCurrency", type: "uint8" },
467
+ { name: "numTokens", type: "uint64" },
468
+ { name: "nonce", type: "uint32" },
469
+ { name: "expiration", type: "int64" }
470
+ ]
471
+ };
472
+ const tokenMultiplier = BigInt(10) ** BigInt(payload.balanceDecimals);
473
+ const message = {
474
+ fromAccount: payload.fromAccount,
475
+ toEthAddress: payload.toEthAddress,
476
+ tokenCurrency: payload.tokenCurrency,
477
+ numTokens: decimalToBigInt(payload.numTokens, tokenMultiplier),
478
+ nonce: payload.nonce,
479
+ expiration: BigInt(payload.expiration)
480
+ };
481
+ return { domain, types, primaryType: "Withdrawal", message };
482
+ };
483
+ var buildDeriskTypedData = (payload, env) => {
484
+ const chainIds = getChainIds(env);
485
+ const domain = {
486
+ name: "GRVT Exchange",
487
+ version: "0",
488
+ chainId: BigInt(chainIds.l2)
489
+ };
490
+ const types = {
491
+ SetDeriskMMRatio: [
492
+ { name: "subAccountID", type: "uint64" },
493
+ { name: "ratio", type: "uint64" },
494
+ { name: "nonce", type: "uint32" },
495
+ { name: "expiration", type: "int64" }
496
+ ]
497
+ };
498
+ const message = {
499
+ subAccountID: BigInt(payload.subAccountId),
500
+ ratio: decimalToBigInt(payload.ratio, PRICE_MULTIPLIER),
501
+ nonce: payload.nonce,
502
+ expiration: BigInt(payload.expiration)
503
+ };
504
+ return { domain, types, primaryType: "SetDeriskMMRatio", message };
505
+ };
506
+
507
+ // src/core/signing/signer.ts
508
+ import { privateKeyToAccount } from "viem/accounts";
509
+ import { parseSignature } from "viem";
510
+
511
+ // src/commands/trade/orders.ts
512
+ var createOrder = async (client, order) => {
513
+ const body = { order };
514
+ const result = await client.post("trading", ENDPOINTS.trading.createOrder, body);
515
+ return result.result;
516
+ };
517
+ var cancelOrder = async (client, params) => {
518
+ const result = await client.post("trading", ENDPOINTS.trading.cancelOrder, params);
519
+ return result.result;
520
+ };
521
+ var cancelAllOrders = async (client, params) => {
522
+ const result = await client.post("trading", ENDPOINTS.trading.cancelAllOrders, params);
523
+ return result.result;
524
+ };
525
+ var getOrder = async (client, params) => {
526
+ const result = await client.post("trading", ENDPOINTS.trading.getOrder, params);
527
+ return result.result;
528
+ };
529
+ var getOpenOrders = async (client, params) => {
530
+ const result = await client.post("trading", ENDPOINTS.trading.openOrders, params);
531
+ return result.result;
532
+ };
533
+ var getOrderHistory = async (client, params) => {
534
+ return client.post("trading", ENDPOINTS.trading.orderHistory, params);
535
+ };
536
+
537
+ // src/commands/trade/fills.ts
538
+ var getFillHistory = async (client, params) => {
539
+ return client.post("trading", ENDPOINTS.trading.fillHistory, params);
540
+ };
541
+
542
+ // src/commands/trade/positions.ts
543
+ var getPositions = async (client, params) => {
544
+ const result = await client.post("trading", ENDPOINTS.trading.positions, params);
545
+ return result.result;
546
+ };
547
+
548
+ // src/commands/trade/funding-payments.ts
549
+ var getFundingPayments = async (client, params) => {
550
+ return client.post("trading", ENDPOINTS.trading.fundingPaymentHistory, params);
551
+ };
552
+
553
+ // src/commands/account.ts
554
+ var getFundingAccountSummary = async (client) => {
555
+ const result = await client.post("trading", ENDPOINTS.account.fundingAccountSummary, {});
556
+ return result.result;
557
+ };
558
+ var getSubAccountSummary = async (client, subAccountId) => {
559
+ const body = { sub_account_id: subAccountId };
560
+ const result = await client.post("trading", ENDPOINTS.account.accountSummary, body);
561
+ return result.result;
562
+ };
563
+ var getSubAccountHistory = getSubAccountSummary;
564
+ var getAccountHistory = async (client, params) => {
565
+ return client.post("trading", ENDPOINTS.account.accountHistory, params);
566
+ };
567
+ var getAggregatedAccountSummary = async (client) => {
568
+ const result = await client.post("trading", ENDPOINTS.account.aggregatedAccountSummary, {});
569
+ return result.result;
570
+ };
571
+
572
+ // src/commands/funds/deposits.ts
573
+ var createDeposit = async (_client, _params) => {
574
+ throw new Error("Deposit creation is not available via REST API. Use the GRVT web interface.");
575
+ };
576
+ var getDepositHistory = async (client, params) => {
577
+ return client.post("trading", ENDPOINTS.funds.depositHistory, params);
578
+ };
579
+
580
+ // src/core/currencies/cache.ts
581
+ import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
582
+ import { join as join3 } from "path";
583
+ import { homedir as homedir3 } from "os";
584
+ var CACHE_TTL_MS2 = 60 * 60 * 1e3;
585
+ var getCacheDir = () => {
586
+ const xdgCache = process.env["XDG_CACHE_HOME"];
587
+ const base = xdgCache || join3(homedir3(), ".cache");
588
+ return join3(base, "grvt");
589
+ };
590
+ var getCachePath = (env) => join3(getCacheDir(), `currencies-${env}.json`);
591
+ var loadCache = (env) => {
592
+ const path = getCachePath(env);
593
+ if (!existsSync3(path)) return null;
594
+ try {
595
+ const raw = readFileSync4(path, "utf-8");
596
+ const cache = JSON.parse(raw);
597
+ if (cache.env !== env || Date.now() - cache.fetched_at > CACHE_TTL_MS2) {
598
+ return null;
599
+ }
600
+ return cache;
601
+ } catch {
602
+ return null;
603
+ }
604
+ };
605
+ var saveCache = (env, currencies) => {
606
+ const dir = getCacheDir();
607
+ if (!existsSync3(dir)) {
608
+ mkdirSync3(dir, { recursive: true });
609
+ }
610
+ const cache = { env, fetched_at: Date.now(), currencies };
611
+ writeFileSync3(getCachePath(env), JSON.stringify(cache), "utf-8");
612
+ };
613
+ var getCurrencies = async (env, cookie, accountId) => {
614
+ const cached = loadCache(env);
615
+ if (cached) return cached.currencies;
616
+ const client = createHttpClient({ env, cookie, accountId });
617
+ const response = await client.post(
618
+ "marketData",
619
+ ENDPOINTS.marketData.currency,
620
+ {}
621
+ );
622
+ const currencies = {};
623
+ for (const cur of response.result ?? []) {
624
+ currencies[cur.symbol] = cur;
625
+ }
626
+ saveCache(env, currencies);
627
+ return currencies;
628
+ };
629
+ var getCurrencyId = async (env, symbol, cookie, accountId) => {
630
+ const currencies = await getCurrencies(env, cookie, accountId);
631
+ const cur = currencies[symbol.toUpperCase()];
632
+ if (!cur) {
633
+ throw new Error(`Currency not found: ${symbol}. Run 'grvt market currency' to see available currencies.`);
634
+ }
635
+ return cur.id;
636
+ };
637
+ var getCurrencyDecimals = async (env, symbol, cookie, accountId) => {
638
+ const currencies = await getCurrencies(env, cookie, accountId);
639
+ const cur = currencies[symbol.toUpperCase()];
640
+ if (!cur) {
641
+ throw new Error(`Currency not found: ${symbol}. Run 'grvt market currency' to see available currencies.`);
642
+ }
643
+ return cur.balance_decimals;
644
+ };
645
+
646
+ // src/commands/funds/transfers.ts
647
+ var createTransfer = async (client, params) => {
648
+ const result = await client.post("trading", ENDPOINTS.funds.transfer, params);
649
+ return result.result;
650
+ };
651
+ var getTransferHistory = async (client, params) => {
652
+ return client.post("trading", ENDPOINTS.funds.transferHistory, params);
653
+ };
654
+
655
+ // src/commands/funds/withdrawals.ts
656
+ var createWithdrawal = async (client, params) => {
657
+ const result = await client.post("trading", ENDPOINTS.funds.withdrawal, params);
658
+ return result.result;
659
+ };
660
+ var getWithdrawalHistory = async (client, params) => {
661
+ return client.post("trading", ENDPOINTS.funds.withdrawalHistory, params);
662
+ };
663
+ export {
664
+ ENDPOINTS,
665
+ buildDeriskTypedData,
666
+ buildTransferTypedData,
667
+ buildWithdrawalTypedData,
668
+ cancelAllOrders,
669
+ cancelOrder,
670
+ configSchema,
671
+ createDeposit,
672
+ createHttpClient,
673
+ createOrder,
674
+ createTransfer,
675
+ createWithdrawal,
676
+ getAccountHistory,
677
+ getAggregatedAccountSummary,
678
+ getCurrencies,
679
+ getCurrencyDecimals,
680
+ getCurrencyId,
681
+ getDepositHistory,
682
+ getFillHistory,
683
+ getFundingAccountSummary,
684
+ getFundingPayments,
685
+ getOpenOrders,
686
+ getOrder,
687
+ getOrderHistory,
688
+ getPositions,
689
+ getSubAccountHistory,
690
+ getSubAccountSummary,
691
+ getTransferHistory,
692
+ getWithdrawalHistory,
693
+ loadConfig,
694
+ login,
695
+ logout,
696
+ paginateCursor,
697
+ saveConfig,
698
+ verifySession
699
+ };
700
+ //# sourceMappingURL=index.js.map