Convert getOrderBook and add unit test

This commit is contained in:
Chris Clark
2015-06-25 16:34:03 -07:00
parent 6a763fab18
commit 3e0f43e44e
17 changed files with 1736 additions and 229 deletions

View File

@@ -11,7 +11,7 @@ const getTrustlines = require('./ledger/trustlines');
const getBalances = require('./ledger/balances');
// const getPathFind = require('./ledger/pathfind');
const getOrders = require('./ledger/orders');
// const getOrderBook = require('./ledger/orderbook');
const getOrderBook = require('./ledger/orderbook');
const getSettings = require('./ledger/settings');
const preparePayment = require('./transaction/payment');
const prepareTrustline = require('./transaction/trustline');
@@ -39,7 +39,7 @@ RippleAPI.prototype = {
getBalances,
// getPathFind,
getOrders,
// getOrderBook,
getOrderBook,
getSettings,
preparePayment,

View File

@@ -40,4 +40,4 @@ function getBalances(account, options, callback) {
], composeAsync(formatBalances, callback));
}
module.exports = getBalances;
module.exports = utils.wrapCatch(getBalances);

View File

@@ -1,171 +1,54 @@
'use strict';
const _ = require('lodash');
const async = require('async');
const utils = require('./utils');
const ripple = utils.common.core;
const parseOrderbookOrder = require('./parse/orderbook-order');
const validate = utils.common.validate;
const bignum = require('bignumber.js');
const composeAsync = utils.common.composeAsync;
// account is to specify a "perspective", which affects which unfunded offers
// are returned
function getBookOffers(remote, account, ledgerVersion, limit,
takerGets, takerPays, callback) {
remote.requestBookOffers({
taker_gets: takerGets,
taker_pays: takerPays,
ledger: ledgerVersion || 'validated',
limit: limit,
taker: account
}, composeAsync((data) => data.offers.map(parseOrderbookOrder), callback));
}
function isSameIssue(a, b) {
return a.currency === b.currency && a.counterparty === b.counterparty;
}
function orderFilter(issue, direction, order) {
return isSameIssue(issue, order.specification.quantity)
&& order.specification.direction === direction;
}
function formatBidsAndAsks(orderbook, orders) {
// the "base" currency is the currency that you are buying or selling
// the "counter" is the currency that the "base" is priced in
// a "bid"/"ask" is an order to buy/sell the base, respectively
const bids = orders.filter(_.partial(orderFilter, orderbook.base, 'buy'));
const asks = orders.filter(_.partial(orderFilter, orderbook.base, 'sell'));
return {bids, asks};
}
/**
* Get the most recent spapshot of the order book for a currency pair
*
* @url
* @param {RippleAddress} request.params.account
* - The ripple address to use as point-of-view
* (returns unfunded orders for this account)
* @param {String ISO 4217 Currency Code + RippleAddress} request.params.base
* - Base currency as currency+issuer
* @param {String ISO 4217 Currency Code + RippleAddress}
* request.params.counter - Counter currency as currency+issuer
*
* @query
* @param {String} [request.query.limit]
* - Set a limit to the number of results returned
*
* @param {Express.js Request} request
*/
function getOrderBook(account, orderbook, options, callback) {
const self = this;
validate.address(account);
validate.orderbook(orderbook);
validate.options(options);
const params = _.assign({}, orderbook, options, {
validated: true,
order_book: orderbook.base + '/' + orderbook.counter
});
function getLastValidatedLedger(parameters) {
const promise = new Promise(function(resolve, reject) {
const ledgerRequest = self.remote.requestLedger('validated');
ledgerRequest.once('success', function(res) {
parameters.ledger = res.ledger.ledger_index;
resolve(parameters);
});
ledgerRequest.once('error', reject);
ledgerRequest.request();
});
return promise;
}
function getBookOffers(taker_gets, taker_pays, parameters) {
const promise = new Promise(function(resolve, reject) {
const bookOffersRequest = self.remote.requestBookOffers({
taker_gets: {currency: taker_gets.currency,
issuer: taker_gets.counterparty},
taker_pays: {currency: taker_pays.currency,
issuer: taker_pays.counterparty},
ledger: parameters.ledger,
limit: parameters.limit,
taker: account
});
bookOffersRequest.once('success', resolve);
bookOffersRequest.once('error', reject);
bookOffersRequest.request();
});
return promise;
}
function getBids(parameters) {
const taker_gets = parameters.counter;
const taker_pays = parameters.base;
return getBookOffers(taker_gets, taker_pays, parameters);
}
function getAsks(parameters) {
const taker_gets = parameters.base;
const taker_pays = parameters.counter;
return getBookOffers(taker_gets, taker_pays, parameters);
}
function getBidsAndAsks(parameters) {
return Promise.join(
getBids(parameters),
getAsks(parameters),
function(bids, asks) {
return [bids, asks, parameters];
}
);
}
function getParsedBookOffers(offers, isAsk) {
return offers.reduce(function(orderBook, off) {
let price;
const order_maker = off.Account;
const sequence = off.Sequence;
// Transaction Flags
const passive = (off.Flags & ripple.Remote.flags.offer.Passive) !== 0;
const sell = (off.Flags & ripple.Remote.flags.offer.Sell) !== 0;
const taker_gets_total = utils.parseCurrencyAmount(off.TakerGets);
const taker_gets_funded = off.taker_gets_funded ?
utils.parseCurrencyAmount(off.taker_gets_funded) : taker_gets_total;
const taker_pays_total = utils.parseCurrencyAmount(off.TakerPays);
const taker_pays_funded = off.taker_pays_funded ?
utils.parseCurrencyAmount(off.taker_pays_funded) : taker_pays_total;
if (isAsk) {
price = {
currency: taker_pays_total.currency,
counterparty: taker_pays_total.counterparty,
value: bignum(taker_pays_total.value).div(
bignum(taker_gets_total.value))
};
} else {
price = {
currency: taker_gets_total.currency,
counterparty: taker_gets_total.counterparty,
value: bignum(taker_gets_total.value).div(
bignum(taker_pays_total.value))
};
}
price.value = price.value.toString();
orderBook.push({
price: price,
taker_gets_funded: taker_gets_funded,
taker_gets_total: taker_gets_total,
taker_pays_funded: taker_pays_funded,
taker_pays_total: taker_pays_total,
order_maker: order_maker,
sequence: sequence,
passive: passive,
sell: sell
});
return orderBook;
}, []);
}
function respondWithOrderBook(bids, asks, parameters) {
const promise = new Promise(function(resolve) {
const orderBook = {
order_book: parameters.order_book,
ledger: parameters.ledger,
validated: parameters.validated,
bids: getParsedBookOffers(bids.offers),
asks: getParsedBookOffers(asks.offers, true)
};
resolve(callback(null, orderBook));
});
return promise;
}
getLastValidatedLedger(params)
.then(getBidsAndAsks)
.spread(respondWithOrderBook)
.catch(callback);
const getter = _.partial(getBookOffers, this.remote, account,
options.ledgerVersion, options.limit);
const getOrders = _.partial(getter, orderbook.base, orderbook.counter);
const getReverseOrders = _.partial(getter, orderbook.counter, orderbook.base);
async.parallel([getOrders, getReverseOrders],
composeAsync((data) => formatBidsAndAsks(orderbook, _.flatten(data)),
callback));
}
module.exports = getOrderBook;
module.exports = utils.wrapCatch(getOrderBook);

