From 4bd5789203aa9f75cc7834aa0e29412ba3abba4f Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Tue, 21 Nov 2017 10:30:29 +1100 Subject: Refactor into a calculator class --- .../order_watcher/remaining_fillable_calculator.ts | 68 ++++++++++++++ packages/0x.js/src/utils/order_state_utils.ts | 101 ++------------------- 2 files changed, 76 insertions(+), 93 deletions(-) create mode 100644 packages/0x.js/src/order_watcher/remaining_fillable_calculator.ts (limited to 'packages') diff --git a/packages/0x.js/src/order_watcher/remaining_fillable_calculator.ts b/packages/0x.js/src/order_watcher/remaining_fillable_calculator.ts new file mode 100644 index 000000000..fe373eae4 --- /dev/null +++ b/packages/0x.js/src/order_watcher/remaining_fillable_calculator.ts @@ -0,0 +1,68 @@ +import { + SignedOrder, +} from '../types'; +import { BigNumber } from 'bignumber.js'; +export class RemainingFillableCalculator { + private _signedOrder: SignedOrder; + private _isMakerTokenZRX: boolean; + private _transferrableMakerTokenAmount: BigNumber; + private _transferrableMakerFeeTokenAmount: BigNumber; + private _remainingMakerTokenAmount: BigNumber; + private _remainingMakerFeeAmount: BigNumber; + constructor(signedOrder: SignedOrder, + zrxAddress: string, + transferrableMakerTokenAmount: BigNumber, + transferrableMakerFeeTokenAmount: BigNumber, + remainingMakerTokenAmount: BigNumber) { + this._signedOrder = signedOrder; + this._isMakerTokenZRX = signedOrder.makerTokenAddress === zrxAddress; + this._transferrableMakerTokenAmount = transferrableMakerTokenAmount; + this._transferrableMakerFeeTokenAmount = transferrableMakerFeeTokenAmount; + this._remainingMakerTokenAmount = remainingMakerTokenAmount; + this._remainingMakerFeeAmount = remainingMakerTokenAmount.times(signedOrder.makerFee) + .dividedToIntegerBy(signedOrder.makerTokenAmount); + } + public computeRemainingMakerFillable(): BigNumber { + if (this.hasSufficientFundsForFeeAndTransferAmount()) { + return this._remainingMakerTokenAmount; + } + if (this._signedOrder.makerFee.isZero()) { + return BigNumber.min(this._remainingMakerTokenAmount, this._transferrableMakerTokenAmount); + } else { + return this.calculatePartiallyFillableMakerTokenAmount(); + } + } + public computeRemainingTakerFillable(): BigNumber { + return this.computeRemainingMakerFillable().times(this._signedOrder.takerTokenAmount) + .dividedToIntegerBy(this._signedOrder.makerTokenAmount); + } + private hasSufficientFundsForFeeAndTransferAmount(): boolean { + if (this._isMakerTokenZRX) { + const totalZRXTransferAmount = this._remainingMakerTokenAmount.plus(this._remainingMakerFeeAmount); + return this._transferrableMakerTokenAmount.gte(totalZRXTransferAmount); + } else { + const hasSufficientFundsForTransferAmount = this._transferrableMakerTokenAmount.gte( + this._remainingMakerTokenAmount); + const hasSufficientFundsForFeeAmount = this._transferrableMakerFeeTokenAmount.gte( + this._remainingMakerFeeAmount); + return (hasSufficientFundsForTransferAmount && hasSufficientFundsForFeeAmount); + } + } + + private calculatePartiallyFillableMakerTokenAmount(): BigNumber { + const orderToFeeRatio = this._signedOrder.makerTokenAmount.dividedToIntegerBy(this._signedOrder.makerFee); + const fillableTimesInFeeToken = BigNumber.min(this._transferrableMakerFeeTokenAmount, + this._remainingMakerFeeAmount); + let fillableTimesInMakerToken = this._transferrableMakerTokenAmount.dividedToIntegerBy(orderToFeeRatio); + if (this._isMakerTokenZRX) { + // when zrx == maker token transferrable maker == transfer + const totalZRXTokenPooled = this._transferrableMakerTokenAmount; + fillableTimesInMakerToken = totalZRXTokenPooled.dividedToIntegerBy( + orderToFeeRatio.plus(new BigNumber(1))); + + } + const partiallyFillableMakerTokenAmount = fillableTimesInMakerToken.times(orderToFeeRatio); + const partiallyFillableFeeTokenAmount = fillableTimesInFeeToken.times(orderToFeeRatio); + return BigNumber.min(partiallyFillableMakerTokenAmount, partiallyFillableFeeTokenAmount); + } +} diff --git a/packages/0x.js/src/utils/order_state_utils.ts b/packages/0x.js/src/utils/order_state_utils.ts index 78333e907..9ff26a7f1 100644 --- a/packages/0x.js/src/utils/order_state_utils.ts +++ b/packages/0x.js/src/utils/order_state_utils.ts @@ -17,6 +17,7 @@ import {utils} from '../utils/utils'; import {constants} from '../utils/constants'; import {OrderFilledCancelledLazyStore} from '../stores/order_filled_cancelled_lazy_store'; import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store'; +import {RemainingFillableCalculator} from '../order_watcher/remaining_fillable_calculator'; const ACCEPTABLE_RELATIVE_ROUNDING_ERROR = 0.0001; @@ -78,19 +79,16 @@ export class OrderStateUtils { const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount); const remainingMakerTokenAmount = remainingTakerTokenAmount.times(totalMakerTokenAmount) .dividedToIntegerBy(totalTakerTokenAmount); - const remainingMakerFeeAmount = remainingTakerTokenAmount.times(signedOrder.makerFee) - .dividedToIntegerBy(totalTakerTokenAmount); const transferrableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]); const transferrableFeeTokenAmount = BigNumber.min([makerFeeProxyAllowance, makerFeeBalance]); - const remainingFillableMakerTokenAmount = this.calculateRemainingMakerTokenAmount( - transferrableMakerTokenAmount, transferrableFeeTokenAmount, remainingMakerTokenAmount, - remainingMakerFeeAmount, totalMakerTokenAmount, signedOrder.makerFee, signedOrder.makerTokenAddress, - zrxTokenAddress); - - const remainingFillableTakerTokenAmount = remainingFillableMakerTokenAmount - .times(totalTakerTokenAmount) - .dividedToIntegerBy(totalMakerTokenAmount); + const remainingFillableCalculator = new RemainingFillableCalculator(signedOrder, + zrxTokenAddress, + transferrableMakerTokenAmount, + transferrableFeeTokenAmount, + remainingMakerTokenAmount); + const remainingFillableMakerTokenAmount = remainingFillableCalculator.computeRemainingMakerFillable(); + const remainingFillableTakerTokenAmount = remainingFillableCalculator.computeRemainingTakerFillable(); const orderRelevantState = { makerBalance, makerProxyAllowance, @@ -103,89 +101,6 @@ export class OrderStateUtils { }; return orderRelevantState; } - private calculateRemainingMakerTokenAmount(transferrableMakerTokenAmount: BigNumber, - transferrableMakerFeeTokenAmount: BigNumber, - remainingMakerAmount: BigNumber, - remainingMakerFeeAmount: BigNumber, - totalMakerAmount: BigNumber, - makerFeeAmount: BigNumber, - makerTokenAddress: string, - zrxTokenAddress: string): BigNumber { - if ((makerTokenAddress !== zrxTokenAddress || makerFeeAmount.isZero())) { - return this.computeFillableMakerTokenAmountWhenMakerTokenIsNotZRX( - transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerAmount, - remainingMakerFeeAmount, totalMakerAmount, makerFeeAmount, makerTokenAddress, - zrxTokenAddress); - } else { - return this.computeFillableMakerTokenAmountWhenMakerTokenIsZRX( - transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerAmount, - remainingMakerFeeAmount, totalMakerAmount, makerFeeAmount, makerTokenAddress, - zrxTokenAddress); - } - } - private computeFillableMakerTokenAmountWhenMakerTokenIsNotZRX(transferrableMakerTokenAmount: BigNumber, - transferrableMakerFeeTokenAmount: BigNumber, - remainingMakerAmount: BigNumber, - remainingMakerFeeAmount: BigNumber, - totalMakerAmount: BigNumber, - makerFeeAmount: BigNumber, - makerTokenAddress: string, - zrxTokenAddress: string): BigNumber { - const hasSufficientFundsForTransferAmount = transferrableMakerTokenAmount.gte(remainingMakerAmount); - const hasSufficientFundsForFeeAmount = transferrableMakerFeeTokenAmount.gte(remainingMakerFeeAmount); - const hasSufficientFundsForFeeAndTransferAmount = (hasSufficientFundsForTransferAmount && - hasSufficientFundsForFeeAmount); - - if (makerFeeAmount.isZero()) { - return BigNumber.min(remainingMakerAmount, transferrableMakerTokenAmount); - } else if (hasSufficientFundsForFeeAndTransferAmount) { - return remainingMakerAmount; - } else { - return this.calculatePartiallyFillableMakerTokenAmount( - transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerAmount, - remainingMakerFeeAmount, totalMakerAmount, makerFeeAmount, makerTokenAddress, - zrxTokenAddress); - } - } - private computeFillableMakerTokenAmountWhenMakerTokenIsZRX(transferrableMakerTokenAmount: BigNumber, - transferrableMakerFeeTokenAmount: BigNumber, - remainingMakerAmount: BigNumber, - remainingMakerFeeAmount: BigNumber, - totalMakerAmount: BigNumber, - makerFeeAmount: BigNumber, - makerTokenAddress: string, - zrxTokenAddress: string): BigNumber { - const totalZRXTransferAmount = remainingMakerAmount.plus(remainingMakerFeeAmount); - const hasSufficientFundsForFeeAndTransferAmount = transferrableMakerTokenAmount.gte(totalZRXTransferAmount); - if (hasSufficientFundsForFeeAndTransferAmount) { - return remainingMakerAmount; - } else { - return this.calculatePartiallyFillableMakerTokenAmount( - transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerAmount, - remainingMakerFeeAmount, totalMakerAmount, makerFeeAmount, makerTokenAddress, - zrxTokenAddress); - } - } - private calculatePartiallyFillableMakerTokenAmount(transferrableMakerTokenAmount: BigNumber, - transferrableMakerFeeTokenAmount: BigNumber, - remainingMakerAmount: BigNumber, - remainingMakerFeeAmount: BigNumber, - totalMakerAmount: BigNumber, makerFeeAmount: BigNumber, - makerTokenAddress: string, zrxTokenAddress: string): BigNumber { - const orderToFeeRatio = totalMakerAmount.dividedToIntegerBy(makerFeeAmount); - const fillableTimesInFeeToken = BigNumber.min(transferrableMakerFeeTokenAmount, remainingMakerFeeAmount); - let fillableTimesInMakerToken = transferrableMakerTokenAmount.dividedToIntegerBy(orderToFeeRatio); - if (makerTokenAddress === zrxTokenAddress) { - // when zrx == maker token transferrable maker == transfer - const totalZRXTokenPooled = transferrableMakerTokenAmount; - fillableTimesInMakerToken = totalZRXTokenPooled.dividedToIntegerBy( - orderToFeeRatio.plus(new BigNumber(1))); - - } - const partiallyFillableMakerTokenAmount = fillableTimesInMakerToken.times(orderToFeeRatio); - const partiallyFillableFeeTokenAmount = fillableTimesInFeeToken.times(orderToFeeRatio); - return BigNumber.min(partiallyFillableMakerTokenAmount, partiallyFillableFeeTokenAmount); - } private validateIfOrderIsValid(signedOrder: SignedOrder, orderRelevantState: OrderRelevantState): void { const unavailableTakerTokenAmount = orderRelevantState.cancelledTakerTokenAmount.add( orderRelevantState.filledTakerTokenAmount, -- cgit v1.2.3