Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: v4 subgraph on Sepelia in routing cron #808

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion lib/cron/cache-config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import { Protocol } from '@uniswap/router-sdk'
import { V2SubgraphProvider, V3SubgraphProvider } from '@uniswap/smart-order-router'
import { V2SubgraphProvider, V3SubgraphProvider, V4SubgraphProvider } from '@uniswap/smart-order-router'
import { ChainId } from '@uniswap/sdk-core'

// during local cdk stack update, the env vars are not populated
// make sure to fill in the env vars below
// process.env.ALCHEMY_QUERY_KEY = ''

export const v4SubgraphUrlOverride = (chainId: ChainId) => {
switch (chainId) {
case ChainId.SEPOLIA:
return `https://subgraph.satsuma-prod.com/${process.env.ALCHEMY_QUERY_KEY}/uniswap/uniswap-v4-sepolia-test/api`
default:
return undefined
}
}

export const v3SubgraphUrlOverride = (chainId: ChainId) => {
switch (chainId) {
case ChainId.MAINNET:
Expand Down Expand Up @@ -54,6 +63,10 @@ export const v2SubgraphUrlOverride = (chainId: ChainId) => {
}
}

// TODO: ROUTE-225 - follow up on v4 subgraph pools filtering threshold
const v4TrackedEthThreshold = 0 // Pools need at least 0 of trackedEth to be selected
jsy1218 marked this conversation as resolved.
Show resolved Hide resolved
const v4UntrackedUsdThreshold = 0 // Pools need at least 0k USD (untracked) to be selected (for metrics only)

export const v3TrackedEthThreshold = 0.01 // Pools need at least 0.01 of trackedEth to be selected
const v3UntrackedUsdThreshold = 25000 // Pools need at least 25K USD (untracked) to be selected (for metrics only)

Expand Down Expand Up @@ -311,4 +324,18 @@ export const chainProtocols = [
v2SubgraphUrlOverride(ChainId.BLAST)
),
},
{
protocol: Protocol.V4,
chainId: ChainId.SEPOLIA,
timeout: 90000,
provider: new V4SubgraphProvider(
ChainId.SEPOLIA,
3,
90000,
true,
v4TrackedEthThreshold,
v4UntrackedUsdThreshold,
v4SubgraphUrlOverride(ChainId.SEPOLIA)
),
},
]
9 changes: 4 additions & 5 deletions lib/handlers/marshalling/cached-route-marshaller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { CachedRoute } from '@uniswap/smart-order-router'
import { MixedRoute, V2Route, V3Route } from '@uniswap/smart-order-router/build/main/routers'
import { CachedRoute, SupportedRoutes } from '@uniswap/smart-order-router'
import { MarshalledRoute, RouteMarshaller } from './route-marshaller'

