Skip to content

Commit

Permalink
feat: add IRfqClient (#467)
Browse files Browse the repository at this point in the history
  • Loading branch information
phil-ociraptor authored and Noah Khamliche committed Jun 15, 2022
1 parent f395be9 commit 300a649
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 17 deletions.
14 changes: 14 additions & 0 deletions packages/asset-swapper/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,20 @@ export {
} from './types';
export { affiliateFeeUtils } from './utils/affiliate_fee_utils';
export {
<<<<<<< HEAD
=======
IRfqClient,
RfqClientV1Price,
RfqClientV1PriceRequest,
RfqClientV1PriceResponse,
RfqClientV1Quote,
RfqClientV1QuoteRequest,
RfqClientV1QuoteResponse,
} from './utils/irfq_client';
export {
DEFAULT_TOKEN_ADJACENCY_GRAPH_BY_CHAIN_ID,
DEFAULT_GAS_SCHEDULE,
>>>>>>> a7f23a982 (feat: add IRfqClient (#467))
SOURCE_FLAGS,
BUY_SOURCE_FILTER_BY_CHAIN_ID,
SELL_SOURCE_FILTER_BY_CHAIN_ID,
Expand Down
3 changes: 3 additions & 0 deletions packages/asset-swapper/src/swap_quoter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
SwapQuoterRfqOpts,
} from './types';
import { assert } from './utils/assert';
import { IRfqClient } from './utils/irfq_client';
import { MarketOperationUtils } from './utils/market_operation_utils';
import { ZERO_AMOUNT } from './utils/market_operation_utils/constants';
import { SamplerClient } from './utils/market_operation_utils/sampler';
Expand Down Expand Up @@ -287,6 +288,7 @@ export class SwapQuoter {
assetFillAmount: BigNumber,
marketOperation: MarketOperation,
options: Partial<SwapQuoteRequestOpts>,
rfqClient: IRfqClient | undefined,
): Promise<SwapQuote> {
assert.isETHAddressHex('makerToken', makerToken);
assert.isETHAddressHex('takerToken', takerToken);
Expand Down Expand Up @@ -336,6 +338,7 @@ export class SwapQuoter {
this.expiryBufferMs,
rfqtOptions?.metricsProxy,
);
calcOpts.rfqt.rfqClient = rfqClient;
}

const result: OptimizerResultWithReport = await this._marketOperationUtils.getOptimizerResultAsync(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ import {

const SUCCESS_CODE = 201;

function getAltMarketInfo(
/**
* Returns the AltOffering if it exists for a given pair
*/
export function getAltMarketInfo(
offerings: AltOffering[],
buyTokenAddress: string,
sellTokenAddress: string,
Expand Down
59 changes: 59 additions & 0 deletions packages/asset-swapper/src/utils/irfq_client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { RfqOrder, Signature } from '@0x/protocol-utils';
import { BigNumber } from '@0x/utils';

import { AltRfqMakerAssetOfferings } from '../types';

export interface RfqClientV1PriceRequest {
altRfqAssetOfferings: AltRfqMakerAssetOfferings | undefined;
assetFillAmount: BigNumber;
chainId: number;
comparisonPrice: BigNumber | undefined;
integratorId: string;
intentOnFilling: boolean;
makerToken: string;
marketOperation: 'Sell' | 'Buy';
takerAddress: string;
takerToken: string;
txOrigin: string;
}

export interface RfqClientV1QuoteRequest extends RfqClientV1PriceRequest {}

export interface RfqClientV1Price {
expiry: BigNumber;
kind: 'rfq' | 'otc';
makerAmount: BigNumber;
makerToken: string;
makerUri: string;
takerAmount: BigNumber;
takerToken: string;
}

export interface RfqClientV1PriceResponse {
prices: RfqClientV1Price[];
}

export interface RfqClientV1Quote {
makerUri: string;
order: RfqOrder;
signature: Signature;
}

export interface RfqClientV1QuoteResponse {
quotes: RfqClientV1Quote[];
}

/**
* IRfqClient is an interface that defines how to connect with an Rfq system.
*/
export interface IRfqClient {
/**
* Fetches a list of "indicative quotes" or prices from a remote Rfq server
*/
getV1PricesAsync(request: RfqClientV1PriceRequest): Promise<RfqClientV1PriceResponse>;

/**
* Fetches a list of "firm quotes" or signed quotes from a remote Rfq server.
*/
getV1QuotesAsync(request: RfqClientV1QuoteRequest): Promise<RfqClientV1QuoteResponse>;
}
96 changes: 80 additions & 16 deletions packages/asset-swapper/src/utils/market_operation_utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,30 @@ import * as _ from 'lodash';

import { DEFAULT_INFO_LOGGER, INVALID_SIGNATURE } from '../../constants';
import {
<<<<<<< HEAD
Address,
=======
AltRfqMakerAssetOfferings,
>>>>>>> a7f23a982 (feat: add IRfqClient (#467))
AssetSwapperContractAddresses,
MarketOperation,
SamplerMetrics,
SignedNativeOrder,
SignedRfqOrder,
} from '../../types';
<<<<<<< HEAD
import { NativeOrderWithFillableAmounts } from '../native_orders';
import { QuoteRequestor } from '../quote_requestor';
=======
import { getAltMarketInfo } from '../alt_mm_implementation_utils';
import { QuoteRequestor, V4RFQIndicativeQuoteMM } from '../quote_requestor';
import { toSignedNativeOrder } from '../rfq_client_mappers';
import {
getNativeAdjustedFillableAmountsFromMakerAmount,
getNativeAdjustedFillableAmountsFromTakerAmount,
getNativeAdjustedMakerFillAmount,
} from '../utils';
>>>>>>> a7f23a982 (feat: add IRfqClient (#467))

import {
dexSampleToReportSource,
Expand Down Expand Up @@ -751,17 +766,49 @@ export class MarketOperationUtils {
// Timing of RFQT lifecycle
const timeStart = new Date().getTime();
const { makerToken, takerToken } = nativeOrders[0].order;

// Filter Alt Rfq Maker Asset Offerings to the current pair
const filteredOfferings: AltRfqMakerAssetOfferings = {};
if (rfqt.altRfqAssetOfferings) {
const endpoints = Object.keys(rfqt.altRfqAssetOfferings);
for (const endpoint of endpoints) {
// Get the current pair if being offered
const offering = getAltMarketInfo(rfqt.altRfqAssetOfferings[endpoint], makerToken, takerToken);
if (offering) {
filteredOfferings[endpoint] = [offering];
}
}
}

if (rfqt.isIndicative) {
// An indicative quote is being 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 rfqt.quoteRequestor.requestRfqtIndicativeQuotesAsync(
makerToken,
takerToken,
amount,
side,
wholeOrderPrice,
rfqt,
);

const indicativeQuotes =
rfqt.rfqClient !== undefined
? ((
await rfqt.rfqClient.getV1PricesAsync({
altRfqAssetOfferings: filteredOfferings,
assetFillAmount: amount,
chainId: this._sampler.chainId,
comparisonPrice: wholeOrderPrice,
integratorId: rfqt.integrator.integratorId,
intentOnFilling: rfqt.intentOnFilling,
makerToken,
marketOperation: side,
takerAddress: rfqt.takerAddress,
takerToken,
txOrigin: rfqt.txOrigin,
})
).prices as V4RFQIndicativeQuoteMM[])
: await rfqt.quoteRequestor.requestRfqtIndicativeQuotesAsync(
makerToken,
takerToken,
amount,
side,
wholeOrderPrice,
rfqt,
);
const deltaTime = new Date().getTime() - timeStart;
DEFAULT_INFO_LOGGER({
rfqQuoteType: 'indicative',
Expand All @@ -781,14 +828,31 @@ export class MarketOperationUtils {
} else {
// A firm quote is being requested, and firm quotes price-aware enabled.
// Ensure that `intentOnFilling` is enabled and make the request.
const firmQuotes = await rfqt.quoteRequestor.requestRfqtFirmQuotesAsync(
makerToken,
takerToken,
amount,
side,
wholeOrderPrice,
rfqt,
);
const firmQuotes =
rfqt.rfqClient !== undefined
? (
await rfqt.rfqClient.getV1QuotesAsync({
altRfqAssetOfferings: filteredOfferings,
assetFillAmount: amount,
chainId: this._sampler.chainId,
comparisonPrice: wholeOrderPrice,
integratorId: rfqt.integrator.integratorId,
intentOnFilling: rfqt.intentOnFilling,
makerToken,
marketOperation: side,
takerAddress: rfqt.takerAddress,
takerToken,
txOrigin: rfqt.txOrigin,
})
).quotes.map(toSignedNativeOrder)
: await rfqt.quoteRequestor.requestRfqtFirmQuotesAsync(
makerToken,
takerToken,
amount,
side,
wholeOrderPrice,
rfqt,
);
const deltaTime = new Date().getTime() - timeStart;
DEFAULT_INFO_LOGGER({
rfqQuoteType: 'firm',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,15 @@ import {
import { MarketOperation } from '@0x/types';
import { BigNumber } from '@0x/utils';

<<<<<<< HEAD
import { Address, Bytes, RfqFirmQuoteValidator, RfqRequestOpts } from '../../types';
import { NativeOrderWithFillableAmounts } from '../native_orders';
import { QuoteRequestor } from '../../utils/quote_requestor';
=======
import { NativeOrderWithFillableAmounts, RfqFirmQuoteValidator, RfqRequestOpts } from '../../types';
import { QuoteRequestor, V4RFQIndicativeQuoteMM } from '../../utils/quote_requestor';
import { IRfqClient } from '../irfq_client';
>>>>>>> a7f23a982 (feat: add IRfqClient (#467))
import { ExtendedQuoteReportSources, PriceComparisonsReport, QuoteReport } from '../quote_report_generator';

import { SourceFilters } from './source_filters';
Expand Down Expand Up @@ -401,6 +407,7 @@ export interface OptimizedRfqOrder extends OptimizedNativeOrder {
}

export interface GetMarketOrdersRfqOpts extends RfqRequestOpts {
rfqClient?: IRfqClient;
quoteRequestor?: QuoteRequestor;
firmQuoteValidator?: RfqFirmQuoteValidator;
}
Expand Down
16 changes: 16 additions & 0 deletions packages/asset-swapper/src/utils/rfq_client_mappers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { FillQuoteTransformerOrderType } from '@0x/protocol-utils';

import { SignedNativeOrder } from '../types';

import { RfqClientV1Quote } from './irfq_client';

/**
* Converts a RfqClientRfqOrderFirmQuote to a SignedNativeOrder
*/
export const toSignedNativeOrder = (quote: RfqClientV1Quote): SignedNativeOrder => {
return {
type: FillQuoteTransformerOrderType.Rfq,
order: quote.order,
signature: quote.signature,
};
};

0 comments on commit 300a649

Please sign in to comment.