@bithumb-official/bithumb-cli 0.1.16 → 0.1.17
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/{chunk-AUQ7MB6O.js → chunk-3VWN4HON.js} +35 -8
- package/dist/chunk-3VWN4HON.js.map +1 -0
- package/dist/{chunk-YXIFBNEQ.js → chunk-HT2P7KTV.js} +67 -994
- package/dist/chunk-HT2P7KTV.js.map +1 -0
- package/dist/{deposit-HNUSMKX5.js → deposit-KAUQEY7H.js} +6 -6
- package/dist/deposit-KAUQEY7H.js.map +1 -0
- package/dist/{deposit-TCMLJ7MI.js → deposit-L3BBLG4X.js} +21 -13
- package/dist/deposit-L3BBLG4X.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +99 -60
- package/dist/index.js.map +1 -1
- package/dist/{market-GLU62BWO.js → market-4IEKEJ4N.js} +8 -7
- package/dist/market-4IEKEJ4N.js.map +1 -0
- package/dist/{market-EEF3KI4T.js → market-C5ESTU3F.js} +6 -6
- package/dist/market-C5ESTU3F.js.map +1 -0
- package/dist/{setup-LAAVO63H.js → setup-NC3QC63P.js} +2 -3
- package/dist/setup-NC3QC63P.js.map +1 -0
- package/dist/{system-XRZ2KHXL.js → system-RVBNM3IX.js} +2 -2
- package/dist/{system-BRZY7PTZ.js → system-XK2EF5SQ.js} +3 -7
- package/dist/system-XK2EF5SQ.js.map +1 -0
- package/dist/{trade-H4G5P2W2.js → trade-RKL7RNME.js} +18 -8
- package/dist/trade-RKL7RNME.js.map +1 -0
- package/dist/{trade-FERR47DJ.js → trade-X5VBEQJE.js} +21 -10
- package/dist/trade-X5VBEQJE.js.map +1 -0
- package/dist/{twap-44UCVSIR.js → twap-FQJVPUWH.js} +12 -4
- package/dist/twap-FQJVPUWH.js.map +1 -0
- package/dist/{twap-4LRBUMTG.js → twap-MZ7ALPBC.js} +3 -3
- package/dist/twap-MZ7ALPBC.js.map +1 -0
- package/dist/{withdraw-TLGVRUBS.js → withdraw-65X3DXR5.js} +17 -9
- package/dist/withdraw-65X3DXR5.js.map +1 -0
- package/dist/{withdraw-IRMICBD2.js → withdraw-LDERU7T7.js} +6 -6
- package/dist/withdraw-LDERU7T7.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-AUQ7MB6O.js.map +0 -1
- package/dist/chunk-YXIFBNEQ.js.map +0 -1
- package/dist/config-2P3Y3TQH.js +0 -182
- package/dist/config-2P3Y3TQH.js.map +0 -1
- package/dist/config-6BIS2PLC.js +0 -154
- package/dist/config-6BIS2PLC.js.map +0 -1
- package/dist/deposit-HNUSMKX5.js.map +0 -1
- package/dist/deposit-TCMLJ7MI.js.map +0 -1
- package/dist/market-EEF3KI4T.js.map +0 -1
- package/dist/market-GLU62BWO.js.map +0 -1
- package/dist/setup-LAAVO63H.js.map +0 -1
- package/dist/system-BRZY7PTZ.js.map +0 -1
- package/dist/trade-FERR47DJ.js.map +0 -1
- package/dist/trade-H4G5P2W2.js.map +0 -1
- package/dist/twap-44UCVSIR.js.map +0 -1
- package/dist/twap-4LRBUMTG.js.map +0 -1
- package/dist/withdraw-IRMICBD2.js.map +0 -1
- package/dist/withdraw-TLGVRUBS.js.map +0 -1
- /package/dist/{system-XRZ2KHXL.js.map → system-RVBNM3IX.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../core/src/utils/signature.ts","../../core/src/utils/errors.ts","../../core/src/utils/rate-limiter.ts","../../core/src/constants.ts","../../core/src/client/rest-client.ts","../../core/src/tools/helpers.ts","../../core/src/tools/common.ts","../../core/src/tools/market.ts","../../core/src/tools/account.ts","../../core/src/tools/trade.ts","../../core/src/tools/audit.ts","../../core/src/tools/diagnose.ts","../../core/src/tools/twap.ts","../../core/src/tools/withdraw.ts","../../core/src/tools/deposit.ts","../../core/src/tools/index.ts","../../core/src/tools/types.ts","../../core/src/config.ts","../../core/src/utils/logger.ts","../../core/src/utils/update-check.ts","../../core/src/setup.ts"],"sourcesContent":["// ─── Bithumb JWT HS256 Authentication ──────────────────────────────\n\nimport { createHash, createHmac, randomUUID } from \"node:crypto\";\n\nfunction base64url(input: string | Buffer): string {\n const buf = typeof input === \"string\" ? Buffer.from(input) : input;\n return buf.toString(\"base64url\");\n}\n\n/**\n * SHA-512 hash of query string for JWT payload.\n */\nexport function hashQuery(queryString: string): string {\n return createHash(\"sha512\").update(queryString, \"utf8\").digest(\"hex\");\n}\n\nexport interface JwtPayload {\n access_key: string;\n nonce: string;\n timestamp: number;\n query_hash?: string;\n query_hash_alg?: string;\n}\n\n/**\n * Create a JWT token with HS256 signing (manual implementation, no deps).\n */\nexport function createJwt(payload: JwtPayload, secretKey: string): string {\n const header = { alg: \"HS256\", typ: \"JWT\" };\n const headerB64 = base64url(JSON.stringify(header));\n const payloadB64 = base64url(JSON.stringify(payload));\n const signature = createHmac(\"sha256\", secretKey)\n .update(`${headerB64}.${payloadB64}`)\n .digest(\"base64url\");\n return `${headerB64}.${payloadB64}.${signature}`;\n}\n\n/**\n * Build a signed JWT Bearer token for Bithumb API v2.1.5.\n *\n * @param accessKey - BITHUMB_ACCESS_KEY\n * @param secretKey - BITHUMB_SECRET_KEY\n * @param queryString - Optional query/body string to hash (key=value&key=value)\n */\nexport function signRequest(\n accessKey: string,\n secretKey: string,\n queryString?: string,\n): string {\n const payload: JwtPayload = {\n access_key: accessKey,\n nonce: randomUUID(),\n timestamp: Date.now(),\n };\n\n if (queryString && queryString.length > 0) {\n payload.query_hash = hashQuery(queryString);\n payload.query_hash_alg = \"SHA512\";\n }\n\n return createJwt(payload, secretKey);\n}\n","// ─── Bithumb MCP Error Hierarchy ───────────────────────────────────\n\nexport type ErrorType =\n | \"ConfigError\"\n | \"AuthenticationError\"\n | \"RateLimitError\"\n | \"ValidationError\"\n | \"BithumbApiError\"\n | \"NetworkError\"\n | \"InternalError\";\n\nexport interface ToolErrorPayload {\n error: true;\n type: ErrorType;\n code?: string;\n message: string;\n suggestion?: string;\n endpoint?: string;\n timestamp: string;\n}\n\nexport class BithumbMcpError extends Error {\n public readonly type: ErrorType;\n public readonly code?: string;\n public readonly suggestion?: string;\n public readonly endpoint?: string;\n\n constructor(\n type: ErrorType,\n message: string,\n options?: {\n code?: string;\n suggestion?: string;\n endpoint?: string;\n cause?: unknown;\n },\n ) {\n super(message, options?.cause ? { cause: options.cause } : undefined);\n this.name = type;\n this.type = type;\n this.code = options?.code;\n this.suggestion = options?.suggestion;\n this.endpoint = options?.endpoint;\n }\n}\n\nexport class ConfigError extends BithumbMcpError {\n constructor(message: string, suggestion?: string) {\n super(\"ConfigError\", message, { suggestion });\n }\n}\n\nexport class ValidationError extends BithumbMcpError {\n constructor(message: string, suggestion?: string) {\n super(\"ValidationError\", message, { suggestion });\n }\n}\n\nexport class RateLimitError extends BithumbMcpError {\n constructor(message: string, suggestion?: string, endpoint?: string) {\n super(\"RateLimitError\", message, { suggestion, endpoint });\n }\n}\n\nexport class AuthenticationError extends BithumbMcpError {\n constructor(message: string, suggestion?: string, endpoint?: string) {\n super(\"AuthenticationError\", message, { suggestion, endpoint });\n }\n}\n\nexport class BithumbApiError extends BithumbMcpError {\n constructor(\n message: string,\n options?: { code?: string; endpoint?: string; cause?: unknown },\n ) {\n super(\"BithumbApiError\", message, options);\n }\n}\n\nexport class NetworkError extends BithumbMcpError {\n constructor(message: string, endpoint?: string, cause?: unknown) {\n super(\"NetworkError\", message, {\n endpoint,\n cause,\n suggestion: \"Check network connectivity and try again.\",\n });\n }\n}\n\nexport class InternalError extends BithumbMcpError {\n constructor(message: string, cause?: unknown) {\n super(\"InternalError\", message, { cause });\n }\n}\n\n// ─── Error → MCP payload ───────────────────────────────────────────\n\nexport function toToolErrorPayload(error: unknown): ToolErrorPayload {\n if (error instanceof BithumbMcpError) {\n return {\n error: true,\n type: error.type,\n code: error.code,\n message: error.message,\n suggestion: error.suggestion,\n endpoint: error.endpoint,\n timestamp: new Date().toISOString(),\n };\n }\n\n const message =\n error instanceof Error ? error.message : \"An unexpected error occurred.\";\n return {\n error: true,\n type: \"InternalError\",\n message,\n timestamp: new Date().toISOString(),\n };\n}\n","// ─── Token-Bucket Rate Limiter ─────────────────────────────────────\n\nimport { RateLimitError } from \"./errors.js\";\n\nexport interface RateLimitConfig {\n /** Unique key for this bucket (e.g. \"public:markets\") */\n key: string;\n /** Maximum burst capacity */\n capacity: number;\n /** Tokens restored per second */\n refillPerSecond: number;\n}\n\ninterface Bucket {\n tokens: number;\n capacity: number;\n refillPerSecond: number;\n lastRefill: number;\n}\n\nexport class RateLimiter {\n private readonly buckets = new Map<string, Bucket>();\n private readonly cleanupMs: number;\n private readonly verbose: boolean;\n private lastCleanup: number;\n\n constructor(cleanupMs = 30_000, verbose = false) {\n this.cleanupMs = cleanupMs;\n this.verbose = verbose;\n this.lastCleanup = Date.now();\n }\n\n async consume(config: RateLimitConfig, amount = 1): Promise<void> {\n this.maybeCleanup();\n const bucket = this.getBucket(config);\n this.refill(bucket);\n\n if (bucket.tokens >= amount) {\n bucket.tokens -= amount;\n return;\n }\n\n // Wait for tokens to refill\n const deficit = amount - bucket.tokens;\n const waitMs = Math.ceil((deficit / bucket.refillPerSecond) * 1_000);\n\n if (waitMs > 10_000) {\n throw new RateLimitError(\n `Rate limit exceeded for \"${config.key}\". Need ${deficit.toFixed(1)} tokens, wait ~${waitMs}ms.`,\n \"Reduce request frequency or wait.\",\n );\n }\n\n if (this.verbose) {\n process.stderr.write(\n `[rate-limiter] ${config.key}: waiting ${waitMs}ms for ${deficit.toFixed(1)} tokens\\n`,\n );\n }\n\n await new Promise((resolve) => setTimeout(resolve, waitMs));\n this.refill(bucket);\n\n if (bucket.tokens >= amount) {\n bucket.tokens -= amount;\n return;\n }\n\n throw new RateLimitError(\n `Rate limit exceeded for \"${config.key}\" after waiting.`,\n \"Reduce request frequency.\",\n );\n }\n\n private getBucket(config: RateLimitConfig): Bucket {\n let bucket = this.buckets.get(config.key);\n if (!bucket) {\n bucket = {\n tokens: config.capacity,\n capacity: config.capacity,\n refillPerSecond: config.refillPerSecond,\n lastRefill: Date.now(),\n };\n this.buckets.set(config.key, bucket);\n }\n return bucket;\n }\n\n private refill(bucket: Bucket): void {\n const now = Date.now();\n const elapsed = (now - bucket.lastRefill) / 1_000;\n if (elapsed <= 0) return;\n bucket.tokens = Math.min(\n bucket.capacity,\n bucket.tokens + elapsed * bucket.refillPerSecond,\n );\n bucket.lastRefill = now;\n }\n\n private maybeCleanup(): void {\n const now = Date.now();\n if (now - this.lastCleanup < this.cleanupMs) return;\n this.lastCleanup = now;\n\n for (const [key, bucket] of this.buckets) {\n const idle = (now - bucket.lastRefill) / 1_000;\n if (idle > 60 && bucket.tokens >= bucket.capacity) {\n this.buckets.delete(key);\n }\n }\n }\n}\n","// ─── Bithumb Constants ─────────────────────────────────────────────\n\nexport const BITHUMB_API_BASE_URL = \"https://api.bithumb.com\";\n\nexport const MODULES = [\"market\", \"account\", \"trade\", \"twap\", \"withdraw\", \"deposit\", \"system\"] as const;\nexport type ModuleId = (typeof MODULES)[number];\nexport const DEFAULT_MODULES: ModuleId[] = [\"market\", \"account\", \"trade\", \"twap\", \"withdraw\", \"deposit\", \"system\"];\n\n// Telemetry: client identifier sent to Bithumb API for usage statistics\nexport const TRADE_KIT_HEADER = \"X-AI-Trade-Kit\";\nexport const CLIENT_TYPES = [\"mcp\", \"cli\", \"etc\"] as const;\nexport type ClientType = (typeof CLIENT_TYPES)[number];\n","// ─── Bithumb REST Client ───────────────────────────────────────────\n\nimport { signRequest } from \"../utils/signature.js\";\nimport {\n AuthenticationError,\n BithumbApiError,\n ConfigError,\n NetworkError,\n RateLimitError,\n} from \"../utils/errors.js\";\nimport { RateLimiter } from \"../utils/rate-limiter.js\";\nimport { TRADE_KIT_HEADER } from \"../constants.js\";\nimport type { BithumbConfig } from \"../config.js\";\nimport type {\n BithumbErrorResponse,\n QueryParams,\n RequestConfig,\n RequestResult,\n} from \"./types.js\";\n\n// ─── Helpers ───────────────────────────────────────────────────────\n\nfunction isDefined(value: unknown): boolean {\n return value !== undefined && value !== null;\n}\n\n/** Build URL-encoded query string for GET params. */\nexport function buildQueryString(query?: QueryParams): string {\n if (!query) return \"\";\n const entries = Object.entries(query).filter(([, v]) => isDefined(v));\n if (entries.length === 0) return \"\";\n\n const parts: string[] = [];\n for (const [key, value] of entries) {\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n const item = value[i];\n if (item && typeof item === \"object\" && !Array.isArray(item)) {\n for (const [subKey, subVal] of Object.entries(item as Record<string, unknown>)) {\n parts.push(\n `${encodeURIComponent(key)}[${i}][${encodeURIComponent(subKey)}]=${encodeURIComponent(String(subVal))}`,\n );\n }\n } else {\n parts.push(\n `${encodeURIComponent(key)}[]=${encodeURIComponent(String(item))}`,\n );\n }\n }\n } else {\n parts.push(\n `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`,\n );\n }\n }\n return parts.join(\"&\");\n}\n\n/** Build unencoded query string for JWT hash computation. */\nexport function buildHashString(\n query?: QueryParams,\n body?: Record<string, unknown>,\n): string {\n const source = body ?? query;\n if (!source) return \"\";\n const entries = Object.entries(source).filter(([, v]) => isDefined(v));\n if (entries.length === 0) return \"\";\n\n const parts: string[] = [];\n for (const [key, value] of entries) {\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n const item = value[i];\n if (item && typeof item === \"object\" && !Array.isArray(item)) {\n for (const [subKey, subVal] of Object.entries(item as Record<string, unknown>)) {\n parts.push(`${key}[${i}][${subKey}]=${String(subVal)}`);\n }\n } else {\n parts.push(`${key}[]=${String(item)}`);\n }\n }\n } else {\n parts.push(`${key}=${String(value)}`);\n }\n }\n return parts.join(\"&\");\n}\n\nfunction vlog(message: string): void {\n process.stderr.write(`[verbose] ${message}\\n`);\n}\n\n// ─── Client ────────────────────────────────────────────────────────\n\nexport class BithumbRestClient {\n private readonly config: BithumbConfig;\n private readonly rateLimiter: RateLimiter;\n\n constructor(config: BithumbConfig) {\n this.config = config;\n this.rateLimiter = new RateLimiter(30_000, config.verbose);\n }\n\n async publicGet<TData = unknown>(\n path: string,\n query?: QueryParams,\n rateLimit?: RequestConfig[\"rateLimit\"],\n ): Promise<RequestResult<TData>> {\n return this.request<TData>({\n method: \"GET\",\n path,\n auth: \"public\",\n query,\n rateLimit,\n });\n }\n\n async privateGet<TData = unknown>(\n path: string,\n query?: QueryParams,\n rateLimit?: RequestConfig[\"rateLimit\"],\n ): Promise<RequestResult<TData>> {\n return this.request<TData>({\n method: \"GET\",\n path,\n auth: \"private\",\n query,\n rateLimit,\n });\n }\n\n async privatePost<TData = unknown>(\n path: string,\n body?: RequestConfig[\"body\"],\n rateLimit?: RequestConfig[\"rateLimit\"],\n ): Promise<RequestResult<TData>> {\n return this.request<TData>({\n method: \"POST\",\n path,\n auth: \"private\",\n body,\n rateLimit,\n });\n }\n\n async privateDelete<TData = unknown>(\n path: string,\n query?: QueryParams,\n rateLimit?: RequestConfig[\"rateLimit\"],\n ): Promise<RequestResult<TData>> {\n return this.request<TData>({\n method: \"DELETE\",\n path,\n auth: \"private\",\n query,\n rateLimit,\n });\n }\n\n // ─── Core request ────────────────────────────────────────────────\n\n private async request<TData = unknown>(\n reqConfig: RequestConfig,\n ): Promise<RequestResult<TData>> {\n const queryString = buildQueryString(reqConfig.query);\n const requestPath =\n queryString.length > 0\n ? `${reqConfig.path}?${queryString}`\n : reqConfig.path;\n const url = `${this.config.baseUrl}${requestPath}`;\n\n if (this.config.verbose) vlog(`→ ${reqConfig.method} ${url}`);\n\n // Rate limiting\n if (reqConfig.rateLimit) await this.rateLimiter.consume(reqConfig.rateLimit);\n\n // Headers\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n [TRADE_KIT_HEADER]: this.config.clientType,\n };\n\n // Auth: JWT Bearer token\n if (reqConfig.auth === \"private\") {\n if (\n !this.config.hasAuth ||\n !this.config.accessKey ||\n !this.config.secretKey\n ) {\n throw new ConfigError(\n \"Private endpoint requires API credentials.\",\n \"Set BITHUMB_ACCESS_KEY and BITHUMB_SECRET_KEY.\",\n );\n }\n const hashStr = buildHashString(reqConfig.query, reqConfig.body);\n const token = signRequest(\n this.config.accessKey,\n this.config.secretKey,\n hashStr,\n );\n headers[\"Authorization\"] = `Bearer ${token}`;\n }\n\n // Fetch\n const t0 = Date.now();\n let response: Response;\n try {\n const fetchOptions: RequestInit = {\n method: reqConfig.method,\n headers,\n signal: AbortSignal.timeout(this.config.timeoutMs),\n };\n if (reqConfig.body && reqConfig.method === \"POST\") {\n fetchOptions.body = JSON.stringify(reqConfig.body);\n }\n response = await fetch(url, fetchOptions);\n } catch (error) {\n if (this.config.verbose) {\n vlog(`✗ NetworkError after ${Date.now() - t0}ms`);\n }\n throw new NetworkError(\n `Failed to call ${reqConfig.method} ${reqConfig.path}.`,\n `${reqConfig.method} ${reqConfig.path}`,\n error,\n );\n }\n\n // Parse response\n const rawText = await response.text();\n const elapsed = Date.now() - t0;\n if (this.config.verbose) {\n vlog(`← ${response.status} | ${rawText.length}B | ${elapsed}ms`);\n }\n\n let parsed: unknown;\n try {\n parsed = rawText ? JSON.parse(rawText) : null;\n } catch {\n throw new NetworkError(\n `Non-JSON response from ${reqConfig.method} ${reqConfig.path}.`,\n `${reqConfig.method} ${reqConfig.path}`,\n );\n }\n\n // Error handling: Bithumb returns { error: { name, message } }\n // - error.name 은 HTTP 코드가 아닌 자유 문자열(invalid_jwt, too_many_requests 등)이라\n // 분기 키로 신뢰할 수 없다. 분기는 HTTP response.status 로만 한다.\n // - 사용자에게는 name + message 를 그대로 결합해 노출. 한쪽이 없으면 있는 쪽만,\n // 둘 다 없으면 최후 fallback 으로 HTTP <status> 사용.\n if (parsed && typeof parsed === \"object\" && \"error\" in parsed) {\n const errResp = parsed as BithumbErrorResponse;\n const errName = errResp.error?.name;\n const errMsg = errResp.error?.message;\n const displayMsg =\n [errName, errMsg].filter(Boolean).join(\": \") ||\n `HTTP ${response.status}`;\n const endpoint = `${reqConfig.method} ${reqConfig.path}`;\n\n if (response.status === 401) {\n throw new AuthenticationError(\n displayMsg,\n \"Check BITHUMB_ACCESS_KEY and BITHUMB_SECRET_KEY.\",\n endpoint,\n );\n }\n if (response.status === 429) {\n throw new RateLimitError(\n displayMsg,\n \"Reduce request frequency.\",\n endpoint,\n );\n }\n throw new BithumbApiError(displayMsg, {\n code: errName ?? String(response.status),\n endpoint,\n });\n }\n\n if (!response.ok) {\n throw new BithumbApiError(`HTTP ${response.status}`, {\n code: String(response.status),\n endpoint: `${reqConfig.method} ${reqConfig.path}`,\n });\n }\n\n return {\n endpoint: `${reqConfig.method} ${reqConfig.path}`,\n requestTime: new Date().toISOString(),\n data: parsed as TData,\n };\n }\n}\n","// ─── Tool Argument Helpers ─────────────────────────────────────────\n\nimport { ValidationError } from \"../utils/errors.js\";\n\nexport type ArgsRecord = Record<string, unknown>;\n\n/** Safely cast args to Record. */\nexport function asRecord(args: unknown): ArgsRecord {\n if (args && typeof args === \"object\" && !Array.isArray(args)) {\n return args as ArgsRecord;\n }\n return {};\n}\n\n// ─── Read helpers (return undefined if missing) ────────────────────\n\nexport function readString(\n args: ArgsRecord,\n key: string,\n): string | undefined {\n const v = args[key];\n if (v === undefined || v === null || v === \"\") return undefined;\n return String(v);\n}\n\nexport function readNumber(\n args: ArgsRecord,\n key: string,\n): number | undefined {\n const v = args[key];\n if (v === undefined || v === null || v === \"\") return undefined;\n const n = Number(v);\n if (!Number.isFinite(n)) return undefined;\n return n;\n}\n\nexport function readBoolean(\n args: ArgsRecord,\n key: string,\n): boolean | undefined {\n const v = args[key];\n if (v === undefined || v === null) return undefined;\n if (typeof v === \"boolean\") return v;\n if (v === \"true\" || v === \"1\") return true;\n if (v === \"false\" || v === \"0\") return false;\n return undefined;\n}\n\nexport function readStringArray(\n args: ArgsRecord,\n key: string,\n): string[] | undefined {\n const v = args[key];\n if (v === undefined || v === null) return undefined;\n if (Array.isArray(v)) return v.map(String);\n if (typeof v === \"string\") {\n return v\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n }\n return undefined;\n}\n\n// ─── Require helpers (throw on missing) ────────────────────────────\n\nexport function requireString(\n args: ArgsRecord,\n key: string,\n): string {\n const v = readString(args, key);\n if (!v) {\n throw new ValidationError(\n `Missing required parameter \"${key}\".`,\n `Provide a non-empty \"${key}\" string.`,\n );\n }\n return v;\n}\n\nexport function assertEnum<T extends string>(\n value: string,\n allowed: readonly T[],\n paramName: string,\n): T {\n if (!allowed.includes(value as T)) {\n throw new ValidationError(\n `Invalid value \"${value}\" for \"${paramName}\".`,\n `Allowed: ${allowed.join(\", \")}.`,\n );\n }\n return value as T;\n}\n\n// ─── Misc utilities ────────────────────────────────────────────────\n\n/** Remove undefined/null entries from an object. */\nexport function compactObject<T extends Record<string, unknown>>(\n obj: T,\n): Partial<T> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n if (value !== undefined && value !== null) {\n result[key] = value;\n }\n }\n return result as Partial<T>;\n}\n\n/** Normalize tool response into a consistent shape. */\nexport function normalizeResponse(data: unknown): unknown {\n if (data === null || data === undefined) return {};\n return data;\n}\n","// ─── Common Rate Limit Presets ─────────────────────────────────────\n\nimport type { RateLimitConfig } from \"../utils/rate-limiter.js\";\n\n/** Public endpoint: 150 requests/sec default. */\nexport function publicRateLimit(key: string, rps = 150): RateLimitConfig {\n return { key: `public:${key}`, capacity: rps, refillPerSecond: rps };\n}\n\n/** Private endpoint: 140 requests/sec default. */\nexport function privateRateLimit(key: string, rps = 140): RateLimitConfig {\n return { key: `private:${key}`, capacity: rps, refillPerSecond: rps };\n}\n\n/** Order endpoint: 10 requests/sec default. */\nexport function orderRateLimit(key: string, rps = 10): RateLimitConfig {\n return { key: `order:${key}`, capacity: rps, refillPerSecond: rps };\n}\n","// ─── Market Tools (Public) ─────────────────────────────────────────\n\nimport type { ToolSpec } from \"./types.js\";\nimport {\n asRecord,\n compactObject,\n normalizeResponse,\n readBoolean,\n readNumber,\n readString,\n requireString,\n} from \"./helpers.js\";\nimport { publicRateLimit } from \"./common.js\";\n\nexport function registerMarketTools(): ToolSpec[] {\n return [\n // ── 1. market_get_markets ──────────────────────────────────────\n {\n name: \"market_get_markets\",\n module: \"market\",\n description:\n \"빗썸 거래 가능한 마켓(거래 페어) 목록을 조회합니다. Get all available trading pairs on Bithumb.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n isDetails: {\n type: \"boolean\",\n description: \"Include detailed market info\",\n },\n },\n required: [],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.publicGet(\n \"/v1/market/all\",\n compactObject({ isDetails: readBoolean(args, \"isDetails\") }),\n publicRateLimit(\"market_get_markets\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 2. market_get_ticker ───────────────────────────────────────\n {\n name: \"market_get_ticker\",\n module: \"market\",\n description:\n \"현재가(Ticker) 정보를 조회합니다. Get current price ticker for specified markets.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n markets: {\n type: \"string\",\n description:\n \"Comma-separated market codes, e.g. KRW-BTC,KRW-ETH\",\n },\n },\n required: [\"markets\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.publicGet(\n \"/v1/ticker\",\n compactObject({ markets: requireString(args, \"markets\") }),\n publicRateLimit(\"market_get_ticker\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 3. market_get_orderbook ────────────────────────────────────\n {\n name: \"market_get_orderbook\",\n module: \"market\",\n description:\n \"호가(Orderbook) 정보를 조회합니다. Get orderbook (bids/asks) for specified markets.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n markets: {\n type: \"string\",\n description:\n \"Comma-separated market codes, e.g. KRW-BTC,KRW-ETH\",\n },\n },\n required: [\"markets\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.publicGet(\n \"/v1/orderbook\",\n compactObject({ markets: requireString(args, \"markets\") }),\n publicRateLimit(\"market_get_orderbook\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 4. market_get_trades ───────────────────────────────────────\n {\n name: \"market_get_trades\",\n module: \"market\",\n description:\n \"최근 체결 내역을 조회합니다. Get recent trades for a market.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n market: {\n type: \"string\",\n description: \"Market code, e.g. KRW-BTC\",\n },\n to: {\n type: \"string\",\n description: \"Return trades before this timestamp (exclusive)\",\n },\n count: {\n type: \"number\",\n description: \"Number of trades to return (1-500)\",\n },\n cursor: {\n type: \"string\",\n description: \"Pagination cursor from previous response\",\n },\n daysAgo: {\n type: \"number\",\n description: \"Filter trades from N days ago (1-7)\",\n },\n },\n required: [\"market\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.publicGet(\n \"/v1/trades/ticks\",\n compactObject({\n market: requireString(args, \"market\"),\n to: readString(args, \"to\"),\n count: readNumber(args, \"count\"),\n cursor: readString(args, \"cursor\"),\n daysAgo: readNumber(args, \"daysAgo\"),\n }),\n publicRateLimit(\"market_get_trades\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 5. market_get_candles_minutes ──────────────────────────────\n {\n name: \"market_get_candles_minutes\",\n module: \"market\",\n description:\n \"분(minute) 캔들을 조회합니다. Get minute candles (OHLCV).\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n unit: {\n type: \"number\",\n enum: [1, 3, 5, 10, 15, 30, 60, 240],\n description: \"Candle unit in minutes\",\n },\n market: {\n type: \"string\",\n description: \"Market code, e.g. KRW-BTC\",\n },\n to: {\n type: \"string\",\n description: \"Return candles before this timestamp\",\n },\n count: {\n type: \"number\",\n description: \"Number of candles to return (max 200)\",\n },\n },\n required: [\"unit\", \"market\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const unit = readNumber(args, \"unit\");\n if (!unit) throw new Error('Missing required parameter \"unit\".');\n const response = await context.client.publicGet(\n `/v1/candles/minutes/${unit}`,\n compactObject({\n market: requireString(args, \"market\"),\n to: readString(args, \"to\"),\n count: readNumber(args, \"count\"),\n }),\n publicRateLimit(\"market_get_candles_minutes\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 6. market_get_candles_days ─────────────────────────────────\n {\n name: \"market_get_candles_days\",\n module: \"market\",\n description:\n \"일(day) 캔들을 조회합니다. Get daily candles.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n market: {\n type: \"string\",\n description: \"Market code, e.g. KRW-BTC\",\n },\n to: {\n type: \"string\",\n description: \"Return candles before this timestamp\",\n },\n count: {\n type: \"number\",\n description: \"Number of candles to return (max 200)\",\n },\n convertingPriceUnit: {\n type: \"string\",\n description: \"Price unit for conversion\",\n },\n },\n required: [\"market\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.publicGet(\n \"/v1/candles/days\",\n compactObject({\n market: requireString(args, \"market\"),\n to: readString(args, \"to\"),\n count: readNumber(args, \"count\"),\n convertingPriceUnit: readString(args, \"convertingPriceUnit\"),\n }),\n publicRateLimit(\"market_get_candles_days\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 7. market_get_candles_weeks ────────────────────────────────\n {\n name: \"market_get_candles_weeks\",\n module: \"market\",\n description:\n \"주(week) 캔들을 조회합니다. Get weekly candles.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n market: {\n type: \"string\",\n description: \"Market code, e.g. KRW-BTC\",\n },\n to: {\n type: \"string\",\n description: \"Return candles before this timestamp\",\n },\n count: {\n type: \"number\",\n description: \"Number of candles to return (max 200)\",\n },\n },\n required: [\"market\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.publicGet(\n \"/v1/candles/weeks\",\n compactObject({\n market: requireString(args, \"market\"),\n to: readString(args, \"to\"),\n count: readNumber(args, \"count\"),\n }),\n publicRateLimit(\"market_get_candles_weeks\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 8. market_get_candles_months ───────────────────────────────\n {\n name: \"market_get_candles_months\",\n module: \"market\",\n description:\n \"월(month) 캔들을 조회합니다. Get monthly candles.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n market: {\n type: \"string\",\n description: \"Market code, e.g. KRW-BTC\",\n },\n to: {\n type: \"string\",\n description: \"Return candles before this timestamp\",\n },\n count: {\n type: \"number\",\n description: \"Number of candles to return (max 200)\",\n },\n },\n required: [\"market\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.publicGet(\n \"/v1/candles/months\",\n compactObject({\n market: requireString(args, \"market\"),\n to: readString(args, \"to\"),\n count: readNumber(args, \"count\"),\n }),\n publicRateLimit(\"market_get_candles_months\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 9. market_get_warnings ─────────────────────────────────────\n {\n name: \"market_get_warnings\",\n module: \"market\",\n description:\n \"투자경보 마켓 목록을 조회합니다. Get virtual asset warning market list.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n },\n handler: async (_rawArgs, context) => {\n const response = await context.client.publicGet(\n \"/v1/market/virtual_asset_warning\",\n {},\n publicRateLimit(\"market_get_warnings\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 10. market_get_notices ─────────────────────────────────────\n {\n name: \"market_get_notices\",\n module: \"market\",\n description:\n \"공지사항 목록을 조회합니다. Get notice list.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n count: {\n type: \"number\",\n description: \"Number of notices to return (min 1, max 20, default 5)\",\n },\n },\n required: [],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const count = readNumber(args, \"count\");\n const response = await context.client.publicGet(\n \"/v1/notices\",\n compactObject({ count }),\n publicRateLimit(\"market_get_notices\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 11. market_get_fee_inout ───────────────────────────────────\n {\n name: \"market_get_fee_inout\",\n module: \"market\",\n description:\n \"입출금 수수료를 조회합니다. Get deposit/withdrawal fee info for a currency.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n currency: {\n type: \"string\",\n description:\n 'Currency symbol (use \"ALL\" to retrieve all currencies), e.g. BTC, ETH',\n },\n },\n required: [\"currency\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const currency = requireString(args, \"currency\");\n const response = await context.client.publicGet(\n `/v2/fee/inout/${currency}`,\n {},\n publicRateLimit(\"market_get_fee_inout\"),\n );\n return normalizeResponse(response);\n },\n },\n ];\n}\n","// ─── Account Tools (Private) ───────────────────────────────────────\n\nimport type { ToolSpec } from \"./types.js\";\nimport {\n asRecord,\n compactObject,\n normalizeResponse,\n requireString,\n} from \"./helpers.js\";\nimport { privateRateLimit } from \"./common.js\";\n\nexport function registerAccountTools(): ToolSpec[] {\n return [\n // ── 1. account_get_balance ─────────────────────────────────────\n {\n name: \"account_get_balance\",\n module: \"account\",\n description:\n \"전체 계좌 잔고를 조회합니다. Get all account balances. \" +\n \"Returns all currencies with balance, locked amounts, and avg buy price. \" +\n \"Run before any trade or withdrawal to verify available funds.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n },\n handler: async (_rawArgs, context) => {\n const response = await context.client.privateGet(\n \"/v1/accounts\",\n undefined,\n privateRateLimit(\"account_get_balance\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 2. account_get_order_chance ────────────────────────────────\n {\n name: \"account_get_order_chance\",\n module: \"account\",\n description:\n \"주문 가능 정보를 조회합니다. Get order chance info (available balance, fees, limits) for a market. \" +\n \"Run before placing any order to confirm available balance, bid/ask fee rates, and min/max order size constraints.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n market: {\n type: \"string\",\n description: \"Market code, e.g. KRW-BTC\",\n },\n },\n required: [\"market\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateGet(\n \"/v1/orders/chance\",\n compactObject({ market: requireString(args, \"market\") }),\n privateRateLimit(\"account_get_order_chance\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 3. account_get_wallet_status ───────────────────────────────\n {\n name: \"account_get_wallet_status\",\n module: \"account\",\n description:\n \"입출금 현황을 조회합니다. Get wallet status (block status, deposit/withdrawal availability). \" +\n \"Run before any deposit or withdrawal to verify the blockchain is synced and operations are not disabled for maintenance.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n },\n handler: async (_rawArgs, context) => {\n const response = await context.client.privateGet(\n \"/v1/status/wallet\",\n {},\n privateRateLimit(\"account_get_wallet_status\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 4. account_get_api_keys ────────────────────────────────────\n {\n name: \"account_get_api_keys\",\n module: \"account\",\n description:\n \"API 키 목록을 조회합니다. Get list of API keys and expiration dates. \" +\n \"Check periodically to avoid unexpected authentication failures due to key expiration.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n },\n handler: async (_rawArgs, context) => {\n const response = await context.client.privateGet(\n \"/v1/api_keys\",\n {},\n privateRateLimit(\"account_get_api_keys\"),\n );\n return normalizeResponse(response);\n },\n },\n ];\n}\n","// ─── Trade Tools (Private) ─────────────────────────────────────────\n\nimport type { ToolSpec } from \"./types.js\";\nimport {\n asRecord,\n compactObject,\n normalizeResponse,\n readNumber,\n readString,\n readStringArray,\n requireString,\n} from \"./helpers.js\";\nimport { orderRateLimit, privateRateLimit } from \"./common.js\";\nimport { ValidationError } from \"../utils/errors.js\";\n\nexport function registerTradeTools(): ToolSpec[] {\n return [\n // ── 1. trade_get_order ─────────────────────────────────────────\n {\n name: \"trade_get_order\",\n module: \"trade\",\n description:\n \"개별(단건) 주문을 조회합니다. Get a SINGLE order by order_id or client_order_id. \" +\n \"Use when: you have exactly one order identifier. \" +\n \"Do NOT use: for multiple orders at once — do NOT call this repeatedly. \" +\n \"Pass all identifiers to trade_get_orders (order_ids/client_order_ids arrays) in a single call instead. \" +\n 'Example call: {\"order_id\":\"C0101...\"}',\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n order_id: {\n type: \"string\",\n description: \"Order ID\",\n },\n client_order_id: {\n type: \"string\",\n description: \"Client-assigned order ID\",\n },\n },\n required: [],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n // Exposed param is `order_id`, but the Bithumb v1 endpoint expects it in\n // the `uuid` field (legacy naming — the v1 \"uuid\" is actually the order_id).\n const response = await context.client.privateGet(\n \"/v1/order\",\n compactObject({\n uuid: readString(args, \"order_id\"),\n client_order_id: readString(args, \"client_order_id\"),\n }),\n privateRateLimit(\"trade_get_order\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 2. trade_get_orders ────────────────────────────────────────\n {\n name: \"trade_get_orders\",\n module: \"trade\",\n description:\n \"주문 리스트/복수 주문을 조회합니다. Get orders — fetch MULTIPLE specific orders in one call via order_ids/client_order_ids (arrays), or list by market/state filters. \" +\n \"Use when: the user gives two or more order numbers, or wants a filtered list. \" +\n \"Do NOT use trade_get_order repeatedly for multiple ids — pass them all here in one call. \" +\n \"Note: the server defaults to state=wait when omitted, so to fetch done/cancel orders (e.g. by order_ids) set states explicitly, e.g. states=[\\\"wait\\\",\\\"done\\\",\\\"cancel\\\"]. \" +\n \"The auto-order state (watch) CANNOT be mixed with general states (wait/done/cancel); query it separately with state=watch. state and states cannot be used together. \" +\n 'Example call: {\"order_ids\":[\"C0101...\",\"C0102...\"],\"states\":[\"wait\",\"done\",\"cancel\"]}',\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n market: {\n type: \"string\",\n description: \"Market code, e.g. KRW-BTC\",\n },\n state: {\n type: \"string\",\n enum: [\"wait\", \"watch\", \"done\", \"cancel\"],\n description: \"Order state filter\",\n },\n states: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n \"Multiple order state filters. Constraints: general states (wait/done/cancel) and the auto-order state (watch) CANNOT be mixed in one query; state and states cannot be used together. If omitted, the server defaults to state=wait — pass states=[\\\"wait\\\",\\\"done\\\",\\\"cancel\\\"] to include done/cancel orders.\",\n },\n order_ids: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Fetch multiple specific orders by order ID in one call (batch lookup). Pass all order IDs here instead of calling trade_get_order repeatedly.\",\n },\n client_order_ids: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Filter by client order IDs\",\n },\n page: {\n type: \"number\",\n description: \"Page number\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results per page\",\n },\n order_by: {\n type: \"string\",\n description: \"Sort order\",\n },\n },\n required: [],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n // Exposed param is `order_ids`, but the Bithumb v1 endpoint expects it in\n // the `uuids` field (legacy naming — the v1 \"uuids\" are actually order_ids).\n const response = await context.client.privateGet(\n \"/v1/orders\",\n compactObject({\n market: readString(args, \"market\"),\n state: readString(args, \"state\"),\n states: readStringArray(args, \"states\"),\n uuids: readStringArray(args, \"order_ids\"),\n client_order_ids: readStringArray(args, \"client_order_ids\"),\n page: readNumber(args, \"page\"),\n limit: readNumber(args, \"limit\"),\n order_by: readString(args, \"order_by\"),\n }),\n privateRateLimit(\"trade_get_orders\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 3. trade_place_order ───────────────────────────────────────\n {\n name: \"trade_place_order\",\n module: \"trade\",\n description:\n \"주문을 생성합니다. Place a new spot order on Bithumb. \" +\n \"Use when: user asks to buy/sell a single market at a specific price or quantity. \" +\n \"Do NOT use: for multiple orders at once (use trade_batch_place); for time-weighted execution (use twap_place). \" +\n \"Field: order_type ∈ {limit, price, market}. limit: price+volume required. price(시장가 매수): only price (total KRW). market(시장가 매도): only volume (coin qty). \" +\n \"Note: Bithumb API response field is `ord_type` (not `order_type`). \" +\n \"⚠️ REQUIRES EXPLICIT USER CONFIRMATION before executing: show the user market, side, order_type, price, volume, and total notional, then wait for explicit approval. Do NOT place the order without user confirmation. \" +\n 'Example call: {\"market\":\"KRW-BTC\",\"side\":\"bid\",\"order_type\":\"limit\",\"price\":\"50000000\",\"volume\":\"0.0001\"}',\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n market: {\n type: \"string\",\n description: \"Market code, e.g. KRW-BTC\",\n },\n side: {\n type: \"string\",\n enum: [\"bid\", \"ask\"],\n description: \"Order side: bid (buy) or ask (sell)\",\n },\n order_type: {\n type: \"string\",\n enum: [\"limit\", \"price\", \"market\"],\n description:\n \"Order type: limit, price (market buy), market (market sell). \" +\n \"Note: Bithumb API response field is `ord_type` (not `order_type`).\",\n },\n price: {\n type: \"string\",\n description: \"Order price (required for limit and price orders)\",\n },\n volume: {\n type: \"string\",\n description:\n \"Order volume (required for limit and market orders)\",\n },\n client_order_id: {\n type: \"string\",\n description: \"Client-assigned order ID for idempotency\",\n },\n },\n required: [\"market\", \"side\", \"order_type\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/v2/orders\",\n compactObject({\n market: requireString(args, \"market\"),\n side: requireString(args, \"side\"),\n order_type: requireString(args, \"order_type\"),\n price: readString(args, \"price\"),\n volume: readString(args, \"volume\"),\n client_order_id: readString(args, \"client_order_id\"),\n }),\n orderRateLimit(\"trade_place_order\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 4. trade_cancel_order ──────────────────────────────────────\n {\n name: \"trade_cancel_order\",\n module: \"trade\",\n description:\n \"주문을 취소합니다. Cancel an order by order_id or client_order_id. \" +\n \"⚠️ REQUIRES EXPLICIT USER CONFIRMATION before executing: show the user the order details (order_id or client_order_id) and wait for explicit approval. Do NOT cancel without user confirmation.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n order_id: {\n type: \"string\",\n description: \"Order ID to cancel\",\n },\n client_order_id: {\n type: \"string\",\n description: \"Client-assigned order ID to cancel\",\n },\n },\n required: [],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateDelete(\n \"/v2/order\",\n compactObject({\n order_id: readString(args, \"order_id\"),\n client_order_id: readString(args, \"client_order_id\"),\n }),\n orderRateLimit(\"trade_cancel_order\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 5. trade_batch_place ───────────────────────────────────────\n {\n name: \"trade_batch_place\",\n module: \"trade\",\n description:\n \"다건 주문을 요청합니다. Place multiple orders in a single batch (max 20). \" +\n \"Use when: user asks for multiple orders at once (e.g., grid orders, simultaneous BTC+ETH limit buys). \" +\n \"Do NOT use: for a single order (use trade_place_order); for time-sliced execution (use twap_place). \" +\n \"Each order item field: `order_type` (canonical) ∈ {limit, price, market}. \" +\n \"Partial-failure semantics: each item may succeed or fail independently. Do NOT auto-retry failed items; surface them to the user. \" +\n \"⚠️ REQUIRES EXPLICIT USER CONFIRMATION before executing: read all orders back to the user (market, side, order_type, price, volume for each) and wait for explicit approval. Do NOT place any order without user confirmation. \" +\n 'Example call: {\"batch_orders\":[{\"market\":\"KRW-BTC\",\"side\":\"bid\",\"order_type\":\"limit\",\"price\":\"50000000\",\"volume\":\"0.0001\"},{\"market\":\"KRW-ETH\",\"side\":\"bid\",\"order_type\":\"limit\",\"price\":\"4500000\",\"volume\":\"0.001\"}]}',\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n batch_orders: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n market: { type: \"string\", description: \"Market code, e.g. KRW-BTC\" },\n side: { type: \"string\", enum: [\"bid\", \"ask\"], description: \"Order side\" },\n order_type: { type: \"string\", enum: [\"limit\", \"price\", \"market\"], description: \"Order type\" },\n price: { type: \"string\", description: \"Order price\" },\n volume: { type: \"string\", description: \"Order volume\" },\n client_order_id: { type: \"string\", description: \"Client-assigned order ID\" },\n },\n required: [\"market\", \"side\", \"order_type\"],\n },\n description: \"Array of order objects (max 20)\",\n },\n },\n required: [\"batch_orders\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const batchOrders = args.batch_orders;\n if (!Array.isArray(batchOrders) || batchOrders.length === 0) {\n throw new ValidationError(\n \"Missing required parameter \\\"batch_orders\\\".\",\n \"Provide an array of order objects.\",\n );\n }\n const response = await context.client.privatePost(\n \"/v2/orders/batch\",\n { batch_orders: batchOrders },\n orderRateLimit(\"trade_batch_place\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 6. trade_batch_cancel ──────────────────────────────────────\n {\n name: \"trade_batch_cancel\",\n module: \"trade\",\n description:\n \"다건 주문을 취소합니다. Cancel multiple orders (max 30). Provide order_ids or client_order_ids. \" +\n \"⚠️ REQUIRES EXPLICIT USER CONFIRMATION before executing: show the user all order IDs to be cancelled and wait for explicit approval. Do NOT cancel without user confirmation.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n order_ids: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"List of order IDs to cancel (max 30)\",\n },\n client_order_ids: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"List of client-assigned order IDs to cancel (max 30)\",\n },\n },\n required: [],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/v2/orders/cancel\",\n compactObject({\n order_ids: readStringArray(args, \"order_ids\"),\n client_order_ids: readStringArray(args, \"client_order_ids\"),\n }),\n orderRateLimit(\"trade_batch_cancel\"),\n );\n return normalizeResponse(response);\n },\n },\n ];\n}\n","// ─── Audit / Log History Tools ─────────────────────────────────────\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport type { ToolSpec } from \"./types.js\";\nimport { asRecord, readNumber, readString } from \"./helpers.js\";\nimport type { LogEntry } from \"../utils/logger.js\";\n\nconst DEFAULT_LOG_DIR = path.join(os.homedir(), \".bithumb\", \"logs\");\n\n/** Generate file paths for the last N days (default 7). */\nfunction getLogPaths(logDir: string, days = 7): string[] {\n const paths: string[] = [];\n const now = new Date();\n for (let i = 0; i < days; i++) {\n const d = new Date(now);\n d.setDate(d.getDate() - i);\n const yyyy = d.getFullYear();\n const mm = String(d.getMonth() + 1).padStart(2, \"0\");\n const dd = String(d.getDate()).padStart(2, \"0\");\n paths.push(path.join(logDir, `trade-${yyyy}-${mm}-${dd}.log`));\n }\n return paths;\n}\n\n/** Read and parse all log entries from files in the log directory. */\nfunction readEntries(logDir: string): LogEntry[] {\n const filePaths = getLogPaths(logDir);\n const entries: LogEntry[] = [];\n\n for (const filePath of filePaths) {\n if (!fs.existsSync(filePath)) continue;\n let content: string;\n try {\n content = fs.readFileSync(filePath, \"utf8\");\n } catch {\n continue;\n }\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const entry = JSON.parse(trimmed) as LogEntry;\n entries.push(entry);\n } catch {\n // skip malformed lines\n }\n }\n }\n\n return entries;\n}\n\n/** Extract tool name from a LogEntry. */\nfunction extractTool(entry: LogEntry): string | undefined {\n if (entry.tool) return entry.tool;\n if (typeof entry.message === \"string\" && entry.message.startsWith(\"tool:\")) {\n return entry.message.slice(\"tool:\".length);\n }\n return undefined;\n}\n\nexport function registerAuditTools(logDir?: string): ToolSpec[] {\n const resolvedLogDir = logDir ?? DEFAULT_LOG_DIR;\n return [\n // ── system_get_audit_log ───────────────────────────────────────\n {\n name: \"system_get_audit_log\",\n module: \"system\",\n description:\n \"로컬 로그에서 거래 이력을 조회합니다. Read local audit logs filtered by tool, level, and time.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n limit: {\n type: \"number\",\n description: \"Maximum number of entries to return (default 20).\",\n },\n tool: {\n type: \"string\",\n description: \"Filter by tool name.\",\n },\n level: {\n type: \"string\",\n enum: [\"INFO\", \"WARN\", \"ERROR\", \"DEBUG\"],\n description: \"Filter by log level (case-insensitive).\",\n },\n since: {\n type: \"string\",\n description: \"ISO 8601 timestamp; return entries at or after this time.\",\n },\n },\n required: [],\n },\n handler: async (rawArgs, _context) => {\n const args = asRecord(rawArgs);\n const limit = readNumber(args, \"limit\") ?? 20;\n const toolFilter = readString(args, \"tool\");\n const levelFilter = readString(args, \"level\")?.toLowerCase();\n const sinceStr = readString(args, \"since\");\n const sinceMs = sinceStr ? new Date(sinceStr).getTime() : undefined;\n\n const entries = readEntries(resolvedLogDir);\n\n const filtered = entries.filter((entry) => {\n if (toolFilter) {\n const t = extractTool(entry);\n if (!t || !t.includes(toolFilter)) return false;\n }\n if (levelFilter && entry.level !== levelFilter) return false;\n if (sinceMs !== undefined) {\n const entryMs = new Date(entry.ts).getTime();\n if (Number.isNaN(entryMs) || entryMs < sinceMs) return false;\n }\n return true;\n });\n\n // Sort descending by ts\n filtered.sort((a, b) => {\n const ta = new Date(a.ts).getTime();\n const tb = new Date(b.ts).getTime();\n return tb - ta;\n });\n\n return {\n endpoint: \"local:audit-log\",\n requestTime: new Date().toISOString(),\n data: filtered.slice(0, limit),\n };\n },\n },\n ];\n}\n","import type { ToolSpec } from \"./types.js\";\nimport { BITHUMB_API_BASE_URL, MODULES } from \"../constants.js\";\n\ninterface DiagCheck {\n name: string;\n status: \"pass\" | \"fail\";\n message: string;\n}\n\nasync function checkApiReachability(baseUrl: string): Promise<DiagCheck> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5000);\n const res = await fetch(`${baseUrl}/v1/market/all`, {\n signal: controller.signal,\n });\n clearTimeout(timeout);\n return {\n name: \"API Reachability\",\n status: res.ok ? \"pass\" : \"fail\",\n message: res.ok\n ? `${baseUrl} reachable (HTTP ${res.status})`\n : `${baseUrl} returned HTTP ${res.status}`,\n };\n } catch (err) {\n return {\n name: \"API Reachability\",\n status: \"fail\",\n message: `Cannot reach ${baseUrl}: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n}\n\nfunction checkAuthentication(hasAuth: boolean): DiagCheck {\n if (hasAuth) {\n return { name: \"Authentication\", status: \"pass\", message: \"API keys configured (--access-key/--secret-key flags or BITHUMB_ACCESS_KEY/BITHUMB_SECRET_KEY env vars)\" };\n }\n return { name: \"Authentication\", status: \"fail\", message: \"No credentials found. Set --access-key/--secret-key flags or BITHUMB_ACCESS_KEY/BITHUMB_SECRET_KEY env vars.\" };\n}\n\nfunction checkModules(enabledModules: string[]): DiagCheck {\n return {\n name: \"Enabled Modules\",\n status: \"pass\",\n message: `Active: ${enabledModules.join(\", \")}`,\n };\n}\n\nexport function registerDiagnoseTools(): ToolSpec[] {\n return [\n {\n name: \"system_get_capabilities\",\n module: \"system\",\n description:\n \"Return server capabilities and module availability for agent planning.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {},\n additionalProperties: false,\n },\n handler: async (_args, context) => {\n const enabledModules = new Set(context.config.modules);\n const moduleAvailability: Record<string, { status: string; reasonCode?: string }> = {};\n for (const mod of MODULES) {\n if (!enabledModules.has(mod)) {\n moduleAvailability[mod] = { status: \"disabled\", reasonCode: \"MODULE_FILTERED\" };\n } else if (mod !== \"market\" && mod !== \"system\" && !context.config.hasAuth) {\n moduleAvailability[mod] = { status: \"requires_auth\", reasonCode: \"AUTH_MISSING\" };\n } else {\n moduleAvailability[mod] = { status: \"enabled\" };\n }\n }\n return {\n endpoint: \"local:capabilities\",\n requestTime: new Date().toISOString(),\n data: {\n readOnly: context.config.readOnly,\n hasAuth: context.config.hasAuth,\n moduleAvailability,\n },\n };\n },\n },\n {\n name: \"system_diagnose\",\n module: \"system\",\n description:\n \"Run diagnostic checks on the Bithumb Trade Kit configuration. \" +\n \"Checks API reachability, authentication, and module status.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {},\n },\n handler: async (_args, context) => {\n const baseUrl = context?.config?.baseUrl ?? BITHUMB_API_BASE_URL;\n const modules = context?.config?.modules ?? [];\n const hasAuth = context?.config?.hasAuth ?? false;\n\n const checks: DiagCheck[] = [];\n checks.push(await checkApiReachability(baseUrl));\n checks.push(checkAuthentication(hasAuth));\n checks.push(checkModules(modules as string[]));\n\n const passed = checks.filter((c) => c.status === \"pass\").length;\n const total = checks.length;\n\n return {\n endpoint: \"local:diagnose\",\n requestTime: new Date().toISOString(),\n data: {\n summary: `${passed}/${total} checks passed`,\n checks,\n },\n };\n },\n },\n ];\n}\n","// ─── TWAP Tools (Private) ─────────────────────────────────────────\n\nimport type { ToolSpec } from \"./types.js\";\nimport {\n asRecord,\n compactObject,\n normalizeResponse,\n readNumber,\n readString,\n readStringArray,\n requireString,\n} from \"./helpers.js\";\nimport { orderRateLimit, privateRateLimit } from \"./common.js\";\n\nexport function registerTwapTools(): ToolSpec[] {\n return [\n // ── 6. twap_place_order ────────────────────────────────────────\n {\n name: \"twap_place_order\",\n module: \"twap\",\n description:\n \"TWAP 주문을 요청합니다. Place a TWAP (Time-Weighted Average Price) order. \" +\n \"⚠️ REQUIRES EXPLICIT USER CONFIRMATION before executing: show the user market, side, price/volume, duration, frequency, and computed slice count (duration ÷ frequency), then wait for explicit approval. Do NOT place the order without user confirmation.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n market: {\n type: \"string\",\n description: \"거래 대상 페어의 고유 심볼 (예시: KRW-BTC)\",\n },\n side: {\n type: \"string\",\n enum: [\"bid\", \"ask\"],\n description: \"주문 종류: bid (매수), ask (매도)\",\n },\n duration: {\n type: \"string\",\n description:\n \"주문 시간 - TWAP 주문이 진행되는 시간(초). min 300, max 43200\",\n },\n frequency: {\n type: \"string\",\n enum: [\"15\", \"20\", \"30\", \"60\", \"120\"],\n description: \"주문 간격(초)\",\n },\n volume: {\n type: \"string\",\n description: \"주문 수량 (매도 시 필수)\",\n },\n price: {\n type: \"string\",\n description: \"주문 가격 (매수 시 필수)\",\n },\n },\n required: [\"market\", \"side\", \"duration\", \"frequency\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/v1/twap\",\n compactObject({\n market: requireString(args, \"market\"),\n side: requireString(args, \"side\"),\n duration: requireString(args, \"duration\"),\n frequency: requireString(args, \"frequency\"),\n volume: readString(args, \"volume\"),\n price: readString(args, \"price\"),\n }),\n orderRateLimit(\"twap_place_order\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 7. twap_get_orders ─────────────────────────────────────────\n {\n name: \"twap_get_orders\",\n module: \"twap\",\n description:\n \"TWAP 주문 내역을 조회합니다. Get TWAP order history. \" +\n \"Use after twap_place_order to verify the order is active (state: progress). \" +\n \"Default state filter is 'progress'; pass state: 'done' or 'cancel' to query completed or cancelled orders.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n market: {\n type: \"string\",\n description: \"거래 대상 페어의 고유 심볼 (예시: KRW-BTC)\",\n },\n order_ids: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"TWAP 주문 ID 목록\",\n },\n state: {\n type: \"string\",\n enum: [\"progress\", \"done\", \"cancel\"],\n description:\n \"주문 상태: progress (진행중, default), done (완료), cancel (취소)\",\n },\n next_key: {\n type: \"string\",\n description: \"다음 페이지 조회를 위한 커서 값\",\n },\n limit: {\n type: \"number\",\n description: \"개수 제한 (max 100)\",\n },\n order_by: {\n type: \"string\",\n enum: [\"asc\", \"desc\"],\n description: \"조회 결과 정렬 방식: asc (오름차순), desc (내림차순, default)\",\n },\n },\n required: [],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n // Exposed param is `order_ids`, but the Bithumb GET /v1/twap endpoint\n // expects it in the `uuids` field (legacy naming — the \"uuids\" are\n // actually order_ids; same value the cancel endpoint calls algo_order_id).\n const response = await context.client.privateGet(\n \"/v1/twap\",\n compactObject({\n market: readString(args, \"market\"),\n uuids: readStringArray(args, \"order_ids\"),\n state: readString(args, \"state\"),\n next_key: readString(args, \"next_key\"),\n limit: readNumber(args, \"limit\"),\n order_by: readString(args, \"order_by\"),\n }),\n privateRateLimit(\"twap_get_orders\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 8. twap_cancel_order ───────────────────────────────────────\n {\n name: \"twap_cancel_order\",\n module: \"twap\",\n description:\n \"TWAP 주문을 취소합니다. Cancel a TWAP order. \" +\n \"⚠️ REQUIRES EXPLICIT USER CONFIRMATION before executing: show the user the TWAP order ID and wait for explicit approval. Do NOT cancel without user confirmation.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n algo_order_id: {\n type: \"string\",\n description: \"취소할 TWAP 주문 ID\",\n },\n },\n required: [\"algo_order_id\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const algo_order_id = requireString(args, \"algo_order_id\");\n const response = await context.client.privateDelete(\n \"/v1/twap\",\n { algo_order_id },\n orderRateLimit(\"twap_cancel_order\"),\n );\n return normalizeResponse(response);\n },\n },\n ];\n}\n","// ─── Withdraw Tools (Private) ─────────────────────────────────────\n\nimport type { ToolSpec } from \"./types.js\";\nimport {\n asRecord,\n compactObject,\n normalizeResponse,\n readNumber,\n readString,\n readStringArray,\n requireString,\n} from \"./helpers.js\";\nimport { orderRateLimit, privateRateLimit } from \"./common.js\";\n\nexport function registerWithdrawTools(): ToolSpec[] {\n return [\n // ── 9. withdraw_get_chance ───────────────────────────────────────\n {\n name: \"withdraw_get_chance\",\n module: \"withdraw\",\n description:\n \"출금 가능 정보를 조회합니다. Get withdrawal chance info (available balance, fees, limits). \" +\n \"Always call this before withdraw_coin to confirm supported net_type values, withdrawal fee, minimum amount, and daily limits. \" +\n \"For multi-network coins (USDT, USDC, XRP, etc.), this is the only way to discover valid net_type values — never guess.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n currency: {\n type: \"string\",\n description: \"Currency symbol, e.g. BTC\",\n },\n net_type: {\n type: \"string\",\n description: \"Withdrawal network, e.g. BTC, DASH\",\n },\n },\n required: [\"currency\", \"net_type\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateGet(\n \"/v1/withdraws/chance\",\n {\n currency: requireString(args, \"currency\"),\n net_type: requireString(args, \"net_type\"),\n },\n privateRateLimit(\"withdraw_get_chance\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 10. withdraw_get ─────────────────────────────────────────────\n {\n name: \"withdraw_get\",\n module: \"withdraw\",\n description:\n \"개별 출금을 조회합니다. Get a specific withdrawal by currency. \" +\n \"Use when: you have a specific withdrawal UUID or txid. \" +\n \"Do NOT use: to search withdrawal history or filter by state — use withdraw_get_list instead.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n currency: {\n type: \"string\",\n description: \"Currency symbol, e.g. BTC\",\n },\n withdrawal_id: {\n type: \"string\",\n description: \"Withdrawal unique ID\",\n },\n txid: {\n type: \"string\",\n description: \"Withdrawal transaction ID\",\n },\n },\n required: [\"currency\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n // Exposed param is `withdrawal_id`, but the Bithumb GET /v1/withdraw\n // endpoint expects it in the `uuid` field (legacy naming — the \"uuid\"\n // is actually the withdrawal_id, matching the cancel endpoint's name).\n const response = await context.client.privateGet(\n \"/v1/withdraw\",\n compactObject({\n currency: requireString(args, \"currency\"),\n uuid: readString(args, \"withdrawal_id\"),\n txid: readString(args, \"txid\"),\n }),\n privateRateLimit(\"withdraw_get\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 11. withdraw_get_list ────────────────────────────────────────\n {\n name: \"withdraw_get_list\",\n module: \"withdraw\",\n description:\n \"출금 리스트를 조회합니다. Get list of coin withdrawals.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n currency: {\n type: \"string\",\n description: \"Currency symbol, e.g. BTC\",\n },\n state: {\n type: \"string\",\n enum: [\"PROCESSING\", \"DONE\", \"CANCELED\"],\n description: \"Withdrawal state filter\",\n },\n withdrawal_ids: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Filter by withdrawal IDs\",\n },\n txids: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Filter by transaction IDs\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results per page (max 100)\",\n },\n page: {\n type: \"number\",\n description: \"Page number\",\n },\n order_by: {\n type: \"string\",\n enum: [\"asc\", \"desc\"],\n description: \"Sort order (default: desc)\",\n },\n },\n required: [],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n // Exposed param is `withdrawal_ids`, mapped to the API's legacy `uuids`.\n const response = await context.client.privateGet(\n \"/v1/withdraws\",\n compactObject({\n currency: readString(args, \"currency\"),\n state: readString(args, \"state\"),\n uuids: readStringArray(args, \"withdrawal_ids\"),\n txids: readStringArray(args, \"txids\"),\n limit: readNumber(args, \"limit\"),\n page: readNumber(args, \"page\"),\n order_by: readString(args, \"order_by\"),\n }),\n privateRateLimit(\"withdraw_get_list\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 12. withdraw_get_list_krw ────────────────────────────────────\n {\n name: \"withdraw_get_list_krw\",\n module: \"withdraw\",\n description:\n \"원화 출금 리스트를 조회합니다. Get list of KRW withdrawals.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n state: {\n type: \"string\",\n enum: [\"PROCESSING\", \"DONE\", \"CANCELED\"],\n description: \"Withdrawal state filter\",\n },\n withdrawal_ids: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Filter by withdrawal IDs\",\n },\n txids: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Filter by transaction IDs\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results per page (max 100)\",\n },\n page: {\n type: \"number\",\n description: \"Page number\",\n },\n order_by: {\n type: \"string\",\n enum: [\"asc\", \"desc\"],\n description: \"Sort order (default: desc)\",\n },\n },\n required: [],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n // Exposed param is `withdrawal_ids`, mapped to the API's legacy `uuids`.\n const response = await context.client.privateGet(\n \"/v1/withdraws/krw\",\n compactObject({\n state: readString(args, \"state\"),\n uuids: readStringArray(args, \"withdrawal_ids\"),\n txids: readStringArray(args, \"txids\"),\n limit: readNumber(args, \"limit\"),\n page: readNumber(args, \"page\"),\n order_by: readString(args, \"order_by\"),\n }),\n privateRateLimit(\"withdraw_get_list_krw\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 13. withdraw_coin ────────────────────────────────────────────\n {\n name: \"withdraw_coin\",\n module: \"withdraw\",\n description:\n \"실제 가상 자산을 출금합니다. 이 작업은 되돌릴 수 없습니다. Withdraw cryptocurrency. This action is IRREVERSIBLE. \" +\n \"Use when: user has explicitly approved a withdrawal AND the full pre-flight checklist has run (account_get_balance, account_get_wallet_status, withdraw_get_chance, withdraw_get_addresses, market_get_fee_inout). \" +\n \"Do NOT use: without prior `withdraw_get_chance` to confirm net_type/min/fee; without `withdraw_get_addresses` to confirm destination is in the allow-list; without explicit user confirmation of the full destination string. \" +\n \"Multi-network coins (USDT/USDC/XRP): always run `withdraw_get_chance` first to discover supported `net_type`. Wrong net_type = permanent loss. \" +\n \"secondary_address (memo/tag): mandatory for XRP/EOS/ATOM-class coins. Missing it = lost funds.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n currency: {\n type: \"string\",\n description: \"Currency symbol, e.g. BTC\",\n },\n net_type: {\n type: \"string\",\n description: \"Withdrawal network, e.g. BTC, DASH\",\n },\n amount: {\n type: \"string\",\n description: \"Withdrawal amount\",\n },\n address: {\n type: \"string\",\n description: \"Registered withdrawal address\",\n },\n secondary_address: {\n type: \"string\",\n description: \"Secondary address (for certain assets)\",\n },\n exchange_name: {\n type: \"string\",\n description: \"Exchange name (English)\",\n },\n receiver_type: {\n type: \"string\",\n enum: [\"personal\", \"corporation\"],\n description: \"Receiver type: personal or corporation\",\n },\n receiver_ko_name: {\n type: \"string\",\n description: \"Receiver Korean name\",\n },\n receiver_en_name: {\n type: \"string\",\n description: \"Receiver English name\",\n },\n receiver_corp_ko_name: {\n type: \"string\",\n description: \"Corporation Korean name (required if corporation)\",\n },\n receiver_corp_en_name: {\n type: \"string\",\n description: \"Corporation English name (required if corporation)\",\n },\n },\n required: [\"currency\", \"net_type\", \"amount\", \"address\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/v1/withdraws/coin\",\n compactObject({\n currency: requireString(args, \"currency\"),\n net_type: requireString(args, \"net_type\"),\n amount: requireString(args, \"amount\"),\n address: requireString(args, \"address\"),\n secondary_address: readString(args, \"secondary_address\"),\n exchange_name: readString(args, \"exchange_name\"),\n receiver_type: readString(args, \"receiver_type\"),\n receiver_ko_name: readString(args, \"receiver_ko_name\"),\n receiver_en_name: readString(args, \"receiver_en_name\"),\n receiver_corp_ko_name: readString(args, \"receiver_corp_ko_name\"),\n receiver_corp_en_name: readString(args, \"receiver_corp_en_name\"),\n }),\n orderRateLimit(\"withdraw_coin\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 14. withdraw_krw ─────────────────────────────────────────────\n {\n name: \"withdraw_krw\",\n module: \"withdraw\",\n description:\n \"등록된 계좌로 원화를 출금합니다. 이 작업은 되돌릴 수 없습니다. 2차 인증(카카오)이 필요합니다. Withdraw KRW to registered bank account. This action is IRREVERSIBLE. Requires 2FA (Kakao). \" +\n \"⚠️ REQUIRES EXPLICIT USER CONFIRMATION before executing: show the user the withdrawal amount and wait for explicit approval. Do NOT withdraw without user confirmation.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n amount: {\n type: \"string\",\n description: \"Withdrawal amount in KRW\",\n },\n two_factor_type: {\n type: \"string\",\n description: \"2FA method (e.g. kakao)\",\n },\n },\n required: [\"amount\", \"two_factor_type\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/v1/withdraws/krw\",\n {\n amount: requireString(args, \"amount\"),\n two_factor_type: requireString(args, \"two_factor_type\"),\n },\n orderRateLimit(\"withdraw_krw\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 15. withdraw_cancel_coin ─────────────────────────────────────\n {\n name: \"withdraw_cancel_coin\",\n module: \"withdraw\",\n description:\n \"가상 자산 출금을 취소합니다. Cancel a cryptocurrency withdrawal. \" +\n \"⚠️ REQUIRES EXPLICIT USER CONFIRMATION before executing: show the user the withdrawal ID and wait for explicit approval. Do NOT cancel without user confirmation.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n withdrawal_id: {\n type: \"string\",\n description: \"Withdrawal unique ID to cancel\",\n },\n },\n required: [\"withdrawal_id\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateDelete(\n \"/v1/withdraws/coin\",\n {\n withdrawal_id: requireString(args, \"withdrawal_id\"),\n },\n orderRateLimit(\"withdraw_cancel_coin\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 16. withdraw_get_addresses ───────────────────────────────────\n {\n name: \"withdraw_get_addresses\",\n module: \"withdraw\",\n description:\n \"출금 허용 주소 리스트를 조회합니다. Get list of allowed withdrawal addresses.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n },\n handler: async (_rawArgs, context) => {\n const response = await context.client.privateGet(\n \"/v1/withdraws/coin_addresses\",\n {},\n privateRateLimit(\"withdraw_get_addresses\"),\n );\n return normalizeResponse(response);\n },\n },\n ];\n}\n","// ─── Deposit Tools (Private) ──────────────────────────────────────\n\nimport type { ToolSpec } from \"./types.js\";\nimport {\n asRecord,\n compactObject,\n normalizeResponse,\n readNumber,\n readString,\n readStringArray,\n requireString,\n} from \"./helpers.js\";\nimport { privateRateLimit } from \"./common.js\";\n\nexport function registerDepositTools(): ToolSpec[] {\n return [\n // ── 17. deposit_get ───────────────────────────────────────────\n {\n name: \"deposit_get\",\n module: \"deposit\",\n description:\n \"개별 입금을 조회합니다. Get a single deposit by currency + deposit_id (or single txid). \" +\n \"Use when: you have a specific deposit_id and want the full record. \" +\n \"Do NOT use: to search by txid list — use deposit_get_list with txids (array) instead. \" +\n 'Example call: {\"currency\":\"BTC\",\"deposit_id\":\"12345678-....\"}',\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n currency: {\n type: \"string\",\n description: \"Currency symbol, e.g. BTC\",\n },\n deposit_id: {\n type: \"string\",\n description: \"Deposit ID\",\n },\n txid: {\n type: \"string\",\n description: \"Deposit TXID\",\n },\n },\n required: [\"currency\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n // Exposed param is `deposit_id`, but the Bithumb GET /v1/deposit endpoint\n // expects it in the `uuid` field (legacy naming — the \"uuid\" is actually\n // the deposit_id).\n const response = await context.client.privateGet(\n \"/v1/deposit\",\n compactObject({\n currency: requireString(args, \"currency\"),\n uuid: readString(args, \"deposit_id\"),\n txid: readString(args, \"txid\"),\n }),\n privateRateLimit(\"deposit_get\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 18. deposit_get_list ──────────────────────────────────────\n {\n name: \"deposit_get_list\",\n module: \"deposit\",\n description:\n \"입금 리스트를 조회합니다. Get list of coin deposits with optional filters. \" +\n \"Use when: user asks 'find this txid' / 'recent deposits' / 'list deposits in PROCESSING state'. \" +\n \"Do NOT use: when you already have a deposit UUID and want a single record (use `deposit_get`). \" +\n 'Example call (txid lookup): {\"txids\":[\"0xabc123...\"]}',\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n currency: {\n type: \"string\",\n description: \"Currency symbol, e.g. BTC\",\n },\n state: {\n type: \"string\",\n description: \"Deposit state filter\",\n },\n deposit_ids: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Filter by deposit IDs\",\n },\n txids: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Filter by deposit TXIDs\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results (max 100)\",\n },\n page: {\n type: \"number\",\n description: \"Page number (default 1)\",\n },\n order_by: {\n type: \"string\",\n description: \"Sort order: asc or desc (default desc)\",\n },\n },\n required: [],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n // Exposed param is `deposit_ids`, mapped to the API's legacy `uuids`.\n const response = await context.client.privateGet(\n \"/v1/deposits\",\n compactObject({\n currency: readString(args, \"currency\"),\n state: readString(args, \"state\"),\n uuids: readStringArray(args, \"deposit_ids\"),\n txids: readStringArray(args, \"txids\"),\n limit: readNumber(args, \"limit\"),\n page: readNumber(args, \"page\"),\n order_by: readString(args, \"order_by\"),\n }),\n privateRateLimit(\"deposit_get_list\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 19. deposit_get_list_krw ──────────────────────────────────\n {\n name: \"deposit_get_list_krw\",\n module: \"deposit\",\n description:\n \"원화 입금 리스트를 조회합니다. Get list of KRW deposits.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n state: {\n type: \"string\",\n description: \"Deposit state: PROCESSING, ACCEPTED, CANCELED\",\n },\n deposit_ids: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Filter by deposit IDs\",\n },\n txids: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Filter by deposit TXIDs\",\n },\n limit: {\n type: \"number\",\n description: \"Number of results (max 100)\",\n },\n page: {\n type: \"number\",\n description: \"Page number (default 1)\",\n },\n order_by: {\n type: \"string\",\n description: \"Sort order: asc or desc (default desc)\",\n },\n },\n required: [],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n // Exposed param is `deposit_ids`, mapped to the API's legacy `uuids`.\n const response = await context.client.privateGet(\n \"/v1/deposits/krw\",\n compactObject({\n state: readString(args, \"state\"),\n uuids: readStringArray(args, \"deposit_ids\"),\n txids: readStringArray(args, \"txids\"),\n limit: readNumber(args, \"limit\"),\n page: readNumber(args, \"page\"),\n order_by: readString(args, \"order_by\"),\n }),\n privateRateLimit(\"deposit_get_list_krw\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 20. deposit_krw ──────────────────────────────────────────\n {\n name: \"deposit_krw\",\n module: \"deposit\",\n description:\n \"원화 입금을 요청합니다. 2차 인증(카카오)이 필요합니다. Request KRW deposit. Requires 2FA (Kakao). \" +\n \"⚠️ REQUIRES EXPLICIT USER CONFIRMATION before executing: show the user the deposit amount and wait for explicit approval. Do NOT request deposit without user confirmation.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n amount: {\n type: \"string\",\n description: \"Deposit amount in KRW\",\n },\n two_factor_type: {\n type: \"string\",\n description: \"2FA method, e.g. kakao\",\n },\n },\n required: [\"amount\", \"two_factor_type\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/v1/deposits/krw\",\n {\n amount: requireString(args, \"amount\"),\n two_factor_type: requireString(args, \"two_factor_type\"),\n },\n privateRateLimit(\"deposit_krw\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 21. deposit_generate_address ─────────────────────────────\n {\n name: \"deposit_generate_address\",\n module: \"deposit\",\n description:\n \"입금 주소를 생성합니다. Generate a new deposit address. \" +\n \"⚠️ REQUIRES EXPLICIT USER CONFIRMATION before executing: show the user the currency and network type, then wait for explicit approval. Do NOT generate without user confirmation.\",\n isWrite: true,\n inputSchema: {\n type: \"object\",\n properties: {\n currency: {\n type: \"string\",\n description: \"Currency symbol, e.g. BTC\",\n },\n net_type: {\n type: \"string\",\n description: \"Network type, e.g. BTC, ETH\",\n },\n },\n required: [\"currency\", \"net_type\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privatePost(\n \"/v1/deposits/generate_coin_address\",\n {\n currency: requireString(args, \"currency\"),\n net_type: requireString(args, \"net_type\"),\n },\n privateRateLimit(\"deposit_generate_address\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 22. deposit_get_addresses ────────────────────────────────\n {\n name: \"deposit_get_addresses\",\n module: \"deposit\",\n description:\n \"전체 입금 주소를 조회합니다. Get all deposit addresses. \" +\n \"Use this first for multi-network coins (USDT, USDC, XRP, etc.) to discover available currency + net_type combinations before calling deposit_get_address.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n },\n handler: async (_rawArgs, context) => {\n const response = await context.client.privateGet(\n \"/v1/deposits/coin_addresses\",\n {},\n privateRateLimit(\"deposit_get_addresses\"),\n );\n return normalizeResponse(response);\n },\n },\n\n // ── 23. deposit_get_address ──────────────────────────────────\n {\n name: \"deposit_get_address\",\n module: \"deposit\",\n description:\n \"개별 입금 주소를 조회합니다. Get deposit address for a specific currency and network. \" +\n \"For multi-network coins (USDT, USDC, XRP, etc.), run deposit_get_addresses first to confirm the correct net_type — wrong network = permanent loss of funds.\",\n isWrite: false,\n inputSchema: {\n type: \"object\",\n properties: {\n currency: {\n type: \"string\",\n description: \"Currency symbol, e.g. BTC\",\n },\n net_type: {\n type: \"string\",\n description: \"Network type, e.g. BTC, ETH\",\n },\n },\n required: [\"currency\", \"net_type\"],\n },\n handler: async (rawArgs, context) => {\n const args = asRecord(rawArgs);\n const response = await context.client.privateGet(\n \"/v1/deposits/coin_address\",\n {\n currency: requireString(args, \"currency\"),\n net_type: requireString(args, \"net_type\"),\n },\n privateRateLimit(\"deposit_get_address\"),\n );\n return normalizeResponse(response);\n },\n },\n ];\n}\n","// ─── Tool Registry ─────────────────────────────────────────────────\n\nimport type { BithumbConfig } from \"../config.js\";\nimport type { BithumbRestClient } from \"../client/rest-client.js\";\nimport type { ToolSpec, ToolArgs } from \"./types.js\";\nimport { registerMarketTools } from \"./market.js\";\nimport { registerAccountTools } from \"./account.js\";\nimport { registerTradeTools } from \"./trade.js\";\nimport { registerAuditTools } from \"./audit.js\";\nimport { registerDiagnoseTools } from \"./diagnose.js\";\nimport { registerTwapTools } from \"./twap.js\";\nimport { registerWithdrawTools } from \"./withdraw.js\";\nimport { registerDepositTools } from \"./deposit.js\";\n\n/** Return all registered tool specs. */\nexport function allToolSpecs(): ToolSpec[] {\n return [\n ...registerMarketTools(),\n ...registerAccountTools(),\n ...registerTradeTools(),\n ...registerAuditTools(),\n ...registerDiagnoseTools(),\n ...registerTwapTools(),\n ...registerWithdrawTools(),\n ...registerDepositTools(),\n ];\n}\n\n/** Filter tools by enabled modules and readOnly mode. */\nexport function buildTools(config: BithumbConfig): ToolSpec[] {\n const enabledModules = new Set(config.modules);\n const tools = allToolSpecs().filter((t) => enabledModules.has(t.module));\n return config.readOnly ? tools.filter((t) => !t.isWrite) : tools;\n}\n\nexport interface ToolResult {\n endpoint: string;\n requestTime: string;\n data: unknown;\n}\n\nexport type ToolRunner = (\n toolName: string,\n args: ToolArgs,\n) => Promise<ToolResult>;\n\n/** Create a function that dispatches tool calls by name. */\nexport function createToolRunner(\n client: BithumbRestClient,\n config: BithumbConfig,\n): ToolRunner {\n const tools = allToolSpecs();\n const toolMap = new Map<string, ToolSpec>(\n tools.map((t) => [t.name, t]),\n );\n\n return async (toolName, args) => {\n const tool = toolMap.get(toolName);\n if (!tool) throw new Error(`Unknown tool: ${toolName}`);\n return (await tool.handler(args, { config, client })) as ToolResult;\n };\n}\n","// ─── Tool Types ────────────────────────────────────────────────────\n\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { BithumbRestClient } from \"../client/rest-client.js\";\nimport type { BithumbConfig } from \"../config.js\";\nimport type { ModuleId } from \"../constants.js\";\n\nexport type ToolArgs = Record<string, unknown>;\nexport type JsonSchema = Tool[\"inputSchema\"];\n\nexport interface ToolContext {\n config: BithumbConfig;\n client: BithumbRestClient;\n}\n\nexport interface ToolSpec {\n name: string;\n module: ModuleId;\n description: string;\n inputSchema: JsonSchema;\n isWrite: boolean;\n handler: (args: ToolArgs, context: ToolContext) => Promise<unknown>;\n}\n\nexport function toMcpTool(tool: ToolSpec): Tool {\n return {\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n annotations: {\n readOnlyHint: !tool.isWrite,\n destructiveHint: tool.isWrite,\n idempotentHint: !tool.isWrite,\n openWorldHint: true,\n },\n };\n}\n","// ─── Configuration ─────────────────────────────────────────────────\n\nimport {\n BITHUMB_API_BASE_URL,\n DEFAULT_MODULES,\n MODULES,\n type ModuleId,\n type ClientType,\n} from \"./constants.js\";\nimport { ConfigError } from \"./utils/errors.js\";\n\nexport interface BithumbConfig {\n accessKey?: string;\n secretKey?: string;\n hasAuth: boolean;\n baseUrl: string;\n timeoutMs: number;\n modules: ModuleId[];\n readOnly: boolean;\n verbose: boolean;\n clientType: ClientType;\n}\n\nexport function loadConfig(options?: {\n modules?: string;\n readOnly?: boolean;\n verbose?: boolean;\n accessKey?: string;\n secretKey?: string;\n clientType?: ClientType;\n}): BithumbConfig {\n // Priority: CLI flag > env var > default\n const accessKey = options?.accessKey?.trim() || process.env.BITHUMB_ACCESS_KEY?.trim();\n const secretKey = options?.secretKey?.trim() || process.env.BITHUMB_SECRET_KEY?.trim();\n const hasAuth = Boolean(accessKey && secretKey);\n const partialAuth = Boolean(accessKey) || Boolean(secretKey);\n\n if (partialAuth && !hasAuth) {\n throw new ConfigError(\n \"Partial API credentials.\",\n \"Set both access and secret keys via --access-key/--secret-key flags or BITHUMB_ACCESS_KEY/BITHUMB_SECRET_KEY env vars.\",\n );\n }\n\n const baseUrl = (\n process.env.BITHUMB_API_BASE_URL?.trim() ?? BITHUMB_API_BASE_URL\n ).replace(/\\/+$/, \"\");\n\n const rawTimeout = process.env.BITHUMB_TIMEOUT_MS\n ? Number(process.env.BITHUMB_TIMEOUT_MS)\n : 15_000;\n\n if (!Number.isFinite(rawTimeout) || rawTimeout <= 0) {\n throw new ConfigError(\n \"Invalid timeout.\",\n \"BITHUMB_TIMEOUT_MS must be a positive integer.\",\n );\n }\n\n // Parse modules\n let modules: ModuleId[] = [...DEFAULT_MODULES];\n if (options?.modules) {\n const requested = options.modules\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n\n if (requested.length > 0) {\n let isAll = false;\n for (const m of requested) {\n if (m === \"all\") {\n modules = [...MODULES];\n isAll = true;\n break;\n }\n if (!MODULES.includes(m as ModuleId)) {\n throw new ConfigError(\n `Unknown module \"${m}\".`,\n `Use: ${MODULES.join(\", \")} or \"all\".`,\n );\n }\n }\n if (!isAll) modules = requested as ModuleId[];\n }\n }\n\n return {\n accessKey,\n secretKey,\n hasAuth,\n baseUrl,\n timeoutMs: Math.floor(rawTimeout),\n modules,\n readOnly: options?.readOnly ?? false,\n verbose: options?.verbose ?? false,\n clientType: options?.clientType ?? \"etc\",\n };\n}\n","// ─── Trade Logger ──────────────────────────────────────────────────\n\nimport { mkdirSync, appendFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nexport interface LogEntry {\n ts: string;\n level: LogLevel;\n tool?: string;\n endpoint?: string;\n elapsed?: number;\n message: string;\n [key: string]: unknown;\n}\n\nconst LEVEL_ORDER: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\nconst SENSITIVE_KEY_PATTERN =\n /accessKey|secretKey|password|secret|token|jwt/i;\n\nfunction redactSensitive(obj: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n if (SENSITIVE_KEY_PATTERN.test(key)) {\n result[key] = \"***REDACTED***\";\n } else if (value && typeof value === \"object\" && !Array.isArray(value)) {\n result[key] = redactSensitive(value as Record<string, unknown>);\n } else {\n result[key] = value;\n }\n }\n return result;\n}\n\nfunction todayDateString(): string {\n const d = new Date();\n const yyyy = d.getFullYear();\n const mm = String(d.getMonth() + 1).padStart(2, \"0\");\n const dd = String(d.getDate()).padStart(2, \"0\");\n return `${yyyy}-${mm}-${dd}`;\n}\n\nexport class TradeLogger {\n private readonly logDir: string;\n private readonly minLevel: LogLevel;\n private readonly verbose: boolean;\n private readonly emitToStderr: boolean;\n\n constructor(minLevelOrOptions?: LogLevel | { logDir?: string; minLevel?: LogLevel; verbose?: boolean; emitToStderr?: boolean }) {\n if (typeof minLevelOrOptions === \"string\") {\n this.logDir = join(homedir(), \".bithumb\", \"logs\");\n this.minLevel = minLevelOrOptions;\n this.verbose = false;\n this.emitToStderr = true;\n } else {\n this.logDir = minLevelOrOptions?.logDir ?? join(homedir(), \".bithumb\", \"logs\");\n this.minLevel = minLevelOrOptions?.minLevel ?? \"info\";\n this.verbose = minLevelOrOptions?.verbose ?? false;\n this.emitToStderr = minLevelOrOptions?.emitToStderr ?? true;\n }\n\n try {\n mkdirSync(this.logDir, { recursive: true });\n } catch {\n // Silently ignore if directory cannot be created\n }\n }\n\n debug(message: string, meta?: Record<string, unknown>): void {\n this.log(\"debug\", message, meta);\n }\n\n info(message: string, meta?: Record<string, unknown>): void {\n this.log(\"info\", message, meta);\n }\n\n warn(message: string, meta?: Record<string, unknown>): void {\n this.log(\"warn\", message, meta);\n }\n\n error(message: string, meta?: Record<string, unknown>): void {\n this.log(\"error\", message, meta);\n }\n\n /** Log a tool invocation result (used by MCP server). */\n logTool(\n level: LogLevel,\n toolName: string,\n args: unknown,\n result: unknown,\n elapsedMs: number,\n ): void {\n this.log(level, `tool:${toolName}`, {\n args: args as Record<string, unknown>,\n result: result as Record<string, unknown>,\n elapsedMs,\n });\n }\n\n private log(level: LogLevel, message: string, meta?: Record<string, unknown>): void {\n if (LEVEL_ORDER[level] < LEVEL_ORDER[this.minLevel]) return;\n\n const entry: LogEntry = {\n ts: new Date().toISOString(),\n level,\n message,\n ...(meta ? redactSensitive(meta) : {}),\n };\n\n const line = JSON.stringify(entry);\n\n if (this.emitToStderr && (this.verbose || level === \"error\")) {\n process.stderr.write(`[${level}] ${message}\\n`);\n }\n\n try {\n const filePath = join(this.logDir, `trade-${todayDateString()}.log`);\n appendFileSync(filePath, line + \"\\n\", \"utf8\");\n } catch {\n // Silently ignore file write errors\n }\n }\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nconst CACHE_DIR = join(homedir(), \".bithumb\");\nconst CACHE_FILE = join(CACHE_DIR, \"update-check.json\");\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours\n\ninterface UpdateCache {\n latestVersion: string;\n checkedAt: number;\n}\n\nexport function isNewerVersion(current: string, latest: string): boolean {\n const parse = (v: string): number[] =>\n v\n .replace(/^v/, \"\")\n .split(\".\")\n .map((n) => parseInt(n, 10) || 0);\n\n const cur = parse(current);\n const lat = parse(latest);\n\n for (let i = 0; i < Math.max(cur.length, lat.length); i++) {\n const c = cur[i] ?? 0;\n const l = lat[i] ?? 0;\n if (l > c) return true;\n if (l < c) return false;\n }\n return false;\n}\n\nexport async function fetchDistTags(\n packageName: string\n): Promise<Record<string, string> | null> {\n try {\n const url = `https://registry.npmjs.org/-/package/${encodeURIComponent(packageName)}/dist-tags`;\n const res = await fetch(url, { signal: AbortSignal.timeout(5000) });\n if (!res.ok) return null;\n return (await res.json()) as Record<string, string>;\n } catch {\n return null;\n }\n}\n\nexport async function fetchLatestVersion(\n packageName: string\n): Promise<string | null> {\n const tags = await fetchDistTags(packageName);\n return tags?.latest ?? null;\n}\n\nfunction readCache(): UpdateCache | null {\n try {\n if (!existsSync(CACHE_FILE)) return null;\n const raw = readFileSync(CACHE_FILE, \"utf8\");\n return JSON.parse(raw) as UpdateCache;\n } catch {\n return null;\n }\n}\n\nfunction writeCache(data: UpdateCache): void {\n try {\n if (!existsSync(CACHE_DIR)) {\n mkdirSync(CACHE_DIR, { recursive: true });\n }\n writeFileSync(CACHE_FILE, JSON.stringify(data), \"utf8\");\n } catch {\n // ignore write errors\n }\n}\n\nfunction isCacheStale(cache: UpdateCache): boolean {\n return Date.now() - cache.checkedAt > CACHE_TTL_MS;\n}\n\nexport function checkForUpdates(\n packageName: string,\n currentVersion: string\n): void {\n try {\n const cache = readCache();\n\n if (cache && !isCacheStale(cache)) {\n if (isNewerVersion(currentVersion, cache.latestVersion)) {\n process.stderr.write(\n `\\nUpdate available: ${currentVersion} → ${cache.latestVersion}\\n` +\n `Run: npm install -g ${packageName}\\n\\n`\n );\n }\n return;\n }\n\n // Cache is stale or missing — refresh in background\n // Use setImmediate so it doesn't block the current tick\n setImmediate(() => {\n fetchLatestVersion(packageName)\n .then((latest) => {\n if (latest) {\n writeCache({ latestVersion: latest, checkedAt: Date.now() });\n if (isNewerVersion(currentVersion, latest)) {\n process.stderr.write(\n `\\nUpdate available: ${currentVersion} → ${latest}\\n` +\n `Run: npm install -g ${packageName}\\n\\n`\n );\n }\n }\n })\n .catch(() => {\n // ignore network errors\n });\n });\n } catch {\n // update check must never crash the main process\n }\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\nimport { execFileSync } from \"node:child_process\";\n\nexport type ClientId = \"claude-desktop\" | \"cursor\" | \"windsurf\" | \"vscode\" | \"claude-code\";\n\nexport interface SetupOptions {\n client: ClientId;\n modules?: string;\n}\n\nexport const CLIENT_NAMES: Record<ClientId, string> = {\n \"claude-desktop\": \"Claude Desktop\",\n cursor: \"Cursor\",\n windsurf: \"Windsurf\",\n vscode: \"VS Code\",\n \"claude-code\": \"Claude Code CLI\",\n};\n\nexport const SUPPORTED_CLIENTS = Object.keys(CLIENT_NAMES) as ClientId[];\n\nfunction appData(): string {\n return process.env.APPDATA ?? path.join(os.homedir(), \"AppData\", \"Roaming\");\n}\n\nconst CLAUDE_CONFIG_FILE = \"claude_desktop_config.json\";\n\n/**\n * Detect Microsoft Store installation of Claude Desktop on Windows.\n * MS Store apps use a sandboxed path:\n * %LOCALAPPDATA%\\Packages\\Claude_<hash>\\LocalCache\\Roaming\\Claude\\\n * Returns the config file path if found, null otherwise.\n */\nfunction findMsStoreClaudePath(): string | null {\n const localAppData = process.env.LOCALAPPDATA ?? path.join(os.homedir(), \"AppData\", \"Local\");\n const packagesDir = path.join(localAppData, \"Packages\");\n try {\n const entries = fs.readdirSync(packagesDir);\n const claudePkg = entries.find((e) => e.startsWith(\"Claude_\"));\n if (claudePkg) {\n const configPath = path.join(\n packagesDir, claudePkg, \"LocalCache\", \"Roaming\", \"Claude\", CLAUDE_CONFIG_FILE,\n );\n // Return if the config file or its parent directory already exists\n if (fs.existsSync(configPath) || fs.existsSync(path.dirname(configPath))) {\n return configPath;\n }\n }\n } catch {\n // Packages dir may not exist or may not be readable\n }\n return null;\n}\n\nexport function getConfigPath(client: ClientId): string | null {\n const home = os.homedir();\n const platform = process.platform;\n switch (client) {\n case \"claude-desktop\":\n if (platform === \"win32\") {\n // Prefer MS Store path if detected, otherwise standard %APPDATA%\n return findMsStoreClaudePath() ?? path.join(appData(), \"Claude\", CLAUDE_CONFIG_FILE);\n }\n if (platform === \"darwin\") {\n return path.join(home, \"Library\", \"Application Support\", \"Claude\", CLAUDE_CONFIG_FILE);\n }\n // Linux / other\n return path.join(process.env.XDG_CONFIG_HOME ?? path.join(home, \".config\"), \"Claude\", CLAUDE_CONFIG_FILE);\n case \"cursor\":\n return path.join(home, \".cursor\", \"mcp.json\");\n case \"windsurf\":\n return path.join(home, \".codeium\", \"windsurf\", \"mcp_config.json\");\n case \"vscode\":\n return path.join(process.cwd(), \".mcp.json\");\n case \"claude-code\":\n return null;\n }\n}\n\nconst NPX_PACKAGE = \"@bithumb-official/bithumb-mcp\";\n\nfunction buildEntry(\n client: ClientId,\n args: string[]\n): Record<string, unknown> {\n if (client === \"vscode\") {\n // VS Code inherits the terminal PATH — bare command is fine\n return { type: \"stdio\", command: \"bithumb-mcp\", args };\n }\n // Standalone apps (Claude Desktop, Cursor, Windsurf) have a limited PATH\n // that often can't find globally-installed npm bins. Use npx to ensure\n // the binary is always resolved.\n return { command: \"npx\", args: [\"-y\", NPX_PACKAGE, ...args] };\n}\n\nfunction buildArgs(options: SetupOptions): string[] {\n const args: string[] = [];\n args.push(\"--modules\", options.modules ?? \"all\");\n return args;\n}\n\nfunction mergeJsonConfig(\n configPath: string,\n serverName: string,\n entry: Record<string, unknown>\n): void {\n const dir = path.dirname(configPath);\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n\n let data: Record<string, unknown> = {};\n if (fs.existsSync(configPath)) {\n const raw = fs.readFileSync(configPath, \"utf-8\");\n try {\n data = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n throw new Error(`Failed to parse existing config at ${configPath}`);\n }\n // Backup before modifying\n const backupPath = configPath + \".bak\";\n fs.copyFileSync(configPath, backupPath);\n process.stdout.write(` Backup → ${backupPath}\\n`);\n }\n\n if (typeof data.mcpServers !== \"object\" || data.mcpServers === null) {\n data.mcpServers = {};\n }\n (data.mcpServers as Record<string, unknown>)[serverName] = entry;\n\n fs.writeFileSync(configPath, JSON.stringify(data, null, 2) + \"\\n\", \"utf-8\");\n}\n\nexport function printSetupUsage(): void {\n process.stdout.write(\n `Usage: bithumb setup --client <client> [--modules <list>]\\n\\n` +\n `Clients:\\n` +\n SUPPORTED_CLIENTS.map((id) => ` ${id.padEnd(16)} ${CLIENT_NAMES[id]}`).join(\"\\n\") +\n `\\n\\nOptions:\\n` +\n ` --modules <list> Comma-separated modules or \"all\" (default: all)\\n`\n );\n}\n\nexport function runSetup(options: SetupOptions): void {\n const { client } = options;\n const name = CLIENT_NAMES[client];\n const args = buildArgs(options);\n const serverName = \"bithumb-mcp\";\n\n if (client === \"claude-code\") {\n const claudeArgs = [\n \"mcp\",\n \"add\",\n \"--transport\",\n \"stdio\",\n serverName,\n \"--\",\n \"bithumb-mcp\",\n ...args,\n ];\n process.stdout.write(`Running: claude ${claudeArgs.join(\" \")}\\n`);\n execFileSync(\"claude\", claudeArgs, { stdio: \"inherit\" }); // NOSONAR\n process.stdout.write(`✓ Configured ${name}\\n`);\n return;\n }\n\n const configPath = getConfigPath(client);\n if (!configPath) {\n throw new Error(`${name} is not supported on this platform`);\n }\n\n const entry = buildEntry(client, args);\n mergeJsonConfig(configPath, serverName, entry);\n process.stdout.write(\n `✓ Configured ${name}\\n` +\n ` ${configPath}\\n` +\n ` Server args: ${args.join(\" \")}\\n`\n );\n if (client !== \"vscode\") {\n process.stdout.write(` Restart ${name} to apply changes.\\n`);\n }\n}\n"],"mappings":"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","names":["mkdirSync","homedir","join","fs","path","os","path","join","homedir","mkdirSync"]}
|
|
@@ -23,17 +23,17 @@ Examples:
|
|
|
23
23
|
var GET_HELP = `
|
|
24
24
|
Usage: bithumb deposit get [options]
|
|
25
25
|
|
|
26
|
-
Get details of a single deposit by
|
|
26
|
+
Get details of a single deposit by deposit ID for a specific currency.
|
|
27
27
|
|
|
28
28
|
Required:
|
|
29
29
|
--currency <code> Currency code (e.g., BTC)
|
|
30
|
-
--
|
|
30
|
+
--deposit-id <id> Deposit ID
|
|
31
31
|
|
|
32
32
|
Options:
|
|
33
33
|
(none \u2014 for txid lookup, use 'bithumb deposit list --txids <txid>')
|
|
34
34
|
|
|
35
35
|
Examples:
|
|
36
|
-
bithumb deposit get --currency BTC --
|
|
36
|
+
bithumb deposit get --currency BTC --deposit-id abc-123
|
|
37
37
|
`;
|
|
38
38
|
var LIST_HELP = `
|
|
39
39
|
Usage: bithumb deposit list [options]
|
|
@@ -46,7 +46,7 @@ Required:
|
|
|
46
46
|
Options:
|
|
47
47
|
--currency <code> Currency code (e.g., BTC)
|
|
48
48
|
--state <state> State filter (e.g., done / processing)
|
|
49
|
-
--
|
|
49
|
+
--deposit-ids <ids> Filter by deposit IDs (comma-separated)
|
|
50
50
|
--txids <txids> Filter by transaction IDs (comma-separated)
|
|
51
51
|
--limit <n> Results per page (max 100) (default: 100)
|
|
52
52
|
--page <n> Page number (default: 1)
|
|
@@ -66,7 +66,7 @@ Required:
|
|
|
66
66
|
|
|
67
67
|
Options:
|
|
68
68
|
--state <state> State filter (e.g., done / processing)
|
|
69
|
-
--
|
|
69
|
+
--deposit-ids <ids> Filter by deposit IDs (comma-separated)
|
|
70
70
|
--txids <txids> Filter by transaction IDs (comma-separated)
|
|
71
71
|
--limit <n> Results per page (max 100) (default: 100)
|
|
72
72
|
--page <n> Page number (default: 1)
|
|
@@ -158,4 +158,4 @@ export {
|
|
|
158
158
|
ACTION_HELP,
|
|
159
159
|
MODULE_HELP
|
|
160
160
|
};
|
|
161
|
-
//# sourceMappingURL=deposit-
|
|
161
|
+
//# sourceMappingURL=deposit-KAUQEY7H.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/help/deposit.ts"],"sourcesContent":["export const MODULE_HELP = `\nUsage: bithumb deposit <command> [options]\n\nCommands:\n get Get specific deposit\n list List coin deposits\n list-krw List KRW deposits\n krw Request KRW deposit (CAUTION)\n generate-address Generate deposit address\n addresses List all deposit addresses\n address Get specific deposit address\n\nRun bithumb deposit <command> --help for command-specific options.\n\nExamples:\n bithumb deposit list --currency BTC\n bithumb deposit address --currency BTC --net-type BTC\n bithumb deposit addresses\n`;\n\nconst GET_HELP = `\nUsage: bithumb deposit get [options]\n\nGet details of a single deposit by deposit ID for a specific currency.\n\nRequired:\n --currency <code> Currency code (e.g., BTC)\n --deposit-id <id> Deposit ID\n\nOptions:\n (none — for txid lookup, use 'bithumb deposit list --txids <txid>')\n\nExamples:\n bithumb deposit get --currency BTC --deposit-id abc-123\n`;\n\nconst LIST_HELP = `\nUsage: bithumb deposit list [options]\n\nList coin deposits, optionally filtered by currency, state, or identifiers.\n\nRequired:\n (none — all filters are optional)\n\nOptions:\n --currency <code> Currency code (e.g., BTC)\n --state <state> State filter (e.g., done / processing)\n --deposit-ids <ids> Filter by deposit IDs (comma-separated)\n --txids <txids> Filter by transaction IDs (comma-separated)\n --limit <n> Results per page (max 100) (default: 100)\n --page <n> Page number (default: 1)\n --order-by <order> Sort order: asc / desc (default: desc)\n\nExamples:\n bithumb deposit list --currency BTC\n bithumb deposit list --state done --limit 50 --order-by desc\n`;\n\nconst LIST_KRW_HELP = `\nUsage: bithumb deposit list-krw [options]\n\nList KRW deposits, optionally filtered by state or identifiers.\n\nRequired:\n (none — all filters are optional)\n\nOptions:\n --state <state> State filter (e.g., done / processing)\n --deposit-ids <ids> Filter by deposit IDs (comma-separated)\n --txids <txids> Filter by transaction IDs (comma-separated)\n --limit <n> Results per page (max 100) (default: 100)\n --page <n> Page number (default: 1)\n --order-by <order> Sort order: asc / desc (default: desc)\n\nExamples:\n bithumb deposit list-krw\n bithumb deposit list-krw --state done --limit 50\n`;\n\nconst KRW_HELP = `\nUsage: bithumb deposit krw [options]\n\nRequest a KRW deposit. Triggers a real KRW deposit procedure tied to your\nregistered bank/identity — invoke carefully.\n\nRequired:\n --amount <amount> Deposit amount (KRW)\n --two-factor-type <type> 2FA type (e.g., kakao)\n\nOptions:\n (none)\n\nExamples:\n bithumb deposit krw --amount 1000000 --two-factor-type kakao\n\nCaution:\n - This command initiates the official KRW deposit procedure with Bithumb;\n it is not a sandbox call. Confirm the amount and the registered bank\n account on the Bithumb site BEFORE invoking.\n - 2FA (--two-factor-type) is mandatory; the request fails without it.\n - Once submitted, the deposit follows Bithumb's settlement rules and cannot\n be retracted via CLI — handle support requests through official channels.\n`;\n\nconst GENERATE_ADDRESS_HELP = `\nUsage: bithumb deposit generate-address [options]\n\nUse this only when no deposit address yet exists for the (currency, net-type) pair.\n\nRequired:\n --currency <code> Currency code (e.g., BTC)\n --net-type <type> Network type (e.g., BTC)\n\nOptions:\n (none)\n\nExamples:\n bithumb deposit generate-address --currency BTC --net-type BTC\n`;\n\nconst ADDRESSES_HELP = `\nUsage: bithumb deposit addresses [options]\n\nReturn every registered deposit address across all currencies/networks on the account, in one call.\n\nRequired:\n (none)\n\nOptions:\n (none)\n\nExamples:\n bithumb deposit addresses\n`;\n\nconst ADDRESS_HELP = `\nUsage: bithumb deposit address [options]\n\nLook up a single existing deposit address for the given (currency, net-type). Errors if no address has been generated yet;\nuse 'bithumb deposit generate-address' first.\n\nRequired:\n --currency <code> Currency code (e.g., BTC)\n --net-type <type> Network type (e.g., BTC)\n\nOptions:\n (none)\n\nExamples:\n bithumb deposit address --currency BTC --net-type BTC\n`;\n\nexport const ACTION_HELP: Record<string, string> = {\n get: GET_HELP,\n list: LIST_HELP,\n \"list-krw\": LIST_KRW_HELP,\n krw: KRW_HELP,\n \"generate-address\": GENERATE_ADDRESS_HELP,\n addresses: ADDRESSES_HELP,\n address: ADDRESS_HELP,\n};\n"],"mappings":";;;AAAO,IAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoB3B,IAAM,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBjB,IAAM,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBlB,IAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBtB,IAAM,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyBjB,IAAM,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgB9B,IAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAevB,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBd,IAAM,cAAsC;AAAA,EACjD,KAAK;AAAA,EACL,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,KAAK;AAAA,EACL,oBAAoB;AAAA,EACpB,WAAW;AAAA,EACX,SAAS;AACX;","names":[]}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
BithumbApiError
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-HT2P7KTV.js";
|
|
5
5
|
import {
|
|
6
6
|
toArray,
|
|
7
7
|
toNumber
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-3VWN4HON.js";
|
|
9
9
|
import {
|
|
10
10
|
errorLine,
|
|
11
11
|
outputLine,
|
|
@@ -38,23 +38,23 @@ async function handleDepositCommand(run, action, v, json) {
|
|
|
38
38
|
}
|
|
39
39
|
async function cmdGet(run, v, json) {
|
|
40
40
|
if (v.txids) {
|
|
41
|
-
errorLine("Error: 'deposit get' supports --
|
|
41
|
+
errorLine("Error: 'deposit get' supports --deposit-id only. For txid lookup use:");
|
|
42
42
|
errorLine(" bithumb deposit list --txids <txid1,txid2>");
|
|
43
43
|
process.exitCode = 1;
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
46
|
if (!v.currency) {
|
|
47
|
-
errorLine("Error: --currency required. Example: bithumb deposit get --currency BTC --
|
|
47
|
+
errorLine("Error: --currency required. Example: bithumb deposit get --currency BTC --deposit-id abc-123");
|
|
48
48
|
process.exitCode = 1;
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
51
|
-
if (!v.
|
|
52
|
-
errorLine("Error: --
|
|
51
|
+
if (!v.depositId) {
|
|
52
|
+
errorLine("Error: --deposit-id required for 'deposit get'. Example: bithumb deposit get --currency BTC --deposit-id abc-123");
|
|
53
53
|
errorLine("Tip: To search by txid, use 'bithumb deposit list --txids <txid>'.");
|
|
54
54
|
process.exitCode = 1;
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
|
-
const args = { currency: v.currency,
|
|
57
|
+
const args = { currency: v.currency, deposit_id: v.depositId };
|
|
58
58
|
try {
|
|
59
59
|
const result = await run("deposit_get", args);
|
|
60
60
|
const data = result.data;
|
|
@@ -63,7 +63,7 @@ async function cmdGet(run, v, json) {
|
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
if (json) return printJson(data);
|
|
66
|
-
printKv(data);
|
|
66
|
+
printKv(renameKey(data, "uuid", "deposit_id"));
|
|
67
67
|
} catch (err) {
|
|
68
68
|
if (err instanceof BithumbApiError) {
|
|
69
69
|
const codeNum = Number(err.code);
|
|
@@ -87,7 +87,7 @@ async function cmdList(run, v, json) {
|
|
|
87
87
|
const args = {};
|
|
88
88
|
if (v.currency) args.currency = v.currency;
|
|
89
89
|
if (v.state) args.state = v.state;
|
|
90
|
-
if (v.
|
|
90
|
+
if (v.depositIds) args.deposit_ids = toArray(v.depositIds);
|
|
91
91
|
if (v.txids) args.txids = toArray(v.txids);
|
|
92
92
|
if (v.limit) args.limit = toNumber(v.limit);
|
|
93
93
|
if (v.page) args.page = toNumber(v.page);
|
|
@@ -99,12 +99,12 @@ async function cmdList(run, v, json) {
|
|
|
99
99
|
outputLine("No deposits found");
|
|
100
100
|
return;
|
|
101
101
|
}
|
|
102
|
-
printTable(items);
|
|
102
|
+
printTable(items.map((o) => renameKey(o, "uuid", "deposit_id")));
|
|
103
103
|
}
|
|
104
104
|
async function cmdListKrw(run, v, json) {
|
|
105
105
|
const args = {};
|
|
106
106
|
if (v.state) args.state = v.state;
|
|
107
|
-
if (v.
|
|
107
|
+
if (v.depositIds) args.deposit_ids = toArray(v.depositIds);
|
|
108
108
|
if (v.txids) args.txids = toArray(v.txids);
|
|
109
109
|
if (v.limit) args.limit = toNumber(v.limit);
|
|
110
110
|
if (v.page) args.page = toNumber(v.page);
|
|
@@ -116,7 +116,15 @@ async function cmdListKrw(run, v, json) {
|
|
|
116
116
|
outputLine("No KRW deposits found");
|
|
117
117
|
return;
|
|
118
118
|
}
|
|
119
|
-
printTable(items);
|
|
119
|
+
printTable(items.map((o) => renameKey(o, "uuid", "deposit_id")));
|
|
120
|
+
}
|
|
121
|
+
function renameKey(obj, from, to) {
|
|
122
|
+
if (!(from in obj)) return obj;
|
|
123
|
+
const out = {};
|
|
124
|
+
for (const [k, val] of Object.entries(obj)) {
|
|
125
|
+
out[k === from ? to : k] = val;
|
|
126
|
+
}
|
|
127
|
+
return out;
|
|
120
128
|
}
|
|
121
129
|
async function cmdKrw(run, v, json) {
|
|
122
130
|
if (!v.amount || !v.twoFactorType) {
|
|
@@ -166,4 +174,4 @@ async function cmdAddress(run, v, json) {
|
|
|
166
174
|
export {
|
|
167
175
|
handleDepositCommand
|
|
168
176
|
};
|
|
169
|
-
//# sourceMappingURL=deposit-
|
|
177
|
+
//# sourceMappingURL=deposit-L3BBLG4X.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/deposit.ts"],"sourcesContent":["import type { ToolRunner } from \"@bithumb-official/bithumb-core\";\nimport { BithumbApiError } from \"@bithumb-official/bithumb-core\";\nimport type { CliValues } from \"../parser.js\";\nimport { toNumber, toArray } from \"../parser.js\";\nimport { outputLine, errorLine, printJson, printTable, printKv } from \"../formatter.js\";\n\nexport async function handleDepositCommand(\n run: ToolRunner,\n action: string,\n v: CliValues,\n json: boolean,\n): Promise<void> {\n switch (action) {\n case \"get\":\n return cmdGet(run, v, json);\n case \"list\":\n return cmdList(run, v, json);\n case \"list-krw\":\n return cmdListKrw(run, v, json);\n case \"krw\":\n return cmdKrw(run, v, json);\n case \"generate-address\":\n return cmdGenerateAddress(run, v, json);\n case \"addresses\":\n return cmdAddresses(run, json);\n case \"address\":\n return cmdAddress(run, v, json);\n default:\n errorLine(`Unknown deposit command: ${action}. Run 'bithumb deposit --help' for usage.`);\n process.exitCode = 1;\n }\n}\n\nasync function cmdGet(run: ToolRunner, v: CliValues, json: boolean): Promise<void> {\n if (v.txids) {\n errorLine(\"Error: 'deposit get' supports --deposit-id only. For txid lookup use:\");\n errorLine(\" bithumb deposit list --txids <txid1,txid2>\");\n process.exitCode = 1;\n return;\n }\n if (!v.currency) {\n errorLine(\"Error: --currency required. Example: bithumb deposit get --currency BTC --deposit-id abc-123\");\n process.exitCode = 1;\n return;\n }\n if (!v.depositId) {\n errorLine(\"Error: --deposit-id required for 'deposit get'. Example: bithumb deposit get --currency BTC --deposit-id abc-123\");\n errorLine(\"Tip: To search by txid, use 'bithumb deposit list --txids <txid>'.\");\n process.exitCode = 1;\n return;\n }\n const args: Record<string, unknown> = { currency: v.currency, deposit_id: v.depositId };\n try {\n const result = await run(\"deposit_get\", args);\n const data = result.data as Record<string, unknown> | undefined;\n if (!data || (typeof data === \"object\" && Object.keys(data).length === 0)) {\n outputLine(\"No deposit found.\");\n return;\n }\n if (json) return printJson(data);\n // Relabel the response's legacy `uuid` field as `deposit_id` for display\n // consistency with the input flag. Raw JSON (--json) keeps the original field.\n printKv(renameKey(data, \"uuid\", \"deposit_id\"));\n } catch (err) {\n // Bithumb API may return 4xx for unknown UUID; render gracefully without the `Fatal:` prefix.\n if (err instanceof BithumbApiError) {\n const codeNum = Number(err.code);\n const codeStr = err.code ?? \"\";\n const errNamePattern = /not.?found|invalid|forbidden|unauthorized|bad.?request/i;\n const messagePattern = /not.?found|invalid/i;\n const isClientError =\n (Number.isFinite(codeNum) && codeNum >= 400 && codeNum < 500) ||\n errNamePattern.test(codeStr) ||\n messagePattern.test(err.message);\n if (isClientError) {\n errorLine(`Error: deposit not found or invalid request (${err.code}). ${err.message}`);\n process.exitCode = 1;\n return;\n }\n // Other Bithumb API errors (5xx, unknown code): still graceful, not Fatal.\n errorLine(`Error: ${err.message}`);\n process.exitCode = 1;\n return;\n }\n throw err;\n }\n}\n\nasync function cmdList(run: ToolRunner, v: CliValues, json: boolean): Promise<void> {\n const args: Record<string, unknown> = {};\n if (v.currency) args.currency = v.currency;\n if (v.state) args.state = v.state;\n if (v.depositIds) args.deposit_ids = toArray(v.depositIds);\n if (v.txids) args.txids = toArray(v.txids);\n if (v.limit) args.limit = toNumber(v.limit);\n if (v.page) args.page = toNumber(v.page);\n if (v.orderBy) args.order_by = v.orderBy;\n const result = await run(\"deposit_get_list\", args);\n const items = result.data as Record<string, unknown>[];\n if (json) return printJson(items);\n if (!items?.length) { outputLine(\"No deposits found\"); return; }\n printTable(items.map((o) => renameKey(o, \"uuid\", \"deposit_id\")));\n}\n\nasync function cmdListKrw(run: ToolRunner, v: CliValues, json: boolean): Promise<void> {\n const args: Record<string, unknown> = {};\n if (v.state) args.state = v.state;\n if (v.depositIds) args.deposit_ids = toArray(v.depositIds);\n if (v.txids) args.txids = toArray(v.txids);\n if (v.limit) args.limit = toNumber(v.limit);\n if (v.page) args.page = toNumber(v.page);\n if (v.orderBy) args.order_by = v.orderBy;\n const result = await run(\"deposit_get_list_krw\", args);\n const items = result.data as Record<string, unknown>[];\n if (json) return printJson(items);\n if (!items?.length) { outputLine(\"No KRW deposits found\"); return; }\n printTable(items.map((o) => renameKey(o, \"uuid\", \"deposit_id\")));\n}\n\n// Return a shallow copy of `obj` with key `from` renamed to `to`, preserving\n// insertion order. If `from` is absent, returns the object unchanged.\nfunction renameKey(\n obj: Record<string, unknown>,\n from: string,\n to: string,\n): Record<string, unknown> {\n if (!(from in obj)) return obj;\n const out: Record<string, unknown> = {};\n for (const [k, val] of Object.entries(obj)) {\n out[k === from ? to : k] = val;\n }\n return out;\n}\n\nasync function cmdKrw(run: ToolRunner, v: CliValues, json: boolean): Promise<void> {\n if (!v.amount || !v.twoFactorType) {\n errorLine(\"Error: --amount and --two-factor-type required.\");\n errorLine(\"CAUTION: This will initiate a real KRW deposit request!\");\n process.exitCode = 1;\n return;\n }\n outputLine(\"WARNING: Initiating KRW deposit request.\");\n const result = await run(\"deposit_krw\", { amount: v.amount, two_factor_type: v.twoFactorType });\n const data = result.data as Record<string, unknown>;\n if (json) return printJson(data);\n printKv(data);\n}\n\nasync function cmdGenerateAddress(run: ToolRunner, v: CliValues, json: boolean): Promise<void> {\n if (!v.currency || !v.netType) {\n errorLine(\"Error: --currency and --net-type required. Example: bithumb deposit generate-address --currency BTC --net-type BTC\");\n process.exitCode = 1;\n return;\n }\n const result = await run(\"deposit_generate_address\", { currency: v.currency, net_type: v.netType });\n const data = result.data as Record<string, unknown>;\n if (json) return printJson(data);\n printKv(data);\n}\n\nasync function cmdAddresses(run: ToolRunner, json: boolean): Promise<void> {\n const result = await run(\"deposit_get_addresses\", {});\n const items = result.data as Record<string, unknown>[];\n if (json) return printJson(items);\n if (!items?.length) { outputLine(\"No deposit addresses found\"); return; }\n printTable(items);\n}\n\nasync function cmdAddress(run: ToolRunner, v: CliValues, json: boolean): Promise<void> {\n if (!v.currency || !v.netType) {\n errorLine(\"Error: --currency and --net-type required. Example: bithumb deposit address --currency BTC --net-type BTC\");\n process.exitCode = 1;\n return;\n }\n const result = await run(\"deposit_get_address\", { currency: v.currency, net_type: v.netType });\n const data = result.data as Record<string, unknown>;\n if (json) return printJson(data);\n printKv(data);\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.ts
CHANGED