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 4b7b3a5d41..ff176d09dc 100644 --- a/packages/asset-swapper/src/utils/market_operation_utils/index.ts +++ b/packages/asset-swapper/src/utils/market_operation_utils/index.ts @@ -217,16 +217,17 @@ export class MarketOperationUtils { ), ); - const rfqtPromise = !IS_PRICE_AWARE_RFQ_ENABLED && quoteSourceFilters.isAllowed(ERC20BridgeSource.Native) - ? getRfqtIndicativeQuotesAsync( - nativeOrders[0].makerAssetData, - nativeOrders[0].takerAssetData, - MarketOperation.Sell, - takerAmount, - undefined, - _opts, - ) - : Promise.resolve([]); + const rfqtPromise = + !IS_PRICE_AWARE_RFQ_ENABLED && quoteSourceFilters.isAllowed(ERC20BridgeSource.Native) + ? getRfqtIndicativeQuotesAsync( + nativeOrders[0].makerAssetData, + nativeOrders[0].takerAssetData, + MarketOperation.Sell, + takerAmount, + undefined, + _opts, + ) + : Promise.resolve([]); const offChainBalancerPromise = sampleBalancerOffChain ? this._sampler.getBalancerSellQuotesOffChainAsync(makerToken, takerToken, sampleAmounts) @@ -364,16 +365,17 @@ export class MarketOperationUtils { this._liquidityProviderRegistry, ), ); - const rfqtPromise = !IS_PRICE_AWARE_RFQ_ENABLED && quoteSourceFilters.isAllowed(ERC20BridgeSource.Native) - ? getRfqtIndicativeQuotesAsync( - nativeOrders[0].makerAssetData, - nativeOrders[0].takerAssetData, - MarketOperation.Buy, - makerAmount, - undefined, - _opts, - ) - : Promise.resolve([]); + const rfqtPromise = + !IS_PRICE_AWARE_RFQ_ENABLED && quoteSourceFilters.isAllowed(ERC20BridgeSource.Native) + ? getRfqtIndicativeQuotesAsync( + nativeOrders[0].makerAssetData, + nativeOrders[0].takerAssetData, + MarketOperation.Buy, + makerAmount, + undefined, + _opts, + ) + : Promise.resolve([]); const offChainBalancerPromise = sampleBalancerOffChain ? this._sampler.getBalancerBuyQuotesOffChainAsync(makerToken, takerToken, sampleAmounts) : Promise.resolve([]); @@ -675,7 +677,12 @@ export class MarketOperationUtils { // If RFQ liquidity is enabled, make a request to check RFQ liquidity const { rfqt } = _opts; - if (IS_PRICE_AWARE_RFQ_ENABLED && rfqt && rfqt.quoteRequestor && marketSideLiquidity.quoteSourceFilters.isAllowed(ERC20BridgeSource.Native)) { + if ( + IS_PRICE_AWARE_RFQ_ENABLED && + rfqt && + rfqt.quoteRequestor && + marketSideLiquidity.quoteSourceFilters.isAllowed(ERC20BridgeSource.Native) + ) { // Calculate a suggested price. For now, this is simply the overall price of the aggregation. let comparisonPrice: BigNumber | undefined; if (optimizerResult) { diff --git a/packages/asset-swapper/test/market_operation_utils_test.ts b/packages/asset-swapper/test/market_operation_utils_test.ts index 98851fc438..ac952760f0 100644 --- a/packages/asset-swapper/test/market_operation_utils_test.ts +++ b/packages/asset-swapper/test/market_operation_utils_test.ts @@ -725,326 +725,379 @@ describe('MarketOperationUtils tests', () => { } }); - it('getMarketSellOrdersAsync() optimizer will be called once only if RFQ if not defined', IS_PRICE_AWARE_RFQ_ENABLED ? async () => { - const mockedMarketOpUtils = TypeMoq.Mock.ofType( - MarketOperationUtils, - TypeMoq.MockBehavior.Loose, - false, - MOCK_SAMPLER, - contractAddresses, - ORDER_DOMAIN, - ); - mockedMarketOpUtils.callBase = true; + it( + 'getMarketSellOrdersAsync() optimizer will be called once only if RFQ if not defined', + IS_PRICE_AWARE_RFQ_ENABLED + ? async () => { + const mockedMarketOpUtils = TypeMoq.Mock.ofType( + MarketOperationUtils, + TypeMoq.MockBehavior.Loose, + false, + MOCK_SAMPLER, + contractAddresses, + ORDER_DOMAIN, + ); + mockedMarketOpUtils.callBase = true; - // Ensure that `_generateOptimizedOrdersAsync` is only called once - mockedMarketOpUtils - .setup(m => m._generateOptimizedOrdersAsync(TypeMoq.It.isAny(), TypeMoq.It.isAny())) - .returns(async (a, b) => mockedMarketOpUtils.target._generateOptimizedOrdersAsync(a, b)) - .verifiable(TypeMoq.Times.once()); + // Ensure that `_generateOptimizedOrdersAsync` is only called once + mockedMarketOpUtils + .setup(m => m._generateOptimizedOrdersAsync(TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .returns(async (a, b) => mockedMarketOpUtils.target._generateOptimizedOrdersAsync(a, b)) + .verifiable(TypeMoq.Times.once()); - const totalAssetAmount = ORDERS.map(o => o.takerAssetAmount).reduce((a, b) => a.plus(b)); - await mockedMarketOpUtils.object.getMarketSellOrdersAsync(ORDERS, totalAssetAmount, DEFAULT_OPTS); - mockedMarketOpUtils.verifyAll(); - } : undefined); + const totalAssetAmount = ORDERS.map(o => o.takerAssetAmount).reduce((a, b) => a.plus(b)); + await mockedMarketOpUtils.object.getMarketSellOrdersAsync( + ORDERS, + totalAssetAmount, + DEFAULT_OPTS, + ); + mockedMarketOpUtils.verifyAll(); + } + : undefined, + ); - it('optimizer will send in a comparison price to RFQ providers', IS_PRICE_AWARE_RFQ_ENABLED ? async () => { - // Set up mocked quote requestor, will return an order that is better - // than the best of the orders. - const mockedQuoteRequestor = TypeMoq.Mock.ofType(QuoteRequestor, TypeMoq.MockBehavior.Loose, false, {}); + it( + 'optimizer will send in a comparison price to RFQ providers', + IS_PRICE_AWARE_RFQ_ENABLED + ? async () => { + // Set up mocked quote requestor, will return an order that is better + // than the best of the orders. + const mockedQuoteRequestor = TypeMoq.Mock.ofType( + QuoteRequestor, + TypeMoq.MockBehavior.Loose, + false, + {}, + ); - let requestedComparisonPrice: BigNumber | undefined; - mockedQuoteRequestor - .setup(mqr => - mqr.requestRfqtFirmQuotesAsync( - TypeMoq.It.isAny(), - TypeMoq.It.isAny(), - TypeMoq.It.isAny(), - TypeMoq.It.isAny(), - TypeMoq.It.isAny(), - TypeMoq.It.isAny(), - ), - ) - .callback( - ( - _makerAssetData: string, - _takerAssetData: string, - _assetFillAmount: BigNumber, - _marketOperation: MarketOperation, - comparisonPrice: BigNumber | undefined, - _options: RfqtRequestOpts, - ) => { - requestedComparisonPrice = comparisonPrice; - }, - ) - .returns(async () => { - return [ - { - signedOrder: createOrder({ - makerAssetData: MAKER_ASSET_DATA, - takerAssetData: TAKER_ASSET_DATA, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(321, 6), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(1, 18), - }), - }, - ]; - }); + let requestedComparisonPrice: BigNumber | undefined; + mockedQuoteRequestor + .setup(mqr => + mqr.requestRfqtFirmQuotesAsync( + TypeMoq.It.isAny(), + TypeMoq.It.isAny(), + TypeMoq.It.isAny(), + TypeMoq.It.isAny(), + TypeMoq.It.isAny(), + TypeMoq.It.isAny(), + ), + ) + .callback( + ( + _makerAssetData: string, + _takerAssetData: string, + _assetFillAmount: BigNumber, + _marketOperation: MarketOperation, + comparisonPrice: BigNumber | undefined, + _options: RfqtRequestOpts, + ) => { + requestedComparisonPrice = comparisonPrice; + }, + ) + .returns(async () => { + return [ + { + signedOrder: createOrder({ + makerAssetData: MAKER_ASSET_DATA, + takerAssetData: TAKER_ASSET_DATA, + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(321, 6), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(1, 18), + }), + }, + ]; + }); - // Set up sampler, will only return 1 on-chain order - const mockedMarketOpUtils = TypeMoq.Mock.ofType( - MarketOperationUtils, - TypeMoq.MockBehavior.Loose, - false, - MOCK_SAMPLER, - contractAddresses, - ORDER_DOMAIN, - ); - mockedMarketOpUtils.callBase = true; - mockedMarketOpUtils - .setup(mou => - mou.getMarketSellLiquidityAsync(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), - ) - .returns(async () => { - return { - dexQuotes: [], - ethToInputRate: Web3Wrapper.toBaseUnitAmount(1, 18), - ethToOutputRate: Web3Wrapper.toBaseUnitAmount(1, 6), - inputAmount: Web3Wrapper.toBaseUnitAmount(1, 18), - inputToken: MAKER_TOKEN, - outputToken: TAKER_TOKEN, - nativeOrders: [ - createOrder({ - makerAssetData: MAKER_ASSET_DATA, - takerAssetData: TAKER_ASSET_DATA, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(320, 6), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(1, 18), - }), - ], - orderFillableAmounts: [Web3Wrapper.toBaseUnitAmount(1, 18)], - rfqtIndicativeQuotes: [], - side: MarketOperation.Sell, - twoHopQuotes: [], - quoteSourceFilters: new SourceFilters(), - makerTokenDecimals: 6, - takerTokenDecimals: 18, - }; - }); - const result = await mockedMarketOpUtils.object.getMarketSellOrdersAsync( - ORDERS, - Web3Wrapper.toBaseUnitAmount(1, 18), - { - ...DEFAULT_OPTS, - rfqt: { - isIndicative: false, - apiKey: 'foo', - takerAddress: randomAddress(), - intentOnFilling: true, - quoteRequestor: { - requestRfqtFirmQuotesAsync: mockedQuoteRequestor.object.requestRfqtFirmQuotesAsync, - } as any, - }, - }, - ); - expect(result.optimizedOrders.length).to.eql(1); - // tslint:disable-next-line:no-unnecessary-type-assertion - expect(requestedComparisonPrice!.toString()).to.eql('320'); - expect(result.optimizedOrders[0].makerAssetAmount.toString()).to.eql('321000000'); - expect(result.optimizedOrders[0].takerAssetAmount.toString()).to.eql('1000000000000000000'); - } : undefined); + // Set up sampler, will only return 1 on-chain order + const mockedMarketOpUtils = TypeMoq.Mock.ofType( + MarketOperationUtils, + TypeMoq.MockBehavior.Loose, + false, + MOCK_SAMPLER, + contractAddresses, + ORDER_DOMAIN, + ); + mockedMarketOpUtils.callBase = true; + mockedMarketOpUtils + .setup(mou => + mou.getMarketSellLiquidityAsync( + TypeMoq.It.isAny(), + TypeMoq.It.isAny(), + TypeMoq.It.isAny(), + ), + ) + .returns(async () => { + return { + dexQuotes: [], + ethToInputRate: Web3Wrapper.toBaseUnitAmount(1, 18), + ethToOutputRate: Web3Wrapper.toBaseUnitAmount(1, 6), + inputAmount: Web3Wrapper.toBaseUnitAmount(1, 18), + inputToken: MAKER_TOKEN, + outputToken: TAKER_TOKEN, + nativeOrders: [ + createOrder({ + makerAssetData: MAKER_ASSET_DATA, + takerAssetData: TAKER_ASSET_DATA, + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(320, 6), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(1, 18), + }), + ], + orderFillableAmounts: [Web3Wrapper.toBaseUnitAmount(1, 18)], + rfqtIndicativeQuotes: [], + side: MarketOperation.Sell, + twoHopQuotes: [], + quoteSourceFilters: new SourceFilters(), + makerTokenDecimals: 6, + takerTokenDecimals: 18, + }; + }); + const result = await mockedMarketOpUtils.object.getMarketSellOrdersAsync( + ORDERS, + Web3Wrapper.toBaseUnitAmount(1, 18), + { + ...DEFAULT_OPTS, + rfqt: { + isIndicative: false, + apiKey: 'foo', + takerAddress: randomAddress(), + intentOnFilling: true, + quoteRequestor: { + requestRfqtFirmQuotesAsync: + mockedQuoteRequestor.object.requestRfqtFirmQuotesAsync, + } as any, + }, + }, + ); + expect(result.optimizedOrders.length).to.eql(1); + // tslint:disable-next-line:no-unnecessary-type-assertion + expect(requestedComparisonPrice!.toString()).to.eql('320'); + expect(result.optimizedOrders[0].makerAssetAmount.toString()).to.eql('321000000'); + expect(result.optimizedOrders[0].takerAssetAmount.toString()).to.eql('1000000000000000000'); + } + : undefined, + ); - it('getMarketSellOrdersAsync() will not rerun the optimizer if no orders are returned', IS_PRICE_AWARE_RFQ_ENABLED ? async () => { - // Ensure that `_generateOptimizedOrdersAsync` is only called once - const mockedMarketOpUtils = TypeMoq.Mock.ofType( - MarketOperationUtils, - TypeMoq.MockBehavior.Loose, - false, - MOCK_SAMPLER, - contractAddresses, - ORDER_DOMAIN, - ); - mockedMarketOpUtils.callBase = true; - mockedMarketOpUtils - .setup(m => m._generateOptimizedOrdersAsync(TypeMoq.It.isAny(), TypeMoq.It.isAny())) - .returns(async (a, b) => mockedMarketOpUtils.target._generateOptimizedOrdersAsync(a, b)) - .verifiable(TypeMoq.Times.once()); + it( + 'getMarketSellOrdersAsync() will not rerun the optimizer if no orders are returned', + IS_PRICE_AWARE_RFQ_ENABLED + ? async () => { + // Ensure that `_generateOptimizedOrdersAsync` is only called once + const mockedMarketOpUtils = TypeMoq.Mock.ofType( + MarketOperationUtils, + TypeMoq.MockBehavior.Loose, + false, + MOCK_SAMPLER, + contractAddresses, + ORDER_DOMAIN, + ); + mockedMarketOpUtils.callBase = true; + mockedMarketOpUtils + .setup(m => m._generateOptimizedOrdersAsync(TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .returns(async (a, b) => mockedMarketOpUtils.target._generateOptimizedOrdersAsync(a, b)) + .verifiable(TypeMoq.Times.once()); - const requestor = getMockedQuoteRequestor('firm', [], TypeMoq.Times.once()); + const requestor = getMockedQuoteRequestor('firm', [], TypeMoq.Times.once()); - const totalAssetAmount = ORDERS.map(o => o.takerAssetAmount).reduce((a, b) => a.plus(b)); - await mockedMarketOpUtils.object.getMarketSellOrdersAsync(ORDERS, totalAssetAmount, { - ...DEFAULT_OPTS, - rfqt: { - isIndicative: false, - apiKey: 'foo', - takerAddress: randomAddress(), - intentOnFilling: true, - quoteRequestor: { - requestRfqtFirmQuotesAsync: requestor.object.requestRfqtFirmQuotesAsync, - } as any, - }, - }); - mockedMarketOpUtils.verifyAll(); - requestor.verifyAll(); - } : undefined); + const totalAssetAmount = ORDERS.map(o => o.takerAssetAmount).reduce((a, b) => a.plus(b)); + await mockedMarketOpUtils.object.getMarketSellOrdersAsync(ORDERS, totalAssetAmount, { + ...DEFAULT_OPTS, + rfqt: { + isIndicative: false, + apiKey: 'foo', + takerAddress: randomAddress(), + intentOnFilling: true, + quoteRequestor: { + requestRfqtFirmQuotesAsync: requestor.object.requestRfqtFirmQuotesAsync, + } as any, + }, + }); + mockedMarketOpUtils.verifyAll(); + requestor.verifyAll(); + } + : undefined, + ); - it('getMarketSellOrdersAsync() will rerun the optimizer if one or more indicative are returned', IS_PRICE_AWARE_RFQ_ENABLED ? async () => { - const requestor = getMockedQuoteRequestor('indicative', [ORDERS[0], ORDERS[1]], TypeMoq.Times.once()); + it( + 'getMarketSellOrdersAsync() will rerun the optimizer if one or more indicative are returned', + IS_PRICE_AWARE_RFQ_ENABLED + ? async () => { + const requestor = getMockedQuoteRequestor( + 'indicative', + [ORDERS[0], ORDERS[1]], + TypeMoq.Times.once(), + ); - const numOrdersInCall: number[] = []; - const numIndicativeQuotesInCall: number[] = []; + const numOrdersInCall: number[] = []; + const numIndicativeQuotesInCall: number[] = []; - const mockedMarketOpUtils = TypeMoq.Mock.ofType( - MarketOperationUtils, - TypeMoq.MockBehavior.Loose, - false, - MOCK_SAMPLER, - contractAddresses, - ORDER_DOMAIN, - ); - mockedMarketOpUtils.callBase = true; - mockedMarketOpUtils - .setup(m => m._generateOptimizedOrdersAsync(TypeMoq.It.isAny(), TypeMoq.It.isAny())) - .callback(async (msl: MarketSideLiquidity, _opts: GenerateOptimizedOrdersOpts) => { - numOrdersInCall.push(msl.nativeOrders.length); - numIndicativeQuotesInCall.push(msl.rfqtIndicativeQuotes.length); - }) - .returns(async (a, b) => mockedMarketOpUtils.target._generateOptimizedOrdersAsync(a, b)) - .verifiable(TypeMoq.Times.exactly(2)); + const mockedMarketOpUtils = TypeMoq.Mock.ofType( + MarketOperationUtils, + TypeMoq.MockBehavior.Loose, + false, + MOCK_SAMPLER, + contractAddresses, + ORDER_DOMAIN, + ); + mockedMarketOpUtils.callBase = true; + mockedMarketOpUtils + .setup(m => m._generateOptimizedOrdersAsync(TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .callback(async (msl: MarketSideLiquidity, _opts: GenerateOptimizedOrdersOpts) => { + numOrdersInCall.push(msl.nativeOrders.length); + numIndicativeQuotesInCall.push(msl.rfqtIndicativeQuotes.length); + }) + .returns(async (a, b) => mockedMarketOpUtils.target._generateOptimizedOrdersAsync(a, b)) + .verifiable(TypeMoq.Times.exactly(2)); - const totalAssetAmount = ORDERS.map(o => o.takerAssetAmount).reduce((a, b) => a.plus(b)); - await mockedMarketOpUtils.object.getMarketSellOrdersAsync( - ORDERS.slice(2, ORDERS.length), - totalAssetAmount, - { - ...DEFAULT_OPTS, - rfqt: { - isIndicative: true, - apiKey: 'foo', - takerAddress: randomAddress(), - intentOnFilling: true, - quoteRequestor: { - requestRfqtIndicativeQuotesAsync: requestor.object.requestRfqtIndicativeQuotesAsync, - } as any, - }, - }, - ); - mockedMarketOpUtils.verifyAll(); - requestor.verifyAll(); + const totalAssetAmount = ORDERS.map(o => o.takerAssetAmount).reduce((a, b) => a.plus(b)); + await mockedMarketOpUtils.object.getMarketSellOrdersAsync( + ORDERS.slice(2, ORDERS.length), + totalAssetAmount, + { + ...DEFAULT_OPTS, + rfqt: { + isIndicative: true, + apiKey: 'foo', + takerAddress: randomAddress(), + intentOnFilling: true, + quoteRequestor: { + requestRfqtIndicativeQuotesAsync: + requestor.object.requestRfqtIndicativeQuotesAsync, + } as any, + }, + }, + ); + mockedMarketOpUtils.verifyAll(); + requestor.verifyAll(); - // The first and second optimizer call contains same number of RFQ orders. - expect(numOrdersInCall.length).to.eql(2); - expect(numOrdersInCall[0]).to.eql(1); - expect(numOrdersInCall[1]).to.eql(1); + // The first and second optimizer call contains same number of RFQ orders. + expect(numOrdersInCall.length).to.eql(2); + expect(numOrdersInCall[0]).to.eql(1); + expect(numOrdersInCall[1]).to.eql(1); - // The first call to optimizer will have no RFQ indicative quotes. The second call will have - // two indicative quotes. - expect(numIndicativeQuotesInCall.length).to.eql(2); - expect(numIndicativeQuotesInCall[0]).to.eql(0); - expect(numIndicativeQuotesInCall[1]).to.eql(2); - } : undefined); + // The first call to optimizer will have no RFQ indicative quotes. The second call will have + // two indicative quotes. + expect(numIndicativeQuotesInCall.length).to.eql(2); + expect(numIndicativeQuotesInCall[0]).to.eql(0); + expect(numIndicativeQuotesInCall[1]).to.eql(2); + } + : undefined, + ); - it('getMarketSellOrdersAsync() will rerun the optimizer if one or more RFQ orders are returned', IS_PRICE_AWARE_RFQ_ENABLED ? async () => { - const requestor = getMockedQuoteRequestor('firm', [ORDERS[0]], TypeMoq.Times.once()); + it( + 'getMarketSellOrdersAsync() will rerun the optimizer if one or more RFQ orders are returned', + IS_PRICE_AWARE_RFQ_ENABLED + ? async () => { + const requestor = getMockedQuoteRequestor('firm', [ORDERS[0]], TypeMoq.Times.once()); - // Ensure that `_generateOptimizedOrdersAsync` is only called once + // Ensure that `_generateOptimizedOrdersAsync` is only called once - // TODO: Ensure fillable amounts increase too - const numOrdersInCall: number[] = []; - const mockedMarketOpUtils = TypeMoq.Mock.ofType( - MarketOperationUtils, - TypeMoq.MockBehavior.Loose, - false, - MOCK_SAMPLER, - contractAddresses, - ORDER_DOMAIN, - ); - mockedMarketOpUtils.callBase = true; - mockedMarketOpUtils - .setup(m => m._generateOptimizedOrdersAsync(TypeMoq.It.isAny(), TypeMoq.It.isAny())) - .callback(async (msl: MarketSideLiquidity, _opts: GenerateOptimizedOrdersOpts) => { - numOrdersInCall.push(msl.nativeOrders.length); - }) - .returns(async (a, b) => mockedMarketOpUtils.target._generateOptimizedOrdersAsync(a, b)) - .verifiable(TypeMoq.Times.exactly(2)); + // TODO: Ensure fillable amounts increase too + const numOrdersInCall: number[] = []; + const mockedMarketOpUtils = TypeMoq.Mock.ofType( + MarketOperationUtils, + TypeMoq.MockBehavior.Loose, + false, + MOCK_SAMPLER, + contractAddresses, + ORDER_DOMAIN, + ); + mockedMarketOpUtils.callBase = true; + mockedMarketOpUtils + .setup(m => m._generateOptimizedOrdersAsync(TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .callback(async (msl: MarketSideLiquidity, _opts: GenerateOptimizedOrdersOpts) => { + numOrdersInCall.push(msl.nativeOrders.length); + }) + .returns(async (a, b) => mockedMarketOpUtils.target._generateOptimizedOrdersAsync(a, b)) + .verifiable(TypeMoq.Times.exactly(2)); - const totalAssetAmount = ORDERS.map(o => o.takerAssetAmount).reduce((a, b) => a.plus(b)); - await mockedMarketOpUtils.object.getMarketSellOrdersAsync( - ORDERS.slice(1, ORDERS.length), - totalAssetAmount, - { - ...DEFAULT_OPTS, - rfqt: { - isIndicative: false, - apiKey: 'foo', - takerAddress: randomAddress(), - intentOnFilling: true, - quoteRequestor: { - requestRfqtFirmQuotesAsync: requestor.object.requestRfqtFirmQuotesAsync, - } as any, - }, - }, - ); - mockedMarketOpUtils.verifyAll(); - requestor.verifyAll(); - expect(numOrdersInCall.length).to.eql(2); + const totalAssetAmount = ORDERS.map(o => o.takerAssetAmount).reduce((a, b) => a.plus(b)); + await mockedMarketOpUtils.object.getMarketSellOrdersAsync( + ORDERS.slice(1, ORDERS.length), + totalAssetAmount, + { + ...DEFAULT_OPTS, + rfqt: { + isIndicative: false, + apiKey: 'foo', + takerAddress: randomAddress(), + intentOnFilling: true, + quoteRequestor: { + requestRfqtFirmQuotesAsync: requestor.object.requestRfqtFirmQuotesAsync, + } as any, + }, + }, + ); + mockedMarketOpUtils.verifyAll(); + requestor.verifyAll(); + expect(numOrdersInCall.length).to.eql(2); - // The first call to optimizer was without an RFQ order. - // The first call to optimizer was with an extra RFQ order. - expect(numOrdersInCall[0]).to.eql(2); - expect(numOrdersInCall[1]).to.eql(3); - } : undefined); + // The first call to optimizer was without an RFQ order. + // The first call to optimizer was with an extra RFQ order. + expect(numOrdersInCall[0]).to.eql(2); + expect(numOrdersInCall[1]).to.eql(3); + } + : undefined, + ); - it('getMarketSellOrdersAsync() will not raise a NoOptimalPath error if no initial path was found during on-chain DEX optimization, but a path was found after RFQ optimization', IS_PRICE_AWARE_RFQ_ENABLED ? async () => { - let hasFirstOptimizationRun = false; - let hasSecondOptimizationRun = false; - const requestor = getMockedQuoteRequestor('firm', [ORDERS[0], ORDERS[1]], TypeMoq.Times.once()); + it( + 'getMarketSellOrdersAsync() will not raise a NoOptimalPath error if no initial path was found during on-chain DEX optimization, but a path was found after RFQ optimization', + IS_PRICE_AWARE_RFQ_ENABLED + ? async () => { + let hasFirstOptimizationRun = false; + let hasSecondOptimizationRun = false; + const requestor = getMockedQuoteRequestor( + 'firm', + [ORDERS[0], ORDERS[1]], + TypeMoq.Times.once(), + ); - const mockedMarketOpUtils = TypeMoq.Mock.ofType( - MarketOperationUtils, - TypeMoq.MockBehavior.Loose, - false, - MOCK_SAMPLER, - contractAddresses, - ORDER_DOMAIN, - ); - mockedMarketOpUtils.callBase = true; - mockedMarketOpUtils - .setup(m => m._generateOptimizedOrdersAsync(TypeMoq.It.isAny(), TypeMoq.It.isAny())) - .returns(async (msl: MarketSideLiquidity, _opts: GenerateOptimizedOrdersOpts) => { - if (msl.nativeOrders.length === 1) { - hasFirstOptimizationRun = true; - throw new Error(AggregationError.NoOptimalPath); - } else if (msl.nativeOrders.length === 3) { - hasSecondOptimizationRun = true; - return mockedMarketOpUtils.target._generateOptimizedOrdersAsync(msl, _opts); - } else { - throw new Error('Invalid path. this error message should never appear'); - } - }) - .verifiable(TypeMoq.Times.exactly(2)); + const mockedMarketOpUtils = TypeMoq.Mock.ofType( + MarketOperationUtils, + TypeMoq.MockBehavior.Loose, + false, + MOCK_SAMPLER, + contractAddresses, + ORDER_DOMAIN, + ); + mockedMarketOpUtils.callBase = true; + mockedMarketOpUtils + .setup(m => m._generateOptimizedOrdersAsync(TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .returns(async (msl: MarketSideLiquidity, _opts: GenerateOptimizedOrdersOpts) => { + if (msl.nativeOrders.length === 1) { + hasFirstOptimizationRun = true; + throw new Error(AggregationError.NoOptimalPath); + } else if (msl.nativeOrders.length === 3) { + hasSecondOptimizationRun = true; + return mockedMarketOpUtils.target._generateOptimizedOrdersAsync(msl, _opts); + } else { + throw new Error('Invalid path. this error message should never appear'); + } + }) + .verifiable(TypeMoq.Times.exactly(2)); - const totalAssetAmount = ORDERS.map(o => o.takerAssetAmount).reduce((a, b) => a.plus(b)); - await mockedMarketOpUtils.object.getMarketSellOrdersAsync( - ORDERS.slice(2, ORDERS.length), - totalAssetAmount, - { - ...DEFAULT_OPTS, - rfqt: { - isIndicative: false, - apiKey: 'foo', - takerAddress: randomAddress(), - intentOnFilling: true, - quoteRequestor: { - requestRfqtFirmQuotesAsync: requestor.object.requestRfqtFirmQuotesAsync, - } as any, - }, - }, - ); - mockedMarketOpUtils.verifyAll(); - requestor.verifyAll(); + const totalAssetAmount = ORDERS.map(o => o.takerAssetAmount).reduce((a, b) => a.plus(b)); + await mockedMarketOpUtils.object.getMarketSellOrdersAsync( + ORDERS.slice(2, ORDERS.length), + totalAssetAmount, + { + ...DEFAULT_OPTS, + rfqt: { + isIndicative: false, + apiKey: 'foo', + takerAddress: randomAddress(), + intentOnFilling: true, + quoteRequestor: { + requestRfqtFirmQuotesAsync: requestor.object.requestRfqtFirmQuotesAsync, + } as any, + }, + }, + ); + mockedMarketOpUtils.verifyAll(); + requestor.verifyAll(); - expect(hasFirstOptimizationRun).to.eql(true); - expect(hasSecondOptimizationRun).to.eql(true); - } : undefined); + expect(hasFirstOptimizationRun).to.eql(true); + expect(hasSecondOptimizationRun).to.eql(true); + } + : undefined, + ); it('getMarketSellOrdersAsync() will raise a NoOptimalPath error if no path was found during on-chain DEX optimization and RFQ optimization', async () => { const mockedMarketOpUtils = TypeMoq.Mock.ofType(