mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-12-06 17:27:59 +00:00
Merge pull request #553 from darkdarkdragon/develop-master-merge
Merge OrderBook optimizations from master to develop
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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,7 +438,8 @@ function setLegOneTakerGetsFunded(legOneOffer, takerGetsFunded) {
|
||||
|
||||
legOneOffer.taker_gets_funded = takerGetsFunded.to_text();
|
||||
legOneOffer.taker_pays_funded = takerGetsFunded
|
||||
.multiply(Utils.getOfferQuality(legOneOffer, this._currencyGets))
|
||||
.multiply(Utils.getOfferQuality(legOneOffer, this._currencyGets,
|
||||
this._currencyPays, this._issuerPaysObj))
|
||||
.to_text();
|
||||
|
||||
if (legOneOffer.taker_gets_funded === legOneOffer.TakerGets.value) {
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,9 +61,9 @@ 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);
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,7 +435,9 @@ 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 ||
|
||||
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');
|
||||
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,6 +1079,15 @@ OrderBook.prototype.insertOffer = function(node) {
|
||||
|
||||
const originalLength = this._offers.length;
|
||||
|
||||
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(
|
||||
@@ -964,6 +1101,7 @@ OrderBook.prototype.insertOffer = function(node) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this._offers.length === originalLength) {
|
||||
this._offers.push(offer);
|
||||
@@ -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
|
||||
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);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
|
||||
17
test/fixtures/orderbook.js
vendored
17
test/fixtures/orderbook.js
vendored
@@ -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: {
|
||||
|
||||
@@ -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);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user