From 7accdaa84fe8b79a105c4821b084792799799960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Mon, 25 Jan 2021 23:51:39 +0000 Subject: [PATCH] Code readability and added the forgotten mocks --- lib/exchange.js | 15 ++++++- lib/plugins/common/ccxt.js | 40 +++++++++-------- lib/plugins/exchange/bitstamp.js | 18 ++++---- lib/plugins/exchange/ccxt.js | 45 +++++++++---------- lib/plugins/exchange/consts.js | 6 +-- lib/plugins/exchange/itbit.js | 18 ++++---- lib/plugins/exchange/kraken.js | 18 ++++---- .../{mock-exchange => }/mock-exchange.js | 4 +- lib/plugins/ticker/{bitpay => }/bitpay.js | 13 ++++-- lib/plugins/ticker/ccxt.js | 26 +++++------ .../ticker/{mock-ticker => }/mock-ticker.js | 4 +- lib/ticker.js | 15 +++++-- 12 files changed, 126 insertions(+), 96 deletions(-) rename lib/plugins/exchange/{mock-exchange => }/mock-exchange.js (69%) rename lib/plugins/ticker/{bitpay => }/bitpay.js (59%) rename lib/plugins/ticker/{mock-ticker => }/mock-ticker.js (58%) diff --git a/lib/exchange.js b/lib/exchange.js index 3b5640ac..a0c36676 100644 --- a/lib/exchange.js +++ b/lib/exchange.js @@ -1,5 +1,6 @@ const configManager = require('./new-config-manager') const ccxt = require('./plugins/exchange/ccxt') +const mockExchange = require('./plugins/exchange/mock-exchange') function lookupExchange (settings, cryptoCode) { const exchange = configManager.getWalletSettings(cryptoCode, settings.config).exchange @@ -20,12 +21,22 @@ function fetchExchange (settings, cryptoCode) { function buy (settings, cryptoAtoms, fiatCode, cryptoCode) { return fetchExchange(settings, cryptoCode) - .then(r => ccxt.trade('buy', r.account, cryptoAtoms, fiatCode, cryptoCode, r.exchangeName)) + .then(r => { + if (r.exchangeName === 'mock-exchange') { + return mockExchange.buy(cryptoAtoms, fiatCode, cryptoCode) + } + return ccxt.trade('buy', r.account, cryptoAtoms, fiatCode, cryptoCode, r.exchangeName) + }) } function sell (settings, cryptoAtoms, fiatCode, cryptoCode) { return fetchExchange(settings, cryptoCode) - .then(r => ccxt.trade('sell', r.account, cryptoAtoms, fiatCode, cryptoCode, r.exchangeName)) + .then(r => { + if (r.exchangeName === 'mock-exchange') { + return mockExchange.sell(cryptoAtoms, fiatCode, cryptoCode) + } + return ccxt.trade('sell', r.account, cryptoAtoms, fiatCode, cryptoCode, r.exchangeName) + }) } function active (settings, cryptoCode) { diff --git a/lib/plugins/common/ccxt.js b/lib/plugins/common/ccxt.js index 0b990f79..47ee37a6 100644 --- a/lib/plugins/common/ccxt.js +++ b/lib/plugins/common/ccxt.js @@ -1,28 +1,32 @@ const _ = require('lodash/fp') -const CRYPTO = { - bitstamp: ['BTC', 'ETH', 'LTC', 'BCH'], - itbit: ['BTC', 'ETH', 'LTC', 'BCH'], - kraken: ['BTC', 'ETH', 'LTC', 'DASH', 'ZEC', 'BCH'], - coinbase: ['BTC', 'ETH', 'LTC', 'BCH', 'ZEC', 'DASH'] +const kraken = require('../exchange/kraken') +const bitstamp = require('../exchange/bitstamp') +const itbit = require('../exchange/itbit') +const bitpay = require('../ticker/bitpay') +const { COINS } = require('../../new-admin/config/coins') +const { BTC, BCH, DASH, ETH, LTC, ZEC } = COINS + +const ALL = { + kraken: kraken, + bitstamp: bitstamp, + itbit: itbit, + bitpay: bitpay, + coinbase: { + CRYPTO: [BTC, ETH, LTC, DASH, ZEC, BCH], + FIAT: 'ALL_CURRENCIES' + } } -const FIAT = { - bitstamp: ['USD', 'EUR'], - itbit: ['USD'], - kraken: ['USD', 'EUR'] -} - -function verifyCurrencies (exchangeName, fiatCode, cryptoCode) { - if (!_.includes(cryptoCode, CRYPTO[exchangeName])) { +function buildMarket (fiatCode, cryptoCode, serviceName) { + if (!_.includes(cryptoCode, ALL[serviceName].CRYPTO)) { throw new Error('Unsupported crypto: ' + cryptoCode) } - if (exchangeName !== 'coinbase') { - if (!_.includes(fiatCode, FIAT[exchangeName])) { - throw new Error('Unsupported fiat: ' + fiatCode) - } + const fiatSupported = ALL[serviceName].FIAT + if (fiatSupported !== 'ALL_CURRENCIES' && !_.includes(fiatCode, fiatSupported)) { + throw new Error('Unsupported fiat: ' + fiatCode) } return cryptoCode + '/' + fiatCode } -module.exports = { verifyCurrencies, CRYPTO, FIAT } +module.exports = { buildMarket, ALL } diff --git a/lib/plugins/exchange/bitstamp.js b/lib/plugins/exchange/bitstamp.js index 7e9d9086..6a88d223 100644 --- a/lib/plugins/exchange/bitstamp.js +++ b/lib/plugins/exchange/bitstamp.js @@ -1,9 +1,13 @@ -const common = require('../common/ccxt') const _ = require('lodash/fp') -const consts = require('./consts') -const ORDER_TYPE = consts.ORDER_TYPES.MARKET -const FIAT = common.FIAT['kraken'] -const CRYPTO = common.CRYPTO['kraken'] + +const { ORDER_TYPES } = require('./consts') +const { COINS } = require('../../new-admin/config/coins') + +const ORDER_TYPE = ORDER_TYPES.MARKET +const { BTC, ETH, LTC, BCH } = COINS +const CRYPTO = [BTC, ETH, LTC, BCH] +const FIAT = ['USD', 'EUR'] +const AMOUNT_PRECISION = 8 const loadConfig = (account) => { const mapper = { @@ -16,6 +20,4 @@ const loadConfig = (account) => { const isConfigValid = ({ key, clientId, secret }) => key && secret && clientId -const amountPrecision = () => 8 - -module.exports = { loadConfig, isConfigValid, amountPrecision , CRYPTO, FIAT, ORDER_TYPE } +module.exports = { loadConfig, isConfigValid, CRYPTO, FIAT, ORDER_TYPE, AMOUNT_PRECISION } diff --git a/lib/plugins/exchange/ccxt.js b/lib/plugins/exchange/ccxt.js index 9f90756b..4bfa2951 100644 --- a/lib/plugins/exchange/ccxt.js +++ b/lib/plugins/exchange/ccxt.js @@ -1,37 +1,34 @@ -var ccxt = require('ccxt') -const coinUtils = require('../../coin-utils') -const common = require('../common/ccxt') -const kraken = require('./kraken') -const bitstamp = require('./bitstamp') -const itbit = require('./itbit') -const consts = require('./consts') +const _ = require('lodash/fp') +const ccxt = require('ccxt') -const ALL_EXCHANGES = { - kraken, - bitstamp, - itbit -} +const { toUnit } = require('../../coin-utils') +const { buildMarket, ALL } = require('../common/ccxt') +const { ORDER_TYPES } = require('./consts') + +const DEFAULT_PRICE_PRECISION = 2 +const DEFAULT_AMOUNT_PRECISION = 8 function trade (side, account, cryptoAtoms, fiatCode, cryptoCode, exchangeName) { try { - const exchangeConfig = ALL_EXCHANGES[exchangeName] + const exchangeConfig = ALL[exchangeName] + if (!exchangeConfig) throw Error('Exchange configuration not found') - if (!exchangeConfig) throw Error('no exchange') - if (exchangeConfig.isConfigValid && !exchangeConfig.isConfigValid(account)) throw Error('Invalid config') + const { loadOptions, loadConfig = _.noop, isConfigValid, ORDER_TYPE, AMOUNT_PRECISION } = exchangeConfig + if (_.isFunction(isConfigValid) && !isConfigValid(account)) throw Error('Invalid config') - const exchange = new ccxt[exchangeName](exchangeConfig.loadConfig(account)) + const symbol = buildMarket(fiatCode, cryptoCode, exchangeName) + const precision = _.defaultTo(DEFAULT_AMOUNT_PRECISION, AMOUNT_PRECISION) + const amount = toUnit(cryptoAtoms, cryptoCode).toFixed(precision) + const options = _.isFunction(loadOptions) ? loadOptions(account) : {} + const exchange = new ccxt[exchangeName](loadConfig(account)) - const symbol = common.verifyCurrencies(exchangeName, fiatCode, cryptoCode) - const precision = exchangeConfig.amountPrecision ? exchangeConfig.amountPrecision() : consts.DECIMAL_PRECISION.DEFAULT_AMOUNT - const amount = coinUtils.toUnit(cryptoAtoms, cryptoCode).toFixed(precision) - const options = exchangeConfig.loadOptions ? exchangeConfig.loadOptions(account) : {} - if (exchangeConfig.ORDER_TYPE === consts.ORDER_TYPES.MARKET) { - return exchange.createOrder(symbol, consts.ORDER_TYPES.MARKET, side, amount, null, options) + if (ORDER_TYPE === ORDER_TYPES.MARKET) { + return exchange.createOrder(symbol, ORDER_TYPES.MARKET, side, amount, null, options) } return exchange.fetchOrderBook(symbol) .then(orderBook => { - const price = calculatePrice(side, amount, orderBook).toFixed(consts.DECIMAL_PRECISION.PRICE) - return exchange.createOrder(symbol, consts.ORDER_TYPES.LIMIT, side, amount, price, options) + const price = calculatePrice(side, amount, orderBook).toFixed(DEFAULT_PRICE_PRECISION) + return exchange.createOrder(symbol, ORDER_TYPES.LIMIT, side, amount, price, options) }) } catch (e) { return Promise.reject(e) diff --git a/lib/plugins/exchange/consts.js b/lib/plugins/exchange/consts.js index 31ffea71..690b75c9 100644 --- a/lib/plugins/exchange/consts.js +++ b/lib/plugins/exchange/consts.js @@ -3,9 +3,5 @@ const ORDER_TYPES = { MARKET: 'market', LIMIT: 'limit' } -const DECIMAL_PRECISION = { - PRICE: 2, - DEFAULT_AMOUNT: 8 -} -module.exports = { ORDER_TYPES, DECIMAL_PRECISION } +module.exports = { ORDER_TYPES } diff --git a/lib/plugins/exchange/itbit.js b/lib/plugins/exchange/itbit.js index 61b80d90..9c559249 100644 --- a/lib/plugins/exchange/itbit.js +++ b/lib/plugins/exchange/itbit.js @@ -1,9 +1,13 @@ -const common = require('../common/ccxt') const _ = require('lodash/fp') -const consts = require('./consts') -const ORDER_TYPE = consts.ORDER_TYPES.LIMIT -const FIAT = common.FIAT['kraken'] -const CRYPTO = common.CRYPTO['kraken'] + +const { ORDER_TYPES } = require('./consts') +const { COINS } = require('../../new-admin/config/coins') // para cada exchange + +const ORDER_TYPE = ORDER_TYPES.LIMIT +const { BTC, ETH, LTC, BCH } = COINS +const CRYPTO = [BTC, ETH, LTC, BCH] +const FIAT = ['USD'] +const AMOUNT_PRECISION = 4 const loadConfig = (account) => { const mapper = { @@ -17,6 +21,4 @@ const loadConfig = (account) => { const loadOptions = ({ walletId }) => ({ walletId }) const isConfigValid = ({ clientKey, clientSecret, userId, walletId }) => clientKey && clientSecret && userId && walletId -const amountPrecision = () => 4 - -module.exports = { amountPrecision, loadOptions, loadConfig, isConfigValid, CRYPTO, FIAT, ORDER_TYPE } +module.exports = { loadOptions, loadConfig, isConfigValid, CRYPTO, FIAT, ORDER_TYPE, AMOUNT_PRECISION } diff --git a/lib/plugins/exchange/kraken.js b/lib/plugins/exchange/kraken.js index 3491820d..e766fdc3 100644 --- a/lib/plugins/exchange/kraken.js +++ b/lib/plugins/exchange/kraken.js @@ -1,9 +1,13 @@ -const common = require('../common/ccxt') const _ = require('lodash/fp') -const consts = require('./consts') -const ORDER_TYPE = consts.ORDER_TYPES.MARKET -const FIAT = common.FIAT['kraken'] -const CRYPTO = common.CRYPTO['kraken'] + +const { ORDER_TYPES } = require('./consts') +const { COINS } = require('../../new-admin/config/coins') + +const ORDER_TYPE = ORDER_TYPES.MARKET +const { BTC, BCH, DASH, ETH, LTC, ZEC } = COINS +const CRYPTO = [BTC, ETH, LTC, DASH, ZEC, BCH] +const FIAT = ['USD', 'EUR'] +const AMOUNT_PRECISION = 6 const loadConfig = (account) => { const mapper = { @@ -16,6 +20,4 @@ const loadConfig = (account) => { const loadOptions = () => ({ expiretm: '+60' }) const isConfigValid = ({ apiKey, privateKey }) => apiKey && privateKey -const amountPrecision = () => 6 - -module.exports = { amountPrecision, loadOptions, loadConfig, isConfigValid, CRYPTO, FIAT, ORDER_TYPE } +module.exports = { loadOptions, loadConfig, isConfigValid, CRYPTO, FIAT, ORDER_TYPE, AMOUNT_PRECISION } diff --git a/lib/plugins/exchange/mock-exchange/mock-exchange.js b/lib/plugins/exchange/mock-exchange.js similarity index 69% rename from lib/plugins/exchange/mock-exchange/mock-exchange.js rename to lib/plugins/exchange/mock-exchange.js index 42c3e9a2..bdf287da 100644 --- a/lib/plugins/exchange/mock-exchange/mock-exchange.js +++ b/lib/plugins/exchange/mock-exchange.js @@ -3,12 +3,12 @@ module.exports = { sell } -function buy (account, cryptoAtoms, fiatCode, cryptoCode) { +function buy (cryptoAtoms, fiatCode, cryptoCode) { console.log('[mock] buying %s %s for %s', cryptoAtoms.toString(), cryptoCode, fiatCode) return Promise.resolve() } -function sell (account, cryptoAtoms, fiatCode, cryptoCode) { +function sell (cryptoAtoms, fiatCode, cryptoCode) { console.log('[mock] selling %s %s for %s', cryptoAtoms.toString(), cryptoCode, fiatCode) return Promise.resolve() } diff --git a/lib/plugins/ticker/bitpay/bitpay.js b/lib/plugins/ticker/bitpay.js similarity index 59% rename from lib/plugins/ticker/bitpay/bitpay.js rename to lib/plugins/ticker/bitpay.js index 099ed3be..6a758463 100644 --- a/lib/plugins/ticker/bitpay/bitpay.js +++ b/lib/plugins/ticker/bitpay.js @@ -1,7 +1,12 @@ const axios = require('axios') -const BN = require('../../../bn') -function ticker (account, fiatCode, cryptoCode) { +const BN = require('../../bn') +const { BTC, BCH } = require('../../new-admin/config/coins') + +const CRYPTO = [BTC, BCH] +const FIAT = 'ALL_CURRENCIES' + +function ticker (fiatCode, cryptoCode) { return axios.get('https://bitpay.com/rates/' + cryptoCode + '/' + fiatCode) .then(r => { const data = r.data.data @@ -17,5 +22,7 @@ function ticker (account, fiatCode, cryptoCode) { module.exports = { ticker, - name: 'BitPay' + name: 'BitPay', + CRYPTO, + FIAT } diff --git a/lib/plugins/ticker/ccxt.js b/lib/plugins/ticker/ccxt.js index 2d3f498a..2cdbf535 100644 --- a/lib/plugins/ticker/ccxt.js +++ b/lib/plugins/ticker/ccxt.js @@ -1,14 +1,14 @@ -const ccxt = require('ccxt') -const BN = require('../../bn') -const axios = require('axios') const _ = require('lodash/fp') -const common = require('../common/ccxt') +const axios = require('axios') +const ccxt = require('ccxt') -function ticker (exchangeName, fiatCode, cryptoCode) { - const exchange = new ccxt[exchangeName]() +const BN = require('../../bn') +const { buildMarket } = require('../common/ccxt') - if (fiatCode === 'EUR' || fiatCode === 'USD' || exchange.id === 'coinbase') { - return getCurrencyRates(exchange, fiatCode, cryptoCode) +function ticker (fiatCode, cryptoCode, tickerName) { + const ticker = new ccxt[tickerName]({ timeout: 3000 }) + if (fiatCode === 'EUR' || fiatCode === 'USD' || ticker.id === 'coinbase') { + return getCurrencyRates(ticker, fiatCode, cryptoCode) } return axios.get('https://bitpay.com/rates') @@ -18,7 +18,7 @@ function ticker (exchangeName, fiatCode, cryptoCode) { const usdRate = findCurrencyRates(fxRates, 'USD') const fxRate = findCurrencyRates(fxRates, fiatCode).div(usdRate) - return getCurrencyRates(exchange, 'USD', cryptoCode) + return getCurrencyRates(ticker, 'USD', cryptoCode) .then(res => ({ rates: { ask: res.rates.ask.times(fxRate), @@ -31,11 +31,11 @@ function ticker (exchangeName, fiatCode, cryptoCode) { }) } -function getCurrencyRates (exchange, fiatCode, cryptoCode) { +function getCurrencyRates (ticker, fiatCode, cryptoCode) { try { - if (exchange.has['fetchTicker']) { - const symbol = common.verifyCurrencies(exchange.id, fiatCode, cryptoCode) - return exchange.fetchTicker(symbol) + if (ticker.has['fetchTicker']) { + const symbol = buildMarket(fiatCode, cryptoCode, ticker.id) + return ticker.fetchTicker(symbol) .then(res => ({ rates: { ask: BN(res.ask), diff --git a/lib/plugins/ticker/mock-ticker/mock-ticker.js b/lib/plugins/ticker/mock-ticker.js similarity index 58% rename from lib/plugins/ticker/mock-ticker/mock-ticker.js rename to lib/plugins/ticker/mock-ticker.js index 49470e90..703630d6 100644 --- a/lib/plugins/ticker/mock-ticker/mock-ticker.js +++ b/lib/plugins/ticker/mock-ticker.js @@ -1,6 +1,6 @@ -const BN = require('../../../bn') +const BN = require('../../bn') -function ticker (account, fiatCode, cryptoCode) { +function ticker (fiatCode, cryptoCode) { return Promise.resolve({ rates: { ask: BN(105), diff --git a/lib/ticker.js b/lib/ticker.js index 7c4ccb72..c032a079 100644 --- a/lib/ticker.js +++ b/lib/ticker.js @@ -1,19 +1,22 @@ const mem = require('mem') const configManager = require('./new-config-manager') const logger = require('./logger') -const ccxt = require('./plugins/ticker/ccxt') const lastRate = {} +const ccxt = require('./plugins/ticker/ccxt') +const mockTicker = require('./plugins/ticker/mock-ticker') +const bitpay = require('./plugins/ticker/bitpay') + const FETCH_INTERVAL = 60000 function _getRates (settings, fiatCode, cryptoCode) { return Promise.resolve() .then(() => { const config = settings.config - const exchangeName = configManager.getWalletSettings(cryptoCode, config).ticker + const tickerName = configManager.getWalletSettings(cryptoCode, config).ticker const market = [cryptoCode, fiatCode].join('-') - return ccxt.ticker(exchangeName, fiatCode, cryptoCode) + return buildTicker(fiatCode, cryptoCode, tickerName) .then(r => ({ rates: r.rates, timestamp: Date.now() @@ -29,6 +32,12 @@ function _getRates (settings, fiatCode, cryptoCode) { }) } +function buildTicker (fiatCode, cryptoCode, tickerName) { + if (tickerName === 'bitpay') return bitpay.ticker(fiatCode, cryptoCode) + if (tickerName === 'mock-ticker') return mockTicker.ticker(fiatCode, cryptoCode) + return ccxt.ticker(fiatCode, cryptoCode, tickerName) +} + const getRates = mem(_getRates, { maxAge: FETCH_INTERVAL, cacheKey: (settings, fiatCode, cryptoCode) => JSON.stringify([fiatCode, cryptoCode])