export interface MarshalledCachedRoute {
Expand All @@ -8,15 +7,15 @@ export interface MarshalledCachedRoute {
}

export class CachedRouteMarshaller {
public static marshal(cachedRoute: CachedRoute<V3Route | V2Route | MixedRoute>): MarshalledCachedRoute {
public static marshal(cachedRoute: CachedRoute<SupportedRoutes>): MarshalledCachedRoute {
return {
route: RouteMarshaller.marshal(cachedRoute.route),
percent: cachedRoute.percent,
}
}

public static unmarshal(marshalledCachedRoute: MarshalledCachedRoute): CachedRoute<V3Route | V2Route | MixedRoute> {
return new CachedRoute<V3Route | V2Route | MixedRoute>({
public static unmarshal(marshalledCachedRoute: MarshalledCachedRoute): CachedRoute<SupportedRoutes> {
return new CachedRoute<SupportedRoutes>({
route: RouteMarshaller.unmarshal(marshalledCachedRoute.route),
percent: marshalledCachedRoute.percent,
})
Expand Down
2 changes: 1 addition & 1 deletion lib/handlers/marshalling/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ export * from './cached-route-marshaller'
export * from './cached-routes-marshaller'
export * from './currency-amount-marshaller'
export * from './pair-marshaller'
export * from './pool-marshaller'
export * from './v3/pool-marshaller'
export * from './route-marshaller'
export * from './token-marshaller'
72 changes: 56 additions & 16 deletions lib/handlers/marshalling/route-marshaller.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { MixedRoute, V2Route, V3Route } from '@uniswap/smart-order-router/build/main/routers'
import { MixedRoute, V2Route, V3Route, V4Route } from '@uniswap/smart-order-router/build/main/routers'
import { Protocol } from '@uniswap/router-sdk'
import { MarshalledToken, TokenMarshaller } from './token-marshaller'
import { MarshalledPair, PairMarshaller } from './pair-marshaller'
import { MarshalledPool, PoolMarshaller } from './pool-marshaller'
import { Pool } from '@uniswap/v3-sdk'
import { MarshalledPool as V3MarshalledPool, PoolMarshaller as V3PoolMarshaller } from './v3/pool-marshaller'
import { MarshalledPool as V4MarshalledPool, PoolMarshaller as V4PoolMarshaller } from './v4/pool-marshaller'
import { Pool as V3Pool } from '@uniswap/v3-sdk'
import { Pool as V4Pool } from '@uniswap/v4-sdk'
import { SupportedRoutes } from '@uniswap/smart-order-router'
import { Pair } from '@uniswap/v2-sdk'

export interface MarshalledV2Route {
protocol: Protocol
Expand All @@ -16,20 +20,27 @@ export interface MarshalledV3Route {
protocol: Protocol
input: MarshalledToken
output: MarshalledToken
pools: MarshalledPool[]
pools: V3MarshalledPool[]
}

export interface MarshalledV4Route {
protocol: Protocol
input: MarshalledToken
output: MarshalledToken
pools: V4MarshalledPool[]
}

export interface MarshalledMixedRoute {
protocol: Protocol
input: MarshalledToken
output: MarshalledToken
pools: (MarshalledPool | MarshalledPair)[]
pools: (V4MarshalledPool | V3MarshalledPool | MarshalledPair)[]
}

export type MarshalledRoute = MarshalledV2Route | MarshalledV3Route | MarshalledMixedRoute

export class RouteMarshaller {
public static marshal(route: V3Route | V2Route | MixedRoute): MarshalledRoute {
public static marshal(route: SupportedRoutes): MarshalledRoute {
switch (route.protocol) {
case Protocol.V2:
return {
Expand All @@ -43,25 +54,42 @@ export class RouteMarshaller {
protocol: Protocol.V3,
input: TokenMarshaller.marshal(route.input),
output: TokenMarshaller.marshal(route.output),
pools: route.pools.map((pool) => PoolMarshaller.marshal(pool)),
pools: route.pools.map((pool) => V3PoolMarshaller.marshal(pool)),
}
case Protocol.V4:
return {
protocol: Protocol.V4,
// TODO: ROUTE-217 - Support native currency routing in V4
// token.wrapped is wrong for V4
// Probably need to use the token symbol for native, and still use address for non-native tokens
// Check later CELO token, which is both native and ERC20, which one to use
input: TokenMarshaller.marshal(route.input.wrapped),
output: TokenMarshaller.marshal(route.output.wrapped),
pools: route.pools.map((pool) => V4PoolMarshaller.marshal(pool)),
}
case Protocol.MIXED:
return {
protocol: Protocol.MIXED,
input: TokenMarshaller.marshal(route.input),
output: TokenMarshaller.marshal(route.output),
pools: route.pools.map((tpool) => {
if (tpool instanceof Pool) {
return PoolMarshaller.marshal(tpool)
} else {
if (tpool instanceof V3Pool) {
return V3PoolMarshaller.marshal(tpool)
} else if (tpool instanceof V4Pool) {
return V4PoolMarshaller.marshal(tpool)
} else if (tpool instanceof Pair) {
return PairMarshaller.marshal(tpool)
} else {
throw new Error(`Unsupported pool type ${JSON.stringify(tpool)}`)
}
}),
}
default:
throw new Error(`Unsupported protocol ${JSON.stringify(route)}`)
}
}

public static unmarshal(marshalledRoute: MarshalledRoute): V3Route | V2Route | MixedRoute {
public static unmarshal(marshalledRoute: MarshalledRoute): SupportedRoutes {
switch (marshalledRoute.protocol) {
case Protocol.V2:
const v2Route = marshalledRoute as MarshalledV2Route
Expand All @@ -73,17 +101,29 @@ export class RouteMarshaller {
case Protocol.V3:
const v3Route = marshalledRoute as MarshalledV3Route
return new V3Route(
v3Route.pools.map((marshalledPool) => PoolMarshaller.unmarshal(marshalledPool)),
v3Route.pools.map((marshalledPool) => V3PoolMarshaller.unmarshal(marshalledPool)),
TokenMarshaller.unmarshal(v3Route.input),
TokenMarshaller.unmarshal(v3Route.output)
)
case Protocol.V4:
const v4Route = marshalledRoute as MarshalledV4Route
return new V4Route(
v4Route.pools.map((marshalledPool) => V4PoolMarshaller.unmarshal(marshalledPool)),
TokenMarshaller.unmarshal(v4Route.input),
TokenMarshaller.unmarshal(v4Route.output)
)
case Protocol.MIXED:
const mixedRoute = marshalledRoute as MarshalledMixedRoute
const tpools = mixedRoute.pools.map((tpool) => {
if (tpool.protocol === Protocol.V2) {
return PairMarshaller.unmarshal(tpool as MarshalledPair)
} else {
return PoolMarshaller.unmarshal(tpool as MarshalledPool)
switch (tpool.protocol) {
case Protocol.V2:
return PairMarshaller.unmarshal(tpool as MarshalledPair)
case Protocol.V3:
return V3PoolMarshaller.unmarshal(tpool as V3MarshalledPool)
case Protocol.V4:
return V4PoolMarshaller.unmarshal(tpool as V4MarshalledPool)
default:
throw new Error(`Unsupported protocol ${JSON.stringify(tpool)}`)
}
})

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Pool } from '@uniswap/v3-sdk'
import { FeeAmount } from '@uniswap/v3-sdk/dist/constants'
import { MarshalledToken, TokenMarshaller } from './token-marshaller'
import { MarshalledToken, TokenMarshaller } from '../token-marshaller'
import { Protocol } from '@uniswap/router-sdk'

export interface MarshalledPool {
Expand Down
47 changes: 47 additions & 0 deletions lib/handlers/marshalling/v4/pool-marshaller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Pool } from '@uniswap/v4-sdk'
import { FeeAmount } from '@uniswap/v3-sdk/dist/constants'
import { MarshalledToken, TokenMarshaller } from '../token-marshaller'
import { Protocol } from '@uniswap/router-sdk'

export interface MarshalledPool {
protocol: Protocol
token0: MarshalledToken
token1: MarshalledToken
fee: FeeAmount
tickSpacing: number
hooks: string
sqrtRatioX96: string
liquidity: string
tickCurrent: number
}

export class PoolMarshaller {
public static marshal(pool: Pool): MarshalledPool {
return {
protocol: Protocol.V4,
// TODO: ROUTE-217 - Support native currency routing in V4
// V4 we should not just wrap
token0: TokenMarshaller.marshal(pool.token0.wrapped),
token1: TokenMarshaller.marshal(pool.token1.wrapped),
fee: pool.fee,
tickSpacing: pool.tickSpacing,
hooks: pool.hooks,
sqrtRatioX96: pool.sqrtRatioX96.toString(),
liquidity: pool.liquidity.toString(),
tickCurrent: pool.tickCurrent,
}
}

public static unmarshal(marshalledPool: MarshalledPool): Pool {
return new Pool(
TokenMarshaller.unmarshal(marshalledPool.token0),
TokenMarshaller.unmarshal(marshalledPool.token1),
marshalledPool.fee,
marshalledPool.tickSpacing,
marshalledPool.hooks,
marshalledPool.sqrtRatioX96,
marshalledPool.liquidity,
marshalledPool.tickCurrent
)
}
}
2 changes: 1 addition & 1 deletion lib/handlers/pools/pool-caching/v3/cache-dynamo-pool.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { DynamoCaching, DynamoCachingProps } from '../cache-dynamo'
import { Pool } from '@uniswap/v3-sdk'
import { log, metric, MetricLoggerUnit } from '@uniswap/smart-order-router'
import { PoolMarshaller } from '../../../marshalling/pool-marshaller'
import { PoolMarshaller } from '../../../marshalling/v3/pool-marshaller'

interface DynamoCachingV3PoolProps extends DynamoCachingProps {}

Expand Down
21 changes: 14 additions & 7 deletions lib/handlers/quote/quote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import {
SwapOptions,
SwapRoute,
} from '@uniswap/smart-order-router'
import { Pool } from '@uniswap/v3-sdk'
import { Pool as V3Pool } from '@uniswap/v3-sdk'
import { Pool as V4Pool } from '@uniswap/v4-sdk'
import JSBI from 'jsbi'
import _ from 'lodash'
import { APIGLambdaHandler, ErrorResponse, HandleRequestParams, Response } from '../handler'
Expand All @@ -35,6 +36,7 @@ import { SwapOptionsFactory } from './SwapOptionsFactory'
import { GlobalRpcProviders } from '../../rpc/GlobalRpcProviders'
import { adhocCorrectGasUsed } from '../../util/estimateGasUsed'
import { adhocCorrectGasUsedUSD } from '../../util/estimateGasUsedUSD'
import { Pair } from '@uniswap/v2-sdk'

export class QuoteHandler extends APIGLambdaHandler<
ContainerInjected,
Expand Down Expand Up @@ -502,20 +504,23 @@ export class QuoteHandler extends APIGLambdaHandler<
edgeAmountOut = type == 'exactIn' ? quote.quotient.toString() : amount.quotient.toString()
}

if (nextPool instanceof Pool) {
if (nextPool instanceof V4Pool) {
// TODO - ROUTE-220: Support V4 Pool
throw new Error(`V4 pools are not supported in quote response deserialization ${JSON.stringify(nextPool)}`)
} else if (nextPool instanceof V3Pool) {
curRoute.push({
type: 'v3-pool',
address: v3PoolProvider.getPoolAddress(nextPool.token0, nextPool.token1, nextPool.fee).poolAddress,
tokenIn: {
chainId: tokenIn.chainId,
decimals: tokenIn.decimals.toString(),
address: tokenIn.address,
address: tokenIn.wrapped.address,
symbol: tokenIn.symbol!,
},
tokenOut: {
chainId: tokenOut.chainId,
decimals: tokenOut.decimals.toString(),
address: tokenOut.address,
address: tokenOut.wrapped.address,
symbol: tokenOut.symbol!,
},
fee: nextPool.fee.toString(),
Expand All @@ -525,7 +530,7 @@ export class QuoteHandler extends APIGLambdaHandler<
amountIn: edgeAmountIn,
amountOut: edgeAmountOut,
})
} else {
} else if (nextPool instanceof Pair) {
const reserve0 = nextPool.reserve0
const reserve1 = nextPool.reserve1

Expand All @@ -535,15 +540,15 @@ export class QuoteHandler extends APIGLambdaHandler<
tokenIn: {
chainId: tokenIn.chainId,
decimals: tokenIn.decimals.toString(),
address: tokenIn.address,
address: tokenIn.wrapped.address,
symbol: tokenIn.symbol!,
buyFeeBps: this.deriveBuyFeeBps(tokenIn, reserve0, reserve1, enableFeeOnTransferFeeFetching),
sellFeeBps: this.deriveSellFeeBps(tokenIn, reserve0, reserve1, enableFeeOnTransferFeeFetching),
},
tokenOut: {
chainId: tokenOut.chainId,
decimals: tokenOut.decimals.toString(),
address: tokenOut.address,
address: tokenOut.wrapped.address,
symbol: tokenOut.symbol!,
buyFeeBps: this.deriveBuyFeeBps(tokenOut, reserve0, reserve1, enableFeeOnTransferFeeFetching),
sellFeeBps: this.deriveSellFeeBps(tokenOut, reserve0, reserve1, enableFeeOnTransferFeeFetching),
Expand Down Expand Up @@ -593,6 +598,8 @@ export class QuoteHandler extends APIGLambdaHandler<
amountIn: edgeAmountIn,
amountOut: edgeAmountOut,
})
} else {
throw new Error(`Unsupported pool type ${JSON.stringify(nextPool)}`)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import {
metric,
MetricLoggerUnit,
routeToString,
SupportedRoutes,
} from '@uniswap/smart-order-router'
import { AWSError, DynamoDB, Lambda } from 'aws-sdk'
import { ChainId, Currency, CurrencyAmount, Fraction, Token, TradeType } from '@uniswap/sdk-core'
import { Protocol } from '@uniswap/router-sdk'
import { PairTradeTypeChainId } from './model/pair-trade-type-chain-id'
import { CachedRoutesMarshaller } from '../../marshalling/cached-routes-marshaller'
import { MixedRoute, V2Route, V3Route } from '@uniswap/smart-order-router/build/main/routers'
import { PromiseResult } from 'aws-sdk/lib/request'

interface ConstructorParams {
Expand Down Expand Up @@ -208,7 +208,7 @@ export class DynamoRouteCachingProvider extends IRouteCachingProvider {
return CachedRoutesMarshaller.unmarshal(cachedRoutesJson)
})

const routesMap: Map<string, CachedRoute<V3Route | V2Route | MixedRoute>> = new Map()
const routesMap: Map<string, CachedRoute<SupportedRoutes>> = new Map()
let blockNumber: number = 0
let originalAmount: string = ''

Expand Down
Loading
Loading