Skip to content

Commit

Permalink
Merge pull request #226 from Uniswap/opposing-quote
Browse files Browse the repository at this point in the history
chore: log opposing quote iff real quote is valid
  • Loading branch information
ConjunctiveNormalForm authored Nov 6, 2023
2 parents e880162 + 6505b31 commit 664840d
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 1 deletion.
9 changes: 9 additions & 0 deletions lib/entities/QuoteRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,15 @@ export class QuoteRequest {
...(this.quoteId && { quoteId: this.quoteId }),
};
}

public toOpposingRequest(): QuoteRequest {
const opposingJSON = this.toOpposingCleanJSON();
return new QuoteRequest({
...opposingJSON,
amount: BigNumber.from(opposingJSON.amount),
type: TradeType[opposingJSON.type as keyof typeof TradeType],
});
}

public get requestId(): string {
return this.data.requestId;
Expand Down
13 changes: 12 additions & 1 deletion lib/quoters/WebhookQuoter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export class WebhookQuoter implements Quoter {
...(!!headers && { headers }),
};

const [hookResponse] = await Promise.all([
const [hookResponse, opposite] = await Promise.all([
axios.post(endpoint, cleanRequest, axiosConfig),
axios.post(endpoint, opposingCleanRequest, axiosConfig),
]);
Expand Down Expand Up @@ -170,6 +170,17 @@ export class WebhookQuoter implements Quoter {
request.requestId
} for endpoint ${endpoint} successful quote: ${request.amount.toString()} -> ${quote.toString()}}`
);

//iff valid quote, log the opposing side as well
const opposingRequest = request.toOpposingRequest();
const opposingResponse = QuoteResponse.fromRFQ(opposingRequest, opposite.data, opposingRequest.type);
if (opposingResponse && !isNonQuote(opposingRequest, opposite, opposingResponse.response) && !opposingResponse.validation.error) {
this.log.info({
eventType: 'QuoteResponse',
body: { ...opposingResponse.response.toLog(), offerer: opposingResponse.response.swapper },
});
}

return response;
} catch (e) {
metric.putMetric(Metric.RFQ_FAIL_ERROR, 1, MetricLoggerUnit.Count);
Expand Down
15 changes: 15 additions & 0 deletions test/entities/QuoteRequest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,19 @@ describe('QuoteRequest', () => {
numOutputs: 1,
});
});

it('toOpposingRequest', async () => {
const opposingRequest = request.toOpposingRequest();
expect(opposingRequest.toCleanJSON()).toEqual({
tokenInChainId: CHAIN_ID,
tokenOutChainId: CHAIN_ID,
requestId: REQUEST_ID,
tokenIn: TOKEN_OUT,
tokenOut: TOKEN_IN,
amount: ethers.utils.parseEther('1').toString(),
swapper: SWAPPER,
type: 'EXACT_OUTPUT',
numOutputs: 1,
});
});
});
36 changes: 36 additions & 0 deletions test/handlers/quote/handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,19 @@ describe('Quote handler', () => {
quoteId: QUOTE_ID,
},
});
}).mockImplementationOnce((_endpoint, _req, _options) => {
return Promise.resolve({
data: {
amountOut: amountIn.mul(3).toString(),
requestId: request.requestId,
tokenIn: request.tokenOut,
tokenOut: request.tokenIn,
amountIn: request.amount,
swapper: request.swapper,
chainId: request.tokenInChainId,
quoteId: QUOTE_ID,
},
});
});

const response: APIGatewayProxyResult = await getQuoteHandler(quoters).handler(
Expand Down Expand Up @@ -274,6 +287,16 @@ describe('Quote handler', () => {
...responseFromRequest(request, { amountOut: amountIn.mul(2).toString() }),
},
});
}).mockImplementationOnce((_endpoint, _req, options: any) => {
expect(options.headers['X-Authentication']).toEqual('1234');
const res = responseFromRequest(request, { amountOut: amountIn.mul(3).toString() });
return Promise.resolve({
data: {
...res,
tokenIn: res.tokenOut,
tokenOut: res.tokenIn,
},
});
});

const response: APIGatewayProxyResult = await getQuoteHandler(quoters).handler(
Expand Down Expand Up @@ -404,6 +427,19 @@ describe('Quote handler', () => {
quoteId: QUOTE_ID,
},
});
}).mockImplementationOnce((_endpoint, _req, _options) => {
return Promise.resolve({
data: {
amountOut: amountIn.div(2).toString(),
tokenIn: request.tokenOut,
tokenOut: request.tokenIn,
amountIn: request.amount,
swapper: request.swapper,
chainId: request.tokenInChainId,
requestId: request.requestId,
quoteId: QUOTE_ID,
},
});
});

const response: APIGatewayProxyResult = await getQuoteHandler(quoters).handler(
Expand Down
40 changes: 40 additions & 0 deletions test/providers/quoters/WebhookQuoter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ describe('WebhookQuoter tests', () => {
return Promise.resolve({
data: quote,
});
}).mockImplementationOnce((_endpoint, _req, _options) => {
return Promise.resolve({
data: {
...quote,
tokenIn: request.tokenOut,
tokenOut: request.tokenIn,
}
});
});
const response = await webhookQuoter.quote(request);

Expand All @@ -82,6 +90,14 @@ describe('WebhookQuoter tests', () => {
return Promise.resolve({
data: quote,
});
}).mockImplementationOnce((_endpoint, _req, _options) => {
return Promise.resolve({
data: {
...quote,
tokenIn: request.tokenOut,
tokenOut: request.tokenIn,
}
});
});
await webhookQuoter.quote(request);

Expand Down Expand Up @@ -168,6 +184,14 @@ describe('WebhookQuoter tests', () => {
return Promise.resolve({
data: quote,
});
}).mockImplementationOnce((_endpoint, _req, _options) => {
return Promise.resolve({
data: {
...quote,
tokenIn: request.tokenOut,
tokenOut: request.tokenIn,
}
});
});
const response = await webhookQuoter.quote(request);

Expand Down Expand Up @@ -202,6 +226,14 @@ describe('WebhookQuoter tests', () => {
return Promise.resolve({
data: quote,
});
}).mockImplementationOnce((_endpoint, _req, _options) => {
return Promise.resolve({
data: {
...quote,
tokenIn: request.tokenOut,
tokenOut: request.tokenIn,
}
});
});
const response = await webhookQuoter.quote(request);

Expand Down Expand Up @@ -230,6 +262,14 @@ describe('WebhookQuoter tests', () => {
return Promise.resolve({
data: quote,
});
}).mockImplementationOnce((_endpoint, _req, _options) => {
return Promise.resolve({
data: {
...quote,
tokenIn: request.tokenOut,
tokenOut: request.tokenIn,
}
});
});
const response = await quoter.quote(request);

Expand Down

0 comments on commit 664840d

Please sign in to comment.