@0x/asset-swapper: Clean up source breakdown code a bit.
`@0x/asset-swapper`: Allow Kyber conflicts in fallback path.
This commit is contained in:
@@ -260,23 +260,23 @@ export function collapsePath(side: MarketOperation, path: Fill[]): CollapsedFill
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getFallbackSourcePaths(optimalPath: Fill[], allPaths: Fill[][]): Fill[][] {
|
export function getFallbackSourcePaths(optimalPath: Fill[], allPaths: Fill[][]): Fill[][] {
|
||||||
let optimalPathFlags = 0;
|
|
||||||
const optimalSources: ERC20BridgeSource[] = [];
|
const optimalSources: ERC20BridgeSource[] = [];
|
||||||
for (const fill of optimalPath) {
|
for (const fill of optimalPath) {
|
||||||
optimalPathFlags |= fill.flags;
|
|
||||||
if (!optimalSources.includes(fill.source)) {
|
if (!optimalSources.includes(fill.source)) {
|
||||||
optimalSources.push(fill.source);
|
optimalSources.push(fill.source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const conflictFlags = FillFlags.Kyber | FillFlags.ConflictsWithKyber;
|
|
||||||
const fallbackPaths: Fill[][] = [];
|
const fallbackPaths: Fill[][] = [];
|
||||||
for (const path of allPaths) {
|
for (const path of allPaths) {
|
||||||
if (((optimalPathFlags | path[0].flags) & conflictFlags) === conflictFlags) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (optimalSources.includes(path[0].source)) {
|
if (optimalSources.includes(path[0].source)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// HACK(dorothy-zbornak): We *should* be filtering out paths that
|
||||||
|
// conflict with the optimal path (i.e., Kyber conflicts), but in
|
||||||
|
// practice we often end up not being able to find a fallback path
|
||||||
|
// because we've lost 2 major liquiduty sources. The end result is
|
||||||
|
// we end up with many more reverts than what would be actually caused
|
||||||
|
// by conflicts.
|
||||||
fallbackPaths.push(path);
|
fallbackPaths.push(path);
|
||||||
}
|
}
|
||||||
return fallbackPaths;
|
return fallbackPaths;
|
||||||
|
|||||||
@@ -285,10 +285,10 @@ export class MarketOperationUtils {
|
|||||||
let fallbackPath: Fill[] = [];
|
let fallbackPath: Fill[] = [];
|
||||||
const nativeSubPath = optimalPath.filter(f => f.source === ERC20BridgeSource.Native);
|
const nativeSubPath = optimalPath.filter(f => f.source === ERC20BridgeSource.Native);
|
||||||
if (opts.allowFallback && nativeSubPath.length !== 0) {
|
if (opts.allowFallback && nativeSubPath.length !== 0) {
|
||||||
// The fallback path is only as large as the native path.
|
// The fallback path is, at most, as large as the native path.
|
||||||
const [nativeInputAmount] = getPathSize(nativeSubPath, inputAmount);
|
const fallbackInputAmount = BigNumber.min(inputAmount, getPathSize(nativeSubPath, inputAmount)[0]);
|
||||||
fallbackPath =
|
fallbackPath =
|
||||||
findOptimalPath(side, getFallbackSourcePaths(optimalPath, paths), nativeInputAmount, opts.runLimit) ||
|
findOptimalPath(side, getFallbackSourcePaths(optimalPath, paths), fallbackInputAmount, opts.runLimit) ||
|
||||||
[];
|
[];
|
||||||
}
|
}
|
||||||
return createOrdersFromPath([...optimalPath, ...fallbackPath], {
|
return createOrdersFromPath([...optimalPath, ...fallbackPath], {
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ export class SwapQuoteCalculator {
|
|||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
const breakdown = this._getSwapQuoteOrdersBreakdown(resultOrders, operation);
|
const breakdown = getSwapQuoteOrdersBreakdown(resultOrders, operation);
|
||||||
|
|
||||||
const quoteBase: SwapQuoteBase = {
|
const quoteBase: SwapQuoteBase = {
|
||||||
takerAssetData,
|
takerAssetData,
|
||||||
@@ -427,36 +427,27 @@ export class SwapQuoteCalculator {
|
|||||||
gas: 0,
|
gas: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// tslint:disable-next-line: prefer-function-over-method
|
function getSwapQuoteOrdersBreakdown(
|
||||||
private _getSwapQuoteOrdersBreakdown(
|
orders: OptimizedMarketOrder[],
|
||||||
orders: OptimizedMarketOrder[],
|
operation: MarketOperation,
|
||||||
operation: MarketOperation,
|
): SwapQuoteOrdersBreakdown {
|
||||||
): SwapQuoteOrdersBreakdown {
|
const orderAmounts =
|
||||||
// HACK: to shut up linter
|
operation === MarketOperation.Buy
|
||||||
const breakdown: SwapQuoteOrdersBreakdown = {};
|
? orders.map(o => o.fill.totalMakerAssetAmount)
|
||||||
|
: orders.map(o => o.fill.totalTakerAssetAmount);
|
||||||
// total asset amount (accounting for slippage protection)
|
const amountsBySource: SwapQuoteOrdersBreakdown = {};
|
||||||
const totalAssetAmount = BigNumber.sum(
|
orders.forEach((o, i) => {
|
||||||
...[
|
const source = o.fill.source;
|
||||||
constants.ZERO_AMOUNT,
|
amountsBySource[source] = orderAmounts[i].plus(amountsBySource[source] || 0);
|
||||||
...orders.map(o => (operation === MarketOperation.Buy ? o.makerAssetAmount : o.takerAssetAmount)),
|
});
|
||||||
],
|
const totalAmount = BigNumber.sum(0, ...orderAmounts);
|
||||||
);
|
const breakdown: SwapQuoteOrdersBreakdown = {};
|
||||||
|
for (const [source, amount] of Object.entries(amountsBySource)) {
|
||||||
return orders.reduce((acc: SwapQuoteOrdersBreakdown, order: OptimizedMarketOrder): SwapQuoteOrdersBreakdown => {
|
breakdown[source] = amount.div(totalAmount);
|
||||||
const assetAmount = operation === MarketOperation.Buy ? order.makerAssetAmount : order.takerAssetAmount;
|
|
||||||
const { source } = order.fill;
|
|
||||||
return {
|
|
||||||
...acc,
|
|
||||||
...{
|
|
||||||
[source]: !!acc[source]
|
|
||||||
? acc[source].plus(assetAmount.dividedBy(totalAssetAmount))
|
|
||||||
: assetAmount.dividedBy(totalAssetAmount),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}, breakdown);
|
|
||||||
}
|
}
|
||||||
|
return breakdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTakerAssetAmountBreakDown(
|
function getTakerAssetAmountBreakDown(
|
||||||
|
|||||||
Reference in New Issue
Block a user