feat: add IRfqClient (#467)
This commit is contained in:
parent
9eadc5fc28
commit
a7f23a982e
@ -116,6 +116,15 @@ export {
|
||||
SamplerMetrics,
|
||||
} from './types';
|
||||
export { affiliateFeeUtils } from './utils/affiliate_fee_utils';
|
||||
export {
|
||||
IRfqClient,
|
||||
RfqClientV1Price,
|
||||
RfqClientV1PriceRequest,
|
||||
RfqClientV1PriceResponse,
|
||||
RfqClientV1Quote,
|
||||
RfqClientV1QuoteRequest,
|
||||
RfqClientV1QuoteResponse,
|
||||
} from './utils/irfq_client';
|
||||
export {
|
||||
DEFAULT_TOKEN_ADJACENCY_GRAPH_BY_CHAIN_ID,
|
||||
DEFAULT_GAS_SCHEDULE,
|
||||
|
@ -25,6 +25,7 @@ import {
|
||||
SwapQuoterRfqOpts,
|
||||
} from './types';
|
||||
import { assert } from './utils/assert';
|
||||
import { IRfqClient } from './utils/irfq_client';
|
||||
import { MarketOperationUtils } from './utils/market_operation_utils';
|
||||
import { BancorService } from './utils/market_operation_utils/bancor_service';
|
||||
import { SAMPLER_ADDRESS, SOURCE_FLAGS, ZERO_AMOUNT } from './utils/market_operation_utils/constants';
|
||||
@ -327,6 +328,7 @@ export class SwapQuoter {
|
||||
assetFillAmount: BigNumber,
|
||||
marketOperation: MarketOperation,
|
||||
options: Partial<SwapQuoteRequestOpts>,
|
||||
rfqClient: IRfqClient | undefined,
|
||||
): Promise<SwapQuote> {
|
||||
assert.isETHAddressHex('makerToken', makerToken);
|
||||
assert.isETHAddressHex('takerToken', takerToken);
|
||||
@ -381,6 +383,7 @@ export class SwapQuoter {
|
||||
this.expiryBufferMs,
|
||||
rfqtOptions?.metricsProxy,
|
||||
);
|
||||
calcOpts.rfqt.rfqClient = rfqClient;
|
||||
}
|
||||
|
||||
const result: OptimizerResultWithReport = await this._marketOperationUtils.getOptimizerResultAsync(
|
||||
|
@ -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,
|
||||
|
59
packages/asset-swapper/src/utils/irfq_client.ts
Normal file
59
packages/asset-swapper/src/utils/irfq_client.ts
Normal file
@ -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>;
|
||||
}
|
@ -4,12 +4,15 @@ import * as _ from 'lodash';
|
||||
|
||||
import { DEFAULT_INFO_LOGGER, INVALID_SIGNATURE } from '../../constants';
|
||||
import {
|
||||
AltRfqMakerAssetOfferings,
|
||||
AssetSwapperContractAddresses,
|
||||
MarketOperation,
|
||||
NativeOrderWithFillableAmounts,
|
||||
SignedNativeOrder,
|
||||
} from '../../types';
|
||||
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,
|
||||
@ -663,10 +666,42 @@ 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(
|
||||
|
||||
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,
|
||||
@ -687,7 +722,24 @@ 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(
|
||||
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,
|
||||
|
@ -8,6 +8,7 @@ import { BigNumber } from '@0x/utils';
|
||||
|
||||
import { NativeOrderWithFillableAmounts, RfqFirmQuoteValidator, RfqRequestOpts } from '../../types';
|
||||
import { QuoteRequestor, V4RFQIndicativeQuoteMM } from '../../utils/quote_requestor';
|
||||
import { IRfqClient } from '../irfq_client';
|
||||
import { ExtendedQuoteReportSources, PriceComparisonsReport, QuoteReport } from '../quote_report_generator';
|
||||
|
||||
import { SourceFilters } from './source_filters';
|
||||
@ -446,6 +447,7 @@ export type OptimizedMarketOrder =
|
||||
| OptimizedMarketOrderBase<NativeRfqOrderFillData>;
|
||||
|
||||
export interface GetMarketOrdersRfqOpts extends RfqRequestOpts {
|
||||
rfqClient?: IRfqClient;
|
||||
quoteRequestor?: QuoteRequestor;
|
||||
firmQuoteValidator?: RfqFirmQuoteValidator;
|
||||
}
|
||||
|
16
packages/asset-swapper/src/utils/rfq_client_mappers.ts
Normal file
16
packages/asset-swapper/src/utils/rfq_client_mappers.ts
Normal file
@ -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,
|
||||
};
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user