Skip to content

Commit bb14cab

Browse files
authored
Dutchv3 (#490)
* Add Dutchv3 support * Make missing env vars easier to find * First test working * Remove dutchV2 filter * more tests * Moar tests * All the tests * Add tests/check for min/max amounts * Address PR feedback * Update yarn.lock * Fix lint * Add override validation * lint fixes * Resolve Dutchv3 amounts * Add deadline explicitly to test * Use 0x00... as valid cosigner * Fix EXACT_INPUT check
1 parent 3614707 commit bb14cab

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1702
-92
lines changed

bin/stacks/step-function-stack.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,20 @@ export class StepFunctionStack extends cdk.NestedStack {
6262
// TODO: remove the if block after accounts are set up for parameterization-api
6363
if (props.envVars['FILL_EVENT_DESTINATION_ARN']) {
6464
new aws_logs.CfnSubscriptionFilter(this, 'TerminalStateSub', {
65-
destinationArn: checkDefined(props.envVars['FILL_EVENT_DESTINATION_ARN']),
65+
destinationArn: checkDefined(
66+
props.envVars['FILL_EVENT_DESTINATION_ARN'],
67+
'FILL_EVENT_DESTINATION_ARN is undefined'
68+
),
6669
// filter patterns should match ORDER_STATUS.FILLED, ORDER_STATUS.CANCELLED
6770
filterPattern: '{ $.orderInfo.orderStatus = "filled" || $.orderInfo.orderStatus = "cancelled" }',
6871
logGroupName: checkStatusFunction.logGroup.logGroupName,
6972
})
7073

7174
new aws_logs.CfnSubscriptionFilter(this, 'nonTerminalSub', {
72-
destinationArn: checkDefined(props.envVars['ACTIVE_ORDER_EVENT_DESTINATION_ARN']),
75+
destinationArn: checkDefined(
76+
props.envVars['ACTIVE_ORDER_EVENT_DESTINATION_ARN'],
77+
'ACTIVE_ORDER_EVENT_DESTINATION_ARN is undefined'
78+
),
7379
filterPattern: '{ $.orderInfo.orderStatus = "insufficient-funds" }',
7480
logGroupName: checkStatusFunction.logGroup.logGroupName,
7581
})

lib/entities/Order.ts

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ export type OrderInput = {
1515
endAmount?: string
1616
}
1717

18+
export type V3OrderInput = {
19+
token: string
20+
startAmount: string
21+
curve?: NonlinearDutchDecay
22+
maxAmount: string
23+
adjustmentPerGweiBaseFee: string
24+
}
25+
1826
export type PriorityOrderInput = {
1927
token: string
2028
amount: string
@@ -28,6 +36,20 @@ export type OrderOutput = {
2836
recipient: string
2937
}
3038

39+
export type V3OrderOutput = {
40+
token: string
41+
startAmount: string
42+
curve: NonlinearDutchDecay
43+
recipient: string
44+
minAmount: string
45+
adjustmentPerGweiBaseFee: string
46+
}
47+
48+
export type NonlinearDutchDecay = {
49+
relativeBlocks: number[]
50+
relativeAmounts: string[]
51+
}
52+
3153
export type PriorityOrderOutput = {
3254
token: string
3355
amount: string
@@ -88,6 +110,20 @@ export type DutchV2OrderEntity = SharedXOrderEntity & {
88110
cosignature: string
89111
}
90112

113+
export type DutchV3OrderEntity = SharedXOrderEntity & {
114+
type: OrderType.Dutch_V3
115+
input: V3OrderInput
116+
outputs: V3OrderOutput[]
117+
startingBaseFee: string
118+
cosignerData: {
119+
decayStartBlock: number
120+
exclusiveFiller: string
121+
inputOverride: string
122+
outputOverrides: string[]
123+
}
124+
cosignature: string
125+
}
126+
91127
export type PriorityOrderEntity = SharedXOrderEntity & {
92128
type: OrderType.Priority
93129
auctionStartBlock: number
@@ -100,9 +136,9 @@ export type PriorityOrderEntity = SharedXOrderEntity & {
100136
cosignature: string
101137
}
102138

103-
// Db representation of Dutch V1, Dutch V2, or Limit Order
139+
// Db representation of Dutch V1, Dutch V2, Dutch V3, or Limit Order
104140
// indexes are returned at runtime but not represented on this type. Ideally we will include a mapping at repo layer boundary
105-
export type UniswapXOrderEntity = DutchV1OrderEntity | DutchV2OrderEntity | PriorityOrderEntity
141+
export type UniswapXOrderEntity = DutchV1OrderEntity | DutchV2OrderEntity | PriorityOrderEntity | DutchV3OrderEntity
106142

107143
export enum SORT_FIELDS {
108144
CREATED_AT = 'createdAt',
@@ -112,6 +148,10 @@ export function isPriorityOrderEntity(order: UniswapXOrderEntity): order is Prio
112148
return order.type === OrderType.Priority
113149
}
114150

151+
export function isDutchV3OrderEntity(order: UniswapXOrderEntity): order is DutchV3OrderEntity {
152+
return order.type === OrderType.Dutch_V3
153+
}
154+
115155
export function isDutchV2OrderEntity(order: UniswapXOrderEntity): order is DutchV2OrderEntity {
116156
return order.type === OrderType.Dutch_V2
117157
}

lib/handlers/check-order-status/handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export class CheckOrderStatusHandler extends SfnLambdaHandler<ContainerInjected,
6666
stateMachineArn: input.requestInjected.stateMachineArn,
6767
}
6868
} else {
69-
// Dutch, Dutch_V2, Priority
69+
// Dutch, Dutch_V2, Dutch_V3, Priority
7070
const response = await this.checkOrderStatusService.handleRequest(input.requestInjected)
7171
return {
7272
...response,

lib/handlers/check-order-status/service.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
CosignedPriorityOrder,
33
CosignedV2DutchOrder,
4+
CosignedV3DutchOrder,
45
DutchOrder,
56
FillInfo,
67
OrderType,
@@ -81,6 +82,9 @@ export class CheckOrderStatusService {
8182
case OrderType.Dutch_V2:
8283
parsedOrder = CosignedV2DutchOrder.parse(order.encodedOrder, chainId)
8384
break
85+
case OrderType.Dutch_V3:
86+
parsedOrder = CosignedV3DutchOrder.parse(order.encodedOrder, chainId)
87+
break
8488
case OrderType.Priority:
8589
parsedOrder = CosignedPriorityOrder.parse(order.encodedOrder, chainId)
8690
break
@@ -133,7 +137,7 @@ export class CheckOrderStatusService {
133137
maxPriorityFeePerGas: tx.maxPriorityFeePerGas,
134138
maxFeePerGas: tx.maxFeePerGas,
135139
},
136-
parsedOrder as DutchOrder | CosignedV2DutchOrder | CosignedPriorityOrder
140+
parsedOrder as DutchOrder | CosignedV2DutchOrder | CosignedV3DutchOrder | CosignedPriorityOrder
137141
)
138142

139143
await this.fillEventLogger.processFillEvent({

lib/handlers/check-order-status/util.ts

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
CosignedPriorityOrder,
33
CosignedV2DutchOrder,
4+
CosignedV3DutchOrder,
45
DutchOrder,
56
FillInfo,
67
OrderType,
@@ -25,10 +26,12 @@ export interface FillMetadata {
2526
export function getSettledAmounts(
2627
fill: FillInfo,
2728
metadata: FillMetadata,
28-
parsedOrder: DutchOrder | CosignedV2DutchOrder | CosignedPriorityOrder
29+
parsedOrder: DutchOrder | CosignedV2DutchOrder | CosignedV3DutchOrder | CosignedPriorityOrder
2930
) {
3031
if (parsedOrder instanceof DutchOrder || parsedOrder instanceof CosignedV2DutchOrder) {
3132
return getDutchSettledAmounts(fill, metadata.timestamp, parsedOrder)
33+
} else if (parsedOrder instanceof CosignedV3DutchOrder) {
34+
return getDutchV3SettledAmounts(fill, parsedOrder)
3235
} else if (parsedOrder instanceof CosignedPriorityOrder) {
3336
return getPrioritySettledAmounts(fill, metadata, parsedOrder)
3437
} else {
@@ -95,6 +98,73 @@ export function getPrioritySettledAmounts(
9598
return settledAmounts
9699
}
97100

101+
/**
102+
* get the ammounts transfered on chain
103+
* used for logging
104+
*/
105+
export function getDutchV3SettledAmounts(
106+
fill: FillInfo,
107+
parsedOrder: CosignedV3DutchOrder
108+
): SettledAmount[] {
109+
parsedOrder.resolve({currentBlock: fill.blockNumber})
110+
const nativeOutputs = parsedOrder.info.outputs.filter((output) => output.token.toLowerCase() === NATIVE_ADDRESS)
111+
const settledAmounts: SettledAmount[] = []
112+
let amountIn: string
113+
114+
if (!parsedOrder.info.input.curve ||
115+
(parsedOrder.info.input.curve.relativeAmounts.length === 1 &&
116+
parsedOrder.info.input.curve.relativeAmounts[0] === BigInt(0))) {
117+
// If the order is EXACT_INPUT then the input will not decay and resolves to the startAmount/endAmount.
118+
amountIn = parsedOrder.info.input.startAmount.toString()
119+
120+
// Resolve the native outputs using the fill block number and filler address from the fill log.
121+
// This will give us a minimum resolved amount for native out swaps.
122+
const resolvedOrder = parsedOrder.resolve({ currentBlock: fill.blockNumber, filler: fill.filler })
123+
const resolvedNativeOutputs = resolvedOrder.outputs.filter(
124+
(output) => output.token.toLowerCase() === NATIVE_ADDRESS
125+
)
126+
127+
// Add all the resolved native outputs to the settledAmounts as they are not included in the fill logs.
128+
resolvedNativeOutputs.forEach((resolvedNativeOutput) => {
129+
settledAmounts.push({
130+
tokenIn: parsedOrder.info.input.token,
131+
amountIn,
132+
tokenOut: resolvedNativeOutput.token,
133+
amountOut: resolvedNativeOutput.amount.toString(),
134+
})
135+
})
136+
} else {
137+
// If the order is EXACT_OUTPUT we will have all the ERC20 transfers in the fill logs,
138+
// only log the amountIn that matches the order input token.
139+
140+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
141+
const input = fill.inputs.find((input) => input.token.toLowerCase() === parsedOrder.info.input.token.toLowerCase())!
142+
amountIn = input.amount.toString()
143+
144+
// Add all the native outputs to the settledAmounts as they are not included in the fill logs.
145+
// The amount is just the startAmount because the order is EXACT_OUTPUT so there is no decay on the outputs.
146+
nativeOutputs.forEach((nativeOutput) => {
147+
settledAmounts.push({
148+
tokenIn: parsedOrder.info.input.token,
149+
amountIn,
150+
tokenOut: nativeOutput.token,
151+
amountOut: nativeOutput.startAmount.toString(),
152+
})
153+
})
154+
}
155+
156+
fill.outputs.forEach((output) => {
157+
settledAmounts.push({
158+
tokenIn: parsedOrder.info.input.token,
159+
amountIn,
160+
tokenOut: output.token,
161+
amountOut: output.amount.toString(),
162+
})
163+
})
164+
165+
return settledAmounts
166+
}
167+
98168
/**
99169
* get the ammounts transfered on chain
100170
* used for logging

lib/handlers/get-orders/handler.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import Joi from 'joi'
2-
3-
import { OrderType } from '@uniswap/uniswapx-sdk'
42
import { Unit } from 'aws-embedded-metrics'
53
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda'
64
import { UniswapXOrderEntity } from '../../entities'
@@ -21,14 +19,15 @@ import { GetOrdersResponse, GetOrdersResponseJoi } from './schema/GetOrdersRespo
2119
import { GetPriorityOrderResponse } from './schema/GetPriorityOrderResponse'
2220
import { GetRelayOrderResponse, GetRelayOrdersResponseJoi } from './schema/GetRelayOrderResponse'
2321
import { GetOrdersQueryParams, GetOrdersQueryParamsJoi, RawGetOrdersQueryParams } from './schema/index'
22+
import { GetDutchV3OrderResponse } from './schema/GetDutchV3OrderResponse'
2423

2524
export class GetOrdersHandler extends APIGLambdaHandler<
2625
ContainerInjected,
2726
RequestInjected,
2827
void,
2928
RawGetOrdersQueryParams,
3029
GetOrdersResponse<
31-
UniswapXOrderEntity | GetDutchV2OrderResponse | GetRelayOrderResponse | GetPriorityOrderResponse | undefined
30+
UniswapXOrderEntity | GetDutchV2OrderResponse | GetDutchV3OrderResponse | GetRelayOrderResponse | GetPriorityOrderResponse | undefined
3231
>
3332
> {
3433
constructor(
@@ -44,13 +43,13 @@ export class GetOrdersHandler extends APIGLambdaHandler<
4443
): Promise<
4544
| Response<
4645
GetOrdersResponse<
47-
UniswapXOrderEntity | GetDutchV2OrderResponse | GetRelayOrderResponse | GetPriorityOrderResponse | undefined
46+
UniswapXOrderEntity | GetDutchV2OrderResponse | GetDutchV3OrderResponse | GetRelayOrderResponse | GetPriorityOrderResponse | undefined
4847
>
4948
>
5049
| ErrorResponse
5150
> {
5251
const {
53-
requestInjected: { limit, queryFilters, cursor, includeV2, orderType },
52+
requestInjected: { limit, queryFilters, cursor, orderType },
5453
containerInjected: { dbInterface },
5554
} = params
5655

@@ -72,9 +71,6 @@ export class GetOrdersHandler extends APIGLambdaHandler<
7271

7372
//without orderType specified, keep legacy implementation
7473
const getOrdersResult = await dbInterface.getOrders(limit, queryFilters, cursor)
75-
if (!includeV2) {
76-
getOrdersResult.orders = getOrdersResult.orders.filter((order) => order.type !== OrderType.Dutch_V2)
77-
}
7874

7975
return {
8076
statusCode: 200,

lib/handlers/get-orders/injector.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ export interface RequestInjected extends ApiRInj {
1414
limit: number
1515
queryFilters: GetOrdersQueryParams
1616
cursor?: string
17-
includeV2?: boolean
1817
orderType?: GetOrderTypeQueryParamEnum
1918
}
2019

0 commit comments

Comments
 (0)