crypto-client
Version:
An unified client for all cryptocurrency exchanges.
335 lines (334 loc) • 12.4 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.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;