diff --git a/packages/asset-swapper/src/index.ts b/packages/asset-swapper/src/index.ts index 0e3e273728..184f15066e 100644 --- a/packages/asset-swapper/src/index.ts +++ b/packages/asset-swapper/src/index.ts @@ -103,6 +103,7 @@ export { MockedRfqtFirmQuoteResponse, OrderPrunerPermittedFeeTypes, RfqtMakerAssetOfferings, + RfqtFirmQuoteValidator, RfqtRequestOpts, SamplerOverrides, SignedOrderWithFillableAmounts, diff --git a/packages/asset-swapper/src/types.ts b/packages/asset-swapper/src/types.ts index de7ef036c0..8b038ee587 100644 --- a/packages/asset-swapper/src/types.ts +++ b/packages/asset-swapper/src/types.ts @@ -295,6 +295,10 @@ export interface RfqtMakerAssetOfferings { export type LogFunction = (obj: object, msg?: string, ...args: any[]) => void; +export interface RfqtFirmQuoteValidator { + getRFQTTakerFillableAmounts(quotes: SignedOrder[]): Promise; +} + export interface SwapQuoterRfqtOpts { takerApiKeyWhitelist: string[]; makerAssetOfferings: RfqtMakerAssetOfferings; diff --git a/packages/asset-swapper/src/utils/market_operation_utils/index.ts b/packages/asset-swapper/src/utils/market_operation_utils/index.ts index fdc6dc871c..ed9889d420 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/index.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/index.ts @@ -683,20 +683,24 @@ export class MarketOperationUtils { rfqt, ); if (firmQuotes.length > 0) { + // Compute the RFQ order fillable amounts. This is done by performing a "soft" order + // validation and by checking order balances that are monitored by our worker. + // If a firm quote validator does not exist, then we assume that all orders are valid. + const firmQuoteSignedOrders = firmQuotes.map(quote => quote.signedOrder); + const rfqOrderFillableAmounts = + rfqt.firmQuoteValidator === undefined + ? firmQuoteSignedOrders.map(signedOrder => signedOrder.takerAssetAmount) + : await rfqt.firmQuoteValidator.getRFQTTakerFillableAmounts(firmQuoteSignedOrders); + // Re-run optimizer with the new firm quote. This is the second and last time // we run the optimized in a block of code. In this case, we don't catch a potential `NoOptimalPath` exception // and we let it bubble up if it happens. - // - // NOTE: as of now, we assume that RFQ orders are 100% fillable because these are trusted market makers, therefore - // we do not perform an extra check to get fillable taker amounts. optimizerResult = await this._generateOptimizedOrdersAsync( { ...marketSideLiquidity, - nativeOrders: marketSideLiquidity.nativeOrders.concat( - firmQuotes.map(quote => quote.signedOrder), - ), + nativeOrders: marketSideLiquidity.nativeOrders.concat(firmQuoteSignedOrders), orderFillableAmounts: marketSideLiquidity.orderFillableAmounts.concat( - firmQuotes.map(quote => quote.signedOrder.takerAssetAmount), + rfqOrderFillableAmounts, ), }, optimizerOpts, diff --git a/packages/asset-swapper/src/utils/market_operation_utils/types.ts b/packages/asset-swapper/src/utils/market_operation_utils/types.ts index 67aed749e8..536f8988ec 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/types.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/types.ts @@ -2,7 +2,7 @@ import { RFQTIndicativeQuote } from '@0x/quote-server'; import { MarketOperation, SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; -import { RfqtRequestOpts, SignedOrderWithFillableAmounts } from '../../types'; +import { RfqtFirmQuoteValidator, RfqtRequestOpts, SignedOrderWithFillableAmounts } from '../../types'; import { QuoteRequestor } from '../../utils/quote_requestor'; import { QuoteReport } from '../quote_report_generator'; @@ -239,6 +239,7 @@ export interface OptimizedMarketOrder extends SignedOrderWithFillableAmounts { export interface GetMarketOrdersRfqtOpts extends RfqtRequestOpts { quoteRequestor?: QuoteRequestor; + firmQuoteValidator?: RfqtFirmQuoteValidator; } export type FeeEstimate = (fillData?: FillData) => number | BigNumber;