UNPKG

node-kraken-api

Version:

a typed REST/WS Node.JS client for the Kraken cryptocurrency exchange

1,249 lines (1,248 loc) 54.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports._hidePrivates = exports._CountTrigger = exports._Legacy = exports._request = exports._sendRequest = exports._prepareRequest = exports._BinaryReceiver = exports._UTF8Receiver = exports._Authenticator = exports.Kraken = exports._GENNONCE = exports._REST_VERSION = exports._WS_PRIV_HOSTNAME = exports._WS_PUB_HOSTNAME = exports._REST_HOSTNAME = exports._USER_AGENT = void 0; const url_1 = require("url"); const https = __importStar(require("https")); const ts_ev_1 = require("ts-ev"); const crc_1 = require("crc"); const crypto_1 = __importDefault(require("crypto")); const ws_1 = __importDefault(require("ws")); exports._USER_AGENT = "node-kraken-api/2.2.2"; exports._REST_HOSTNAME = "api.kraken.com"; exports._WS_PUB_HOSTNAME = "ws.kraken.com"; exports._WS_PRIV_HOSTNAME = "ws-auth.kraken.com"; exports._REST_VERSION = "0"; exports._GENNONCE = (() => { let prev = -1; let next = -1; return Object.freeze(() => { next = Date.now(); if (next <= prev) next = prev + 1; prev = next; return next; }); })(); class Kraken { constructor({ key, secret, genotp, gennonce = exports._GENNONCE, timeout = 1000, pubMethods, privMethods, parse, dataFormatter, } = {}) { this._legacy = _Legacy.Settings.defaults(); this.ws = new (class WS { constructor(kraken) { this.pub = new Kraken.WS.Connection(exports._WS_PUB_HOSTNAME, () => kraken.timeout); this.priv = new Kraken.WS.Connection(exports._WS_PRIV_HOSTNAME, () => kraken.timeout); } ticker() { return new Kraken.WS.Subscriber(this.pub, "ticker", (self, payload, status) => { for (let i = 1; i < payload.length - 2; ++i) self.emit("update", payload[i], status.pair); }, {}); } ohlc(options) { return new Kraken.WS.Subscriber(this.pub, "ohlc", (self, payload, status) => { for (let i = 1; i < payload.length - 2; ++i) self.emit("update", payload[i], status.pair); }, options || {}); } trade() { return new Kraken.WS.Subscriber(this.pub, "trade", (self, payload, status) => { for (let i = 1; i < payload.length - 2; ++i) self.emit("update", payload[i], status.pair); }, {}); } spread() { return new Kraken.WS.Subscriber(this.pub, "spread", (self, payload, status) => { for (let i = 1; i < payload.length - 2; ++i) self.emit("update", payload[i], status.pair); }, {}); } book(options) { const mirrors = {}; const locks = {}; function spawnResubscribe(sub, status) { return __awaiter(this, void 0, void 0, function* () { if (locks[status.pair]) return; locks[status.pair] = true; try { delete mirrors[status.pair]; yield sub.unsubscribe(status.pair); yield sub.subscribe(status.pair); } catch (e) { if (e instanceof Error) sub.emit("error", e, status); else sub.emit("error", new Kraken.UnknownError("received an unknown error", e), status); } delete locks[status.pair]; }); } return new Kraken.WS.Subscriber(this.pub, "book", (self, payload, status) => __awaiter(this, void 0, void 0, function* () { for (let i = 1; i < payload.length - 2; ++i) { try { if (payload[i].as && payload[i].bs) { self.emit("snapshot", payload[i], status.pair); mirrors[status.pair] = payload[i]; } else { if (payload[i].a) self.emit("ask", payload[i], status.pair); if (payload[i].b) self.emit("bid", payload[i], status.pair); if (mirrors[status.pair]) { const { modified, verified } = Kraken.WS.Book.applyUpdate(mirrors[status.pair], payload[i]); if (modified && verified) { self.emit("mirror", mirrors[status.pair], status.pair); } else if (!verified) { spawnResubscribe(self, status); } } } } catch (e) { if (e instanceof Error) self.emit("error", e, status); else self.emit("error", new Kraken.UnknownError("received an unknown error", e), status); } } }), options || {}); } ownTrades(options) { return new Kraken.WS.Subscriber(this.priv, "ownTrades", (self, payload) => { for (let i = 0; i < payload.length - 2; ++i) self.emit("update", payload[i], payload[payload.length - 1].sequence); }, options); } openOrders(options) { return new Kraken.WS.Subscriber(this.priv, "openOrders", (self, payload) => { for (let i = 0; i < payload.length - 2; ++i) self.emit("update", payload[i], payload[payload.length - 1].sequence); }, options); } addOrder(options) { return this.priv.request(Object.assign(Object.assign({}, options), { event: "addOrder" })); } cancelOrder(options) { return this.priv.requestMulti(Object.assign(Object.assign({}, options), { event: "cancelOrder" }), options.txid.length); } cancelAll(options) { return this.priv.request(Object.assign(Object.assign({}, options), { event: "cancelAll" })); } cancelAllOrdersAfter(options) { return this.priv.request(Object.assign(Object.assign({}, options), { event: "cancelAllOrdersAfter" })); } })(this); if (key && !secret) { throw new Kraken.SettingsError("Key provided without secret"); } if (!key && secret) { throw new Kraken.SettingsError("Secret provided without key"); } if (genotp && !key && !secret) { throw new Kraken.SettingsError("OTPGen provided without key or secret"); } if (timeout <= 0) { throw new Kraken.SettingsError("Timeout must be > 0"); } this.timeout = timeout; this._gennonce = gennonce; this._auth = key && secret ? new _Authenticator(key, secret, genotp) : null; if (pubMethods) this._legacy.pubMethods = pubMethods; if (privMethods) this._legacy.privMethods = privMethods; if (parse) this._legacy.parse = parse; if (dataFormatter) this._legacy.dataFormatter = dataFormatter; _hidePrivates(this); } request(endpoint, options = null, type = "public", encoding = "utf8") { return _request(endpoint, options, type, encoding, this.timeout, this._gennonce, this._auth); } call(method, options, cb) { let type; if (this._legacy.pubMethods.includes(method)) { type = "public"; } else if (this._legacy.privMethods.includes(method)) { type = "private"; } else { throw Error(`Bad method: ${method}. See documentation and check settings.`); } const onceresponse = new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { try { const res = _Legacy.parseNested(yield this.request(method, options || null, type, "utf8"), this._legacy.parse); if (this._legacy.dataFormatter) { resolve(this._legacy.dataFormatter(method, options, res)); } else { resolve(res); } } catch (e) { reject(e); } })); if (cb) { onceresponse.then((data) => cb(null, data)).catch((err) => cb(err, null)); } else { return onceresponse; } } time() { return this.request("Time"); } systemStatus() { return this.request("SystemStatus"); } assets(options) { return this.request("Assets", options); } assetPairs(options) { return this.request("AssetPairs", options); } ticker(options) { return this.request("Ticker", options); } ohlc(options) { return this.request("OHLC", options); } depth(options) { return this.request("Depth", options); } trades(options) { return this.request("Trades", options); } spread(options) { return this.request("Spread", options); } getWebSocketsToken() { return this.request("GetWebSocketsToken", null, "private"); } balance() { return this.request("Balance", null, "private"); } tradeBalance(options) { return this.request("TradeBalance", options, "private"); } openOrders(options) { return this.request("OpenOrders", options, "private"); } closedOrders(options) { return this.request("ClosedOrders", options, "private"); } queryOrders(options) { return this.request("QueryOrders", options, "private"); } tradesHistory(options) { return this.request("TradesHistory", options, "private"); } queryTrades(options) { return this.request("QueryTrades", options, "private"); } openPositions(options) { return this.request("OpenPositions", options, "private"); } ledgers(options) { return this.request("Ledgers", options, "private"); } queryLedgers(options) { return this.request("QueryLedgers", options, "private"); } tradeVolume(options) { return this.request("TradeVolume", options, "private"); } addExport(options) { return this.request("AddExport", options, "private"); } exportStatus(options) { return this.request("ExportStatus", options, "private"); } retrieveExport(options) { return this.request("RetrieveExport", options, "private", "binary"); } removeExport(options) { return this.request("RemoveExport", options, "private"); } addOrder(options) { return this.request("AddOrder", options, "private"); } cancelOrder(options) { return this.request("CancelOrder", options, "private"); } cancelAll() { return this.request("CancelAll", null, "private"); } cancelAllOrdersAfter(options) { return this.request("CancelAllOrdersAfter", options, "private"); } depositMethods(options) { return this.request("DepositMethods", options, "private"); } depositAddresses(options) { return this.request("DepositAddresses", options, "private"); } depositStatus(options) { return this.request("DepositStatus", options, "private"); } withdrawInfo(options) { return this.request("WithdrawInfo", options, "private"); } withdraw(options) { return this.request("Withdraw", options, "private"); } withdrawStatus(options) { return this.request("WithdrawStatus", options, "private"); } withdrawCancel(options) { return this.request("WithdrawCancel", options, "private"); } walletTransfer(options) { return this.request("WalletTransfer", options, "private"); } stake(options) { return this.request("Stake", options, "private"); } unstake(options) { return this.request("Unstake", options, "private"); } stakingAssets() { return this.request("Staking/Assets", null, "private"); } stakingPending() { return this.request("Staking/Pending", null, "private"); } stakingTransactions() { return this.request("Staking/Transactions", null, "private"); } } exports.Kraken = Kraken; (function (Kraken) { class InternalError extends Error { constructor(message, info) { super(message); this.info = info; } } Kraken.InternalError = InternalError; class UnknownError extends Error { constructor(message, info) { super(message); this.info = info; } } Kraken.UnknownError = UnknownError; class ArgumentError extends Error { constructor(message) { super(message); } } Kraken.ArgumentError = ArgumentError; class UsageError extends Error { constructor(message) { super(message); } } Kraken.UsageError = UsageError; class SettingsError extends ArgumentError { constructor(description) { super(description); } } Kraken.SettingsError = SettingsError; class JSONParseError extends Error { constructor(source, parseError) { super(parseError.message); this.source = source; } } Kraken.JSONParseError = JSONParseError; class BufferParseError extends Error { constructor(source, parseError) { super(parseError.message); this.source = source; } } Kraken.BufferParseError = BufferParseError; class HTTPRequestError extends Error { constructor(statusCode, statusMessage) { if (statusCode === undefined) { super("Expected an HTTP status code"); } else { super(statusCode + ": " + statusMessage); this.statusCode = statusCode; this.statusMessage = statusMessage; } } } Kraken.HTTPRequestError = HTTPRequestError; class RESTAPIError extends Error { constructor(body) { super(JSON.stringify(body.error)); this.body = body; } } Kraken.RESTAPIError = RESTAPIError; class TimeoutError extends Error { constructor(message) { super(message); } } Kraken.TimeoutError = TimeoutError; class WSAPIError extends Error { constructor(eventMessage) { super(eventMessage.errorMessage); this.eventMessage = eventMessage; } } Kraken.WSAPIError = WSAPIError; let WS; (function (WS) { let Book; (function (Book) { function applyUpdate(snapshot, update) { const [snaphsotLevels, updateLevels, ascending] = (() => { if (update.a) { return [snapshot.as, update.a, true]; } else { return [snapshot.bs, update.b, false]; } })(); let modified = false; const depth = snaphsotLevels.length; for (const u of updateLevels) { const uPrice = +u[0]; const uTime = +u[2]; let matched = false; for (let i = 0; i < snaphsotLevels.length; ++i) { const lPrice = +snaphsotLevels[i][0]; if (ascending && uPrice > lPrice) continue; if (!ascending && uPrice < lPrice) continue; if (uPrice === lPrice) { if (uTime > +snaphsotLevels[i][2]) { if (+u[1] !== 0) { snaphsotLevels[i][1] = u[1]; snaphsotLevels[i][2] = u[2]; } else { snaphsotLevels.splice(i, 1); } modified = true; } matched = true; break; } else { snaphsotLevels.splice(i, 0, [u[0], u[1], u[2]]); matched = true; modified = true; break; } } if (!matched) { snaphsotLevels.push([u[0], u[1], u[2]]); modified = true; } } for (let i = 0; i < snaphsotLevels.length - depth; ++i) snaphsotLevels.pop(); let verifystr = ""; { let i = 0; for (const a of snapshot.as) { verifystr += a[0].replace(".", "").replace(/^0*(.*)/m, "$1"); verifystr += a[1].replace(".", "").replace(/^0*(.*)/m, "$1"); if (++i >= 10) break; } } { let i = 0; for (const b of snapshot.bs) { verifystr += b[0].replace(".", "").replace(/^0*(.*)/m, "$1"); verifystr += b[1].replace(".", "").replace(/^0*(.*)/m, "$1"); if (++i >= 10) break; } } return { modified, verified: update.c === "" + (0, crc_1.crc32)(verifystr) }; } Book.applyUpdate = applyUpdate; })(Book = WS.Book || (WS.Book = {})); class Connection extends ts_ev_1.Emitter { constructor(hostname, gettimeout) { super(); this._state = "closed"; this._socket = null; this._sendQueue = []; this.hostname = hostname; this._gettimeout = gettimeout; this._setState("closed"); _hidePrivates(this); } get state() { return this._state; } get socket() { return this._socket; } ping() { return __awaiter(this, void 0, void 0, function* () { yield this.request({ event: "ping" }); }); } request(request) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { try { const reqid = (0, exports._GENNONCE)(); let prevreqid = request.reqid; this.once("dict", (o) => { if (!o.errorMessage) { if (prevreqid) o.reqid = prevreqid; resolve(o); } else { reject(new WSAPIError(o)); } }, { protect: true, filter: (args) => args[0].reqid === reqid, }); this.write(JSON.stringify(Object.assign(Object.assign({}, request), { reqid }))); } catch (e) { reject(new InternalError("an unexpected error occurred", e)); } }); }); } requestMulti(request, nResponses) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { try { const reqid = (0, exports._GENNONCE)(); let prevreqid = request.reqid; const responses = []; const resolver = new _CountTrigger(nResponses, () => { this.off("dict", l); resolve(responses); }); const l = (o) => { if (prevreqid) o.reqid = prevreqid; responses.push(o); resolver.fireWhenReady(); }; this.on("dict", l, { protect: true, filter: (args) => args[0].reqid === reqid, }); this.write(JSON.stringify(Object.assign(Object.assign({}, request), { reqid }))); } catch (e) { reject(new InternalError("an unexpected error occurred", e)); } }); }); } open() { return new Promise((resolve, reject) => { try { if (this._state === "open" || this._state === "opening") { reject(new UsageError("cannot open the connection twice")); } else { this._setState("opening"); this._socket = new ws_1.default("wss://" + this.hostname + ":443", { timeout: this._gettimeout(), }); this._socket.addListener("message", this._onread.bind(this)); this._socket.addListener("error", this._onerror.bind(this)); this._socket.addListener("close", this._onclose.bind(this)); this._socket.addListener("open", this._onopen.bind(this)); const onceOpen = () => { if (!this._socket) reject(new InternalError("Socket should have been available")); else { this._socket.removeListener("open", onceOpen); resolve(); } }; this._socket.addListener("open", onceOpen); } } catch (e) { reject(new InternalError("an unexpected error occurred", e)); } }); } close(code, reason) { return new Promise((resolve, reject) => { try { if (this._state === "closed" || this._state === "closing") reject(new UsageError("cannot close the connection twice")); else { this._setState("closing"); if (this._socket) { const onceClosed = () => { if (!this._socket) { resolve(); } else { reject(new InternalError("Socket should not have been available")); } }; this._socket.addListener("close", onceClosed); this._socket.close(code, reason); } else { reject(new InternalError("Socket should have been available")); } } } catch (e) { reject(new InternalError("an unexpected error occurred", e)); } }); } terminate() { if (this._socket) { this._socket.removeAllListeners(); this._socket.terminate(); this._socket = null; } this._setState("closed"); } write(data) { if (this._socket && this._state === "open") { this._socket.send(data); this.emit("write", data); } else { if (this._state !== "opening") this.open(); this._sendQueue.push(data); } return this; } _setState(state) { if (this._state !== state) { this._state = state; this.emit("state", state); } } _parseRead(data) { try { const parsed = JSON.parse(data); this.emit("json", parsed); if (parsed instanceof Array) { this.emit("array", parsed); } else if (parsed instanceof Object) { this.emit("dict", parsed); if (parsed.event === "heartbeat") { this.emit("heartbeat"); } else if (parsed.event === "systemStatus") { this.emit("systemStatus", parsed); } if (parsed.status === "error") this.emit("error", new WSAPIError(parsed)); } } catch (_) { } } _onread(data) { this.emit("read", data); if (typeof data === "string") { this._parseRead(data); } else if (data instanceof Buffer) { this._parseRead(data.toString("utf8")); } else { this.emit("error", new InternalError("Expected either a string or buffer WS response.")); } } _onerror(err) { this.emit("error", err); } _onclose(code, message) { this.emit("close", code, message); this.terminate(); } _onopen() { this.emit("open"); if (this._state !== "open") { this._setState("open"); if (this._socket) { for (const data of this._sendQueue) { this._socket.send(data); this.emit("write", data); } } else { this.terminate(); } } } } WS.Connection = Connection; class Subscriber extends ts_ev_1.Emitter { constructor(con, name, payloadDistributor, options) { super(); this._reqid = (0, exports._GENNONCE)(); this.subscriptions = new Set(); this._con = con; this.name = name; this.options = options; this.on("payload", (payload, status) => payloadDistributor(this, payload, status), { protect: true, }); _hidePrivates(this); } subscribe(...pairs) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { try { const request = { event: "subscribe", reqid: this._reqid, subscription: Object.assign(Object.assign({}, this.options), { name: this.name }), }; if (pairs.length) { request.pair = pairs; const resolver = new _CountTrigger(request.pair.length, () => resolve(this)); request.pair.forEach((p) => this._mksub(p) .then(() => resolver.fireWhenReady()) .catch(reject)); } else { this._mksub() .then(() => resolve(this)) .catch(reject); } this._con.write(JSON.stringify(request)); } catch (e) { reject(new InternalError("an unexpected error occurred", e)); } }); }); } unsubscribe(...pairs) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { try { const request = { event: "unsubscribe", reqid: this._reqid, subscription: Object.assign(Object.assign({}, this.options), { name: this.name }), }; if (pairs.length) { request.pair = pairs; const resolver = new _CountTrigger(request.pair.length, () => resolve(this)); request.pair.forEach((p) => this._rmsub(p) .then(() => resolver.fireWhenReady()) .catch(reject)); } else { this._rmsub() .then(() => resolve(this)) .catch(reject); } this._con.write(JSON.stringify(request)); } catch (e) { reject(new InternalError("an unexpected error occurred", e)); } }); }); } _mksub(pair) { return new Promise((resolve, reject) => { try { const protect = { protect: true }; const sub = new Subscription(this._con, this._reqid, pair); const onstatus = (status) => this.emit("status", status); const onerror = (error) => this.emit("error", error, sub.status); const onpayload = (payload) => this.emit("payload", payload, sub.status); sub .once("created", () => { this.subscriptions.add(sub); resolve(); }, protect) .once("destroyed", () => { this.subscriptions.delete(sub); sub.off("status", onstatus).off("error", onerror).off("payload", onpayload); }, protect) .on("status", onstatus, protect) .on("error", onerror, protect) .on("payload", onpayload, protect); } catch (e) { reject(new InternalError("an unexpected error occurred", e)); } }); } _rmsub(pair) { return new Promise((resolve, reject) => { try { for (const sub of this.subscriptions) if (sub.status.pair === pair) sub.once("destroyed", () => resolve(), { protect: true }); } catch (e) { reject(new InternalError("an unexpected error occurred", e)); } }); } } WS.Subscriber = Subscriber; class Subscription extends ts_ev_1.Emitter { constructor(con, reqid, pair) { super(); this._isstatus = (args) => { return (args[0].event === "subscriptionStatus" && args[0].reqid === this.status.reqid && args[0].pair === this.status.pair); }; this._onstatus = (status) => { this.status = status; this.emit("status", this.status); if (this.status.errorMessage) this.emit("error", new WSAPIError(this.status)); if (this.status.status === "unsubscribed") this._destroy(); }; this._onpayload = (payload) => { this.emit("payload", payload); }; this._init = (status) => { this.status = status; this.emit("status", status); if (this.status.errorMessage) { this.emit("error", new WSAPIError(this.status)); } else if (this.status.status === "subscribed") { this.emit("created"); this._con.on("dict", this._onstatus, { protect: true, filter: this._isstatus, }); this._con.on("array", this._onpayload, { protect: true, filter: (args) => args[0][args[0].length - 2] === this.status.channelName && (this.status.pair ? args[0][args[0].length - 1] === this.status.pair : true), }); } else { this.emit("error", new UnknownError('Expected either a "subscribed" status or an errorMessage')); } }; this._con = con; this.status = { event: "subscriptionStatus", reqid, pair: pair, status: "init", }; this._con.once("dict", this._init, { protect: true, filter: this._isstatus, }); _hidePrivates(this); } _destroy() { this._con.off("dict", this._onstatus); this._con.off("array", this._onpayload); this.emit("destroyed"); } } WS.Subscription = Subscription; })(WS = Kraken.WS || (Kraken.WS = {})); })(Kraken = exports.Kraken || (exports.Kraken = {})); class _Authenticator { constructor(key, secret, genotp) { this.signedHeaders = (path, postdata, nonce) => { return { "User-Agent": exports._USER_AGENT, "API-Key": key, "API-Sign": crypto_1.default .createHmac("sha512", Buffer.from(secret, "base64")) .update(path) .update(crypto_1.default .createHash("sha256") .update(nonce + postdata) .digest()) .digest("base64"), "Content-Type": "application/x-www-form-urlencoded", }; }; if (genotp) { this.signedQuery = (input) => { const otp = genotp(); return Object.assign(Object.assign({}, input), { otp }); }; } else { this.signedQuery = (input) => { return input; }; } } } exports._Authenticator = _Authenticator; class _UTF8Receiver { constructor(onjson, onerror) { this._finalized = false; this._chunked = ""; this._onjson = (json) => { try { onjson(json); } catch (_) { } this._finalized = true; }; this._onerror = (error) => { try { onerror(error); } catch (_) { } this._finalized = true; }; _hidePrivates(this); } nextChunk(chunk, statusCode, statusMessage) { if (this._finalized) return; if (!this._verifyStatus(statusCode, statusMessage)) return; this._chunked += chunk; } finalize(statusCode, statusMessage) { if (this._finalized) return; if (!this._verifyStatus(statusCode, statusMessage)) return; this._finalized = true; try { const body = JSON.parse(this._chunked); if (body.error && body.error.length > 0) { this._onerror(new Kraken.RESTAPIError(body)); } else { this._onjson(body); } } catch (err) { if (err instanceof Error) this._onerror(new Kraken.JSONParseError(this._chunked, err)); else this._onerror(new Kraken.JSONParseError(this._chunked, new Kraken.UnknownError("received an unknown error", err))); } } _verifyStatus(statusCode, statusMessage) { if (statusCode === undefined || statusCode < 200 || statusCode >= 300) { this._finalized = true; this._onerror(new Kraken.HTTPRequestError(statusCode, statusMessage)); return false; } return true; } } exports._UTF8Receiver = _UTF8Receiver; class _BinaryReceiver { constructor(onbuffer, onerror) { this._finalized = false; this._chunks = []; this._onbuffer = (buffer) => { try { onbuffer(buffer); } catch (_) { } this._finalized = true; }; this._onerror = (error) => { try { onerror(error); } catch (_) { } this._finalized = true; }; _hidePrivates(this); } nextChunk(chunk, statusCode, statusMessage) { if (this._finalized) return; if (!this._verifyStatus(statusCode, statusMessage)) return; try { this._chunks.push(Buffer.from(chunk, "binary")); } catch (e) { if (e instanceof Error) this._onerror(new Kraken.BufferParseError(chunk, e)); else this._onerror(new Kraken.BufferParseError(chunk, new Kraken.UnknownError("received an unknown error", e))); } } finalize(statusCode, statusMessage) { if (this._finalized) return; if (!this._verifyStatus(statusCode, statusMessage)) return; this._finalized = true; if (this._chunks.length <= 0) { this._onerror(new Kraken.InternalError("Connection closed before chunks were received")); return; } try { this._onbuffer(Buffer.concat(this._chunks)); } catch (e) { if (e instanceof Error) this._onerror(new Kraken.UnknownError(e.message)); else this._onerror(new Kraken.UnknownError("received an unknown error", e)); } } _verifyStatus(statusCode, statusMessage) { if (statusCode === undefined || statusCode < 200 || statusCode >= 300) { this._finalized = true; this._onerror(new Kraken.HTTPRequestError(statusCode, statusMessage)); return false; } return true; } } exports._BinaryReceiver = _BinaryReceiver; function _prepareRequest(endpoint, options, type, gennonce, auth) { const hostname = exports._REST_HOSTNAME; const nonce = gennonce(); if (type === "private") { if (auth === null) { throw new Kraken.SettingsError("Cannot make a private request without key and secret."); } const method = "POST"; const path = `/${exports._REST_VERSION}/private/${endpoint}`; const postdata = options ? new url_1.URLSearchParams(auth.signedQuery(Object.assign(Object.assign({}, options), { nonce }))).toString() : new url_1.URLSearchParams(auth.signedQuery({ nonce })).toString(); const headers = auth.signedHeaders(path, postdata, nonce); return { requestOptions: { hostname, path, method, headers, }, postdata, }; } else { const path = `/${exports._REST_VERSION}/public/${endpoint}`; const headers = { "User-Agent": exports._USER_AGENT, "Content-Type": "application/x-www-form-urlencoded", }; if (options) { const method = "POST"; const postdata = new url_1.URLSearchParams(Object.assign(Object.assign({}, options), { nonce })).toString(); return { requestOptions: { hostname, path, method, headers, }, postdata, }; } else { const method = "GET"; const postdata = null; return { requestOptions: { hostname, path, method, headers, }, postdata, }; } } } exports._prepareRequest = _prepareRequest; function _sendRequest(requestOptions, postdata, encoding, timeout) { return new Promise((resolve, reject) => { try { let didRespond = false; const r = https .request(requestOptions, (res) => { didRespond = true; try { const handler = (() => { if (encoding === "utf8") { return new _UTF8Receiver(resolve, reject); } else if (encoding === "binary") { return new _BinaryReceiver(resolve, reject); } else { throw new Kraken.ArgumentError("Invalid Encoding: " + encoding); } })(); res.setEncoding(encoding); res.on("data", (chunk) => handler.nextChunk(chunk, res.statusCode, res.statusMessage)); res.on("end", () => { handler.finalize(res.statusCode, res.statusMessage); res.removeAllListeners(); }); } catch (e) { reject(e); } }) .on("error", (e) => { r.destroy(); reject(e); }) .setTimeout(timeout, () => { if (!didRespond) { r.destroy(); reject(new Kraken.TimeoutError("REST request timed out.")); } }); if (postdata) r.write(postdata); r.end(); } catch (e) { reject(new Kraken.InternalError("an unexpected error occurred", e)); } }); } exports._sendRequest = _sendRequest; function _request(endpoint, options, type, encoding, timeout, gennonce, auth) { return __awaiter(this, void 0, void 0, function* () { const { requestOptions, postdata } = _prepareRequest(endpoint, options, type, gennonce, auth); if (encoding === "utf8") { return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { try { const data = yield _sendRequest(requestOptions, postdata, encoding, timeout); if (data.error.length) reject(new Kraken.RESTAPIError(data)); resolve(data.result); } catch (e) { reject(e); } })); } else if (encoding === "binary") { return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { try { const data = yield _sendRequest(requestOptions, postdata, encoding, timeout); resolve(data); } catch (e) { reject(e); } })); } else { throw new Kraken.ArgumentError('encoding must be "utf8" or "binary"'); } }); } exports._request = _request; var _Legacy; (function (_Legacy) { let Settings; (function (Settings) { function defaults() { return { pubMethods: [ "Time", "SystemStatus", "Assets", "AssetPairs", "Ticker", "OHLC", "Depth", "Trades", "Spread", ], privMethods: [ "GetWebSocketsToken", "Balance", "TradeBalance", "OpenOrders", "ClosedOrders", "QueryOrders", "TradesHistory", "QueryTrades", "OpenPositions", "Ledgers", "QueryLedgers", "TradeVolume", "AddExport", "ExportStatus", "RemoveExport", "AddOrder", "CancelOrder", "CancelAll", "CancelAllOrdersAfter", "DepositMethods", "DepositAddresses", "DepositStatus", "WithdrawInfo", "Withdraw",