fix: add separate priceComparisonsReport to fix missing quoteReport data [TKR-91] (#219)

* fix: add separate priceComparisonsReport to fix missing quoteReport data

* chore: remove notice about unconfirmed Uniswap V3 addresses

* refactor: move price comparisons computation logic into separate method

* chore: add AS changelog entry
This commit is contained in:
Kim Persson 2021-05-06 14:54:54 +02:00 committed by GitHub
parent 7d15baad0f
commit 7d34e09a12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 89 additions and 14 deletions

View File

@ -2,9 +2,13 @@
{
"version": "6.11.0",
"changes": [
{
"note": "Add price comparisons data separate from the quote report",
"pr": 219
},
{
"note": "Add caching for top Balancer V2 pools on startup and during regular intervals",
"pr": "228"
"pr": 228
},
{
"note": "Tweak compiler settings for smaller sampler bytecode",

View File

@ -161,6 +161,7 @@ export {
NativeRfqOrderQuoteReportEntry,
QuoteReport,
QuoteReportEntry,
PriceComparisonsReport,
} from './utils/quote_report_generator';
export { QuoteRequestor } from './utils/quote_requestor';
export { ERC20BridgeSamplerContract, BalanceCheckerContract, FakeTakerContract } from './wrappers';

View File

@ -495,7 +495,14 @@ function createSwapQuote(
gasSchedule: FeeSchedule,
slippage: number,
): SwapQuote {
const { optimizedOrders, quoteReport, sourceFlags, takerAmountPerEth, makerAmountPerEth } = optimizerResult;
const {
optimizedOrders,
quoteReport,
sourceFlags,
takerAmountPerEth,
makerAmountPerEth,
priceComparisonsReport,
} = optimizerResult;
const isTwoHop = sourceFlags === SOURCE_FLAGS[ERC20BridgeSource.MultiHop];
// Calculate quote info
@ -519,6 +526,7 @@ function createSwapQuote(
makerAmountPerEth,
quoteReport,
isTwoHop,
priceComparisonsReport,
};
if (operation === MarketOperation.Buy) {

View File

@ -18,7 +18,7 @@ import {
OptimizedMarketOrder,
TokenAdjacencyGraph,
} from './utils/market_operation_utils/types';
import { QuoteReport } from './utils/quote_report_generator';
import { PriceComparisonsReport, QuoteReport } from './utils/quote_report_generator';
/**
* expiryBufferMs: The number of seconds to add when calculating whether an order is expired or not. Defaults to 300s (5m).
@ -169,6 +169,7 @@ export interface SwapQuoteBase {
worstCaseQuoteInfo: SwapQuoteInfo;
sourceBreakdown: SwapQuoteOrdersBreakdown;
quoteReport?: QuoteReport;
priceComparisonsReport?: PriceComparisonsReport;
isTwoHop: boolean;
makerTokenDecimals: number;
takerTokenDecimals: number;

View File

@ -1059,7 +1059,6 @@ export const BALANCER_V2_SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name
export const UNISWAPV3_CONFIG_BY_CHAIN_ID = valueByChainId(
{
// Unconfirmed Mainnet contracts, please confirm
[ChainId.Mainnet]: {
quoter: '0xb27308f9f90d607463bb33ea1bebb41c27ce5ab6',
router: '0xe592427a0aece92de3edee1f18e0157c05861564',
@ -1335,5 +1334,6 @@ export const DEFAULT_GET_MARKET_ORDERS_OPTS: GetMarketOrdersOpts = {
exchangeProxyOverhead: () => ZERO_AMOUNT,
allowFallback: true,
shouldGenerateQuoteReport: true,
shouldIncludePriceComparisonsReport: false,
tokenAdjacencyGraph: { default: [] },
};

View File

@ -16,7 +16,14 @@ import {
getNativeAdjustedMakerFillAmount,
} from '../utils';
import { generateQuoteReport, QuoteReport } from './../quote_report_generator';
import {
dexSampleToReportSource,
generateQuoteReport,
multiHopSampleToReportSource,
nativeOrderToReportEntry,
PriceComparisonsReport,
QuoteReport,
} from './../quote_report_generator';
import { getComparisonPrices } from './comparison_price';
import {
BUY_SOURCE_FILTER_BY_CHAIN_ID,
@ -68,6 +75,27 @@ export class MarketOperationUtils {
return generateQuoteReport(side, quotes.nativeOrders, liquidityDelivered, comparisonPrice, quoteRequestor);
}
private static _computePriceComparisonsReport(
quoteRequestor: QuoteRequestor | undefined,
marketSideLiquidity: MarketSideLiquidity,
comparisonPrice?: BigNumber | undefined,
): PriceComparisonsReport {
const { side, quotes } = marketSideLiquidity;
const dexSources = _.flatten(quotes.dexQuotes).map(quote => dexSampleToReportSource(quote, side));
const multiHopSources = quotes.twoHopQuotes.map(quote => multiHopSampleToReportSource(quote, side));
const nativeSources = quotes.nativeOrders.map(order =>
nativeOrderToReportEntry(
order.type,
order as any,
order.fillableTakerAmount,
comparisonPrice,
quoteRequestor,
),
);
return { dexSources, multiHopSources, nativeSources };
}
constructor(
private readonly _sampler: DexOrderSampler,
private readonly contractAddresses: AssetSwapperContractAddresses,
@ -677,7 +705,16 @@ export class MarketOperationUtils {
wholeOrderPrice,
);
}
return { ...optimizerResult, quoteReport };
let priceComparisonsReport: PriceComparisonsReport | undefined;
if (_opts.shouldIncludePriceComparisonsReport) {
priceComparisonsReport = MarketOperationUtils._computePriceComparisonsReport(
_opts.rfqt ? _opts.rfqt.quoteRequestor : undefined,
marketSideLiquidity,
wholeOrderPrice,
);
}
return { ...optimizerResult, quoteReport, priceComparisonsReport };
}
private async _refreshPoolCacheIfRequiredAsync(takerToken: string, makerToken: string): Promise<void> {

View File

@ -9,7 +9,7 @@ import { BigNumber } from '@0x/utils';
import { NativeOrderWithFillableAmounts, RfqFirmQuoteValidator, RfqRequestOpts } from '../../types';
import { QuoteRequestor } from '../../utils/quote_requestor';
import { QuoteReport } from '../quote_report_generator';
import { PriceComparisonsReport, QuoteReport } from '../quote_report_generator';
import { CollapsedPath } from './path';
import { SourceFilters } from './source_filters';
@ -401,6 +401,11 @@ export interface GetMarketOrdersOpts {
* Whether to generate a quote report
*/
shouldGenerateQuoteReport: boolean;
/**
* Whether to include price comparison data in the quote
*/
shouldIncludePriceComparisonsReport: boolean;
/**
* Token addresses with a list of adjacent intermediary tokens to consider
* hopping to. E.g DAI->USDC via an adjacent token WETH
@ -435,6 +440,7 @@ export interface OptimizerResult {
export interface OptimizerResultWithReport extends OptimizerResult {
quoteReport?: QuoteReport;
priceComparisonsReport?: PriceComparisonsReport;
}
export type MarketDepthSide = Array<Array<DexSample<FillData>>>;

View File

@ -60,6 +60,12 @@ export interface QuoteReport {
sourcesDelivered: QuoteReportEntry[];
}
export interface PriceComparisonsReport {
dexSources: BridgeQuoteReportEntry[];
multiHopSources: MultiHopQuoteReportEntry[];
nativeSources: Array<NativeLimitOrderQuoteReportEntry | NativeRfqOrderQuoteReportEntry>;
}
/**
* Generates a report of sources considered while computing the optimized
* swap quote, and the sources ultimately included in the computed quote.
@ -72,7 +78,7 @@ export function generateQuoteReport(
quoteRequestor?: QuoteRequestor,
): QuoteReport {
const nativeOrderSourcesConsidered = nativeOrders.map(order =>
_nativeOrderToReportEntry(order.type, order as any, order.fillableTakerAmount, comparisonPrice, quoteRequestor),
nativeOrderToReportEntry(order.type, order as any, order.fillableTakerAmount, comparisonPrice, quoteRequestor),
);
const sourcesConsidered = [...nativeOrderSourcesConsidered.filter(order => order.isRfqt)];
@ -87,7 +93,7 @@ export function generateQuoteReport(
// map sources delivered
sourcesDelivered = liquidityDelivered.map(collapsedFill => {
if (_isNativeOrderFromCollapsedFill(collapsedFill)) {
return _nativeOrderToReportEntry(
return nativeOrderToReportEntry(
collapsedFill.type,
collapsedFill.fillData,
nativeOrderSignaturesToFillableAmounts[_nativeDataToId(collapsedFill.fillData)],
@ -95,13 +101,13 @@ export function generateQuoteReport(
quoteRequestor,
);
} else {
return _dexSampleToReportSource(collapsedFill, marketOperation);
return dexSampleToReportSource(collapsedFill, marketOperation);
}
});
} else {
sourcesDelivered = [
// tslint:disable-next-line: no-unnecessary-type-assertion
_multiHopSampleToReportSource(liquidityDelivered as DexSample<MultiHopFillData>, marketOperation),
multiHopSampleToReportSource(liquidityDelivered as DexSample<MultiHopFillData>, marketOperation),
];
}
return {
@ -115,7 +121,11 @@ function _nativeDataToId(data: { signature: Signature }): string {
return `${v}${r}${s}`;
}
function _dexSampleToReportSource(ds: DexSample, marketOperation: MarketOperation): BridgeQuoteReportEntry {
/**
* Generates a report sample for a DEX source
* NOTE: this is used for the QuoteReport and quote price comparison data
*/
export function dexSampleToReportSource(ds: DexSample, marketOperation: MarketOperation): BridgeQuoteReportEntry {
const liquiditySource = ds.source;
if (liquiditySource === ERC20BridgeSource.Native) {
@ -143,7 +153,11 @@ function _dexSampleToReportSource(ds: DexSample, marketOperation: MarketOperatio
}
}
function _multiHopSampleToReportSource(
/**
* Generates a report sample for a MultiHop source
* NOTE: this is used for the QuoteReport and quote price comparison data
*/
export function multiHopSampleToReportSource(
ds: DexSample<MultiHopFillData>,
marketOperation: MarketOperation,
): MultiHopQuoteReportEntry {
@ -176,7 +190,11 @@ function _isNativeOrderFromCollapsedFill(cf: CollapsedFill): cf is NativeCollaps
return type === FillQuoteTransformerOrderType.Limit || type === FillQuoteTransformerOrderType.Rfq;
}
function _nativeOrderToReportEntry(
/**
* Generates a report entry for a native order
* NOTE: this is used for the QuoteReport and quote price comparison data
*/
export function nativeOrderToReportEntry(
type: FillQuoteTransformerOrderType,
fillData: NativeLimitOrderFillData | NativeRfqOrderFillData,
fillableAmount: BigNumber,