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) 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 = new BN(1).div(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) .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 }