diff --git a/src/core/amount.js b/src/core/amount.js index 0e50d7f2..98dd8bef 100644 --- a/src/core/amount.js +++ b/src/core/amount.js @@ -105,6 +105,19 @@ Amount.NaN = function() { return result; // but let's be careful }; +Amount.from_components_unsafe = function(value: Value, currency: Currency, + issuer: UInt160, isNative: boolean +) { + const result = new Amount(value); + result._is_native = isNative; + result._currency = currency; + result._issuer = issuer; + + result._value = value.isZero() && value.isNegative() ? + value.negate() : value; + return result; +}; + // be sure that _is_native is set properly BEFORE calling _set_value Amount.prototype._set_value = function(value: Value) { @@ -122,27 +135,30 @@ Amount.prototype.abs = function() { }; Amount.prototype.add = function(addend) { - const addendAmount = Amount.from_json(addend); + const addendAmount = addend instanceof Amount ? + addend : Amount.from_json(addend); if (!this.is_comparable(addendAmount)) { return new Amount(); } return this._copy(this._value.add(addendAmount._value)); - }; Amount.prototype.subtract = function(subtrahend) { // Correctness over speed, less code has less bugs, reuse add code. - return this.add(Amount.from_json(subtrahend).negate()); + const subsAmount = subtrahend instanceof Amount ? + subtrahend : Amount.from_json(subtrahend); + return this.add(subsAmount.negate()); }; // XXX Diverges from cpp. Amount.prototype.multiply = function(multiplicand) { + const multiplicandValue = multiplicand instanceof Amount ? + multiplicand._value : + Amount.from_json(multiplicand)._value; - const multiplicandAmount = Amount.from_json(multiplicand); - - return this._copy(this._value.multiply(multiplicandAmount._value)); + return this._copy(this._value.multiply(multiplicandValue)); }; @@ -151,9 +167,11 @@ Amount.prototype.scale = function(scaleFactor) { }; Amount.prototype.divide = function(divisor) { - const divisorAmount = Amount.from_json(divisor); + const divisorValue = divisor instanceof Amount ? + divisor._value : + Amount.from_json(divisor)._value; - return this._copy(this._value.divide(divisorAmount._value)); + return this._copy(this._value.divide(divisorValue)); }; /** @@ -344,7 +362,7 @@ Amount.prototype._check_limits = function() { }; Amount.prototype.clone = function(negate) { - return this.copyTo(new Amount(), negate); + return this.copyTo(new Amount(this._value), negate); }; Amount.prototype._copy = function(value) { @@ -354,9 +372,10 @@ Amount.prototype._copy = function(value) { }; Amount.prototype.compareTo = function(to) { - const toAmount = Amount.from_json(to); + const toAmount = to instanceof Amount ? to : Amount.from_json(to); + if (!this.is_comparable(toAmount)) { - return new Amount(); + throw new Error('Not comparable'); } return this._value.comparedTo(toAmount._value); }; @@ -730,6 +749,14 @@ Amount.prototype.to_number = function() { return Number(this.to_text()); }; + +// this one is needed because Value.abs creates new BigNumber, +// and BigNumber constructor is very slow, so we want to +// call it only if absolutely necessary +function absValue(value: Value): Value { + return value.isNegative() ? value.abs() : value; +} + // Convert only value to JSON wire format. Amount.prototype.to_text = function() { if (!this.is_valid()) { @@ -743,8 +770,8 @@ Amount.prototype.to_text = function() { // not native const offset = this._value.getExponent() - 15; const sign = this._value.isNegative() ? '-' : ''; - const mantissa = utils.getMantissa16FromString( - this._value.abs().toString()); + const mantissa = + utils.getMantissa16FromString(absValue(this._value).toString()); if (offset !== 0 && (offset < -25 || offset > -4)) { // Use e notation. // XXX Clamp output. diff --git a/src/core/autobridgecalculator.js b/src/core/autobridgecalculator.js index 746a085d..9b2a6e60 100644 --- a/src/core/autobridgecalculator.js +++ b/src/core/autobridgecalculator.js @@ -18,17 +18,24 @@ function assertValidLegOneOffer(legOneOffer, message) { } function AutobridgeCalculator(currencyGets, currencyPays, - legOneOffers, legTwoOffers, issuerGets, issuerPays) { + legOneOffers, legTwoOffers, issuerGets, issuerPays +) { this._currencyGets = currencyGets; this._currencyPays = currencyPays; + this._currencyGetsHex = currencyGets.to_hex(); + this._currencyPaysHex = currencyPays.to_hex(); this._issuerGets = issuerGets; + this._issuerGetsObj = UInt160.from_json(issuerGets); this._issuerPays = issuerPays; + this._issuerPaysObj = UInt160.from_json(issuerPays); this.legOneOffers = _.cloneDeep(legOneOffers); this.legTwoOffers = _.cloneDeep(legTwoOffers); this._ownerFundsLeftover = {}; } +const NULL_AMOUNT = Utils.normalizeAmount('0'); + /** * Calculates an ordered array of autobridged offers by quality * @@ -36,10 +43,13 @@ function AutobridgeCalculator(currencyGets, currencyPays, */ AutobridgeCalculator.prototype.calculate = function() { + const oldMode = Amount.strict_mode; + Amount.strict_mode = false; + let legOnePointer = 0; let legTwoPointer = 0; - let offersAutobridged = []; + const offersAutobridged = []; this.clearOwnerFundsLeftover(); @@ -55,8 +65,10 @@ AutobridgeCalculator.prototype.calculate = function() { this.adjustLegOneFundedAmount(legOneOffer); } - const legOneTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer); - const legTwoTakerPaysFunded = Utils.getOfferTakerPaysFunded(legTwoOffer); + const legOneTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer, + this._currencyPays, this._issuerPaysObj); + const legTwoTakerPaysFunded = Utils.getOfferTakerPaysFunded(legTwoOffer, + this._currencyGets, this._issuerGetsObj); if (legOneTakerGetsFunded.is_zero()) { legOnePointer++; @@ -70,14 +82,17 @@ AutobridgeCalculator.prototype.calculate = function() { continue; } - if (legOneTakerGetsFunded.compareTo(legTwoTakerPaysFunded) > 0) { + // using private fields for speed + if (legOneTakerGetsFunded._value.comparedTo( + legTwoTakerPaysFunded._value) > 0) { autobridgedOffer = this.getAutobridgedOfferWithClampedLegOne( legOneOffer, legTwoOffer ); legTwoPointer++; - } else if (legTwoTakerPaysFunded.compareTo(legOneTakerGetsFunded) > 0) { + } else if (legTwoTakerPaysFunded._value.comparedTo( + legOneTakerGetsFunded._value) > 0) { autobridgedOffer = this.getAutobridgedOfferWithClampedLegTwo( legOneOffer, legTwoOffer @@ -97,6 +112,7 @@ AutobridgeCalculator.prototype.calculate = function() { offersAutobridged.push(autobridgedOffer); } + Amount.strict_mode = oldMode; return offersAutobridged; }; @@ -112,15 +128,20 @@ AutobridgeCalculator.prototype.calculate = function() { AutobridgeCalculator.prototype.getAutobridgedOfferWithClampedLegOne = function(legOneOffer, legTwoOffer) { - const legOneTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer); - const legTwoTakerPaysFunded = Utils.getOfferTakerPaysFunded(legTwoOffer); - const legOneQuality = Utils.getOfferQuality(legOneOffer, this._currencyGets); + const legOneTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer, + this._currencyPays, this._issuerPaysObj); + const legTwoTakerPaysFunded = Utils.getOfferTakerPaysFunded(legTwoOffer, + this._currencyGets, this._issuerGetsObj); + const legOneQuality = Utils.getOfferQuality(legOneOffer, this._currencyGets, + this._currencyPays, this._issuerPaysObj); - const autobridgedTakerGets = Utils.getOfferTakerGetsFunded(legTwoOffer); + const autobridgedTakerGets = Utils.getOfferTakerGetsFunded(legTwoOffer, + this._currencyGets, this._issuerGetsObj); const autobridgedTakerPays = legTwoTakerPaysFunded.multiply(legOneQuality); if (legOneOffer.Account === legTwoOffer.Account) { - const legOneTakerGets = Utils.getOfferTakerGets(legOneOffer); + const legOneTakerGets = Utils.getOfferTakerGets(legOneOffer, + this._currencyPays, this._issuerPaysObj); const updatedTakerGets = legOneTakerGets.subtract(legTwoTakerPaysFunded); this.setLegOneTakerGets(legOneOffer, updatedTakerGets); @@ -152,15 +173,20 @@ function(legOneOffer, legTwoOffer) { AutobridgeCalculator.prototype.getAutobridgedOfferWithClampedLegTwo = function(legOneOffer, legTwoOffer) { - const legOneTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer); - const legTwoTakerPaysFunded = Utils.getOfferTakerPaysFunded(legTwoOffer); - const legTwoQuality = Utils.getOfferQuality(legTwoOffer, this._currencyGets); + const legOneTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer, + this._currencyPays, this._issuerPaysObj); + const legTwoTakerPaysFunded = Utils.getOfferTakerPaysFunded(legTwoOffer, + this._currencyGets, this._issuerGetsObj); + const legTwoQuality = Utils.getOfferQuality(legTwoOffer, this._currencyGets, + this._currencyGets, this._issuerGetsObj); const autobridgedTakerGets = legOneTakerGetsFunded.divide(legTwoQuality); - const autobridgedTakerPays = Utils.getOfferTakerPaysFunded(legOneOffer); + const autobridgedTakerPays = Utils.getOfferTakerPaysFunded(legOneOffer, + this._currencyPays, this._issuerPaysObj); // Update funded amount since leg two offer was not completely consumed - legTwoOffer.taker_gets_funded = Utils.getOfferTakerGetsFunded(legTwoOffer) + legTwoOffer.taker_gets_funded = Utils.getOfferTakerGetsFunded(legTwoOffer, + this._currencyGets, this._issuerGetsObj) .subtract(autobridgedTakerGets) .to_text(); legTwoOffer.taker_pays_funded = legTwoTakerPaysFunded @@ -184,8 +210,10 @@ function(legOneOffer, legTwoOffer) { AutobridgeCalculator.prototype.getAutobridgedOfferWithoutClamps = function(legOneOffer, legTwoOffer) { - const autobridgedTakerGets = Utils.getOfferTakerGetsFunded(legTwoOffer); - const autobridgedTakerPays = Utils.getOfferTakerPaysFunded(legOneOffer); + const autobridgedTakerGets = Utils.getOfferTakerGetsFunded(legTwoOffer, + this._currencyGets, this._issuerGetsObj); + const autobridgedTakerPays = Utils.getOfferTakerPaysFunded(legOneOffer, + this._currencyPays, this._issuerPaysObj); return this.formatAutobridgedOffer( autobridgedTakerGets, @@ -210,9 +238,7 @@ AutobridgeCalculator.prototype.clearOwnerFundsLeftover = function() { */ AutobridgeCalculator.prototype.resetOwnerFundsLeftover = function(account) { - assert(UInt160.is_valid(account), 'Account is invalid'); - - this._ownerFundsLeftover[account] = Utils.normalizeAmount('0'); + this._ownerFundsLeftover[account] = NULL_AMOUNT.clone(); return this._ownerFundsLeftover[account]; }; @@ -226,12 +252,10 @@ AutobridgeCalculator.prototype.resetOwnerFundsLeftover = function(account) { */ AutobridgeCalculator.prototype.getLeftoverOwnerFunds = function(account) { - assert(UInt160.is_valid(account), 'Account is invalid'); - let amount = this._ownerFundsLeftover[account]; if (!amount) { - amount = Utils.normalizeAmount('0'); + amount = NULL_AMOUNT.clone(); } return amount; @@ -248,7 +272,6 @@ AutobridgeCalculator.prototype.getLeftoverOwnerFunds = function(account) { AutobridgeCalculator.prototype.addLeftoverOwnerFunds = function(account, amount) { - assert(UInt160.is_valid(account), 'Account is invalid'); assert(amount instanceof Amount, 'Amount is invalid'); this._ownerFundsLeftover[account] = this.getLeftoverOwnerFunds(account) @@ -266,7 +289,6 @@ function(account, amount) { AutobridgeCalculator.prototype.setLeftoverOwnerFunds = function(account, amount) { - assert(UInt160.is_valid(account), 'Account is invalid'); assert(amount instanceof Amount, 'Amount is invalid'); this._ownerFundsLeftover[account] = amount; @@ -291,13 +313,13 @@ function(takerGets, takerPays) { autobridgedOffer.TakerGets = { value: takerGets.to_text(), - currency: this._currencyGets.to_hex(), + currency: this._currencyGetsHex, issuer: this._issuerGets }; autobridgedOffer.TakerPays = { value: takerPays.to_text(), - currency: this._currencyPays.to_hex(), + currency: this._currencyPaysHex, issuer: this._issuerPays }; @@ -308,7 +330,9 @@ function(takerGets, takerPays) { autobridgedOffer.autobridged = true; - autobridgedOffer.BookDirectory = Utils.convertOfferQualityToHex(quality); + autobridgedOffer.BookDirectory = + Utils.convertOfferQualityToHexFromText(autobridgedOffer.quality); + autobridgedOffer.qualityHex = autobridgedOffer.BookDirectory; return autobridgedOffer; }; @@ -325,11 +349,13 @@ function(takerGets, takerPays) { AutobridgeCalculator.prototype.unclampLegOneOwnerFunds = function(legOneOffer) { assertValidLegOneOffer(legOneOffer, 'Leg one offer is invalid'); - legOneOffer.initTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer); + legOneOffer.initTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer, + this._currencyPays, this._issuerPaysObj); this.setLegOneTakerGetsFunded( legOneOffer, - Utils.getOfferTakerGets(legOneOffer) + Utils.getOfferTakerGets(legOneOffer, this._currencyPays, + this._issuerPaysObj) ); }; @@ -350,7 +376,8 @@ AutobridgeCalculator.prototype.unclampLegOneOwnerFunds = function(legOneOffer) { AutobridgeCalculator.prototype.clampLegOneOwnerFunds = function(legOneOffer) { assertValidLegOneOffer(legOneOffer, 'Leg one offer is invalid'); - const takerGets = Utils.getOfferTakerGets(legOneOffer); + const takerGets = Utils.getOfferTakerGets(legOneOffer, this._currencyPays, + this._issuerPaysObj); if (takerGets.compareTo(legOneOffer.initTakerGetsFunded) > 0) { // After clamping, TakerGets is still greater than initial funded amount @@ -375,12 +402,16 @@ function(legOneOffer) { assertValidLegOneOffer(legOneOffer, 'Leg one offer is invalid'); assert(!legOneOffer.is_fully_funded, 'Leg one offer cannot be fully funded'); - const fundedSum = Utils.getOfferTakerGetsFunded(legOneOffer) + const fundedSum = Utils.getOfferTakerGetsFunded(legOneOffer, + this._currencyPays, this._issuerPaysObj) .add(this.getLeftoverOwnerFunds(legOneOffer.Account)); - if (fundedSum.compareTo(Utils.getOfferTakerGets(legOneOffer)) >= 0) { + if (fundedSum.compareTo(Utils.getOfferTakerGets(legOneOffer, + this._currencyPays, this._issuerPaysObj)) >= 0 + ) { // There are enough extra funds to fully fund the offer - const legOneTakerGets = Utils.getOfferTakerGets(legOneOffer); + const legOneTakerGets = Utils.getOfferTakerGets(legOneOffer, + this._currencyPays, this._issuerPaysObj); const updatedLeftover = fundedSum.subtract(legOneTakerGets); this.setLegOneTakerGetsFunded(legOneOffer, legOneTakerGets); @@ -407,8 +438,9 @@ function setLegOneTakerGetsFunded(legOneOffer, takerGetsFunded) { legOneOffer.taker_gets_funded = takerGetsFunded.to_text(); legOneOffer.taker_pays_funded = takerGetsFunded - .multiply(Utils.getOfferQuality(legOneOffer, this._currencyGets)) - .to_text(); + .multiply(Utils.getOfferQuality(legOneOffer, this._currencyGets, + this._currencyPays, this._issuerPaysObj)) + .to_text(); if (legOneOffer.taker_gets_funded === legOneOffer.TakerGets.value) { legOneOffer.is_fully_funded = true; @@ -428,10 +460,11 @@ function(legOneOffer, takerGets) { assertValidLegOneOffer(legOneOffer, 'Leg one offer is invalid'); assert(takerGets instanceof Amount, 'Taker gets funded is invalid'); - const legOneQuality = Utils.getOfferQuality(legOneOffer, this._currencyGets); + const legOneQuality = Utils.getOfferQuality(legOneOffer, this._currencyGets, + this._currencyPays, this._issuerPaysObj); legOneOffer.TakerGets = takerGets.to_text(); - legOneOffer.TakerPays = takerGets.multiply(legOneQuality); + legOneOffer.TakerPays = takerGets.multiply(legOneQuality).to_json(); }; module.exports = AutobridgeCalculator; diff --git a/src/core/baseconverter.js b/src/core/baseconverter.js index 6c0bc541..34650dbf 100644 --- a/src/core/baseconverter.js +++ b/src/core/baseconverter.js @@ -1,28 +1,41 @@ 'use strict'; + function normalize(digitArray) { - while (digitArray[0] === 0) { - digitArray.shift(); + let i = 0; + while (digitArray[i] === 0) { + ++i; + } + if (i > 0) { + digitArray.splice(0, i); } return digitArray; } function divmod(digitArray, base, divisor) { - var remainder = 0; - var quotient = []; - for (var j = 0; j < digitArray.length; j++) { - var temp = remainder * base + parseInt(digitArray[j], 10); - quotient.push(Math.floor(temp / divisor)); + let remainder = 0; + let temp; + let divided; + let j = -1; + + const length = digitArray.length; + const quotient = new Array(length); + + while (++j < length) { + temp = remainder * base + digitArray[j]; + divided = temp / divisor; + quotient[j] = divided << 0; remainder = temp % divisor; } return {quotient: normalize(quotient), remainder: remainder}; } function convertBase(digitArray, fromBase, toBase) { - var result = []; - var dividend = digitArray; + const result = []; + let dividend = digitArray; + let qr; while (dividend.length > 0) { - var qr = divmod(dividend, fromBase, toBase); + qr = divmod(dividend, fromBase, toBase); result.unshift(qr.remainder); dividend = qr.quotient; } diff --git a/src/core/currency.js b/src/core/currency.js index 66a7e603..a23e97f0 100644 --- a/src/core/currency.js +++ b/src/core/currency.js @@ -1,15 +1,15 @@ 'use strict'; -var extend = require('extend'); -var UInt160 = require('./uint160').UInt160; -var utils = require('./utils'); -var Float = require('./ieee754').Float; +const extend = require('extend'); +const UInt160 = require('./uint160').UInt160; +const utils = require('./utils'); +const Float = require('./ieee754').Float; // // Currency support // -var Currency = extend(function() { +const Currency = extend(function() { // Internal form: 0 = XRP. 3 letter-code. // XXX Internal should be 0 or hex with three letter annotation when valid. @@ -22,7 +22,7 @@ var Currency = extend(function() { this._update(); }, UInt160); -Currency.prototype = extend({}, UInt160.prototype); +Currency.prototype = Object.create(extend({}, UInt160.prototype)); Currency.prototype.constructor = Currency; Currency.HEX_CURRENCY_BAD = '0000000000000000000000005852500000000000'; @@ -61,12 +61,12 @@ Currency.HEX_CURRENCY_BAD = '0000000000000000000000005852500000000000'; * */ -/*eslint-disable max-len*/ +/* eslint-disable max-len*/ Currency.prototype.human_RE = /^\s*([a-zA-Z0-9\<\>\(\)\{\}\[\]\|\?\!\@\#\$\%\^\&]{3})(\s*-\s*[- \w]+)?(\s*\(-?\d+\.?\d*%pa\))?\s*$/; -/*eslint-enable max-len*/ +/* eslint-enable max-len*/ Currency.from_json = function(j, shouldInterpretXrpAsIou) { - return (new Currency()).parse_json(j, shouldInterpretXrpAsIou); + return (new Currency()).parse_json(j, shouldInterpretXrpAsIou); }; Currency.from_human = function(j, opts) { @@ -78,7 +78,7 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) { this._value = NaN; if (j instanceof Currency) { - this._value = j.copyTo({})._value; + this._value = j._value; this._update(); return this; } @@ -111,10 +111,10 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) { } // match the given string to see if it's in an allowed format - var matches = j.match(this.human_RE); + const matches = j.match(this.human_RE); if (matches) { - var currencyCode = matches[1]; + let currencyCode = matches[1]; // for the currency 'XRP' case // we drop everything else that could have been provided @@ -131,14 +131,14 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) { // the full currency is matched as it is part of the valid currency // format, but not stored // var full_currency = matches[2] || ''; - var interest = matches[3] || ''; + const interest = matches[3] || ''; // interest is defined as interest per year, per annum (pa) - var percentage = interest.match(/(-?\d+\.?\d+)/); + let percentage = interest.match(/(-?\d+\.?\d+)/); currencyCode = currencyCode.toUpperCase(); - var currencyData = utils.arraySet(20, 0); + const currencyData = utils.arraySet(20, 0); if (percentage) { /* @@ -164,15 +164,15 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) { // the interest or demurrage is expressed as a yearly (per annum) // value - var secondsPerYear = 31536000; // 60 * 60 * 24 * 365 + const secondsPerYear = 31536000; // 60 * 60 * 24 * 365 // Calculating the interest e-fold // 0.5% demurrage is expressed 0.995, 0.005 less than 1 // 0.5% interest is expressed as 1.005, 0.005 more than 1 - var interestEfold = secondsPerYear / Math.log(1 + percentage / 100); - var bytes = Float.toIEEE754Double(interestEfold); + const interestEfold = secondsPerYear / Math.log(1 + percentage / 100); + const bytes = Float.toIEEE754Double(interestEfold); - for (var i = 0; i <= bytes.length; i++) { + for (let i = 0; i <= bytes.length; i++) { currencyData[8 + i] = bytes[i] & 0xff; } @@ -204,10 +204,10 @@ Currency.prototype.parse_human = function(j) { */ Currency.prototype._update = function() { - var bytes = this.to_bytes(); + const bytes = this.to_bytes(); // is it 0 everywhere except 12, 13, 14? - var isZeroExceptInStandardPositions = true; + let isZeroExceptInStandardPositions = true; if (!bytes) { return; @@ -219,7 +219,7 @@ Currency.prototype._update = function() { this._interest_period = NaN; this._iso_code = ''; - for (var i = 0; i < 20; i++) { + for (let i = 0; i < 20; i++) { isZeroExceptInStandardPositions = isZeroExceptInStandardPositions && (i === 12 || i === 13 || i === 14 || bytes[i] === 0); } @@ -249,6 +249,34 @@ Currency.prototype._update = function() { } }; +/** + * Returns copy. + * + * This copies code from UInt.copyTo so we do not call _update, + * bvecause to_bytes is very expensive. + */ + +Currency.prototype.copyTo = function(d) { + d._value = this._value; + + if (this._version_byte !== undefined) { + d._version_byte = this._version_byte; + } + + if (!d.is_valid()) { + return d; + } + + d._native = this._native; + d._type = this._type; + d._interest_start = this._interest_start; + d._interest_period = this._interest_period; + d._iso_code = this._iso_code; + + return d; +}; + + // XXX Probably not needed anymore? /* Currency.prototype.parse_bytes = function(byte_array) { @@ -300,18 +328,20 @@ Currency.prototype.has_interest = function() { /** * - * @param {number} referenceDate number of seconds since the Ripple Epoch + * @param {number} referenceDate_ number of seconds since the Ripple Epoch * (0:00 on January 1, 2000 UTC) used to calculate the * interest over provided interval pass in one years * worth of seconds to ge the yearly interest * @returns {number} interest for provided interval, can be negative for * demurred currencies */ -Currency.prototype.get_interest_at = function(referenceDate) { +Currency.prototype.get_interest_at = function(referenceDate_) { if (!this.has_interest()) { return 0; } + let referenceDate = referenceDate_; + // use one year as a default period if (!referenceDate) { referenceDate = this._interest_start + 3600 * 24 * 365; @@ -326,13 +356,14 @@ Currency.prototype.get_interest_at = function(referenceDate) { / this._interest_period); }; -Currency.prototype.get_interest_percentage_at -= function(referenceDate, decimals) { - var interest = this.get_interest_at(referenceDate, decimals); +Currency.prototype.get_interest_percentage_at = function(referenceDate, + decimals +) { + let interest = this.get_interest_at(referenceDate, decimals); // convert to percentage interest = (interest * 100) - 100; - var decimalMultiplier = decimals ? Math.pow(10, decimals) : 100; + const decimalMultiplier = decimals ? Math.pow(10, decimals) : 100; // round to two decimals behind the dot return Math.round(interest * decimalMultiplier) / decimalMultiplier; @@ -347,18 +378,14 @@ Currency.prototype.get_interest_percentage_at // return UInt.prototype.is_valid() && ...; // }; -Currency.prototype.to_json = function(opts) { +Currency.prototype.to_json = function(opts = {}) { if (!this.is_valid()) { // XXX This is backwards compatible behavior, but probably not very good. return 'XRP'; } - if (!opts) { - opts = {}; - } - - var currency; - var fullName = opts && opts.full_name ? ' - ' + opts.full_name : ''; + let currency; + const fullName = opts && opts.full_name ? ' - ' + opts.full_name : ''; opts.show_interest = opts.show_interest !== undefined ? opts.show_interest : this.has_interest(); @@ -366,8 +393,8 @@ Currency.prototype.to_json = function(opts) { if (!opts.force_hex && /^[A-Z0-9]{3}$/.test(this._iso_code)) { currency = this._iso_code + fullName; if (opts.show_interest) { - var decimals = !isNaN(opts.decimals) ? opts.decimals : undefined; - var interestPercentage = this.has_interest() + const decimals = !isNaN(opts.decimals) ? opts.decimals : undefined; + const interestPercentage = this.has_interest() ? this.get_interest_percentage_at( this._interest_start + 3600 * 24 * 365, decimals ) diff --git a/src/core/index.js b/src/core/index.js index f90d6e18..97d5c76d 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -21,6 +21,7 @@ exports.TransactionQueue = require('./transactionqueue').TransactionQueue; exports.convertBase = require('./baseconverter'); exports._test = { + IOUValue: require('./iouvalue').IOUValue, Log: require('./log'), PathFind: require('./pathfind').PathFind, TransactionManager: require('./transactionmanager').TransactionManager, diff --git a/src/core/orderbook.js b/src/core/orderbook.js index 10360bd3..676f2104 100644 --- a/src/core/orderbook.js +++ b/src/core/orderbook.js @@ -24,8 +24,15 @@ const OrderBookUtils = require('./orderbookutils'); const log = require('./log').internal.sub('orderbook'); const IOUValue = require('./iouvalue').IOUValue; -function assertValidNumber(number, message) { - assert(!_.isNull(number) && !isNaN(number), message); +function _sortOffers(a, b) { + const aQuality = OrderBookUtils.getOfferQuality(a, this._currencyGets); + const bQuality = OrderBookUtils.getOfferQuality(b, this._currencyGets); + + return aQuality._value.comparedTo(bQuality._value); +} + +function _sortOffersQuick(a, b) { + return a.qualityHex.localeCompare(b.qualityHex); } /** @@ -36,11 +43,13 @@ function assertValidNumber(number, message) { * @param {String} bid currency * @param {String} bid issuer * @param {String} orderbook key + * @param {Boolean} fire 'model' event after receiving transaction + only once in 10 seconds */ function OrderBook(remote, - currencyGets, issuerGets, currencyPays, issuerPays, - key) { + currencyGets, issuerGets, currencyPays, issuerPays, key +) { EventEmitter.call(this); const self = this; @@ -61,6 +70,8 @@ function OrderBook(remote, this._ownerFundsUnadjusted = {}; this._ownerFunds = {}; this._ownerOffersTotal = {}; + this._validAccounts = {}; + this._validAccountsCount = 0; // We consider ourselves synced if we have a current // copy of the offers, we are online and subscribed to updates @@ -73,13 +84,44 @@ function OrderBook(remote, // books that we must keep track of to compute autobridged offers this._legOneBook = null; this._legTwoBook = null; + this._gotOffersFromLegOne = false; + this._gotOffersFromLegTwo = false; + + this.sortOffers = this._currencyGets.has_interest() ? + _sortOffers.bind(this) : _sortOffersQuick; + + this.notifyDirectOffersChanged = + _.debounce( + this.notifyDirectOffersChangedInternal, + OrderBook.NOTIFY_TIMEOUT, + {maxWait: OrderBook.NOTIFY_MAXWAIT}); this._isAutobridgeable = !this._currencyGets.is_native() && !this._currencyPays.is_native(); - function computeAutobridgedOffersWrapper() { - self.computeAutobridgedOffers(); - self.mergeDirectAndAutobridgedBooks(); + this._autobridgeThrottleTimeMultiplier = 1; + this.createDebouncedOffersWrapper(); + + function computeAutobridgedOffersWrapperOne() { + self._gotOffersFromLegOne = true; + self.computeAutobridgedOffersThrottled(); + } + + function computeAutobridgedOffersWrapperTwo() { + self._gotOffersFromLegTwo = true; + self.computeAutobridgedOffersThrottled(); + } + + function onDisconnect() { + self.resetCache(); + self._gotOffersFromLegOne = false; + self._gotOffersFromLegTwo = false; + if (!self._destroyed) { + self._remote.once('disconnect', onDisconnect); + self._remote.once('connect', function() { + self.subscribe(); + }); + } } if (this._isAutobridgeable) { @@ -89,15 +131,15 @@ function OrderBook(remote, issuer_pays: issuerPays }); - this._legOneBook.on('model', computeAutobridgedOffersWrapper); - this._legTwoBook = remote.createOrderBook({ currency_gets: currencyGets, issuer_gets: issuerGets, currency_pays: 'XRP' }); + } - this._legTwoBook.on('model', computeAutobridgedOffersWrapper); + function updateFundedAmountsWrapper(transaction) { + self.updateFundedAmounts(transaction); } function listenersModified(action, event) { @@ -107,7 +149,16 @@ function OrderBook(remote, switch (action) { case 'add': if (++self._listeners === 1) { + self._shouldSubscribe = true; self.subscribe(); + + self._remote.on('transaction', updateFundedAmountsWrapper); + self._remote.once('disconnect', onDisconnect); + + if (self._isAutobridgeable) { + self._legOneBook.on('model', computeAutobridgedOffersWrapperOne); + self._legTwoBook.on('model', computeAutobridgedOffersWrapperTwo); + } } break; case 'remove': @@ -119,10 +170,6 @@ function OrderBook(remote, } } - function updateFundedAmountsWrapper(transaction) { - self.updateFundedAmounts(transaction); - } - this.on('newListener', function(event) { listenersModified('add', event); }); @@ -131,23 +178,21 @@ function OrderBook(remote, listenersModified('remove', event); }); - this._remote.on('transaction', updateFundedAmountsWrapper); - this.on('unsubscribe', function() { self.resetCache(); self._remote.removeListener('transaction', updateFundedAmountsWrapper); - }); + self._remote.removeListener('disconnect', onDisconnect); - this._remote.once('prepare_subscribe', function() { - self.subscribe(); - }); + self._gotOffersFromLegOne = false; + self._gotOffersFromLegTwo = false; - this._remote.on('disconnect', function() { - self.resetCache(); - self._remote.once('prepare_subscribe', function() { - self.subscribe(); - }); + if (self._isAutobridgeable) { + self._legOneBook.removeListener('model', + computeAutobridgedOffersWrapperOne); + self._legTwoBook.removeListener('model', + computeAutobridgedOffersWrapperTwo); + } }); return this; @@ -165,7 +210,21 @@ OrderBook.EVENTS = [ 'offer_changed', 'offer_funds_changed' ]; -OrderBook.DEFAULT_TRANSFER_RATE = 1000000000; +OrderBook.DEFAULT_TRANSFER_RATE = new IOUValue(1000000000); + +OrderBook.NOTIFY_TIMEOUT = 100; + +OrderBook.NOTIFY_MAXWAIT = 250; + +OrderBook.AUTOBRIDGE_CALCULATE_THROTTLE_TIME = 1000; + +OrderBook.AUTOBRIDGE_CALCULATE_DEBOUNCE_TIME = 250; + +OrderBook.AUTOBRIDGE_CALCULATE_DEBOUNCE_MAXWAIT = 500; + +OrderBook.ZERO_NATIVE_AMOUNT = Amount.from_json('0'); + +OrderBook.ZERO_NORMALIZED_AMOUNT = OrderBookUtils.normalizeAmount('0'); /** * Normalize offers from book_offers and transaction stream @@ -192,18 +251,20 @@ OrderBook.offerRewrite = function(offer) { result.Flags = result.Flags || 0; result.OwnerNode = result.OwnerNode || new Array(16 + 1).join('0'); result.BookNode = result.BookNode || new Array(16 + 1).join('0'); + result.qualityHex = result.BookDirectory.slice(-16); return result; }; /** * Initialize orderbook. Get orderbook offers and subscribe to transactions + * @api private */ OrderBook.prototype.subscribe = function() { const self = this; - if (!this._shouldSubscribe) { + if (!this._shouldSubscribe || this._destroyed) { return; } @@ -216,7 +277,7 @@ OrderBook.prototype.subscribe = function() { self.requestTransferRate(callback); }, function(callback) { - self.requestOffers(callback); + self.requestOffers(callback, true); }, function(callback) { self.subscribeTransactions(callback); @@ -229,6 +290,7 @@ OrderBook.prototype.subscribe = function() { /** * Unhook event listeners and prevent ripple-lib from further work on this * orderbook. There is no more orderbook stream, so "unsubscribe" is nominal + * @api private */ OrderBook.prototype.unsubscribe = function() { @@ -250,33 +312,75 @@ OrderBook.prototype.unsubscribe = function() { this.emit('unsubscribe'); }; +/** + * After that you can't use this object. + */ + +OrderBook.prototype.destroy = function() { + this._destroyed = true; + if (this._subscribed) { + this.unsubscribe(); + } + + if (this._remote._books.hasOwnProperty(this._key)) { + delete this._remote._books[this._key]; + } + + if (this._isAutobridgeable) { + this._legOneBook.destroy(); + this._legTwoBook.destroy(); + } +}; + /** * Request orderbook entries from server * * @param {Function} callback */ -OrderBook.prototype.requestOffers = function(callback=function() {}) { +OrderBook.prototype.requestOffers = function(callback = function() {}, + internal = false) { const self = this; + if (!this._remote.isConnected()) { + // do not make request if not online. + // that requests will be queued and + // eventually all of them will fire back + return undefined; + } + if (!this._shouldSubscribe) { - return callback(new Error('Should not request offers')); + callback(new Error('Should not request offers')); + return undefined; } if (this._remote.trace) { log.info('requesting offers', this._key); } + if (this._isAutobridgeable && !internal) { + this._gotOffersFromLegOne = false; + this._gotOffersFromLegTwo = false; + + this._legOneBook.requestOffers(); + this._legTwoBook.requestOffers(); + } + + function handleOffers(res) { + if (self._destroyed) { + return; + } + if (!Array.isArray(res.offers)) { // XXX What now? - return callback(new Error('Invalid response')); + callback(new Error('Invalid response')); + return; } if (self._remote.trace) { log.info('requested offers', self._key, 'offers: ' + res.offers.length); } - self.setOffers(res.offers); self.notifyDirectOffersChanged(); @@ -331,8 +435,10 @@ OrderBook.prototype.requestTransferRate = function(callback) { // When transfer rate is not explicitly set on account, it implies the // default transfer rate - self._issuerTransferRate = info.account_data.TransferRate || - OrderBook.DEFAULT_TRANSFER_RATE; + self._issuerTransferRate = + info.account_data.TransferRate ? + new IOUValue(info.account_data.TransferRate) : + OrderBook.DEFAULT_TRANSFER_RATE; callback(null, self._issuerTransferRate); } @@ -392,7 +498,7 @@ OrderBook.prototype.subscribeTransactions = function(callback) { * books, an additional merge step is also performed */ -OrderBook.prototype.notifyDirectOffersChanged = function() { +OrderBook.prototype.notifyDirectOffersChangedInternal = function() { if (this._isAutobridgeable) { this.mergeDirectAndAutobridgedBooks(); } else { @@ -409,6 +515,12 @@ OrderBook.prototype.resetCache = function() { this._ownerOffersTotal = {}; this._offerCounts = {}; this._synced = false; + this._offers = []; + + if (this._validAccountsCount > 3000) { + this._validAccounts = {}; + this._validAccountsCount = 0; + } }; /** @@ -418,7 +530,6 @@ OrderBook.prototype.resetCache = function() { */ OrderBook.prototype.hasOwnerFunds = function(account) { - assert(UInt160.is_valid(account), 'Account is invalid'); return this._ownerFunds[account] !== undefined; }; @@ -430,7 +541,6 @@ OrderBook.prototype.hasOwnerFunds = function(account) { */ OrderBook.prototype.setOwnerFunds = function(account, fundedAmount) { - assert(UInt160.is_valid(account), 'Account is invalid'); assert(!isNaN(fundedAmount), 'Funded amount is invalid'); this._ownerFundsUnadjusted[account] = fundedAmount; @@ -447,11 +557,10 @@ OrderBook.prototype.setOwnerFunds = function(account, fundedAmount) { OrderBook.prototype.applyTransferRate = function(balance) { assert(!isNaN(balance), 'Balance is invalid'); - assertValidNumber(this._issuerTransferRate, 'Transfer rate is invalid'); const adjustedBalance = (new IOUValue(balance)) - .divide(new IOUValue(this._issuerTransferRate)) - .multiply(new IOUValue(OrderBook.DEFAULT_TRANSFER_RATE)).toString(); + .divide(this._issuerTransferRate) + .multiply(OrderBook.DEFAULT_TRANSFER_RATE).toString(); return adjustedBalance; }; @@ -464,7 +573,6 @@ OrderBook.prototype.applyTransferRate = function(balance) { */ OrderBook.prototype.getOwnerFunds = function(account) { - assert(UInt160.is_valid(account), 'Account is invalid'); if (this.hasOwnerFunds(account)) { if (this._currencyGets.is_native()) { return Amount.from_json(this._ownerFunds[account]); @@ -481,7 +589,6 @@ OrderBook.prototype.getOwnerFunds = function(account) { */ OrderBook.prototype.getUnadjustedOwnerFunds = function(account) { - assert(UInt160.is_valid(account), 'Account is invalid'); return this._ownerFundsUnadjusted[account]; }; @@ -492,7 +599,6 @@ OrderBook.prototype.getUnadjustedOwnerFunds = function(account) { */ OrderBook.prototype.deleteOwnerFunds = function(account) { - assert(UInt160.is_valid(account), 'Account is invalid'); this._ownerFunds[account] = undefined; }; @@ -504,7 +610,6 @@ OrderBook.prototype.deleteOwnerFunds = function(account) { */ OrderBook.prototype.getOwnerOfferCount = function(account) { - assert(UInt160.is_valid(account), 'Account is invalid'); return this._offerCounts[account] || 0; }; @@ -516,7 +621,6 @@ OrderBook.prototype.getOwnerOfferCount = function(account) { */ OrderBook.prototype.incrementOwnerOfferCount = function(account) { - assert(UInt160.is_valid(account), 'Account is invalid'); const result = (this._offerCounts[account] || 0) + 1; this._offerCounts[account] = result; return result; @@ -531,7 +635,6 @@ OrderBook.prototype.incrementOwnerOfferCount = function(account) { */ OrderBook.prototype.decrementOwnerOfferCount = function(account) { - assert(UInt160.is_valid(account), 'Account is invalid'); const result = (this._offerCounts[account] || 1) - 1; this._offerCounts[account] = result; @@ -552,8 +655,6 @@ OrderBook.prototype.decrementOwnerOfferCount = function(account) { */ OrderBook.prototype.addOwnerOfferTotal = function(account, amount) { - assert(UInt160.is_valid(account), 'Account is invalid'); - const previousAmount = this.getOwnerOfferTotal(account); const currentAmount = previousAmount.add(Amount.from_json(amount)); @@ -572,14 +673,12 @@ OrderBook.prototype.addOwnerOfferTotal = function(account, amount) { */ OrderBook.prototype.subtractOwnerOfferTotal = function(account, amount) { - assert(UInt160.is_valid(account), 'Account is invalid'); - const previousAmount = this.getOwnerOfferTotal(account); const newAmount = previousAmount.subtract(Amount.from_json(amount)); + this._ownerOffersTotal[account] = newAmount; assert(!newAmount.is_negative(), 'Offer total cannot be negative'); - return newAmount; }; @@ -591,15 +690,14 @@ OrderBook.prototype.subtractOwnerOfferTotal = function(account, amount) { */ OrderBook.prototype.getOwnerOfferTotal = function(account) { - assert(UInt160.is_valid(account), 'Account is invalid'); const amount = this._ownerOffersTotal[account]; if (amount) { return amount; } if (this._currencyGets.is_native()) { - return Amount.from_json('0'); + return OrderBook.ZERO_NATIVE_AMOUNT.clone(); } - return OrderBookUtils.normalizeAmount('0'); + return OrderBook.ZERO_NORMALIZED_AMOUNT.clone(); }; /** @@ -610,11 +708,10 @@ OrderBook.prototype.getOwnerOfferTotal = function(account) { */ OrderBook.prototype.resetOwnerOfferTotal = function(account) { - assert(UInt160.is_valid(account), 'Account is invalid'); if (this._currencyGets.is_native()) { - this._ownerOffersTotal[account] = Amount.from_json('0'); + this._ownerOffersTotal[account] = OrderBook.ZERO_NATIVE_AMOUNT.clone(); } else { - this._ownerOffersTotal[account] = OrderBookUtils.normalizeAmount('0'); + this._ownerOffersTotal[account] = OrderBook.ZERO_NORMALIZED_AMOUNT.clone(); } }; @@ -632,17 +729,18 @@ OrderBook.prototype.resetOwnerOfferTotal = function(account) { OrderBook.prototype.setOfferFundedAmount = function(offer) { assert.strictEqual(typeof offer, 'object', 'Offer is invalid'); + const takerGets = Amount.from_json(offer.TakerGets); const fundedAmount = this.getOwnerFunds(offer.Account); const previousOfferSum = this.getOwnerOfferTotal(offer.Account); - const currentOfferSum = previousOfferSum.add( - Amount.from_json(offer.TakerGets)); + const currentOfferSum = previousOfferSum.add(takerGets); offer.owner_funds = this.getUnadjustedOwnerFunds(offer.Account); - offer.is_fully_funded = fundedAmount.compareTo(currentOfferSum) >= 0; + offer.is_fully_funded = fundedAmount.is_comparable(currentOfferSum) && + fundedAmount.compareTo(currentOfferSum) >= 0; if (offer.is_fully_funded) { - offer.taker_gets_funded = Amount.from_json(offer.TakerGets).to_text(); + offer.taker_gets_funded = takerGets.to_text(); offer.taker_pays_funded = Amount.from_json(offer.TakerPays).to_text(); } else if (previousOfferSum.compareTo(fundedAmount) < 0) { offer.taker_gets_funded = fundedAmount.subtract(previousOfferSum).to_text(); @@ -698,7 +796,11 @@ OrderBook.prototype.parseAccountBalanceFromNode = function(node) { } assert(!isNaN(result.balance), 'node has an invalid balance'); - assert(UInt160.is_valid(result.account), 'node has an invalid account'); + if (this._validAccounts[result.Account] === undefined) { + assert(UInt160.is_valid(result.account), 'node has an invalid account'); + this._validAccounts[result.Account] = true; + this._validAccountsCount++; + } return result; }; @@ -786,6 +888,7 @@ OrderBook.prototype.updateFundedAmounts = function(transaction) { }); }; + /** * Update offers' funded amount with their owner's funds * @@ -793,10 +896,15 @@ OrderBook.prototype.updateFundedAmounts = function(transaction) { */ OrderBook.prototype.updateOwnerOffersFundedAmount = function(account) { - assert(UInt160.is_valid(account), 'Account is invalid'); + // assert(UInt160.is_valid(account), 'Account is invalid'); const self = this; + if (!this.hasOwnerFunds(account)) { + // We are only updating owner funds that are already cached + return; + } + if (this._remote.trace) { const ownerFunds = this.getOwnerFunds(account); log.info('updating offer funds', this._key, account, @@ -848,7 +956,7 @@ OrderBook.prototype.updateOwnerOffersFundedAmount = function(account) { OrderBook.prototype.notify = function(transaction) { const self = this; - if (!(this._subscribed && this._synced)) { + if (!(this._subscribed && this._synced) || this._destroyed) { return; } @@ -884,6 +992,12 @@ OrderBook.prototype.notify = function(transaction) { function handleNode(node) { switch (node.nodeType) { case 'DeletedNode': + if (self._validAccounts[node.fields.Account] === undefined) { + assert(UInt160.is_valid(node.fields.Account), + 'node has an invalid account'); + self._validAccounts[node.fields.Account] = true; + self._validAccountsCount++; + } self.deleteOffer(node, isOfferCancel); // We don't want to count an OfferCancel as a trade @@ -894,6 +1008,12 @@ OrderBook.prototype.notify = function(transaction) { break; case 'ModifiedNode': + if (self._validAccounts[node.fields.Account] === undefined) { + assert(UInt160.is_valid(node.fields.Account), + 'node has an invalid account'); + self._validAccounts[node.fields.Account] = true; + self._validAccountsCount++; + } self.modifyOffer(node); takerGetsTotal = takerGetsTotal @@ -906,6 +1026,12 @@ OrderBook.prototype.notify = function(transaction) { break; case 'CreatedNode': + if (self._validAccounts[node.fields.Account] === undefined) { + assert(UInt160.is_valid(node.fields.Account), + 'node has an invalid account'); + self._validAccounts[node.fields.Account] = true; + self._validAccountsCount++; + } // rippled does not set owner_funds if the order maker is the issuer // because the value would be infinite const fundedAmount = transactionOwnerFunds !== undefined ? @@ -919,7 +1045,9 @@ OrderBook.prototype.notify = function(transaction) { _.each(affectedNodes, handleNode); this.emit('transaction', transaction); + this.notifyDirectOffersChanged(); + if (!takerGetsTotal.is_zero()) { this.emit('trade', takerPaysTotal, takerGetsTotal); } @@ -951,17 +1079,27 @@ OrderBook.prototype.insertOffer = function(node) { const originalLength = this._offers.length; - for (let i = 0; i < originalLength; i++) { - const quality = OrderBookUtils.getOfferQuality(offer, this._currencyGets); - const existingOfferQuality = OrderBookUtils.getOfferQuality( - this._offers[i], - this._currencyGets - ); + if (!this._currencyGets.has_interest()) { + // use fast path + for (let i = 0; i < originalLength; i++) { + if (offer.qualityHex <= this._offers[i].qualityHex) { + this._offers.splice(i, 0, offer); + break; + } + } + } else { + for (let i = 0; i < originalLength; i++) { + const quality = OrderBookUtils.getOfferQuality(offer, this._currencyGets); + const existingOfferQuality = OrderBookUtils.getOfferQuality( + this._offers[i], + this._currencyGets + ); - if (quality.compareTo(existingOfferQuality) <= 0) { - this._offers.splice(i, 0, offer); + if (quality.compareTo(existingOfferQuality) <= 0) { + this._offers.splice(i, 0, offer); - break; + break; + } } } @@ -1067,28 +1205,34 @@ OrderBook.prototype.deleteOffer = function(node, isOfferCancel) { OrderBook.prototype.setOffers = function(offers) { assert(Array.isArray(offers), 'Offers is not an array'); - const self = this; - this.resetCache(); - const newOffers = _.map(offers, function(rawOffer) { - const offer = OrderBook.offerRewrite(rawOffer); + let i = -1; + let offer; + const l = offers.length; - if (offer.hasOwnProperty('owner_funds')) { + while (++i < l) { + offer = OrderBook.offerRewrite(offers[i]); + + if (this._validAccounts[offer.Account] === undefined) { + assert(UInt160.is_valid(offer.Account), 'Account is invalid'); + this._validAccounts[offer.Account] = true; + this._validAccountsCount++; + } + if (offer.owner_funds !== undefined) { // The first offer of each owner from book_offers contains owner balance // of offer's output - self.setOwnerFunds(offer.Account, offer.owner_funds); + this.setOwnerFunds(offer.Account, offer.owner_funds); } - self.incrementOwnerOfferCount(offer.Account); + this.incrementOwnerOfferCount(offer.Account); - self.setOfferFundedAmount(offer); - self.addOwnerOfferTotal(offer.Account, offer.TakerGets); + this.setOfferFundedAmount(offer); + this.addOwnerOfferTotal(offer.Account, offer.TakerGets); + offers[i] = offer; + } - return offer; - }); - - this._offers = newOffers; + this._offers = offers; this._synced = true; }; @@ -1191,6 +1335,14 @@ OrderBook.prototype.computeAutobridgedOffers = function() { assert(!this._currencyGets.is_native() && !this._currencyPays.is_native(), 'Autobridging is only for IOU:IOU orderbooks'); + if (this._destroyed) { + return; + } + + if (!this._gotOffersFromLegOne || !this._gotOffersFromLegTwo) { + return; + } + const autobridgeCalculator = new AutobridgeCalculator( this._currencyGets, this._currencyPays, @@ -1203,6 +1355,33 @@ OrderBook.prototype.computeAutobridgedOffers = function() { this._offersAutobridged = autobridgeCalculator.calculate(); }; +OrderBook.prototype.computeAutobridgedOffersWrapper = function() { + const startTime = Date.now(); + this.computeAutobridgedOffers(); + this.mergeDirectAndAutobridgedBooks(); + const lasted = (Date.now() - startTime); + + const newMult = + Math.floor(lasted * 2 / OrderBook.AUTOBRIDGE_CALCULATE_THROTTLE_TIME) + 1; + if (newMult !== this._autobridgeThrottleTimeMultiplier) { + this._autobridgeThrottleTimeMultiplier = newMult; + this.createDebouncedOffersWrapper(); + } +}; + +OrderBook.prototype.createDebouncedOffersWrapper = function() { + const m = this._autobridgeThrottleTimeMultiplier; + this.computeAutobridgedOffersThrottled = + _.debounce( + _.throttle( + this.computeAutobridgedOffersWrapper, + OrderBook.AUTOBRIDGE_CALCULATE_THROTTLE_TIME * m, + {leading: true, trailing: true}), + OrderBook.AUTOBRIDGE_CALCULATE_DEBOUNCE_TIME, + {maxWait: OrderBook.AUTOBRIDGE_CALCULATE_DEBOUNCE_MAXWAIT}); +}; + + /** * Merge direct and autobridged offers into a combined orderbook * @@ -1210,22 +1389,24 @@ OrderBook.prototype.computeAutobridgedOffers = function() { */ OrderBook.prototype.mergeDirectAndAutobridgedBooks = function() { - const self = this; + + if (this._destroyed) { + return; + } if (_.isEmpty(this._offers) && _.isEmpty(this._offersAutobridged)) { - // still emit empty offers list to indicate that load is completed - this.emit('model', []); + if (this._synced && this._gotOffersFromLegOne && + this._gotOffersFromLegTwo) { + // emit empty model to indicate to listeners that we've got offers, + // just there was no one + this.emit('model', []); + } return; } this._mergedOffers = this._offers .concat(this._offersAutobridged) - .sort(function(a, b) { - const aQuality = OrderBookUtils.getOfferQuality(a, self._currencyGets); - const bQuality = OrderBookUtils.getOfferQuality(b, self._currencyGets); - - return aQuality.compareTo(bQuality); - }); + .sort(this.sortOffers); this.emit('model', this._mergedOffers); }; diff --git a/src/core/orderbookutils.js b/src/core/orderbookutils.js index 34705dcc..f43cc4a9 100644 --- a/src/core/orderbookutils.js +++ b/src/core/orderbookutils.js @@ -5,6 +5,9 @@ const assert = require('assert'); const SerializedObject = require('./serializedobject').SerializedObject; const Types = require('./serializedtypes'); const Amount = require('./amount').Amount; +const Currency = require('./currency').Currency; +const UInt160 = require('./uint160').UInt160; +const IOUValue = require('./iouvalue').IOUValue; const OrderBookUtils = {}; function assertValidNumber(number, message) { @@ -19,10 +22,18 @@ function assertValidNumber(number, message) { * @return JSON amount object */ -function createAmount(value, currency, counterparty) { - const newJSON = - {'value': value, 'currency': currency, 'issuer': counterparty}; - return Amount.from_json(newJSON); +function createAmount(value, currency_, counterparty_) { + + const currency = currency_ instanceof Currency ? + currency_ : + Currency.from_json(currency_); + + const counterparty = counterparty_ instanceof UInt160 ? + counterparty_ : + UInt160.from_json(counterparty_); + + return Amount.from_components_unsafe(new IOUValue(value), + currency, counterparty, false); } /** @@ -52,11 +63,11 @@ function getIssuerFromOffer(offer) { * @return {Amount} */ -OrderBookUtils.getOfferTakerGetsFunded = function(offer) { +OrderBookUtils.getOfferTakerGetsFunded = function(offer, currency_, issuer_) { assertValidNumber(offer.taker_gets_funded, 'Taker gets funded is invalid'); - const currency = getCurrencyFromOffer(offer); - const issuer = getIssuerFromOffer(offer); + const currency = currency_ || getCurrencyFromOffer(offer); + const issuer = issuer_ || getIssuerFromOffer(offer); return createAmount(offer.taker_gets_funded, currency, issuer); }; @@ -68,11 +79,11 @@ OrderBookUtils.getOfferTakerGetsFunded = function(offer) { * @return {Amount} */ -OrderBookUtils.getOfferTakerPaysFunded = function(offer) { +OrderBookUtils.getOfferTakerPaysFunded = function(offer, currency_, issuer_) { assertValidNumber(offer.taker_pays_funded, 'Taker gets funded is invalid'); - const currency = getCurrencyFromOffer(offer); - const issuer = getIssuerFromOffer(offer); + const currency = currency_ || getCurrencyFromOffer(offer); + const issuer = issuer_ || getIssuerFromOffer(offer); return createAmount(offer.taker_pays_funded, currency, issuer); }; @@ -85,11 +96,11 @@ OrderBookUtils.getOfferTakerPaysFunded = function(offer) { * @return {Amount} */ -OrderBookUtils.getOfferTakerGets = function(offer) { +OrderBookUtils.getOfferTakerGets = function(offer, currency_, issuer_) { assert(typeof offer, 'object', 'Offer is invalid'); - const currency = offer.TakerPays.currency; - const issuer = offer.TakerPays.issuer; + const currency = currency_ || offer.TakerPays.currency; + const issuer = issuer_ || offer.TakerPays.issuer; return createAmount(offer.TakerGets, currency, issuer); }; @@ -101,7 +112,9 @@ OrderBookUtils.getOfferTakerGets = function(offer) { * @param {Currency} currencyGets */ -OrderBookUtils.getOfferQuality = function(offer, currencyGets) { +OrderBookUtils.getOfferQuality = function(offer, currencyGets, currency_, + issuer_ +) { let amount; if (currencyGets.has_interest()) { @@ -113,8 +126,8 @@ OrderBookUtils.getOfferQuality = function(offer, currencyGets) { }); } else { - const currency = getCurrencyFromOffer(offer); - const issuer = getIssuerFromOffer(offer); + const currency = currency_ || getCurrencyFromOffer(offer); + const issuer = issuer_ || getIssuerFromOffer(offer); amount = createAmount(offer.quality, currency, issuer); } @@ -140,13 +153,35 @@ OrderBookUtils.convertOfferQualityToHex = function(quality) { return so.to_hex(); }; +/** + * Formats an offer quality amount to a hex that can be parsed by + * Amount.parse_quality + * + * @param {String} quality + * + * @return {String} + */ + +OrderBookUtils.convertOfferQualityToHexFromText = function(quality) { + + const so = new SerializedObject(); + Types.Quality.serialize(so, quality); + + return so.to_hex(); +}; + + +OrderBookUtils.CURRENCY_ONE = Currency.from_json(1); + +OrderBookUtils.ISSUER_ONE = UInt160.from_json(1); + /** * */ OrderBookUtils.normalizeAmount = function(value) { - - return Amount.from_number(value); + return Amount.from_components_unsafe(new IOUValue(value), + OrderBookUtils.CURRENCY_ONE, OrderBookUtils.ISSUER_ONE, false); }; module.exports = OrderBookUtils; diff --git a/src/core/seed.js b/src/core/seed.js index 2e0f0115..e44c7a51 100644 --- a/src/core/seed.js +++ b/src/core/seed.js @@ -19,7 +19,7 @@ const Seed = extend(function() { }, UInt); Seed.width = 16; -Seed.prototype = extend({}, UInt.prototype); +Seed.prototype = Object.create(extend({}, UInt.prototype)); Seed.prototype.constructor = Seed; // value = NaN on error. diff --git a/src/core/uint128.js b/src/core/uint128.js index f3de0f96..cfcd088e 100644 --- a/src/core/uint128.js +++ b/src/core/uint128.js @@ -1,23 +1,23 @@ 'use strict'; -var utils = require('./utils'); -var extend = require('extend'); -var UInt = require('./uint').UInt; +const utils = require('./utils'); +const extend = require('extend'); +const UInt = require('./uint').UInt; // // UInt128 support // -var UInt128 = extend(function() { +const UInt128 = extend(function() { this._value = NaN; }, UInt); UInt128.width = 16; -UInt128.prototype = extend({}, UInt.prototype); +UInt128.prototype = Object.create(extend({}, UInt.prototype)); UInt128.prototype.constructor = UInt128; -var HEX_ZERO = UInt128.HEX_ZERO = '00000000000000000000000000000000'; -var HEX_ONE = UInt128.HEX_ONE = '00000000000000000000000000000000'; +const HEX_ZERO = UInt128.HEX_ZERO = '00000000000000000000000000000000'; +const HEX_ONE = UInt128.HEX_ONE = '00000000000000000000000000000000'; UInt128.STR_ZERO = utils.hexToString(HEX_ZERO); UInt128.STR_ONE = utils.hexToString(HEX_ONE); diff --git a/src/core/uint160.js b/src/core/uint160.js index 70cd4e97..878cb7de 100644 --- a/src/core/uint160.js +++ b/src/core/uint160.js @@ -1,27 +1,27 @@ 'use strict'; -var utils = require('./utils'); -var extend = require('extend'); +const utils = require('./utils'); +const extend = require('extend'); -var UInt = require('./uint').UInt; -var Base = require('./base').Base; +const UInt = require('./uint').UInt; +const Base = require('./base').Base; // // UInt160 support // -var UInt160 = extend(function() { +const UInt160 = extend(function() { this._value = NaN; this._version_byte = undefined; this._update(); }, UInt); UInt160.width = 20; -UInt160.prototype = extend({}, UInt.prototype); +UInt160.prototype = Object.create(extend({}, UInt.prototype)); UInt160.prototype.constructor = UInt160; -var HEX_ZERO = UInt160.HEX_ZERO = '0000000000000000000000000000000000000000'; -var HEX_ONE = UInt160.HEX_ONE = '0000000000000000000000000000000000000001'; +const HEX_ZERO = UInt160.HEX_ZERO = '0000000000000000000000000000000000000000'; +const HEX_ONE = UInt160.HEX_ONE = '0000000000000000000000000000000000000001'; UInt160.ACCOUNT_ZERO = 'rrrrrrrrrrrrrrrrrrrrrhoLvTp'; UInt160.ACCOUNT_ONE = 'rrrrrrrrrrrrrrrrrrrrBZbvji'; @@ -74,13 +74,12 @@ UInt160.prototype.parse_generic = function(j) { }; // XXX Json form should allow 0 and 1, C++ doesn't currently allow it. -UInt160.prototype.to_json = function(opts) { - opts = opts || {}; +UInt160.prototype.to_json = function(opts = {}) { if (this.is_valid()) { // If this value has a type, return a Base58 encoded string. if (typeof this._version_byte === 'number') { - var output = Base.encode_check(this._version_byte, this.to_bytes()); + let output = Base.encode_check(this._version_byte, this.to_bytes()); if (opts.gateways && output in opts.gateways) { output = opts.gateways[output]; diff --git a/src/core/uint256.js b/src/core/uint256.js index 47cd1cd0..9127466a 100644 --- a/src/core/uint256.js +++ b/src/core/uint256.js @@ -1,25 +1,25 @@ 'use strict'; -var utils = require('./utils'); -var extend = require('extend'); -var UInt = require('./uint').UInt; +const utils = require('./utils'); +const extend = require('extend'); +const UInt = require('./uint').UInt; // // UInt256 support // -var UInt256 = extend(function() { +const UInt256 = extend(function() { this._value = NaN; }, UInt); UInt256.width = 32; -UInt256.prototype = extend({}, UInt.prototype); +UInt256.prototype = Object.create(extend({}, UInt.prototype)); UInt256.prototype.constructor = UInt256; -var HEX_ZERO = UInt256.HEX_ZERO = '00000000000000000000000000000000' + +const HEX_ZERO = UInt256.HEX_ZERO = '00000000000000000000000000000000' + '00000000000000000000000000000000'; -var HEX_ONE = UInt256.HEX_ONE = '00000000000000000000000000000000' + +const HEX_ONE = UInt256.HEX_ONE = '00000000000000000000000000000000' + '00000000000000000000000000000001'; UInt256.STR_ZERO = utils.hexToString(HEX_ZERO); diff --git a/test/fixtures/orderbook.js b/test/fixtures/orderbook.js index 31ee8db3..2568f264 100644 --- a/test/fixtures/orderbook.js +++ b/test/fixtures/orderbook.js @@ -1,10 +1,13 @@ -/*eslint-disable max-len, no-param-reassign*/ +/* eslint-disable max-len, no-param-reassign */ 'use strict'; const _ = require('lodash'); const addresses = require('./addresses'); const Meta = require('ripple-lib').Meta; +const SerializedObject = require('ripple-lib').SerializedObject; +const Types = require('ripple-lib').types; +const IOUValue = require('ripple-lib')._test.IOUValue; module.exports.FIAT_BALANCE = '10'; module.exports.NATIVE_BALANCE = '55'; @@ -809,6 +812,7 @@ module.exports.transactionWithInvalidAccountRoot = function(options) { }; }; + module.exports.transactionWithCreatedOffer = function(options) { options = options || {}; _.defaults(options, { @@ -816,6 +820,15 @@ module.exports.transactionWithCreatedOffer = function(options) { amount: '1.9951' }); + const takerGets = new IOUValue(options.amount); + const takerPays = new IOUValue(module.exports.TAKER_PAYS); + const quality = takerPays.divide(takerGets); + + const so = new SerializedObject(); + Types.Quality.serialize(so, quality); + + const BookDirectory = so.to_hex(); + const meta = new Meta({ AffectedNodes: [ { @@ -824,7 +837,7 @@ module.exports.transactionWithCreatedOffer = function(options) { LedgerIndex: 'AF3C702057C9C47DB9E809FD8C76CD22521012C5CC7AE95D914EC9E226F1D7E5', NewFields: { Account: options.account, - BookDirectory: '7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F211CEE1E0697A0', + BookDirectory: BookDirectory, Flags: 131072, Sequence: 1404, TakerGets: { diff --git a/test/orderbook-autobridge-test.js b/test/orderbook-autobridge-test.js index 8d07d037..6d61b907 100644 --- a/test/orderbook-autobridge-test.js +++ b/test/orderbook-autobridge-test.js @@ -1,19 +1,30 @@ -/*eslint-disable max-len */ +/* eslint-disable max-len */ 'use strict'; -var _ = require('lodash'); -var assert = require('assert-diff'); -var Remote = require('ripple-lib').Remote; -var Currency = require('ripple-lib').Currency; -var addresses = require('./fixtures/addresses'); -var fixtures = require('./fixtures/orderbook'); +const _ = require('lodash'); +const assert = require('assert-diff'); +const Remote = require('ripple-lib').Remote; +const Currency = require('ripple-lib').Currency; +const addresses = require('./fixtures/addresses'); +const fixtures = require('./fixtures/orderbook'); +const IOUValue = require('ripple-lib')._test.IOUValue; describe('OrderBook Autobridging', function() { this.timeout(0); + function createRemote() { + const remote = new Remote(); + + remote.isConnected = function() { + return true; + }; + + return remote; + } + it('Initialize IOU/IOU', function() { - var book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, currency_pays: 'USD', @@ -27,23 +38,24 @@ describe('OrderBook Autobridging', function() { }); it('Compute autobridged offers', function() { - var book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, currency_pays: 'USD', issuer_pays: addresses.ISSUER }); - book._issuerTransferRate = 1000000000; - book._legOneBook._issuerTransferRate = 1000000000; - book._legTwoBook._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); + book._legOneBook._issuerTransferRate = new IOUValue(1000000000); + book._legTwoBook._issuerTransferRate = new IOUValue(1000000000); - var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); - var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1)); + const legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); + const legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1)); book._legOneBook.setOffers(legOneOffers); book._legTwoBook.setOffers(legTwoOffers); + book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; book.computeAutobridgedOffers(); assert.strictEqual(book._offersAutobridged.length, 1); @@ -58,25 +70,26 @@ describe('OrderBook Autobridging', function() { }); it('Compute autobridged offers - leg one partially funded', function() { - var book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, currency_pays: 'USD', issuer_pays: addresses.ISSUER }); - book._issuerTransferRate = 1000000000; - book._legOneBook._issuerTransferRate = 1000000000; - book._legTwoBook._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); + book._legOneBook._issuerTransferRate = new IOUValue(1000000000); + book._legTwoBook._issuerTransferRate = new IOUValue(1000000000); - var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); - var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1)); + const legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); + const legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1)); legOneOffers[0].owner_funds = '2105863129'; book._legOneBook.setOffers(legOneOffers); book._legTwoBook.setOffers(legTwoOffers); + book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; book.computeAutobridgedOffers(); assert.strictEqual(book._offersAutobridged.length, 1); @@ -88,25 +101,26 @@ describe('OrderBook Autobridging', function() { }); it('Compute autobridged offers - leg two partially funded', function() { - var book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, currency_pays: 'USD', issuer_pays: addresses.ISSUER }); - book._issuerTransferRate = 1000000000; - book._legOneBook._issuerTransferRate = 1000000000; - book._legTwoBook._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); + book._legOneBook._issuerTransferRate = new IOUValue(1000000000); + book._legTwoBook._issuerTransferRate = new IOUValue(1000000000); - var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); - var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1)); + const legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); + const legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1)); legTwoOffers[0].owner_funds = '10'; book._legOneBook.setOffers(legOneOffers); book._legTwoBook.setOffers(legTwoOffers); + book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; book.computeAutobridgedOffers(); assert.strictEqual(book._offersAutobridged.length, 1); @@ -118,25 +132,26 @@ describe('OrderBook Autobridging', function() { }); it('Compute autobridged offers - leg two transfer rate', function() { - var book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, currency_pays: 'USD', issuer_pays: addresses.ISSUER }); - book._issuerTransferRate = 1000000000; - book._legOneBook._issuerTransferRate = 1000000000; - book._legTwoBook._issuerTransferRate = 1002000000; + book._issuerTransferRate = new IOUValue(1000000000); + book._legOneBook._issuerTransferRate = new IOUValue(1000000000); + book._legTwoBook._issuerTransferRate = new IOUValue(1002000000); - var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); - var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1)); + const legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); + const legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1)); legTwoOffers[0].owner_funds = '10'; book._legOneBook.setOffers(legOneOffers); book._legTwoBook.setOffers(legTwoOffers); + book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; book.computeAutobridgedOffers(); assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '9.980039920159681'); @@ -146,19 +161,19 @@ describe('OrderBook Autobridging', function() { }); it('Compute autobridged offers - taker funds < leg two in', function() { - var book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, currency_pays: 'USD', issuer_pays: addresses.ISSUER }); - book._issuerTransferRate = 1000000000; - book._legOneBook._issuerTransferRate = 1000000000; - book._legTwoBook._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); + book._legOneBook._issuerTransferRate = new IOUValue(1000000000); + book._legTwoBook._issuerTransferRate = new IOUValue(1000000000); - var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); - var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1)); + const legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); + const legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1)); legOneOffers[0].owner_funds = '33461561812'; @@ -169,6 +184,7 @@ describe('OrderBook Autobridging', function() { book._legOneBook.setOffers(legOneOffers); book._legTwoBook.setOffers(legTwoOffers); + book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; book.computeAutobridgedOffers(); assert.strictEqual(book._offersAutobridged.length, 1); @@ -180,19 +196,19 @@ describe('OrderBook Autobridging', function() { }); it('Compute autobridged offers - leg one partially funded - owners equal', function() { - var book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, currency_pays: 'USD', issuer_pays: addresses.ISSUER }); - book._issuerTransferRate = 1000000000; - book._legOneBook._issuerTransferRate = 1000000000; - book._legTwoBook._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); + book._legOneBook._issuerTransferRate = new IOUValue(1000000000); + book._legTwoBook._issuerTransferRate = new IOUValue(1000000000); - var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); - var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1)); + const legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); + const legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1)); legOneOffers[0].owner_funds = '2105863129'; @@ -201,6 +217,7 @@ describe('OrderBook Autobridging', function() { book._legOneBook.setOffers(legOneOffers); book._legTwoBook.setOffers(legTwoOffers); + book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; book.computeAutobridgedOffers(); assert.strictEqual(book._offersAutobridged.length, 1); @@ -212,19 +229,19 @@ describe('OrderBook Autobridging', function() { }); it('Compute autobridged offers - leg one partially funded - owners equal - leg two in > leg one out', function() { - var book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, currency_pays: 'USD', issuer_pays: addresses.ISSUER }); - book._issuerTransferRate = 1000000000; - book._legOneBook._issuerTransferRate = 1000000000; - book._legTwoBook._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); + book._legOneBook._issuerTransferRate = new IOUValue(1000000000); + book._legTwoBook._issuerTransferRate = new IOUValue(1000000000); - var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); - var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1)); + const legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); + const legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1)); legOneOffers[0].owner_funds = '2105863129'; @@ -236,6 +253,7 @@ describe('OrderBook Autobridging', function() { book._legOneBook.setOffers(legOneOffers); book._legTwoBook.setOffers(legTwoOffers); + book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; book.computeAutobridgedOffers(); assert.strictEqual(book._offersAutobridged.length, 1); @@ -247,23 +265,24 @@ describe('OrderBook Autobridging', function() { }); it('Compute autobridged offers - leg one consumes leg two fully', function() { - var book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, currency_pays: 'USD', issuer_pays: addresses.ISSUER }); - book._issuerTransferRate = 1000000000; - book._legOneBook._issuerTransferRate = 1000000000; - book._legTwoBook._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); + book._legOneBook._issuerTransferRate = new IOUValue(1000000000); + book._legTwoBook._issuerTransferRate = new IOUValue(1000000000); - var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); - var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 2)); + const legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); + const legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 2)); book._legOneBook.setOffers(legOneOffers); book._legTwoBook.setOffers(legTwoOffers); + book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; book.computeAutobridgedOffers(); assert.strictEqual(book._offersAutobridged.length, 2); @@ -280,19 +299,19 @@ describe('OrderBook Autobridging', function() { }); it('Compute autobridged offers - leg two consumes first leg one offer fully', function() { - var book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, currency_pays: 'USD', issuer_pays: addresses.ISSUER }); - book._issuerTransferRate = 1000000000; - book._legOneBook._issuerTransferRate = 1000000000; - book._legTwoBook._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); + book._legOneBook._issuerTransferRate = new IOUValue(1000000000); + book._legTwoBook._issuerTransferRate = new IOUValue(1000000000); - var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 2)); - var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1)); + const legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 2)); + const legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1)); legTwoOffers[0].TakerGets.value = '170.7639524223001'; legTwoOffers[0].TakerPays = '49439476610'; @@ -301,6 +320,7 @@ describe('OrderBook Autobridging', function() { book._legOneBook.setOffers(legOneOffers); book._legTwoBook.setOffers(legTwoOffers); + book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; book.computeAutobridgedOffers(); assert.strictEqual(book._offersAutobridged.length, 2); @@ -317,19 +337,19 @@ describe('OrderBook Autobridging', function() { }); it('Compute autobridged offers - owners equal', function() { - var book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, currency_pays: 'USD', issuer_pays: addresses.ISSUER }); - book._issuerTransferRate = 1000000000; - book._legOneBook._issuerTransferRate = 1000000000; - book._legTwoBook._issuerTransferRate = 1002000000; + book._issuerTransferRate = new IOUValue(1000000000); + book._legOneBook._issuerTransferRate = new IOUValue(1000000000); + book._legTwoBook._issuerTransferRate = new IOUValue(1002000000); - var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); - var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 2)); + const legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); + const legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 2)); legOneOffers[0].owner_funds = '2105863129'; legTwoOffers[1].owner_funds = '19.32660005780981'; @@ -339,6 +359,7 @@ describe('OrderBook Autobridging', function() { book._legOneBook.setOffers(legOneOffers); book._legTwoBook.setOffers(legTwoOffers); + book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; book.computeAutobridgedOffers(); assert.strictEqual(book._offersAutobridged.length, 2); @@ -355,19 +376,19 @@ describe('OrderBook Autobridging', function() { }); it('Compute autobridged offers - owners equal - leg one overfunded', function() { - var book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, currency_pays: 'USD', issuer_pays: addresses.ISSUER }); - book._issuerTransferRate = 1000000000; - book._legOneBook._issuerTransferRate = 1000000000; - book._legTwoBook._issuerTransferRate = 1002000000; + book._issuerTransferRate = new IOUValue(1000000000); + book._legOneBook._issuerTransferRate = new IOUValue(1000000000); + book._legTwoBook._issuerTransferRate = new IOUValue(1002000000); - var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); - var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 2)); + const legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1)); + const legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 2)); legOneOffers[0].owner_funds = '41461561812'; @@ -378,6 +399,7 @@ describe('OrderBook Autobridging', function() { book._legOneBook.setOffers(legOneOffers); book._legTwoBook.setOffers(legTwoOffers); + book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; book.computeAutobridgedOffers(); assert.strictEqual(book._offersAutobridged.length, 2); @@ -394,20 +416,21 @@ describe('OrderBook Autobridging', function() { }); it('Compute autobridged offers - TakerPays < Quality * TakerGets', function() { - var book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, currency_pays: 'USD', issuer_pays: addresses.ISSUER }); - book._issuerTransferRate = 1000000000; - book._legOneBook._issuerTransferRate = 1000000000; - book._legTwoBook._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); + book._legOneBook._issuerTransferRate = new IOUValue(1000000000); + book._legTwoBook._issuerTransferRate = new IOUValue(1000000000); book._legOneBook.setOffers([ { Account: addresses.ACCOUNT, + BookDirectory: '3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E570463F9CDB31517', TakerGets: '75', TakerPays: { value: '50', @@ -422,6 +445,7 @@ describe('OrderBook Autobridging', function() { book._legTwoBook.setOffers([ { Account: addresses.ACCOUNT, + BookDirectory: '3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E570463F9CDB31517', TakerGets: { value: '90', issuer: addresses.ISSUER, @@ -433,6 +457,7 @@ describe('OrderBook Autobridging', function() { } ]); + book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; book.computeAutobridgedOffers(); assert.strictEqual(book._offersAutobridged.length, 1); @@ -444,20 +469,21 @@ describe('OrderBook Autobridging', function() { }); it('Compute autobridged offers - update funded amount', function() { - var book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, currency_pays: 'USD', issuer_pays: addresses.ISSUER }); - book._issuerTransferRate = 1000000000; - book._legOneBook._issuerTransferRate = 1000000000; - book._legTwoBook._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); + book._legOneBook._issuerTransferRate = new IOUValue(1000000000); + book._legTwoBook._issuerTransferRate = new IOUValue(1000000000); book._legOneBook.setOffers([ { Account: addresses.ACCOUNT, + BookDirectory: '3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E570463F9CDB31517', TakerGets: '100', TakerPays: { value: '100', @@ -469,6 +495,7 @@ describe('OrderBook Autobridging', function() { }, { Account: addresses.ACCOUNT, + BookDirectory: '3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E570463F9CDB31517', TakerGets: '50', TakerPays: { value: '100', @@ -482,6 +509,7 @@ describe('OrderBook Autobridging', function() { book._legTwoBook.setOffers([ { Account: addresses.ACCOUNT, + BookDirectory: '3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E570463F9CDB31517', TakerGets: { value: '90', issuer: addresses.ISSUER, @@ -493,6 +521,7 @@ describe('OrderBook Autobridging', function() { }, { Account: addresses.OTHER_ACCOUNT, + BookDirectory: '3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E570463F9CDB31517', TakerGets: { value: '30', issuer: addresses.ISSUER, @@ -504,6 +533,7 @@ describe('OrderBook Autobridging', function() { } ]); + book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; book.computeAutobridgedOffers(); assert.strictEqual(book._offersAutobridged.length, 3); @@ -525,20 +555,21 @@ describe('OrderBook Autobridging', function() { }); it('Compute autobridged offers - update funded amount - owners equal', function() { - var book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, currency_pays: 'USD', issuer_pays: addresses.ISSUER }); - book._issuerTransferRate = 1000000000; - book._legOneBook._issuerTransferRate = 1000000000; - book._legTwoBook._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); + book._legOneBook._issuerTransferRate = new IOUValue(1000000000); + book._legTwoBook._issuerTransferRate = new IOUValue(1000000000); book._legOneBook.setOffers([ { Account: addresses.ACCOUNT, + BookDirectory: '3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E570463F9CDB31517', TakerGets: '100', TakerPays: { value: '100', @@ -550,6 +581,7 @@ describe('OrderBook Autobridging', function() { }, { Account: addresses.ACCOUNT, + BookDirectory: '3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E570463F9CDB31517', TakerGets: '20', TakerPays: { value: '100', @@ -563,6 +595,7 @@ describe('OrderBook Autobridging', function() { book._legTwoBook.setOffers([ { Account: addresses.ACCOUNT, + BookDirectory: '3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E570463F9CDB31517', TakerGets: { value: '90', issuer: addresses.ISSUER, @@ -574,6 +607,7 @@ describe('OrderBook Autobridging', function() { }, { Account: addresses.OTHER_ACCOUNT, + BookDirectory: '3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E570463F9CDB31517', TakerGets: { value: '30', issuer: addresses.ISSUER, @@ -585,6 +619,7 @@ describe('OrderBook Autobridging', function() { } ]); + book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; book.computeAutobridgedOffers(); assert.strictEqual(book._offersAutobridged.length, 3); @@ -606,20 +641,21 @@ describe('OrderBook Autobridging', function() { }); it('Compute autobridged offers - update funded amount - first two owners equal', function() { - var book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, currency_pays: 'USD', issuer_pays: addresses.ISSUER }); - book._issuerTransferRate = 1000000000; - book._legOneBook._issuerTransferRate = 1000000000; - book._legTwoBook._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); + book._legOneBook._issuerTransferRate = new IOUValue(1000000000); + book._legTwoBook._issuerTransferRate = new IOUValue(1000000000); book._legOneBook.setOffers([ { Account: addresses.ACCOUNT, + BookDirectory: '3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E570463F9CDB31517', TakerGets: '100', TakerPays: { value: '100', @@ -631,6 +667,7 @@ describe('OrderBook Autobridging', function() { }, { Account: addresses.ACCOUNT, + BookDirectory: '3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E570463F9CDB31517', TakerGets: '100', TakerPays: { value: '200', @@ -644,6 +681,7 @@ describe('OrderBook Autobridging', function() { book._legTwoBook.setOffers([ { Account: addresses.ACCOUNT, + BookDirectory: '3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E570463F9CDB31517', TakerGets: { value: '90', issuer: addresses.ISSUER, @@ -655,6 +693,7 @@ describe('OrderBook Autobridging', function() { }, { Account: addresses.ACCOUNT, + BookDirectory: '3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E570463F9CDB31517', TakerGets: { value: '30', issuer: addresses.ISSUER, @@ -665,6 +704,7 @@ describe('OrderBook Autobridging', function() { }, { Account: addresses.OTHER_ACCOUNT, + BookDirectory: '3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E570463F9CDB31517', TakerGets: { value: '20', issuer: addresses.ISSUER, @@ -676,6 +716,7 @@ describe('OrderBook Autobridging', function() { } ]); + book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; book.computeAutobridgedOffers(); assert.strictEqual(book._offersAutobridged.length, 4); @@ -702,20 +743,21 @@ describe('OrderBook Autobridging', function() { }); it('Compute autobridged offers - unfunded offer - owners equal', function() { - var book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'EUR', issuer_gets: addresses.ISSUER, currency_pays: 'USD', issuer_pays: addresses.ISSUER }); - book._issuerTransferRate = 1000000000; - book._legOneBook._issuerTransferRate = 1000000000; - book._legTwoBook._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); + book._legOneBook._issuerTransferRate = new IOUValue(1000000000); + book._legTwoBook._issuerTransferRate = new IOUValue(1000000000); book._legOneBook.setOffers([ { Account: addresses.ACCOUNT, + BookDirectory: '3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E570463F9CDB31517', TakerGets: '75', TakerPays: { value: '75', @@ -730,6 +772,7 @@ describe('OrderBook Autobridging', function() { book._legTwoBook.setOffers([ { Account: addresses.ACCOUNT, + BookDirectory: '3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E570463F9CDB31517', TakerGets: { value: '90', issuer: addresses.ISSUER, @@ -741,6 +784,7 @@ describe('OrderBook Autobridging', function() { } ]); + book._gotOffersFromLegOne = book._gotOffersFromLegTwo = true; book.computeAutobridgedOffers(); assert.strictEqual(book._offersAutobridged.length, 1); diff --git a/test/orderbook-test.js b/test/orderbook-test.js index caefa353..7c6e77a6 100644 --- a/test/orderbook-test.js +++ b/test/orderbook-test.js @@ -1,4 +1,4 @@ -/*eslint-disable max-len */ +/* eslint-disable max-len */ 'use strict'; @@ -9,12 +9,23 @@ const Amount = require('ripple-lib').Amount; const Meta = require('ripple-lib').Meta; const addresses = require('./fixtures/addresses'); const fixtures = require('./fixtures/orderbook'); +const IOUValue = require('ripple-lib')._test.IOUValue; describe('OrderBook', function() { this.timeout(0); + function createRemote() { + const remote = new Remote(); + + remote.isConnected = function() { + return true; + }; + + return remote; + } + it('toJSON', function() { - let book = new Remote().createOrderBook({ + let book = createRemote().createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, currency_pays: 'BTC' @@ -30,7 +41,7 @@ describe('OrderBook', function() { } }); - book = new Remote().createOrderBook({ + book = createRemote().createOrderBook({ issuer_gets: addresses.ISSUER, currency_gets: 'BTC', currency_pays: 'XRP' @@ -48,7 +59,7 @@ describe('OrderBook', function() { }); it('Check orderbook validity', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, currency_pays: 'BTC' @@ -58,7 +69,7 @@ describe('OrderBook', function() { }); it('Automatic subscription (based on listeners)', function(done) { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, currency_pays: 'BTC' @@ -72,7 +83,7 @@ describe('OrderBook', function() { }); it('Subscribe', function(done) { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, currency_pays: 'BTC' @@ -94,7 +105,7 @@ describe('OrderBook', function() { }); it('Unsubscribe', function(done) { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, currency_pays: 'BTC' @@ -114,7 +125,7 @@ describe('OrderBook', function() { }); it('Automatic unsubscription - remove all listeners', function(done) { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, currency_pays: 'BTC' @@ -129,7 +140,7 @@ describe('OrderBook', function() { }); it('Automatic unsubscription - once listener', function(done) { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, currency_pays: 'BTC' @@ -144,33 +155,33 @@ describe('OrderBook', function() { }); it('Set owner funds', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, currency_pays: 'BTC' }); - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book.setOwnerFunds(addresses.ACCOUNT, '1'); assert.strictEqual(book.getOwnerFunds(addresses.ACCOUNT).to_text(), '1'); }); it('Set owner funds - unadjusted funds', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, currency_pays: 'BTC' }); - book._issuerTransferRate = 1002000000; + book._issuerTransferRate = new IOUValue(1002000000); book.setOwnerFunds(addresses.ACCOUNT, '1'); assert.strictEqual(book._ownerFundsUnadjusted[addresses.ACCOUNT], '1'); }); it('Set owner funds - invalid account', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, currency_pays: 'BTC' @@ -182,7 +193,7 @@ describe('OrderBook', function() { }); it('Set owner funds - invalid amount', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, currency_pays: 'BTC' @@ -194,7 +205,7 @@ describe('OrderBook', function() { }); it('Has owner funds', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, currency_pays: 'BTC' @@ -205,7 +216,7 @@ describe('OrderBook', function() { }); it('Delete owner funds', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, currency_pays: 'BTC' @@ -218,23 +229,8 @@ describe('OrderBook', function() { assert(!book.hasOwnerFunds(addresses.ACCOUNT)); }); - it('Delete owner funds', function() { - const book = new Remote().createOrderBook({ - currency_gets: 'BTC', - issuer_gets: addresses.ISSUER, - currency_pays: 'XRP' - }); - - book._ownerFunds[addresses.ACCOUNT] = '1'; - assert(book.hasOwnerFunds(addresses.ACCOUNT)); - - assert.throws(function() { - book.deleteOwnerFunds('0rrrrrrrrrrrrrrrrrrrrBZbvji'); - }); - }); - it('Increment owner offer count', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'BTC', issuer_gets: addresses.ISSUER, currency_pays: 'XRP' @@ -244,20 +240,8 @@ describe('OrderBook', function() { assert.strictEqual(book.getOwnerOfferCount(addresses.ACCOUNT), 1); }); - it('Increment owner offer count - invalid address', function() { - const book = new Remote().createOrderBook({ - currency_gets: 'BTC', - issuer_gets: addresses.ISSUER, - currency_pays: 'XRP' - }); - - assert.throws(function() { - book.incrementOwnerOfferCount('zrrrrrrrrrrrrrrrrrrrBZbvji'); - }); - }); - it('Decrement owner offer count', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'BTC', issuer_gets: addresses.ISSUER, currency_pays: 'XRP' @@ -270,7 +254,7 @@ describe('OrderBook', function() { }); it('Decrement owner offer count - no more offers', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'BTC', issuer_gets: addresses.ISSUER, currency_pays: 'XRP' @@ -283,20 +267,8 @@ describe('OrderBook', function() { assert.strictEqual(book.getOwnerFunds(addresses.ACCOUNT), undefined); }); - it('Decrement owner offer count - invalid address', function() { - const book = new Remote().createOrderBook({ - currency_gets: 'BTC', - issuer_gets: addresses.ISSUER, - currency_pays: 'XRP' - }); - - assert.throws(function() { - book.decrementOwnerOfferCount('zrrrrrrrrrrrrrrrrrrrBZbvji'); - }); - }); - it('Subtract owner offer total', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'BTC', issuer_gets: addresses.ISSUER, currency_pays: 'XRP' @@ -324,7 +296,7 @@ describe('OrderBook', function() { }); it('Subtract owner offer total - negative total', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'BTC', issuer_gets: addresses.ISSUER, currency_pays: 'XRP' @@ -340,7 +312,7 @@ describe('OrderBook', function() { }); it('Get owner offer total', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'BTC', issuer_gets: addresses.ISSUER, currency_pays: 'XRP' @@ -355,7 +327,7 @@ describe('OrderBook', function() { }); it('Get owner offer total - native', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, currency_pays: 'XRP' @@ -367,7 +339,7 @@ describe('OrderBook', function() { }); it('Get owner offer total - no total', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'BTC', issuer_gets: addresses.ISSUER, currency_pays: 'XRP' @@ -377,7 +349,7 @@ describe('OrderBook', function() { }); it('Get owner offer total - native - no total', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, currency_pays: 'BTC' @@ -387,31 +359,31 @@ describe('OrderBook', function() { }); it('Apply transfer rate - cached transfer rate', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'BTC', issuer_gets: addresses.ISSUER, currency_pays: 'XRP' }); - book._issuerTransferRate = 1002000000; + book._issuerTransferRate = new IOUValue(1002000000); assert.strictEqual(book.applyTransferRate('1'), '0.9980039920159681'); }); it('Apply transfer rate - native currency', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, currency_pays: 'BTC' }); - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); assert.strictEqual(book.applyTransferRate('0.9980039920159681'), '0.9980039920159681'); }); it('Apply transfer rate - invalid balance', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'BTC', issuer_gets: addresses.ISSUER, currency_pays: 'XRP' @@ -423,7 +395,7 @@ describe('OrderBook', function() { }); it('Apply transfer rate - invalid transfer rate', function() { - const book = new Remote().createOrderBook({ + const book = createRemote().createOrderBook({ currency_gets: 'BTC', issuer_gets: addresses.ISSUER, currency_pays: 'XRP' @@ -435,7 +407,7 @@ describe('OrderBook', function() { }); it('Request transfer rate', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'BTC', issuer_gets: addresses.ISSUER, @@ -458,12 +430,12 @@ describe('OrderBook', function() { book.requestTransferRate(function(err, rate) { assert.ifError(err); - assert.strictEqual(rate, 1002000000); + assert(rate.equals(new IOUValue(1002000000))); }); }); it('Request transfer rate - not set', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'BTC', issuer_gets: addresses.ISSUER, @@ -485,19 +457,19 @@ describe('OrderBook', function() { book.requestTransferRate(function(err, rate) { assert.ifError(err); - assert.strictEqual(rate, 1000000000); + assert(rate.equals(new IOUValue(1000000000))); }); }); it('Request transfer rate - cached transfer rate', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'BTC', issuer_gets: addresses.ISSUER, currency_pays: 'XRP' }); - book._issuerTransferRate = 1002000000; + book._issuerTransferRate = new IOUValue(1002000000); remote.request = function() { assert(false); @@ -505,12 +477,12 @@ describe('OrderBook', function() { book.requestTransferRate(function(err, rate) { assert.ifError(err); - assert.strictEqual(rate, 1002000000); + assert(rate.equals(new IOUValue(1002000000))); }); }); it('Request transfer rate - native currency', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, @@ -523,20 +495,20 @@ describe('OrderBook', function() { book.requestTransferRate(function(err, rate) { assert.ifError(err); - assert.strictEqual(rate, 1000000000); - assert.strictEqual(book._issuerTransferRate, 1000000000); + assert(rate.equals(new IOUValue(1000000000))); + assert(book._issuerTransferRate.equals(new IOUValue(1000000000))); }); }); it('Set offer funded amount - iou/xrp - fully funded', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'BTC', currency_pays: 'XRP', issuer_gets: addresses.ISSUER }); - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); const offer = { Account: addresses.ACCOUNT, @@ -565,14 +537,14 @@ describe('OrderBook', function() { }); it('Set offer funded amount - iou/xrp - unfunded', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'BTC', currency_pays: 'XRP', issuer_gets: addresses.ISSUER }); - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); const offer = { Account: addresses.ACCOUNT, @@ -603,14 +575,14 @@ describe('OrderBook', function() { }); it('Set offer funded amount - xrp/iou - funded', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, currency_pays: 'BTC' }); - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); const offer = { Account: addresses.ACCOUNT, @@ -639,14 +611,14 @@ describe('OrderBook', function() { }); it('Set offer funded amount - xrp/iou - unfunded', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, currency_pays: 'BTC' }); - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); const offer = { Account: addresses.ACCOUNT, @@ -677,14 +649,14 @@ describe('OrderBook', function() { }); it('Set offer funded amount - zero funds', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'XRP', issuer_pays: addresses.ISSUER, currency_pays: 'BTC' }); - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); const offer = { Account: addresses.ACCOUNT, @@ -711,7 +683,7 @@ describe('OrderBook', function() { }); it('Check is balance change node', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', @@ -761,7 +733,7 @@ describe('OrderBook', function() { }); it('Check is balance change node - not balance change', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'XRP', @@ -804,7 +776,7 @@ describe('OrderBook', function() { }); it('Check is balance change node - different currency', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'BTC', @@ -854,7 +826,7 @@ describe('OrderBook', function() { }); it('Check is balance change node - different issuer', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', @@ -904,7 +876,7 @@ describe('OrderBook', function() { }); it('Check is balance change node - native currency', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'XRP', @@ -939,7 +911,7 @@ describe('OrderBook', function() { }); it('Check is balance change node - native currency - not balance change', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'XRP', @@ -969,7 +941,7 @@ describe('OrderBook', function() { }); it('Parse account balance from node', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', @@ -1064,7 +1036,7 @@ describe('OrderBook', function() { }); it('Parse account balance from node - native currency', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', @@ -1105,7 +1077,7 @@ describe('OrderBook', function() { let receivedChangedEvents = 0; let receivedFundsChangedEvents = 0; - const remote = new Remote(); + const remote = createRemote(); const message = fixtures.transactionWithRippleState(); @@ -1115,7 +1087,7 @@ describe('OrderBook', function() { currency_pays: 'XRP' }); - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book._offers = fixtures.fiatOffers(); @@ -1155,7 +1127,7 @@ describe('OrderBook', function() { it('Update funded amounts - increase funds', function() { let receivedFundsChangedEvents = 0; - const remote = new Remote(); + const remote = createRemote(); const message = fixtures.transactionWithRippleState({ balance: '50' @@ -1167,7 +1139,7 @@ describe('OrderBook', function() { currency_pays: 'XRP' }); - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book.setOffers(fixtures.fiatOffers({ account_funds: '19' @@ -1196,7 +1168,7 @@ describe('OrderBook', function() { }); it('Update funded amounts - owner_funds', function(done) { - const remote = new Remote(); + const remote = createRemote(); const message = fixtures.transactionWithRippleState(); @@ -1206,7 +1178,7 @@ describe('OrderBook', function() { currency_pays: 'XRP' }); - book._issuerTransferRate = 1002000000; + book._issuerTransferRate = new IOUValue(1002000000); book._offers = fixtures.fiatOffers(); @@ -1222,7 +1194,7 @@ describe('OrderBook', function() { }); it('Update funded amounts - issuer transfer rate set', function(done) { - const remote = new Remote(); + const remote = createRemote(); const message = fixtures.transactionWithRippleState(); @@ -1232,7 +1204,7 @@ describe('OrderBook', function() { currency_pays: 'XRP' }); - book._issuerTransferRate = 1002000000; + book._issuerTransferRate = new IOUValue(1002000000); book._ownerFunds[addresses.ACCOUNT] = '100'; book._offers = fixtures.fiatOffers(); @@ -1250,7 +1222,7 @@ describe('OrderBook', function() { let receivedChangedEvents = 0; let receivedFundsChangedEvents = 0; - const remote = new Remote(); + const remote = createRemote(); const message = fixtures.transactionWithAccountRoot(); @@ -1292,7 +1264,7 @@ describe('OrderBook', function() { }); it('Update funded amounts - no affected account', function(done) { - const remote = new Remote(); + const remote = createRemote(); const message = fixtures.transactionWithAccountRoot({ account: addresses.ACCOUNT @@ -1324,7 +1296,7 @@ describe('OrderBook', function() { }); it('Update funded amounts - no balance change', function(done) { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'XRP', @@ -1357,7 +1329,7 @@ describe('OrderBook', function() { }); it('Update funded amounts - deferred TransferRate', function(done) { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', @@ -1376,7 +1348,7 @@ describe('OrderBook', function() { request.emit('success', fixtures.accountInfoResponse()); - assert.strictEqual(book._issuerTransferRate, fixtures.TRANSFER_RATE); + assert(book._issuerTransferRate.equals(new IOUValue(fixtures.TRANSFER_RATE))); done(); }; @@ -1385,7 +1357,7 @@ describe('OrderBook', function() { }); it('Set offers - issuer transfer rate set - iou/xrp', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', @@ -1393,7 +1365,7 @@ describe('OrderBook', function() { currency_pays: 'XRP' }); - book._issuerTransferRate = 1002000000; + book._issuerTransferRate = new IOUValue(1002000000); const offers = fixtures.bookOffersResponse().offers; @@ -1418,7 +1390,7 @@ describe('OrderBook', function() { }); it('Set offers - issuer transfer rate set - iou/xrp - funded amounts', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', @@ -1426,7 +1398,7 @@ describe('OrderBook', function() { currency_pays: 'XRP' }); - book._issuerTransferRate = 1002000000; + book._issuerTransferRate = new IOUValue(1002000000); const offers = fixtures.bookOffersResponse({ account_funds: '233.13532' @@ -1491,7 +1463,7 @@ describe('OrderBook', function() { }); it('Set offers - multiple calls', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', @@ -1499,7 +1471,7 @@ describe('OrderBook', function() { currency_pays: 'XRP' }); - book._issuerTransferRate = 1002000000; + book._issuerTransferRate = new IOUValue(1002000000); const offers = fixtures.bookOffersResponse().offers; @@ -1525,7 +1497,7 @@ describe('OrderBook', function() { }); it('Set offers - incorrect taker pays funded', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', @@ -1533,7 +1505,7 @@ describe('OrderBook', function() { currency_pays: 'XRP' }); - book._issuerTransferRate = 1002000000; + book._issuerTransferRate = new IOUValue(1002000000); const offers = fixtures.DECIMAL_TAKER_PAYS_FUNDED_OFFERS; @@ -1546,7 +1518,7 @@ describe('OrderBook', function() { }); it('Notify - created node', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', @@ -1554,7 +1526,7 @@ describe('OrderBook', function() { currency_pays: 'XRP' }); - book._issuerTransferRate = 1002000000; + book._issuerTransferRate = new IOUValue(1002000000); book._subscribed = book._synced = true; const message = fixtures.transactionWithCreatedOffer(); @@ -1568,7 +1540,7 @@ describe('OrderBook', function() { }); it('Notify - created nodes - correct sorting', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', @@ -1576,7 +1548,7 @@ describe('OrderBook', function() { currency_pays: 'XRP' }); - book._issuerTransferRate = 1002000000; + book._issuerTransferRate = new IOUValue(1002000000); book._subscribed = book._synced = true; const offer = fixtures.transactionWithCreatedOffer(); @@ -1601,12 +1573,12 @@ describe('OrderBook', function() { assert.strictEqual(book._offers[2].Account, addresses.OTHER_ACCOUNT); }); - it('Notify - created nodes - events', function() { + it('Notify - created nodes - events', function(done) { let numTransactionEvents = 0; let numModelEvents = 0; let numOfferAddedEvents = 0; - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', @@ -1626,7 +1598,7 @@ describe('OrderBook', function() { numOfferAddedEvents += 1; }); - book._issuerTransferRate = 1002000000; + book._issuerTransferRate = new IOUValue(1002000000); book._subscribed = book._synced = true; const offer = fixtures.transactionWithCreatedOffer(); @@ -1638,12 +1610,15 @@ describe('OrderBook', function() { book.notify(offer3); assert.strictEqual(numTransactionEvents, 3); - assert.strictEqual(numModelEvents, 3); assert.strictEqual(numOfferAddedEvents, 3); + setTimeout(function() { + assert.strictEqual(numModelEvents, 1); + done(); + }, 300); }); it('Notify - deleted node', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', @@ -1652,7 +1627,7 @@ describe('OrderBook', function() { }); book._subscribed = true; - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book.setOffers(fixtures.fiatOffers()); @@ -1666,7 +1641,7 @@ describe('OrderBook', function() { }); it('Notify - deleted node - last offer', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', @@ -1675,7 +1650,7 @@ describe('OrderBook', function() { }); book._subscribed = true; - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book.setOffers(fixtures.fiatOffers().slice(0, 1)); @@ -1687,13 +1662,13 @@ describe('OrderBook', function() { assert.strictEqual(book.getOwnerFunds(addresses.ACCOUNT), undefined); }); - it('Notify - deleted node - events', function() { + it('Notify - deleted node - events', function(done) { let numTransactionEvents = 0; let numModelEvents = 0; let numTradeEvents = 0; let numOfferRemovedEvents = 0; - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', issuer_gets: addresses.ISSUER, @@ -1717,7 +1692,7 @@ describe('OrderBook', function() { }); book._subscribed = true; - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book.setOffers(fixtures.fiatOffers()); @@ -1726,13 +1701,16 @@ describe('OrderBook', function() { book.notify(message); assert.strictEqual(numTransactionEvents, 1); - assert.strictEqual(numModelEvents, 1); assert.strictEqual(numTradeEvents, 1); assert.strictEqual(numOfferRemovedEvents, 1); + setTimeout(function() { + assert.strictEqual(numModelEvents, 1); + done(); + }, 300); }); it('Notify - deleted node - trade', function(done) { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', issuer_gets: addresses.ISSUER, @@ -1754,7 +1732,7 @@ describe('OrderBook', function() { }); book._subscribed = true; - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book.setOffers(fixtures.fiatOffers()); @@ -1764,7 +1742,7 @@ describe('OrderBook', function() { }); it('Notify - deleted node - offer cancel', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', @@ -1773,7 +1751,7 @@ describe('OrderBook', function() { }); book._subscribed = true; - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book.setOffers(fixtures.fiatOffers()); @@ -1789,7 +1767,7 @@ describe('OrderBook', function() { }); it('Notify - deleted node - offer cancel - last offer', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', @@ -1798,7 +1776,7 @@ describe('OrderBook', function() { }); book._subscribed = true; - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book.setOffers(fixtures.fiatOffers().slice(0, 1)); @@ -1813,7 +1791,7 @@ describe('OrderBook', function() { }); it('Notify - modified node', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', @@ -1822,7 +1800,7 @@ describe('OrderBook', function() { }); book._subscribed = true; - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book.setOffers(fixtures.fiatOffers()); @@ -1843,13 +1821,13 @@ describe('OrderBook', function() { assert.strictEqual(book._offers[1].taker_pays_funded, '972251352'); }); - it('Notify - modified node - events', function() { + it('Notify - modified node - events', function(done) { let numTransactionEvents = 0; let numModelEvents = 0; let numTradeEvents = 0; let numOfferChangedEvents = 0; - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', issuer_gets: addresses.ISSUER, @@ -1873,7 +1851,7 @@ describe('OrderBook', function() { }); book._subscribed = true; - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book.setOffers(fixtures.fiatOffers()); @@ -1882,13 +1860,16 @@ describe('OrderBook', function() { book.notify(message); assert.strictEqual(numTransactionEvents, 1); - assert.strictEqual(numModelEvents, 1); assert.strictEqual(numTradeEvents, 1); assert.strictEqual(numOfferChangedEvents, 1); + setTimeout(function() { + assert.strictEqual(numModelEvents, 1); + done(); + }, 300); }); it('Notify - modified node - trade', function(done) { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', issuer_gets: addresses.ISSUER, @@ -1910,7 +1891,7 @@ describe('OrderBook', function() { }); book._subscribed = true; - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book.setOffers(fixtures.fiatOffers()); @@ -1920,7 +1901,7 @@ describe('OrderBook', function() { }); it('Notify - modified nodes - trade', function(done) { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', issuer_gets: addresses.ISSUER, @@ -1942,7 +1923,7 @@ describe('OrderBook', function() { }); book._subscribed = true; - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book.setOffers(fixtures.fiatOffers()); @@ -1957,7 +1938,7 @@ describe('OrderBook', function() { let numTradeEvents = 0; let numOfferChangedEvents = 0; - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', issuer_gets: addresses.ISSUER, @@ -1981,7 +1962,7 @@ describe('OrderBook', function() { }); book._subscribed = true; - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book.setOffers(fixtures.fiatOffers()); @@ -1998,7 +1979,7 @@ describe('OrderBook', function() { it('Notify - in disconnected state', function(done) { this.timeout(100); - const remote = new Remote(); + const remote = createRemote(); const transaction = fixtures.transactionWithDeletedOfferR(); const offers = { offers: fixtures.REQUEST_OFFERS_NATIVE @@ -2043,7 +2024,7 @@ describe('OrderBook', function() { }); }); it('Delete offer - offer cancel - funded after delete', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', issuer_gets: addresses.ISSUER, @@ -2051,7 +2032,7 @@ describe('OrderBook', function() { }); book._subscribed = true; - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book.setOffers(fixtures.fiatOffers({ account_funds: '20' @@ -2070,7 +2051,7 @@ describe('OrderBook', function() { }); it('Delete offer - offer cancel - not fully funded after delete', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', issuer_gets: addresses.ISSUER, @@ -2078,7 +2059,7 @@ describe('OrderBook', function() { }); book._subscribed = true; - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book.setOffers(fixtures.fiatOffers({ account_funds: '4.5' @@ -2099,7 +2080,7 @@ describe('OrderBook', function() { }); it('Insert offer - best quality', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', issuer_gets: addresses.ISSUER, @@ -2107,7 +2088,7 @@ describe('OrderBook', function() { }); book._subscribed = true; - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book.setOffers(fixtures.QUALITY_OFFERS); @@ -2123,7 +2104,7 @@ describe('OrderBook', function() { }); it('Insert offer - best quality - insufficient funds for all offers', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', issuer_gets: addresses.ISSUER, @@ -2131,7 +2112,7 @@ describe('OrderBook', function() { }); book._subscribed = true; - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book.setOffers(fixtures.fiatOffers()); @@ -2158,7 +2139,7 @@ describe('OrderBook', function() { }); it('Insert offer - worst quality - insufficient funds for all orders', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', issuer_gets: addresses.ISSUER, @@ -2166,7 +2147,7 @@ describe('OrderBook', function() { }); book._subscribed = true; - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book.setOffers(fixtures.fiatOffers({ account_funds: '25' @@ -2195,7 +2176,7 @@ describe('OrderBook', function() { }); it('Insert offer - middle quality - insufficient funds for all offers', function() { - const remote = new Remote(); + const remote = createRemote(); const book = remote.createOrderBook({ currency_gets: 'USD', issuer_gets: addresses.ISSUER, @@ -2203,7 +2184,7 @@ describe('OrderBook', function() { }); book._subscribed = true; - book._issuerTransferRate = 1000000000; + book._issuerTransferRate = new IOUValue(1000000000); book.setOffers(fixtures.fiatOffers({ account_funds: '30' @@ -2232,7 +2213,7 @@ describe('OrderBook', function() { }); it('Request offers - native currency', function(done) { - const remote = new Remote(); + const remote = createRemote(); const offers = { offers: fixtures.REQUEST_OFFERS_NATIVE @@ -2258,6 +2239,7 @@ describe('OrderBook', function() { is_fully_funded: false, taker_gets_funded: '600', taker_pays_funded: '33.6398379637041', + qualityHex: '5711A3A4254F5000', quality: '.0560663966061735' }, { @@ -2280,6 +2262,7 @@ describe('OrderBook', function() { is_fully_funded: true, taker_gets_funded: '2000', taker_pays_funded: '99.72233516476456', + qualityHex: '5711B6D8C62EF414', quality: '0.049861167582382' }, { @@ -2302,6 +2285,7 @@ describe('OrderBook', function() { is_fully_funded: true, taker_gets_funded: '2000', taker_pays_funded: '99.72233516476456', + qualityHex: '5711B6D8C62EF414', quality: '0.049861167582382' }, { @@ -2324,6 +2308,7 @@ describe('OrderBook', function() { taker_gets_funded: '1900', taker_pays_funded: '94.7362184065258', owner_funds: '3900', + qualityHex: '5711B6D8C62EF414', quality: '0.049861167582382' } ];