UNPKG

crypto-client

Version:

An unified client for all cryptocurrency exchanges.

294 lines (293 loc) 11.3 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.getWithdrawalFees = exports.getDepositAddresses = exports.fetchDepositAddress = exports.queryAllBalances = exports.queryAllBalancesV2 = exports.queryOrder = exports.cancelOrder = exports.placeOrder = void 0; const assert_1 = require("assert"); const axios_1 = __importDefault(require("axios")); const crypto_pair_1 = require("crypto-pair"); const config_1 = require("../config"); const util_1 = require("../util"); const { RESTv1, RESTv2 } = require('bfx-api-node-rest'); const { Order } = require('bfx-api-node-models'); function createAuthenticatedClient(version = 'v2') { assert_1.strict.ok(config_1.USER_CONFIG.BITFINEX_API_KEY); assert_1.strict.ok(config_1.USER_CONFIG.BITFINEX_API_SECRET); const rest = version === 'v2' ? new RESTv2({ apiKey: config_1.USER_CONFIG.BITFINEX_API_KEY, apiSecret: config_1.USER_CONFIG.BITFINEX_API_SECRET, transform: true, }) : new RESTv1({ apiKey: config_1.USER_CONFIG.BITFINEX_API_KEY, apiSecret: config_1.USER_CONFIG.BITFINEX_API_SECRET, }); return rest; } 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 order = { type: 'EXCHANGE LIMIT', symbol: `t${market.id.toUpperCase()}`, price: priceStr, amount: `${sell ? '-' : ''}${quantityStr}`, }; if (clientOrderId) { order.cid = parseInt(clientOrderId, 10); } const authClient = createAuthenticatedClient(); const arr = await authClient.submitOrder(new Order(order)).catch((e) => { return e; }); if (arr instanceof Error) return arr; return arr[0].toString(); } catch (e) { return e; } } exports.placeOrder = placeOrder; async function cancelOrder(orderId) { const authClient = createAuthenticatedClient(); try { const arr = (await authClient.cancelOrder(parseInt(orderId, 10))); const order = Order.unserialize(arr); return order.id === parseInt(orderId, 10); } catch (e) { return false; } } exports.cancelOrder = cancelOrder; async function queryOrder(orderId) { const authClient = createAuthenticatedClient(); // eslint-disable-next-line no-underscore-dangle const arr = await authClient._makeAuthRequest('/auth/r/orders', { id: [parseInt(orderId, 10)] }, undefined, Order); if (arr.length === 0) return undefined; assert_1.strict.equal(arr.length, 1); return arr[0]; } exports.queryOrder = queryOrder; async function queryAllBalancesV2(all = false) { const authClient = createAuthenticatedClient(); const wallets = await authClient.wallets().catch((e) => { return e; }); if (wallets instanceof Error) return wallets; const arr = wallets.filter((x) => !all && x.type === 'exchange'); const result = {}; arr.forEach((x) => { const pair = crypto_pair_1.normalizeSymbol(x.currency, 'Bitfinex'); result[pair] = x.balance; }); return result; } exports.queryAllBalancesV2 = queryAllBalancesV2; async function queryAllBalances(all = false) { const authClient = createAuthenticatedClient('v1'); const arr = await new Promise((resolve, reject) => { authClient.wallet_balances((err, data) => { if (err) reject(err); else resolve(data); }); }).catch((e) => { return e; }); if (arr instanceof Error) return arr; const result = {}; arr.forEach((x) => { const symbol = crypto_pair_1.normalizeSymbol(x.currency, 'Bitfinex'); result[symbol] = parseFloat(all ? x.amount : x.available); }); return result; } exports.queryAllBalances = queryAllBalances; async function fetchDepositAddress(symbolOrLabel) { try { const client = createAuthenticatedClient(); const data = await client.getDepositAddress({ wallet: 'exchange', method: symbolOrLabel, opRenew: 0, }); return data.notifyInfo[5] ? { address: data.notifyInfo[5], memo: data.notifyInfo[4], } : { address: data.notifyInfo[4], }; } catch (e) { return e; } } exports.fetchDepositAddress = fetchDepositAddress; const USDT_METHOD_MAP = { OMNI: 'tetheruso', ERC20: 'tetheruse', TRC20: 'tetherusx', EOS: 'tetheruss', LIQUID: 'tetherusl', }; async function fetchMethod() { const response = await axios_1.default.get('https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method'); assert_1.strict.equal(response.status, 200); const symbolMethodMap = {}; const arr = response.data[0]; arr.forEach((x) => { assert_1.strict.equal(x.length, 2); const [method, currencies] = x; currencies.forEach((rawSymbol) => { if (rawSymbol === 'USD') return; // skip USD // BCH is now fully replaced by BAB when using API, ["BCH","Bitcoin Cash"] // will be removed, quoted from custom support. if (rawSymbol === 'BCH') return; // BAB is BCH at Bitfinex const symbol = crypto_pair_1.normalizeSymbol(rawSymbol, 'Bitfinex'); symbolMethodMap[symbol] = { method: method.toLowerCase(), rawSymbol, }; }); }); return symbolMethodMap; } async function getDepositAddresses(symbols) { assert_1.strict.ok(symbols.length); const ethAddress = (await fetchDepositAddress('Ethereum')).address; const trxAddress = (await fetchDepositAddress('TRX')).address; assert_1.strict.ok(ethAddress); assert_1.strict.ok(trxAddress); const symbolMethodMap = await fetchMethod(); // console.info(symbolMethodMap); const result = {}; for (let i = 0; i < symbols.length; i += 1) { const symbol = symbols[i]; const symbolOrLabels = symbol === 'USDT' ? Object.values(USDT_METHOD_MAP).map((x) => x.toLowerCase()) : [symbol in symbolMethodMap ? symbolMethodMap[symbol].method : symbol]; for (let j = 0; j < symbolOrLabels.length; j += 1) { // eslint-disable-next-line no-await-in-loop const address = await fetchDepositAddress(symbolOrLabels[j]); if (!(address instanceof Error)) { if (!(symbol in result)) result[symbol] = {}; let platform = symbol; if (address.address === ethAddress && symbol !== 'ETH' && symbol !== 'ETC') { platform = 'ERC20'; assert_1.strict.equal(platform, util_1.detectPlatform(address.address, symbol)); } if (address.address === trxAddress && symbol !== 'TRX') { platform = symbol === 'BTT' ? 'TRC10' : 'TRC20'; assert_1.strict.equal(platform, util_1.detectPlatform(address.address, symbol)); } result[symbol][platform] = Object.assign({ symbol, platform }, address); } else { // console.error(address); } } } return result; } exports.getDepositAddresses = getDepositAddresses; async function getWithdrawalFees() { const client = createAuthenticatedClient(); const data = (await client.accountFees()); Object.keys(data.withdraw).forEach((rawSymbol) => { const normalizedSymbol = crypto_pair_1.normalizeSymbol(rawSymbol, 'Bitfinex'); data.withdraw[normalizedSymbol] = data.withdraw[rawSymbol]; }); const depositAddresses = await getDepositAddresses(Object.keys(data.withdraw).map((rawSymbol) => crypto_pair_1.normalizeSymbol(rawSymbol, 'Bitfinex'))); const tokenPlatformMap = util_1.calcTokenPlatform(depositAddresses); const result = {}; Object.keys(data.withdraw).forEach((rawSymbol) => { const symbol = crypto_pair_1.normalizeSymbol(rawSymbol, 'Bitfinex'); if (!(symbol in result)) result[symbol] = {}; const platform = tokenPlatformMap[symbol] || symbol; result[symbol][platform] = { symbol, platform: tokenPlatformMap[symbol] || symbol, fee: parseFloat(data.withdraw[symbol]), min: 0, }; }); return result; } exports.getWithdrawalFees = getWithdrawalFees; async function fetchUSDPrice(symbol, symbolMethodMap) { const rawSymbol = symbol in symbolMethodMap ? symbolMethodMap[symbol].rawSymbol : symbol; const response = await axios_1.default.get(`https://api-pub.bitfinex.com/v2/ticker/t${rawSymbol}USD`); assert_1.strict.equal(response.status, 200); if (response.data[0] === 'error') return -1; const arr = response.data; return arr[6]; } async function withdrawV1(withdraw_type, walletselected, address, amount, payment_id) { assert_1.strict.ok(payment_id); const parameters = { withdraw_type, walletselected, address, amount: amount.toString(), payment_id, }; const arr = await new Promise((resolve, reject) => { createAuthenticatedClient('v1').make_request('withdraw', parameters, (err, data) => { if (err) reject(err); else resolve(data); }); }).catch((e) => { return e; }); if (arr instanceof Error) return arr; if (arr.length !== 1) return new Error('Returned more than one item'); return arr[0].withdrawal_id.toString(); } async function withdraw(symbol, address, amount, platform, memo, params = {}) { if (!params.wallet) return new Error('wallet should be one of exchange, margin and funding'); const symbolMethodMap = await fetchMethod(); const price = await fetchUSDPrice(symbol, symbolMethodMap); if (amount * price < 5) return new Error(`${amount} ${symbol} value is less than 5 USD. Current price is $${price}`); const method = symbol === 'USDT' ? USDT_METHOD_MAP[platform] : symbolMethodMap[symbol].method; if (method === undefined) return new Error(`Bitfinex ${symbol} can NOT find method`); if (memo) return withdrawV1(method, params.wallet, address, amount, memo); Object.assign(params, { address, amount: amount.toString(), method }); if (memo) params.memo = memo; // eslint-disable-line no-param-reassign const data = await createAuthenticatedClient() .withdraw(params) .catch((e) => { return e; }); if (data instanceof Error) return data; assert_1.strict.equal(data.status, 'SUCCESS'); if (data.notifyInfo[0] === 0) return new Error(data.text); return data.notifyInfo[0].toString(); } exports.withdraw = withdraw;