@0x/asset-swapper: respect max slippage in EP consumer

This commit is contained in:
Lawrence Forman 2020-09-23 15:52:44 -04:00
parent a57cf68ee4
commit 6138955f93
3 changed files with 36 additions and 2 deletions

View File

@ -129,6 +129,10 @@
{ {
"note": "Fix Balancer sampling", "note": "Fix Balancer sampling",
"pr": 2711 "pr": 2711
},
{
"note": "Respect max slippage in EP consumer",
"pr": 2712
} }
] ]
}, },

View File

@ -30,6 +30,8 @@ import { assert } from '../utils/assert';
import { ERC20BridgeSource, UniswapV2FillData } from '../utils/market_operation_utils/types'; import { ERC20BridgeSource, UniswapV2FillData } from '../utils/market_operation_utils/types';
import { getTokenFromAssetData } from '../utils/utils'; import { getTokenFromAssetData } from '../utils/utils';
import { getMinBuyAmount } from './utils';
// tslint:disable-next-line:custom-no-magic-numbers // tslint:disable-next-line:custom-no-magic-numbers
const MAX_UINT256 = new BigNumber(2).pow(256).minus(1); const MAX_UINT256 = new BigNumber(2).pow(256).minus(1);
const { NULL_ADDRESS, ZERO_AMOUNT } = constants; const { NULL_ADDRESS, ZERO_AMOUNT } = constants;
@ -93,6 +95,7 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
const sellToken = getTokenFromAssetData(quote.takerAssetData); const sellToken = getTokenFromAssetData(quote.takerAssetData);
const buyToken = getTokenFromAssetData(quote.makerAssetData); const buyToken = getTokenFromAssetData(quote.makerAssetData);
const sellAmount = quote.worstCaseQuoteInfo.totalTakerAssetAmount; const sellAmount = quote.worstCaseQuoteInfo.totalTakerAssetAmount;
const minBuyAmount = getMinBuyAmount(quote);
// VIP routes. // VIP routes.
if (isDirectUniswapCompatible(quote, optsWithDefaults)) { if (isDirectUniswapCompatible(quote, optsWithDefaults)) {
@ -111,7 +114,7 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
return a; return a;
}), }),
sellAmount, sellAmount,
quote.worstCaseQuoteInfo.makerAssetAmount, minBuyAmount,
source === ERC20BridgeSource.SushiSwap, source === ERC20BridgeSource.SushiSwap,
) )
.getABIEncodedTransactionData(), .getABIEncodedTransactionData(),
@ -225,7 +228,6 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
}), }),
}); });
const minBuyAmount = BigNumber.max(0, quote.worstCaseQuoteInfo.makerAssetAmount.minus(buyTokenFeeAmount));
const calldataHexString = this._exchangeProxy const calldataHexString = this._exchangeProxy
.transformERC20( .transformERC20(
isFromETH ? ETH_TOKEN_ADDRESS : sellToken, isFromETH ? ETH_TOKEN_ADDRESS : sellToken,

View File

@ -0,0 +1,28 @@
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
import { MarketOperation, SwapQuote } from '../types';
/**
* Compute the mminimum buy token amount for market operations by inferring
* the slippage from the orders in a quote. We cannot rely on
* `worstCaseQuoteInfo.makerAssetAmount` because that does not stop at
* maximum slippage.
*/
export function getMinBuyAmount(quote: SwapQuote): BigNumber {
// Infer the allowed maker asset slippage from the orders.
const totalOrderMakerAssetAmount = BigNumber.sum(...quote.orders.map(o => o.makerAssetAmount));
const totalFillMakerAssetAmount =
quote.type === MarketOperation.Sell
? BigNumber.sum(...quote.orders.map(o => BigNumber.sum(0, ...o.fills.map(f => f.output))))
: BigNumber.sum(...quote.orders.map(o => BigNumber.sum(0, ...o.fills.map(f => f.input))));
if (totalFillMakerAssetAmount.eq(0)) {
return quote.worstCaseQuoteInfo.makerAssetAmount;
}
if (totalOrderMakerAssetAmount.eq(totalFillMakerAssetAmount)) {
// No slippage allowed on bought tokens.
return quote.bestCaseQuoteInfo.makerAssetAmount;
}
const slipRatio = totalOrderMakerAssetAmount.div(totalFillMakerAssetAmount);
return quote.bestCaseQuoteInfo.makerAssetAmount.times(slipRatio).integerValue(BigNumber.ROUND_DOWN);
}