From 23995490784910f31a86c63e9f37f502d02ab24c Mon Sep 17 00:00:00 2001 From: Daniel McNally Date: Sun, 26 May 2019 03:58:37 -0400 Subject: [PATCH] fix: calculate swap amount for market orders This fixes a bug where the calculated swap amount for a market buy order could be infinity. This could cause the sanity capacity check to fail when checking a market order. Market buy orders internally have a positive infinity price value for matching logic purposes, but the final price for market orders is not known upon first placing them. Fixes #978. --- lib/db/models/Order.ts | 2 +- lib/orderbook/OrderBook.ts | 2 +- lib/swaps/Swaps.ts | 7 +++++-- test/unit/DB.spec.ts | 2 +- test/unit/Swaps.spec.ts | 14 ++++++++++++++ 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/lib/db/models/Order.ts b/lib/db/models/Order.ts index 139441f83..2c9f9ff43 100644 --- a/lib/db/models/Order.ts +++ b/lib/db/models/Order.ts @@ -12,7 +12,7 @@ export default (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) type: DataTypes.DOUBLE, allowNull: true, set(this: db.OrderInstance, value: number) { - if (value === 0 || value === Number.MAX_VALUE) { + if (value === 0 || value === Number.POSITIVE_INFINITY) { this.setDataValue('price', undefined); } else { this.setDataValue('price', value); diff --git a/lib/orderbook/OrderBook.ts b/lib/orderbook/OrderBook.ts index 1721b08ef..e556e3cdb 100644 --- a/lib/orderbook/OrderBook.ts +++ b/lib/orderbook/OrderBook.ts @@ -303,7 +303,7 @@ class OrderBook extends EventEmitter { throw errors.MARKET_ORDERS_NOT_ALLOWED(); } - const stampedOrder = this.stampOwnOrder({ ...order, price: order.isBuy ? Number.MAX_VALUE : 0 }); + const stampedOrder = this.stampOwnOrder({ ...order, price: order.isBuy ? Number.POSITIVE_INFINITY : 0 }); const addResult = await this.placeOrder(stampedOrder, true, onUpdate, Date.now() + OrderBook.MAX_PLACEORDER_ITERATIONS_TIME); delete addResult.remainingOrder; return addResult; diff --git a/lib/swaps/Swaps.ts b/lib/swaps/Swaps.ts index 31c8d03d8..3314ab718 100644 --- a/lib/swaps/Swaps.ts +++ b/lib/swaps/Swaps.ts @@ -94,12 +94,15 @@ class Swaps extends EventEmitter { * @param quantity The quantity of the order * @param price The price of the order * @param isBuy Whether the order is a buy - * @returns An object with the calculated incoming and outgoing values. + * @returns An object with the calculated incoming and outgoing values. The quote currency + * amount is returned as zero if the price is 0 or infinity, indicating a market order. */ public static calculateInboundOutboundAmounts = (quantity: number, price: number, isBuy: boolean, pairId: string) => { const [baseCurrency, quoteCurrency] = pairId.split('/'); const baseCurrencyAmount = Math.round(quantity * Swaps.UNITS_PER_CURRENCY[baseCurrency]); - const quoteCurrencyAmount = Math.round(quantity * price * Swaps.UNITS_PER_CURRENCY[quoteCurrency]); + const quoteCurrencyAmount = price > 0 && price < Number.POSITIVE_INFINITY ? + Math.round(quantity * price * Swaps.UNITS_PER_CURRENCY[quoteCurrency]) : + 0; // if price is zero or infinity, this is a market order and we can't know the quote currency amount const inboundCurrency = isBuy ? baseCurrency : quoteCurrency; const inboundAmount = isBuy ? baseCurrencyAmount : quoteCurrencyAmount; diff --git a/test/unit/DB.spec.ts b/test/unit/DB.spec.ts index 16cf6ab60..4f0b54441 100644 --- a/test/unit/DB.spec.ts +++ b/test/unit/DB.spec.ts @@ -129,7 +129,7 @@ describe('Database', () => { }); it('should add market orders and have their price in db be null', async () => { - const buyMarketOrder = createOwnOrder(Number.MAX_VALUE, quantity, true); + const buyMarketOrder = createOwnOrder(Number.POSITIVE_INFINITY, quantity, true); const sellMarketOrder = createOwnOrder(0, quantity, true); await orderBookRepo.addOrderIfNotExists(buyMarketOrder); await orderBookRepo.addOrderIfNotExists(sellMarketOrder); diff --git a/test/unit/Swaps.spec.ts b/test/unit/Swaps.spec.ts index e93e18486..51da9dccc 100644 --- a/test/unit/Swaps.spec.ts +++ b/test/unit/Swaps.spec.ts @@ -110,6 +110,20 @@ describe('Swaps', () => { expect(outboundAmount).to.equal(Swaps['UNITS_PER_CURRENCY']['LTC'] * quantity); }); + it('should calculate 0 outbound amount for a market buy order', () => { + const { outboundCurrency, outboundAmount } = + Swaps.calculateInboundOutboundAmounts(quantity, 0, true, pairId); + expect(outboundCurrency).to.equal('BTC'); + expect(outboundAmount).to.equal(0); + }); + + it('should calculate 0 inbound amount for a market sell order', () => { + const { inboundCurrency, inboundAmount } = + Swaps.calculateInboundOutboundAmounts(quantity, Number.POSITIVE_INFINITY, false, pairId); + expect(inboundCurrency).to.equal('BTC'); + expect(inboundAmount).to.equal(0); + }); + it('should validate a good swap request', () => { expect(Swaps.validateSwapRequest(swapRequest)).to.be.true; });