adds amendments to the rollout feature flag. Rollout indicative quote… (#30)

* adds amendments to the rollout feature flag. Rollout indicative quotes indipendently from firm quotes.

* Updates based on Brandon's feedback
This commit is contained in:
Daniel Pyrathon 2020-11-05 12:46:06 -08:00 committed by GitHub
parent c3ad42221e
commit 36bd8f68c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 54 additions and 20 deletions

View File

@ -90,7 +90,10 @@ const DEFAULT_SWAP_QUOTE_REQUEST_OPTS: SwapQuoteRequestOpts = {
const DEFAULT_RFQT_REQUEST_OPTS: Partial<RfqtRequestOpts> = {
makerEndpointMaxResponseTimeMs: 1000,
isPriceAwareRFQEnabled: false,
priceAwareRFQFlag: {
isFirmPriceAwareEnabled: false,
isIndicativePriceAwareEnabled: false,
},
};
export const DEFAULT_INFO_LOGGER: LogFunction = (obj, msg) =>

View File

@ -41,6 +41,7 @@ import { ProtocolFeeUtils } from './utils/protocol_fee_utils';
import { QuoteRequestor } from './utils/quote_requestor';
import { sortingUtils } from './utils/sorting_utils';
import { SwapQuoteCalculator } from './utils/swap_quote_calculator';
import { getPriceAwareRFQRolloutFlags } from './utils/utils';
import { ERC20BridgeSamplerContract } from './wrappers';
export class SwapQuoter {
@ -700,7 +701,7 @@ export class SwapQuoter {
if (
opts.rfqt && // This is an RFQT-enabled API request
!opts.rfqt.isPriceAwareRFQEnabled && // If Price-aware RFQ is enabled, firm quotes are requested later on in the process.
!getPriceAwareRFQRolloutFlags(opts.rfqt.priceAwareRFQFlag).isFirmPriceAwareEnabled && // If Price-aware RFQ is enabled, firm quotes are requested later on in the process.
opts.rfqt.intentOnFilling && // The requestor is asking for a firm quote
opts.rfqt.apiKey &&
this._isApiKeyWhitelisted(opts.rfqt.apiKey) && // A valid API key was provided

View File

@ -234,6 +234,11 @@ export type SwapQuoteOrdersBreakdown = Partial<
}
>;
export interface PriceAwareRFQFlags {
isIndicativePriceAwareEnabled: boolean;
isFirmPriceAwareEnabled: boolean;
}
/**
* nativeExclusivelyRFQT: if set to `true`, Swap quote will exclude Open Orderbook liquidity.
* If set to `true` and `ERC20BridgeSource.Native` is part of the `excludedSources`
@ -256,7 +261,7 @@ export interface RfqtRequestOpts {
* the feature flag. When that time comes, follow this PR to "undo" the feature flag:
* https://github.com/0xProject/0x-monorepo/pull/2735
*/
isPriceAwareRFQEnabled?: boolean;
priceAwareRFQFlag?: PriceAwareRFQFlags;
}
/**

View File

@ -6,6 +6,7 @@ import * as _ from 'lodash';
import { AssetSwapperContractAddresses, MarketOperation, Omit } from '../../types';
import { QuoteRequestor } from '../quote_requestor';
import { getPriceAwareRFQRolloutFlags } from '../utils';
import { generateQuoteReport, QuoteReport } from './../quote_report_generator';
import {
@ -214,7 +215,8 @@ export class MarketOperationUtils {
),
);
const isPriceAwareRfqEnabled = _opts.rfqt && _opts.rfqt.isPriceAwareRFQEnabled;
const isPriceAwareRfqEnabled =
_opts.rfqt && getPriceAwareRFQRolloutFlags(_opts.rfqt.priceAwareRFQFlag).isIndicativePriceAwareEnabled;
const rfqtPromise =
!isPriceAwareRfqEnabled && quoteSourceFilters.isAllowed(ERC20BridgeSource.Native)
? getRfqtIndicativeQuotesAsync(
@ -362,7 +364,8 @@ export class MarketOperationUtils {
this._liquidityProviderRegistry,
),
);
const isPriceAwareRfqEnabled = _opts.rfqt && _opts.rfqt.isPriceAwareRFQEnabled;
const isPriceAwareRfqEnabled =
_opts.rfqt && getPriceAwareRFQRolloutFlags(_opts.rfqt.priceAwareRFQFlag).isIndicativePriceAwareEnabled;
const rfqtPromise =
!isPriceAwareRfqEnabled && quoteSourceFilters.isAllowed(ERC20BridgeSource.Native)
? getRfqtIndicativeQuotesAsync(
@ -677,12 +680,7 @@ export class MarketOperationUtils {
// If RFQ liquidity is enabled, make a request to check RFQ liquidity
let comparisonPrice: BigNumber | undefined;
const { rfqt } = _opts;
if (
rfqt &&
rfqt.isPriceAwareRFQEnabled &&
rfqt.quoteRequestor &&
marketSideLiquidity.quoteSourceFilters.isAllowed(ERC20BridgeSource.Native)
) {
if (rfqt && rfqt.quoteRequestor && marketSideLiquidity.quoteSourceFilters.isAllowed(ERC20BridgeSource.Native)) {
// Calculate a suggested price. For now, this is simply the overall price of the aggregation.
if (optimizerResult) {
const totalMakerAmount = BigNumber.sum(
@ -706,8 +704,12 @@ export class MarketOperationUtils {
}
}
// If we are making an indicative quote, make the RFQT request and then re-run the sampler if new orders come back.
if (rfqt.isIndicative) {
const { isFirmPriceAwareEnabled, isIndicativePriceAwareEnabled } = getPriceAwareRFQRolloutFlags(
rfqt.priceAwareRFQFlag,
);
if (rfqt.isIndicative && isIndicativePriceAwareEnabled) {
// An indicative quote is beingh requested, and indicative quotes price-aware enabled. Make the RFQT request and then re-run the sampler if new orders come back.
const indicativeQuotes = await getRfqtIndicativeQuotesAsync(
nativeOrders[0].makerAssetData,
nativeOrders[0].takerAssetData,
@ -726,8 +728,8 @@ export class MarketOperationUtils {
optimizerOpts,
);
}
} else {
// A firm quote is being requested. Ensure that `intentOnFilling` is enabled.
} else if (!rfqt.isIndicative && isFirmPriceAwareEnabled) {
// A firm quote is being requested, and firm quotes price-aware enabled. Ensure that `intentOnFilling` is enabled.
if (rfqt.intentOnFilling) {
// Extra validation happens when requesting a firm quote, such as ensuring that the takerAddress
// is indeed valid.

View File

@ -4,9 +4,27 @@ import { BigNumber, NULL_BYTES } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { constants } from '../constants';
import { PriceAwareRFQFlags } from '../types';
// tslint:disable: no-unnecessary-type-assertion completed-docs
/**
* Returns 2 flags (one for firm quotes and another for indicative quotes) that serve as rollout flags for the price-aware RFQ feature.
* By default, indicative quotes should *always* go through the new price-aware flow. This means that all indicative RFQ requests made to
* market makers will contain the new price-aware `suggestedPrice` field.
* The `isPriceAwareRFQEnabled` feature object that is passed in by the 0x API will then control whether firm quotes go through price-aware RFQ.
*
* @param isPriceAwareRFQEnabled the feature flag that is passed in by the 0x API.
*/
export function getPriceAwareRFQRolloutFlags(priceAwareRFQFlags?: PriceAwareRFQFlags): PriceAwareRFQFlags {
return priceAwareRFQFlags !== undefined
? priceAwareRFQFlags
: {
isFirmPriceAwareEnabled: false,
isIndicativePriceAwareEnabled: false,
};
}
export function isSupportedAssetDataInOrders(orders: SignedOrder[]): boolean {
const firstOrderMakerAssetData = !!orders[0]
? assetDataUtils.decodeAssetDataOrThrow(orders[0].makerAssetData)

View File

@ -17,6 +17,7 @@ import * as _ from 'lodash';
import * as TypeMoq from 'typemoq';
import { MarketOperation, QuoteRequestor, RfqtRequestOpts, SignedOrderWithFillableAmounts } from '../src';
import { PriceAwareRFQFlags } from '../src/types';
import { getRfqtIndicativeQuotesAsync, MarketOperationUtils } from '../src/utils/market_operation_utils/';
import { BalancerPoolsCache } from '../src/utils/market_operation_utils/balancer_utils';
import {
@ -66,6 +67,10 @@ const DEFAULT_EXCLUDED = [
const BUY_SOURCES = BUY_SOURCE_FILTER.sources;
const SELL_SOURCES = SELL_SOURCE_FILTER.sources;
const TOKEN_ADJACENCY_GRAPH: TokenAdjacencyGraph = {};
const PRICE_AWARE_RFQ_ENABLED: PriceAwareRFQFlags = {
isFirmPriceAwareEnabled: true,
isIndicativePriceAwareEnabled: true,
};
// tslint:disable: custom-no-magic-numbers promise-function-async
describe('MarketOperationUtils tests', () => {
@ -891,7 +896,7 @@ describe('MarketOperationUtils tests', () => {
apiKey: 'foo',
takerAddress: randomAddress(),
intentOnFilling: true,
isPriceAwareRFQEnabled: true,
priceAwareRFQFlag: PRICE_AWARE_RFQ_ENABLED,
quoteRequestor: {
requestRfqtFirmQuotesAsync: mockedQuoteRequestor.object.requestRfqtFirmQuotesAsync,
} as any,
@ -931,7 +936,7 @@ describe('MarketOperationUtils tests', () => {
apiKey: 'foo',
takerAddress: randomAddress(),
intentOnFilling: true,
isPriceAwareRFQEnabled: true,
priceAwareRFQFlag: PRICE_AWARE_RFQ_ENABLED,
quoteRequestor: {
requestRfqtFirmQuotesAsync: requestor.object.requestRfqtFirmQuotesAsync,
} as any,
@ -974,7 +979,7 @@ describe('MarketOperationUtils tests', () => {
rfqt: {
isIndicative: true,
apiKey: 'foo',
isPriceAwareRFQEnabled: true,
priceAwareRFQFlag: PRICE_AWARE_RFQ_ENABLED,
takerAddress: randomAddress(),
intentOnFilling: true,
quoteRequestor: {
@ -1033,7 +1038,7 @@ describe('MarketOperationUtils tests', () => {
apiKey: 'foo',
takerAddress: randomAddress(),
intentOnFilling: true,
isPriceAwareRFQEnabled: true,
priceAwareRFQFlag: PRICE_AWARE_RFQ_ENABLED,
quoteRequestor: {
requestRfqtFirmQuotesAsync: requestor.object.requestRfqtFirmQuotesAsync,
} as any,
@ -1089,7 +1094,7 @@ describe('MarketOperationUtils tests', () => {
isIndicative: false,
apiKey: 'foo',
takerAddress: randomAddress(),
isPriceAwareRFQEnabled: true,
priceAwareRFQFlag: PRICE_AWARE_RFQ_ENABLED,
intentOnFilling: true,
quoteRequestor: {
requestRfqtFirmQuotesAsync: requestor.object.requestRfqtFirmQuotesAsync,