UNPKG

@swtc/serializer

Version:
317 lines 12.4 kB
// Represent amounts and currencies objects // in Jingtum. // - Numbers in hex are big-endian. import Bignumber from "bignumber.js"; import BN from "bn-plus.js"; import extend from "extend"; import { Factory as WalletFactory } from "@swtc/wallet"; import { isNumber } from "./Utils"; import { AMOUNT_CONSTS, allNumeric, isCurrency, isCustomTum, isFloat, isLetterNumer, isRelation, isTumCode } from "@swtc/common"; // // Amount class in the style of Java's BigInteger class // https://docs.oracle.com/javase/7/docs/api/java/math/BigInteger.html // const Factory = (Wallet = WalletFactory("jingtum")) => { var _a; const isAmount = (obj) => { if (obj === null || typeof obj !== "object" || typeof obj.value !== "string" || !isFloat(obj.value) || !isTumCode(obj.currency)) { return false; } if (obj.issuer) { if (!Wallet.isValidAddress(obj.issuer)) { return false; } } else { if (obj.currency !== Wallet.getCurrency()) { return false; } obj.issuer = ""; } return true; }; const isBalance = (obj) => { if (obj === null || typeof obj !== "object" || !isFloat(obj.freezed) || !isFloat(obj.value) || !isTumCode(obj.currency)) { return false; } if (!Wallet.isValidAddress(obj.counterparty)) { return false; } return true; }; const DataCheck = { allNumeric, isCustomTum, isRelation, isTumCode, isCurrency, isLetterNumer, isAmount, isBalance }; return _a = class Amount { constructor() { // Json format: // integer : SWT // { 'value' : ..., 'currency' : ..., 'issuer' : ...} this._value = new BN(0); // 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; // Add constants to Amount class extend(this, AMOUNT_CONSTS); } static from_json(j) { return new Amount().parse_json(j); } is_valid() { if (this.is_native()) { return isNumber(this._value); } return isAmount({ value: this._value.toString(), currency: this._currency, issuer: this._issuer }); } currency() { return this._currency; } is_native() { return this._is_native; } offset() { return this._offset; } is_negative() { return this._is_negative; } is_positive() { return !this.is_zero() && !this.is_negative(); } is_zero() { return this._value.isZero(); } issuer() { return this._issuer; } /** * Only set the issuer if the input is a valid address. * * @param {string} issuer * @returns {Amount} * @memberof Amount */ parse_issuer(issuer) { if (Wallet.isValidAddress(issuer)) { this._issuer = issuer; } return this; } /** * For SWT, only keep as the integer with precision * * @param {string} j * @returns {Amount} * @memberof Amount */ parse_swt_value(j) { let m; if (typeof j === "string") { m = j.match(/^(-?)(\d*)(\.\d{0,6})?$/); } if (m) { if (m[3] === undefined) { // 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 = Boolean(m[1]) && this._value !== 0; if (this._value > this.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! * * @param {(number | string)} j * @returns {Amount} * @memberof Amount */ parse_tum_value(j) { this._is_native = false; switch (typeof j) { case "number": this._is_negative = j < 0; this._value = new BN(Math.abs(j)); this._offset = 0; break; case "string": const i = j.match(/^(-?)(\d+)$/); const d = !i && j.match(/^(-?)(\d*)\.(\d*)$/); const 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], 10); this._is_negative = Boolean(e[1]); } else if (d) { // float notation const precision = d[3].length; this._value = this._offset = -precision; // integer.multiply(Amount.bi_10.clone().pow(precision)).add(fraction); this._is_negative = Boolean(d[1]); } else if (i) { // integer notation this._value = i[2]; // new BigInteger(i[2]); this._offset = 0; this._is_negative = Boolean(i[1]); } else { this._value = NaN; } break; default: this._value = NaN; } return this; } /** * Convert the internal obj to JSON * * @returns {IAmount} * @memberof Amount */ to_json() { let result; if (this._is_native) { result = new Bignumber(this._value.toString(10)) .dividedBy(1e6) .toString(10); } else { result = {}; result.value = new Bignumber(this._value.toString(10)) .dividedBy(Math.pow(10, Math.abs(this._offset))) .toString(10); result.currency = this.currency(); if (this.is_valid()) { result.issuer = this._issuer; } } 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). * * @returns {number[]} * @memberof Amount */ tum_to_bytes() { let currencyData = new Array(20).fill(0); // Only handle the currency with correct symbol if (isCurrency(this._currency)) { const currencyCode = this._currency; // 区分大小写 const end = 14; const len = currencyCode.length - 1; for (let j = len; j >= 0; j--) { currencyData[end - j] = currencyCode.charCodeAt(len - j) & 0xff; } } else if (isCustomTum(this._currency)) { // for TUM code start with 8 // should be HEX code currencyData = new BN(this._currency, 16).toArray(undefined, 20); } else { throw new Error("Incorrect currency code length."); } return currencyData; } /** * 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"} * * @param {(number | string | IAmount)} in_json * @returns {Amount} * @memberof Amount */ parse_json(in_json) { if (typeof in_json === "number" || typeof in_json === "string") { this.parse_swt_value(in_json.toString()); } else if (in_json !== null && typeof in_json === "object") { if (!isTumCode(in_json.currency)) { throw new Error("Amount.parse_json: Input JSON has invalid Tum info!"); } // AMOUNT could have a field named either as 'issuer' or as 'counterparty' for SWT, this can be undefined if (in_json.currency !== Wallet.getCurrency()) { this._currency = in_json.currency; this._is_native = false; if (in_json.issuer && Wallet.isValidAddress(in_json.issuer)) { this._issuer = in_json.issuer; // TODO, need to find a better way for extracting the exponent and digits const vpow = Number(in_json.value).toExponential().toString(); const len = Number(vpow.substr(vpow.lastIndexOf("e") + 1)); const offset = 15 - len; const factor = Math.pow(10, offset); const newvalue = new Bignumber(in_json.value) .multipliedBy(factor) .toString(); this._value = new BN(newvalue, 10); this._offset = -1 * offset; } 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; } }, _a.DataCheck = DataCheck, _a; }; // const Amount = Factory() export { Factory }; //# sourceMappingURL=TumAmount.js.map