diff --git a/src/api/index.js b/src/api/index.js index 0afbc09a..0c3abc7d 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -12,7 +12,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'); @@ -41,7 +41,7 @@ RippleAPI.prototype = { getBalances, getPathFind, getOrders, - getOrderBook, + getOrderbook, getSettings, preparePayment, diff --git a/src/api/ledger/orderbook.js b/src/api/ledger/orderbook.js index 75b0a848..f94f46a4 100644 --- a/src/api/ledger/orderbook.js +++ b/src/api/ledger/orderbook.js @@ -49,7 +49,7 @@ function formatBidsAndAsks(orderbook, offers) { return {bids, asks, flipped}; } -function getOrderBook(account, orderbook, options, callback) { +function getOrderbook(account, orderbook, options, callback) { validate.address(account); validate.orderbook(orderbook); validate.options(options); @@ -63,4 +63,4 @@ function getOrderBook(account, orderbook, options, callback) { callback)); } -module.exports = utils.wrapCatch(getOrderBook); +module.exports = utils.wrapCatch(getOrderbook); diff --git a/src/api/ledger/orders.js b/src/api/ledger/orders.js index 19331533..fe3d4b27 100644 --- a/src/api/ledger/orders.js +++ b/src/api/ledger/orders.js @@ -15,7 +15,7 @@ function requestAccountOffers(remote, address, ledgerVersion, options, }, composeAsync((data) => ({ marker: data.marker, - results: data.offers.map(parseAccountOrder) + results: data.offers.map(_.partial(parseAccountOrder, address)) }), callback)); } diff --git a/src/api/ledger/parse/account-order.js b/src/api/ledger/parse/account-order.js index b79344e4..adbf14f3 100644 --- a/src/api/ledger/parse/account-order.js +++ b/src/api/ledger/parse/account-order.js @@ -2,25 +2,38 @@ const utils = require('./utils'); const flags = utils.core.Remote.flags.offer; const parseAmount = require('./amount'); +const BigNumber = require('bignumber.js'); + +// TODO: remove this function once rippled provides quality directly +function computeQuality(takerGets, takerPays) { + const quotient = new BigNumber(takerPays.value).dividedBy(takerGets.value); + return quotient.toDigits(16, BigNumber.ROUND_HALF_UP).toString(); +} // rippled 'account_offers' returns a different format for orders than 'tx' // the flags are also different -function parseAccountOrder(order: Object): Object { +function parseAccountOrder(address: string, 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; + // note: immediateOrCancel and fillOrKill orders cannot enter the order book + // so we can omit those flags here const specification = utils.removeUndefined({ direction: direction, quantity: quantity, totalPrice: totalPrice, passive: ((order.flags & flags.Passive) !== 0) || undefined }); + const properties = { - sequence: order.seq + maker: address, + sequence: order.seq, + makerExchangeRate: computeQuality(takerGetsAmount, takerPaysAmount) }; + return {specification, properties}; } diff --git a/src/api/ledger/parse/orderbook-order.js b/src/api/ledger/parse/orderbook-order.js index 8754b2e5..6197701b 100644 --- a/src/api/ledger/parse/orderbook-order.js +++ b/src/api/ledger/parse/orderbook-order.js @@ -11,19 +11,22 @@ function parseOrderbookOrder(order: Object): Object { const quantity = (direction === 'buy') ? takerPaysAmount : takerGetsAmount; const totalPrice = (direction === 'buy') ? takerGetsAmount : takerPaysAmount; + // note: immediateOrCancel and fillOrKill orders cannot enter the order book + // so we can omit those flags here 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 + sequence: order.Sequence, + makerExchangeRate: utils.adjustQualityForXRP(order.quality, + takerGetsAmount.currency, takerPaysAmount.currency) }; + const takerGetsFunded = order.taker_gets_funded ? parseAmount(order.taker_gets_funded) : undefined; const takerPaysFunded = order.taker_pays_funded ? diff --git a/src/api/ledger/parse/utils.js b/src/api/ledger/parse/utils.js index 6fdc546e..3c84a269 100644 --- a/src/api/ledger/parse/utils.js +++ b/src/api/ledger/parse/utils.js @@ -4,6 +4,15 @@ const _ = require('lodash'); const transactionParser = require('ripple-lib-transactionparser'); const toTimestamp = require('../../../core/utils').toTimestamp; const utils = require('../utils'); +const BigNumber = require('bignumber.js'); + +function adjustQualityForXRP(quality: string, takerGetsCurrency: string, + takerPaysCurrency: string) { + const shift = (takerGetsCurrency === 'XRP' ? 6 : 0) + - (takerPaysCurrency === 'XRP' ? 6 : 0); + return shift === 0 ? quality : + (new BigNumber(quality)).shift(shift).toString(); +} function parseTimestamp(tx: {date: string}): string | void { return tx.date ? (new Date(toTimestamp(tx.date))).toISOString() : undefined; @@ -58,6 +67,7 @@ function parseOutcome(tx: Object): ?Object { module.exports = { parseOutcome, removeUndefined, + adjustQualityForXRP, dropsToXrp: utils.common.dropsToXrp, constants: utils.common.constants, core: utils.common.core diff --git a/test/api-test.js b/test/api-test.js index 3b7e360f..5189222e 100644 --- a/test/api-test.js +++ b/test/api-test.js @@ -28,7 +28,7 @@ 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'); +const getOrderbookResponse = require('./fixtures/get-orderbook-response'); const getServerInfoResponse = require('./fixtures/get-server-info-response'); const getPathFindResponse = require('./fixtures/get-pathfind-response'); const address = addresses.ACCOUNT; @@ -142,7 +142,7 @@ describe('RippleAPI', function() { _.partial(checkResult, getOrdersResponse, done)); }); - it('getOrderBook', function(done) { + it('getOrderbook', function(done) { const orderbook = { base: { currency: 'USD', @@ -153,8 +153,8 @@ describe('RippleAPI', function() { counterparty: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B' } }; - this.api.getOrderBook(address, orderbook, {}, - _.partial(checkResult, getOrderBookResponse, done)); + this.api.getOrderbook(address, orderbook, {}, + _.partial(checkResult, getOrderbookResponse, done)); }); it('getServerInfo', function(done) { diff --git a/test/fixtures/get-orderbook-response.json b/test/fixtures/get-orderbook-response.json index 3b163a95..0343e609 100644 --- a/test/fixtures/get-orderbook-response.json +++ b/test/fixtures/get-orderbook-response.json @@ -16,7 +16,8 @@ }, "properties": { "maker": "r49y2xKuKVG2dPkNHgWQAV61cjxk8gryjQ", - "sequence": 434 + "sequence": 434, + "makerExchangeRate": "0.003120027456241615" } }, { @@ -35,7 +36,8 @@ }, "properties": { "maker": "rDYCRhpahKEhCFV25xScg67Bwf4W9sTYAm", - "sequence": 233 + "sequence": 233, + "makerExchangeRate": "0.003125" } }, { @@ -54,7 +56,8 @@ }, "properties": { "maker": "raudnGKfTK23YKfnS7ixejHrqGERTYNFXk", - "sequence": 110104 + "sequence": 110104, + "makerExchangeRate": "0.003144542101755081" }, "state": { "availableQuantity": { @@ -85,7 +88,8 @@ }, "properties": { "maker": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE", - "sequence": 35625 + "sequence": 35625, + "makerExchangeRate": "0.003145529403882357" }, "state": { "availableQuantity": { @@ -116,7 +120,8 @@ }, "properties": { "maker": "rwBYyfufTzk77zUSKEu4MvixfarC35av1J", - "sequence": 387756 + "sequence": 387756, + "makerExchangeRate": "0.003155743848271834" } }, { @@ -135,7 +140,8 @@ }, "properties": { "maker": "rwjsRktX1eguUr1pHTffyHnC4uyrvX58V1", - "sequence": 208927 + "sequence": 208927, + "makerExchangeRate": "0.003160328237957649" } }, { @@ -154,7 +160,8 @@ }, "properties": { "maker": "r49y2xKuKVG2dPkNHgWQAV61cjxk8gryjQ", - "sequence": 429 + "sequence": 429, + "makerExchangeRate": "0.003174603174603175" } }, { @@ -173,7 +180,8 @@ }, "properties": { "maker": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE", - "sequence": 35627 + "sequence": 35627, + "makerExchangeRate": "0.003222279177208227" }, "state": { "availableQuantity": { @@ -204,7 +212,8 @@ }, "properties": { "maker": "r49y2xKuKVG2dPkNHgWQAV61cjxk8gryjQ", - "sequence": 431 + "sequence": 431, + "makerExchangeRate": "0.003222687721559781" } } ], @@ -225,7 +234,8 @@ }, "properties": { "maker": "raudnGKfTK23YKfnS7ixejHrqGERTYNFXk", - "sequence": 110103 + "sequence": 110103, + "makerExchangeRate": "331.1338298016111" } }, { @@ -244,7 +254,8 @@ }, "properties": { "maker": "rPyYxUGK8L4dgEvjPs3aRc1B1jEiLr3Hx5", - "sequence": 392 + "sequence": 392, + "makerExchangeRate": "332" }, "state": { "availableQuantity": { @@ -275,7 +286,8 @@ }, "properties": { "maker": "raudnGKfTK23YKfnS7ixejHrqGERTYNFXk", - "sequence": 110105 + "sequence": 110105, + "makerExchangeRate": "337.7996295968016" } }, { @@ -294,7 +306,8 @@ }, "properties": { "maker": "rDbsCJr5m8gHDCNEHCZtFxcXHsD4S9jH83", - "sequence": 110061 + "sequence": 110061, + "makerExchangeRate": "347.2306949944844" } }, { @@ -313,7 +326,8 @@ }, "properties": { "maker": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE", - "sequence": 35788 + "sequence": 35788, + "makerExchangeRate": "352.7092203179974" } }, { @@ -332,7 +346,8 @@ }, "properties": { "maker": "rN6jbxx4H6NxcnmkzBxQnbCWLECNKrgSSf", - "sequence": 491 + "sequence": 491, + "makerExchangeRate": "358.96" }, "state": { "availableQuantity": { @@ -363,7 +378,8 @@ }, "properties": { "maker": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE", - "sequence": 35789 + "sequence": 35789, + "makerExchangeRate": "360.9637829743709" } } ], @@ -385,7 +401,8 @@ }, "properties": { "maker": "rwBYyfufTzk77zUSKEu4MvixfarC35av1J", - "sequence": 386940 + "sequence": 386940, + "makerExchangeRate": "326.5003614141928" } }, { @@ -404,7 +421,8 @@ }, "properties": { "maker": "rwjsRktX1eguUr1pHTffyHnC4uyrvX58V1", - "sequence": 207855 + "sequence": 207855, + "makerExchangeRate": "330.6364334177034" } }, { @@ -423,7 +441,8 @@ }, "properties": { "maker": "rUeCeioKJkbYhv4mRGuAbZpPcqkMCoYq6N", - "sequence": 5255 + "sequence": 5255, + "makerExchangeRate": "365.9629780181032" }, "state": { "availableQuantity": { @@ -456,7 +475,8 @@ }, "properties": { "maker": "rDbsCJr5m8gHDCNEHCZtFxcXHsD4S9jH83", - "sequence": 110099 + "sequence": 110099, + "makerExchangeRate": "0.003193013959408667" } } ] diff --git a/test/fixtures/get-orders-response.json b/test/fixtures/get-orders-response.json index 8373b149..03440033 100644 --- a/test/fixtures/get-orders-response.json +++ b/test/fixtures/get-orders-response.json @@ -14,7 +14,9 @@ } }, "properties": { - "sequence": 719930 + "maker": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "sequence": 719930, + "makerExchangeRate": "63.44025128030504" } }, { @@ -32,7 +34,9 @@ } }, "properties": { - "sequence": 756999 + "maker": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "sequence": 756999, + "makerExchangeRate": "39.23215583132338" } }, { @@ -50,7 +54,9 @@ } }, "properties": { - "sequence": 757002 + "maker": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "sequence": 757002, + "makerExchangeRate": "1.056334989703257" } }, { @@ -68,7 +74,9 @@ } }, "properties": { - "sequence": 757003 + "maker": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "sequence": 757003, + "makerExchangeRate": "100.3518240218094" } }, { @@ -86,7 +94,9 @@ } }, "properties": { - "sequence": 782148 + "maker": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "sequence": 782148, + "makerExchangeRate": "81.7121820757743" } }, { @@ -104,7 +114,9 @@ } }, "properties": { - "sequence": 787368 + "maker": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "sequence": 787368, + "makerExchangeRate": "50.26296114247091" } }, { @@ -122,7 +134,9 @@ } }, "properties": { - "sequence": 787408 + "maker": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "sequence": 787408, + "makerExchangeRate": "1000.519693952099" } }, { @@ -140,7 +154,9 @@ } }, "properties": { - "sequence": 803438 + "maker": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "sequence": 803438, + "makerExchangeRate": "1356.054621894598" } }, { @@ -158,7 +174,9 @@ } }, "properties": { - "sequence": 807858 + "maker": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "sequence": 807858, + "makerExchangeRate": "123763.8630020459" } }, { @@ -176,7 +194,9 @@ } }, "properties": { - "sequence": 807896 + "maker": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "sequence": 807896, + "makerExchangeRate": "123646.6837435794" } }, { @@ -193,7 +213,9 @@ } }, "properties": { - "sequence": 814018 + "maker": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "sequence": 814018, + "makerExchangeRate": "16922.62953364839" } }, { @@ -211,7 +233,9 @@ } }, "properties": { - "sequence": 827522 + "maker": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "sequence": 827522, + "makerExchangeRate": "62.63032241192674" } }, { @@ -229,7 +253,9 @@ } }, "properties": { - "sequence": 833591 + "maker": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "sequence": 833591, + "makerExchangeRate": "160.8325363767064" } }, { @@ -247,7 +273,9 @@ } }, "properties": { - "sequence": 833592 + "maker": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "sequence": 833592, + "makerExchangeRate": "1608.325363767062" } }, { @@ -265,7 +293,9 @@ } }, "properties": { - "sequence": 838954 + "maker": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "sequence": 838954, + "makerExchangeRate": "162.9564891233845" } }, { @@ -282,7 +312,9 @@ } }, "properties": { - "sequence": 843730 + "maker": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "sequence": 843730, + "makerExchangeRate": "0.0004485854972648762" } }, { @@ -300,7 +332,9 @@ } }, "properties": { - "sequence": 844068 + "maker": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", + "sequence": 844068, + "makerExchangeRate": "42.19320561670911" } } ]