84 lines
2 KiB
JavaScript
84 lines
2 KiB
JavaScript
const _ = require('lodash/fp')
|
|
const axios = require('axios')
|
|
const mem = require('mem')
|
|
|
|
const BN = require('./bn')
|
|
const T = require('./time')
|
|
|
|
const MAX_ROTATIONS = 5
|
|
|
|
const _getFiatRates = () =>
|
|
axios.get('https://bitpay.com/api/rates').then(response => response.data)
|
|
|
|
const getFiatRates = mem(_getFiatRates, {
|
|
maxAge: 6 * T.hours,
|
|
cacheKey: () => '',
|
|
})
|
|
|
|
const API_QUEUE = [
|
|
{
|
|
api: getBitPayFxRate,
|
|
name: 'bitpay',
|
|
fiatCodeProperty: 'code',
|
|
rateProperty: 'rate',
|
|
},
|
|
]
|
|
|
|
function getBitPayFxRate(
|
|
fiatCode,
|
|
defaultFiatMarket,
|
|
fiatCodeProperty,
|
|
rateProperty,
|
|
) {
|
|
return getFiatRates().then(fxRates => {
|
|
const defaultFiatRate = findCurrencyRates(
|
|
fxRates,
|
|
defaultFiatMarket,
|
|
fiatCodeProperty,
|
|
rateProperty,
|
|
)
|
|
const fxRate = findCurrencyRates(
|
|
fxRates,
|
|
fiatCode,
|
|
fiatCodeProperty,
|
|
rateProperty,
|
|
).div(defaultFiatRate)
|
|
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, defaultFiatMarket) => {
|
|
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,
|
|
defaultFiatMarket,
|
|
fiatCodeProperty,
|
|
rateProperty,
|
|
).catch(err => {
|
|
const erroredService = API_QUEUE.shift()
|
|
API_QUEUE.push(erroredService)
|
|
if (retries >= MAX_ROTATIONS)
|
|
throw new Error(
|
|
`FOREX API error from ${erroredService.name} ${err?.message}`,
|
|
)
|
|
|
|
return getRate(++retries, fiatCode, defaultFiatMarket)
|
|
})
|
|
}
|
|
|
|
module.exports = { getFiatRates, getRate }
|