UNPKG

crypto-client

Version:

An unified client for all cryptocurrency exchanges.

335 lines (334 loc) 12.4 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.withdraw = exports.fetchCurrencies = exports.getWithdrawalFees = exports.getDepositAddresses = exports.queryBalance = exports.queryAllBalances = exports.queryOrder = exports.cancelOrder = exports.placeOrder = void 0; const okex_node_1 = require("@okfe/okex-node"); const assert_1 = require("assert"); const bignumber_js_1 = __importDefault(require("bignumber.js")); const crypto_pair_1 = require("crypto-pair"); const config_1 = require("../config"); const util_1 = require("../util"); function createAuthenticatedClient() { assert_1.strict.ok(config_1.USER_CONFIG.OKEX_SPOT_API_KEY); assert_1.strict.ok(config_1.USER_CONFIG.OKEX_SPOT_API_SECRET); assert_1.strict.ok(config_1.USER_CONFIG.OKEX_SPOT_API_PASSPHRASE); const authClient = okex_node_1.AuthenticatedClient(config_1.USER_CONFIG.OKEX_SPOT_API_KEY, config_1.USER_CONFIG.OKEX_SPOT_API_SECRET, config_1.USER_CONFIG.OKEX_SPOT_API_PASSPHRASE); return authClient; } async function placeOrder(market, price, quantity, sell, clientOrderId) { try { assert_1.strict.ok(market); const [priceStr, quantityStr] = util_1.convertPriceAndQuantityToStrings(market, price, quantity, sell); const params = { type: 'limit', side: sell ? 'sell' : 'buy', instrument_id: market.id, price: priceStr, size: quantityStr, }; if (clientOrderId) { params.client_oid = clientOrderId; } const authClient = createAuthenticatedClient(); const data = await authClient .spot() .postOrder(params) .catch((e) => { return e; }); if (data instanceof Error) return data; if (!data.result || data.error_code !== '0' || data.order_id === '-1') { return new Error(data.error_message); } return data.order_id; } catch (e) { return e; } } exports.placeOrder = placeOrder; async function cancelOrder(market, orderId, clientOrderId) { assert_1.strict.ok(market); const params = { instrument_id: market.id, }; if (clientOrderId) { params.client_oid = clientOrderId; } const authClient = createAuthenticatedClient(); const data = await authClient.spot().postCancelOrder(clientOrderId || orderId, params); return data.result; } exports.cancelOrder = cancelOrder; async function queryOrder(market, orderId, clientOrderId) { assert_1.strict.ok(market); const params = { instrument_id: market.id, }; const authClient = createAuthenticatedClient(); const data = await authClient.spot().getOrder(clientOrderId || orderId, params); return data; } exports.queryOrder = queryOrder; async function queryAllBalances(all = false) { const authClient = createAuthenticatedClient(); const data = await authClient .spot() .getAccounts() .catch((e) => { return e; }); if (data instanceof Error) return data; const arr = data; const result = {}; arr.forEach((x) => { result[x.currency] = all ? parseFloat(x.balance) : parseFloat(x.available); }); return result; } exports.queryAllBalances = queryAllBalances; async function queryBalance(symbol) { const authClient = createAuthenticatedClient(); const data = (await authClient.spot().getAccounts(symbol)); return parseFloat(data.available); } exports.queryBalance = queryBalance; function parseCurrency(currency) { currency = currency.toUpperCase(); // eslint-disable-line no-param-reassign let symbol; let platform; if (currency.includes('-')) { const [symbol_, platform_] = currency.split('-'); symbol = symbol_; platform = platform_; } else { symbol = currency; platform = symbol; } return [symbol, platform]; } async function getAddressWithTryCatch(authClient, symbol) { try { return await authClient .account() .getAddress(symbol) .catch((e) => { return e; }); } catch (e) { return e; } } async function getDepositAddresses(symbols, all = false) { if (!symbols.includes('ETH')) symbols.push('ETH'); if (!symbols.includes('TRX')) symbols.push('TRX'); const result = {}; const authClient = createAuthenticatedClient(); const arr = []; for (let i = 0; i < symbols.length; i += 1) { const tmp = await getAddressWithTryCatch(authClient, symbols[i]); // eslint-disable-line no-await-in-loop if (!(tmp instanceof Error)) { arr.push(...tmp); } } const ethAddresses = arr.filter((x) => x.currency.toUpperCase() === 'ETH').map((x) => x.address); assert_1.strict.ok(ethAddresses.length > 0); const trxAddresses = arr.filter((x) => x.currency.toUpperCase() === 'TRX').map((x) => x.address); assert_1.strict.ok(trxAddresses.length > 0); // Rename USDT to USDT-OMNI arr .filter((x) => x.currency.toUpperCase() === 'USDT') .forEach((x) => { x.currency = 'USDT-OMNI'; // eslint-disable-line no-param-reassign }); // console.info(arr); arr .filter((x) => all || x.to === 1 || x.to === 6) // 1, spot; 6, fund .forEach((x) => { const [symbol, platformTmp] = parseCurrency(x.currency); if (!(symbol in result)) result[symbol] = {}; let platform = platformTmp; if (ethAddresses.includes(x.address) && symbol !== 'ETH' && symbol !== 'ETC') { platform = 'ERC20'; assert_1.strict.equal(platform, util_1.detectPlatform(x.address, symbol)); } if (trxAddresses.includes(x.address) && symbol !== 'TRX') { platform = symbol === 'BTT' ? 'TRC10' : 'TRC20'; assert_1.strict.equal(platform, util_1.detectPlatform(x.address, symbol)); } const depositAddress = { symbol, platform, address: x.address, }; if (x.memo || x.tag) depositAddress.memo = x.memo || x.tag; if (platform in result[symbol]) { if (x.to === 1) { // spot address has higher priority result[symbol][platform] = depositAddress; } } else { result[symbol][platform] = depositAddress; } }); return result; } exports.getDepositAddresses = getDepositAddresses; async function getWithdrawalFees() { const result = {}; const authClient = createAuthenticatedClient(); const currenciesTmp = await authClient .account() .getCurrencies() .catch((e) => { return e; }); if (currenciesTmp instanceof Error) return result; const currencies = currenciesTmp; // Rename USDT to USDT-OMNI currencies .filter((x) => x.currency === 'USDT') .forEach((x) => { x.currency = 'USDT-OMNI'; // eslint-disable-line no-param-reassign }); // console.info(JSON.stringify(currencies, undefined, 2)); // Usded for validation const currencyMap = {}; currencies.forEach((x) => { currencyMap[x.currency] = { symbol: x.currency, can_deposit: x.can_deposit === '1', can_withdraw: x.can_withdraw === '1', }; if (x.min_withdrawal) { currencyMap[x.currency].min_withdraw_amount = parseFloat(x.min_withdrawal); } }); const withdrawalFeesTmp = await authClient .account() .getWithdrawalFee() .catch((e) => { return e; }); if (withdrawalFeesTmp instanceof Error) return result; const withdrawalFees = withdrawalFeesTmp; // console.info(JSON.stringify(withdrawalFees, undefined, 2)); // Rename USDT to USDT-OMNI withdrawalFees .filter((x) => x.currency === 'USDT') .forEach((x) => { x.currency = 'USDT-OMNI'; // eslint-disable-line no-param-reassign }); // Only USDT has '-' withdrawalFees .filter((x) => x.currency.includes('-')) .map((x) => parseCurrency(x.currency)[0]) .forEach((currency) => { assert_1.strict.equal(currency, 'USDT'); }); const depositAddresses = await getDepositAddresses(withdrawalFees .filter((x) => x.min_fee && !x.currency.includes('-')) .map((x) => parseCurrency(x.currency)[0]), true); const tokenPlatformMap = util_1.calcTokenPlatform(depositAddresses); // console.info(withdrawalFees.filter(x => x.currency.includes('-')).map(x => x.currency)); withdrawalFees .filter((x) => x.min_fee) .forEach((x) => { const symbol = parseCurrency(x.currency)[0]; const platform = tokenPlatformMap[symbol] || parseCurrency(x.currency)[1]; if (!(symbol in result)) result[symbol] = {}; result[symbol][platform] = { symbol, platform, fee: parseFloat(x.min_fee), min: x.currency in currencyMap && 'min_withdraw_amount' in currencyMap[x.currency] ? currencyMap[x.currency].min_withdraw_amount : 0.0, }; }); return result; } exports.getWithdrawalFees = getWithdrawalFees; async function fetchCurrencies() { const result = {}; const authClient = createAuthenticatedClient(); const currencies = (await await authClient.account().getCurrencies()); // console.info(JSON.stringify(currencies, undefined, 2)); currencies.forEach((x) => { const symbol = crypto_pair_1.normalizeSymbol(x.currency, 'OKEx'); result[symbol] = { symbol, active: x.can_deposit === '1' && x.can_withdraw === '1', depositEnabled: x.can_deposit === '1', withdrawalEnabled: x.can_withdraw === '1', }; }); return result; } exports.fetchCurrencies = fetchCurrencies; async function withdraw(symbol, address, // only supports existing addresses in your withdrawal address list amount, platform, memo) { const authClient = createAuthenticatedClient(); if (!config_1.USER_CONFIG.OKEX_SPOT_FUND_PASSWORD) return new Error('OKEX_SPOT_FUND_PASSWORD is empty'); const transferData = await authClient .account() .postTransfer({ currency: symbol, amount, from: 1, to: 6 }) .catch((e) => { return e; }); if (transferData instanceof Error) return transferData; const typedTransferData = transferData; if (!typedTransferData.result) return new Error(JSON.stringify(typedTransferData)); const withdrawalFees = await getWithdrawalFees(); if (!(symbol in withdrawalFees)) return new Error(`${symbol} not in withdrawalFees`); const withdrawalFee = withdrawalFees[symbol][platform]; if (withdrawalFee === undefined) { return new Error(`Can NOT find platform ${platform} in withdrawalFees[${symbol}]`); } if (amount < withdrawalFee.min) { return new Error(`amount ${amount} is less than withdrawalFee.min ${withdrawalFee.min}`); } const amountMinusFee = new bignumber_js_1.default(amount - withdrawalFee.fee) .times(new bignumber_js_1.default(10).pow(8)) .integerValue(bignumber_js_1.default.ROUND_DOWN) .div(new bignumber_js_1.default(10).pow(8)); const amountStr = amountMinusFee.toFixed(8); // TODO: precision_on_chain || precision of exchange const withdrawData = await authClient .account() .postWithdrawal({ currency: symbol, amount: amountStr, destination: 4, to_address: memo ? `${address}:${memo}` : address, trade_pwd: config_1.USER_CONFIG.OKEX_SPOT_FUND_PASSWORD, fee: withdrawalFee.fee, }) .catch((e) => { return e; }); if (withdrawData instanceof Error) return withdrawData; const typedWithdrawData = withdrawData; if (typedWithdrawData.result) return typedWithdrawData.withdrawal_id.toString(); return new Error(JSON.stringify(typedWithdrawData)); } exports.withdraw = withdraw;