UNPKG

@abcpros/bitcore-wallet-service

Version:
514 lines 24.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (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 (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __spreadArrays = (this && this.__spreadArrays) || function () { for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; for (var r = Array(s), k = 0, i = 0; i < il; i++) for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j]; return r; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.FiatRateService = void 0; var async = __importStar(require("async")); var lodash_1 = __importDefault(require("lodash")); var request = __importStar(require("request")); var storage_1 = require("./storage"); var $ = require('preconditions').singleton(); var Common = require('./common'); var Defaults = Common.Defaults; var Constants = Common.Constants; var config = require('../config'); var Bitcore = require('@abcpros/bitcore-lib'); var ELECTRICITY_RATE = config.fiatRateServiceOpts.lotusFormula.ELECTRICITY_RATE; var MINER_MARGIN = config.fiatRateServiceOpts.lotusFormula.MINER_MARGIN; var RIG_HASHRATE = config.fiatRateServiceOpts.lotusFormula.RIG_HASHRATE; var RIG_POWER = config.fiatRateServiceOpts.lotusFormula.RIG_POWER; var MINING_EFFICIENCY = RIG_HASHRATE / RIG_POWER; var blockchainexplorer_1 = require("./blockchainexplorer"); var logger_1 = __importDefault(require("./logger")); var FiatRateService = (function () { function FiatRateService() { this.cryptoCompareApiKey = ''; } FiatRateService.prototype.init = function (opts, cb) { var _this = this; opts = opts || {}; this.request = opts.request || request; this.defaultProvider = opts.defaultProvider || Defaults.FIAT_RATE_PROVIDER; this.cryptoCompareApiKey = opts.cryptoCompareApiKey; async.parallel([ function (done) { if (opts.storage) { _this.storage = opts.storage; done(); } else { _this.storage = new storage_1.Storage(); _this.storage.connect(opts.storageOpts, done); } } ], function (err) { if (err) { logger_1.default.error(err); } return cb(err); }); }; FiatRateService.prototype.startCron = function (opts, cb) { var _this = this; opts = opts || {}; this.providers = lodash_1.default.values(require('./fiatrateproviders')); var interval = opts.fetchInterval || Defaults.FIAT_RATE_FETCH_INTERVAL; if (interval) { this._fetch(); setInterval(function () { _this._fetch(); }, interval * 60 * 1000); } return cb(); }; FiatRateService.prototype.handleRateCurrencyCoin = function (res, listRate) { return __awaiter(this, void 0, void 0, function () { var newData, valueUsd; return __generator(this, function (_a) { newData = []; valueUsd = lodash_1.default.get(lodash_1.default.find(res, function (item) { return item.code == 'USD'; }), 'value', 0); return [2, new Promise(function (resolve, reject) { lodash_1.default.forEach(listRate, function (rate) { newData.push({ code: rate.code, value: valueUsd * rate.value }); }); return resolve(newData); })]; }); }); }; FiatRateService.prototype._getProviderRate = function (coin) { var nameProvider = this.defaultProvider; var etoken = this._getEtokenSupportPrice(); if (coin == 'xpi') { nameProvider = 'LotusExbitron'; } else if (lodash_1.default.includes(etoken, coin)) { nameProvider = 'EtokenPrice'; } else { nameProvider = this.defaultProvider; } return lodash_1.default.find(this.providers, function (provider) { return provider.name === nameProvider; }); }; FiatRateService.prototype.getLatestCurrencyRates = function (opts) { var _this = this; return new Promise(function (resolve, reject) { var now = Date.now(); var ts = opts.ts ? opts.ts : now; var fiatFiltered = []; var rates = []; if (opts.code) { fiatFiltered = lodash_1.default.filter(Defaults.FIAT_CURRENCIES, ['code', opts.code]); if (!fiatFiltered.length) return reject(opts.code + ' is not supported'); } var currencies = fiatFiltered.length ? fiatFiltered : Defaults.SUPPORT_FIAT_CURRENCIES; var promiseList = []; lodash_1.default.forEach(currencies, function (currency) { promiseList.push(_this._getCurrencyRate(currency.code, ts)); }); Promise.all(promiseList).then(function (listRate) { return resolve(listRate); }); }); }; FiatRateService.prototype._getCurrencyRate = function (code, ts) { var _this = this; return new Promise(function (resolve, reject) { _this.storage.fetchCurrencyRates(code, ts, function (err, res) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { if (err) { logger_1.default.warn('Error fetching data for ' + code, err); } return [2, resolve(res)]; }); }); }); }); }; FiatRateService.prototype._getEtokenSupportPrice = function () { var etokenSupportPrice = lodash_1.default.get(config, 'etoken.etokenSupportPrice', undefined); if (!etokenSupportPrice) return []; return lodash_1.default.map(etokenSupportPrice, 'coin'); }; FiatRateService.prototype._fetch = function (cb) { return __awaiter(this, void 0, void 0, function () { var coinsData, etoken, coins, listRate; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: cb = cb || function () { }; coinsData = ['btc', 'bch', 'xec', 'eth', 'xrp', 'doge', 'xpi', 'ltc']; etoken = this._getEtokenSupportPrice(); coins = lodash_1.default.concat(coinsData, etoken); return [4, this.getLatestCurrencyRates({})]; case 1: listRate = _a.sent(); if (listRate) { async.eachSeries(coins, function (coin, next2) { return __awaiter(_this, void 0, void 0, function () { var provider; var _this = this; return __generator(this, function (_a) { provider = this._getProviderRate(coin); this._retrieve(provider, coin, function (err, res) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: if (err) { logger_1.default.warn('Error retrieving data for ' + provider.name + coin, err); return [2, next2()]; } return [4, this.handleRateCurrencyCoin(res, listRate)]; case 1: res = _a.sent(); this.storage.storeFiatRate(coin, res, function (err) { if (err) { logger_1.default.warn('Error storing data for ' + provider.name, err); } return next2(); }); return [2]; } }); }); }); return [2]; }); }); }, cb); } return [2]; } }); }); }; FiatRateService.prototype._retrieve = function (provider, coin, cb) { var _a; return __awaiter(this, void 0, void 0, function () { var params, appendString, headers, etokenSupportPrice, currencyRate, body, rates, e_1; return __generator(this, function (_b) { switch (_b.label) { case 0: if (coin === 'xpi') { return [2, this._retrieveLotus(cb)]; } logger_1.default.debug("Fetching data for " + provider.name + " / " + coin + " "); params = []; appendString = ''; headers = (_a = provider.headers) !== null && _a !== void 0 ? _a : ''; if (!(provider.name === 'CryptoCompare')) return [3, 1]; params = provider.params; params['fsym'] = coin.toUpperCase(); return [3, 12]; case 1: if (!(provider.name === 'Coingecko')) return [3, 2]; params = provider.params; params['ids'] = provider.coinMapping[coin]; return [3, 12]; case 2: if (!(provider.name === 'LotusExplorer')) return [3, 3]; appendString = ''; return [3, 12]; case 3: if (!(provider.name === 'LotusExbitron')) return [3, 4]; appendString = ''; return [3, 12]; case 4: if (!(provider.name === 'EtokenPrice')) return [3, 11]; _b.label = 5; case 5: _b.trys.push([5, 9, , 10]); etokenSupportPrice = lodash_1.default.get(config, 'etoken.etokenSupportPrice', []); if (!etokenSupportPrice) return [2, cb('no etoken supported')]; currencyRate = null; if (!(coin.toLowerCase() === 'elps')) return [3, 7]; return [4, this.getLatestCurrencyRates({ code: 'HNL' })]; case 6: currencyRate = _b.sent(); _b.label = 7; case 7: return [4, provider.getRate(coin, etokenSupportPrice, currencyRate && currencyRate[0] ? currencyRate[0] : null)]; case 8: body = _b.sent(); rates = lodash_1.default.filter(body, function (x) { return lodash_1.default.some(Defaults.FIAT_CURRENCIES, ['code', x.code]); }); return [2, cb(null, rates)]; case 9: e_1 = _b.sent(); return [2, cb(e_1)]; case 10: return [3, 12]; case 11: appendString = coin.toUpperCase(); _b.label = 12; case 12: this.request.get({ url: provider.url + appendString, qs: params, useQuerystring: true, headers: headers, json: true }, function (err, res, body) { if (err || !body) { return cb(err); } 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 { var rates = lodash_1.default.filter(provider.parseFn(body), function (x) { return lodash_1.default.some(Defaults.FIAT_CURRENCIES, ['code', x.code]); }); return cb(null, rates); } catch (e) { return cb(e); } }); return [2]; } }); }); }; FiatRateService.prototype._retrieveLotus = function (cb) { logger_1.default.debug('Fetching data for lotus'); var bc = blockchainexplorer_1.BlockChainExplorer({ coin: 'xpi', network: 'livenet', url: config.blockchainExplorerOpts.xpi.livenet.url }); bc.getBlockBits(function (err, bits) { if (err) return cb(err); var currentDiff = Bitcore.BlockHeader({ bits: bits }).getDifficulty(); var lotusPrice = 0; var networkHashRate = ((Math.pow(2, 48) / 65535 / (2 * 60)) * currentDiff) / 1000 / 1000 / 1000; var currentMinerReward = Math.round((Math.log2(currentDiff / 16) + 1) * 130); var dailyElectricityCost = (((networkHashRate / MINING_EFFICIENCY) * 24) / 1000) * ELECTRICITY_RATE; var lotusCost = dailyElectricityCost / currentMinerReward / 30 / 24; lotusPrice = lotusCost * (1 + MINER_MARGIN); return cb(null, [{ code: 'USD', value: lotusPrice }]); }); }; FiatRateService.prototype.getRate = function (opts, cb) { var _this = this; $.shouldBeFunction(cb, 'Failed state: type error (cb not a function) at <getRate()>'); opts = opts || {}; var now = Date.now(); var coin = opts.coin || 'btc'; var ts = lodash_1.default.isNumber(opts.ts) || lodash_1.default.isArray(opts.ts) ? opts.ts : now; async.map([].concat(ts), function (ts, cb) { if (coin === 'wbtc') { logger_1.default.info('Using btc for wbtc rate.'); coin = 'btc'; } _this.storage.fetchFiatRate(coin, opts.code, ts, function (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 ? rate.value : undefined, fetchedOn: rate ? rate.ts : undefined }); }); }, function (err, res) { if (err) return cb(err); if (!lodash_1.default.isArray(ts)) res = res[0]; return cb(null, res); }); }; FiatRateService.prototype.getRates = function (opts, cb) { var _this = this; $.shouldBeFunction(cb, 'Failed state: type error (cb not a function) at <getRates()>'); opts = opts || {}; var now = Date.now(); var ts = opts.ts ? opts.ts : now; var fiatFiltered = []; var rates = []; if (opts.code) { fiatFiltered = lodash_1.default.filter(Defaults.FIAT_CURRENCIES, ['code', opts.code]); if (!fiatFiltered.length) return cb(opts.code + ' is not supported'); } var currencies = fiatFiltered.length ? fiatFiltered : Defaults.SUPPORT_FIAT_CURRENCIES; var etoken = this._getEtokenSupportPrice(); var coins = lodash_1.default.concat(lodash_1.default.values(Constants.COINS), etoken); async.map(coins, function (coin, cb) { rates[coin] = []; async.map(currencies, function (currency, cb) { var c = coin; if (coin === 'wbtc') { logger_1.default.info('Using btc for wbtc rate.'); c = 'btc'; } _this.storage.fetchFiatRate(c, currency.code, ts, function (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 ? rate.value : undefined, fetchedOn: rate ? rate.ts : undefined, code: currency.code, name: currency.name }); }); }, function (err, res) { if (err) return cb(err); var obj = {}; obj[coin] = res; return cb(null, obj); }); }, function (err, res) { if (err) return cb(err); return cb(null, Object.assign.apply(Object, __spreadArrays([{}], res))); }); }; FiatRateService.prototype.getRatesByCoin = function (opts, cb) { var _this = this; $.shouldBeFunction(cb, 'Failed state: type error (cb not a function) at <getRatesByCoin()>'); opts = opts || {}; var rates = []; var now = Date.now(); var coin = opts.coin; var ts = opts.ts ? opts.ts : now; var fiatFiltered = []; if (opts.code) { fiatFiltered = lodash_1.default.filter(Defaults.FIAT_CURRENCIES, ['code', opts.code]); if (!fiatFiltered.length) return cb(opts.code + ' is not supported'); } var currencies = fiatFiltered.length ? fiatFiltered : Defaults.FIAT_CURRENCIES; async.map(currencies, function (currency, cb) { if (coin === 'wbtc') { logger_1.default.info('Using btc for wbtc rate.'); coin = 'btc'; } _this.storage.fetchFiatRate(coin, currency.code, ts, function (err, rate) { if (err) return cb(err); if (rate && ts - rate.ts > Defaults.FIAT_RATE_MAX_LOOK_BACK_TIME * 60 * 1000) rate = null; rates.push({ ts: +ts, rate: rate ? rate.value : undefined, fetchedOn: rate ? rate.ts : undefined, code: currency.code, name: currency.name }); return cb(null, rates); }); }, function (err, res) { if (err) return cb(err); return cb(null, res[0]); }); }; FiatRateService.prototype.getHistoricalRates = function (opts, cb) { var _this = this; $.shouldBeFunction(cb); opts = opts || {}; var historicalRates = {}; var now = Date.now() - Defaults.FIAT_RATE_FETCH_INTERVAL * 60 * 1000; var ts = lodash_1.default.isNumber(opts.ts) ? opts.ts : now; var coins = ['btc', 'bch', 'xec', 'eth', 'xrp', 'doge', 'xpi', 'ltc']; async.map(coins, function (coin, cb) { _this.storage.fetchHistoricalRates(coin, opts.code, ts, function (err, rates) { if (err) return cb(err); if (!rates) return cb(); for (var _i = 0, rates_1 = rates; _i < rates_1.length; _i++) { var rate = rates_1[_i]; rate.rate = rate.value; delete rate['_id']; delete rate['code']; delete rate['value']; delete rate['coin']; } historicalRates[coin] = rates; return cb(null, historicalRates); }); }, function (err, res) { if (err) return cb(err); return cb(null, res[0]); }); }; return FiatRateService; }()); exports.FiatRateService = FiatRateService; //# sourceMappingURL=fiatrateservice.js.map