crypto-client
Version:
An unified client for all cryptocurrency exchanges.
294 lines (293 loc) • 11.3 kB
JavaScript
;
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;