From 3af6d3a773d3d2eb0bbda37f1b952dee4dbbb9f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Tue, 2 Nov 2021 17:07:26 +0000 Subject: [PATCH] feat: coincap forex api fallback --- lib/forex.js | 59 +++++++++++++++++++++++++++++++++++++- lib/plugins/ticker/ccxt.js | 19 ++++-------- 2 files changed, 63 insertions(+), 15 deletions(-) diff --git a/lib/forex.js b/lib/forex.js index 22dc903a..aa5ce06e 100644 --- a/lib/forex.js +++ b/lib/forex.js @@ -1,5 +1,62 @@ +const _ = require('lodash/fp') const axios = require('axios') +const BN = require('./bn') + +const MAX_ROTATIONS = 5 const getFiatRates = () => axios.get('https://bitpay.com/api/rates').then(response => response.data) -module.exports = { getFiatRates } +const API_QUEUE = [ + { api: getBitPayFxRate, name: 'bitpay', fiatCodeProperty: 'code', rateProperty: 'rate' }, + { api: getCoinCapFxRate, name: 'coincap', fiatCodeProperty: 'symbol', rateProperty: 'rateUsd' } +] + +function getBitPayFxRate (fiatCode, fiatCodeProperty, rateProperty) { + return axios.get('https://bitpay.com/rates') + .then(response => { + const fxRates = response.data.data + const usdRate = findCurrencyRates(fxRates, 'USD', fiatCodeProperty, rateProperty) + const fxRate = findCurrencyRates(fxRates, fiatCode, fiatCodeProperty, rateProperty).div(usdRate) + return { + fxRate + } + }) +} + +function getCoinCapFxRate (fiatCode, fiatCodeProperty, rateProperty) { + return axios.get('https://api.coincap.io/v2/rates') + .then(response => { + const fxRates = response.data.data + const fxRate = findCurrencyRates(fxRates, fiatCode, fiatCodeProperty, rateProperty) + return { + fxRate + } + }) +} + +function findCurrencyRates (fxRates, fiatCode, fiatCodeProperty, rateProperty) { + const rates = _.find(_.matchesProperty(fiatCodeProperty, fiatCode), fxRates) + if (!rates || !rates[rateProperty]) throw new Error(`Unsupported currency: ${fiatCode}`) + return new BN(rates[rateProperty].toString()) +} + +const getRate = (retries = 1, fiatCode) => { + const selected = _.first(API_QUEUE).name + const activeAPI = _.first(API_QUEUE).api + const fiatCodeProperty = _.first(API_QUEUE).fiatCodeProperty + const rateProperty = _.first(API_QUEUE).rateProperty + + if (!activeAPI) throw new Error(`FOREX api ${selected} does not exist.`) + + return activeAPI(fiatCode, fiatCodeProperty, rateProperty).then(res => res) + .catch(() => { + // Switch service + const erroredService = API_QUEUE.shift() + API_QUEUE.push(erroredService) + if (retries >= MAX_ROTATIONS) throw new Error(`FOREX API error from ${erroredService.name}`) + + return getRate(++retries, fiatCode) + }) +} + +module.exports = { getFiatRates, getRate } diff --git a/lib/plugins/ticker/ccxt.js b/lib/plugins/ticker/ccxt.js index d56c1156..4f74f811 100644 --- a/lib/plugins/ticker/ccxt.js +++ b/lib/plugins/ticker/ccxt.js @@ -1,9 +1,10 @@ -const _ = require('lodash/fp') -const axios = require('axios') const ccxt = require('ccxt') const BN = require('../../bn') const { buildMarket, verifyFiatSupport } = require('../common/ccxt') +const { getRate } = require('../../../lib/forex') + +const RETRIES = 2 function ticker (fiatCode, cryptoCode, tickerName) { const ticker = new ccxt[tickerName]({ timeout: 3000 }) @@ -11,13 +12,9 @@ function ticker (fiatCode, cryptoCode, tickerName) { return getCurrencyRates(ticker, fiatCode, cryptoCode) } - return axios.get('https://bitpay.com/rates') - .then(response => { + return getRate(RETRIES, fiatCode) + .then(({ fxRate }) => { try { - const fxRates = response.data.data - const usdRate = findCurrencyRates(fxRates, 'USD') - const fxRate = findCurrencyRates(fxRates, fiatCode).div(usdRate) - return getCurrencyRates(ticker, 'USD', cryptoCode) .then(res => ({ rates: { @@ -49,10 +46,4 @@ function getCurrencyRates (ticker, fiatCode, cryptoCode) { } } -function findCurrencyRates (fxRates, fiatCode) { - const rates = _.find(_.matchesProperty('code', fiatCode), fxRates) - if (!rates || !rates.rate) throw new Error(`Unsupported currency: ${fiatCode}`) - return new BN(rates.rate.toString()) -} - module.exports = { ticker }