Return unoptimized quote in SwapQuote (#62)
* return unoptimized alternatives in SwapQuote * refactor: dedupe
This commit is contained in:
parent
475b608338
commit
db81a94adb
@ -84,7 +84,7 @@ export {
|
|||||||
export { artifacts } from './artifacts';
|
export { artifacts } from './artifacts';
|
||||||
export { InsufficientAssetLiquidityError } from './errors';
|
export { InsufficientAssetLiquidityError } from './errors';
|
||||||
export { SwapQuoteConsumer } from './quote_consumers/swap_quote_consumer';
|
export { SwapQuoteConsumer } from './quote_consumers/swap_quote_consumer';
|
||||||
export { getSwapMinBuyAmount } from './quote_consumers/utils';
|
export { getSwapMinBuyAmount, getQuoteInfoMinBuyAmount } from './quote_consumers/utils';
|
||||||
export { SwapQuoter } from './swap_quoter';
|
export { SwapQuoter } from './swap_quoter';
|
||||||
export {
|
export {
|
||||||
AffiliateFee,
|
AffiliateFee,
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { MarketOperation, SwapQuote } from '../types';
|
import { MarketOperation, SwapQuote, SwapQuoteInfo } from '../types';
|
||||||
import { ERC20BridgeSource } from '../utils/market_operation_utils/types';
|
import { ERC20BridgeSource, OptimizedMarketOrder } from '../utils/market_operation_utils/types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the minimum buy token amount for market operations by inferring
|
* Compute the minimum buy token amount for market operations by inferring
|
||||||
@ -31,3 +31,34 @@ export function getSwapMinBuyAmount(quote: SwapQuote): BigNumber {
|
|||||||
}
|
}
|
||||||
return quote.bestCaseQuoteInfo.makerAssetAmount.times(slipRatio).integerValue(BigNumber.ROUND_DOWN);
|
return quote.bestCaseQuoteInfo.makerAssetAmount.times(slipRatio).integerValue(BigNumber.ROUND_DOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `getSwapMinBuyAmount` but operates
|
||||||
|
* on a single quote info instead of using best and worst case
|
||||||
|
* Orders must be derived from the same path as the quote info
|
||||||
|
*/
|
||||||
|
export function getQuoteInfoMinBuyAmount(
|
||||||
|
quoteInfo: SwapQuoteInfo,
|
||||||
|
orders: OptimizedMarketOrder[],
|
||||||
|
marketOperation: MarketOperation,
|
||||||
|
): BigNumber {
|
||||||
|
if (marketOperation === MarketOperation.Buy) {
|
||||||
|
return quoteInfo.makerAssetAmount;
|
||||||
|
}
|
||||||
|
let slipRatio = new BigNumber(1);
|
||||||
|
// Infer the allowed maker asset slippage from any non-native order.
|
||||||
|
for (const o of orders) {
|
||||||
|
if (o.fills.length === 0 || o.fills[0].source === ERC20BridgeSource.Native) {
|
||||||
|
// No slippage on native orders.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const totalFillMakerAssetAmount = BigNumber.sum(...o.fills.map(f => f.output));
|
||||||
|
slipRatio = o.fillableMakerAssetAmount.div(totalFillMakerAssetAmount);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (slipRatio.gte(1)) {
|
||||||
|
// No slippage allowed across all orders.
|
||||||
|
return quoteInfo.makerAssetAmount;
|
||||||
|
}
|
||||||
|
return quoteInfo.makerAssetAmount.times(slipRatio).integerValue(BigNumber.ROUND_DOWN);
|
||||||
|
}
|
||||||
|
@ -191,6 +191,8 @@ export interface SwapQuoteBase {
|
|||||||
worstCaseQuoteInfo: SwapQuoteInfo;
|
worstCaseQuoteInfo: SwapQuoteInfo;
|
||||||
sourceBreakdown: SwapQuoteOrdersBreakdown;
|
sourceBreakdown: SwapQuoteOrdersBreakdown;
|
||||||
quoteReport?: QuoteReport;
|
quoteReport?: QuoteReport;
|
||||||
|
unoptimizedQuoteInfo: SwapQuoteInfo;
|
||||||
|
unoptimizedOrders: OptimizedMarketOrder[];
|
||||||
isTwoHop: boolean;
|
isTwoHop: boolean;
|
||||||
makerTokenDecimals: number;
|
makerTokenDecimals: number;
|
||||||
takerTokenDecimals: number;
|
takerTokenDecimals: number;
|
||||||
|
@ -26,7 +26,7 @@ import {
|
|||||||
createSignedOrdersWithFillableAmounts,
|
createSignedOrdersWithFillableAmounts,
|
||||||
getNativeOrderTokens,
|
getNativeOrderTokens,
|
||||||
} from './orders';
|
} from './orders';
|
||||||
import { findOptimalPathAsync } from './path_optimizer';
|
import { fillsToSortedPaths, findOptimalPathAsync } from './path_optimizer';
|
||||||
import { DexOrderSampler, getSampleAmounts } from './sampler';
|
import { DexOrderSampler, getSampleAmounts } from './sampler';
|
||||||
import { SourceFilters } from './source_filters';
|
import { SourceFilters } from './source_filters';
|
||||||
import {
|
import {
|
||||||
@ -543,6 +543,10 @@ export class MarketOperationUtils {
|
|||||||
exchangeProxyOverhead: opts.exchangeProxyOverhead || (() => ZERO_AMOUNT),
|
exchangeProxyOverhead: opts.exchangeProxyOverhead || (() => ZERO_AMOUNT),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Find the unoptimized best rate to calculate savings from optimizer
|
||||||
|
const unoptimizedPath = fillsToSortedPaths(fills, side, inputAmount, optimizerOpts)[0].collapse(orderOpts);
|
||||||
|
|
||||||
|
// Find the optimal path
|
||||||
const optimalPath = await findOptimalPathAsync(side, fills, inputAmount, opts.runLimit, optimizerOpts);
|
const optimalPath = await findOptimalPathAsync(side, fills, inputAmount, opts.runLimit, optimizerOpts);
|
||||||
const optimalPathRate = optimalPath ? optimalPath.adjustedRate() : ZERO_AMOUNT;
|
const optimalPathRate = optimalPath ? optimalPath.adjustedRate() : ZERO_AMOUNT;
|
||||||
|
|
||||||
@ -559,6 +563,7 @@ export class MarketOperationUtils {
|
|||||||
sourceFlags: SOURCE_FLAGS[ERC20BridgeSource.MultiHop],
|
sourceFlags: SOURCE_FLAGS[ERC20BridgeSource.MultiHop],
|
||||||
marketSideLiquidity,
|
marketSideLiquidity,
|
||||||
adjustedRate: bestTwoHopRate,
|
adjustedRate: bestTwoHopRate,
|
||||||
|
unoptimizedPath,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -591,6 +596,7 @@ export class MarketOperationUtils {
|
|||||||
sourceFlags: collapsedPath.sourceFlags,
|
sourceFlags: collapsedPath.sourceFlags,
|
||||||
marketSideLiquidity,
|
marketSideLiquidity,
|
||||||
adjustedRate: optimalPathRate,
|
adjustedRate: optimalPathRate,
|
||||||
|
unoptimizedPath,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,14 +21,13 @@ export async function findOptimalPathAsync(
|
|||||||
runLimit: number = 2 ** 8,
|
runLimit: number = 2 ** 8,
|
||||||
opts: PathPenaltyOpts = DEFAULT_PATH_PENALTY_OPTS,
|
opts: PathPenaltyOpts = DEFAULT_PATH_PENALTY_OPTS,
|
||||||
): Promise<Path | undefined> {
|
): Promise<Path | undefined> {
|
||||||
const rates = rateBySourcePathId(side, fills, targetInput);
|
|
||||||
const paths = fills.map(singleSourceFills => Path.create(side, singleSourceFills, targetInput, opts));
|
|
||||||
// Sort fill arrays by descending adjusted completed rate.
|
// Sort fill arrays by descending adjusted completed rate.
|
||||||
const sortedPaths = paths.sort((a, b) => b.adjustedCompleteRate().comparedTo(a.adjustedCompleteRate()));
|
const sortedPaths = fillsToSortedPaths(fills, side, targetInput, opts);
|
||||||
if (sortedPaths.length === 0) {
|
if (sortedPaths.length === 0) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
let optimalPath = sortedPaths[0];
|
let optimalPath = sortedPaths[0];
|
||||||
|
const rates = rateBySourcePathId(side, fills, targetInput);
|
||||||
for (const [i, path] of sortedPaths.slice(1).entries()) {
|
for (const [i, path] of sortedPaths.slice(1).entries()) {
|
||||||
optimalPath = mixPaths(side, optimalPath, path, targetInput, runLimit * RUN_LIMIT_DECAY_FACTOR ** i, rates);
|
optimalPath = mixPaths(side, optimalPath, path, targetInput, runLimit * RUN_LIMIT_DECAY_FACTOR ** i, rates);
|
||||||
// Yield to event loop.
|
// Yield to event loop.
|
||||||
@ -37,6 +36,18 @@ export async function findOptimalPathAsync(
|
|||||||
return optimalPath.isComplete() ? optimalPath : undefined;
|
return optimalPath.isComplete() ? optimalPath : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sort fill arrays by descending adjusted completed rate.
|
||||||
|
export function fillsToSortedPaths(
|
||||||
|
fills: Fill[][],
|
||||||
|
side: MarketOperation,
|
||||||
|
targetInput: BigNumber,
|
||||||
|
opts: PathPenaltyOpts,
|
||||||
|
): Path[] {
|
||||||
|
const paths = fills.map(singleSourceFills => Path.create(side, singleSourceFills, targetInput, opts));
|
||||||
|
const sortedPaths = paths.sort((a, b) => b.adjustedCompleteRate().comparedTo(a.adjustedCompleteRate()));
|
||||||
|
return sortedPaths;
|
||||||
|
}
|
||||||
|
|
||||||
function mixPaths(
|
function mixPaths(
|
||||||
side: MarketOperation,
|
side: MarketOperation,
|
||||||
pathA: Path,
|
pathA: Path,
|
||||||
|
@ -6,6 +6,7 @@ import { RfqtFirmQuoteValidator, RfqtRequestOpts, SignedOrderWithFillableAmounts
|
|||||||
import { QuoteRequestor } from '../../utils/quote_requestor';
|
import { QuoteRequestor } from '../../utils/quote_requestor';
|
||||||
import { QuoteReport } from '../quote_report_generator';
|
import { QuoteReport } from '../quote_report_generator';
|
||||||
|
|
||||||
|
import { CollapsedPath } from './path';
|
||||||
import { SourceFilters } from './source_filters';
|
import { SourceFilters } from './source_filters';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -343,6 +344,7 @@ export interface OptimizerResult {
|
|||||||
liquidityDelivered: CollapsedFill[] | DexSample<MultiHopFillData>;
|
liquidityDelivered: CollapsedFill[] | DexSample<MultiHopFillData>;
|
||||||
marketSideLiquidity: MarketSideLiquidity;
|
marketSideLiquidity: MarketSideLiquidity;
|
||||||
adjustedRate: BigNumber;
|
adjustedRate: BigNumber;
|
||||||
|
unoptimizedPath: CollapsedPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OptimizerResultWithReport extends OptimizerResult {
|
export interface OptimizerResultWithReport extends OptimizerResult {
|
||||||
|
@ -22,8 +22,8 @@ import {
|
|||||||
FillData,
|
FillData,
|
||||||
GetMarketOrdersOpts,
|
GetMarketOrdersOpts,
|
||||||
OptimizedMarketOrder,
|
OptimizedMarketOrder,
|
||||||
|
OptimizerResultWithReport,
|
||||||
} from './market_operation_utils/types';
|
} from './market_operation_utils/types';
|
||||||
import { QuoteReport } from './quote_report_generator';
|
|
||||||
import { QuoteFillResult, simulateBestCaseFill, simulateWorstCaseFill } from './quote_simulation';
|
import { QuoteFillResult, simulateBestCaseFill, simulateWorstCaseFill } from './quote_simulation';
|
||||||
import { getTokenFromAssetData, isSupportedAssetDataInOrders } from './utils';
|
import { getTokenFromAssetData, isSupportedAssetDataInOrders } from './utils';
|
||||||
|
|
||||||
@ -98,15 +98,13 @@ export class SwapQuoteCalculator {
|
|||||||
if (result) {
|
if (result) {
|
||||||
const { makerAssetData, takerAssetData } = batchPrunedOrders[i][0];
|
const { makerAssetData, takerAssetData } = batchPrunedOrders[i][0];
|
||||||
return createSwapQuote(
|
return createSwapQuote(
|
||||||
|
result,
|
||||||
makerAssetData,
|
makerAssetData,
|
||||||
takerAssetData,
|
takerAssetData,
|
||||||
result.optimizedOrders,
|
|
||||||
operation,
|
operation,
|
||||||
assetFillAmounts[i],
|
assetFillAmounts[i],
|
||||||
gasPrice,
|
gasPrice,
|
||||||
opts.gasSchedule,
|
opts.gasSchedule,
|
||||||
result.marketSideLiquidity.makerTokenDecimals,
|
|
||||||
result.marketSideLiquidity.takerTokenDecimals,
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -128,12 +126,6 @@ export class SwapQuoteCalculator {
|
|||||||
}
|
}
|
||||||
// since prunedOrders do not have fillState, we will add a buffer of fillable orders to consider that some native are orders are partially filled
|
// since prunedOrders do not have fillState, we will add a buffer of fillable orders to consider that some native are orders are partially filled
|
||||||
|
|
||||||
let optimizedOrders: OptimizedMarketOrder[];
|
|
||||||
let quoteReport: QuoteReport | undefined;
|
|
||||||
let sourceFlags: number = 0;
|
|
||||||
let makerTokenDecimals: number;
|
|
||||||
let takerTokenDecimals: number;
|
|
||||||
|
|
||||||
// Scale fees by gas price.
|
// Scale fees by gas price.
|
||||||
const _opts: GetMarketOrdersOpts = {
|
const _opts: GetMarketOrdersOpts = {
|
||||||
...opts,
|
...opts,
|
||||||
@ -148,60 +140,94 @@ export class SwapQuoteCalculator {
|
|||||||
? await this._marketOperationUtils.getMarketBuyOrdersAsync(prunedOrders, assetFillAmount, _opts)
|
? await this._marketOperationUtils.getMarketBuyOrdersAsync(prunedOrders, assetFillAmount, _opts)
|
||||||
: await this._marketOperationUtils.getMarketSellOrdersAsync(prunedOrders, assetFillAmount, _opts);
|
: await this._marketOperationUtils.getMarketSellOrdersAsync(prunedOrders, assetFillAmount, _opts);
|
||||||
|
|
||||||
optimizedOrders = result.optimizedOrders;
|
|
||||||
quoteReport = result.quoteReport;
|
|
||||||
sourceFlags = result.sourceFlags;
|
|
||||||
makerTokenDecimals = result.marketSideLiquidity.makerTokenDecimals;
|
|
||||||
takerTokenDecimals = result.marketSideLiquidity.takerTokenDecimals;
|
|
||||||
|
|
||||||
// assetData information for the result
|
|
||||||
const { makerAssetData, takerAssetData } = prunedOrders[0];
|
const { makerAssetData, takerAssetData } = prunedOrders[0];
|
||||||
const swapQuote =
|
const swapQuote = createSwapQuote(
|
||||||
sourceFlags === SOURCE_FLAGS[ERC20BridgeSource.MultiHop]
|
result,
|
||||||
? createTwoHopSwapQuote(
|
makerAssetData,
|
||||||
makerAssetData,
|
takerAssetData,
|
||||||
takerAssetData,
|
operation,
|
||||||
optimizedOrders,
|
assetFillAmount,
|
||||||
operation,
|
gasPrice,
|
||||||
assetFillAmount,
|
opts.gasSchedule,
|
||||||
gasPrice,
|
);
|
||||||
opts.gasSchedule,
|
|
||||||
makerTokenDecimals,
|
|
||||||
takerTokenDecimals,
|
|
||||||
quoteReport,
|
|
||||||
)
|
|
||||||
: createSwapQuote(
|
|
||||||
makerAssetData,
|
|
||||||
takerAssetData,
|
|
||||||
optimizedOrders,
|
|
||||||
operation,
|
|
||||||
assetFillAmount,
|
|
||||||
gasPrice,
|
|
||||||
opts.gasSchedule,
|
|
||||||
makerTokenDecimals,
|
|
||||||
takerTokenDecimals,
|
|
||||||
quoteReport,
|
|
||||||
);
|
|
||||||
// Use the raw gas, not scaled by gas price
|
// Use the raw gas, not scaled by gas price
|
||||||
const exchangeProxyOverhead = opts.exchangeProxyOverhead(sourceFlags).toNumber();
|
const exchangeProxyOverhead = opts.exchangeProxyOverhead(result.sourceFlags).toNumber();
|
||||||
swapQuote.bestCaseQuoteInfo.gas += exchangeProxyOverhead;
|
swapQuote.bestCaseQuoteInfo.gas += exchangeProxyOverhead;
|
||||||
swapQuote.worstCaseQuoteInfo.gas += exchangeProxyOverhead;
|
swapQuote.worstCaseQuoteInfo.gas += exchangeProxyOverhead;
|
||||||
|
swapQuote.unoptimizedQuoteInfo.gas += exchangeProxyOverhead;
|
||||||
|
|
||||||
return swapQuote;
|
return swapQuote;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createSwapQuote(
|
function createSwapQuote(
|
||||||
|
optimizerResult: OptimizerResultWithReport,
|
||||||
makerAssetData: string,
|
makerAssetData: string,
|
||||||
takerAssetData: string,
|
takerAssetData: string,
|
||||||
|
operation: MarketOperation,
|
||||||
|
assetFillAmount: BigNumber,
|
||||||
|
gasPrice: BigNumber,
|
||||||
|
gasSchedule: FeeSchedule,
|
||||||
|
): SwapQuote {
|
||||||
|
const { optimizedOrders, quoteReport, sourceFlags, unoptimizedPath } = optimizerResult;
|
||||||
|
const isTwoHop = sourceFlags === SOURCE_FLAGS[ERC20BridgeSource.MultiHop];
|
||||||
|
|
||||||
|
// Calculate quote info
|
||||||
|
const { bestCaseQuoteInfo, worstCaseQuoteInfo, sourceBreakdown } = isTwoHop
|
||||||
|
? calculateTwoHopQuoteInfo(optimizedOrders, operation, gasSchedule)
|
||||||
|
: calculateQuoteInfo(optimizedOrders, operation, assetFillAmount, gasPrice, gasSchedule);
|
||||||
|
|
||||||
|
// Calculate the unoptimised alternative
|
||||||
|
const unoptimizedFillResult = simulateBestCaseFill({
|
||||||
|
gasPrice,
|
||||||
|
orders: unoptimizedPath.orders,
|
||||||
|
side: operation,
|
||||||
|
fillAmount: assetFillAmount,
|
||||||
|
opts: { gasSchedule },
|
||||||
|
});
|
||||||
|
const unoptimizedQuoteInfo = fillResultsToQuoteInfo(unoptimizedFillResult);
|
||||||
|
|
||||||
|
// Put together the swap quote
|
||||||
|
const { makerTokenDecimals, takerTokenDecimals } = optimizerResult.marketSideLiquidity;
|
||||||
|
const swapQuote = {
|
||||||
|
makerAssetData,
|
||||||
|
takerAssetData,
|
||||||
|
gasPrice,
|
||||||
|
orders: optimizedOrders,
|
||||||
|
bestCaseQuoteInfo,
|
||||||
|
worstCaseQuoteInfo,
|
||||||
|
unoptimizedQuoteInfo,
|
||||||
|
unoptimizedOrders: unoptimizedPath.orders,
|
||||||
|
sourceBreakdown,
|
||||||
|
makerTokenDecimals,
|
||||||
|
takerTokenDecimals,
|
||||||
|
quoteReport,
|
||||||
|
isTwoHop,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (operation === MarketOperation.Buy) {
|
||||||
|
return {
|
||||||
|
...swapQuote,
|
||||||
|
type: MarketOperation.Buy,
|
||||||
|
makerAssetFillAmount: assetFillAmount,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
...swapQuote,
|
||||||
|
type: MarketOperation.Sell,
|
||||||
|
takerAssetFillAmount: assetFillAmount,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateQuoteInfo(
|
||||||
optimizedOrders: OptimizedMarketOrder[],
|
optimizedOrders: OptimizedMarketOrder[],
|
||||||
operation: MarketOperation,
|
operation: MarketOperation,
|
||||||
assetFillAmount: BigNumber,
|
assetFillAmount: BigNumber,
|
||||||
gasPrice: BigNumber,
|
gasPrice: BigNumber,
|
||||||
gasSchedule: FeeSchedule,
|
gasSchedule: FeeSchedule,
|
||||||
makerTokenDecimals: number,
|
): { bestCaseQuoteInfo: SwapQuoteInfo; worstCaseQuoteInfo: SwapQuoteInfo; sourceBreakdown: SwapQuoteOrdersBreakdown } {
|
||||||
takerTokenDecimals: number,
|
|
||||||
quoteReport?: QuoteReport,
|
|
||||||
): SwapQuote {
|
|
||||||
const bestCaseFillResult = simulateBestCaseFill({
|
const bestCaseFillResult = simulateBestCaseFill({
|
||||||
gasPrice,
|
gasPrice,
|
||||||
orders: optimizedOrders,
|
orders: optimizedOrders,
|
||||||
@ -218,49 +244,18 @@ function createSwapQuote(
|
|||||||
opts: { gasSchedule },
|
opts: { gasSchedule },
|
||||||
});
|
});
|
||||||
|
|
||||||
const quoteBase = {
|
return {
|
||||||
takerAssetData,
|
|
||||||
makerAssetData,
|
|
||||||
gasPrice,
|
|
||||||
bestCaseQuoteInfo: fillResultsToQuoteInfo(bestCaseFillResult),
|
bestCaseQuoteInfo: fillResultsToQuoteInfo(bestCaseFillResult),
|
||||||
worstCaseQuoteInfo: fillResultsToQuoteInfo(worstCaseFillResult),
|
worstCaseQuoteInfo: fillResultsToQuoteInfo(worstCaseFillResult),
|
||||||
sourceBreakdown: getSwapQuoteOrdersBreakdown(bestCaseFillResult.fillAmountBySource),
|
sourceBreakdown: getSwapQuoteOrdersBreakdown(bestCaseFillResult.fillAmountBySource),
|
||||||
orders: optimizedOrders,
|
|
||||||
quoteReport,
|
|
||||||
isTwoHop: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (operation === MarketOperation.Buy) {
|
|
||||||
return {
|
|
||||||
...quoteBase,
|
|
||||||
type: MarketOperation.Buy,
|
|
||||||
makerAssetFillAmount: assetFillAmount,
|
|
||||||
makerTokenDecimals,
|
|
||||||
takerTokenDecimals,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
...quoteBase,
|
|
||||||
type: MarketOperation.Sell,
|
|
||||||
takerAssetFillAmount: assetFillAmount,
|
|
||||||
makerTokenDecimals,
|
|
||||||
takerTokenDecimals,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTwoHopSwapQuote(
|
function calculateTwoHopQuoteInfo(
|
||||||
makerAssetData: string,
|
|
||||||
takerAssetData: string,
|
|
||||||
optimizedOrders: OptimizedMarketOrder[],
|
optimizedOrders: OptimizedMarketOrder[],
|
||||||
operation: MarketOperation,
|
operation: MarketOperation,
|
||||||
assetFillAmount: BigNumber,
|
|
||||||
gasPrice: BigNumber,
|
|
||||||
gasSchedule: FeeSchedule,
|
gasSchedule: FeeSchedule,
|
||||||
makerTokenDecimals: number,
|
): { bestCaseQuoteInfo: SwapQuoteInfo; worstCaseQuoteInfo: SwapQuoteInfo; sourceBreakdown: SwapQuoteOrdersBreakdown } {
|
||||||
takerTokenDecimals: number,
|
|
||||||
quoteReport?: QuoteReport,
|
|
||||||
): SwapQuote {
|
|
||||||
const [firstHopOrder, secondHopOrder] = optimizedOrders;
|
const [firstHopOrder, secondHopOrder] = optimizedOrders;
|
||||||
const [firstHopFill] = firstHopOrder.fills;
|
const [firstHopFill] = firstHopOrder.fills;
|
||||||
const [secondHopFill] = secondHopOrder.fills;
|
const [secondHopFill] = secondHopOrder.fills;
|
||||||
@ -271,10 +266,7 @@ function createTwoHopSwapQuote(
|
|||||||
}),
|
}),
|
||||||
).toNumber();
|
).toNumber();
|
||||||
|
|
||||||
const quoteBase = {
|
return {
|
||||||
takerAssetData,
|
|
||||||
makerAssetData,
|
|
||||||
gasPrice,
|
|
||||||
bestCaseQuoteInfo: {
|
bestCaseQuoteInfo: {
|
||||||
makerAssetAmount: operation === MarketOperation.Sell ? secondHopFill.output : secondHopFill.input,
|
makerAssetAmount: operation === MarketOperation.Sell ? secondHopFill.output : secondHopFill.input,
|
||||||
takerAssetAmount: operation === MarketOperation.Sell ? firstHopFill.input : firstHopFill.output,
|
takerAssetAmount: operation === MarketOperation.Sell ? firstHopFill.input : firstHopFill.output,
|
||||||
@ -298,28 +290,7 @@ function createTwoHopSwapQuote(
|
|||||||
hops: [firstHopFill.source, secondHopFill.source],
|
hops: [firstHopFill.source, secondHopFill.source],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
orders: optimizedOrders,
|
|
||||||
quoteReport,
|
|
||||||
isTwoHop: true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (operation === MarketOperation.Buy) {
|
|
||||||
return {
|
|
||||||
...quoteBase,
|
|
||||||
type: MarketOperation.Buy,
|
|
||||||
makerAssetFillAmount: assetFillAmount,
|
|
||||||
makerTokenDecimals,
|
|
||||||
takerTokenDecimals,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
...quoteBase,
|
|
||||||
type: MarketOperation.Sell,
|
|
||||||
takerAssetFillAmount: assetFillAmount,
|
|
||||||
makerTokenDecimals,
|
|
||||||
takerTokenDecimals,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSwapQuoteOrdersBreakdown(fillAmountBySource: { [source: string]: BigNumber }): SwapQuoteOrdersBreakdown {
|
function getSwapQuoteOrdersBreakdown(fillAmountBySource: { [source: string]: BigNumber }): SwapQuoteOrdersBreakdown {
|
||||||
|
@ -37,6 +37,8 @@ export async function getFullyFillableSwapQuoteWithNoFeesAsync(
|
|||||||
gasPrice,
|
gasPrice,
|
||||||
bestCaseQuoteInfo: quoteInfo,
|
bestCaseQuoteInfo: quoteInfo,
|
||||||
worstCaseQuoteInfo: quoteInfo,
|
worstCaseQuoteInfo: quoteInfo,
|
||||||
|
unoptimizedQuoteInfo: quoteInfo,
|
||||||
|
unoptimizedOrders: orders.map(order => ({ ...order, fills: [] })),
|
||||||
sourceBreakdown: breakdown,
|
sourceBreakdown: breakdown,
|
||||||
isTwoHop: false,
|
isTwoHop: false,
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user