View File

@@ -30,8 +30,8 @@ function getAccountOrders(account, options, callback) {
const getter = _.partial(requestAccountOffers, this.remote, account,
ledgerVersion, options);
utils.getRecursive(getter, limit,
composeAsync((orders) => _.sortBy(orders, (order) => order.state.sequence),
callback));
composeAsync((orders) => _.sortBy(orders,
(order) => order.properties.sequence), callback));
}
module.exports = getAccountOrders;
module.exports = utils.wrapCatch(getAccountOrders);

View File

@@ -1,14 +1,27 @@
'use strict';
const parseOrderBase = require('./order-base');
const utils = require('./utils');
const flags = utils.core.Remote.flags.offer;
const parseAmount = require('./amount');
// rippled 'account_offers' returns a different format for orders than 'tx'
function parseAccountOrder(order) {
const specification = parseOrderBase(
order.taker_gets, order.taker_pays, order.flags);
const state = {
// the flags are also different
function parseAccountOrder(order: Object): Object {
const direction = (order.flags & flags.Sell) === 0 ? 'buy' : 'sell';
const takerGetsAmount = parseAmount(order.taker_gets);
const takerPaysAmount = parseAmount(order.taker_pays);
const quantity = (direction === 'buy') ? takerPaysAmount : takerGetsAmount;
const totalPrice = (direction === 'buy') ? takerGetsAmount : takerPaysAmount;
const specification = utils.removeUndefined({
direction: direction,
quantity: quantity,
totalPrice: totalPrice,
passive: ((order.flags & flags.Passive) !== 0) || undefined
});
const properties = {
sequence: order.seq
};
return {specification, state};
return {specification, properties};
}
module.exports = parseAccountOrder;

View File

@@ -1,27 +0,0 @@
/* @flow */
'use strict';
const utils = require('./utils');
const parseAmount = require('./amount');
const orderFlags = utils.core.Transaction.flags.OfferCreate;
/*:: type Amount = string | {currency: string, issuer: string, value: string} */
function parseOrder(takerGets: Amount, takerPays: Amount, flags: number):
Object {
const direction = (flags & orderFlags.Sell) === 0 ? 'buy' : 'sell';
const takerGetsAmount = parseAmount(takerGets);
const takerPaysAmount = parseAmount(takerPays);
const quantity = (direction === 'buy') ? takerPaysAmount : takerGetsAmount;
const totalPrice = (direction === 'buy') ? takerGetsAmount : takerPaysAmount;
return utils.removeUndefined({
direction: direction,
quantity: quantity,
totalPrice: totalPrice,
passive: ((flags & orderFlags.Passive) !== 0) || undefined,
immediateOrCancel: ((flags & orderFlags.ImmediateOrCancel) !== 0)
|| undefined,
fillOrKill: ((flags & orderFlags.FillOrKill) !== 0) || undefined
});
}
module.exports = parseOrder;

View File

@@ -1,11 +1,28 @@
/* @flow */
'use strict';
const assert = require('assert');
const parseOrderBase = require('./order-base');
const utils = require('./utils');
const parseAmount = require('./amount');
const flags = utils.core.Transaction.flags.OfferCreate;
function parseOrder(tx: Object): Object {
assert(tx.TransactionType === 'OfferCreate');
return parseOrderBase(tx.TakerGets, tx.TakerPays, tx.Flags);
const direction = (tx.Flags & flags.Sell) === 0 ? 'buy' : 'sell';
const takerGetsAmount = parseAmount(tx.TakerGets);
const takerPaysAmount = parseAmount(tx.TakerPays);
const quantity = (direction === 'buy') ? takerPaysAmount : takerGetsAmount;
const totalPrice = (direction === 'buy') ? takerGetsAmount : takerPaysAmount;
return utils.removeUndefined({
direction: direction,
quantity: quantity,
totalPrice: totalPrice,
passive: ((tx.Flags & flags.Passive) !== 0) || undefined,
immediateOrCancel: ((tx.Flags & flags.ImmediateOrCancel) !== 0)
|| undefined,
fillOrKill: ((tx.Flags & flags.FillOrKill) !== 0) || undefined
});
}
module.exports = parseOrder;

View File

@@ -0,0 +1,40 @@
'use strict';
const _ = require('lodash');
const utils = require('./utils');
const flags = utils.core.Remote.flags.offer;
const parseAmount = require('./amount');
function parseOrderbookOrder(order: Object): Object {
const direction = (order.Flags & flags.Sell) === 0 ? 'buy' : 'sell';
const takerGetsAmount = parseAmount(order.TakerGets);
const takerPaysAmount = parseAmount(order.TakerPays);
const quantity = (direction === 'buy') ? takerPaysAmount : takerGetsAmount;
const totalPrice = (direction === 'buy') ? takerGetsAmount : takerPaysAmount;
const specification = utils.removeUndefined({
direction: direction,
quantity: quantity,
totalPrice: totalPrice,
passive: ((order.Flags & flags.Passive) !== 0) || undefined
});
// "quality" is omitted intentionally as it corresponds to
// either price or inverse price, and it is better to avoid
// inverting floats where precision issues can arise
const properties = {
maker: order.Account,
sequence: order.Sequence
};
const takerGetsFunded = order.taker_gets_funded ?
parseAmount(order.taker_gets_funded) : undefined;
const takerPaysFunded = order.taker_pays_funded ?
parseAmount(order.taker_pays_funded) : undefined;
const available = utils.removeUndefined({
availableQuantity: direction === 'buy' ? takerPaysFunded : takerGetsFunded,
priceOfAvailableQuantity: direction === 'buy' ?
takerGetsFunded : takerPaysFunded
});
const state = _.isEmpty(available) ? undefined : available;
return utils.removeUndefined({specification, properties, state});
}
module.exports = parseOrderbookOrder;

View File

@@ -144,4 +144,4 @@ function getPathFind(pathfind, callback) {
async.waterfall(steps, callback);
}
module.exports = getPathFind;
module.exports = utils.wrapCatch(getPathFind);

View File

@@ -41,4 +41,4 @@ function getSettings(account, callback) {
});
}
module.exports = getSettings;
module.exports = utils.wrapCatch(getSettings);

