aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--packages/asset-buyer/src/utils/buy_quote_calculator.ts12
-rw-r--r--packages/asset-buyer/test/buy_quote_calculator_test.ts76
2 files changed, 70 insertions, 18 deletions
diff --git a/packages/asset-buyer/src/utils/buy_quote_calculator.ts b/packages/asset-buyer/src/utils/buy_quote_calculator.ts
index 53f2228e9..5a531e000 100644
--- a/packages/asset-buyer/src/utils/buy_quote_calculator.ts
+++ b/packages/asset-buyer/src/utils/buy_quote_calculator.ts
@@ -92,16 +92,16 @@ function calculateRate(
assetBuyAmount: BigNumber,
feePercentage: number,
): BigNumber {
- // find the total eth and zrx needed to buy assetAmount from the resultOrders from left to right (best rate to worst rate)
- const [minEthAmountToBuyAsset, minZrxAmountToBuyAsset] = findEthAndZrxAmountNeededToBuyAsset(
+ // find the total eth and zrx needed to buy assetAmount from the resultOrders from left to right
+ const [ethAmountToBuyAsset, zrxAmountToBuyAsset] = findEthAndZrxAmountNeededToBuyAsset(
ordersAndFillableAmounts,
assetBuyAmount,
);
// find the total eth needed to buy fees
- const minEthAmountToBuyFees = findEthAmountNeededToBuyFees(feeOrdersAndFillableAmounts, minZrxAmountToBuyAsset);
- const finalMinEthAmount = minEthAmountToBuyAsset.plus(minEthAmountToBuyFees).mul(feePercentage + 1);
+ const ethAmountToBuyFees = findEthAmountNeededToBuyFees(feeOrdersAndFillableAmounts, zrxAmountToBuyAsset);
+ const ethAmount = ethAmountToBuyAsset.plus(ethAmountToBuyFees).mul(feePercentage + 1);
// divide into the assetBuyAmount in order to find rate of makerAsset / WETH
- const result = assetBuyAmount.div(finalMinEthAmount);
+ const result = assetBuyAmount.div(ethAmount);
return result;
}
@@ -156,7 +156,7 @@ function findEthAndZrxAmountNeededToBuyAsset(
const zrxAmountForThisOrder = amountToFill.mul(order.takerFee).dividedToIntegerBy(order.makerAssetAmount);
return {
ethAmount: acc.ethAmount.plus(ethAmountForThisOrder),
- zrxAmount: acc.ethAmount.plus(zrxAmountForThisOrder),
+ zrxAmount: acc.zrxAmount.plus(zrxAmountForThisOrder),
remainingAssetBuyAmount: BigNumber.max(
constants.ZERO_AMOUNT,
acc.remainingAssetBuyAmount.minus(amountToFill),
diff --git a/packages/asset-buyer/test/buy_quote_calculator_test.ts b/packages/asset-buyer/test/buy_quote_calculator_test.ts
index 2cad1ab05..37a429531 100644
--- a/packages/asset-buyer/test/buy_quote_calculator_test.ts
+++ b/packages/asset-buyer/test/buy_quote_calculator_test.ts
@@ -19,7 +19,8 @@ const NULL_BYTES = '0x';
describe('buyQuoteCalculator', () => {
describe('#calculate', () => {
let ordersAndFillableAmounts: OrdersAndFillableAmounts;
- let feeOrdersAndFillableAmounts: OrdersAndFillableAmounts;
+ let smallFeeOrderAndFillableAmount: OrdersAndFillableAmounts;
+ let allFeeOrdersAndFillableAmounts: OrdersAndFillableAmounts;
beforeEach(() => {
// generate two orders for our desired maker asset
// the first order has a rate of 4 makerAsset / WETH with a takerFee of 200 ZRX and has only 200 / 400 makerAsset units left to fill (half fillable)
@@ -60,7 +61,7 @@ describe('buyQuoteCalculator', () => {
orders: signedOrders,
remainingFillableMakerAssetAmounts: [firstRemainingFillAmount, secondRemainingFillAmount],
};
- const feeOrder = orderFactory.createOrder(
+ const smallFeeOrder = orderFactory.createOrder(
NULL_ADDRESS,
new BigNumber(100),
NULL_BYTES,
@@ -68,13 +69,32 @@ describe('buyQuoteCalculator', () => {
NULL_BYTES,
NULL_ADDRESS,
);
- const signedFeeOrder = {
- ...feeOrder,
+ const signedSmallFeeOrder = {
+ ...smallFeeOrder,
signature: NULL_BYTES,
};
- feeOrdersAndFillableAmounts = {
- orders: [signedFeeOrder],
- remainingFillableMakerAssetAmounts: [signedFeeOrder.makerAssetAmount],
+ smallFeeOrderAndFillableAmount = {
+ orders: [signedSmallFeeOrder],
+ remainingFillableMakerAssetAmounts: [signedSmallFeeOrder.makerAssetAmount],
+ };
+ const largeFeeOrder = orderFactory.createOrder(
+ NULL_ADDRESS,
+ new BigNumber(100),
+ NULL_BYTES,
+ new BigNumber(200),
+ NULL_BYTES,
+ NULL_ADDRESS,
+ );
+ const signedLargeFeeOrder = {
+ ...largeFeeOrder,
+ signature: NULL_BYTES,
+ };
+ allFeeOrdersAndFillableAmounts = {
+ orders: [signedSmallFeeOrder, signedLargeFeeOrder],
+ remainingFillableMakerAssetAmounts: [
+ signedSmallFeeOrder.makerAssetAmount,
+ largeFeeOrder.makerAssetAmount,
+ ],
};
});
it('should throw if not enough maker asset liquidity', () => {
@@ -82,7 +102,7 @@ describe('buyQuoteCalculator', () => {
expect(() =>
buyQuoteCalculator.calculate(
ordersAndFillableAmounts,
- feeOrdersAndFillableAmounts,
+ smallFeeOrderAndFillableAmount,
new BigNumber(500),
0,
0,
@@ -94,14 +114,14 @@ describe('buyQuoteCalculator', () => {
expect(() =>
buyQuoteCalculator.calculate(
ordersAndFillableAmounts,
- feeOrdersAndFillableAmounts,
+ smallFeeOrderAndFillableAmount,
new BigNumber(300),
0,
0,
),
).to.throw(AssetBuyerError.InsufficientZrxLiquidity);
});
- it('calculates a correct buyQuote', () => {
+ it('calculates a correct buyQuote with no slippage', () => {
// we request 200 makerAsset units which can be filled using the first order
// the first order requires a fee of 100 ZRX from the taker which can be filled by the feeOrder
const assetBuyAmount = new BigNumber(200);
@@ -109,15 +129,16 @@ describe('buyQuoteCalculator', () => {
const slippagePercentage = 0;
const buyQuote = buyQuoteCalculator.calculate(
ordersAndFillableAmounts,
- feeOrdersAndFillableAmounts,
+ smallFeeOrderAndFillableAmount,
assetBuyAmount,
feePercentage,
slippagePercentage,
);
// test if orders are correct
expect(buyQuote.orders).to.deep.equal([ordersAndFillableAmounts.orders[0]]);
- expect(buyQuote.feeOrders).to.deep.equal([feeOrdersAndFillableAmounts.orders[0]]);
+ expect(buyQuote.feeOrders).to.deep.equal([smallFeeOrderAndFillableAmount.orders[0]]);
// test if rates are correct
+ // 50 eth to fill the first order + 100 eth for fees
const expectedMinEthToFill = new BigNumber(150);
const expectedMinRate = assetBuyAmount.div(expectedMinEthToFill.mul(feePercentage + 1));
expect(buyQuote.minRate).to.bignumber.equal(expectedMinRate);
@@ -126,5 +147,36 @@ describe('buyQuoteCalculator', () => {
// test if feePercentage gets passed through
expect(buyQuote.feePercentage).to.equal(feePercentage);
});
+ it('calculates a correct buyQuote with with slippage', () => {
+ // we request 200 makerAsset units which can be filled using the first order
+ // however with 50% slippage we are protecting the buy with 100 extra makerAssetUnits
+ // so we need enough orders to fill 300 makerAssetUnits
+ // 300 makerAssetUnits can only be filled using both orders
+ // the first order requires a fee of 100 ZRX from the taker which can be filled by the feeOrder
+ const assetBuyAmount = new BigNumber(200);
+ const feePercentage = 0.02;
+ const slippagePercentage = 0.5;
+ const buyQuote = buyQuoteCalculator.calculate(
+ ordersAndFillableAmounts,
+ allFeeOrdersAndFillableAmounts,
+ assetBuyAmount,
+ feePercentage,
+ slippagePercentage,
+ );
+ // test if orders are correct
+ expect(buyQuote.orders).to.deep.equal(ordersAndFillableAmounts.orders);
+ expect(buyQuote.feeOrders).to.deep.equal(allFeeOrdersAndFillableAmounts.orders);
+ // test if rates are correct
+ // 50 eth to fill the first order + 100 eth for fees
+ const expectedMinEthToFill = new BigNumber(150);
+ const expectedMinRate = assetBuyAmount.div(expectedMinEthToFill.mul(feePercentage + 1));
+ expect(buyQuote.minRate).to.bignumber.equal(expectedMinRate);
+ // 100 eth to fill the first order + 200 eth for fees
+ const expectedMaxEthToFill = new BigNumber(300);
+ const expectedMaxRate = assetBuyAmount.div(expectedMaxEthToFill.mul(feePercentage + 1));
+ expect(buyQuote.maxRate).to.bignumber.equal(expectedMaxRate);
+ // test if feePercentage gets passed through
+ expect(buyQuote.feePercentage).to.equal(feePercentage);
+ });
});
});