Skip to content

Commit

Permalink
chore: bump sor to 4.7.0 - feat: SOR level implementation to support …
Browse files Browse the repository at this point in the history
…1) expanding mixed quoter v1 to L2s 2) support migrate mixed quoter v1 to mixed quoter v2 across chains (#868)

* chore: bump sor to 4.7.0 - feat: SOR level implementation to support 1) expanding mixed quoter v1 to L2s 2) support migrate mixed quoter v1 to mixed quoter v2 across chains

* mixed supported adding base L2

* v4 should not switch to view-only quoter because it doesn;t exist

* protocol is a enum key for gas params

* enhance test covearge

* only have target having the base mixed quoter v1
  • Loading branch information
jsy1218 authored Oct 15, 2024
1 parent 297b95d commit 87ca978
Show file tree
Hide file tree
Showing 7 changed files with 640 additions and 201 deletions.
30 changes: 20 additions & 10 deletions lib/handlers/injector-sor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ import { OnChainTokenFeeFetcher } from '@uniswap/smart-order-router/build/main/p
import { PortionProvider } from '@uniswap/smart-order-router/build/main/providers/portion-provider'
import { GlobalRpcProviders } from '../rpc/GlobalRpcProviders'
import { StaticJsonRpcProvider } from '@ethersproject/providers'
import { TrafficSwitchOnChainQuoteProvider } from './quote/provider-migration/v3/traffic-switch-on-chain-quote-provider'
import { TrafficSwitchOnChainQuoteProvider } from './quote/provider-migration/traffic-switch-on-chain-quote-provider'
import {
BLOCK_NUMBER_CONFIGS,
GAS_ERROR_FAILURE_OVERRIDES,
Expand Down Expand Up @@ -356,15 +356,17 @@ export abstract class InjectorSOR<Router, QueryParams> extends Injector<
provider,
multicall2Provider,
RETRY_OPTIONS[chainId],
(optimisticCachedRoutes, useMixedRouteQuoter) => {
const protocol = useMixedRouteQuoter ? Protocol.MIXED : Protocol.V3
(optimisticCachedRoutes, protocol) => {
return optimisticCachedRoutes
? OPTIMISTIC_CACHED_ROUTES_BATCH_PARAMS[protocol][chainId]
: NON_OPTIMISTIC_CACHED_ROUTES_BATCH_PARAMS[protocol][chainId]
},
GAS_ERROR_FAILURE_OVERRIDES[chainId],
SUCCESS_RATE_FAILURE_OVERRIDES[chainId],
BLOCK_NUMBER_CONFIGS[chainId],
// nice to have protocol level gas error failure overrides, this is in prep for v4 and mixed w/ v4
(_protocol) => GAS_ERROR_FAILURE_OVERRIDES[chainId],
// nice to have protocol level success rate failure overrides, this is in prep for v4 and mixed w/ v4
(_protocol) => SUCCESS_RATE_FAILURE_OVERRIDES[chainId],
// nice to have protocol level block number configs overrides, this is in prep for v4 and mixed w/ v4
(_protocol) => BLOCK_NUMBER_CONFIGS[chainId],
// We will only enable shadow sample mixed quoter on Base
(useMixedRouteQuoter: boolean, mixedRouteContainsV4Pool: boolean, protocol: Protocol) =>
useMixedRouteQuoter
Expand All @@ -386,14 +388,19 @@ export abstract class InjectorSOR<Router, QueryParams> extends Injector<
? OPTIMISTIC_CACHED_ROUTES_BATCH_PARAMS[protocol][chainId]
: NON_OPTIMISTIC_CACHED_ROUTES_BATCH_PARAMS[protocol][chainId]
},
GAS_ERROR_FAILURE_OVERRIDES[chainId],
SUCCESS_RATE_FAILURE_OVERRIDES[chainId],
BLOCK_NUMBER_CONFIGS[chainId],
// nice to have protocol level gas error failure overrides, this is in prep for v4 and mixed w/ v4
(_protocol) => GAS_ERROR_FAILURE_OVERRIDES[chainId],
// nice to have protocol level success rate failure overrides, this is in prep for v4 and mixed w/ v4
(_protocol) => SUCCESS_RATE_FAILURE_OVERRIDES[chainId],
// nice to have protocol level block number configs overrides, this is in prep for v4 and mixed w/ v4
(_protocol) => BLOCK_NUMBER_CONFIGS[chainId],
(useMixedRouteQuoter: boolean, mixedRouteContainsV4Pool: boolean, protocol: Protocol) =>
useMixedRouteQuoter
? mixedRouteContainsV4Pool
? MIXED_ROUTE_QUOTER_V2_ADDRESSES[chainId]
: MIXED_ROUTE_QUOTER_V1_ADDRESSES[chainId]
: MIXED_ROUTE_QUOTER_V1_ADDRESSES[chainId] ??
// besides mainnet, only base has mixed quoter v1 deployed
(chainId === ChainId.BASE ? '0xe544efae946f0008ae9a8d64493efa7886b73776' : undefined)
: protocol === Protocol.V3
? NEW_QUOTER_V2_ADDRESSES[chainId]
: PROTOCOL_V4_QUOTER_ADDRESSES[chainId],
Expand Down Expand Up @@ -469,6 +476,8 @@ export abstract class InjectorSOR<Router, QueryParams> extends Injector<

const v4Supported = [ChainId.SEPOLIA]

const mixedSupported = [ChainId.MAINNET, ChainId.SEPOLIA, ChainId.GOERLI]

return {
chainId,
dependencies: {
Expand Down Expand Up @@ -501,6 +510,7 @@ export abstract class InjectorSOR<Router, QueryParams> extends Injector<
tokenPropertiesProvider,
v2Supported,
v4Supported,
mixedSupported,
},
}
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import {
} from '@uniswap/smart-order-router'
import { ChainId, Currency, CurrencyAmount } from '@uniswap/sdk-core'
import { ProviderConfig } from '@uniswap/smart-order-router/build/main/providers/provider'
import { QUOTE_PROVIDER_TRAFFIC_SWITCH_CONFIGURATION } from '../../util/quote-provider-traffic-switch-configuration'
import { QUOTE_PROVIDER_TRAFFIC_SWITCH_CONFIGURATION } from '../util/quote-provider-traffic-switch-configuration'
import { BigNumber } from 'ethers'
import { LIKELY_OUT_OF_GAS_THRESHOLD, NEW_QUOTER_DEPLOY_BLOCK } from '../../../../util/onChainQuoteProviderConfigs'
import { LIKELY_OUT_OF_GAS_THRESHOLD, NEW_QUOTER_DEPLOY_BLOCK } from '../../../util/onChainQuoteProviderConfigs'
import { Protocol } from '@uniswap/router-sdk'

export type TrafficSwitchOnChainQuoteProviderProps = {
currentQuoteProvider: IOnChainQuoteProvider
Expand All @@ -24,14 +25,16 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider
private readonly targetQuoteProvider: IOnChainQuoteProvider
private readonly chainId: ChainId

protected readonly SHOULD_SWITCH_EXACT_IN_TRAFFIC = (chainId: ChainId) =>
QUOTE_PROVIDER_TRAFFIC_SWITCH_CONFIGURATION(chainId).switchExactInPercentage > this.getRandomPercentage()
protected readonly SHOULD_SAMPLE_EXACT_IN_TRAFFIC = (chainId: ChainId) =>
QUOTE_PROVIDER_TRAFFIC_SWITCH_CONFIGURATION(chainId).samplingExactInPercentage > this.getRandomPercentage()
protected readonly SHOULD_SWITCH_EXACT_OUT_TRAFFIC = (chainId: ChainId) =>
QUOTE_PROVIDER_TRAFFIC_SWITCH_CONFIGURATION(chainId).switchExactOutPercentage > this.getRandomPercentage()
protected readonly SHOULD_SAMPLE_EXACT_OUT_TRAFFIC = (chainId: ChainId) =>
QUOTE_PROVIDER_TRAFFIC_SWITCH_CONFIGURATION(chainId).samplingExactOutPercentage > this.getRandomPercentage()
protected readonly SHOULD_SWITCH_EXACT_IN_TRAFFIC = (chainId: ChainId, protocol: Protocol) =>
QUOTE_PROVIDER_TRAFFIC_SWITCH_CONFIGURATION(chainId, protocol).switchExactInPercentage > this.getRandomPercentage()
protected readonly SHOULD_SAMPLE_EXACT_IN_TRAFFIC = (chainId: ChainId, protocol: Protocol) =>
QUOTE_PROVIDER_TRAFFIC_SWITCH_CONFIGURATION(chainId, protocol).samplingExactInPercentage >
this.getRandomPercentage()
protected readonly SHOULD_SWITCH_EXACT_OUT_TRAFFIC = (chainId: ChainId, protocol: Protocol) =>
QUOTE_PROVIDER_TRAFFIC_SWITCH_CONFIGURATION(chainId, protocol).switchExactOutPercentage > this.getRandomPercentage()
protected readonly SHOULD_SAMPLE_EXACT_OUT_TRAFFIC = (chainId: ChainId, protocol: Protocol) =>
QUOTE_PROVIDER_TRAFFIC_SWITCH_CONFIGURATION(chainId, protocol).samplingExactOutPercentage >
this.getRandomPercentage()

private readonly EXACT_IN_METRIC = 'EXACT_IN'
private readonly EXACT_OUT_METRIC = 'EXACT_OUT'
Expand All @@ -47,23 +50,29 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider
routes: TRoute[],
providerConfig?: ProviderConfig
): Promise<OnChainQuotes<TRoute>> {
const sampleTraffic = this.SHOULD_SAMPLE_EXACT_IN_TRAFFIC(this.chainId)
const switchTraffic = this.SHOULD_SWITCH_EXACT_IN_TRAFFIC(this.chainId)
const useMixedRouteQuoter =
routes.some((route) => route.protocol === Protocol.V2) ||
routes.some((route) => route.protocol === Protocol.MIXED)
const useV4RouteQuoter = routes.some((route) => route.protocol === Protocol.V4) && !useMixedRouteQuoter
const protocol = useMixedRouteQuoter ? Protocol.MIXED : useV4RouteQuoter ? Protocol.V4 : Protocol.V3

const sampleTraffic = this.SHOULD_SAMPLE_EXACT_IN_TRAFFIC(this.chainId, protocol)
const switchTraffic = this.SHOULD_SWITCH_EXACT_IN_TRAFFIC(this.chainId, protocol)

let [currentRoutesWithQuotes, targetRoutesWithQuotes]: [
OnChainQuotes<TRoute> | undefined,
OnChainQuotes<TRoute> | undefined
] = [undefined, undefined]

metric.putMetric(
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_IN_METRIC}_TRAFFIC_TOTAL_CHAIN_ID_${this.chainId}`,
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_IN_METRIC}_TRAFFIC_TOTAL_CHAIN_ID_${this.chainId}_PROTOCOL_${protocol}`,
1,
MetricLoggerUnit.None
)

if (sampleTraffic) {
metric.putMetric(
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_IN_METRIC}_TRAFFIC_SAMPLING_CHAIN_ID_${this.chainId}`,
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_IN_METRIC}_TRAFFIC_SAMPLING_CHAIN_ID_${this.chainId}_PROTOCOL_${protocol}`,
1,
MetricLoggerUnit.None
)
Expand All @@ -83,15 +92,15 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider
])