View File

@@ -45,4 +45,4 @@ function getTrustlines(account: string, options: Options,
utils.getRecursive(getter, limit, callback);
}
module.exports = getTrustlines;
module.exports = utils.wrapCatch(getTrustlines);

View File

@@ -1610,7 +1610,7 @@ Remote.prototype.requestBookOffers = function(options_, callback_) {
const request = new Request(this, 'book_offers');
request.message.taker_gets = {
currency: Currency.json_rewrite(gets.currency, {force_hex: true})
currency: Currency.json_rewrite(gets.currency)
};
if (!Currency.from_json(request.message.taker_gets.currency).is_native()) {
@@ -1618,7 +1618,7 @@ Remote.prototype.requestBookOffers = function(options_, callback_) {
}
request.message.taker_pays = {
currency: Currency.json_rewrite(pays.currency, {force_hex: true})
currency: Currency.json_rewrite(pays.currency)
};
if (!Currency.from_json(request.message.taker_pays.currency).is_native()) {

View File

@@ -28,12 +28,14 @@ const trustlinesResponse = require('./fixtures/trustlines-response');
const walletResponse = require('./fixtures/wallet.json');
const getSettingsResponse = require('./fixtures/get-settings-response');
const getOrdersResponse = require('./fixtures/get-orders-response');
const getOrderBookResponse = require('./fixtures/get-orderbook-response');
function checkResult(expected, done, error, response) {
if (error) {
done(error);
return;
}
// console.log(JSON.stringify(response, null, 2));
assert.deepEqual(response, expected);
done();
}
@@ -137,4 +139,18 @@ describe('RippleAPI', function() {
_.partial(checkResult, getOrdersResponse, done));
});
it('getOrderBook', function(done) {
const orderbook = {
base: {
currency: 'USD',
counterparty: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
},
counter: {
currency: 'BTC',
counterparty: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
}
};
this.api.getOrderBook(address, orderbook, {},
_.partial(checkResult, getOrderBookResponse, done));
});
});

