mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-24 06:05:51 +00:00
Change this._value to be an instance of IOU or XRP Value
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Value = require('./value').Value;
|
const Value = require('./value').Value;
|
||||||
|
const XRPValue = require('./XRPValue').XRPValue;
|
||||||
const GlobalBigNumber = require('bignumber.js');
|
const GlobalBigNumber = require('bignumber.js');
|
||||||
const BigNumber = GlobalBigNumber.another({
|
const BigNumber = GlobalBigNumber.another({
|
||||||
ROUNDING_MODE: GlobalBigNumber.ROUND_HALF_UP,
|
ROUNDING_MODE: GlobalBigNumber.ROUND_HALF_UP,
|
||||||
@@ -11,33 +12,44 @@ const BigNumber = GlobalBigNumber.another({
|
|||||||
|
|
||||||
class IOUValue extends Value {
|
class IOUValue extends Value {
|
||||||
|
|
||||||
constructor(value: string | BigNumber) {
|
constructor(value: string | BigNumber, roundingMode: ?number = null,
|
||||||
super(value);
|
base: ?number = null) {
|
||||||
|
|
||||||
|
super(new BigNumber(value, base).toDigits(16, roundingMode));
|
||||||
}
|
}
|
||||||
|
|
||||||
multiplyByXRP(multiplicand: {_value: BigNumber, _bi_xns_unit: number}) {
|
multiply(multiplicand: Value) {
|
||||||
const constant = new BigNumber((multiplicand._bi_xns_unit).toString());
|
if (multiplicand instanceof XRPValue) {
|
||||||
const value = new BigNumber(multiplicand._value);
|
return super.multiply(
|
||||||
multiplicand._value = (value).times(constant);
|
new IOUValue(
|
||||||
|
multiplicand._value.times(multiplicand.rippleUnits)));
|
||||||
|
}
|
||||||
return super.multiply(multiplicand);
|
return super.multiply(multiplicand);
|
||||||
}
|
}
|
||||||
|
|
||||||
divideByXRP(divisor: {_value: BigNumber, _bi_xns_unit: number}) {
|
divide(divisor: Value) {
|
||||||
const constant = new BigNumber((divisor._bi_xns_unit).toString());
|
if (divisor instanceof XRPValue) {
|
||||||
const value = new BigNumber(divisor._value);
|
return super.divide(
|
||||||
divisor._value = (value).times(constant);
|
new IOUValue(divisor._value.times(divisor.rippleUnits)));
|
||||||
|
}
|
||||||
return super.divide(divisor);
|
return super.divide(divisor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
negate() {
|
||||||
|
return new IOUValue(this._value.neg());
|
||||||
|
}
|
||||||
|
|
||||||
_canonicalize(value) {
|
_canonicalize(value) {
|
||||||
|
if (value.isNaN()) {
|
||||||
|
throw new Error('Invalid result');
|
||||||
|
}
|
||||||
return new IOUValue(value.toPrecision(16));
|
return new IOUValue(value.toPrecision(16));
|
||||||
}
|
}
|
||||||
|
|
||||||
equals(comparator) {
|
equals(comparator) {
|
||||||
return (comparator instanceof IOUValue)
|
return (comparator instanceof IOUValue)
|
||||||
&& this._value.equals(comparator.value);
|
&& this._value.equals(comparator._value);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.IOUValue = IOUValue;
|
exports.IOUValue = IOUValue;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* @flow */
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const GlobalBigNumber = require('bignumber.js');
|
const GlobalBigNumber = require('bignumber.js');
|
||||||
@@ -10,20 +12,48 @@ const Value = require('./value').Value;
|
|||||||
|
|
||||||
class XRPValue extends Value {
|
class XRPValue extends Value {
|
||||||
|
|
||||||
constructor(value, bi_xns_unit) {
|
constructor(value: string | BigNumber) {
|
||||||
super(value);
|
super(value);
|
||||||
this._bi_xns_unit = bi_xns_unit;
|
this.rippleUnits = new BigNumber(1e6);
|
||||||
|
if (this._value.dp() > 6) {
|
||||||
|
throw new Error(
|
||||||
|
'Value has more than 6 digits of precision past the decimal point, '
|
||||||
|
+ 'an IOUValue may be being cast to an XRPValue'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
multiply(multiplicand: Value) {
|
||||||
|
if (multiplicand instanceof XRPValue) {
|
||||||
|
return super.multiply(
|
||||||
|
new XRPValue(multiplicand._value.times(multiplicand.rippleUnits)));
|
||||||
|
}
|
||||||
|
return super.multiply(multiplicand);
|
||||||
|
}
|
||||||
|
|
||||||
|
divide(divisor: Value) {
|
||||||
|
if (divisor instanceof XRPValue) {
|
||||||
|
return super.divide(
|
||||||
|
new XRPValue(divisor._value.times(divisor.rippleUnits)));
|
||||||
|
}
|
||||||
|
return super.divide(divisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
negate() {
|
||||||
|
return new XRPValue(this._value.neg());
|
||||||
}
|
}
|
||||||
|
|
||||||
_canonicalize(value) {
|
_canonicalize(value) {
|
||||||
|
if (value.isNaN()) {
|
||||||
|
throw new Error('Invalid result');
|
||||||
|
}
|
||||||
return new XRPValue(value.round(6, BigNumber.ROUND_DOWN));
|
return new XRPValue(value.round(6, BigNumber.ROUND_DOWN));
|
||||||
}
|
}
|
||||||
|
|
||||||
equals(comparator) {
|
equals(comparator) {
|
||||||
return (comparator instanceof XRPValue)
|
return (comparator instanceof XRPValue)
|
||||||
&& this._value.equals(comparator.value);
|
&& this._value.equals(comparator._value);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.XRPValue = XRPValue;
|
exports.XRPValue = XRPValue;
|
||||||
|
|||||||
@@ -13,17 +13,13 @@ const Value = require('./value').Value;
|
|||||||
const IOUValue = require('./IOUValue').IOUValue;
|
const IOUValue = require('./IOUValue').IOUValue;
|
||||||
const XRPValue = require('./XRPValue').XRPValue;
|
const XRPValue = require('./XRPValue').XRPValue;
|
||||||
|
|
||||||
|
function Amount(value = new XRPValue(NaN)) {
|
||||||
function inverse(number) {
|
|
||||||
return new IOUValue(number).invert()._value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Amount() {
|
|
||||||
// Json format:
|
// Json format:
|
||||||
// integer : XRP
|
// integer : XRP
|
||||||
// { 'value' : ..., 'currency' : ..., 'issuer' : ...}
|
// { 'value' : ..., 'currency' : ..., 'issuer' : ...}
|
||||||
|
assert(value instanceof Value);
|
||||||
|
|
||||||
this._value = new Value(NaN)._value;
|
this._value = value;
|
||||||
this._is_native = true; // Default to XRP. Only valid if value is not NaN.
|
this._is_native = true; // Default to XRP. Only valid if value is not NaN.
|
||||||
this._currency = new Currency();
|
this._currency = new Currency();
|
||||||
this._issuer = new UInt160();
|
this._issuer = new UInt160();
|
||||||
@@ -41,19 +37,11 @@ const consts = {
|
|||||||
xns_precision: 6,
|
xns_precision: 6,
|
||||||
|
|
||||||
// bi_ prefix refers to "big integer"
|
// bi_ prefix refers to "big integer"
|
||||||
// TODO: we shouldn't expose our BigNumber library publicly
|
// man refers to mantissa
|
||||||
bi_5: new Value(5)._value,
|
bi_man_max_value: '9999999999999999',
|
||||||
bi_7: new Value(7)._value,
|
bi_man_min_value: Number(1e15).toString(),
|
||||||
bi_10: new Value(10)._value,
|
bi_xns_max: Number(1e17).toString(),
|
||||||
bi_1e14: new Value(1e14)._value,
|
bi_xns_min: Number(-1e17).toString(),
|
||||||
bi_1e16: new Value(1e16)._value,
|
|
||||||
bi_1e17: new Value(1e17)._value,
|
|
||||||
bi_1e32: new Value(1e32)._value,
|
|
||||||
bi_man_max_value: new Value('9999999999999999')._value,
|
|
||||||
bi_man_min_value: new Value(1e15)._value,
|
|
||||||
bi_xns_max: new Value(1e17)._value,
|
|
||||||
bi_xns_min: new Value(-1e17)._value,
|
|
||||||
bi_xns_unit: new Value(1e6)._value,
|
|
||||||
|
|
||||||
cMinOffset: -96,
|
cMinOffset: -96,
|
||||||
cMaxOffset: 80,
|
cMaxOffset: 80,
|
||||||
@@ -65,9 +53,11 @@ const consts = {
|
|||||||
min_value: '-1000000000000000e-96'
|
min_value: '-1000000000000000e-96'
|
||||||
};
|
};
|
||||||
|
|
||||||
const MAX_XRP_VALUE = new Value(1e11)._value;
|
const MAX_XRP_VALUE = new XRPValue(1e11);
|
||||||
const MAX_IOU_VALUE = new Value(consts.max_value)._value;
|
const MAX_IOU_VALUE = new IOUValue(consts.max_value);
|
||||||
const MIN_IOU_VALUE = new Value(consts.min_value)._value.abs();
|
const MIN_IOU_VALUE = new IOUValue(consts.min_value).abs();
|
||||||
|
|
||||||
|
const bi_xns_unit = new IOUValue(1e6);
|
||||||
|
|
||||||
// Add constants to Amount class
|
// Add constants to Amount class
|
||||||
extend(Amount, consts);
|
extend(Amount, consts);
|
||||||
@@ -111,21 +101,15 @@ Amount.is_valid_full = function(j) {
|
|||||||
|
|
||||||
Amount.NaN = function() {
|
Amount.NaN = function() {
|
||||||
const result = new Amount();
|
const result = new Amount();
|
||||||
result._value = new Value(NaN)._value; // should have no effect
|
result._value = new IOUValue(NaN); // should have no effect
|
||||||
return result; // but let's be careful
|
return result; // but let's be careful
|
||||||
};
|
};
|
||||||
|
|
||||||
// be sure that _is_native is set properly BEFORE calling _set_value
|
// be sure that _is_native is set properly BEFORE calling _set_value
|
||||||
Amount.prototype._set_value = function(value, roundingMode) {
|
Amount.prototype._set_value = function(value: Value) {
|
||||||
assert(value instanceof Object);
|
|
||||||
|
|
||||||
this._value = this._value = value.isZero() && value.isNegative() ?
|
|
||||||
value.negated()._value : value._value;
|
|
||||||
if (!this._value) {
|
|
||||||
this._value = value.isZero() && value.isNegative() ?
|
this._value = value.isZero() && value.isNegative() ?
|
||||||
value.negated() : value;
|
value.negate() : value;
|
||||||
}
|
|
||||||
this.canonicalize(roundingMode);
|
|
||||||
this._check_limits();
|
this._check_limits();
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -133,8 +117,7 @@ Amount.prototype._set_value = function(value, roundingMode) {
|
|||||||
// Returns a new value which is the absolute value of this.
|
// Returns a new value which is the absolute value of this.
|
||||||
Amount.prototype.abs = function() {
|
Amount.prototype.abs = function() {
|
||||||
|
|
||||||
const val = (new IOUValue(this._value)).abs();
|
return this._copy(this._value.abs());
|
||||||
return this._copy(val);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -142,12 +125,10 @@ Amount.prototype.add = function(addend) {
|
|||||||
const addendAmount = Amount.from_json(addend);
|
const addendAmount = Amount.from_json(addend);
|
||||||
|
|
||||||
if (!this.is_comparable(addendAmount)) {
|
if (!this.is_comparable(addendAmount)) {
|
||||||
return new Amount(NaN);
|
return new Amount();
|
||||||
}
|
}
|
||||||
|
|
||||||
const thisValue = new IOUValue(this._value);
|
return this._copy(this._value.add(addendAmount._value));
|
||||||
const addendValue = new IOUValue(addendAmount._value);
|
|
||||||
return this._copy(thisValue.add(addendValue));
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -160,17 +141,8 @@ Amount.prototype.subtract = function(subtrahend) {
|
|||||||
Amount.prototype.multiply = function(multiplicand) {
|
Amount.prototype.multiply = function(multiplicand) {
|
||||||
|
|
||||||
const multiplicandAmount = Amount.from_json(multiplicand);
|
const multiplicandAmount = Amount.from_json(multiplicand);
|
||||||
const thisValue = new IOUValue(this._value);
|
|
||||||
|
|
||||||
let multiplyBy;
|
return this._copy(this._value.multiply(multiplicandAmount._value));
|
||||||
|
|
||||||
if (multiplicandAmount.is_native()) {
|
|
||||||
multiplyBy = new XRPValue(multiplicandAmount._value, Amount.bi_xns_unit);
|
|
||||||
return this._copy(thisValue.multiplyByXRP(multiplyBy)._value);
|
|
||||||
}
|
|
||||||
|
|
||||||
multiplyBy = new IOUValue(multiplicandAmount._value);
|
|
||||||
return this._copy(thisValue.multiply(multiplyBy));
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -180,17 +152,8 @@ Amount.prototype.scale = function(scaleFactor) {
|
|||||||
|
|
||||||
Amount.prototype.divide = function(divisor) {
|
Amount.prototype.divide = function(divisor) {
|
||||||
const divisorAmount = Amount.from_json(divisor);
|
const divisorAmount = Amount.from_json(divisor);
|
||||||
const thisValue = new IOUValue(this._value);
|
|
||||||
|
|
||||||
let divideBy;
|
return this._copy(this._value.divide(divisorAmount._value));
|
||||||
|
|
||||||
if (divisorAmount.is_native()) {
|
|
||||||
divideBy = new XRPValue(divisorAmount._value, Amount.bi_xns_unit);
|
|
||||||
return this._copy(thisValue.divideByXRP(divideBy)._value);
|
|
||||||
}
|
|
||||||
|
|
||||||
divideBy = new IOUValue(divisorAmount._value);
|
|
||||||
return this._copy(thisValue.divide(divideBy));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -248,7 +211,7 @@ Amount.prototype.ratio_human = function(denom, opts) {
|
|||||||
//
|
//
|
||||||
// To compensate, we multiply the numerator by 10^xns_precision.
|
// To compensate, we multiply the numerator by 10^xns_precision.
|
||||||
if (denominator._is_native) {
|
if (denominator._is_native) {
|
||||||
numerator._set_value(numerator.multiply(Amount.bi_xns_unit));
|
numerator._set_value(numerator.multiply(bi_xns_unit));
|
||||||
}
|
}
|
||||||
|
|
||||||
return numerator.divide(denominator);
|
return numerator.divide(denominator);
|
||||||
@@ -268,20 +231,20 @@ Amount.prototype.ratio_human = function(denom, opts) {
|
|||||||
*
|
*
|
||||||
* @see Amount#ratio_human
|
* @see Amount#ratio_human
|
||||||
*
|
*
|
||||||
* @param {Amount} fac The second factor of the product.
|
* @param {Amount} factor The second factor of the product.
|
||||||
* @param {Object} opts Options for the calculation.
|
* @param {Object} opts Options for the calculation.
|
||||||
* @param {Date|Number} opts.reference_date Date based on which
|
* @param {Date|Number} opts.reference_date Date based on which
|
||||||
* demurrage/interest should be applied. Can be given as JavaScript Date or int
|
* demurrage/interest should be applied. Can be given as JavaScript Date or int
|
||||||
* for Ripple epoch.
|
* for Ripple epoch.
|
||||||
* @return {Amount} The product. Unit will be the same as the first factor.
|
* @return {Amount} The product. Unit will be the same as the first factor.
|
||||||
*/
|
*/
|
||||||
Amount.prototype.product_human = function(fac, options = {}) {
|
Amount.prototype.product_human = function(factor, options = {}) {
|
||||||
|
|
||||||
let factor = Amount.from_json(fac);
|
let fac = Amount.from_json(factor);
|
||||||
|
|
||||||
// If either operand is NaN, the result is NaN.
|
// If either operand is NaN, the result is NaN.
|
||||||
if (!this.is_valid() || !factor.is_valid()) {
|
if (!this.is_valid() || !fac.is_valid()) {
|
||||||
return new Amount(NaN);
|
return new Amount();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply interest/demurrage
|
// Apply interest/demurrage
|
||||||
@@ -289,17 +252,17 @@ Amount.prototype.product_human = function(fac, options = {}) {
|
|||||||
// We only need to apply it to the second factor, because the currency unit of
|
// We only need to apply it to the second factor, because the currency unit of
|
||||||
// the first factor will carry over into the result.
|
// the first factor will carry over into the result.
|
||||||
if (options.reference_date) {
|
if (options.reference_date) {
|
||||||
factor = factor.applyInterest(options.reference_date);
|
fac = fac.applyInterest(options.reference_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
const product = this.multiply(factor);
|
const product = this.multiply(fac);
|
||||||
|
|
||||||
// Special case: The second factor is a native (XRP) amount expressed as base
|
// Special case: The second factor is a native (XRP) amount expressed as base
|
||||||
// units (1 XRP = 10^xns_precision base units).
|
// units (1 XRP = 10^xns_precision base units).
|
||||||
//
|
//
|
||||||
// See also Amount#ratio_human.
|
// See also Amount#ratio_human.
|
||||||
if (factor._is_native) {
|
if (fac._is_native) {
|
||||||
const quotient = product.divide(Amount.bi_xns_unit.toString());
|
const quotient = product.divide(bi_xns_unit.toString());
|
||||||
product._set_value(quotient._value);
|
product._set_value(quotient._value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,7 +276,7 @@ Amount.prototype.product_human = function(fac, options = {}) {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
Amount.prototype._invert = function() {
|
Amount.prototype._invert = function() {
|
||||||
this._set_value(inverse(this._value));
|
this._set_value(this._value.invert());
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -328,7 +291,7 @@ Amount.prototype.invert = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Canonicalize amount value
|
* Canonicalize amount value is now taken care of in the Value classes
|
||||||
*
|
*
|
||||||
* Mirrors rippled's internal Amount representation
|
* Mirrors rippled's internal Amount representation
|
||||||
* From https://github.com/ripple/rippled/blob/develop/src/ripple/data
|
* From https://github.com/ripple/rippled/blob/develop/src/ripple/data
|
||||||
@@ -357,19 +320,6 @@ Amount.prototype.invert = function() {
|
|||||||
* bigger than supported
|
* bigger than supported
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Amount.prototype.canonicalize = function(roundingMode) {
|
|
||||||
if (typeof this._value === 'undefined') {
|
|
||||||
throw new Error('undefined value');
|
|
||||||
}
|
|
||||||
if (this._is_native) {
|
|
||||||
this._value = this._value.round(6, Value.getBNRoundDown());
|
|
||||||
} else if (roundingMode) {
|
|
||||||
this._value = new Value(this._value.toPrecision(16, roundingMode))._value;
|
|
||||||
} else {
|
|
||||||
this._value = new Value(this._value.toPrecision(16))._value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Amount.prototype._check_limits = function() {
|
Amount.prototype._check_limits = function() {
|
||||||
if (!Amount.strict_mode) {
|
if (!Amount.strict_mode) {
|
||||||
return this;
|
return this;
|
||||||
@@ -377,7 +327,7 @@ Amount.prototype._check_limits = function() {
|
|||||||
if (this._value.isNaN() || this._value.isZero()) {
|
if (this._value.isNaN() || this._value.isZero()) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
const absval = this._value.absoluteValue();
|
const absval = this._value.abs();
|
||||||
if (this._is_native) {
|
if (this._is_native) {
|
||||||
if (absval.greaterThan(MAX_XRP_VALUE)) {
|
if (absval.greaterThan(MAX_XRP_VALUE)) {
|
||||||
throw new Error('Exceeding max value of ' + MAX_XRP_VALUE.toString());
|
throw new Error('Exceeding max value of ' + MAX_XRP_VALUE.toString());
|
||||||
@@ -406,7 +356,7 @@ Amount.prototype._copy = function(value) {
|
|||||||
Amount.prototype.compareTo = function(to) {
|
Amount.prototype.compareTo = function(to) {
|
||||||
const toAmount = Amount.from_json(to);
|
const toAmount = Amount.from_json(to);
|
||||||
if (!this.is_comparable(toAmount)) {
|
if (!this.is_comparable(toAmount)) {
|
||||||
return new Amount(NaN);
|
return new Amount();
|
||||||
}
|
}
|
||||||
return this._value.comparedTo(toAmount._value);
|
return this._value.comparedTo(toAmount._value);
|
||||||
};
|
};
|
||||||
@@ -414,7 +364,7 @@ Amount.prototype.compareTo = function(to) {
|
|||||||
// Make d a copy of this. Returns d.
|
// Make d a copy of this. Returns d.
|
||||||
// Modification of objects internally refered to is not allowed.
|
// Modification of objects internally refered to is not allowed.
|
||||||
Amount.prototype.copyTo = function(d, negate) {
|
Amount.prototype.copyTo = function(d, negate) {
|
||||||
d._value = negate ? this._value.negated() : this._value;
|
d._value = negate ? this._value.negate() : this._value;
|
||||||
d._is_native = this._is_native;
|
d._is_native = this._is_native;
|
||||||
d._currency = this._currency;
|
d._currency = this._currency;
|
||||||
d._issuer = this._issuer;
|
d._issuer = this._issuer;
|
||||||
@@ -525,7 +475,7 @@ Amount.prototype.parse_human = function(j, options) {
|
|||||||
value = words[0].slice(0, -3);
|
value = words[0].slice(0, -3);
|
||||||
currency = words[0].slice(-3);
|
currency = words[0].slice(-3);
|
||||||
if (!(isNumber(value) && currency.match(currency_RE))) {
|
if (!(isNumber(value) && currency.match(currency_RE))) {
|
||||||
return new Amount(NaN);
|
return new Amount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (words.length === 2) {
|
} else if (words.length === 2) {
|
||||||
@@ -539,22 +489,25 @@ Amount.prototype.parse_human = function(j, options) {
|
|||||||
value = words[0];
|
value = words[0];
|
||||||
currency = words[1];
|
currency = words[1];
|
||||||
} else {
|
} else {
|
||||||
return new Amount(NaN);
|
return new Amount();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return new Amount(NaN);
|
return new Amount();
|
||||||
}
|
}
|
||||||
|
|
||||||
currency = currency.toUpperCase();
|
currency = currency.toUpperCase();
|
||||||
this.set_currency(currency);
|
this.set_currency(currency);
|
||||||
this._is_native = (currency === 'XRP');
|
this._is_native = (currency === 'XRP');
|
||||||
this._set_value(new Value(value)._value);
|
const newValue =
|
||||||
|
(this._is_native ? new XRPValue(value) :
|
||||||
|
new IOUValue(value));
|
||||||
|
this._set_value(newValue);
|
||||||
|
|
||||||
// Apply interest/demurrage
|
// Apply interest/demurrage
|
||||||
if (opts.reference_date && this._currency.has_interest()) {
|
if (opts.reference_date && this._currency.has_interest()) {
|
||||||
const interest = this._currency.get_interest_at(opts.reference_date);
|
const interest = this._currency.get_interest_at(opts.reference_date);
|
||||||
this._set_value(
|
this._set_value(
|
||||||
new IOUValue(this._value).divide(new Value(interest.toString())));
|
this._value.divide(new IOUValue(interest.toString())));
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@@ -608,11 +561,9 @@ function(quality, counterCurrency, counterIssuer, opts) {
|
|||||||
const mantissa_hex = quality.substring(quality.length - 14);
|
const mantissa_hex = quality.substring(quality.length - 14);
|
||||||
const offset_hex = quality.substring(
|
const offset_hex = quality.substring(
|
||||||
quality.length - 16, quality.length - 14);
|
quality.length - 16, quality.length - 14);
|
||||||
const mantissa = new Value(mantissa_hex, 16)._value;
|
const mantissa = new IOUValue(mantissa_hex, null, 16);
|
||||||
const offset = parseInt(offset_hex, 16) - 100;
|
const offset = parseInt(offset_hex, 16) - 100;
|
||||||
|
|
||||||
const valueStr = mantissa.toString() + 'e' + offset.toString();
|
|
||||||
const value = new Value(valueStr)._value;
|
|
||||||
this._currency = Currency.from_json(counterCurrency);
|
this._currency = Currency.from_json(counterCurrency);
|
||||||
this._issuer = UInt160.from_json(counterIssuer);
|
this._issuer = UInt160.from_json(counterIssuer);
|
||||||
this._is_native = this._currency.is_native();
|
this._is_native = this._currency.is_native();
|
||||||
@@ -634,9 +585,9 @@ function(quality, counterCurrency, counterIssuer, opts) {
|
|||||||
quality as stored : 5 USD / 3000000 drops
|
quality as stored : 5 USD / 3000000 drops
|
||||||
inverted : 3000000 drops / 5 USD
|
inverted : 3000000 drops / 5 USD
|
||||||
*/
|
*/
|
||||||
const adjusted = options.inverse ? inverse(value) : value;
|
const valueStr = mantissa.toString() + 'e' + offset.toString();
|
||||||
let nativeAdjusted = this._is_native ?
|
let nativeAdjusted = new IOUValue(valueStr);
|
||||||
new XRPValue(adjusted, Amount.bi_xns_unit) : new IOUValue(adjusted);
|
nativeAdjusted = options.inverse ? nativeAdjusted.invert() : nativeAdjusted;
|
||||||
|
|
||||||
if (!options.xrp_as_drops) {
|
if (!options.xrp_as_drops) {
|
||||||
// `In a currency exchange, the exchange rate is quoted as the units of the
|
// `In a currency exchange, the exchange rate is quoted as the units of the
|
||||||
@@ -647,22 +598,26 @@ function(quality, counterCurrency, counterIssuer, opts) {
|
|||||||
if (this._is_native) {
|
if (this._is_native) {
|
||||||
// pay:$price drops get:1 X
|
// pay:$price drops get:1 X
|
||||||
// pay:($price / 1,000,000) XRP get:1 X
|
// pay:($price / 1,000,000) XRP get:1 X
|
||||||
nativeAdjusted = nativeAdjusted.divide(new Value(Amount.bi_xns_unit));
|
nativeAdjusted = nativeAdjusted.divide(bi_xns_unit);
|
||||||
} else if (baseCurrency.is_valid() && baseCurrency.is_native()) {
|
} else if (baseCurrency.is_valid() && baseCurrency.is_native()) {
|
||||||
// pay:$price X get:1 drop
|
// pay:$price X get:1 drop
|
||||||
// pay:($price * 1,000,000) X get:1 XRP
|
// pay:($price * 1,000,000) X get:1 XRP
|
||||||
nativeAdjusted = nativeAdjusted.multiply(new Value(Amount.bi_xns_unit));
|
nativeAdjusted = nativeAdjusted.multiply(bi_xns_unit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this._is_native) {
|
||||||
|
this._set_value(
|
||||||
|
new XRPValue(nativeAdjusted.round(6, Value.getBNRoundDown())));
|
||||||
|
} else {
|
||||||
this._set_value(nativeAdjusted);
|
this._set_value(nativeAdjusted);
|
||||||
|
}
|
||||||
|
|
||||||
if (options.reference_date && baseCurrency.is_valid()
|
if (options.reference_date && baseCurrency.is_valid()
|
||||||
&& baseCurrency.has_interest()) {
|
&& baseCurrency.has_interest()) {
|
||||||
const interest = baseCurrency.get_interest_at(options.reference_date);
|
const interest = baseCurrency.get_interest_at(options.reference_date);
|
||||||
this._set_value(
|
this._set_value(
|
||||||
new IOUValue(this._value).divide(new Value(interest.toString())));
|
this._value.divide(new IOUValue(interest.toString())));
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -670,7 +625,7 @@ Amount.prototype.parse_number = function(n) {
|
|||||||
this._is_native = false;
|
this._is_native = false;
|
||||||
this._currency = Currency.from_json(1);
|
this._currency = Currency.from_json(1);
|
||||||
this._issuer = UInt160.from_json(1);
|
this._issuer = UInt160.from_json(1);
|
||||||
this._set_value(new Value(n)._value);
|
this._set_value(new IOUValue(n));
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -721,7 +676,7 @@ Amount.prototype.parse_json = function(j) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
this._set_value(new Value(NaN)._value);
|
this._set_value(new IOUValue(NaN));
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@@ -736,11 +691,11 @@ Amount.prototype.parse_native = function(j) {
|
|||||||
if (j.indexOf('.') >= 0) {
|
if (j.indexOf('.') >= 0) {
|
||||||
throw new Error('Native amounts must be specified in integer drops');
|
throw new Error('Native amounts must be specified in integer drops');
|
||||||
}
|
}
|
||||||
const value = new XRPValue(j, Amount.bi_xns_unit);
|
const value = new XRPValue(j);
|
||||||
this._is_native = true;
|
this._is_native = true;
|
||||||
this._set_value(value.divide(new Value(Amount.bi_xns_unit)));
|
this._set_value(value.divide(bi_xns_unit));
|
||||||
} else {
|
} else {
|
||||||
this._set_value(new Value(NaN)._value);
|
this._set_value(new IOUValue(NaN));
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@@ -750,7 +705,8 @@ Amount.prototype.parse_native = function(j) {
|
|||||||
// Requires _currency to be set!
|
// Requires _currency to be set!
|
||||||
Amount.prototype.parse_value = function(j) {
|
Amount.prototype.parse_value = function(j) {
|
||||||
this._is_native = false;
|
this._is_native = false;
|
||||||
this._set_value(new Value(j)._value, Value.getBNRoundDown());
|
const newValue = new IOUValue(j, Value.getBNRoundDown());
|
||||||
|
this._set_value(newValue);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -781,14 +737,14 @@ Amount.prototype.to_text = function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this._is_native) {
|
if (this._is_native) {
|
||||||
return new XRPValue(this._value).multiply(
|
return this._value.multiply(bi_xns_unit).toString();
|
||||||
new Value(Amount.bi_xns_unit))._value.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// not native
|
// not native
|
||||||
const offset = this._value.e - 15;
|
const offset = this._value.getExponent() - 15;
|
||||||
const sign = this._value.isNegative() ? '-' : '';
|
const sign = this._value.isNegative() ? '-' : '';
|
||||||
const mantissa = utils.getMantissaDecimalString(this._value.absoluteValue());
|
const mantissa = utils.getMantissa16FromString(
|
||||||
|
this._value.abs().toString());
|
||||||
if (offset !== 0 && (offset < -25 || offset > -4)) {
|
if (offset !== 0 && (offset < -25 || offset > -4)) {
|
||||||
// Use e notation.
|
// Use e notation.
|
||||||
// XXX Clamp output.
|
// XXX Clamp output.
|
||||||
@@ -825,7 +781,7 @@ Amount.prototype.applyInterest = function(referenceDate) {
|
|||||||
}
|
}
|
||||||
const interest = this._currency.get_interest_at(referenceDate);
|
const interest = this._currency.get_interest_at(referenceDate);
|
||||||
return this._copy(
|
return this._copy(
|
||||||
new IOUValue(this._value).multiply(new Value(interest.toString())));
|
this._value.multiply(new IOUValue(interest.toString())));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1005,7 +961,7 @@ Amount.prototype.not_equals_why = function(d, ignore_issuer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const type = this._is_native ? 'XRP' : 'Non-XRP';
|
const type = this._is_native ? 'XRP' : 'Non-XRP';
|
||||||
if (!this._value.isZero() && this._value.negated().equals(d._value)) {
|
if (!this._value.isZero() && this._value.negate().equals(d._value)) {
|
||||||
return type + ' sign differs.';
|
return type + ' sign differs.';
|
||||||
}
|
}
|
||||||
if (!this._value.equals(d._value)) {
|
if (!this._value.equals(d._value)) {
|
||||||
|
|||||||
@@ -451,8 +451,7 @@ OrderBook.prototype.applyTransferRate = function(balance) {
|
|||||||
|
|
||||||
const adjustedBalance = (new IOUValue(balance))
|
const adjustedBalance = (new IOUValue(balance))
|
||||||
.divide(new IOUValue(this._issuerTransferRate))
|
.divide(new IOUValue(this._issuerTransferRate))
|
||||||
.multiply(new IOUValue(OrderBook.DEFAULT_TRANSFER_RATE))
|
.multiply(new IOUValue(OrderBook.DEFAULT_TRANSFER_RATE)).toString();
|
||||||
._value.toString();
|
|
||||||
|
|
||||||
return adjustedBalance;
|
return adjustedBalance;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -32,12 +32,7 @@ function createAmount(value, currency, counterparty) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function getCurrencyFromOffer(offer) {
|
function getCurrencyFromOffer(offer) {
|
||||||
let currency = offer.TakerPays.currency;
|
return offer.TakerPays.currency || offer.TakerGets.currency;
|
||||||
|
|
||||||
if (!currency) {
|
|
||||||
currency = offer.TakerGets.currency;
|
|
||||||
}
|
|
||||||
return currency;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,12 +42,7 @@ function getCurrencyFromOffer(offer) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function getIssuerFromOffer(offer) {
|
function getIssuerFromOffer(offer) {
|
||||||
let issuer = offer.TakerPays.issuer;
|
return offer.TakerPays.issuer || offer.TakerGets.issuer;
|
||||||
|
|
||||||
if (!issuer) {
|
|
||||||
issuer = offer.TakerGets.issuer;
|
|
||||||
}
|
|
||||||
return issuer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
function getMantissaDecimalString(bignum) {
|
// returns the mantissa from the passed in string,
|
||||||
let mantissa = bignum.toPrecision(16)
|
// adding zeros until it has 16 sd
|
||||||
.replace(/\./, '') // remove decimal point
|
function getMantissa16FromString(decimalString) {
|
||||||
|
let mantissa = decimalString.replace(/\./, '') // remove decimal point
|
||||||
.replace(/e.*/, '') // remove scientific notation
|
.replace(/e.*/, '') // remove scientific notation
|
||||||
.replace(/^0*/, ''); // remove leading zeroes
|
.replace(/^0*/, ''); // remove leading zeroes
|
||||||
while (mantissa.length < 16) {
|
while (mantissa.length < 16) {
|
||||||
@@ -11,6 +12,10 @@ function getMantissaDecimalString(bignum) {
|
|||||||
return mantissa;
|
return mantissa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getMantissaDecimalString(bignum) {
|
||||||
|
return getMantissa16FromString(bignum.toPrecision(16));
|
||||||
|
}
|
||||||
|
|
||||||
function trace(comment, func) {
|
function trace(comment, func) {
|
||||||
return function() {
|
return function() {
|
||||||
console.log('%s: %s', trace, arguments.toString);
|
console.log('%s: %s', trace, arguments.toString);
|
||||||
@@ -156,6 +161,7 @@ exports.arrayUnique = arrayUnique;
|
|||||||
exports.toTimestamp = toTimestamp;
|
exports.toTimestamp = toTimestamp;
|
||||||
exports.fromTimestamp = fromTimestamp;
|
exports.fromTimestamp = fromTimestamp;
|
||||||
exports.getMantissaDecimalString = getMantissaDecimalString;
|
exports.getMantissaDecimalString = getMantissaDecimalString;
|
||||||
|
exports.getMantissa16FromString = getMantissa16FromString;
|
||||||
|
|
||||||
exports.sjcl = require('sjcl-extended');
|
exports.sjcl = require('sjcl-extended');
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,16 @@ const BigNumber = GlobalBigNumber.another({
|
|||||||
DECIMAL_PLACES: 40
|
DECIMAL_PLACES: 40
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
class Value {
|
class Value {
|
||||||
|
|
||||||
constructor(value: string | BigNumber, base: number) {
|
constructor(value: string | BigNumber) {
|
||||||
this._value = new BigNumber(value, base);
|
if (this.constructor === 'Value') {
|
||||||
|
throw new Error(
|
||||||
|
'Cannot instantiate Value directly, it is an abstract base class');
|
||||||
|
}
|
||||||
|
this._value = new BigNumber(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static getBNRoundDown() {
|
static getBNRoundDown() {
|
||||||
@@ -25,35 +31,23 @@ class Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
add(addend: Value) {
|
add(addend: Value) {
|
||||||
|
assert(this.constructor === addend.constructor);
|
||||||
const result = this._value.plus(addend._value);
|
const result = this._value.plus(addend._value);
|
||||||
return this._canonicalize(result);
|
return this._canonicalize(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
subtract(subtrahend: Value) {
|
subtract(subtrahend: Value) {
|
||||||
|
assert(this.constructor === subtrahend.constructor);
|
||||||
const result = this._value.minus(subtrahend._value);
|
const result = this._value.minus(subtrahend._value);
|
||||||
return this._canonicalize(result);
|
return this._canonicalize(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
multiply(multiplicand: Value) {
|
multiply(multiplicand: Value) {
|
||||||
const val = this._value;
|
const result = this._value.times(multiplicand._value);
|
||||||
const mult = multiplicand._value;
|
|
||||||
const result = (val).times(mult);
|
|
||||||
return this._canonicalize(result);
|
return this._canonicalize(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
scale(scaleFactor: Value) {
|
|
||||||
const result = this._value.times(scaleFactor._value);
|
|
||||||
return this._canonicalize(result);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
divide(divisor: Value) {
|
divide(divisor: Value) {
|
||||||
if (this._value.isNaN()) {
|
|
||||||
throw new Error('Invalid dividend');
|
|
||||||
}
|
|
||||||
if (divisor.isNaN()) {
|
|
||||||
throw new Error('Invalid divisor');
|
|
||||||
}
|
|
||||||
if (divisor.isZero()) {
|
if (divisor.isZero()) {
|
||||||
throw new Error('divide by zero');
|
throw new Error('divide by zero');
|
||||||
}
|
}
|
||||||
@@ -66,6 +60,19 @@ class Value {
|
|||||||
return this._canonicalize(result);
|
return this._canonicalize(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
round(decimalPlaces: number, roundingMode: number) {
|
||||||
|
const result = this._value.round(decimalPlaces, roundingMode);
|
||||||
|
return this._canonicalize(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
toFixed(decimalPlaces: number, roundingMode: number) {
|
||||||
|
return this._value.toFixed(decimalPlaces, roundingMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
getExponent() {
|
||||||
|
return this._value.e;
|
||||||
|
}
|
||||||
|
|
||||||
isNaN() {
|
isNaN() {
|
||||||
return this._value.isNaN();
|
return this._value.isNaN();
|
||||||
}
|
}
|
||||||
@@ -78,8 +85,23 @@ class Value {
|
|||||||
return this._value.isNegative();
|
return this._value.isNegative();
|
||||||
}
|
}
|
||||||
|
|
||||||
negated() {
|
toString() {
|
||||||
return this._value.neg();
|
return this._value.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
greaterThan(comparator: Value) {
|
||||||
|
assert(this.constructor === comparator.constructor);
|
||||||
|
return this._value.greaterThan(comparator._value);
|
||||||
|
}
|
||||||
|
|
||||||
|
lessThan(comparator: Value) {
|
||||||
|
assert(this.constructor === comparator.constructor);
|
||||||
|
return this._value.lessThan(comparator._value);
|
||||||
|
}
|
||||||
|
|
||||||
|
comparedTo(comparator: Value) {
|
||||||
|
assert(this.constructor === comparator.constructor);
|
||||||
|
return this._value.comparedTo(comparator._value);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1186,19 +1186,19 @@ describe('Amount', function() {
|
|||||||
|
|
||||||
describe('amount limits', function() {
|
describe('amount limits', function() {
|
||||||
it('max JSON wire limite', function() {
|
it('max JSON wire limite', function() {
|
||||||
assert.strictEqual(Amount.bi_xns_max.toString(), '100000000000000000');
|
assert.strictEqual(Amount.bi_xns_max, '100000000000000000');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('max JSON wire limite', function() {
|
it('max JSON wire limite', function() {
|
||||||
assert.strictEqual(Amount.bi_xns_min.toString(), '-100000000000000000');
|
assert.strictEqual(Amount.bi_xns_min, '-100000000000000000');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('max mantissa value', function() {
|
it('max mantissa value', function() {
|
||||||
assert.strictEqual(Amount.bi_man_max_value.toString(), '9999999999999999');
|
assert.strictEqual(Amount.bi_man_max_value, '9999999999999999');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('min mantissa value', function() {
|
it('min mantissa value', function() {
|
||||||
assert.strictEqual(Amount.bi_man_min_value.toString(), '1000000000000000');
|
assert.strictEqual(Amount.bi_man_min_value, '1000000000000000');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('from_json minimum XRP', function() {
|
it('from_json minimum XRP', function() {
|
||||||
|
|||||||
Reference in New Issue
Block a user