newpay-wallet-js
Version:
523 lines (454 loc) • 18.5 kB
JavaScript
var numeral = require("numeral");
let id_regex = /\b\d+\.\d+\.(\d+)\b/;
import {ChainTypes} from "bitsharesjs/es";
var {object_type} = ChainTypes;
var Utils = {
get_object_id: (obj_id) => {
let id_regex_res = id_regex.exec(obj_id);
return id_regex_res ? Number.parseInt(id_regex_res[1]) : 0;
},
is_object_id: (obj_id) => {
if( 'string' != typeof obj_id ) return false
let match = id_regex.exec(obj_id);
return (match !== null && obj_id.split(".").length === 3);
},
is_object_type: (obj_id, type) => {
let prefix = object_type[type];
if (!prefix || !obj_id) return null;
prefix = "1." + prefix.toString();
return obj_id.substring(0, prefix.length) === prefix;
},
get_satoshi_amount(amount, asset) {
let precision = asset.toJS ? asset.get("precision") : asset.precision;
let assetPrecision = this.get_asset_precision(precision);
amount = typeof amount === "string" ? amount : amount.toString();
let decimalPosition = amount.indexOf(".");
if (decimalPosition === -1) {
return parseInt(amount, 10) * assetPrecision;
} else {
let amountLength = amount.length,
i;
amount = amount.replace(".", "");
amount = amount.substr(0, decimalPosition + precision);
for (i = 0; i < precision; i++) {
decimalPosition += 1;
if (decimalPosition > amount.length) {
amount += "0";
}
};
return parseInt(amount, 10);
}
},
get_asset_precision: (precision) => {
precision = precision.toJS ? precision.get("precision") : precision;
return Math.pow(10, precision);
},
get_asset_amount: function(amount, asset) {
if (amount === 0) return amount;
if (!amount) return null;
return amount / this.get_asset_precision(asset.toJS ? asset.get("precision") : asset.precision);
},
get_asset_price: function(quoteAmount, quoteAsset, baseAmount, baseAsset, inverted = false) {
if (!quoteAsset || !baseAsset) {
return 1;
}
var price = this.get_asset_amount(quoteAmount, quoteAsset) / this.get_asset_amount(baseAmount, baseAsset);
return inverted ? 1 / price : price;
},
round_number: function(number, asset) {
let assetPrecision = asset.toJS ? asset.get("precision") : asset.precision;
let precision = this.get_asset_precision(assetPrecision);
return Math.round(number * precision) / precision;
},
format_volume(amount) {
if (amount < 10000) {
return this.format_number(amount, 3);
} else if (amount < 1000000) {
return (Math.round(amount / 10) / 100).toFixed(2) + "k";
} else {
return (Math.round(amount / 10000) / 100).toFixed(2) + "M";
}
},
format_number: (number, decimals, trailing_zeros = true) => {
if(isNaN(number) || !isFinite(number) || number === undefined || number === null) return "";
let zeros = ".";
for (var i = 0; i < decimals; i++) {
zeros += "0";
}
let num = numeral(number).format("0,0" + zeros);
if( num.indexOf('.') > 0 && !trailing_zeros)
return num.replace(/0+$/,"").replace(/\.$/,"")
return num
},
format_asset: function(amount, asset, noSymbol, trailing_zeros=true) {
let symbol;
let digits = 0
if( asset === undefined )
return undefined
if( 'symbol' in asset )
{
// console.log( "asset: ", asset )
symbol = asset.symbol
digits = asset.precision
}
else
{
// console.log( "asset: ", asset.toJS() )
symbol = asset.get('symbol')
digits = asset.get('precision')
}
let precision = this.get_asset_precision(digits);
// console.log( "precision: ", precision )
return `${this.format_number(amount / precision, digits, trailing_zeros)}${!noSymbol ? " " + symbol : ""}`;
},
format_price: function(quoteAmount, quoteAsset, baseAmount, baseAsset, noSymbol,inverted = false, trailing_zeros = true) {
if (quoteAsset.size) quoteAsset = quoteAsset.toJS();
if (baseAsset.size) baseAsset = baseAsset.toJS();
let precision = this.get_asset_precision(quoteAsset.precision);
let basePrecision = this.get_asset_precision(baseAsset.precision);
if (inverted) {
if (parseInt(quoteAsset.id.split(".")[2], 10) < parseInt(baseAsset.id.split(".")[2], 10)) {
return `${this.format_number((quoteAmount / precision) / (baseAmount / basePrecision), Math.max(5, quoteAsset.precision),trailing_zeros)}${!noSymbol ? "" + quoteAsset.symbol + "/" + baseAsset.symbol : ""}`;
} else {
return `${this.format_number((baseAmount / basePrecision) / (quoteAmount / precision), Math.max(5, baseAsset.precision),trailing_zeros)}${!noSymbol ? "" + baseAsset.symbol + "/" + quoteAsset.symbol : ""}`;
}
} else {
if (parseInt(quoteAsset.id.split(".")[2], 10) > parseInt(baseAsset.id.split(".")[2], 10)) {
return `${this.format_number((quoteAmount / precision) / (baseAmount / basePrecision), Math.max(5, quoteAsset.precision),trailing_zeros)}${!noSymbol ? "" + quoteAsset.symbol + "/" + baseAsset.symbol : ""}`;
} else {
return `${this.format_number((baseAmount / basePrecision) / (quoteAmount / precision), Math.max(5, baseAsset.precision),trailing_zeros)}${!noSymbol ? "" + baseAsset.symbol + "/" + quoteAsset.symbol : ""}`;
}
}
},
price_text: function(price, base, quote) {
let maxDecimals = 8;
let priceText;
let quoteID = quote.toJS ? quote.get("id") : quote.id;
let quotePrecision = quote.toJS ? quote.get("precision") : quote.precision;
let baseID = base.toJS ? base.get("id") : base.id;
let basePrecision = base.toJS ? base.get("precision") : base.precision;
let fixedPrecisionAssets = {
"1.3.113": 5, // bitCNY
"1.3.121": 5 // bitUSD
};
if (quoteID === "1.3.0") {
priceText = this.format_number(price, quotePrecision);
} else if (baseID === "1.3.0") {
priceText = this.format_number(price, Math.min(maxDecimals, quotePrecision + 2));
} else if (fixedPrecisionAssets[quoteID]) {
priceText = this.format_number(price, fixedPrecisionAssets[quoteID]);
} else {
priceText = this.format_number(price, Math.min(maxDecimals, Math.max(quotePrecision + basePrecision, 2)));
}
return priceText;
},
price_to_text: function(price, base, quote, forcePrecision = null) {
if (typeof price !== "number" || !base || !quote) {
return;
}
if (price === Infinity) {
price = 0;
}
let priceText;
if (forcePrecision) {
priceText = this.format_number(price, forcePrecision);
} else {
priceText = this.price_text(price, base, quote);
}
let price_split = priceText.split(".");
let int = price_split[0];
let dec = price_split[1];
let i;
let zeros = 0;
if (dec) {
if (price > 1) {
let l = dec.length;
for (i = l - 1; i >= 0; i--) {
if (dec[i] !== "0") {
break;
}
zeros++;
};
} else {
let l = dec.length;
for (i = 0; i < l; i++) {
if (dec[i] !== "0") {
i--;
break;
}
zeros++;
};
}
}
let trailing = zeros ? dec.substr(Math.max(0, i + 1), dec.length) : null;
if (trailing) {
if (trailing.length === dec.length) {
dec = null;
} else if (trailing.length) {
dec = dec.substr(0, i + 1);
}
}
return {
text: priceText,
int: int,
dec: dec,
trailing: trailing,
full: price
};
},
get_op_type: function(object) {
let type = parseInt(object.split(".")[1], 10);
for (let id in object_type) {
if (object_type[id] === type) {
return id;
}
}
},
add_comma: function(value) {
if (typeof value === "number") {
value = value.toString();
}
value = value.trim()
value = value.replace( /,/g, "" )
if( value == "." || value == "" ) {
return value;
}
else if( value.length ) {
// console.log( "before: ",value )
let n = Number(value)
if( isNaN( n ) )
return
let parts = value.split('.')
// console.log( "split: ", parts )
n = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
if( parts.length > 1 )
n += "." + parts[1]
// console.log( "after: ",transfer.amount )
return n;
}
},
parse_float_with_comma: function(value) {
// let value = new_state.transfer.amount
value = value.replace( /,/g, "" )
let fvalue = parseFloat(value)
if( value.length && isNaN(fvalue) && value != "." )
throw "parse_float_with_comma: must be a number"
else if( fvalue < 0 )
return 0;
return fvalue;
},
are_equal_shallow: function(a, b) {
if (!a && b || a && !b) {
return false;
}
if (Array.isArray(a) && Array.isArray(a)) {
if (a.length > b.length) {
return false;
}
}
for(var key in a) {
if(!(key in b) || a[key] !== b[key]) {
return false;
}
}
for(var key in b) {
if(!(key in a) || a[key] !== b[key]) {
return false;
}
}
return true;
},
format_date: function(date_str) {
let date = new Date(date_str);
return date.toLocaleDateString();
},
format_time: function(time_str) {
let date = new Date(time_str);
return date.toLocaleString();
},
limitByPrecision: function(value, assetPrecision) {
let valueString = value.toString();
let splitString = valueString.split(".");
if (splitString.length === 1 || splitString.length === 2 && splitString[1].length <= assetPrecision) {
return valueString;
} else {
return splitString[0] + "." + splitString[1].substr(0, assetPrecision);
}
// let precision = this.get_asset_precision(assetPrecision);
// value = Math.floor(value * precision) / precision;
// if (isNaN(value) || !isFinite(value)) {
// return 0;
// }
// return value;
},
getFee: function({opType, options, globalObject, asset, coreAsset, balances}) {
let coreFee = {asset: "1.3.0"};
coreFee.amount = this.estimateFee(opType, options, globalObject) || 0;
if (!asset || asset.get("id") === "1.3.0") return coreFee; // Desired fee is in core asset
let cer = asset.getIn(["options", "core_exchange_rate"]).toJS();
if (!coreAsset || cer.base.asset_id === cer.quote.asset_id) return coreFee;
let price = this.convertPrice(coreAsset, cer, null, asset.get("id"));
let eqValue = this.convertValue(price, coreFee.amount, coreAsset, asset);
let fee = {
amount: Math.floor(eqValue + 0.5),
asset: asset.get("id")
};
let useCoreFee = true; // prefer CORE fee by default
if (balances && balances.length) {
balances.forEach(b => {
if (b.get("asset_type") === "1.3.0" && b.get("balance") < coreFee.amount) { // User has sufficient CORE, use it (cheapeest)
useCoreFee = false;
}
});
balances.forEach(b => {
if (b.get("asset_type") === fee.asset && b.get("balance") < fee.amount) { // User has insufficient {asset}, use CORE instead
useCoreFee = true;
}
});
}
return useCoreFee ? coreFee : fee;
},
convertPrice: function(fromRate, toRate, fromID, toID) {
if (!fromRate || !toRate) {
return null;
}
// Handle case of input simply being a fromAsset and toAsset
if (fromRate.toJS && this.is_object_type(fromRate.get("id"), "asset")) {
fromID = fromRate.get("id")
fromRate = fromRate.get("bitasset") ? fromRate.getIn(["bitasset", "current_feed", "settlement_price"]).toJS() : fromRate.getIn(["options", "core_exchange_rate"]).toJS();
}
if (toRate.toJS && this.is_object_type(toRate.get("id"), "asset")) {
toID = toRate.get("id");
toRate = toRate.get("bitasset") ? toRate.getIn(["bitasset", "current_feed", "settlement_price"]).toJS() : toRate.getIn(["options", "core_exchange_rate"]).toJS();
}
let fromRateQuoteID = fromRate.quote.asset_id;
let toRateQuoteID = toRate.quote.asset_id;
let fromRateQuoteAmount, fromRateBaseAmount, finalQuoteID, finalBaseID;
if (fromRateQuoteID === fromID) {
fromRateQuoteAmount = fromRate.quote.amount;
fromRateBaseAmount = fromRate.base.amount;
} else {
fromRateQuoteAmount = fromRate.base.amount;
fromRateBaseAmount = fromRate.quote.amount;
}
let toRateQuoteAmount, toRateBaseAmount;
if (toRateQuoteID === toID) {
toRateQuoteAmount = toRate.quote.amount;
toRateBaseAmount = toRate.base.amount;
} else {
toRateQuoteAmount = toRate.base.amount;
toRateBaseAmount = toRate.quote.amount;
}
let baseRatio, finalQuoteAmount, finalBaseAmount;
if (toRateBaseAmount > fromRateBaseAmount) {
baseRatio = toRateBaseAmount / fromRateBaseAmount;
finalQuoteAmount = fromRateQuoteAmount * baseRatio;
finalBaseAmount = toRateQuoteAmount;
} else {
baseRatio = fromRateBaseAmount / toRateBaseAmount;
finalQuoteAmount = fromRateQuoteAmount;
finalBaseAmount = toRateQuoteAmount * baseRatio;
}
return {
quote: {
amount: finalQuoteAmount,
asset_id: toID
},
base: {
amount: finalBaseAmount,
asset_id: fromID
}
};
},
convertValue: function(priceObject, amount, fromAsset, toAsset) {
priceObject = priceObject.toJS ? priceObject.toJS() : priceObject;
let quotePrecision = this.get_asset_precision(fromAsset.get("precision"));
let basePrecision = this.get_asset_precision(toAsset.get("precision"));
let assetPrice = this.get_asset_price(priceObject.quote.amount, fromAsset, priceObject.base.amount, toAsset);
let eqValue = fromAsset.get("id") !== toAsset.get("id") ?
basePrecision * (amount / quotePrecision) / assetPrice :
amount;
if (isNaN(eqValue) || !isFinite(eqValue)) {
return null;
}
return eqValue;
},
isValidPrice(rate) {
if (!rate || !rate.toJS) {
return false;
}
let base = rate.get("base").toJS();
let quote = rate.get("quote").toJS();
if ((base.amount > 0 && quote.amount > 0) && (base.asset_id !== quote.asset_id)) {
return true;
} else {
return false;
}
},
sortText(a, b, inverse = false) {
if (a > b) {
return inverse ? 1 : -1;
} else if (a < b) {
return inverse ? -1 : 1;
} else {
return 0;
}
},
sortID(a, b, inverse = false) {
// inverse = false => low to high
let intA = parseInt(a.split(".")[2], 10);
let intB = parseInt(b.split(".")[2], 10);
return inverse ? (intB - intA) : (intA -intB);
},
calc_block_time(block_number, globalObject, dynGlobalObject) {
if (!globalObject || !dynGlobalObject) return null;
const block_interval = globalObject.get("parameters").get("block_interval");
const head_block = dynGlobalObject.get("head_block_number");
const head_block_time = new Date(dynGlobalObject.get("time") + "+00:00");
const seconds_below = (head_block - block_number) * block_interval;
return new Date(head_block_time - seconds_below * 1000);
},
get_translation_parts(str) {
let result = [];
let toReplace = {};
let re = /{(.*?)}/g;
let interpolators = str.split(re);
// console.log("split:", str.split(re));
return str.split(re);
// var str = '{{azazdaz}} {{azdazd}}';
// var m;
// while ((m = re.exec(str)) !== null) {
// if (m.index === re.lastIndex) {
// re.lastIndex++;
// }
// console.log("m:", m);
// // View your result using the m-variable.
// // eg m[0] etc.
// //
// toReplace[m[1]] = m[0]
// result.push(m[1])
// }
// return result;
},
get_percentage(a, b) {
return Math.round((a/b) * 100) + "%";
},
replaceName(name, isBitAsset = false) {
let toReplace = ["TRADE.", "OPEN.", "METAEX."];
let suffix = "";
let i;
for (i = 0; i < toReplace.length; i++) {
if (name.indexOf(toReplace[i]) !== -1) {
name = name.replace(toReplace[i], "") + suffix;
break;
}
}
let prefix = isBitAsset ? "bit" : toReplace[i] ? toReplace[i].toLowerCase() : null;
if (prefix === "open.") prefix = "";
return {
name,
prefix
};
}
};
export default Utils;