Skip to content

Commit

Permalink
refactor: distinguish between v2 and v3 requests
Browse files Browse the repository at this point in the history
  • Loading branch information
alanhwu committed Nov 6, 2024
1 parent c169800 commit 38e1990
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 53 deletions.
34 changes: 26 additions & 8 deletions lib/entities/HardQuoteRequest.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { TradeType } from '@uniswap/sdk-core';
import { UnsignedV2DutchOrder } from '@uniswap/uniswapx-sdk';
import { OrderType, UnsignedV2DutchOrder } from '@uniswap/uniswapx-sdk';
import { BigNumber, ethers, utils } from 'ethers';
import { v4 as uuidv4 } from 'uuid';

Expand All @@ -11,16 +11,23 @@ export class HardQuoteRequest {
public order: UnsignedV2DutchOrder;
private data: HardQuoteRequestBody;

public static fromHardRequestBody(body: HardQuoteRequestBody): HardQuoteRequest {
return new HardQuoteRequest(body);
public static fromHardRequestBody(body: HardQuoteRequestBody, orderType: OrderType): HardQuoteRequest {
return new HardQuoteRequest(body, orderType);
}

constructor(_data: HardQuoteRequestBody) {
constructor(_data: HardQuoteRequestBody, orderType: OrderType) {
this.data = {
..._data,
requestId: _data.quoteId ?? uuidv4(),
};
this.order = UnsignedV2DutchOrder.parse(_data.encodedInnerOrder, _data.tokenInChainId);
if (orderType === OrderType.Dutch_V2) {
this.order = UnsignedV2DutchOrder.parse(_data.encodedInnerOrder, _data.tokenInChainId);
// } else if (orderType === OrderType.Dutch_V3) {
// this.order = UnsignedV3DutchOrder.parse(_data.encodedInnerOrder, _data.tokenInChainId);
// }
} else {
throw new Error('Unsupported order type');
}
}

public toCleanJSON(): QuoteRequestDataJSON {
Expand Down Expand Up @@ -110,9 +117,20 @@ export class HardQuoteRequest {
}

public get type(): TradeType {
return this.order.info.input.startAmount.eq(this.order.info.input.endAmount)
? TradeType.EXACT_INPUT
: TradeType.EXACT_OUTPUT;
if (this.order instanceof UnsignedV2DutchOrder) {
return this.order.info.input.startAmount.eq(this.order.info.input.endAmount)
? TradeType.EXACT_INPUT
: TradeType.EXACT_OUTPUT
}
// else if (this.order instanceof UnsignedV3DutchOrder) {
// const startAmount = this.order.info.input.startAmount;
// return startAmount.eq(V3DutchOrderBuilder.getMinAmountOut(startAmount, this.order.info.input.curve.relativeAmounts))
// ? TradeType.EXACT_INPUT
// : TradeType.EXACT_OUTPUT
// }
else {
throw new Error('Unsupported order type');
}
}

public get numOutputs(): number {
Expand Down
89 changes: 57 additions & 32 deletions lib/handlers/hard-quote/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { KMSClient } from '@aws-sdk/client-kms';
import { TradeType } from '@uniswap/sdk-core';
import { KmsSigner } from '@uniswap/signer';
import { MetricLoggerUnit } from '@uniswap/smart-order-router';
import { CosignedV2DutchOrder, CosignerData } from '@uniswap/uniswapx-sdk';
import { CosignedV2DutchOrder, CosignerData, OrderType, UniswapXOrderParser } from '@uniswap/uniswapx-sdk';
import { BigNumber, ethers } from 'ethers';
import Joi from 'joi';

Expand Down Expand Up @@ -45,8 +45,19 @@ export class QuoteHandler extends APIGLambdaHandler<

metric.putMetric(Metric.QUOTE_REQUESTED, 1, MetricLoggerUnit.Count);

const request = HardQuoteRequest.fromHardRequestBody(requestBody);
const orderParser = new UniswapXOrderParser();
const orderType: OrderType = orderParser.getOrderTypeFromEncoded(requestBody.encodedInnerOrder, requestBody.tokenInChainId);

const request = HardQuoteRequest.fromHardRequestBody(requestBody, orderType);


// if (orderType == OrderType.Dutch_V2) {

// } else if (orderType == OrderType.Dutch_V3) {

// } else {
// throw new Error('Unsupported order type');
// }
// re-create KmsClient every call to avoid clock skew issue
// https://github.com/aws/aws-sdk-js-v3/issues/6400
const kmsKeyId = checkDefined(process.env.KMS_KEY_ID, 'KMS_KEY_ID is not defined');
Expand Down Expand Up @@ -93,7 +104,7 @@ export class QuoteHandler extends APIGLambdaHandler<

let cosignerData: CosignerData;
if (bestQuote) {
cosignerData = getCosignerData(request, bestQuote);
cosignerData = getCosignerData(request, bestQuote, orderType);
log.info({ bestQuote: bestQuote }, 'bestQuote');
} else {
cosignerData = getDefaultCosignerData(request);
Expand Down Expand Up @@ -162,40 +173,54 @@ export class QuoteHandler extends APIGLambdaHandler<
}
}

export function getCosignerData(request: HardQuoteRequest, quote: QuoteResponse): CosignerData {
const decayStartTime = getDecayStartTime(request.tokenInChainId);
// default to open order with the original prices
let filler = ethers.constants.AddressZero;
let inputOverride = BigNumber.from(0);
const outputOverrides = request.order.info.outputs.map(() => BigNumber.from(0));
export function getCosignerData(request: HardQuoteRequest, quote: QuoteResponse, orderType: OrderType): CosignerData {
if (orderType === OrderType.Dutch_V2) {
const decayStartTime = getDecayStartTime(request.tokenInChainId);
// default to open order with the original prices
let filler = ethers.constants.AddressZero;
let inputOverride = BigNumber.from(0);
const outputOverrides = request.order.info.outputs.map(() => BigNumber.from(0));

// if the quote is better, then increase amounts by the difference
if (request.type === TradeType.EXACT_INPUT) {
if (quote.amountOut.gt(request.totalOutputAmountStart)) {
const increase = quote.amountOut.sub(request.totalOutputAmountStart);
// give all the increase to the first (swapper) output
outputOverrides[0] = request.order.info.outputs[0].startAmount.add(increase);
if (quote.filler) {
filler = quote.filler;
// if the quote is better, then increase amounts by the difference
if (request.type === TradeType.EXACT_INPUT) {
if (quote.amountOut.gt(request.totalOutputAmountStart)) {
const increase = quote.amountOut.sub(request.totalOutputAmountStart);
// give all the increase to the first (swapper) output
outputOverrides[0] = request.order.info.outputs[0].startAmount.add(increase);
if (quote.filler) {
filler = quote.filler;
}
}
}
} else {
if (quote.amountIn.lt(request.totalInputAmountStart)) {
inputOverride = quote.amountIn;
if (quote.filler) {
filler = quote.filler;
} else {
if (quote.amountIn.lt(request.totalInputAmountStart)) {
inputOverride = quote.amountIn;
if (quote.filler) {
filler = quote.filler;
}
}
}
}

return {
decayStartTime: decayStartTime,
decayEndTime: getDecayEndTime(request.tokenInChainId, decayStartTime),
exclusiveFiller: filler,
exclusivityOverrideBps: DEFAULT_EXCLUSIVITY_OVERRIDE_BPS,
inputOverride: inputOverride,
outputOverrides: outputOverrides,
};
return {
decayStartTime: decayStartTime,
decayEndTime: getDecayEndTime(request.tokenInChainId, decayStartTime),
exclusiveFiller: filler,
exclusivityOverrideBps: DEFAULT_EXCLUSIVITY_OVERRIDE_BPS,
inputOverride: inputOverride,
outputOverrides: outputOverrides,
};
}
// else if (orderType == OrderType.Dutch_V3) {
// return {
// decayStartBlock: 1,
// exclusiveFiller: ethers.constants.AddressZero,
// exclusivityOverrideBps: BigNumber.from(0),
// inputOverride: BigNumber.from(0),
// outputOverrides: request.order.info.outputs.map(() => BigNumber.from(0)),
// }
// }
else {
throw new Error('Unsupported order type');
}
}

export function getDefaultCosignerData(request: HardQuoteRequest): CosignerData {
Expand Down
5 changes: 3 additions & 2 deletions test/entities/HardQuoteRequest.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { TradeType } from '@uniswap/sdk-core';
import { UnsignedV2DutchOrder, UnsignedV2DutchOrderInfo } from '@uniswap/uniswapx-sdk';
import { OrderType, UnsignedV2DutchOrder, UnsignedV2DutchOrderInfo } from '@uniswap/uniswapx-sdk';
import { BigNumber, ethers } from 'ethers';

import { HardQuoteRequest } from '../../lib/entities';
Expand Down Expand Up @@ -55,7 +55,8 @@ const makeRequest = (data: Partial<HardQuoteRequestBody>): HardQuoteRequest => {
innerSig: '0x',
},
data
)
),
OrderType.Dutch_V2
);
};

Expand Down
3 changes: 2 additions & 1 deletion test/entities/HardQuoteResponse.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
CosignedV2DutchOrder,
CosignerData,
OrderType,
UnsignedV2DutchOrder,
UnsignedV2DutchOrderInfo,
} from '@uniswap/uniswapx-sdk';
Expand Down Expand Up @@ -52,7 +53,7 @@ describe('HardQuoteResponse', () => {
cosignerData,
ethers.utils.joinSignature(cosignature)
);
return new V2HardQuoteResponse(new HardQuoteRequest(await getRequest(unsigned)), order);
return new V2HardQuoteResponse(new HardQuoteRequest(await getRequest(unsigned), OrderType.Dutch_V2), order);
};

it('toResponseJSON', async () => {
Expand Down
24 changes: 14 additions & 10 deletions test/handlers/hard-quote/handler.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { KMSClient } from '@aws-sdk/client-kms';
import { TradeType } from '@uniswap/sdk-core';
import { CosignedV2DutchOrder, UnsignedV2DutchOrder, UnsignedV2DutchOrderInfo } from '@uniswap/uniswapx-sdk';
import { CosignedV2DutchOrder, OrderType, UnsignedV2DutchOrder, UnsignedV2DutchOrderInfo } from '@uniswap/uniswapx-sdk';
import { createMetricsLogger } from 'aws-embedded-metrics';
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
// import axios from 'axios';
Expand Down Expand Up @@ -303,7 +303,7 @@ describe('Quote handler', () => {
it('updates decay times reasonably', async () => {
const request = await getRequest(getOrder({ cosigner: cosignerWallet.address }));
const now = Math.floor(Date.now() / 1000);
const cosignerData = getCosignerData(new HardQuoteRequest(request), getQuoteResponse({}));
const cosignerData = getCosignerData(new HardQuoteRequest(request, OrderType.Dutch_V2), getQuoteResponse({}), OrderType.Dutch_V2);
expect(cosignerData.decayStartTime).toBeGreaterThan(now);
expect(cosignerData.decayStartTime).toBeLessThan(now + 1000);
expect(cosignerData.decayEndTime).toBeGreaterThan(cosignerData.decayStartTime);
Expand All @@ -313,8 +313,9 @@ describe('Quote handler', () => {
it('exact input quote worse, no exclusivity', async () => {
const request = await getRequest(getOrder({ cosigner: cosignerWallet.address }));
const cosignerData = getCosignerData(
new HardQuoteRequest(request),
getQuoteResponse({ amountOut: ethers.utils.parseEther('0.8') })
new HardQuoteRequest(request, OrderType.Dutch_V2),
getQuoteResponse({ amountOut: ethers.utils.parseEther('0.8') }),
OrderType.Dutch_V2
);
expect(cosignerData.exclusiveFiller).toEqual(ethers.constants.AddressZero);
expect(cosignerData.inputOverride).toEqual(BigNumber.from(0));
Expand All @@ -326,8 +327,9 @@ describe('Quote handler', () => {
const request = await getRequest(getOrder({ cosigner: cosignerWallet.address }));
const outputAmount = ethers.utils.parseEther('2');
const cosignerData = getCosignerData(
new HardQuoteRequest(request),
getQuoteResponse({ amountOut: outputAmount })
new HardQuoteRequest(request, OrderType.Dutch_V2),
getQuoteResponse({ amountOut: outputAmount }),
OrderType.Dutch_V2
);
expect(cosignerData.exclusiveFiller).toEqual(MOCK_FILLER_ADDRESS);
expect(cosignerData.inputOverride).toEqual(BigNumber.from(0));
Expand All @@ -338,8 +340,9 @@ describe('Quote handler', () => {
it('exact output quote worse, no exclusivity', async () => {
const request = await getRequest(getOrder({ cosigner: cosignerWallet.address }));
const cosignerData = getCosignerData(
new HardQuoteRequest(request),
getQuoteResponse({ amountIn: ethers.utils.parseEther('1.2') }, TradeType.EXACT_OUTPUT)
new HardQuoteRequest(request, OrderType.Dutch_V2),
getQuoteResponse({ amountIn: ethers.utils.parseEther('1.2') }, TradeType.EXACT_OUTPUT),
OrderType.Dutch_V2
);
expect(cosignerData.exclusiveFiller).toEqual(ethers.constants.AddressZero);
expect(cosignerData.inputOverride).toEqual(BigNumber.from(0));
Expand All @@ -351,8 +354,9 @@ describe('Quote handler', () => {
const request = await getRequest(getOrder({ cosigner: cosignerWallet.address }));
const inputOverride = ethers.utils.parseEther('0.8');
const cosignerData = getCosignerData(
new HardQuoteRequest(request),
getQuoteResponse({ amountIn: ethers.utils.parseEther('1.2') }, TradeType.EXACT_OUTPUT)
new HardQuoteRequest(request, OrderType.Dutch_V2),
getQuoteResponse({ amountIn: ethers.utils.parseEther('1.2') }, TradeType.EXACT_OUTPUT),
OrderType.Dutch_V2
);
expect(cosignerData.exclusiveFiller).toEqual(MOCK_FILLER_ADDRESS);
expect(cosignerData.inputOverride).toEqual(inputOverride);
Expand Down

0 comments on commit 38e1990

Please sign in to comment.