@abcpros/bitcore-wallet-service
Version:
A service for Mutisig HD Bitcoin Wallets
514 lines • 24.6 kB
JavaScript
"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