mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-05 05:15:48 +00:00
Compare commits
4 Commits
0.12.4
...
0.12.5-rc1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ba5a18b91 | ||
|
|
bdb3415855 | ||
|
|
5ef5bdd9d9 | ||
|
|
c7bbce8371 |
@@ -1,3 +1,7 @@
|
||||
##0.12.15
|
||||
|
||||
+ [Add offer autobridging](https://github.com/ripple/ripple-lib/commit/c7bbce83719c1e8c6a4fae5ca850e7515db1a4a5)
|
||||
|
||||
##0.12.4
|
||||
|
||||
+ [Improve entropy security](https://github.com/ripple/ripple-lib/commit/c7ba822320880037796f57876d1abb4e525648ed)
|
||||
|
||||
2
npm-shrinkwrap.json
generated
2
npm-shrinkwrap.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "0.12.4",
|
||||
"version": "0.12.5-rc1",
|
||||
"npm-shrinkwrap-version": "5.3.0",
|
||||
"node-version": "v0.10.38",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "0.12.4",
|
||||
"version": "0.12.5-rc1",
|
||||
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
|
||||
"files": [
|
||||
"src/js/*",
|
||||
|
||||
435
src/js/ripple/autobridgecalculator.js
Normal file
435
src/js/ripple/autobridgecalculator.js
Normal file
@@ -0,0 +1,435 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var assert = require('assert');
|
||||
var UInt160 = require('./uint160').UInt160;
|
||||
var Amount = require('./amount').Amount;
|
||||
var Utils = require('./orderbookutils');
|
||||
|
||||
function assertValidNumber(number, message) {
|
||||
assert(!_.isNull(number) && !isNaN(number), message);
|
||||
}
|
||||
|
||||
function assertValidLegOneOffer(legOneOffer, message) {
|
||||
assert(legOneOffer);
|
||||
assert.strictEqual(typeof legOneOffer, 'object', message);
|
||||
assert.strictEqual(typeof legOneOffer.TakerPays, 'object', message);
|
||||
assertValidNumber(legOneOffer.TakerGets, message);
|
||||
}
|
||||
|
||||
function AutobridgeCalculator(currencyGets, currencyPays,
|
||||
legOneOffers, legTwoOffers) {
|
||||
this._currencyGets = currencyGets;
|
||||
this._currencyPays = currencyPays;
|
||||
this.legOneOffers = _.cloneDeep(legOneOffers);
|
||||
this.legTwoOffers = _.cloneDeep(legTwoOffers);
|
||||
|
||||
this._ownerFundsLeftover = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates an ordered array of autobridged offers by quality
|
||||
*
|
||||
* @return {Array}
|
||||
*/
|
||||
|
||||
AutobridgeCalculator.prototype.calculate = function() {
|
||||
var legOnePointer = 0;
|
||||
var legTwoPointer = 0;
|
||||
|
||||
var offersAutobridged = [];
|
||||
|
||||
this.clearOwnerFundsLeftover();
|
||||
|
||||
while (this.legOneOffers[legOnePointer] && this.legTwoOffers[legTwoPointer]) {
|
||||
var legOneOffer = this.legOneOffers[legOnePointer];
|
||||
var legTwoOffer = this.legTwoOffers[legTwoPointer];
|
||||
var leftoverFunds = this.getLeftoverOwnerFunds(legOneOffer.Account);
|
||||
var autobridgedOffer;
|
||||
|
||||
if (legOneOffer.Account === legTwoOffer.Account) {
|
||||
this.unclampLegOneOwnerFunds(legOneOffer);
|
||||
} else if (!legOneOffer.is_fully_funded && !leftoverFunds.is_zero()) {
|
||||
this.adjustLegOneFundedAmount(legOneOffer);
|
||||
}
|
||||
|
||||
var legOneTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer);
|
||||
var legTwoTakerPaysFunded = Utils.getOfferTakerPaysFunded(legTwoOffer);
|
||||
|
||||
if (legOneTakerGetsFunded.is_zero()) {
|
||||
legOnePointer++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (legTwoTakerPaysFunded.is_zero()) {
|
||||
legTwoPointer++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (legOneTakerGetsFunded.compareTo(legTwoTakerPaysFunded) > 0) {
|
||||
autobridgedOffer = this.getAutobridgedOfferWithClampedLegOne(
|
||||
legOneOffer,
|
||||
legTwoOffer
|
||||
);
|
||||
|
||||
legTwoPointer++;
|
||||
} else if (legTwoTakerPaysFunded.compareTo(legOneTakerGetsFunded) > 0) {
|
||||
autobridgedOffer = this.getAutobridgedOfferWithClampedLegTwo(
|
||||
legOneOffer,
|
||||
legTwoOffer
|
||||
);
|
||||
|
||||
legOnePointer++;
|
||||
} else {
|
||||
autobridgedOffer = this.getAutobridgedOfferWithoutClamps(
|
||||
legOneOffer,
|
||||
legTwoOffer
|
||||
);
|
||||
|
||||
legOnePointer++;
|
||||
legTwoPointer++;
|
||||
}
|
||||
|
||||
offersAutobridged.push(autobridgedOffer);
|
||||
}
|
||||
|
||||
return offersAutobridged;
|
||||
};
|
||||
|
||||
/**
|
||||
* In this case, the output from leg one is greater than the input to leg two.
|
||||
* Therefore, we must effectively clamp leg one output to leg two input.
|
||||
*
|
||||
* @param {Object} legOneOffer
|
||||
* @param {Object} legTwoOffer
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
|
||||
AutobridgeCalculator.prototype.getAutobridgedOfferWithClampedLegOne =
|
||||
function(legOneOffer, legTwoOffer) {
|
||||
var legOneTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer);
|
||||
var legTwoTakerPaysFunded = Utils.getOfferTakerPaysFunded(legTwoOffer);
|
||||
var legOneQuality = Utils.getOfferQuality(legOneOffer, this._currencyGets);
|
||||
|
||||
var autobridgedTakerGets = Utils.getOfferTakerGetsFunded(legTwoOffer);
|
||||
var autobridgedTakerPays = legTwoTakerPaysFunded.multiply(legOneQuality);
|
||||
|
||||
if (legOneOffer.Account === legTwoOffer.Account) {
|
||||
var legOneTakerGets = Utils.getOfferTakerGets(legOneOffer);
|
||||
var updatedTakerGets = legOneTakerGets.subtract(legTwoTakerPaysFunded);
|
||||
|
||||
this.setLegOneTakerGets(legOneOffer, updatedTakerGets);
|
||||
|
||||
this.clampLegOneOwnerFunds(legOneOffer);
|
||||
} else {
|
||||
// Update funded amount since leg one offer was not completely consumed
|
||||
var updatedTakerGetsFunded = legOneTakerGetsFunded
|
||||
.subtract(legTwoTakerPaysFunded);
|
||||
|
||||
this.setLegOneTakerGetsFunded(legOneOffer, updatedTakerGetsFunded);
|
||||
}
|
||||
|
||||
return this.formatAutobridgedOffer(
|
||||
autobridgedTakerGets,
|
||||
autobridgedTakerPays
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* In this case, the input from leg two is greater than the output to leg one.
|
||||
* Therefore, we must effectively clamp leg two input to leg one output.
|
||||
*
|
||||
* @param {Object} legOneOffer
|
||||
* @param {Object} legTwoOffer
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
|
||||
AutobridgeCalculator.prototype.getAutobridgedOfferWithClampedLegTwo =
|
||||
function(legOneOffer, legTwoOffer) {
|
||||
var legOneTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer);
|
||||
var legTwoTakerPaysFunded = Utils.getOfferTakerPaysFunded(legTwoOffer);
|
||||
var legTwoQuality = Utils.getOfferQuality(legTwoOffer, this._currencyGets);
|
||||
|
||||
var autobridgedTakerGets = legOneTakerGetsFunded.divide(legTwoQuality);
|
||||
var autobridgedTakerPays = Utils.getOfferTakerPaysFunded(legOneOffer);
|
||||
|
||||
// Update funded amount since leg two offer was not completely consumed
|
||||
legTwoOffer.taker_gets_funded = Utils.getOfferTakerGetsFunded(legTwoOffer)
|
||||
.subtract(autobridgedTakerGets)
|
||||
.to_text();
|
||||
legTwoOffer.taker_pays_funded = legTwoTakerPaysFunded
|
||||
.subtract(legOneTakerGetsFunded)
|
||||
.to_text();
|
||||
|
||||
return this.formatAutobridgedOffer(
|
||||
autobridgedTakerGets,
|
||||
autobridgedTakerPays
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* In this case, the output from leg one and the input to leg two are the same.
|
||||
* We do not need to clamp either.
|
||||
* @param {Object} legOneOffer
|
||||
* @param {Object} legTwoOffer
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
|
||||
AutobridgeCalculator.prototype.getAutobridgedOfferWithoutClamps =
|
||||
function(legOneOffer, legTwoOffer) {
|
||||
var autobridgedTakerGets = Utils.getOfferTakerGetsFunded(legTwoOffer);
|
||||
var autobridgedTakerPays = Utils.getOfferTakerPaysFunded(legOneOffer);
|
||||
|
||||
return this.formatAutobridgedOffer(
|
||||
autobridgedTakerGets,
|
||||
autobridgedTakerPays
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear owner funds leftovers
|
||||
*/
|
||||
|
||||
AutobridgeCalculator.prototype.clearOwnerFundsLeftover = function() {
|
||||
this._ownerFundsLeftover = {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset owner funds leftovers for an account to 0
|
||||
*
|
||||
* @param {String} account
|
||||
*
|
||||
* @return {Amount}
|
||||
*/
|
||||
|
||||
AutobridgeCalculator.prototype.resetOwnerFundsLeftover = function(account) {
|
||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
||||
|
||||
this._ownerFundsLeftover[account] = Utils.normalizeAmount('0');
|
||||
|
||||
return this._ownerFundsLeftover[account];
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve leftover funds found after clamping leg one by account
|
||||
*
|
||||
* @param {String} account
|
||||
*
|
||||
* @return {Amount}
|
||||
*/
|
||||
|
||||
AutobridgeCalculator.prototype.getLeftoverOwnerFunds = function(account) {
|
||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
||||
|
||||
var amount = this._ownerFundsLeftover[account];
|
||||
|
||||
if (!amount) {
|
||||
amount = Utils.normalizeAmount('0');
|
||||
}
|
||||
|
||||
return amount;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add funds to account's leftover funds
|
||||
*
|
||||
* @param {String} account
|
||||
* @param {Amount} amount
|
||||
*
|
||||
* @return {Amount}
|
||||
*/
|
||||
|
||||
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)
|
||||
.add(amount);
|
||||
|
||||
return this._ownerFundsLeftover[account];
|
||||
};
|
||||
|
||||
/**
|
||||
* Set account's leftover funds
|
||||
*
|
||||
* @param {String} account
|
||||
* @param {Amount} 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Format an autobridged offer and compute synthetic values (e.g. quality)
|
||||
*
|
||||
* @param {Amount} takerGets
|
||||
* @param {Amount} takerPays
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
|
||||
AutobridgeCalculator.prototype.formatAutobridgedOffer =
|
||||
function(takerGets, takerPays) {
|
||||
assert(takerGets instanceof Amount, 'Autobridged taker gets is invalid');
|
||||
assert(takerPays instanceof Amount, 'Autobridged taker pays is invalid');
|
||||
|
||||
var autobridgedOffer = {};
|
||||
var quality = takerPays.divide(takerGets);
|
||||
|
||||
autobridgedOffer.TakerGets = {
|
||||
value: takerGets.to_text(),
|
||||
currency: this._currencyGets.to_hex(),
|
||||
issuer: this._issuerGets
|
||||
};
|
||||
|
||||
autobridgedOffer.TakerPays = {
|
||||
value: takerPays.to_text(),
|
||||
currency: this._currencyPays.to_hex(),
|
||||
issuer: this._issuerPays
|
||||
};
|
||||
|
||||
autobridgedOffer.quality = quality.to_text();
|
||||
|
||||
autobridgedOffer.taker_gets_funded = autobridgedOffer.TakerGets.value;
|
||||
autobridgedOffer.taker_pays_funded = autobridgedOffer.TakerPays.value;
|
||||
|
||||
autobridgedOffer.autobridged = true;
|
||||
|
||||
autobridgedOffer.BookDirectory = Utils.convertOfferQualityToHex(quality);
|
||||
|
||||
return autobridgedOffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove funds clamp on leg one offer. This is necessary when the two offers
|
||||
* are owned by the same account. In this case, it doesn't matter if offer one
|
||||
* is not fully funded. Leg one out goes to leg two in and since its the same
|
||||
* account, an infinite amount can flow.
|
||||
*
|
||||
* @param {Object} legOneOffer - IOU:XRP offer
|
||||
*/
|
||||
|
||||
AutobridgeCalculator.prototype.unclampLegOneOwnerFunds = function(legOneOffer) {
|
||||
assertValidLegOneOffer(legOneOffer, 'Leg one offer is invalid');
|
||||
|
||||
legOneOffer.initTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer);
|
||||
|
||||
this.setLegOneTakerGetsFunded(
|
||||
legOneOffer,
|
||||
Utils.getOfferTakerGets(legOneOffer)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply clamp back on leg one offer after a round of autobridge calculation
|
||||
* completes. We must reapply clamps that have been removed because we cannot
|
||||
* guarantee that the next offer from leg two will also be from the same
|
||||
* account.
|
||||
*
|
||||
* When we reapply, it could happen that the amount of TakerGets left after
|
||||
* the autobridge calculation is less than the original funded amount. In this
|
||||
* case, we have extra funds we can use towards unfunded offers with worse
|
||||
* quality by the same owner.
|
||||
*
|
||||
* @param {Object} legOneOffer - IOU:XRP offer
|
||||
*/
|
||||
|
||||
AutobridgeCalculator.prototype.clampLegOneOwnerFunds = function(legOneOffer) {
|
||||
assertValidLegOneOffer(legOneOffer, 'Leg one offer is invalid');
|
||||
|
||||
var takerGets = Utils.getOfferTakerGets(legOneOffer);
|
||||
|
||||
if (takerGets.compareTo(legOneOffer.initTakerGetsFunded) > 0) {
|
||||
// After clamping, TakerGets is still greater than initial funded amount
|
||||
this.setLegOneTakerGetsFunded(legOneOffer, legOneOffer.initTakerGetsFunded);
|
||||
} else {
|
||||
var updatedLeftover = legOneOffer.initTakerGetsFunded.subtract(takerGets);
|
||||
|
||||
this.setLegOneTakerGetsFunded(legOneOffer, takerGets);
|
||||
this.addLeftoverOwnerFunds(legOneOffer.Account, updatedLeftover);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Increase leg one offer funded amount with extra funds found after applying
|
||||
* clamp.
|
||||
*
|
||||
* @param {Object} legOneOffer - IOU:XRP offer
|
||||
*/
|
||||
|
||||
AutobridgeCalculator.prototype.adjustLegOneFundedAmount =
|
||||
function(legOneOffer) {
|
||||
assertValidLegOneOffer(legOneOffer, 'Leg one offer is invalid');
|
||||
assert(!legOneOffer.is_fully_funded, 'Leg one offer cannot be fully funded');
|
||||
|
||||
var fundedSum = Utils.getOfferTakerGetsFunded(legOneOffer)
|
||||
.add(this.getLeftoverOwnerFunds(legOneOffer.Account));
|
||||
|
||||
if (fundedSum.compareTo(Utils.getOfferTakerGets(legOneOffer)) >= 0) {
|
||||
// There are enough extra funds to fully fund the offer
|
||||
var legOneTakerGets = Utils.getOfferTakerGets(legOneOffer);
|
||||
var updatedLeftover = fundedSum.subtract(legOneTakerGets);
|
||||
|
||||
this.setLegOneTakerGetsFunded(legOneOffer, legOneTakerGets);
|
||||
this.setLeftoverOwnerFunds(legOneOffer.Account, updatedLeftover);
|
||||
} else {
|
||||
// There are not enough extra funds to fully fund the offer
|
||||
this.setLegOneTakerGetsFunded(legOneOffer, fundedSum);
|
||||
this.resetOwnerFundsLeftover(legOneOffer.Account);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set taker gets funded amount for a IOU:XRP offer. Also calculates taker
|
||||
* pays funded using offer quality and updates is_fully_funded flag
|
||||
*
|
||||
* @param {Object} legOneOffer - IOU:XRP offer
|
||||
* @param {Amount} takerGetsFunded
|
||||
*/
|
||||
|
||||
AutobridgeCalculator.prototype.setLegOneTakerGetsFunded =
|
||||
function setLegOneTakerGetsFunded(legOneOffer, takerGetsFunded) {
|
||||
assertValidLegOneOffer(legOneOffer, 'Leg one offer is invalid');
|
||||
assert(takerGetsFunded instanceof Amount, 'Taker gets funded is invalid');
|
||||
|
||||
legOneOffer.taker_gets_funded = takerGetsFunded.to_text();
|
||||
legOneOffer.taker_pays_funded = takerGetsFunded
|
||||
.multiply(Utils.getOfferQuality(legOneOffer, this._currencyGets))
|
||||
.to_text();
|
||||
|
||||
if (legOneOffer.taker_gets_funded === legOneOffer.TakerGets.value) {
|
||||
legOneOffer.is_fully_funded = true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set taker gets amount for a IOU:XRP offer. Also calculates taker pays
|
||||
* using offer quality
|
||||
*
|
||||
* @param {Object} legOneOffer - IOU:XRP offer
|
||||
* @param {Amount} takerGets
|
||||
*/
|
||||
|
||||
AutobridgeCalculator.prototype.setLegOneTakerGets =
|
||||
function(legOneOffer, takerGets) {
|
||||
assertValidLegOneOffer(legOneOffer, 'Leg one offer is invalid');
|
||||
assert(takerGets instanceof Amount, 'Taker gets funded is invalid');
|
||||
|
||||
var legOneQuality = Utils.getOfferQuality(legOneOffer, this._currencyGets);
|
||||
|
||||
legOneOffer.TakerGets = takerGets.to_text();
|
||||
legOneOffer.TakerPays = takerGets.multiply(legOneQuality);
|
||||
};
|
||||
|
||||
module.exports = AutobridgeCalculator;
|
||||
@@ -19,6 +19,8 @@ var EventEmitter = require('events').EventEmitter;
|
||||
var Amount = require('./amount').Amount;
|
||||
var UInt160 = require('./uint160').UInt160;
|
||||
var Currency = require('./currency').Currency;
|
||||
var AutobridgeCalculator = require('./autobridgecalculator');
|
||||
var OrderBookUtils = require('./orderbookutils');
|
||||
var log = require('./log').internal.sub('orderbook');
|
||||
|
||||
function assertValidNumber(number, message) {
|
||||
@@ -35,21 +37,25 @@ function assertValidNumber(number, message) {
|
||||
* @param {String} orderbook key
|
||||
*/
|
||||
|
||||
function OrderBook(remote, getsC, getsI, paysC, paysI, key) {
|
||||
function OrderBook(remote,
|
||||
currencyGets, issuerGets, currencyPays, issuerPays,
|
||||
key) {
|
||||
EventEmitter.call(this);
|
||||
|
||||
var self = this;
|
||||
|
||||
this._remote = remote;
|
||||
this._currencyGets = Currency.from_json(getsC);
|
||||
this._issuerGets = getsI;
|
||||
this._currencyPays = Currency.from_json(paysC);
|
||||
this._issuerPays = paysI;
|
||||
this._currencyGets = Currency.from_json(currencyGets);
|
||||
this._issuerGets = issuerGets;
|
||||
this._currencyPays = Currency.from_json(currencyPays);
|
||||
this._issuerPays = issuerPays;
|
||||
this._key = key;
|
||||
this._subscribed = false;
|
||||
this._shouldSubscribe = true;
|
||||
this._listeners = 0;
|
||||
this._offers = [ ];
|
||||
this._offers = [];
|
||||
this._offersAutobridged = [];
|
||||
this._mergedOffers = [];
|
||||
this._offerCounts = {};
|
||||
this._ownerFundsUnadjusted = {};
|
||||
this._ownerFunds = {};
|
||||
@@ -62,6 +68,37 @@ function OrderBook(remote, getsC, getsI, paysC, paysI, key) {
|
||||
// Transfer rate of the taker gets currency issuer
|
||||
this._issuerTransferRate = null;
|
||||
|
||||
// When orderbook is IOU/IOU, there will be IOU/XRP and XRP/IOU
|
||||
// books that we must keep track of to compute autobridged offers
|
||||
this._legOneBook = null;
|
||||
this._legTwoBook = null;
|
||||
|
||||
this._isAutobridgeable = !this._currencyGets.is_native()
|
||||
&& !this._currencyPays.is_native();
|
||||
|
||||
function computeAutobridgedOffersWrapper() {
|
||||
self.computeAutobridgedOffers();
|
||||
self.mergeDirectAndAutobridgedBooks();
|
||||
}
|
||||
|
||||
if (this._isAutobridgeable) {
|
||||
this._legOneBook = remote.createOrderBook({
|
||||
currency_gets: 'XRP',
|
||||
currency_pays: currencyPays,
|
||||
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 listenersModified(action, event) {
|
||||
// Automatically subscribe and unsubscribe to orderbook
|
||||
// on the basis of existing event listeners
|
||||
@@ -81,7 +118,7 @@ function OrderBook(remote, getsC, getsI, paysC, paysI, key) {
|
||||
}
|
||||
}
|
||||
|
||||
function updateFundedAmountsWrapper (transaction) {
|
||||
function updateFundedAmountsWrapper(transaction) {
|
||||
self.updateFundedAmounts(transaction);
|
||||
}
|
||||
|
||||
@@ -129,8 +166,6 @@ OrderBook.EVENTS = [
|
||||
|
||||
OrderBook.DEFAULT_TRANSFER_RATE = 1000000000;
|
||||
|
||||
OrderBook.IOU_SUFFIX = '/000/rrrrrrrrrrrrrrrrrrrrrhoLvTp';
|
||||
|
||||
/**
|
||||
* Normalize offers from book_offers and transaction stream
|
||||
*
|
||||
@@ -247,7 +282,7 @@ OrderBook.prototype.requestOffers = function(callback) {
|
||||
|
||||
self.setOffers(res.offers);
|
||||
self._synchronized = true;
|
||||
self.emit('model', self._offers);
|
||||
self.notifyDirectOffersChanged();
|
||||
|
||||
callback(null, self._offers);
|
||||
}
|
||||
@@ -269,6 +304,48 @@ OrderBook.prototype.requestOffers = function(callback) {
|
||||
return request;
|
||||
};
|
||||
|
||||
/**
|
||||
* Request transfer rate for this orderbook's issuer
|
||||
*
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
OrderBook.prototype.requestTransferRate = function(callback) {
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
var self = this;
|
||||
|
||||
if (this._currencyGets.is_native()) {
|
||||
// Transfer rate is default for the native currency
|
||||
this._issuerTransferRate = OrderBook.DEFAULT_TRANSFER_RATE;
|
||||
|
||||
return callback(null, OrderBook.DEFAULT_TRANSFER_RATE);
|
||||
}
|
||||
|
||||
if (this._issuerTransferRate) {
|
||||
// Transfer rate has already been cached
|
||||
return callback(null, this._issuerTransferRate);
|
||||
}
|
||||
|
||||
function handleAccountInfo(err, info) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// When transfer rate is not explicitly set on account, it implies the
|
||||
// default transfer rate
|
||||
self._issuerTransferRate = info.account_data.TransferRate ||
|
||||
OrderBook.DEFAULT_TRANSFER_RATE;
|
||||
|
||||
callback(null, self._issuerTransferRate);
|
||||
}
|
||||
|
||||
this._remote.requestAccountInfo(
|
||||
{account: this._issuerGets},
|
||||
handleAccountInfo
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Subscribe to transactions stream
|
||||
*
|
||||
@@ -317,6 +394,19 @@ OrderBook.prototype.subscribeTransactions = function(callback) {
|
||||
return request;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles notifying listeners that direct offers have changed. For autobridged
|
||||
* books, an additional merge step is also performed
|
||||
*/
|
||||
|
||||
OrderBook.prototype.notifyDirectOffersChanged = function() {
|
||||
if (this._isAutobridgeable) {
|
||||
this.mergeDirectAndAutobridgedBooks();
|
||||
} else {
|
||||
this.emit('model', this._offers);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset cached owner's funds, offer counts, and offer sums
|
||||
*/
|
||||
@@ -354,6 +444,27 @@ OrderBook.prototype.setOwnerFunds = function(account, fundedAmount) {
|
||||
this._ownerFunds[account] = this.applyTransferRate(fundedAmount);
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute adjusted balance that would be left after issuer's transfer fee is
|
||||
* deducted
|
||||
*
|
||||
* @param {String} balance
|
||||
* @return {String}
|
||||
*/
|
||||
|
||||
OrderBook.prototype.applyTransferRate = function(balance) {
|
||||
assert(!isNaN(balance), 'Balance is invalid');
|
||||
assertValidNumber(this._issuerTransferRate, 'Transfer rate is invalid');
|
||||
|
||||
var adjustedBalance = OrderBookUtils.normalizeAmount(balance)
|
||||
.divide(this._issuerTransferRate)
|
||||
.multiply(Amount.from_json(OrderBook.DEFAULT_TRANSFER_RATE))
|
||||
.to_json()
|
||||
.value;
|
||||
|
||||
return adjustedBalance;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get owner's cached, transfer rate adjusted, funds
|
||||
*
|
||||
@@ -370,9 +481,7 @@ OrderBook.prototype.getOwnerFunds = function(account) {
|
||||
if (this._currencyGets.is_native()) {
|
||||
amount = Amount.from_json(this._ownerFunds[account]);
|
||||
} else {
|
||||
amount = Amount.from_json(
|
||||
this._ownerFunds[account] + OrderBook.IOU_SUFFIX
|
||||
);
|
||||
amount = OrderBookUtils.normalizeAmount(this._ownerFunds[account]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,6 +568,7 @@ OrderBook.prototype.decrementOwnerOfferCount = function(account) {
|
||||
|
||||
OrderBook.prototype.addOwnerOfferTotal = function(account, amount) {
|
||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
||||
|
||||
var previousAmount = this.getOwnerOfferTotal(account);
|
||||
var currentAmount = previousAmount.add(Amount.from_json(amount));
|
||||
|
||||
@@ -478,6 +588,7 @@ OrderBook.prototype.addOwnerOfferTotal = function(account, amount) {
|
||||
|
||||
OrderBook.prototype.subtractOwnerOfferTotal = function(account, amount) {
|
||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
||||
|
||||
var previousAmount = this.getOwnerOfferTotal(account);
|
||||
var newAmount = previousAmount.subtract(Amount.from_json(amount));
|
||||
this._ownerOffersTotal[account] = newAmount;
|
||||
@@ -503,7 +614,7 @@ OrderBook.prototype.getOwnerOfferTotal = function(account) {
|
||||
if (this._currencyGets.is_native()) {
|
||||
amount = Amount.from_json('0');
|
||||
} else {
|
||||
amount = Amount.from_json('0' + OrderBook.IOU_SUFFIX);
|
||||
amount = OrderBookUtils.normalizeAmount('0');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -518,12 +629,14 @@ OrderBook.prototype.getOwnerOfferTotal = function(account) {
|
||||
*/
|
||||
|
||||
OrderBook.prototype.resetOwnerOfferTotal = function(account) {
|
||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
||||
|
||||
var amount;
|
||||
|
||||
if (this._currencyGets.is_native()) {
|
||||
amount = Amount.from_json('0');
|
||||
} else {
|
||||
amount = Amount.from_json('0' + OrderBook.IOU_SUFFIX);
|
||||
amount = OrderBookUtils.normalizeAmount('0');
|
||||
}
|
||||
|
||||
this._ownerOffersTotal[account] = amount;
|
||||
@@ -531,82 +644,6 @@ OrderBook.prototype.resetOwnerOfferTotal = function(account) {
|
||||
return amount;
|
||||
};
|
||||
|
||||
/**
|
||||
* Casts and returns offer's taker gets funded amount as a default IOU amount
|
||||
*
|
||||
* @param {Object} offer
|
||||
* @return {Amount}
|
||||
*/
|
||||
|
||||
OrderBook.prototype.getOfferTakerGetsFunded = function(offer) {
|
||||
assertValidNumber(offer.taker_gets_funded, 'Taker gets funded is invalid');
|
||||
|
||||
return Amount.from_json(offer.taker_gets_funded + OrderBook.IOU_SUFFIX);
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute adjusted balance that would be left after issuer's transfer fee is
|
||||
* deducted
|
||||
*
|
||||
* @param {String} balance
|
||||
* @return {String}
|
||||
*/
|
||||
|
||||
OrderBook.prototype.applyTransferRate = function(balance) {
|
||||
assert(!isNaN(balance), 'Balance is invalid');
|
||||
assertValidNumber(this._issuerTransferRate, 'Transfer rate is invalid');
|
||||
|
||||
var adjustedBalance = Amount.from_json(balance + OrderBook.IOU_SUFFIX)
|
||||
.divide(this._issuerTransferRate)
|
||||
.multiply(Amount.from_json(OrderBook.DEFAULT_TRANSFER_RATE))
|
||||
.to_json()
|
||||
.value;
|
||||
|
||||
return adjustedBalance;
|
||||
};
|
||||
|
||||
/**
|
||||
* Request transfer rate for this orderbook's issuer
|
||||
*
|
||||
* @param {Function} callback
|
||||
*/
|
||||
|
||||
OrderBook.prototype.requestTransferRate = function(callback) {
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
var self = this;
|
||||
|
||||
if (this._currencyGets.is_native()) {
|
||||
// Transfer rate is default for the native currency
|
||||
this._issuerTransferRate = OrderBook.DEFAULT_TRANSFER_RATE;
|
||||
|
||||
return callback(null, OrderBook.DEFAULT_TRANSFER_RATE);
|
||||
}
|
||||
|
||||
if (this._issuerTransferRate) {
|
||||
// Transfer rate has already been cached
|
||||
return callback(null, this._issuerTransferRate);
|
||||
}
|
||||
|
||||
function handleAccountInfo(err, info) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// When transfer rate is not explicitly set on account, it implies the
|
||||
// default transfer rate
|
||||
self._issuerTransferRate = info.account_data.TransferRate ||
|
||||
OrderBook.DEFAULT_TRANSFER_RATE;
|
||||
|
||||
callback(null, self._issuerTransferRate);
|
||||
}
|
||||
|
||||
this._remote.requestAccountInfo(
|
||||
{account: this._issuerGets},
|
||||
handleAccountInfo
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set funded amount on offer with its owner's cached funds
|
||||
*
|
||||
@@ -635,8 +672,9 @@ OrderBook.prototype.setOfferFundedAmount = function(offer) {
|
||||
} else if (previousOfferSum.compareTo(fundedAmount) < 0) {
|
||||
offer.taker_gets_funded = fundedAmount.subtract(previousOfferSum).to_text();
|
||||
|
||||
var takerPaysFunded = this.getOfferQuality(offer).multiply(
|
||||
this.getOfferTakerGetsFunded(offer)
|
||||
var quality = OrderBookUtils.getOfferQuality(offer, this._currencyGets);
|
||||
var takerPaysFunded = quality.multiply(
|
||||
OrderBookUtils.getOfferTakerGetsFunded(offer)
|
||||
);
|
||||
|
||||
offer.taker_pays_funded = this._currencyPays.is_native()
|
||||
@@ -727,8 +765,8 @@ OrderBook.prototype.isBalanceChangeNode = function(node) {
|
||||
/**
|
||||
* Updates funded amounts/balances using modified balance nodes
|
||||
*
|
||||
* Update owner funds using modified AccountRoot and RippleState nodes.
|
||||
* Update funded amounts for offers in the orderbook using owner funds.
|
||||
* Update owner funds using modified AccountRoot and RippleState nodes
|
||||
* Update funded amounts for offers in the orderbook using owner funds
|
||||
*
|
||||
* @param {Object} transaction - transaction that holds meta nodes
|
||||
*/
|
||||
@@ -753,7 +791,7 @@ OrderBook.prototype.updateFundedAmounts = function(transaction) {
|
||||
entryType: this._currencyGets.is_native() ? 'AccountRoot' : 'RippleState'
|
||||
});
|
||||
|
||||
_.each(affectedNodes, function (node) {
|
||||
_.each(affectedNodes, function(node) {
|
||||
if (self.isBalanceChangeNode(node)) {
|
||||
var result = self.parseAccountBalanceFromNode(node);
|
||||
|
||||
@@ -786,7 +824,7 @@ OrderBook.prototype.updateOwnerOffersFundedAmount = function(account) {
|
||||
|
||||
this.resetOwnerOfferTotal(account);
|
||||
|
||||
_.each(this._offers, function (offer) {
|
||||
_.each(this._offers, function(offer) {
|
||||
if (offer.Account !== account) {
|
||||
return;
|
||||
}
|
||||
@@ -798,14 +836,15 @@ OrderBook.prototype.updateOwnerOffersFundedAmount = function(account) {
|
||||
if (_.isString(offer.taker_gets_funded)) {
|
||||
// Offer is not new, so we should consider it for offer_changed and
|
||||
// offer_funds_changed events
|
||||
previousFundedGets = self.getOfferTakerGetsFunded(offer);
|
||||
previousFundedGets = OrderBookUtils.getOfferTakerGetsFunded(offer);
|
||||
}
|
||||
|
||||
self.setOfferFundedAmount(offer);
|
||||
self.addOwnerOfferTotal(offer.Account, offer.TakerGets);
|
||||
|
||||
var takerGetsFunded = OrderBookUtils.getOfferTakerGetsFunded(offer);
|
||||
var areFundsChanged = previousFundedGets
|
||||
&& !self.getOfferTakerGetsFunded(offer).equals(previousFundedGets);
|
||||
&& !takerGetsFunded.equals(previousFundedGets);
|
||||
|
||||
if (areFundsChanged) {
|
||||
self.emit('offer_changed', previousOffer, offer);
|
||||
@@ -894,7 +933,7 @@ OrderBook.prototype.notify = function(transaction) {
|
||||
_.each(affectedNodes, handleNode);
|
||||
|
||||
this.emit('transaction', transaction);
|
||||
this.emit('model', this._offers);
|
||||
this.notifyDirectOffersChanged();
|
||||
if (!takerGetsTotal.is_zero()) {
|
||||
this.emit('trade', takerPaysTotal, takerGetsTotal);
|
||||
}
|
||||
@@ -924,11 +963,14 @@ OrderBook.prototype.insertOffer = function(node) {
|
||||
// We're safe to calculate quality for newly created offers
|
||||
offer.quality = takerPays.divide(takerGets).to_text();
|
||||
|
||||
var quality = this.getOfferQuality(offer);
|
||||
var originalLength = this._offers.length;
|
||||
|
||||
for (var i = 0; i < originalLength; i++) {
|
||||
var existingOfferQuality = this.getOfferQuality(this._offers[i]);
|
||||
var quality = OrderBookUtils.getOfferQuality(offer, this._currencyGets);
|
||||
var existingOfferQuality = OrderBookUtils.getOfferQuality(
|
||||
this._offers[i],
|
||||
this._currencyGets
|
||||
);
|
||||
|
||||
if (quality.compareTo(existingOfferQuality) <= 0) {
|
||||
this._offers.splice(i, 0, offer);
|
||||
@@ -948,29 +990,6 @@ OrderBook.prototype.insertOffer = function(node) {
|
||||
this.emit('offer_added', offer);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve offer quality
|
||||
*
|
||||
* @param {Object} offer
|
||||
*/
|
||||
|
||||
OrderBook.prototype.getOfferQuality = function(offer) {
|
||||
var amount;
|
||||
|
||||
if (this._currencyGets.has_interest()) {
|
||||
// XXX Should use Amount#from_quality
|
||||
amount = Amount.from_json(
|
||||
offer.TakerPays
|
||||
).ratio_human(offer.TakerGets, {
|
||||
reference_date: new Date()
|
||||
});
|
||||
} else {
|
||||
amount = Amount.from_json(offer.quality + OrderBook.IOU_SUFFIX);
|
||||
}
|
||||
|
||||
return amount;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert any amount into default IOU
|
||||
*
|
||||
@@ -986,7 +1005,7 @@ OrderBook.prototype.normalizeAmount = function(currency, amountObj) {
|
||||
? amountObj
|
||||
: amountObj.value;
|
||||
|
||||
return Amount.from_json(value + OrderBook.IOU_SUFFIX);
|
||||
return OrderBookUtils.normalizeAmount(value);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1060,13 +1079,13 @@ OrderBook.prototype.deleteOffer = function(node, isOfferCancel) {
|
||||
*/
|
||||
|
||||
OrderBook.prototype.setOffers = function(offers) {
|
||||
assert(Array.isArray(offers), '');
|
||||
assert(Array.isArray(offers), 'Offers is not an array');
|
||||
|
||||
var self = this;
|
||||
|
||||
this.resetCache();
|
||||
|
||||
var newOffers = _.map(offers, function (rawOffer) {
|
||||
var newOffers = _.map(offers, function(rawOffer) {
|
||||
var offer = OrderBook.offerRewrite(rawOffer);
|
||||
|
||||
if (offer.hasOwnProperty('owner_funds')) {
|
||||
@@ -1176,4 +1195,46 @@ OrderBook.prototype.is_valid = function() {
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute autobridged offers for an IOU:IOU orderbook by merging offers from
|
||||
* IOU:XRP and XRP:IOU books
|
||||
*/
|
||||
|
||||
OrderBook.prototype.computeAutobridgedOffers = function() {
|
||||
assert(!this._currencyGets.is_native() && !this._currencyPays.is_native(),
|
||||
'Autobridging is only for IOU:IOU orderbooks');
|
||||
|
||||
var autobridgeCalculator = new AutobridgeCalculator(
|
||||
this._currencyGets,
|
||||
this._currencyPays,
|
||||
this._legOneBook.getOffersSync(),
|
||||
this._legTwoBook.getOffersSync()
|
||||
);
|
||||
|
||||
this._offersAutobridged = autobridgeCalculator.calculate();
|
||||
};
|
||||
|
||||
/**
|
||||
* Merge direct and autobridged offers into a combined orderbook
|
||||
*
|
||||
* @return [Array]
|
||||
*/
|
||||
|
||||
OrderBook.prototype.mergeDirectAndAutobridgedBooks = function() {
|
||||
var self = this;
|
||||
|
||||
this._mergedOffers = this._offers
|
||||
.concat(this._offersAutobridged)
|
||||
.sort(function(a, b) {
|
||||
var aQuality = OrderBookUtils.getOfferQuality(a, self._currencyGets);
|
||||
var bQuality = OrderBookUtils.getOfferQuality(b, self._currencyGets);
|
||||
|
||||
return aQuality.compareTo(bQuality);
|
||||
});
|
||||
|
||||
this.emit('model', this._mergedOffers);
|
||||
|
||||
return this._mergedOffers;
|
||||
};
|
||||
|
||||
exports.OrderBook = OrderBook;
|
||||
|
||||
106
src/js/ripple/orderbookutils.js
Normal file
106
src/js/ripple/orderbookutils.js
Normal file
@@ -0,0 +1,106 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var assert = require('assert');
|
||||
var SerializedObject = require('./serializedobject').SerializedObject;
|
||||
var Types = require('./serializedtypes');
|
||||
var Amount = require('./amount').Amount;
|
||||
|
||||
var IOU_SUFFIX = '/000/rrrrrrrrrrrrrrrrrrrrrhoLvTp';
|
||||
var OrderBookUtils = {};
|
||||
|
||||
function assertValidNumber(number, message) {
|
||||
assert(!_.isNull(number) && !isNaN(number), message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts and returns offer's taker gets funded amount as a default IOU amount
|
||||
*
|
||||
* @param {Object} offer
|
||||
* @return {Amount}
|
||||
*/
|
||||
|
||||
OrderBookUtils.getOfferTakerGetsFunded = function(offer) {
|
||||
assertValidNumber(offer.taker_gets_funded, 'Taker gets funded is invalid');
|
||||
|
||||
return Amount.from_json(offer.taker_gets_funded + IOU_SUFFIX);
|
||||
};
|
||||
|
||||
/**
|
||||
* Casts and returns offer's taker pays funded amount as a default IOU amount
|
||||
*
|
||||
* @param {Object} offer
|
||||
* @return {Amount}
|
||||
*/
|
||||
|
||||
OrderBookUtils.getOfferTakerPaysFunded = function(offer) {
|
||||
assertValidNumber(offer.taker_pays_funded, 'Taker gets funded is invalid');
|
||||
|
||||
return Amount.from_json(offer.taker_pays_funded + IOU_SUFFIX);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get offer taker gets amount
|
||||
*
|
||||
* @param {Object} offer
|
||||
*
|
||||
* @return {Amount}
|
||||
*/
|
||||
|
||||
OrderBookUtils.getOfferTakerGets = function(offer) {
|
||||
assert(typeof offer, 'object', 'Offer is invalid');
|
||||
|
||||
return Amount.from_json(offer.TakerGets + IOU_SUFFIX);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve offer quality
|
||||
*
|
||||
* @param {Object} offer
|
||||
* @param {Currency} currencyGets
|
||||
*/
|
||||
|
||||
OrderBookUtils.getOfferQuality = function(offer, currencyGets) {
|
||||
var amount;
|
||||
|
||||
if (currencyGets.has_interest()) {
|
||||
// XXX Should use Amount#from_quality
|
||||
amount = Amount.from_json(
|
||||
offer.TakerPays
|
||||
).ratio_human(offer.TakerGets, {
|
||||
reference_date: new Date()
|
||||
});
|
||||
} else {
|
||||
amount = Amount.from_json(offer.quality + IOU_SUFFIX);
|
||||
}
|
||||
|
||||
return amount;
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats an offer quality amount to a hex that can be parsed by
|
||||
* Amount.parse_quality
|
||||
*
|
||||
* @param {Amount} quality
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
|
||||
OrderBookUtils.convertOfferQualityToHex = function(quality) {
|
||||
assert(quality instanceof Amount, 'Quality is not an amount');
|
||||
|
||||
var so = new SerializedObject();
|
||||
Types.Quality.serialize(so, quality.to_text() + IOU_SUFFIX);
|
||||
|
||||
return so.to_hex();
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
OrderBookUtils.normalizeAmount = function(value) {
|
||||
return Amount.from_json(value + IOU_SUFFIX);
|
||||
};
|
||||
|
||||
module.exports = OrderBookUtils;
|
||||
@@ -90,7 +90,7 @@ function sort_fields(keys) {
|
||||
return keys.sort(sort_field_compare);
|
||||
}
|
||||
|
||||
SerializedType.serialize_varint = function (so, val) {
|
||||
SerializedType.serialize_varint = function(so, val) {
|
||||
if (val < 0) {
|
||||
throw new Error('Variable integers are unsigned.');
|
||||
}
|
||||
@@ -108,7 +108,7 @@ SerializedType.serialize_varint = function (so, val) {
|
||||
}
|
||||
};
|
||||
|
||||
SerializedType.prototype.parse_varint = function (so) {
|
||||
SerializedType.prototype.parse_varint = function(so) {
|
||||
var b1 = so.read(1)[0], b2, b3;
|
||||
var result;
|
||||
|
||||
@@ -180,10 +180,10 @@ function readAndSum(so, bytes) {
|
||||
}
|
||||
|
||||
var STInt8 = exports.Int8 = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
serialize: function(so, val) {
|
||||
so.append(convertIntegerToByteArray(val, 1));
|
||||
},
|
||||
parse: function (so) {
|
||||
parse: function(so) {
|
||||
return readAndSum(so, 1);
|
||||
}
|
||||
});
|
||||
@@ -274,10 +274,10 @@ function parse(so) {
|
||||
exports.parse = exports.parse_whatever = parse;
|
||||
|
||||
var STInt16 = exports.Int16 = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
serialize: function(so, val) {
|
||||
so.append(convertIntegerToByteArray(val, 2));
|
||||
},
|
||||
parse: function (so) {
|
||||
parse: function(so) {
|
||||
return readAndSum(so, 2);
|
||||
}
|
||||
});
|
||||
@@ -285,10 +285,10 @@ var STInt16 = exports.Int16 = new SerializedType({
|
||||
STInt16.id = 1;
|
||||
|
||||
var STInt32 = exports.Int32 = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
serialize: function(so, val) {
|
||||
so.append(convertIntegerToByteArray(val, 4));
|
||||
},
|
||||
parse: function (so) {
|
||||
parse: function(so) {
|
||||
return readAndSum(so, 4);
|
||||
}
|
||||
});
|
||||
@@ -296,7 +296,7 @@ var STInt32 = exports.Int32 = new SerializedType({
|
||||
STInt32.id = 2;
|
||||
|
||||
var STInt64 = exports.Int64 = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
serialize: function(so, val) {
|
||||
var bigNumObject;
|
||||
|
||||
if (isNumber(val)) {
|
||||
@@ -320,7 +320,7 @@ var STInt64 = exports.Int64 = new SerializedType({
|
||||
}
|
||||
serializeBits(so, bigNumObject.toBits(64), true); // noLength = true
|
||||
},
|
||||
parse: function (so) {
|
||||
parse: function(so) {
|
||||
var bytes = so.read(8);
|
||||
return SJCL_BN.fromBits(sjcl.codec.bytes.toBits(bytes));
|
||||
}
|
||||
@@ -329,14 +329,14 @@ var STInt64 = exports.Int64 = new SerializedType({
|
||||
STInt64.id = 3;
|
||||
|
||||
var STHash128 = exports.Hash128 = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
serialize: function(so, val) {
|
||||
var hash = UInt128.from_json(val);
|
||||
if (!hash.is_valid()) {
|
||||
throw new Error('Invalid Hash128');
|
||||
}
|
||||
serializeBits(so, hash.to_bits(), true); // noLength = true
|
||||
},
|
||||
parse: function (so) {
|
||||
parse: function(so) {
|
||||
return UInt128.from_bytes(so.read(16));
|
||||
}
|
||||
});
|
||||
@@ -344,14 +344,14 @@ var STHash128 = exports.Hash128 = new SerializedType({
|
||||
STHash128.id = 4;
|
||||
|
||||
var STHash256 = exports.Hash256 = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
serialize: function(so, val) {
|
||||
var hash = UInt256.from_json(val);
|
||||
if (!hash.is_valid()) {
|
||||
throw new Error('Invalid Hash256');
|
||||
}
|
||||
serializeBits(so, hash.to_bits(), true); // noLength = true
|
||||
},
|
||||
parse: function (so) {
|
||||
parse: function(so) {
|
||||
return UInt256.from_bytes(so.read(32));
|
||||
}
|
||||
});
|
||||
@@ -359,14 +359,14 @@ var STHash256 = exports.Hash256 = new SerializedType({
|
||||
STHash256.id = 5;
|
||||
|
||||
var STHash160 = exports.Hash160 = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
serialize: function(so, val) {
|
||||
var hash = UInt160.from_json(val);
|
||||
if (!hash.is_valid()) {
|
||||
throw new Error('Invalid Hash160');
|
||||
}
|
||||
serializeBits(so, hash.to_bits(), true); // noLength = true
|
||||
},
|
||||
parse: function (so) {
|
||||
parse: function(so) {
|
||||
return UInt160.from_bytes(so.read(20));
|
||||
}
|
||||
});
|
||||
@@ -375,7 +375,7 @@ STHash160.id = 17;
|
||||
|
||||
// Internal
|
||||
var STCurrency = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
serialize: function(so, val) {
|
||||
var currencyData = val.to_bytes();
|
||||
|
||||
if (!currencyData) {
|
||||
@@ -385,7 +385,7 @@ var STCurrency = new SerializedType({
|
||||
|
||||
so.append(currencyData);
|
||||
},
|
||||
parse: function (so) {
|
||||
parse: function(so) {
|
||||
var bytes = so.read(20);
|
||||
var currency = Currency.from_bytes(bytes);
|
||||
// XXX Disabled check. Theoretically, the Currency class should support any
|
||||
@@ -399,8 +399,51 @@ var STCurrency = new SerializedType({
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Quality is encoded into 64 bits:
|
||||
* (8 bits offset) (56 bits mantissa)
|
||||
*
|
||||
* Quality differs from Amount because it does not need the first two bits
|
||||
* to represent non-native and non-negative
|
||||
*/
|
||||
exports.Quality = new SerializedType({
|
||||
serialize: function(so, val) {
|
||||
var amount = Amount.from_json(val);
|
||||
|
||||
if (!amount.is_valid()) {
|
||||
throw new Error('Not a valid Amount object.');
|
||||
}
|
||||
|
||||
var hi = 0, lo = 0;
|
||||
var value = new BigNumber(amount.to_text());
|
||||
var offset = value.e - 15;
|
||||
|
||||
if (!amount.is_zero()) {
|
||||
// First eight bits: offset/exponent
|
||||
hi |= ((100 + offset) & 0xff) << 24;
|
||||
|
||||
// Remaining 56 bits: mantissa
|
||||
var mantissaDecimal = utils.getMantissaDecimalString(value.abs());
|
||||
var mantissaHex = (new BigNumber(mantissaDecimal)).toString(16);
|
||||
assert(mantissaHex.length <= 16,
|
||||
'Mantissa hex representation ' + mantissaHex +
|
||||
' exceeds the maximum length of 16');
|
||||
hi |= parseInt(mantissaHex.slice(0, -8), 16) & 0xffffff;
|
||||
lo = parseInt(mantissaHex.slice(-8), 16);
|
||||
}
|
||||
|
||||
var valueBytes = sjcl.codec.bytes.fromBits([hi, lo]);
|
||||
|
||||
so.append(valueBytes);
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Amount is encoded into 64 bits:
|
||||
* (1 bit non-native) (1 bit non-negative) (8 bits offset) (54 bits mantissa)
|
||||
*/
|
||||
var STAmount = exports.Amount = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
serialize: function(so, val) {
|
||||
var amount = Amount.from_json(val);
|
||||
|
||||
if (!amount.is_valid()) {
|
||||
@@ -477,7 +520,7 @@ var STAmount = exports.Amount = new SerializedType({
|
||||
so.append(amount.issuer().to_bytes());
|
||||
}
|
||||
},
|
||||
parse: function (so) {
|
||||
parse: function(so) {
|
||||
var value_bytes = so.read(8);
|
||||
var is_zero = !(value_bytes[0] & 0x7f);
|
||||
|
||||
@@ -519,14 +562,14 @@ var STAmount = exports.Amount = new SerializedType({
|
||||
STAmount.id = 6;
|
||||
|
||||
var STVL = exports.VariableLength = exports.VL = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
serialize: function(so, val) {
|
||||
if (typeof val === 'string') {
|
||||
serializeHex(so, val);
|
||||
} else {
|
||||
throw new Error('Unknown datatype.');
|
||||
}
|
||||
},
|
||||
parse: function (so) {
|
||||
parse: function(so) {
|
||||
var len = this.parse_varint(so);
|
||||
return convertByteArrayToHex(so.read(len));
|
||||
}
|
||||
@@ -535,14 +578,14 @@ var STVL = exports.VariableLength = exports.VL = new SerializedType({
|
||||
STVL.id = 7;
|
||||
|
||||
var STAccount = exports.Account = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
serialize: function(so, val) {
|
||||
var account = UInt160.from_json(val);
|
||||
if (!account.is_valid()) {
|
||||
throw new Error('Invalid account!');
|
||||
}
|
||||
serializeBits(so, account.to_bits());
|
||||
},
|
||||
parse: function (so) {
|
||||
parse: function(so) {
|
||||
var len = this.parse_varint(so);
|
||||
|
||||
if (len !== 20) {
|
||||
@@ -568,7 +611,7 @@ var STPathSet = exports.PathSet = new SerializedType({
|
||||
typeAccount: 0x01,
|
||||
typeCurrency: 0x10,
|
||||
typeIssuer: 0x20,
|
||||
serialize: function (so, val) {
|
||||
serialize: function(so, val) {
|
||||
for (var i = 0, l = val.length; i < l; i++) {
|
||||
// Boundary
|
||||
if (i) {
|
||||
@@ -609,7 +652,7 @@ var STPathSet = exports.PathSet = new SerializedType({
|
||||
|
||||
STInt8.serialize(so, this.typeEnd);
|
||||
},
|
||||
parse: function (so) {
|
||||
parse: function(so) {
|
||||
// should return a list of lists:
|
||||
/*
|
||||
[
|
||||
@@ -694,7 +737,7 @@ var STVector256 = exports.Vector256 = new SerializedType({
|
||||
STHash256.serialize(so, val[i]);
|
||||
}
|
||||
},
|
||||
parse: function (so) {
|
||||
parse: function(so) {
|
||||
var length = this.parse_varint(so);
|
||||
var output = [];
|
||||
// length is number of bytes not number of Hash256
|
||||
@@ -712,7 +755,7 @@ exports.STMemo = new SerializedType({
|
||||
serialize: function(so, val, no_marker) {
|
||||
var keys = [];
|
||||
|
||||
Object.keys(val).forEach(function (key) {
|
||||
Object.keys(val).forEach(function(key) {
|
||||
// Ignore lowercase field names - they're non-serializable fields by
|
||||
// convention.
|
||||
if (key[0] === key[0].toLowerCase()) {
|
||||
@@ -754,6 +797,7 @@ exports.STMemo = new SerializedType({
|
||||
output.parsed_memo_type = parsedType;
|
||||
}
|
||||
} catch (e) {
|
||||
// empty
|
||||
// we don't know what's in the binary, apparently it's not a UTF-8
|
||||
// string
|
||||
// this is fine, we won't add the parsed_memo_type field
|
||||
@@ -764,6 +808,7 @@ exports.STMemo = new SerializedType({
|
||||
try {
|
||||
output.parsed_memo_format = convertHexToString(output.MemoFormat);
|
||||
} catch (e) {
|
||||
// empty
|
||||
// we don't know what's in the binary, apparently it's not a UTF-8
|
||||
// string
|
||||
// this is fine, we won't add the parsed_memo_format field
|
||||
@@ -783,6 +828,7 @@ exports.STMemo = new SerializedType({
|
||||
output.parsed_memo_data = convertHexToString(output.MemoData);
|
||||
}
|
||||
} catch(e) {
|
||||
// empty
|
||||
// we'll fail in case the content does not match what the MemoFormat
|
||||
// described
|
||||
// this is fine, we won't add the parsed_memo_data, the user has to
|
||||
@@ -797,10 +843,10 @@ exports.STMemo = new SerializedType({
|
||||
});
|
||||
|
||||
var STObject = exports.Object = new SerializedType({
|
||||
serialize: function (so, val, no_marker) {
|
||||
serialize: function(so, val, no_marker) {
|
||||
var keys = [];
|
||||
|
||||
Object.keys(val).forEach(function (key) {
|
||||
Object.keys(val).forEach(function(key) {
|
||||
// Ignore lowercase field names - they're non-serializable fields by
|
||||
// convention.
|
||||
if (key[0] === key[0].toLowerCase()) {
|
||||
@@ -827,7 +873,7 @@ var STObject = exports.Object = new SerializedType({
|
||||
}
|
||||
},
|
||||
|
||||
parse: function (so) {
|
||||
parse: function(so) {
|
||||
var output = {};
|
||||
while (so.peek(1)[0] !== 0xe1) {
|
||||
var keyval = parse(so);
|
||||
@@ -841,7 +887,7 @@ var STObject = exports.Object = new SerializedType({
|
||||
STObject.id = 14;
|
||||
|
||||
var STArray = exports.Array = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
serialize: function(so, val) {
|
||||
for (var i = 0, l = val.length; i < l; i++) {
|
||||
var keys = Object.keys(val[i]);
|
||||
|
||||
@@ -859,7 +905,7 @@ var STArray = exports.Array = new SerializedType({
|
||||
STInt8.serialize(so, 0xf1);
|
||||
},
|
||||
|
||||
parse: function (so) {
|
||||
parse: function(so) {
|
||||
var output = [ ];
|
||||
|
||||
while (so.peek(1)[0] !== 0xf1) {
|
||||
|
||||
120
test/fixtures/orderbook.js
vendored
120
test/fixtures/orderbook.js
vendored
@@ -24,7 +24,7 @@ module.exports.OTHER_LEDGER_INDEX = 'D3338DA77BA23122FB5647B74B53636AB54BE246D4B
|
||||
|
||||
module.exports.TRANSFER_RATE = 1002000000;
|
||||
|
||||
module.exports.fiatOffers = function (options) {
|
||||
module.exports.fiatOffers = function(options) {
|
||||
options = options || {};
|
||||
_.defaults(options, {
|
||||
account_funds: '318.3643710638508',
|
||||
@@ -156,12 +156,12 @@ module.exports.NATIVE_OFFERS = [
|
||||
PreviousTxnID: 'CD77500EF28984BFC123E8A257C10E44FF486EA8FC43E1356C42BD6DB853A602',
|
||||
PreviousTxnLgrSeq: 8265523,
|
||||
Sequence: 1139002,
|
||||
TakerGets: {
|
||||
TakerGets: '972251352',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '4.9656112525'
|
||||
},
|
||||
TakerPays: '972251352',
|
||||
index: 'D3338DA77BA23122FB5647B74B53636AB54BE246D4B21707C9D6887DEB334252',
|
||||
owner_funds: '235.0194163432668',
|
||||
quality: '195796912.5171664'
|
||||
@@ -403,7 +403,119 @@ module.exports.DECIMAL_TAKER_PAYS_FUNDED_OFFERS = [
|
||||
}
|
||||
];
|
||||
|
||||
module.exports.bookOffersResponse = function (options) {
|
||||
module.exports.LEG_ONE_OFFERS = [
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
BookDirectory: 'DFA3B6DDAB58C7E8E5D944E736DA4B7046C30E4F460FD9DE4D043654A0DBD245',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000078',
|
||||
PreviousTxnID: '27723DCE3E6DB324DBCE9F0C9110352DBBC04DD6BEFE2A57C4E524FD215144C9',
|
||||
PreviousTxnLgrSeq: 12024847,
|
||||
Sequence: 14532890,
|
||||
TakerGets: '31461561812',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '373.019921005'
|
||||
},
|
||||
index: '7EEE980B0BD43C15504B9A89164D29EF02DBBD3807DA7936F51EA2CE3D0C6324',
|
||||
owner_funds: '210586312936',
|
||||
quality: '0.00000001185637010756165'
|
||||
},
|
||||
{
|
||||
Account: addresses.OTHER_ACCOUNT,
|
||||
BookDirectory: 'DFA3B6DDAB58C7E8E5D944E736DA4B7046C30E4F460FD9DE4D043676B9DEA2FC',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000002',
|
||||
PreviousTxnID: '1B36F7DE44C96FBDB50F8F80D24D3FA11454CB837BA4E4D667C92E01AE9225F5',
|
||||
PreviousTxnLgrSeq: 12024788,
|
||||
Sequence: 244399,
|
||||
TakerGets: '25299728855',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '300'
|
||||
},
|
||||
index: '5F8BDA3343CB792FA0DD55740F5827C5E050A287C96FDE4F7DFF548693420744',
|
||||
owner_funds: '1291056089559',
|
||||
quality: '0.00000001185783459259132'
|
||||
},
|
||||
{
|
||||
Account: addresses.THIRD_ACCOUNT,
|
||||
BookDirectory: 'DFA3B6DDAB58C7E8E5D944E736DA4B7046C30E4F460FD9DE4D0437FF40E6F02A',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 478636633,
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000165',
|
||||
PreviousTxnID: 'D42D81273BDC3ED611ED84DF07EA55E31703F4E05BC70CC12871715FCB58E160',
|
||||
PreviousTxnLgrSeq: 12024847,
|
||||
Sequence: 3858033,
|
||||
TakerGets: '18189943147',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '216'
|
||||
},
|
||||
index: 'FD5E66163DFE67919E64F31D506A8F3E94802E6A0FFEBE7A6FD40A2F1135EDD4',
|
||||
owner_funds: '490342145233',
|
||||
quality: '0.0000000118746935190737'
|
||||
}
|
||||
];
|
||||
|
||||
module.exports.LEG_TWO_OFFERS = [
|
||||
{
|
||||
Account: addresses.FOURTH_ACCOUNT,
|
||||
BookDirectory: 'DA36FDE1B8CE294B214BE4E4C958DAAF9C1F46DE1FCB44115D0A4929E095B160',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000003',
|
||||
PreviousTxnID: '97A8D6B2135231363EC1B3B509DF052D481A0045684464948E6DF2C2B9FC1E64',
|
||||
PreviousTxnLgrSeq: 12004045,
|
||||
Sequence: 384,
|
||||
TakerGets: {
|
||||
currency: 'EUR',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '17.07639524223001'
|
||||
},
|
||||
TakerPays: '4943947661',
|
||||
index: '5B00ACF35041983F070EAE2219C274D24A11D6FD6FE4306A4C72E7B769D4F914',
|
||||
owner_funds: '36.40299530003982',
|
||||
quality: '289519397.75'
|
||||
},
|
||||
{
|
||||
Account: addresses.FOURTH_ACCOUNT,
|
||||
BookDirectory: 'DA36FDE1B8CE294B214BE4E4C958DAAF9C1F46DE1FCB44115E12B2D070B5DBE0',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000006',
|
||||
PreviousTxnID: '425EBA467DD335602BAFBAB5329B1E7FC1ABB325AA5CD4495A5085860D09F2BE',
|
||||
PreviousTxnLgrSeq: 11802828,
|
||||
Sequence: 605,
|
||||
TakerGets: {
|
||||
currency: 'EUR',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '19.99999999954904'
|
||||
},
|
||||
TakerPays: '105263157889',
|
||||
index: '8715E674302D446EBD520FF11B48A0F64822F4F9266D62544987223CA16EDBB1',
|
||||
quality: '5263157894.7',
|
||||
taker_gets_funded: {
|
||||
currency: 'EUR',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '19.25393938854825'
|
||||
},
|
||||
taker_pays_funded: '101336523096'
|
||||
}
|
||||
];
|
||||
|
||||
module.exports.bookOffersResponse = function(options) {
|
||||
options = options || {};
|
||||
_.defaults(options, {
|
||||
account_funds: '2010.027702881682',
|
||||
|
||||
753
test/orderbook-autobridge-test.js
Normal file
753
test/orderbook-autobridge-test.js
Normal file
@@ -0,0 +1,753 @@
|
||||
/*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');
|
||||
|
||||
describe('OrderBook Autobridging', function() {
|
||||
this.timeout(0);
|
||||
|
||||
it('Initialize IOU/IOU', function() {
|
||||
var book = new Remote().createOrderBook({
|
||||
currency_gets: 'EUR',
|
||||
issuer_gets: addresses.ISSUER,
|
||||
currency_pays: 'USD',
|
||||
issuer_pays: addresses.ISSUER
|
||||
});
|
||||
|
||||
assert.deepEqual(book._legOneBook._currencyGets.to_hex(), Currency.from_json('XRP').to_hex());
|
||||
assert.deepEqual(book._legOneBook._currencyPays.to_hex(), Currency.from_json('USD').to_hex());
|
||||
assert.deepEqual(book._legTwoBook._currencyGets.to_hex(), Currency.from_json('EUR').to_hex());
|
||||
assert.deepEqual(book._legTwoBook._currencyPays.to_hex(), Currency.from_json('XRP').to_hex());
|
||||
});
|
||||
|
||||
it('Compute autobridged offers', function() {
|
||||
var book = new Remote().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;
|
||||
|
||||
var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1));
|
||||
var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1));
|
||||
|
||||
book._legOneBook.setOffers(legOneOffers);
|
||||
book._legTwoBook.setOffers(legTwoOffers);
|
||||
|
||||
book.computeAutobridgedOffers();
|
||||
|
||||
assert.strictEqual(book._offersAutobridged.length, 1);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '17.07639524223001');
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '58.61727326122974');
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[0].taker_gets_funded, '17.07639524223001');
|
||||
assert.strictEqual(book._offersAutobridged[0].taker_pays_funded, '58.61727326122974');
|
||||
|
||||
assert(book._offersAutobridged[0].autobridged);
|
||||
});
|
||||
|
||||
it('Compute autobridged offers - leg one partially funded', function() {
|
||||
var book = new Remote().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;
|
||||
|
||||
var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1));
|
||||
var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1));
|
||||
|
||||
legOneOffers[0].owner_funds = '2105863129';
|
||||
|
||||
book._legOneBook.setOffers(legOneOffers);
|
||||
book._legTwoBook.setOffers(legTwoOffers);
|
||||
|
||||
book.computeAutobridgedOffers();
|
||||
|
||||
assert.strictEqual(book._offersAutobridged.length, 1);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '7.273651248813431');
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '24.96789265329184');
|
||||
|
||||
assert(book._offersAutobridged[0].autobridged);
|
||||
});
|
||||
|
||||
it('Compute autobridged offers - leg two partially funded', function() {
|
||||
var book = new Remote().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;
|
||||
|
||||
var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1));
|
||||
var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1));
|
||||
|
||||
legTwoOffers[0].owner_funds = '10';
|
||||
|
||||
book._legOneBook.setOffers(legOneOffers);
|
||||
book._legTwoBook.setOffers(legTwoOffers);
|
||||
|
||||
book.computeAutobridgedOffers();
|
||||
|
||||
assert.strictEqual(book._offersAutobridged.length, 1);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '10');
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '34.32649132449533');
|
||||
|
||||
assert(book._offersAutobridged[0].autobridged);
|
||||
});
|
||||
|
||||
it('Compute autobridged offers - leg two transfer rate', function() {
|
||||
var book = new Remote().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;
|
||||
|
||||
var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1));
|
||||
var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1));
|
||||
|
||||
legTwoOffers[0].owner_funds = '10';
|
||||
|
||||
book._legOneBook.setOffers(legOneOffers);
|
||||
book._legTwoBook.setOffers(legTwoOffers);
|
||||
|
||||
book.computeAutobridgedOffers();
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '9.980039920159681');
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '34.25797537722665');
|
||||
|
||||
assert(book._offersAutobridged[0].autobridged);
|
||||
});
|
||||
|
||||
it('Compute autobridged offers - taker funds < leg two in', function() {
|
||||
var book = new Remote().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;
|
||||
|
||||
var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1));
|
||||
var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1));
|
||||
|
||||
legOneOffers[0].owner_funds = '33461561812';
|
||||
|
||||
legTwoOffers[0].owner_funds = '360';
|
||||
legTwoOffers[0].TakerGets.value = '170.7639524223001';
|
||||
legTwoOffers[0].TakerPays = '49439476610';
|
||||
|
||||
book._legOneBook.setOffers(legOneOffers);
|
||||
book._legTwoBook.setOffers(legTwoOffers);
|
||||
|
||||
book.computeAutobridgedOffers();
|
||||
|
||||
assert.strictEqual(book._offersAutobridged.length, 1);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '108.6682345172846');
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '373.019921005');
|
||||
|
||||
assert(book._offersAutobridged[0].autobridged);
|
||||
});
|
||||
|
||||
it('Compute autobridged offers - leg one partially funded - owners equal', function() {
|
||||
var book = new Remote().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;
|
||||
|
||||
var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1));
|
||||
var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1));
|
||||
|
||||
legOneOffers[0].owner_funds = '2105863129';
|
||||
|
||||
legTwoOffers[0].Account = legOneOffers[0].Account;
|
||||
|
||||
book._legOneBook.setOffers(legOneOffers);
|
||||
book._legTwoBook.setOffers(legTwoOffers);
|
||||
|
||||
book.computeAutobridgedOffers();
|
||||
|
||||
assert.strictEqual(book._offersAutobridged.length, 1);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '17.07639524223001');
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '58.61727326122974');
|
||||
|
||||
assert(book._offersAutobridged[0].autobridged);
|
||||
});
|
||||
|
||||
it('Compute autobridged offers - leg one partially funded - owners equal - leg two in > leg one out', function() {
|
||||
var book = new Remote().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;
|
||||
|
||||
var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1));
|
||||
var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1));
|
||||
|
||||
legOneOffers[0].owner_funds = '2105863129';
|
||||
|
||||
legTwoOffers[0].Account = legOneOffers[0].Account;
|
||||
legTwoOffers[0].owner_funds = '360';
|
||||
legTwoOffers[0].TakerGets.value = '170.7639524223001';
|
||||
legTwoOffers[0].TakerPays = '49439476610';
|
||||
|
||||
book._legOneBook.setOffers(legOneOffers);
|
||||
book._legTwoBook.setOffers(legTwoOffers);
|
||||
|
||||
book.computeAutobridgedOffers();
|
||||
|
||||
assert.strictEqual(book._offersAutobridged.length, 1);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '108.6682345172846');
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '373.0199210049999');
|
||||
|
||||
assert(book._offersAutobridged[0].autobridged);
|
||||
});
|
||||
|
||||
it('Compute autobridged offers - leg one consumes leg two fully', function() {
|
||||
var book = new Remote().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;
|
||||
|
||||
var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1));
|
||||
var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 2));
|
||||
|
||||
book._legOneBook.setOffers(legOneOffers);
|
||||
book._legTwoBook.setOffers(legTwoOffers);
|
||||
|
||||
book.computeAutobridgedOffers();
|
||||
|
||||
assert.strictEqual(book._offersAutobridged.length, 2);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '17.07639524223001');
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '58.61727326122974');
|
||||
|
||||
assert(book._offersAutobridged[0].autobridged);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '5.038346688725268');
|
||||
assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '314.4026477437702');
|
||||
|
||||
assert(book._offersAutobridged[1].autobridged);
|
||||
});
|
||||
|
||||
it('Compute autobridged offers - leg two consumes first leg one offer fully', function() {
|
||||
var book = new Remote().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;
|
||||
|
||||
var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 2));
|
||||
var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 1));
|
||||
|
||||
legTwoOffers[0].TakerGets.value = '170.7639524223001';
|
||||
legTwoOffers[0].TakerPays = '49439476610';
|
||||
legTwoOffers[0].owner_funds = '364.0299530003982';
|
||||
|
||||
book._legOneBook.setOffers(legOneOffers);
|
||||
book._legTwoBook.setOffers(legTwoOffers);
|
||||
|
||||
book.computeAutobridgedOffers();
|
||||
|
||||
assert.strictEqual(book._offersAutobridged.length, 2);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '108.6682345172846');
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '373.019921005');
|
||||
|
||||
assert(book._offersAutobridged[0].autobridged);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '62.0957179050155');
|
||||
assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '213.1791399943838');
|
||||
|
||||
assert(book._offersAutobridged[1].autobridged);
|
||||
});
|
||||
|
||||
it('Compute autobridged offers - owners equal', function() {
|
||||
var book = new Remote().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;
|
||||
|
||||
var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1));
|
||||
var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 2));
|
||||
|
||||
legOneOffers[0].owner_funds = '2105863129';
|
||||
legTwoOffers[1].owner_funds = '19.32660005780981';
|
||||
|
||||
legTwoOffers[0].Account = legOneOffers[0].Account;
|
||||
|
||||
book._legOneBook.setOffers(legOneOffers);
|
||||
book._legTwoBook.setOffers(legTwoOffers);
|
||||
|
||||
book.computeAutobridgedOffers();
|
||||
|
||||
assert.strictEqual(book._offersAutobridged.length, 2);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '17.07639524223001');
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '58.61727326122974');
|
||||
|
||||
assert(book._offersAutobridged[0].autobridged);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '0.4001139945128008');
|
||||
assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '24.96789265329184');
|
||||
|
||||
assert(book._offersAutobridged[1].autobridged);
|
||||
});
|
||||
|
||||
it('Compute autobridged offers - owners equal - leg one overfunded', function() {
|
||||
var book = new Remote().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;
|
||||
|
||||
var legOneOffers = _.cloneDeep(fixtures.LEG_ONE_OFFERS.slice(0, 1));
|
||||
var legTwoOffers = _.cloneDeep(fixtures.LEG_TWO_OFFERS.slice(0, 2));
|
||||
|
||||
legOneOffers[0].owner_funds = '41461561812';
|
||||
|
||||
legTwoOffers[0].Account = legOneOffers[0].Account;
|
||||
|
||||
legTwoOffers[1].owner_funds = '30';
|
||||
|
||||
book._legOneBook.setOffers(legOneOffers);
|
||||
book._legTwoBook.setOffers(legTwoOffers);
|
||||
|
||||
book.computeAutobridgedOffers();
|
||||
|
||||
assert.strictEqual(book._offersAutobridged.length, 2);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '17.07639524223001');
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '58.61727326122974');
|
||||
|
||||
assert(book._offersAutobridged[0].autobridged);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '5.038346688725268');
|
||||
assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '314.4026477437702');
|
||||
|
||||
assert(book._offersAutobridged[1].autobridged);
|
||||
});
|
||||
|
||||
it('Compute autobridged offers - TakerPays < Quality * TakerGets', function() {
|
||||
var book = new Remote().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._legOneBook.setOffers([
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
TakerGets: '75',
|
||||
TakerPays: {
|
||||
value: '50',
|
||||
issuer: addresses.ISSUER,
|
||||
currency: 'USD'
|
||||
},
|
||||
owner_funds: '50',
|
||||
quality: '1'
|
||||
}
|
||||
]);
|
||||
|
||||
book._legTwoBook.setOffers([
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
TakerGets: {
|
||||
value: '90',
|
||||
issuer: addresses.ISSUER,
|
||||
currency: 'EUR'
|
||||
},
|
||||
TakerPays: '90',
|
||||
owner_funds: '150',
|
||||
quality: '1'
|
||||
}
|
||||
]);
|
||||
|
||||
book.computeAutobridgedOffers();
|
||||
|
||||
assert.strictEqual(book._offersAutobridged.length, 1);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '75');
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '75');
|
||||
|
||||
assert(book._offersAutobridged[0].autobridged);
|
||||
});
|
||||
|
||||
it('Compute autobridged offers - update funded amount', function() {
|
||||
var book = new Remote().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._legOneBook.setOffers([
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
TakerGets: '100',
|
||||
TakerPays: {
|
||||
value: '100',
|
||||
issuer: addresses.ISSUER,
|
||||
currency: 'USD'
|
||||
},
|
||||
owner_funds: '50',
|
||||
quality: '1'
|
||||
},
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
TakerGets: '50',
|
||||
TakerPays: {
|
||||
value: '100',
|
||||
issuer: addresses.ISSUER,
|
||||
currency: 'USD'
|
||||
},
|
||||
quality: '2'
|
||||
}
|
||||
]);
|
||||
|
||||
book._legTwoBook.setOffers([
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
TakerGets: {
|
||||
value: '90',
|
||||
issuer: addresses.ISSUER,
|
||||
currency: 'EUR'
|
||||
},
|
||||
TakerPays: '90',
|
||||
owner_funds: '150',
|
||||
quality: '1'
|
||||
},
|
||||
{
|
||||
Account: addresses.OTHER_ACCOUNT,
|
||||
TakerGets: {
|
||||
value: '30',
|
||||
issuer: addresses.ISSUER,
|
||||
currency: 'EUR'
|
||||
},
|
||||
TakerPays: '60',
|
||||
owner_funds: '70',
|
||||
quality: '2'
|
||||
}
|
||||
]);
|
||||
|
||||
book.computeAutobridgedOffers();
|
||||
|
||||
assert.strictEqual(book._offersAutobridged.length, 3);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '90');
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '90');
|
||||
|
||||
assert(book._offersAutobridged[0].autobridged);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '5');
|
||||
assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '10');
|
||||
|
||||
assert(book._offersAutobridged[1].autobridged);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[2].TakerGets.value, '20');
|
||||
assert.strictEqual(book._offersAutobridged[2].TakerPays.value, '80');
|
||||
|
||||
assert(book._offersAutobridged[2].autobridged);
|
||||
});
|
||||
|
||||
it('Compute autobridged offers - update funded amount - owners equal', function() {
|
||||
var book = new Remote().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._legOneBook.setOffers([
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
TakerGets: '100',
|
||||
TakerPays: {
|
||||
value: '100',
|
||||
issuer: addresses.ISSUER,
|
||||
currency: 'USD'
|
||||
},
|
||||
owner_funds: '50',
|
||||
quality: '1'
|
||||
},
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
TakerGets: '20',
|
||||
TakerPays: {
|
||||
value: '100',
|
||||
issuer: addresses.ISSUER,
|
||||
currency: 'USD'
|
||||
},
|
||||
quality: '5'
|
||||
}
|
||||
]);
|
||||
|
||||
book._legTwoBook.setOffers([
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
TakerGets: {
|
||||
value: '90',
|
||||
issuer: addresses.ISSUER,
|
||||
currency: 'EUR'
|
||||
},
|
||||
TakerPays: '90',
|
||||
owner_funds: '150',
|
||||
quality: '1'
|
||||
},
|
||||
{
|
||||
Account: addresses.OTHER_ACCOUNT,
|
||||
TakerGets: {
|
||||
value: '30',
|
||||
issuer: addresses.ISSUER,
|
||||
currency: 'EUR'
|
||||
},
|
||||
TakerPays: '60',
|
||||
owner_funds: '70',
|
||||
quality: '2'
|
||||
}
|
||||
]);
|
||||
|
||||
book.computeAutobridgedOffers();
|
||||
|
||||
assert.strictEqual(book._offersAutobridged.length, 3);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '90');
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '90');
|
||||
|
||||
assert(book._offersAutobridged[0].autobridged);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '5');
|
||||
assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '10');
|
||||
|
||||
assert(book._offersAutobridged[1].autobridged);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[2].TakerGets.value, '10');
|
||||
assert.strictEqual(book._offersAutobridged[2].TakerPays.value, '100');
|
||||
|
||||
assert(book._offersAutobridged[2].autobridged);
|
||||
});
|
||||
|
||||
it('Compute autobridged offers - update funded amount - first two owners equal', function() {
|
||||
var book = new Remote().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._legOneBook.setOffers([
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
TakerGets: '100',
|
||||
TakerPays: {
|
||||
value: '100',
|
||||
issuer: addresses.ISSUER,
|
||||
currency: 'USD'
|
||||
},
|
||||
owner_funds: '50',
|
||||
quality: '1'
|
||||
},
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
TakerGets: '100',
|
||||
TakerPays: {
|
||||
value: '200',
|
||||
issuer: addresses.ISSUER,
|
||||
currency: 'USD'
|
||||
},
|
||||
quality: '2'
|
||||
}
|
||||
]);
|
||||
|
||||
book._legTwoBook.setOffers([
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
TakerGets: {
|
||||
value: '90',
|
||||
issuer: addresses.ISSUER,
|
||||
currency: 'EUR'
|
||||
},
|
||||
TakerPays: '90',
|
||||
owner_funds: '150',
|
||||
quality: '1'
|
||||
},
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
TakerGets: {
|
||||
value: '30',
|
||||
issuer: addresses.ISSUER,
|
||||
currency: 'EUR'
|
||||
},
|
||||
TakerPays: '60',
|
||||
quality: '2'
|
||||
},
|
||||
{
|
||||
Account: addresses.OTHER_ACCOUNT,
|
||||
TakerGets: {
|
||||
value: '20',
|
||||
issuer: addresses.ISSUER,
|
||||
currency: 'EUR'
|
||||
},
|
||||
TakerPays: '40',
|
||||
owner_funds: '70',
|
||||
quality: '2'
|
||||
}
|
||||
]);
|
||||
|
||||
book.computeAutobridgedOffers();
|
||||
|
||||
assert.strictEqual(book._offersAutobridged.length, 4);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '90');
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '90');
|
||||
|
||||
assert(book._offersAutobridged[0].autobridged);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[1].TakerGets.value, '5');
|
||||
assert.strictEqual(book._offersAutobridged[1].TakerPays.value, '10');
|
||||
|
||||
assert(book._offersAutobridged[1].autobridged);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[2].TakerGets.value, '25');
|
||||
assert.strictEqual(book._offersAutobridged[2].TakerPays.value, '100');
|
||||
|
||||
assert(book._offersAutobridged[2].autobridged);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[3].TakerGets.value, '20');
|
||||
assert.strictEqual(book._offersAutobridged[3].TakerPays.value, '80');
|
||||
|
||||
assert(book._offersAutobridged[3].autobridged);
|
||||
});
|
||||
|
||||
it('Compute autobridged offers - unfunded offer - owners equal', function() {
|
||||
var book = new Remote().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._legOneBook.setOffers([
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
TakerGets: '75',
|
||||
TakerPays: {
|
||||
value: '75',
|
||||
issuer: addresses.ISSUER,
|
||||
currency: 'USD'
|
||||
},
|
||||
owner_funds: '0',
|
||||
quality: '1'
|
||||
}
|
||||
]);
|
||||
|
||||
book._legTwoBook.setOffers([
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
TakerGets: {
|
||||
value: '90',
|
||||
issuer: addresses.ISSUER,
|
||||
currency: 'EUR'
|
||||
},
|
||||
TakerPays: '90',
|
||||
owner_funds: '150',
|
||||
quality: '1'
|
||||
}
|
||||
]);
|
||||
|
||||
book.computeAutobridgedOffers();
|
||||
|
||||
assert.strictEqual(book._offersAutobridged.length, 1);
|
||||
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerGets.value, '75');
|
||||
assert.strictEqual(book._offersAutobridged[0].TakerPays.value, '75');
|
||||
|
||||
assert(book._offersAutobridged[0].autobridged);
|
||||
});
|
||||
});
|
||||
@@ -2119,7 +2119,7 @@ describe('OrderBook', function() {
|
||||
assert.strictEqual(book._offers[2].taker_pays_funded, '101533965');
|
||||
});
|
||||
|
||||
it('Insert offer - worst quality - insufficient funds for all orders', function () {
|
||||
it('Insert offer - worst quality - insufficient funds for all orders', function() {
|
||||
var remote = new Remote();
|
||||
var book = remote.createOrderBook({
|
||||
currency_gets: 'USD',
|
||||
@@ -2193,159 +2193,6 @@ describe('OrderBook', function() {
|
||||
assert.strictEqual(book._offers[2].taker_pays_funded, '0');
|
||||
});
|
||||
|
||||
it('Request offers', function(done) {
|
||||
var remote = new Remote();
|
||||
|
||||
var offers = {
|
||||
offers: fixtures.REQUEST_OFFERS
|
||||
};
|
||||
|
||||
remote.request = function(request) {
|
||||
switch (request.message.command) {
|
||||
case 'book_offers':
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'book_offers',
|
||||
id: undefined,
|
||||
taker_gets: {
|
||||
currency: '0000000000000000000000004254430000000000',
|
||||
issuer: addresses.ISSUER
|
||||
},
|
||||
taker_pays: {
|
||||
currency: '0000000000000000000000005553440000000000',
|
||||
issuer: addresses.ISSUER
|
||||
},
|
||||
taker: 'rrrrrrrrrrrrrrrrrrrrBZbvji'
|
||||
});
|
||||
|
||||
setImmediate(function() {
|
||||
request.emit('success', offers);
|
||||
});
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
var book = remote.createOrderBook({
|
||||
currency_gets: 'BTC',
|
||||
issuer_gets: addresses.ISSUER,
|
||||
currency_pays: 'USD',
|
||||
issuer_pays: addresses.ISSUER
|
||||
});
|
||||
|
||||
book._issuerTransferRate = 1002000000;
|
||||
|
||||
var expected = [
|
||||
{
|
||||
Account: addresses.ACCOUNT,
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711A3A4254F5000',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 131072,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000000',
|
||||
Sequence: 195,
|
||||
TakerGets: {
|
||||
currency: 'BTC',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '0.1129232560043778'
|
||||
},
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '56.06639660617357'
|
||||
},
|
||||
index: 'B6BC3B0F87976370EE11F5575593FE63AA5DC1D602830DC96F04B2D597F044BF',
|
||||
owner_funds: '0.1129267125000245',
|
||||
taker_gets_funded: '0.112701309880264',
|
||||
taker_pays_funded: '55.95620035555106',
|
||||
is_fully_funded: false,
|
||||
quality: '496.4999999999999'
|
||||
},
|
||||
{
|
||||
Account: addresses.OTHER_ACCOUNT,
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 461498565,
|
||||
Flags: 131072,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000144',
|
||||
Sequence: 29354,
|
||||
TakerGets: {
|
||||
currency: 'BTC',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '0.2'
|
||||
},
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '99.72233516476456'
|
||||
},
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
owner_funds: '0.950363009783092',
|
||||
is_fully_funded: true,
|
||||
taker_gets_funded: '0.2',
|
||||
taker_pays_funded: '99.72233516476456',
|
||||
quality: '498.6116758238228'
|
||||
},
|
||||
{
|
||||
Account: addresses.THIRD_ACCOUNT,
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 461498565,
|
||||
Flags: 131072,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000144',
|
||||
Sequence: 29356,
|
||||
TakerGets: {
|
||||
currency: 'BTC',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '0.5'
|
||||
},
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '99.72233516476456'
|
||||
},
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
owner_funds: '0.950363009783092',
|
||||
is_fully_funded: true,
|
||||
taker_gets_funded: '0.5',
|
||||
taker_pays_funded: '99.72233516476456',
|
||||
quality: '498.6116758238228'
|
||||
},
|
||||
{
|
||||
Account: addresses.THIRD_ACCOUNT,
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 461498565,
|
||||
Flags: 131078,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000144',
|
||||
Sequence: 29354,
|
||||
TakerGets: {
|
||||
currency: 'BTC',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '0.5'
|
||||
},
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: addresses.ISSUER,
|
||||
value: '99.72233516476456'
|
||||
},
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
owner_funds: '0.950363009783092',
|
||||
is_fully_funded: false,
|
||||
taker_gets_funded: '0.4484660776278363',
|
||||
taker_pays_funded: '89.44416900646082',
|
||||
quality: '199.4446703295291'
|
||||
}
|
||||
];
|
||||
|
||||
book.on('model', function(model) {
|
||||
assert.deepEqual(model, expected);
|
||||
assert.strictEqual(book._synchronized, true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Request offers - native currency', function(done) {
|
||||
var remote = new Remote();
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user