if (currentRoutesWithQuotes && targetRoutesWithQuotes) {
this.compareQuotes(this.EXACT_IN_METRIC, currentRoutesWithQuotes, targetRoutesWithQuotes)
this.compareQuotes(this.EXACT_IN_METRIC, currentRoutesWithQuotes, targetRoutesWithQuotes, protocol)
}
} catch (error) {
if (currentQuoterSucceeded && !targetQuoterSuceeded) {
// If we can enter here, it means the current quoter can return without throwing error,
// but the new quoter threw error, and we swallowed exception here. This is the case worth tracking.
log.error({ error }, 'Target quoter failed to return quotes')
metric.putMetric(
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_IN_METRIC}_TRAFFIC_TARGET_FAILED_CHAIN_ID_${this.chainId}`,
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_IN_METRIC}_TRAFFIC_TARGET_FAILED_CHAIN_ID_${this.chainId}_PROTOCOL_${protocol}`,
1,
MetricLoggerUnit.None
)
Expand All @@ -101,7 +110,7 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider

if (switchTraffic) {
metric.putMetric(
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_IN_METRIC}_TRAFFIC_TARGET_CHAIN_ID_${this.chainId}`,
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_IN_METRIC}_TRAFFIC_TARGET_CHAIN_ID_${this.chainId}_PROTOCOL_${protocol}`,
1,
MetricLoggerUnit.None
)
Expand All @@ -112,7 +121,7 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider
)
} else {
metric.putMetric(
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_IN_METRIC}_TRAFFIC_CURRENT_CHAIN_ID_${this.chainId}`,
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_IN_METRIC}_TRAFFIC_CURRENT_CHAIN_ID_${this.chainId}_PROTOCOL_${protocol}`,
1,
MetricLoggerUnit.None
)
Expand All @@ -129,22 +138,26 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider
routes: TRoute[],
providerConfig?: ProviderConfig
): Promise<OnChainQuotes<TRoute>> {
const sampleTraffic = this.SHOULD_SAMPLE_EXACT_OUT_TRAFFIC(this.chainId)
const switchTraffic = this.SHOULD_SWITCH_EXACT_OUT_TRAFFIC(this.chainId)
// exact out cannot use mixed route quoter
const useV4RouteQuoter = routes.some((route) => route.protocol === Protocol.V4)
const protocol = useV4RouteQuoter ? Protocol.V4 : Protocol.V3

const sampleTraffic = this.SHOULD_SAMPLE_EXACT_OUT_TRAFFIC(this.chainId, protocol)
const switchTraffic = this.SHOULD_SWITCH_EXACT_OUT_TRAFFIC(this.chainId, protocol)

let [currentRoutesWithQuotes, targetRoutesWithQuotes]: [
OnChainQuotes<TRoute> | undefined,
OnChainQuotes<TRoute> | undefined
] = [undefined, undefined]
metric.putMetric(
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_OUT_METRIC}_TRAFFIC_TOTAL_CHAIN_ID_${this.chainId}`,
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_OUT_METRIC}_TRAFFIC_TOTAL_CHAIN_ID_${this.chainId}_PROTOCOL_${protocol}`,
1,
MetricLoggerUnit.None
)