1183
test/fixtures/book-offers-response.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,370 @@
{
"bids": [
{
"specification": {
"direction": "buy",
"quantity": {
"currency": "USD",
"value": "10",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "3205.1",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "r49y2xKuKVG2dPkNHgWQAV61cjxk8gryjQ",
"sequence": 434
}
},
{
"specification": {
"direction": "buy",
"quantity": {
"currency": "USD",
"value": "4.99707396683212",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "1599.063669386278",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "rDYCRhpahKEhCFV25xScg67Bwf4W9sTYAm",
"sequence": 233
}
},
{
"specification": {
"direction": "buy",
"quantity": {
"currency": "USD",
"value": "0.4499999999999999",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "143.1050962074379",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "raudnGKfTK23YKfnS7ixejHrqGERTYNFXk",
"sequence": 110104
},
"state": {
"availableQuantity": {
"currency": "USD",
"value": "0",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"priceOfAvailableQuantity": {
"currency": "BTC",
"value": "0",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
}
},
{
"specification": {
"direction": "buy",
"quantity": {
"currency": "USD",
"value": "0.8",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "254.329207354604",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
"sequence": 35625
},
"state": {
"availableQuantity": {
"currency": "USD",
"value": "0",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"priceOfAvailableQuantity": {
"currency": "BTC",
"value": "0",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
}
},
{
"specification": {
"direction": "buy",
"quantity": {
"currency": "USD",
"value": "1.23231134568807",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "390.4979",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "rwBYyfufTzk77zUSKEu4MvixfarC35av1J",
"sequence": 387756
}
},
{
"specification": {
"direction": "buy",
"quantity": {
"currency": "USD",
"value": "0.003160328237957649",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "1",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "rwjsRktX1eguUr1pHTffyHnC4uyrvX58V1",
"sequence": 208927
}
},
{
"specification": {
"direction": "buy",
"quantity": {
"currency": "USD",
"value": "15",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "4725",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "r49y2xKuKVG2dPkNHgWQAV61cjxk8gryjQ",
"sequence": 429
}
},
{
"specification": {
"direction": "buy",
"quantity": {
"currency": "USD",
"value": "1.6",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "496.5429474010489",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
"sequence": 35627
},
"state": {
"availableQuantity": {
"currency": "USD",
"value": "0",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"priceOfAvailableQuantity": {
"currency": "BTC",
"value": "0",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
}
},
{
"specification": {
"direction": "buy",
"quantity": {
"currency": "USD",
"value": "10",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "3103",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "r49y2xKuKVG2dPkNHgWQAV61cjxk8gryjQ",
"sequence": 431
}
}
],
"asks": [
{
"specification": {
"direction": "sell",
"quantity": {
"currency": "USD",
"value": "0.3",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "99.34014894048333",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "raudnGKfTK23YKfnS7ixejHrqGERTYNFXk",
"sequence": 110103
}
},
{
"specification": {
"direction": "sell",
"quantity": {
"currency": "USD",
"value": "0.8095",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "268.754",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "rPyYxUGK8L4dgEvjPs3aRc1B1jEiLr3Hx5",
"sequence": 392
},
"state": {
"availableQuantity": {
"currency": "USD",
"value": "0.8078974385735969",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"priceOfAvailableQuantity": {
"currency": "BTC",
"value": "268.2219496064341",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
}
},
{
"specification": {
"direction": "sell",
"quantity": {
"currency": "USD",
"value": "0.4499999999999999",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "152.0098333185607",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "raudnGKfTK23YKfnS7ixejHrqGERTYNFXk",
"sequence": 110105
}
},
{
"specification": {
"direction": "sell",
"quantity": {
"currency": "USD",
"value": "0.003768001830745216",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "1.308365894430151",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "rDbsCJr5m8gHDCNEHCZtFxcXHsD4S9jH83",
"sequence": 110061
}
},
{
"specification": {
"direction": "sell",
"quantity": {
"currency": "USD",
"value": "0.5",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "176.3546101589987",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
"sequence": 35788
}
},
{
"specification": {
"direction": "sell",
"quantity": {
"currency": "USD",
"value": "0.5",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "179.48",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "rN6jbxx4H6NxcnmkzBxQnbCWLECNKrgSSf",
"sequence": 491
},
"state": {
"availableQuantity": {
"currency": "USD",
"value": "0.499001996007984",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"priceOfAvailableQuantity": {
"currency": "BTC",
"value": "179.1217564870259",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
}
},
{
"specification": {
"direction": "sell",
"quantity": {
"currency": "USD",
"value": "0.8",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
},
"totalPrice": {
"currency": "BTC",
"value": "288.7710263794967",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"properties": {
"maker": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
"sequence": 35789
}
}
]
}

View File

@@ -1,20 +1,19 @@
[
{
"specification": {
"direction": "buy",
"direction": "sell",
"quantity": {
"currency": "USD",
"value": "1122.990930900328",
"counterparty": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
},
"totalPrice": {
"currency": "EUR",
"value": "17.70155237781915",
"counterparty": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
},
"immediateOrCancel": true
"totalPrice": {
"currency": "USD",
"value": "1122.990930900328",
"counterparty": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
}
},
"state": {
"properties": {
"sequence": 719930
}
},
@@ -32,7 +31,7 @@
"counterparty": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
}
},
"state": {
"properties": {
"sequence": 756999
}
},
@@ -50,7 +49,7 @@
"counterparty": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
}
},
"state": {
"properties": {
"sequence": 757002
}
},
@@ -68,7 +67,7 @@
"counterparty": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
}
},
"state": {
"properties": {
"sequence": 757003
}
},
@@ -86,7 +85,7 @@
"counterparty": "rsP3mgGb2tcYUrxiLFiHJiQXhsziegtwBc"
}
},
"state": {
"properties": {
"sequence": 782148
}
},
@@ -104,7 +103,7 @@
"counterparty": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
}
},
"state": {
"properties": {
"sequence": 787368
}
},
@@ -122,7 +121,7 @@
"counterparty": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
}
},
"state": {
"properties": {
"sequence": 787408
}
},
@@ -140,7 +139,7 @@
"counterparty": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
}
},
"state": {
"properties": {
"sequence": 803438
}
},
@@ -158,7 +157,7 @@
"counterparty": "r9Dr5xwkeLegBeXq6ujinjSBLQzQ1zQGjH"
}
},
"state": {
"properties": {
"sequence": 807858
}
},
@@ -176,7 +175,7 @@
"counterparty": "r9Dr5xwkeLegBeXq6ujinjSBLQzQ1zQGjH"
}
},
"state": {
"properties": {
"sequence": 807896
}
},
@@ -193,7 +192,7 @@
"counterparty": "rsP3mgGb2tcYUrxiLFiHJiQXhsziegtwBc"
}
},
"state": {
"properties": {
"sequence": 814018
}
},
@@ -211,7 +210,7 @@
"counterparty": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
}
},
"state": {
"properties": {
"sequence": 827522
}
},
@@ -229,7 +228,7 @@
"counterparty": "r9Dr5xwkeLegBeXq6ujinjSBLQzQ1zQGjH"
}
},
"state": {
"properties": {
"sequence": 833591
}
},
@@ -247,7 +246,7 @@
"counterparty": "r9Dr5xwkeLegBeXq6ujinjSBLQzQ1zQGjH"
}
},
"state": {
"properties": {
"sequence": 833592
}
},
@@ -265,7 +264,7 @@
"counterparty": "r9Dr5xwkeLegBeXq6ujinjSBLQzQ1zQGjH"
}
},
"state": {
"properties": {
"sequence": 838954
}
},
@@ -282,7 +281,7 @@
"value": "2229.229447"
}
},
"state": {
"properties": {
"sequence": 843730
}
},
@@ -300,7 +299,7 @@
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"state": {
"properties": {
"sequence": 844068
}
}

View File

@@ -7,6 +7,7 @@ const fixtures = require('./fixtures/mock');
const addresses = require('./fixtures/addresses');
const hashes = require('./fixtures/hashes');
const accountOffersResponse = require('./fixtures/acct-offers-response');
const bookOffers = require('./fixtures/book-offers-response');
module.exports = function(port) {
const mock = new WebSocketServer({port: port});
@@ -129,5 +130,17 @@ module.exports = function(port) {
}
});
mock.on('request_book_offers', function(request, conn) {
if (request.taker_gets.currency === 'BTC'
&& request.taker_pays.currency === 'USD') {
conn.send(bookOffers.requestBookOffersBidsResponse(request));
} else if (request.taker_gets.currency === 'USD'
&& request.taker_pays.currency === 'BTC') {
conn.send(bookOffers.requestBookOffersAsksResponse(request));
} else {
assert(false, 'Unrecognized order book: ' + JSON.stringify(request));
}
});
return mock;
};