Move order_utils from asset-buyer to order-utils package
This commit is contained in:
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "6.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Moves order_utils into `@0x/order-utils` package as `orderCalculationUtils`",
|
||||
"pr": 1714
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1553183790,
|
||||
"version": "6.0.5",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { HttpClient } from '@0x/connect';
|
||||
import { orderCalculationUtils } from '@0x/order-utils';
|
||||
import { APIOrder, AssetPairsResponse, OrderbookResponse } from '@0x/types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -10,7 +11,6 @@ import {
|
||||
SignedOrderWithRemainingFillableMakerAssetAmount,
|
||||
} from '../types';
|
||||
import { assert } from '../utils/assert';
|
||||
import { orderUtils } from '../utils/order_utils';
|
||||
|
||||
export class StandardRelayerAPIOrderProvider implements OrderProvider {
|
||||
public readonly apiUrl: string;
|
||||
@@ -31,7 +31,7 @@ export class StandardRelayerAPIOrderProvider implements OrderProvider {
|
||||
'remainingTakerAssetAmount',
|
||||
order.takerAssetAmount,
|
||||
);
|
||||
const remainingFillableMakerAssetAmount = orderUtils.getRemainingMakerAmount(
|
||||
const remainingFillableMakerAssetAmount = orderCalculationUtils.getMakerFillAmount(
|
||||
order,
|
||||
remainingFillableTakerAssetAmount,
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { marketUtils, SignedOrder } from '@0x/order-utils';
|
||||
import { marketUtils, orderCalculationUtils, SignedOrder } from '@0x/order-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -6,8 +6,6 @@ import { constants } from '../constants';
|
||||
import { InsufficientAssetLiquidityError } from '../errors';
|
||||
import { AssetBuyerError, BuyQuote, BuyQuoteInfo, OrdersAndFillableAmounts } from '../types';
|
||||
|
||||
import { orderUtils } from './order_utils';
|
||||
|
||||
// Calculates a buy quote for orders that have WETH as the takerAsset
|
||||
export const buyQuoteCalculator = {
|
||||
calculate(
|
||||
@@ -166,7 +164,7 @@ function findEthAmountNeededToBuyZrx(
|
||||
const { totalEthAmount, remainingZrxBuyAmount } = acc;
|
||||
const remainingFillableMakerAssetAmount = remainingFillableMakerAssetAmounts[index];
|
||||
const makerFillAmount = BigNumber.min(remainingZrxBuyAmount, remainingFillableMakerAssetAmount);
|
||||
const [takerFillAmount, adjustedMakerFillAmount] = orderUtils.getTakerFillAmountForFeeOrder(
|
||||
const [takerFillAmount, adjustedMakerFillAmount] = orderCalculationUtils.getTakerFillAmountForFeeOrder(
|
||||
order,
|
||||
makerFillAmount,
|
||||
);
|
||||
@@ -200,8 +198,8 @@ function findEthAndZrxAmountNeededToBuyAsset(
|
||||
const { totalEthAmount, totalZrxAmount, remainingAssetBuyAmount } = acc;
|
||||
const remainingFillableMakerAssetAmount = remainingFillableMakerAssetAmounts[index];
|
||||
const makerFillAmount = BigNumber.min(acc.remainingAssetBuyAmount, remainingFillableMakerAssetAmount);
|
||||
const takerFillAmount = orderUtils.getTakerFillAmount(order, makerFillAmount);
|
||||
const takerFeeAmount = orderUtils.getTakerFeeAmount(order, takerFillAmount);
|
||||
const takerFillAmount = orderCalculationUtils.getTakerFillAmount(order, makerFillAmount);
|
||||
const takerFeeAmount = orderCalculationUtils.getTakerFeeAmount(order, takerFillAmount);
|
||||
return {
|
||||
totalEthAmount: totalEthAmount.plus(takerFillAmount),
|
||||
totalZrxAmount: totalZrxAmount.plus(takerFeeAmount),
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { orderCalculationUtils } from '@0x/order-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
import { LiquidityForAssetData, OrdersAndFillableAmounts } from '../types';
|
||||
|
||||
import { orderUtils } from './order_utils';
|
||||
|
||||
export const calculateLiquidity = (ordersAndFillableAmounts: OrdersAndFillableAmounts): LiquidityForAssetData => {
|
||||
const { orders, remainingFillableMakerAssetAmounts } = ordersAndFillableAmounts;
|
||||
const liquidityInBigNumbers = orders.reduce(
|
||||
@@ -14,7 +13,10 @@ export const calculateLiquidity = (ordersAndFillableAmounts: OrdersAndFillableAm
|
||||
}
|
||||
|
||||
const tokensAvailableForCurrentOrder = availableMakerAssetAmount;
|
||||
const ethValueAvailableForCurrentOrder = orderUtils.getTakerFillAmount(order, availableMakerAssetAmount);
|
||||
const ethValueAvailableForCurrentOrder = orderCalculationUtils.getTakerFillAmount(
|
||||
order,
|
||||
availableMakerAssetAmount,
|
||||
);
|
||||
return {
|
||||
tokensAvailableInBaseUnits: acc.tokensAvailableInBaseUnits.plus(tokensAvailableForCurrentOrder),
|
||||
ethValueAvailableInWei: acc.ethValueAvailableInWei.plus(ethValueAvailableForCurrentOrder),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { OrderAndTraderInfo, OrderStatus, OrderValidatorWrapper } from '@0x/contract-wrappers';
|
||||
import { sortingUtils } from '@0x/order-utils';
|
||||
import { orderCalculationUtils, sortingUtils } from '@0x/order-utils';
|
||||
import { RemainingFillableCalculator } from '@0x/order-utils/lib/src/remaining_fillable_calculator';
|
||||
import { SignedOrder } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
@@ -14,8 +14,6 @@ import {
|
||||
SignedOrderWithRemainingFillableMakerAssetAmount,
|
||||
} from '../types';
|
||||
|
||||
import { orderUtils } from './order_utils';
|
||||
|
||||
export const orderProviderResponseProcessor = {
|
||||
throwIfInvalidResponse(response: OrderProviderResponse, request: OrderProviderRequest): void {
|
||||
const { makerAssetData, takerAssetData } = request;
|
||||
@@ -83,7 +81,10 @@ function filterOutExpiredAndNonOpenOrders(
|
||||
expiryBufferSeconds: number,
|
||||
): SignedOrderWithRemainingFillableMakerAssetAmount[] {
|
||||
const result = _.filter(orders, order => {
|
||||
return orderUtils.isOpenOrder(order) && !orderUtils.willOrderExpire(order, expiryBufferSeconds);
|
||||
return (
|
||||
orderCalculationUtils.isOpenOrder(order) &&
|
||||
!orderCalculationUtils.willOrderExpire(order, expiryBufferSeconds)
|
||||
);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
@@ -112,7 +113,10 @@ function getValidOrdersWithRemainingFillableMakerAssetAmountsFromOnChain(
|
||||
const transferrableAssetAmount = BigNumber.min(traderInfo.makerAllowance, traderInfo.makerBalance);
|
||||
const transferrableFeeAssetAmount = BigNumber.min(traderInfo.makerZrxAllowance, traderInfo.makerZrxBalance);
|
||||
const remainingTakerAssetAmount = order.takerAssetAmount.minus(orderInfo.orderTakerAssetFilledAmount);
|
||||
const remainingMakerAssetAmount = orderUtils.getRemainingMakerAmount(order, remainingTakerAssetAmount);
|
||||
const remainingMakerAssetAmount = orderCalculationUtils.getMakerFillAmount(
|
||||
order,
|
||||
remainingTakerAssetAmount,
|
||||
);
|
||||
const remainingFillableCalculator = new RemainingFillableCalculator(
|
||||
order.makerFee,
|
||||
order.makerAssetAmount,
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
import { SignedOrder } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
import { constants } from '../constants';
|
||||
|
||||
export const orderUtils = {
|
||||
isOrderExpired(order: SignedOrder): boolean {
|
||||
return orderUtils.willOrderExpire(order, 0);
|
||||
},
|
||||
willOrderExpire(order: SignedOrder, secondsFromNow: number): boolean {
|
||||
const millisecondsInSecond = 1000;
|
||||
const currentUnixTimestampSec = new BigNumber(Date.now() / millisecondsInSecond).integerValue();
|
||||
return order.expirationTimeSeconds.isLessThan(currentUnixTimestampSec.plus(secondsFromNow));
|
||||
},
|
||||
isOpenOrder(order: SignedOrder): boolean {
|
||||
return order.takerAddress === constants.NULL_ADDRESS;
|
||||
},
|
||||
// given a remaining amount of takerAsset, calculate how much makerAsset is available
|
||||
getRemainingMakerAmount(order: SignedOrder, remainingTakerAmount: BigNumber): BigNumber {
|
||||
const remainingMakerAmount = remainingTakerAmount
|
||||
.times(order.makerAssetAmount)
|
||||
.div(order.takerAssetAmount)
|
||||
.integerValue(BigNumber.ROUND_FLOOR);
|
||||
return remainingMakerAmount;
|
||||
},
|
||||
// given a desired amount of makerAsset, calculate how much takerAsset is required to fill that amount
|
||||
getTakerFillAmount(order: SignedOrder, makerFillAmount: BigNumber): BigNumber {
|
||||
// Round up because exchange rate favors Maker
|
||||
const takerFillAmount = makerFillAmount
|
||||
.multipliedBy(order.takerAssetAmount)
|
||||
.div(order.makerAssetAmount)
|
||||
.integerValue(BigNumber.ROUND_CEIL);
|
||||
return takerFillAmount;
|
||||
},
|
||||
// given a desired amount of takerAsset to fill, calculate how much fee is required by the taker to fill that amount
|
||||
getTakerFeeAmount(order: SignedOrder, takerFillAmount: BigNumber): BigNumber {
|
||||
// Round down because Taker fee rate favors Taker
|
||||
const takerFeeAmount = takerFillAmount
|
||||
.multipliedBy(order.takerFee)
|
||||
.div(order.takerAssetAmount)
|
||||
.integerValue(BigNumber.ROUND_FLOOR);
|
||||
return takerFeeAmount;
|
||||
},
|
||||
// given a desired amount of takerAsset to fill, calculate how much makerAsset will be filled
|
||||
getMakerFillAmount(order: SignedOrder, takerFillAmount: BigNumber): BigNumber {
|
||||
// Round down because exchange rate favors Maker
|
||||
const makerFillAmount = takerFillAmount
|
||||
.multipliedBy(order.makerAssetAmount)
|
||||
.div(order.takerAssetAmount)
|
||||
.integerValue(BigNumber.ROUND_FLOOR);
|
||||
return makerFillAmount;
|
||||
},
|
||||
// given a desired amount of makerAsset, calculate how much fee is required by the maker to fill that amount
|
||||
getMakerFeeAmount(order: SignedOrder, makerFillAmount: BigNumber): BigNumber {
|
||||
// Round down because Maker fee rate favors Maker
|
||||
const makerFeeAmount = makerFillAmount
|
||||
.multipliedBy(order.makerFee)
|
||||
.div(order.makerAssetAmount)
|
||||
.integerValue(BigNumber.ROUND_FLOOR);
|
||||
return makerFeeAmount;
|
||||
},
|
||||
// given a desired amount of ZRX from a fee order, calculate how much takerAsset is required to fill that amount
|
||||
// also calculate how much ZRX needs to be bought in order fill the desired amount + takerFee
|
||||
getTakerFillAmountForFeeOrder(order: SignedOrder, makerFillAmount: BigNumber): [BigNumber, BigNumber] {
|
||||
// For each unit of TakerAsset we buy (MakerAsset - TakerFee)
|
||||
const adjustedTakerFillAmount = makerFillAmount
|
||||
.multipliedBy(order.takerAssetAmount)
|
||||
.div(order.makerAssetAmount.minus(order.takerFee))
|
||||
.integerValue(BigNumber.ROUND_CEIL);
|
||||
// The amount that we buy will be greater than makerFillAmount, since we buy some amount for fees.
|
||||
const adjustedMakerFillAmount = orderUtils.getMakerFillAmount(order, adjustedTakerFillAmount);
|
||||
return [adjustedTakerFillAmount, adjustedMakerFillAmount];
|
||||
},
|
||||
};
|
||||
@@ -1211,7 +1211,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
}
|
||||
/**
|
||||
* Validate the transfer from the Maker to the Taker. This is simulated on chain
|
||||
* via an eth_call. If this call fails the asset is unlikely to be transferrable.
|
||||
* via an eth_call. If this call fails the asset is not transferrable.
|
||||
* @param signedOrder SignedOrder of interest
|
||||
* @param fillTakerAssetAmount Amount we'd like to fill the order for
|
||||
* @param takerAddress The taker of the order, defaults to signedOrder.takerAddress
|
||||
|
||||
@@ -317,6 +317,39 @@ describe('ExchangeWrapper', () => {
|
||||
}),
|
||||
).to.eventually.to.be.rejected();
|
||||
});
|
||||
it('should throw when the maker does not have enough balance for the remaining order amount', async () => {
|
||||
const makerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress);
|
||||
// Change maker balance to have less than the order amount
|
||||
const remainingBalance = makerBalance.minus(signedOrder.makerAssetAmount.minus(1));
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await contractWrappers.erc20Token.transferAsync(
|
||||
makerTokenAddress,
|
||||
makerAddress,
|
||||
constants.NULL_ADDRESS,
|
||||
remainingBalance,
|
||||
),
|
||||
);
|
||||
return expect(
|
||||
contractWrappers.exchange.validateOrderFillableOrThrowAsync(signedOrder),
|
||||
).to.eventually.to.be.rejected();
|
||||
});
|
||||
it('should validate the order when remaining order amount has some fillable amount', async () => {
|
||||
const makerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress);
|
||||
// Change maker balance to have less than the order amount
|
||||
const remainingBalance = makerBalance.minus(signedOrder.makerAssetAmount.minus(1));
|
||||
await web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await contractWrappers.erc20Token.transferAsync(
|
||||
makerTokenAddress,
|
||||
makerAddress,
|
||||
constants.NULL_ADDRESS,
|
||||
remainingBalance,
|
||||
),
|
||||
);
|
||||
// An amount is still transferrable
|
||||
await contractWrappers.exchange.validateOrderFillableOrThrowAsync(signedOrder, {
|
||||
validateRemainingOrderAmountIsFillable: false,
|
||||
});
|
||||
});
|
||||
it('should throw when the ERC20 token has transfer restrictions', async () => {
|
||||
const untransferrableToken = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
|
||||
UntransferrableDummyERC20Token,
|
||||
|
||||
@@ -5,6 +5,48 @@ import { constants } from './constants';
|
||||
import { BalanceAndAllowance } from './types';
|
||||
|
||||
export const orderCalculationUtils = {
|
||||
/**
|
||||
* Determines if the order is expired given the current time
|
||||
* @param order The order for expiry calculation
|
||||
*/
|
||||
isOrderExpired(order: Order): boolean {
|
||||
return orderCalculationUtils.willOrderExpire(order, 0);
|
||||
},
|
||||
/**
|
||||
* Calculates if the order will expire in the future.
|
||||
* @param order The order for expiry calculation
|
||||
* @param secondsFromNow The amount of seconds from current time
|
||||
*/
|
||||
willOrderExpire(order: Order, secondsFromNow: number): boolean {
|
||||
const millisecondsInSecond = 1000;
|
||||
const currentUnixTimestampSec = new BigNumber(Date.now() / millisecondsInSecond).integerValue();
|
||||
return order.expirationTimeSeconds.isLessThan(currentUnixTimestampSec.plus(secondsFromNow));
|
||||
},
|
||||
/**
|
||||
* Determines if the order is open and fillable by any taker.
|
||||
* @param order The order
|
||||
*/
|
||||
isOpenOrder(order: Order): boolean {
|
||||
return order.takerAddress === constants.NULL_ADDRESS;
|
||||
},
|
||||
/**
|
||||
* Given an amount of taker asset, calculate the the amount of maker asset
|
||||
* @param order The order
|
||||
* @param makerFillAmount the amount of taker asset
|
||||
*/
|
||||
getMakerFillAmount(order: Order, takerFillAmount: BigNumber): BigNumber {
|
||||
// Round down because exchange rate favors Maker
|
||||
const makerFillAmount = takerFillAmount
|
||||
.multipliedBy(order.makerAssetAmount)
|
||||
.div(order.takerAssetAmount)
|
||||
.integerValue(BigNumber.ROUND_FLOOR);
|
||||
return makerFillAmount;
|
||||
},
|
||||
/**
|
||||
* Given an amount of maker asset, calculate the equivalent amount in taker asset
|
||||
* @param order The order
|
||||
* @param makerFillAmount the amount of maker asset
|
||||
*/
|
||||
getTakerFillAmount(order: Order, makerFillAmount: BigNumber): BigNumber {
|
||||
// Round up because exchange rate favors Maker
|
||||
const takerFillAmount = makerFillAmount
|
||||
@@ -13,14 +55,47 @@ export const orderCalculationUtils = {
|
||||
.integerValue(BigNumber.ROUND_CEIL);
|
||||
return takerFillAmount;
|
||||
},
|
||||
// given a desired amount of takerAsset to fill, calculate how much makerAsset will be filled
|
||||
getMakerFillAmount(order: Order, takerFillAmount: BigNumber): BigNumber {
|
||||
// Round down because exchange rate favors Maker
|
||||
const makerFillAmount = takerFillAmount
|
||||
.multipliedBy(order.makerAssetAmount)
|
||||
/**
|
||||
* Given an amount of taker asset, calculate the fee amount required for the taker
|
||||
* @param order The order
|
||||
* @param takerFillAmount the amount of taker asset
|
||||
*/
|
||||
getTakerFeeAmount(order: Order, takerFillAmount: BigNumber): BigNumber {
|
||||
// Round down because Taker fee rate favors Taker
|
||||
const takerFeeAmount = takerFillAmount
|
||||
.multipliedBy(order.takerFee)
|
||||
.div(order.takerAssetAmount)
|
||||
.integerValue(BigNumber.ROUND_FLOOR);
|
||||
return makerFillAmount;
|
||||
return takerFeeAmount;
|
||||
},
|
||||
/**
|
||||
* Given an amount of maker asset, calculate the fee amount required for the maker
|
||||
* @param order The order
|
||||
* @param makerFillAmount the amount of maker asset
|
||||
*/
|
||||
getMakerFeeAmount(order: Order, makerFillAmount: BigNumber): BigNumber {
|
||||
// Round down because Maker fee rate favors Maker
|
||||
const makerFeeAmount = makerFillAmount
|
||||
.multipliedBy(order.makerFee)
|
||||
.div(order.makerAssetAmount)
|
||||
.integerValue(BigNumber.ROUND_FLOOR);
|
||||
return makerFeeAmount;
|
||||
},
|
||||
/**
|
||||
* Given a desired amount of ZRX from a fee order, calculate the amount of taker asset required to fill.
|
||||
* Also calculate how much ZRX needs to be purchased in order to fill the desired amount plus the taker fee amount
|
||||
* @param order The order
|
||||
* @param makerFillAmount the amount of maker asset
|
||||
*/
|
||||
getTakerFillAmountForFeeOrder(order: Order, makerFillAmount: BigNumber): [BigNumber, BigNumber] {
|
||||
// For each unit of TakerAsset we buy (MakerAsset - TakerFee)
|
||||
const adjustedTakerFillAmount = makerFillAmount
|
||||
.multipliedBy(order.takerAssetAmount)
|
||||
.div(order.makerAssetAmount.minus(order.takerFee))
|
||||
.integerValue(BigNumber.ROUND_CEIL);
|
||||
// The amount that we buy will be greater than makerFillAmount, since we buy some amount for fees.
|
||||
const adjustedMakerFillAmount = orderCalculationUtils.getMakerFillAmount(order, adjustedTakerFillAmount);
|
||||
return [adjustedTakerFillAmount, adjustedMakerFillAmount];
|
||||
},
|
||||
/**
|
||||
* Calculates the remaining fillable amount for an order given:
|
||||
|
||||
Reference in New Issue
Block a user