if (sampleTraffic) {
metric.putMetric(
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_OUT_METRIC}_TRAFFIC_SAMPLING_CHAIN_ID_${this.chainId}`,
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_OUT_METRIC}_TRAFFIC_SAMPLING_CHAIN_ID_${this.chainId}_PROTOCOL_${protocol}`,
1,
MetricLoggerUnit.None
)
Expand All @@ -158,7 +171,7 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider
currentQuoterSucceeded = true
const endTime = Date.now()
metric.putMetric(
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_OUT_METRIC}_TRAFFIC_CURRENT_LATENCIES_CHAIN_ID_${this.chainId}`,
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_OUT_METRIC}_TRAFFIC_CURRENT_LATENCIES_CHAIN_ID_${this.chainId}_PROTOCOL_${protocol}`,
endTime - startTime,
MetricLoggerUnit.Milliseconds
)
Expand All @@ -168,7 +181,7 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider
targetQuoterSuceeded = true
const endTime = Date.now()
metric.putMetric(
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_OUT_METRIC}_TRAFFIC_TARGET_LATENCIES_CHAIN_ID_${this.chainId}`,
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_OUT_METRIC}_TRAFFIC_TARGET_LATENCIES_CHAIN_ID_${this.chainId}_PROTOCOL_${protocol}`,
endTime - startTime,
MetricLoggerUnit.Milliseconds
)
Expand All @@ -177,15 +190,15 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider
])

