UNPKG

jingtum-lib

Version:

jingtum lib

314 lines (268 loc) 9.55 kB
// Represent amounts and currencies objects // in Jingtum. // - Numbers in hex are big-endian. var extend = require('extend'); var base_wallet = require('jingtum-base-lib').Wallet; var BigInteger = require('bn.js'); var bignumber = require('bignumber.js'); var isTumCode = require('./DataCheck').isTumCode; const CURRENCY_NAME_LEN = 3;//货币长度 const CURRENCY_NAME_LEN2 = 6;//货币长度 // // Amount class in the style of Java's BigInteger class // https://docs.oracle.com/javase/7/docs/api/java/math/BigInteger.html // function Amount() { // Json format: // integer : SWT // { 'value' : ..., 'currency' : ..., 'issuer' : ...} this._value = new BigInteger(); // NaN for bad value. Always positive. this._offset = 0; // Always 0 for SWT. this._is_native = true; // Default to SWT. Only valid if value is not NaN. this._is_negative = false; this._currency = null;//new String; this._issuer = null;//new String; }; var consts = { currency_xns: 0, currency_one: 1, xns_precision: 6, // BigInteger values prefixed with bi_. bi_5: 5,// new BigInteger('5'), bi_7: 7,//new BigInteger('7'), bi_10: 10, //new BigInteger('10'), bi_1e14: 1e14, //new BigInteger(String(1e14)), bi_1e16: 1e16, //new BigInteger(String(1e16)), bi_1e17: 1e17, //new BigInteger(String(1e17)), bi_1e32: 1e32, //new BigInteger('100000000000000000000000000000000'), bi_man_max_value: 9999999999999999, //new BigInteger('9999999999999999'), bi_man_min_value: 1e15, //new BigInteger('1000000000000000'), bi_xns_max: 9e18, //new BigInteger('9000000000000000000'), // Json wire limit. bi_xns_min: -9e18,//new BigInteger('-9000000000000000000'),// Json wire limit. bi_xns_unit: 1e6,//new BigInteger('1000000'), cMinOffset: -96, cMaxOffset: 80, // Maximum possible amount for non-SWT currencies using the maximum mantissa // with maximum exponent. Corresponds to hex 0xEC6386F26FC0FFFF. max_value: '9999999999999999e80', // Minimum possible amount for non-SWT currencies. min_value: '-1000000000000000e-96' }; // Add constants to Amount class extend(Amount, consts); Amount.from_json = function (j) { return (new Amount()).parse_json(j); }; //Only check the value of the Amount // Amount.prototype.is_valid = function (j) { //console.log("TODO: decide if the input is a valid amount obj"); return true; }; Amount.prototype.currency = function () { return this._currency; }; Amount.prototype.is_native = function () { return this._is_native; }; //Remove check of NaN Amount.prototype.is_negative = function () { return this._is_negative; }; Amount.prototype.is_positive = function () { return !this.is_zero() && !this.is_negative(); }; Amount.prototype.is_zero = function () { return this._value.isZero(); }; Amount.prototype.issuer = function () { return this._issuer; }; /* * Only set the issuer if the input is * a valid address. */ Amount.prototype.parse_issuer = function (issuer) { if (base_wallet.isValidAddress(issuer)) this._issuer = issuer; return this; }; // <-> j /* * Convert the input JSON data into * a valid Amount object * Amount should have 3 properties * value * issuer/counterparty * currency * Amount: * number: 123456 * string: "123456" * obj: {"value": 129757.754575, "issuer":" ", "currency":"USD"} */ Amount.prototype.parse_json = function (in_json) { if (typeof in_json === 'number') { this.parse_swt_value(in_json.toString()); } else if (typeof in_json === 'string') { //only allow this.parse_swt_value(in_json); } else if (typeof in_json == 'object') { if (!isTumCode(in_json.currency)) throw new Error('Amount.parse_json: Input JSON has invalid Tum info!'); else { //AMOUNT could have a field named either as 'issuer' or as 'counterparty' for SWT, this can be undefined if (in_json.currency != 'SWT') { this._currency = in_json.currency; this._is_native = false; if (typeof in_json.issuer != 'undefined' && in_json.issuer != null) { if (base_wallet.isValidAddress(in_json.issuer)) { this._issuer = in_json.issuer; //TODO, need to find a better way for extracting the exponent and digits var vpow = new Number(in_json.value); vpow = String(vpow.toExponential()); vpow = Number(vpow.substr(vpow.lastIndexOf("e") + 1)); var offset = 15 - vpow; var factor = Math.pow(10, offset); var newvalue = (new bignumber(in_json.value).multipliedBy(factor)).toString(); this._value = new BigInteger(newvalue, 10); this._offset = -1 * offset; } else { throw new Error('Amount.parse_json: Input JSON has invalid issuer info!'); } } else { throw new Error('Amount.parse_json: Input JSON has invalid issuer info!'); } } else this.parse_swt_value(in_json.value.toString()); } } else throw new Error('Amount.parse_json: Unsupported JSON type!'); return this; }; /* * For SWT, only keep as the integer * with precision * */ Amount.prototype.parse_swt_value = function (j) { var m; if (typeof j === 'string') { m = j.match(/^(-?)(\d*)(\.\d{0,6})?$/); } if (m) { if (m[3] === void(0)) { // Integer notation //Changed to agree with floating, values multiplied by 1,000,000. this._value = new bignumber(m[2]).multipliedBy(1e6).toNumber()//new BigInteger(m[2]); } else { // Float notation : values multiplied by 1,000,000. //only keep 6 digits after the decimal point. this._value = new bignumber(m[2] + m[3]).multipliedBy(1e6).toNumber();//int_part+fraction_part;//int_part.add(fraction_part); } this._is_native = true; this._offset = 0; this._is_negative = !!m[1] && this._value !== 0; if (this._value > Amount.bi_xns_max) { this._value = NaN; } } else { this._value = NaN; } return this; }; // Parse a non-native Tum value for the json wire format. // Requires _currency not as SWT! Amount.prototype.parse_tum_value = function (j) { this._is_native = false; switch (typeof j) { case 'number': this._is_negative = j < 0; this._value = new BigInteger(Math.abs(j)); this._offset = 0; this.canonicalize(); break; case 'string': var i = j.match(/^(-?)(\d+)$/); var d = !i && j.match(/^(-?)(\d*)\.(\d*)$/); var e = !d && j.match(/^(-?)(\d*)e(-?\d+)$/);//? !e if (e) { // e notation this._value = e[2];//new BigInteger(e[2]); this._offset = parseInt(e[3]); this._is_negative = !!e[1]; } else if (d) { // float notation var precision = d[3].length; this._value = //integer.multiply(Amount.bi_10.clone().pow(precision)).add(fraction); this._offset = -precision; this._is_negative = !!d[1]; } else if (i) { // integer notation this._value = i[2];//new BigInteger(i[2]); this._offset = 0; this._is_negative = !!i[1]; } else { this._value = NaN; } break; default: this._value = NaN; } return this; }; /* * Convert the internal obj to JSON */ Amount.prototype.to_json = function () { var result; if (this._is_native) { result = this.to_text(); } else { var amount_json = { value: this._value, currency: this._currency }; if (this._issuer.is_valid()) amount_json.issuer = this._issuer; result = amount_json; } return result; }; /* * Convert the internal Tum Code * to byte array * for serialization. * Input: a string represents the Tum. * Output: Bytes array of size 20 (UINT160). * */ Amount.prototype.tum_to_bytes = function () { var currencyData = new Array(20); for (var i = 0; i < 20; i++) { currencyData[i] = 0; } //Only handle the currency with correct symbol if (this._currency.length >= CURRENCY_NAME_LEN && this._currency.length <= CURRENCY_NAME_LEN2) { var currencyCode = this._currency;//区分大小写 var end = 14; var len = currencyCode.length - 1; for(var j = len; j >= 0; j--){ currencyData[end - j] = currencyCode.charCodeAt(len - j) & 0xff; } }else if (this._currency.length === 40){ //for TUM code start with 8 //should be HEX code if (/^[0-9A-F]/i.test(this._currency)){ currencyData = new BigInteger(this._currency, 16).toArray(null, 20); }else{ throw new Error('Invalid currency code.'); } }else{ throw new Error('Incorrect currency code length.'); } return currencyData; }; exports.Amount = Amount;