bitcore-wallet-service
Version:
A service for Mutisig HD Bitcoin Wallets
307 lines • 12.3 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FiatRateService = void 0;
const async = __importStar(require("async"));
const request = __importStar(require("request"));
const common_1 = require("./common");
const fiatrateproviders_1 = require("./fiatrateproviders");
const logger_1 = __importDefault(require("./logger"));
const storage_1 = require("./storage");
const $ = require('preconditions').singleton();
const Defaults = common_1.Common.Defaults;
const Constants = common_1.Common.Constants;
class FiatRateService {
init(opts, cb) {
opts = opts || {};
this.request = opts.request || request;
this.defaultProvider = opts.defaultProvider || Defaults.FIAT_RATE_PROVIDER;
async.parallel([
done => {
if (opts.storage) {
this.storage = opts.storage;
done();
}
else {
this.storage = new storage_1.Storage();
this.storage.connect(opts.storageOpts, done);
}
}
], err => {
if (err) {
logger_1.default.error('%o', err);
}
return cb(err);
});
}
startCron(opts, cb) {
opts = opts || {};
this.providers = fiatrateproviders_1.providers;
const interval = opts.fetchInterval || Defaults.FIAT_RATE_FETCH_INTERVAL;
if (interval) {
this._fetch();
setInterval(() => {
this._fetch();
}, interval * 60 * 1000);
}
return cb();
}
_fetch(cb) {
cb = cb || function () { };
const coins = Object.values(Constants.BITPAY_SUPPORTED_COINS);
const provider = this.providers[0];
async.each(coins, (coin, next2) => {
this._retrieve(provider, coin, (err, res) => {
if (err) {
logger_1.default.warn('Error retrieving data for %o->%o: %o', provider.name, coin, err);
return next2();
}
this.storage.storeFiatRate(coin, res, err => {
if (err) {
logger_1.default.warn('Error storing data for %o: %o', provider.name, err);
}
return next2();
});
});
}, cb);
}
_retrieve(provider, coin, cb) {
logger_1.default.debug(`Fetching data for ${provider.name} / ${coin}`);
const coinUC = coin.toUpperCase();
const handleCoinsRates = (err, res) => {
if (err || !res || res.error) {
return cb(err || new Error('Unable to fetch rates data for ' + provider.name + ' / ' + coin + ': ' + res?.error));
}
logger_1.default.debug(`Data for ${provider.name} / ${coin} fetched successfully`);
if (!provider.parseFn) {
return cb(new Error('No parse function for provider ' + provider.name));
}
try {
const rates = provider.parseFn(res)?.filter(x => Defaults.FIAT_CURRENCIES.some(c => c.code == x.code)) || [];
return cb(null, rates);
}
catch (e) {
return cb(e);
}
};
const ts = Date.now();
if (Constants.BITPAY_USD_STABLECOINS[coinUC]) {
return this.getRatesForStablecoin({ code: 'USD', ts }, handleCoinsRates);
}
if (Constants.BITPAY_EUR_STABLECOINS[coinUC]) {
return this.getRatesForStablecoin({ code: 'EUR', ts }, handleCoinsRates);
}
this.request.get({
url: provider.getUrl(coinUC),
json: true
}, (err, res, body) => handleCoinsRates(err, body));
}
getRate(opts, cb) {
$.shouldBeFunction(cb, 'Failed state: type error (cb not a function) at <getRate()>');
opts = opts || {};
const now = Date.now();
let coin = opts.coin || 'btc';
const ts = !isNaN(opts.ts) || Array.isArray(opts.ts) ? opts.ts : now;
async.map([].concat(ts), (ts, cb) => {
if (coin === 'wbtc') {
logger_1.default.info('Using btc for wbtc rate.');
coin = 'btc';
}
if (coin === 'weth') {
logger_1.default.info('Using eth for weth rate.');
coin = 'eth';
}
this.storage.fetchFiatRate(coin, opts.code, ts, (err, rate) => {
if (err)
return cb(err);
if (rate && ts - rate.ts > Defaults.FIAT_RATE_MAX_LOOK_BACK_TIME * 60 * 1000)
rate = null;
return cb(null, {
ts: +ts,
rate: rate?.value,
fetchedOn: rate?.ts
});
});
}, (err, res) => {
if (err)
return cb(err);
if (!Array.isArray(ts))
res = res[0];
return cb(null, res);
});
}
getRates(opts, cb) {
$.shouldBeFunction(cb, 'Failed state: type error (cb not a function) at <getRates()>');
opts = opts || {};
const now = Date.now();
const ts = opts.ts ? opts.ts : now;
let fiatFiltered = [];
let rates = [];
if (opts.code) {
fiatFiltered = Defaults.FIAT_CURRENCIES.filter(c => c.code === opts.code);
if (!fiatFiltered.length)
return cb(opts.code + ' is not supported');
}
const currencies = fiatFiltered.length ? fiatFiltered : Defaults.FIAT_CURRENCIES;
async.map(Object.values(Constants.BITPAY_SUPPORTED_COINS), (coin, cb) => {
rates[coin] = [];
async.map(currencies, (currency, cb) => {
let c = coin.split('_')[0];
if (c === 'wbtc') {
logger_1.default.info('Using btc for wbtc rate.');
c = 'btc';
}
if (c === 'weth') {
logger_1.default.info('Using eth for weth rate.');
c = 'eth';
}
this.storage.fetchFiatRate(c, currency.code, ts, (err, rate) => {
if (err)
return cb(err);
if (rate && ts - rate.ts > Defaults.FIAT_RATE_MAX_LOOK_BACK_TIME * 60 * 1000)
rate = null;
return cb(null, {
ts: +ts,
rate: rate?.value,
fetchedOn: rate?.ts,
code: currency.code,
name: currency.name
});
});
}, (err, res) => {
if (err)
return cb(err);
var obj = {};
obj[coin] = res;
return cb(null, obj);
});
}, (err, res) => {
if (err)
return cb(err);
return cb(null, Object.assign({}, ...res));
});
}
getRatesByCoin(opts, cb) {
$.shouldBeFunction(cb, 'Failed state: type error (cb not a function) at <getRatesByCoin()>');
let { coin, code } = opts;
const ts = opts.ts || Date.now();
if (Constants.BITPAY_USD_STABLECOINS[coin.toUpperCase()]) {
return this.getRatesForStablecoin({ code: 'USD', ts }, cb);
}
if (Constants.BITPAY_EUR_STABLECOINS[coin.toUpperCase()]) {
return this.getRatesForStablecoin({ code: 'EUR', ts }, cb);
}
let fiatFiltered = [];
if (code) {
fiatFiltered = Defaults.FIAT_CURRENCIES.filter(c => c.code === opts.code);
if (!fiatFiltered.length)
return cb(opts.code + ' is not supported');
}
const currencies = fiatFiltered.length ? fiatFiltered : Defaults.FIAT_CURRENCIES;
async.map(currencies, (currency, cb) => {
if (coin === 'wbtc') {
logger_1.default.info('Using btc for wbtc rate.');
coin = 'btc';
}
if (coin === 'weth') {
logger_1.default.info('Using eth for weth rate.');
coin = 'eth';
}
this.storage.fetchFiatRate(coin, currency.code, ts, (err, rate) => {
if (err)
return cb(err);
if (rate && ts - rate.ts > Defaults.FIAT_RATE_MAX_LOOK_BACK_TIME * 60 * 1000)
rate = null;
return cb(null, {
ts: +ts,
rate: rate?.value,
fetchedOn: rate?.ts,
code: currency.code,
name: currency.name
});
});
}, cb);
}
getHistoricalRates(opts, cb) {
$.shouldBeFunction(cb);
opts = opts || {};
const historicalRates = {};
const now = Date.now() - Defaults.FIAT_RATE_FETCH_INTERVAL * 60 * 1000;
const ts = !isNaN(opts.ts) ? opts.ts : now;
const coins = ['btc', 'bch', 'eth', 'matic', 'xrp', 'doge', 'ltc', 'shib', 'ape', 'sol'];
async.map(coins, (coin, cb) => {
this.storage.fetchHistoricalRates(coin, opts.code, ts, (err, rates) => {
if (err)
return cb(err);
if (!rates)
return cb();
for (const rate of rates) {
rate.rate = rate.value;
delete rate['_id'];
delete rate['code'];
delete rate['value'];
delete rate['coin'];
}
historicalRates[coin] = rates;
return cb(null, historicalRates);
});
}, (err, res) => {
if (err)
return cb(err);
return cb(null, res[0]);
});
}
getRatesForStablecoin(opts, cb) {
$.shouldBeFunction(cb, 'Failed state: type error (cb not a function) at <getRatesForStablecoin()>');
const { coin = 'btc', code } = opts;
const ts = opts.ts || Date.now();
this.getRatesByCoin({ coin, ts }, (err, rates) => {
if (err)
return cb(err);
const fiatRate = rates.find(rate => rate.code === code);
if (!fiatRate || !fiatRate.rate)
return cb(null, []);
return cb(null, rates.map(({ rate, ...obj }) => ({
...obj,
rate: parseFloat((rate / fiatRate.rate).toFixed(2))
})));
});
}
}
exports.FiatRateService = FiatRateService;
//# sourceMappingURL=fiatrateservice.js.map