if (currentRoutesWithQuotes && targetRoutesWithQuotes) {
this.compareQuotes(this.EXACT_OUT_METRIC, currentRoutesWithQuotes, targetRoutesWithQuotes)
this.compareQuotes(this.EXACT_OUT_METRIC, currentRoutesWithQuotes, targetRoutesWithQuotes, protocol)
}
} catch (error) {
if (currentQuoterSucceeded && !targetQuoterSuceeded) {
// If we can enter here, it means the current quoter can return without throwing error,
// but the new quoter threw error, and we swallowed exception here. This is the case worth tracking.
log.error({ error }, 'Target quoter failed to return quotes')
metric.putMetric(
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_OUT_METRIC}_TRAFFIC_TARGET_FAILED_CHAIN_ID_${this.chainId}`,
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_OUT_METRIC}_TRAFFIC_TARGET_FAILED_CHAIN_ID_${this.chainId}_PROTOCOL_${protocol}`,
1,
MetricLoggerUnit.None
)
Expand All @@ -195,7 +208,7 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider

if (switchTraffic) {
metric.putMetric(
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_OUT_METRIC}_TRAFFIC_TARGET_CHAIN_ID_${this.chainId}`,
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_OUT_METRIC}_TRAFFIC_TARGET_CHAIN_ID_${this.chainId}_PROTOCOL_${protocol}`,
1,
MetricLoggerUnit.None
)
Expand All @@ -206,7 +219,7 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider
)
} else {
metric.putMetric(
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_OUT_METRIC}_TRAFFIC_CURRENT_CHAIN_ID_${this.chainId}`,
`ON_CHAIN_QUOTE_PROVIDER_${this.EXACT_OUT_METRIC}_TRAFFIC_CURRENT_CHAIN_ID_${this.chainId}_PROTOCOL_${protocol}`,
1,
MetricLoggerUnit.None
)
Expand All @@ -221,7 +234,8 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider
private compareQuotes<TRoute extends SupportedRoutes>(
tradeTypeMetric: string,
currentRoutesWithQuotes: OnChainQuotes<TRoute>,
targetRoutesWithQuotes: OnChainQuotes<TRoute>
targetRoutesWithQuotes: OnChainQuotes<TRoute>,
protocol: Protocol
): void {
// If the quote comparison happens right on or before the quote deploy block, we skip the entire comparison
if (targetRoutesWithQuotes.blockNumber.lte(NEW_QUOTER_DEPLOY_BLOCK[this.chainId])) {
Expand All @@ -237,7 +251,7 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider
'Current and target quote providers returned different block numbers'
)
metric.putMetric(
`ON_CHAIN_QUOTE_PROVIDER_${tradeTypeMetric}_TRAFFIC_CURRENT_AND_TARGET_BLOCK_NUM_MISMATCH_CHAIN_ID_${this.chainId}`,
`ON_CHAIN_QUOTE_PROVIDER_${tradeTypeMetric}_TRAFFIC_CURRENT_AND_TARGET_BLOCK_NUM_MISMATCH_CHAIN_ID_${this.chainId}_PROTOCOL_${protocol}`,
1,
MetricLoggerUnit.None
)
Expand All @@ -254,7 +268,7 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider
'Current and target quote providers returned different number of routes with quotes'
)
metric.putMetric(
`ON_CHAIN_QUOTE_PROVIDER_${tradeTypeMetric}_TRAFFIC_CURRENT_AND_TARGET_ROUTES_WITH_QUOTES_MISMATCH_CHAIN_ID_${this.chainId}`,
`ON_CHAIN_QUOTE_PROVIDER_${tradeTypeMetric}_TRAFFIC_CURRENT_AND_TARGET_ROUTES_WITH_QUOTES_MISMATCH_CHAIN_ID_${this.chainId}_PROTOCOL_${protocol}`,
1,
MetricLoggerUnit.None
)
Expand All @@ -279,7 +293,7 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider
'Current and target quote providers returned different number of quotes'
)
metric.putMetric(
`ON_CHAIN_QUOTE_PROVIDER_${tradeTypeMetric}_TRAFFIC_CURRENT_AND_TARGET_NUMBER_OF_QUOTES_MISMATCH_CHAIN_ID_${this.chainId}`,
`ON_CHAIN_QUOTE_PROVIDER_${tradeTypeMetric}_TRAFFIC_CURRENT_AND_TARGET_NUMBER_OF_QUOTES_MISMATCH_CHAIN_ID_${this.chainId}_PROTOCOL_${protocol}`,
1,
MetricLoggerUnit.None
)
Expand Down Expand Up @@ -314,7 +328,7 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider
`Current and target quote providers returned different quotes at block ${targetRoutesWithQuotes.blockNumber}`
)
metric.putMetric(
`ON_CHAIN_QUOTE_PROVIDER_${tradeTypeMetric}_TRAFFIC_CURRENT_AND_TARGET_QUOTES_MISMATCH_CHAIN_ID_${this.chainId}`,
`ON_CHAIN_QUOTE_PROVIDER_${tradeTypeMetric}_TRAFFIC_CURRENT_AND_TARGET_QUOTES_MISMATCH_CHAIN_ID_${this.chainId}_PROTOCOL_${protocol}`,
1,
MetricLoggerUnit.None
)
Expand Down
Loading

0 comments on commit 87ca978

Please sign in to comment.