From 87ca978c152c388272c37eb7bbb4b0494bc763ba Mon Sep 17 00:00:00 2001 From: "Siyu Jiang (See-You John)" <91580504+jsy1218@users.noreply.github.com> Date: Tue, 15 Oct 2024 13:57:40 -0700 Subject: [PATCH] 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 (#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 --- lib/handlers/injector-sor.ts | 30 +- .../traffic-switch-on-chain-quote-provider.ts | 80 ++-- ...e-provider-traffic-switch-configuration.ts | 301 +++++++++++----- lib/util/onChainQuoteProviderConfigs.ts | 341 ++++++++++++++++-- package-lock.json | 14 +- package.json | 2 +- .../traffic-switch-quote-provider.test.ts | 73 ++-- 7 files changed, 640 insertions(+), 201 deletions(-) rename lib/handlers/quote/provider-migration/{v3 => }/traffic-switch-on-chain-quote-provider.ts (81%) diff --git a/lib/handlers/injector-sor.ts b/lib/handlers/injector-sor.ts index 7b3b91fa9c..ceb0066033 100644 --- a/lib/handlers/injector-sor.ts +++ b/lib/handlers/injector-sor.ts @@ -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, @@ -356,15 +356,17 @@ export abstract class InjectorSOR 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 @@ -386,14 +388,19 @@ export abstract class InjectorSOR 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], @@ -469,6 +476,8 @@ export abstract class InjectorSOR extends Injector< const v4Supported = [ChainId.SEPOLIA] + const mixedSupported = [ChainId.MAINNET, ChainId.SEPOLIA, ChainId.GOERLI] + return { chainId, dependencies: { @@ -501,6 +510,7 @@ export abstract class InjectorSOR extends Injector< tokenPropertiesProvider, v2Supported, v4Supported, + mixedSupported, }, } }) diff --git a/lib/handlers/quote/provider-migration/v3/traffic-switch-on-chain-quote-provider.ts b/lib/handlers/quote/provider-migration/traffic-switch-on-chain-quote-provider.ts similarity index 81% rename from lib/handlers/quote/provider-migration/v3/traffic-switch-on-chain-quote-provider.ts rename to lib/handlers/quote/provider-migration/traffic-switch-on-chain-quote-provider.ts index dc49ffda75..9fb30b5d1b 100644 --- a/lib/handlers/quote/provider-migration/v3/traffic-switch-on-chain-quote-provider.ts +++ b/lib/handlers/quote/provider-migration/traffic-switch-on-chain-quote-provider.ts @@ -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 @@ -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' @@ -47,8 +50,14 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider routes: TRoute[], providerConfig?: ProviderConfig ): Promise> { - 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 | undefined, @@ -56,14 +65,14 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider ] = [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 ) @@ -83,7 +92,7 @@ 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) { @@ -91,7 +100,7 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider // 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 ) @@ -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 ) @@ -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 ) @@ -129,22 +138,26 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider routes: TRoute[], providerConfig?: ProviderConfig ): Promise> { - 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 | undefined, OnChainQuotes | 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 ) @@ -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 ) @@ -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 ) @@ -177,7 +190,7 @@ 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) { @@ -185,7 +198,7 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider // 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 ) @@ -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 ) @@ -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 ) @@ -221,7 +234,8 @@ export class TrafficSwitchOnChainQuoteProvider implements IOnChainQuoteProvider private compareQuotes( tradeTypeMetric: string, currentRoutesWithQuotes: OnChainQuotes, - targetRoutesWithQuotes: OnChainQuotes + targetRoutesWithQuotes: OnChainQuotes, + 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])) { @@ -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 ) @@ -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 ) @@ -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 ) @@ -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 ) diff --git a/lib/handlers/quote/util/quote-provider-traffic-switch-configuration.ts b/lib/handlers/quote/util/quote-provider-traffic-switch-configuration.ts index 18395ec9a9..ae600ead27 100644 --- a/lib/handlers/quote/util/quote-provider-traffic-switch-configuration.ts +++ b/lib/handlers/quote/util/quote-provider-traffic-switch-configuration.ts @@ -1,4 +1,5 @@ import { ChainId } from '@uniswap/sdk-core' +import { Protocol } from '@uniswap/router-sdk' export type QuoteProviderTrafficSwitchConfiguration = { switchExactInPercentage: number @@ -8,106 +9,244 @@ export type QuoteProviderTrafficSwitchConfiguration = { } export const QUOTE_PROVIDER_TRAFFIC_SWITCH_CONFIGURATION = ( - chainId: ChainId + chainId: ChainId, + protocol: Protocol // only v3 and mixed on L1 is alive, once it needs to live switch 100%, otherwise, can have 0% switch ): QuoteProviderTrafficSwitchConfiguration => { switch (chainId) { // Mumbai was deprecated on April 13th. Do not sample at all case ChainId.POLYGON_MUMBAI: - return { - switchExactInPercentage: 0.0, - samplingExactInPercentage: 0, - switchExactOutPercentage: 0.0, - samplingExactOutPercentage: 0, - } as QuoteProviderTrafficSwitchConfiguration + switch (protocol) { + case Protocol.MIXED: + case Protocol.V4: + return { + switchExactInPercentage: 0.0, + samplingExactInPercentage: 0, + switchExactOutPercentage: 0.0, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + default: + return { + switchExactInPercentage: 0.0, + samplingExactInPercentage: 0, + switchExactOutPercentage: 0.0, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + } // Sepolia together have well below 50 RPM, so we can shadow sample 100% of traffic case ChainId.SEPOLIA: - return { - switchExactInPercentage: 0.0, - samplingExactInPercentage: 100, - switchExactOutPercentage: 0.0, - samplingExactOutPercentage: 100, - } as QuoteProviderTrafficSwitchConfiguration + switch (protocol) { + case Protocol.MIXED: + case Protocol.V4: + return { + switchExactInPercentage: 100, + samplingExactInPercentage: 0, + switchExactOutPercentage: 100, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + default: + return { + switchExactInPercentage: 0.0, + samplingExactInPercentage: 100, + switchExactOutPercentage: 0.0, + samplingExactOutPercentage: 100, + } as QuoteProviderTrafficSwitchConfiguration + } case ChainId.BASE: - // Base RPC eth_call traffic is about double mainnet, so we can shadow sample 0.05% of traffic - return { - switchExactInPercentage: 100, - samplingExactInPercentage: 0, - switchExactOutPercentage: 100, - samplingExactOutPercentage: 0, - } as QuoteProviderTrafficSwitchConfiguration + switch (protocol) { + // only base as L2 has mixed quoter v1 deployed + case Protocol.MIXED: + return { + switchExactInPercentage: 0, + samplingExactInPercentage: 1, + switchExactOutPercentage: 0, + samplingExactOutPercentage: 1, + } as QuoteProviderTrafficSwitchConfiguration + case Protocol.V4: + return { + switchExactInPercentage: 0, + samplingExactInPercentage: 0, + switchExactOutPercentage: 0, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + default: + return { + switchExactInPercentage: 100, + samplingExactInPercentage: 0, + switchExactOutPercentage: 100, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + } case ChainId.MAINNET: - // Total RPM for 'QuoteTotalCallsToProvider' is around 20k-30k (across all chains), so 0.1% means 20-30 RPM shadow sampling - return { - switchExactInPercentage: 100, - samplingExactInPercentage: 0, - switchExactOutPercentage: 100, - samplingExactOutPercentage: 0, - } as QuoteProviderTrafficSwitchConfiguration + switch (protocol) { + case Protocol.V4: + return { + switchExactInPercentage: 0, + samplingExactInPercentage: 0, + switchExactOutPercentage: 0, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + default: + // Total RPM for 'QuoteTotalCallsToProvider' is around 20k-30k (across all chains), so 0.1% means 20-30 RPM shadow sampling + return { + switchExactInPercentage: 100, + samplingExactInPercentage: 0, + switchExactOutPercentage: 100, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + } case ChainId.ARBITRUM_ONE: - // Arbitrum RPC eth_call traffic is about half of mainnet, so we can shadow sample 0.2% of traffic - return { - switchExactInPercentage: 100, - samplingExactInPercentage: 0, - switchExactOutPercentage: 100, - samplingExactOutPercentage: 0, - } as QuoteProviderTrafficSwitchConfiguration + switch (protocol) { + case Protocol.MIXED: + case Protocol.V4: + return { + switchExactInPercentage: 0, + samplingExactInPercentage: 0, + switchExactOutPercentage: 0, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + default: + // Arbitrum RPC eth_call traffic is about half of mainnet, so we can shadow sample 0.2% of traffic + return { + switchExactInPercentage: 100, + samplingExactInPercentage: 0, + switchExactOutPercentage: 100, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + } case ChainId.POLYGON: - // Total RPM for 'QuoteTotalCallsToProvider' is around 20k-30k (across all chains), so 0.1% means 20-30 RPM shadow sampling - return { - switchExactInPercentage: 100, - samplingExactInPercentage: 0, - switchExactOutPercentage: 100, - samplingExactOutPercentage: 0, - } as QuoteProviderTrafficSwitchConfiguration + switch (protocol) { + case Protocol.MIXED: + case Protocol.V4: + return { + switchExactInPercentage: 0, + samplingExactInPercentage: 0, + switchExactOutPercentage: 0, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + default: + // Total RPM for 'QuoteTotalCallsToProvider' is around 20k-30k (across all chains), so 0.1% means 20-30 RPM shadow sampling + return { + switchExactInPercentage: 100, + samplingExactInPercentage: 0, + switchExactOutPercentage: 100, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + } case ChainId.OPTIMISM: - // Optimism RPC eth_call traffic is about 1/10 of mainnet, so we can shadow sample 1% of traffic - return { - switchExactInPercentage: 100, - samplingExactInPercentage: 0, - switchExactOutPercentage: 100, - samplingExactOutPercentage: 0, - } as QuoteProviderTrafficSwitchConfiguration + switch (protocol) { + case Protocol.MIXED: + case Protocol.V4: + return { + switchExactInPercentage: 0, + samplingExactInPercentage: 0, + switchExactOutPercentage: 0, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + default: + // Optimism RPC eth_call traffic is about 1/10 of mainnet, so we can shadow sample 1% of traffic + return { + switchExactInPercentage: 100, + samplingExactInPercentage: 0, + switchExactOutPercentage: 100, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + } case ChainId.BLAST: - // Blast RPC eth_call traffic is about 1/10 of mainnet, so we can shadow sample 1% of traffic - return { - switchExactInPercentage: 100, - samplingExactInPercentage: 0, - switchExactOutPercentage: 100, - samplingExactOutPercentage: 0, - } as QuoteProviderTrafficSwitchConfiguration + switch (protocol) { + case Protocol.MIXED: + case Protocol.V4: + return { + switchExactInPercentage: 0, + samplingExactInPercentage: 0, + switchExactOutPercentage: 0, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + default: + // Blast RPC eth_call traffic is about 1/10 of mainnet, so we can shadow sample 1% of traffic + return { + switchExactInPercentage: 100, + samplingExactInPercentage: 0, + switchExactOutPercentage: 100, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + } case ChainId.BNB: - // BNB RPC eth_call traffic is about 1/10 of mainnet, so we can shadow sample 1% of traffic - return { - switchExactInPercentage: 100, - samplingExactInPercentage: 0, - switchExactOutPercentage: 100, - samplingExactOutPercentage: 0, + switch (protocol) { + case Protocol.MIXED: + case Protocol.V4: + return { + switchExactInPercentage: 0, + samplingExactInPercentage: 0, + switchExactOutPercentage: 0, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + default: + // BNB RPC eth_call traffic is about 1/10 of mainnet, so we can shadow sample 1% of traffic + return { + switchExactInPercentage: 100, + samplingExactInPercentage: 0, + switchExactOutPercentage: 100, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration } case ChainId.CELO: - // Celo RPC eth_call traffic is about 1/100 of mainnet, so we can shadow sample 10% of traffic - return { - switchExactInPercentage: 100, - samplingExactInPercentage: 0, - switchExactOutPercentage: 100, - samplingExactOutPercentage: 0, - } as QuoteProviderTrafficSwitchConfiguration + switch (protocol) { + case Protocol.MIXED: + case Protocol.V4: + return { + switchExactInPercentage: 0, + samplingExactInPercentage: 0, + switchExactOutPercentage: 0, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + default: + // Celo RPC eth_call traffic is about 1/100 of mainnet, so we can shadow sample 10% of traffic + return { + switchExactInPercentage: 100, + samplingExactInPercentage: 0, + switchExactOutPercentage: 100, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + } case ChainId.AVALANCHE: - // Avalanche RPC eth_call traffic is about 1/100 of mainnet, so we can shadow sample 10% of traffic - return { - switchExactInPercentage: 100, - samplingExactInPercentage: 0, - switchExactOutPercentage: 100, - samplingExactOutPercentage: 0, - } as QuoteProviderTrafficSwitchConfiguration + switch (protocol) { + case Protocol.MIXED: + case Protocol.V4: + return { + switchExactInPercentage: 0, + samplingExactInPercentage: 0, + switchExactOutPercentage: 0, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + default: + // Avalanche RPC eth_call traffic is about 1/100 of mainnet, so we can shadow sample 10% of traffic + return { + switchExactInPercentage: 100, + samplingExactInPercentage: 0, + switchExactOutPercentage: 100, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + } // worldchain and astrochain sepolia don't have the view-only quoter yet, so we can shadow sample 0.1% of traffic case ChainId.WORLDCHAIN: case ChainId.ASTROCHAIN_SEPOLIA: - return { - switchExactInPercentage: 0.0, - samplingExactInPercentage: 0.1, - switchExactOutPercentage: 0.0, - samplingExactOutPercentage: 0.1, - } as QuoteProviderTrafficSwitchConfiguration + switch (protocol) { + case Protocol.MIXED: + case Protocol.V4: + return { + switchExactInPercentage: 0, + samplingExactInPercentage: 0, + switchExactOutPercentage: 0, + samplingExactOutPercentage: 0, + } as QuoteProviderTrafficSwitchConfiguration + default: + return { + switchExactInPercentage: 0.0, + samplingExactInPercentage: 0.1, + switchExactOutPercentage: 0.0, + samplingExactOutPercentage: 0.1, + } as QuoteProviderTrafficSwitchConfiguration + } // If we accidentally switch a traffic, we have the protection to shadow sample only 0.1% of traffic default: return { diff --git a/lib/util/onChainQuoteProviderConfigs.ts b/lib/util/onChainQuoteProviderConfigs.ts index f6b2783593..160bfa6c18 100644 --- a/lib/util/onChainQuoteProviderConfigs.ts +++ b/lib/util/onChainQuoteProviderConfigs.ts @@ -54,8 +54,10 @@ export const RETRY_OPTIONS: { [chainId: number]: AsyncRetry.Options | undefined }, } -export const OPTIMISTIC_CACHED_ROUTES_BATCH_PARAMS: { [protocol: string]: { [chainId: number]: BatchParams } } = { - [Protocol.V3]: { +export const OPTIMISTIC_CACHED_ROUTES_BATCH_PARAMS: { [protocol in Protocol]: { [chainId: number]: BatchParams } } = { + // V2 doesn't apply because v2 doesnt call onchain-quote provider at all + // we use Protocol enum type to remember for each new protocol version, we will add the protocol specific tuning + [Protocol.V2]: { ...constructSameBatchParamsMap(DEFAULT_BATCH_PARAMS), [ChainId.BASE]: { multicallChunk: 1320, @@ -120,7 +122,7 @@ export const OPTIMISTIC_CACHED_ROUTES_BATCH_PARAMS: { [protocol: string]: { [cha quoteMinSuccessRate: 0.1, }, }, - [Protocol.MIXED]: { + [Protocol.V3]: { ...constructSameBatchParamsMap(DEFAULT_BATCH_PARAMS), [ChainId.BASE]: { multicallChunk: 1320, @@ -162,6 +164,11 @@ export const OPTIMISTIC_CACHED_ROUTES_BATCH_PARAMS: { [protocol: string]: { [cha gasLimitPerCall: 80_000, quoteMinSuccessRate: 0.15, }, + [ChainId.MAINNET]: { + multicallChunk: 1974, + gasLimitPerCall: 75_000, + quoteMinSuccessRate: 0.15, + }, [ChainId.ZKSYNC]: { multicallChunk: 20, gasLimitPerCall: 4_000_000, @@ -180,29 +187,27 @@ export const OPTIMISTIC_CACHED_ROUTES_BATCH_PARAMS: { [protocol: string]: { [cha quoteMinSuccessRate: 0.1, }, }, -} - -export const NON_OPTIMISTIC_CACHED_ROUTES_BATCH_PARAMS: { [protocol: string]: { [chainId: number]: BatchParams } } = { - [Protocol.V3]: { + // V4 can be the same as V4 to begin. likely v4 is more gas efficient because of pool singleton for swaps by accounting mechanism + [Protocol.V4]: { ...constructSameBatchParamsMap(DEFAULT_BATCH_PARAMS), [ChainId.BASE]: { - multicallChunk: 660, - gasLimitPerCall: 200_000, + multicallChunk: 1320, + gasLimitPerCall: 100_000, quoteMinSuccessRate: 0.1, }, [ChainId.ARBITRUM_ONE]: { - multicallChunk: 1125, - gasLimitPerCall: 200_000, + multicallChunk: 3000, + gasLimitPerCall: 75_000, quoteMinSuccessRate: 0.15, }, [ChainId.OPTIMISM]: { - multicallChunk: 880, - gasLimitPerCall: 150_000, + multicallChunk: 1650, + gasLimitPerCall: 80_000, quoteMinSuccessRate: 0.1, }, [ChainId.CELO]: { - multicallChunk: 3120, - gasLimitPerCall: 160_000, + multicallChunk: 6240, + gasLimitPerCall: 80_000, quoteMinSuccessRate: 0, }, [ChainId.BLAST]: { @@ -211,23 +216,23 @@ export const NON_OPTIMISTIC_CACHED_ROUTES_BATCH_PARAMS: { [protocol: string]: { quoteMinSuccessRate: 0.1, }, [ChainId.AVALANCHE]: { - multicallChunk: 420, - gasLimitPerCall: 375_000, + multicallChunk: 2625, + gasLimitPerCall: 60_000, quoteMinSuccessRate: 0.15, }, [ChainId.BNB]: { - multicallChunk: 2961, - gasLimitPerCall: 50_000, + multicallChunk: 1850, + gasLimitPerCall: 80_000, quoteMinSuccessRate: 0.15, }, [ChainId.POLYGON]: { - multicallChunk: 987, - gasLimitPerCall: 150_000, + multicallChunk: 1850, + gasLimitPerCall: 80_000, quoteMinSuccessRate: 0.15, }, [ChainId.MAINNET]: { - multicallChunk: 987, - gasLimitPerCall: 150_000, + multicallChunk: 1974, + gasLimitPerCall: 75_000, quoteMinSuccessRate: 0.15, }, [ChainId.ZKSYNC]: { @@ -251,23 +256,23 @@ export const NON_OPTIMISTIC_CACHED_ROUTES_BATCH_PARAMS: { [protocol: string]: { [Protocol.MIXED]: { ...constructSameBatchParamsMap(DEFAULT_BATCH_PARAMS), [ChainId.BASE]: { - multicallChunk: 660, - gasLimitPerCall: 200_000, + multicallChunk: 1320, + gasLimitPerCall: 100_000, quoteMinSuccessRate: 0.1, }, [ChainId.ARBITRUM_ONE]: { - multicallChunk: 1125, - gasLimitPerCall: 200_000, + multicallChunk: 3000, + gasLimitPerCall: 75_000, quoteMinSuccessRate: 0.15, }, [ChainId.OPTIMISM]: { - multicallChunk: 880, - gasLimitPerCall: 150_000, + multicallChunk: 1650, + gasLimitPerCall: 80_000, quoteMinSuccessRate: 0.1, }, [ChainId.CELO]: { - multicallChunk: 3120, - gasLimitPerCall: 160_000, + multicallChunk: 6240, + gasLimitPerCall: 80_000, quoteMinSuccessRate: 0, }, [ChainId.BLAST]: { @@ -276,18 +281,18 @@ export const NON_OPTIMISTIC_CACHED_ROUTES_BATCH_PARAMS: { [protocol: string]: { quoteMinSuccessRate: 0.1, }, [ChainId.AVALANCHE]: { - multicallChunk: 420, - gasLimitPerCall: 375_000, + multicallChunk: 2625, + gasLimitPerCall: 60_000, quoteMinSuccessRate: 0.15, }, [ChainId.BNB]: { - multicallChunk: 2961, - gasLimitPerCall: 50_000, + multicallChunk: 1850, + gasLimitPerCall: 80_000, quoteMinSuccessRate: 0.15, }, [ChainId.POLYGON]: { - multicallChunk: 987, - gasLimitPerCall: 150_000, + multicallChunk: 1850, + gasLimitPerCall: 80_000, quoteMinSuccessRate: 0.15, }, [ChainId.ZKSYNC]: { @@ -310,6 +315,268 @@ export const NON_OPTIMISTIC_CACHED_ROUTES_BATCH_PARAMS: { [protocol: string]: { }, } +export const NON_OPTIMISTIC_CACHED_ROUTES_BATCH_PARAMS: { [protocol in Protocol]: { [chainId: number]: BatchParams } } = + { + // V2 doesn't apply because v2 doesnt call onchain-quote provider at all + // we use Protocol enum type to remember for each new protocol version, we will add the protocol specific tuning + [Protocol.V2]: { + ...constructSameBatchParamsMap(DEFAULT_BATCH_PARAMS), + [ChainId.BASE]: { + multicallChunk: 660, + gasLimitPerCall: 200_000, + quoteMinSuccessRate: 0.1, + }, + [ChainId.ARBITRUM_ONE]: { + multicallChunk: 1125, + gasLimitPerCall: 200_000, + quoteMinSuccessRate: 0.15, + }, + [ChainId.OPTIMISM]: { + multicallChunk: 880, + gasLimitPerCall: 150_000, + quoteMinSuccessRate: 0.1, + }, + [ChainId.CELO]: { + multicallChunk: 3120, + gasLimitPerCall: 160_000, + quoteMinSuccessRate: 0, + }, + [ChainId.BLAST]: { + multicallChunk: 1200, + gasLimitPerCall: 80_000, + quoteMinSuccessRate: 0.1, + }, + [ChainId.AVALANCHE]: { + multicallChunk: 420, + gasLimitPerCall: 375_000, + quoteMinSuccessRate: 0.15, + }, + [ChainId.BNB]: { + multicallChunk: 2961, + gasLimitPerCall: 50_000, + quoteMinSuccessRate: 0.15, + }, + [ChainId.POLYGON]: { + multicallChunk: 987, + gasLimitPerCall: 150_000, + quoteMinSuccessRate: 0.15, + }, + [ChainId.MAINNET]: { + multicallChunk: 987, + gasLimitPerCall: 150_000, + quoteMinSuccessRate: 0.15, + }, + [ChainId.ZKSYNC]: { + multicallChunk: 20, + gasLimitPerCall: 4_000_000, + quoteMinSuccessRate: 0.1, + }, + // TODO: once worldchain has view-quoter, optimize muilcallChunk and gasLimitPerCall + [ChainId.WORLDCHAIN]: { + multicallChunk: 80, + gasLimitPerCall: 1_200_000, + quoteMinSuccessRate: 0.1, + }, + // TODO: once astrochain-sepolia has view-quoter, optimize muilcallChunk and gasLimitPerCall + [ChainId.ASTROCHAIN_SEPOLIA]: { + multicallChunk: 80, + gasLimitPerCall: 1_200_000, + quoteMinSuccessRate: 0.1, + }, + }, + [Protocol.V3]: { + ...constructSameBatchParamsMap(DEFAULT_BATCH_PARAMS), + [ChainId.BASE]: { + multicallChunk: 660, + gasLimitPerCall: 200_000, + quoteMinSuccessRate: 0.1, + }, + [ChainId.ARBITRUM_ONE]: { + multicallChunk: 1125, + gasLimitPerCall: 200_000, + quoteMinSuccessRate: 0.15, + }, + [ChainId.OPTIMISM]: { + multicallChunk: 880, + gasLimitPerCall: 150_000, + quoteMinSuccessRate: 0.1, + }, + [ChainId.CELO]: { + multicallChunk: 3120, + gasLimitPerCall: 160_000, + quoteMinSuccessRate: 0, + }, + [ChainId.BLAST]: { + multicallChunk: 1200, + gasLimitPerCall: 80_000, + quoteMinSuccessRate: 0.1, + }, + [ChainId.AVALANCHE]: { + multicallChunk: 420, + gasLimitPerCall: 375_000, + quoteMinSuccessRate: 0.15, + }, + [ChainId.BNB]: { + multicallChunk: 2961, + gasLimitPerCall: 50_000, + quoteMinSuccessRate: 0.15, + }, + [ChainId.POLYGON]: { + multicallChunk: 987, + gasLimitPerCall: 150_000, + quoteMinSuccessRate: 0.15, + }, + [ChainId.MAINNET]: { + multicallChunk: 987, + gasLimitPerCall: 150_000, + quoteMinSuccessRate: 0.15, + }, + [ChainId.ZKSYNC]: { + multicallChunk: 20, + gasLimitPerCall: 4_000_000, + quoteMinSuccessRate: 0.1, + }, + // TODO: once worldchain has view-quoter, optimize muilcallChunk and gasLimitPerCall + [ChainId.WORLDCHAIN]: { + multicallChunk: 80, + gasLimitPerCall: 1_200_000, + quoteMinSuccessRate: 0.1, + }, + // TODO: once astrochain-sepolia has view-quoter, optimize muilcallChunk and gasLimitPerCall + [ChainId.ASTROCHAIN_SEPOLIA]: { + multicallChunk: 80, + gasLimitPerCall: 1_200_000, + quoteMinSuccessRate: 0.1, + }, + }, + // V4 can be the same as V4 to begin. likely v4 is more gas efficient because of pool singleton for swaps by accounting mechanism + [Protocol.V4]: { + ...constructSameBatchParamsMap(DEFAULT_BATCH_PARAMS), + [ChainId.BASE]: { + multicallChunk: 660, + gasLimitPerCall: 200_000, + quoteMinSuccessRate: 0.1, + }, + [ChainId.ARBITRUM_ONE]: { + multicallChunk: 1125, + gasLimitPerCall: 200_000, + quoteMinSuccessRate: 0.15, + }, + [ChainId.OPTIMISM]: { + multicallChunk: 880, + gasLimitPerCall: 150_000, + quoteMinSuccessRate: 0.1, + }, + [ChainId.CELO]: { + multicallChunk: 3120, + gasLimitPerCall: 160_000, + quoteMinSuccessRate: 0, + }, + [ChainId.BLAST]: { + multicallChunk: 1200, + gasLimitPerCall: 80_000, + quoteMinSuccessRate: 0.1, + }, + [ChainId.AVALANCHE]: { + multicallChunk: 420, + gasLimitPerCall: 375_000, + quoteMinSuccessRate: 0.15, + }, + [ChainId.BNB]: { + multicallChunk: 2961, + gasLimitPerCall: 50_000, + quoteMinSuccessRate: 0.15, + }, + [ChainId.POLYGON]: { + multicallChunk: 987, + gasLimitPerCall: 150_000, + quoteMinSuccessRate: 0.15, + }, + [ChainId.MAINNET]: { + multicallChunk: 987, + gasLimitPerCall: 150_000, + quoteMinSuccessRate: 0.15, + }, + [ChainId.ZKSYNC]: { + multicallChunk: 20, + gasLimitPerCall: 4_000_000, + quoteMinSuccessRate: 0.1, + }, + // TODO: once worldchain has view-quoter, optimize muilcallChunk and gasLimitPerCall + [ChainId.WORLDCHAIN]: { + multicallChunk: 80, + gasLimitPerCall: 1_200_000, + quoteMinSuccessRate: 0.1, + }, + // TODO: once astrochain-sepolia has view-quoter, optimize muilcallChunk and gasLimitPerCall + [ChainId.ASTROCHAIN_SEPOLIA]: { + multicallChunk: 80, + gasLimitPerCall: 1_200_000, + quoteMinSuccessRate: 0.1, + }, + }, + [Protocol.MIXED]: { + ...constructSameBatchParamsMap(DEFAULT_BATCH_PARAMS), + [ChainId.BASE]: { + multicallChunk: 660, + gasLimitPerCall: 200_000, + quoteMinSuccessRate: 0.1, + }, + [ChainId.ARBITRUM_ONE]: { + multicallChunk: 1125, + gasLimitPerCall: 200_000, + quoteMinSuccessRate: 0.15, + }, + [ChainId.OPTIMISM]: { + multicallChunk: 880, + gasLimitPerCall: 150_000, + quoteMinSuccessRate: 0.1, + }, + [ChainId.CELO]: { + multicallChunk: 3120, + gasLimitPerCall: 160_000, + quoteMinSuccessRate: 0, + }, + [ChainId.BLAST]: { + multicallChunk: 1200, + gasLimitPerCall: 80_000, + quoteMinSuccessRate: 0.1, + }, + [ChainId.AVALANCHE]: { + multicallChunk: 420, + gasLimitPerCall: 375_000, + quoteMinSuccessRate: 0.15, + }, + [ChainId.BNB]: { + multicallChunk: 2961, + gasLimitPerCall: 50_000, + quoteMinSuccessRate: 0.15, + }, + [ChainId.POLYGON]: { + multicallChunk: 987, + gasLimitPerCall: 150_000, + quoteMinSuccessRate: 0.15, + }, + [ChainId.ZKSYNC]: { + multicallChunk: 20, + gasLimitPerCall: 4_000_000, + quoteMinSuccessRate: 0.1, + }, + // TODO: once worldchain has view-quoter, optimize muilcallChunk and gasLimitPerCall + [ChainId.WORLDCHAIN]: { + multicallChunk: 80, + gasLimitPerCall: 1_200_000, + quoteMinSuccessRate: 0.1, + }, + // TODO: once astrochain-sepolia has view-quoter, optimize muilcallChunk and gasLimitPerCall + [ChainId.ASTROCHAIN_SEPOLIA]: { + multicallChunk: 80, + gasLimitPerCall: 1_200_000, + quoteMinSuccessRate: 0.1, + }, + }, + } + export const GAS_ERROR_FAILURE_OVERRIDES: { [chainId: number]: FailureOverrides } = { ...constructSameGasErrorFailureOverridesMap(DEFAULT_GAS_ERROR_FAILURE_OVERRIDES), [ChainId.BASE]: { diff --git a/package-lock.json b/package-lock.json index 8f1d004e8a..1c221dc9db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@uniswap/permit2-sdk": "^1.3.0", "@uniswap/router-sdk": "^1.14.0", "@uniswap/sdk-core": "^5.8.3", - "@uniswap/smart-order-router": "4.6.2", + "@uniswap/smart-order-router": "4.7.0", "@uniswap/token-lists": "^1.0.0-beta.33", "@uniswap/universal-router-sdk": "^4.4.2", "@uniswap/v2-sdk": "^4.6.1", @@ -4750,9 +4750,9 @@ } }, "node_modules/@uniswap/smart-order-router": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/@uniswap/smart-order-router/-/smart-order-router-4.6.2.tgz", - "integrity": "sha512-NH+q0RK3T/p/h7GcBjB0Ix37RHDZovD1IQM0D5zPFLGmbeIDBIaaBpHn3GYOUbN72I/3lsljesPXZM/k6eCaCw==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@uniswap/smart-order-router/-/smart-order-router-4.7.0.tgz", + "integrity": "sha512-1ABtIhHR2I5baMFiiLULDQlDua8EaR8PQpNW0limyYR9DfDdy9zd6ESko5DV5YDWVWBwvIJQRxUW4+9Gc+AUPQ==", "dependencies": { "@eth-optimism/sdk": "^3.2.2", "@types/brotli": "^1.3.4", @@ -28449,9 +28449,9 @@ } }, "@uniswap/smart-order-router": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/@uniswap/smart-order-router/-/smart-order-router-4.6.2.tgz", - "integrity": "sha512-NH+q0RK3T/p/h7GcBjB0Ix37RHDZovD1IQM0D5zPFLGmbeIDBIaaBpHn3GYOUbN72I/3lsljesPXZM/k6eCaCw==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@uniswap/smart-order-router/-/smart-order-router-4.7.0.tgz", + "integrity": "sha512-1ABtIhHR2I5baMFiiLULDQlDua8EaR8PQpNW0limyYR9DfDdy9zd6ESko5DV5YDWVWBwvIJQRxUW4+9Gc+AUPQ==", "requires": { "@eth-optimism/sdk": "^3.2.2", "@types/brotli": "^1.3.4", diff --git a/package.json b/package.json index e65f58fc70..77d99e8927 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "@uniswap/router-sdk": "^1.14.0", "@uniswap/sdk-core": "^5.8.3", "@types/semver": "^7.5.8", - "@uniswap/smart-order-router": "4.6.2", + "@uniswap/smart-order-router": "4.7.0", "@uniswap/token-lists": "^1.0.0-beta.33", "@uniswap/universal-router-sdk": "^4.4.2", "@uniswap/v2-sdk": "^4.6.1", diff --git a/test/mocha/integ/handlers/quote/provider-migration/traffic-switch-quote-provider.test.ts b/test/mocha/integ/handlers/quote/provider-migration/traffic-switch-quote-provider.test.ts index b9bb0d0cbe..8d78b43fcb 100644 --- a/test/mocha/integ/handlers/quote/provider-migration/traffic-switch-quote-provider.test.ts +++ b/test/mocha/integ/handlers/quote/provider-migration/traffic-switch-quote-provider.test.ts @@ -1,7 +1,7 @@ import sinon, { SinonSpy } from 'sinon' import { metric } from '@uniswap/smart-order-router/build/main/util/metric' import { MetricLoggerUnit, RouteWithQuotes, USDC_MAINNET, WRAPPED_NATIVE_CURRENCY } from '@uniswap/smart-order-router' -import { TrafficSwitchOnChainQuoteProvider } from '../../../../../../lib/handlers/quote/provider-migration/v3/traffic-switch-on-chain-quote-provider' +import { TrafficSwitchOnChainQuoteProvider } from '../../../../../../lib/handlers/quote/provider-migration/traffic-switch-on-chain-quote-provider' import { ChainId, CurrencyAmount } from '@uniswap/sdk-core' import { V3Route } from '@uniswap/smart-order-router/build/main/routers' import { USDC_WETH_LOW } from '../../../../../test-utils/mocked-data' @@ -9,6 +9,7 @@ import { getMockedOnChainQuoteProvider } from '../../../../../test-utils/mocked- import { ProviderConfig } from '@uniswap/smart-order-router/build/main/providers/provider' import { AmountQuote } from '@uniswap/smart-order-router/build/main/providers/on-chain-quote-provider' import { BigNumber } from 'ethers' +import { Protocol } from '@uniswap/router-sdk' describe('TrafficSwitchOnChainQuoteProvider', () => { const amountIns = [CurrencyAmount.fromRawAmount(WRAPPED_NATIVE_CURRENCY[ChainId.MAINNET], '1000000000000000000')] @@ -28,14 +29,18 @@ describe('TrafficSwitchOnChainQuoteProvider', () => { }) it('switch exact in traffic and sample quotes', async () => { - spy.withArgs(`ON_CHAIN_QUOTE_PROVIDER_EXACT_IN_TRAFFIC_TOTAL_CHAIN_ID_${ChainId.MAINNET}`, 1, MetricLoggerUnit.None) spy.withArgs( - `ON_CHAIN_QUOTE_PROVIDER_EXACT_IN_TRAFFIC_SAMPLING_CHAIN_ID_${ChainId.MAINNET}`, + `ON_CHAIN_QUOTE_PROVIDER_EXACT_IN_TRAFFIC_TOTAL_CHAIN_ID_${ChainId.MAINNET}_PROTOCOL_${Protocol.V3}`, 1, MetricLoggerUnit.None ) spy.withArgs( - `ON_CHAIN_QUOTE_PROVIDER_EXACT_IN_TRAFFIC_TARGET_CHAIN_ID_${ChainId.MAINNET}`, + `ON_CHAIN_QUOTE_PROVIDER_EXACT_IN_TRAFFIC_SAMPLING_CHAIN_ID_${ChainId.MAINNET}_PROTOCOL_${Protocol.V3}`, + 1, + MetricLoggerUnit.None + ) + spy.withArgs( + `ON_CHAIN_QUOTE_PROVIDER_EXACT_IN_TRAFFIC_TARGET_CHAIN_ID_${ChainId.MAINNET}_PROTOCOL_${Protocol.V3}`, 1, MetricLoggerUnit.None ) @@ -45,8 +50,8 @@ describe('TrafficSwitchOnChainQuoteProvider', () => { const trafficSwitchProvider = new (class SwitchTrafficSwitchOnChainQuoteProvider extends TrafficSwitchOnChainQuoteProvider { - override readonly SHOULD_SWITCH_EXACT_IN_TRAFFIC = (_: ChainId) => true - override readonly SHOULD_SAMPLE_EXACT_IN_TRAFFIC = (_: ChainId) => true + override readonly SHOULD_SWITCH_EXACT_IN_TRAFFIC = (_chainId: ChainId, _protocol: Protocol) => true + override readonly SHOULD_SAMPLE_EXACT_IN_TRAFFIC = (_chainId: ChainId, _protocol: Protocol) => true })({ currentQuoteProvider: currentQuoteProvider, targetQuoteProvider: targetQuoteProvider, @@ -61,9 +66,13 @@ describe('TrafficSwitchOnChainQuoteProvider', () => { }) it('does not switch exact in traffic and sample quotes', async () => { - spy.withArgs(`ON_CHAIN_QUOTE_PROVIDER_EXACT_IN_TRAFFIC_TOTAL_CHAIN_ID_${ChainId.MAINNET}`, 1, MetricLoggerUnit.None) spy.withArgs( - `ON_CHAIN_QUOTE_PROVIDER_EXACT_IN_TRAFFIC_CURRENT_CHAIN_ID_${ChainId.MAINNET}`, + `ON_CHAIN_QUOTE_PROVIDER_EXACT_IN_TRAFFIC_TOTAL_CHAIN_ID_${ChainId.MAINNET}_PROTOCOL_${Protocol.V3}`, + 1, + MetricLoggerUnit.None + ) + spy.withArgs( + `ON_CHAIN_QUOTE_PROVIDER_EXACT_IN_TRAFFIC_CURRENT_CHAIN_ID_${ChainId.MAINNET}_PROTOCOL_${Protocol.V3}`, 1, MetricLoggerUnit.None ) @@ -73,8 +82,8 @@ describe('TrafficSwitchOnChainQuoteProvider', () => { const trafficSwitchProvider = new (class SwitchTrafficSwitchOnChainQuoteProvider extends TrafficSwitchOnChainQuoteProvider { - override readonly SHOULD_SWITCH_EXACT_IN_TRAFFIC = (_: ChainId) => true - override readonly SHOULD_SAMPLE_EXACT_IN_TRAFFIC = (_: ChainId) => true + override readonly SHOULD_SWITCH_EXACT_IN_TRAFFIC = (_chainId: ChainId, _protocol: Protocol) => true + override readonly SHOULD_SAMPLE_EXACT_IN_TRAFFIC = (_chainId: ChainId, _protocol: Protocol) => true })({ currentQuoteProvider: currentQuoteProvider, targetQuoteProvider: targetQuoteProvider, @@ -90,17 +99,17 @@ describe('TrafficSwitchOnChainQuoteProvider', () => { it('switch exact out traffic and sample quotes', async () => { spy.withArgs( - `ON_CHAIN_QUOTE_PROVIDER_EXACT_OUT_TRAFFIC_TOTAL_CHAIN_ID_${ChainId.MAINNET}`, + `ON_CHAIN_QUOTE_PROVIDER_EXACT_OUT_TRAFFIC_TOTAL_CHAIN_ID_${ChainId.MAINNET}_PROTOCOL_${Protocol.V3}`, 1, MetricLoggerUnit.None ) spy.withArgs( - `ON_CHAIN_QUOTE_PROVIDER_EXACT_OUT_TRAFFIC_SAMPLING_CHAIN_ID_${ChainId.MAINNET}`, + `ON_CHAIN_QUOTE_PROVIDER_EXACT_OUT_TRAFFIC_SAMPLING_CHAIN_ID_${ChainId.MAINNET}_PROTOCOL_${Protocol.V3}`, 1, MetricLoggerUnit.None ) spy.withArgs( - `ON_CHAIN_QUOTE_PROVIDER_EXACT_OUT_TRAFFIC_TARGET_CHAIN_ID_${ChainId.MAINNET}`, + `ON_CHAIN_QUOTE_PROVIDER_EXACT_OUT_TRAFFIC_TARGET_CHAIN_ID_${ChainId.MAINNET}_PROTOCOL_${Protocol.V3}`, 1, MetricLoggerUnit.None ) @@ -110,8 +119,8 @@ describe('TrafficSwitchOnChainQuoteProvider', () => { const trafficSwitchProvider = new (class SwitchTrafficSwitchOnChainQuoteProvider extends TrafficSwitchOnChainQuoteProvider { - override readonly SHOULD_SWITCH_EXACT_OUT_TRAFFIC = (_: ChainId) => true - override readonly SHOULD_SAMPLE_EXACT_OUT_TRAFFIC = (_: ChainId) => true + override readonly SHOULD_SWITCH_EXACT_OUT_TRAFFIC = (_chainId: ChainId, _protocol: Protocol) => true + override readonly SHOULD_SAMPLE_EXACT_OUT_TRAFFIC = (_chainId: ChainId, _protocol: Protocol) => true })({ currentQuoteProvider: currentQuoteProvider, targetQuoteProvider: targetQuoteProvider, @@ -127,12 +136,12 @@ describe('TrafficSwitchOnChainQuoteProvider', () => { it('does not switch exact out traffic and sample quotes', async () => { spy.withArgs( - `ON_CHAIN_QUOTE_PROVIDER_EXACT_OUT_TRAFFIC_TOTAL_CHAIN_ID_${ChainId.MAINNET}`, + `ON_CHAIN_QUOTE_PROVIDER_EXACT_OUT_TRAFFIC_TOTAL_CHAIN_ID_${ChainId.MAINNET}_PROTOCOL_${Protocol.V3}`, 1, MetricLoggerUnit.None ) spy.withArgs( - `ON_CHAIN_QUOTE_PROVIDER_EXACT_OUT_TRAFFIC_CURRENT_CHAIN_ID_${ChainId.MAINNET}`, + `ON_CHAIN_QUOTE_PROVIDER_EXACT_OUT_TRAFFIC_CURRENT_CHAIN_ID_${ChainId.MAINNET}_PROTOCOL_${Protocol.V3}`, 1, MetricLoggerUnit.None ) @@ -142,8 +151,8 @@ describe('TrafficSwitchOnChainQuoteProvider', () => { const trafficSwitchProvider = new (class SwitchTrafficSwitchOnChainQuoteProvider extends TrafficSwitchOnChainQuoteProvider { - override readonly SHOULD_SWITCH_EXACT_OUT_TRAFFIC = (_: ChainId) => true - override readonly SHOULD_SAMPLE_EXACT_OUT_TRAFFIC = (_: ChainId) => true + override readonly SHOULD_SWITCH_EXACT_OUT_TRAFFIC = (_chainId: ChainId, _protocol: Protocol) => true + override readonly SHOULD_SAMPLE_EXACT_OUT_TRAFFIC = (_chainId: ChainId, _protocol: Protocol) => true })({ currentQuoteProvider: currentQuoteProvider, targetQuoteProvider: targetQuoteProvider, @@ -165,8 +174,8 @@ describe('TrafficSwitchOnChainQuoteProvider', () => { const trafficSwitchProvider = new (class SwitchTrafficSwitchOnChainQuoteProvider extends TrafficSwitchOnChainQuoteProvider { - override readonly SHOULD_SAMPLE_EXACT_IN_TRAFFIC = (_: ChainId) => true - override readonly SHOULD_SWITCH_EXACT_IN_TRAFFIC = (_: ChainId) => false + override readonly SHOULD_SAMPLE_EXACT_IN_TRAFFIC = (_chainId: ChainId, _protocol: Protocol) => true + override readonly SHOULD_SWITCH_EXACT_IN_TRAFFIC = (_chainId: ChainId, _protocol: Protocol) => false })({ currentQuoteProvider: currentQuoteProvider, targetQuoteProvider: targetQuoteProvider, @@ -189,8 +198,8 @@ describe('TrafficSwitchOnChainQuoteProvider', () => { const trafficSwitchProvider = new (class SwitchTrafficSwitchOnChainQuoteProvider extends TrafficSwitchOnChainQuoteProvider { - override readonly SHOULD_SAMPLE_EXACT_IN_TRAFFIC = (_: ChainId) => true - override readonly SHOULD_SWITCH_EXACT_IN_TRAFFIC = (_: ChainId) => true + override readonly SHOULD_SAMPLE_EXACT_IN_TRAFFIC = (_chainId: ChainId, _protocol: Protocol) => true + override readonly SHOULD_SWITCH_EXACT_IN_TRAFFIC = (_chainId: ChainId, _protocol: Protocol) => true })({ currentQuoteProvider: currentQuoteProvider, targetQuoteProvider: targetQuoteProvider, @@ -213,8 +222,8 @@ describe('TrafficSwitchOnChainQuoteProvider', () => { const trafficSwitchProvider = new (class SwitchTrafficSwitchOnChainQuoteProvider extends TrafficSwitchOnChainQuoteProvider { - override readonly SHOULD_SAMPLE_EXACT_OUT_TRAFFIC = (_: ChainId) => true - override readonly SHOULD_SWITCH_EXACT_OUT_TRAFFIC = (_: ChainId) => false + override readonly SHOULD_SAMPLE_EXACT_OUT_TRAFFIC = (_chainId: ChainId, _protocol: Protocol) => true + override readonly SHOULD_SWITCH_EXACT_OUT_TRAFFIC = (_chainId: ChainId, _protocol: Protocol) => false })({ currentQuoteProvider: currentQuoteProvider, targetQuoteProvider: targetQuoteProvider, @@ -237,8 +246,8 @@ describe('TrafficSwitchOnChainQuoteProvider', () => { const trafficSwitchProvider = new (class SwitchTrafficSwitchOnChainQuoteProvider extends TrafficSwitchOnChainQuoteProvider { - override readonly SHOULD_SAMPLE_EXACT_OUT_TRAFFIC = (_: ChainId) => true - override readonly SHOULD_SWITCH_EXACT_OUT_TRAFFIC = (_: ChainId) => true + override readonly SHOULD_SAMPLE_EXACT_OUT_TRAFFIC = (_chainId: ChainId, _protocol: Protocol) => true + override readonly SHOULD_SWITCH_EXACT_OUT_TRAFFIC = (_chainId: ChainId, _protocol: Protocol) => true })({ currentQuoteProvider: currentQuoteProvider, targetQuoteProvider: targetQuoteProvider, @@ -255,12 +264,12 @@ describe('TrafficSwitchOnChainQuoteProvider', () => { it('sample exact in quotes and current quoter out of gas for the quote', async () => { spy.withArgs( - `ON_CHAIN_QUOTE_PROVIDER_EXACT_IN_TRAFFIC_CURRENT_AND_TARGET_QUOTES_MATCH_CHAIN_ID_${ChainId.MAINNET}`, + `ON_CHAIN_QUOTE_PROVIDER_EXACT_IN_TRAFFIC_CURRENT_AND_TARGET_QUOTES_MATCH_CHAIN_ID_${ChainId.MAINNET}_PROTOCOL_${Protocol.V3}`, 1, MetricLoggerUnit.None ) spy.withArgs( - `ON_CHAIN_QUOTE_PROVIDER_EXACT_IN_TRAFFIC_CURRENT_AND_TARGET_QUOTES_MISMATCH_CHAIN_ID_${ChainId.MAINNET}`, + `ON_CHAIN_QUOTE_PROVIDER_EXACT_IN_TRAFFIC_CURRENT_AND_TARGET_QUOTES_MISMATCH_CHAIN_ID_${ChainId.MAINNET}_PROTOCOL_${Protocol.V3}`, 1, MetricLoggerUnit.None ) @@ -288,7 +297,7 @@ describe('TrafficSwitchOnChainQuoteProvider', () => { const trafficSwitchProvider = new (class SwitchTrafficSwitchOnChainQuoteProvider extends TrafficSwitchOnChainQuoteProvider { - override readonly SHOULD_SAMPLE_EXACT_IN_TRAFFIC = (_: ChainId) => true + override readonly SHOULD_SAMPLE_EXACT_IN_TRAFFIC = (_chainId: ChainId, _protocol: Protocol) => true })({ currentQuoteProvider: currentQuoteProvider, targetQuoteProvider: targetQuoteProvider, @@ -300,13 +309,13 @@ describe('TrafficSwitchOnChainQuoteProvider', () => { // We will check neither match nor mismatch metric was logged sinon.assert.neverCalledWith( spy, - `ON_CHAIN_QUOTE_PROVIDER_EXACT_IN_TRAFFIC_CURRENT_AND_TARGET_QUOTES_MATCH_CHAIN_ID_${ChainId.MAINNET}`, + `ON_CHAIN_QUOTE_PROVIDER_EXACT_IN_TRAFFIC_CURRENT_AND_TARGET_QUOTES_MATCH_CHAIN_ID_${ChainId.MAINNET}_PROTOCOL_${Protocol.V3}`, 1, MetricLoggerUnit.None ) sinon.assert.neverCalledWith( spy, - `ON_CHAIN_QUOTE_PROVIDER_EXACT_IN_TRAFFIC_CURRENT_AND_TARGET_QUOTES_MISMATCH_CHAIN_ID_${ChainId.MAINNET}`, + `ON_CHAIN_QUOTE_PROVIDER_EXACT_IN_TRAFFIC_CURRENT_AND_TARGET_QUOTES_MISMATCH_CHAIN_ID_${ChainId.MAINNET}_PROTOCOL_${Protocol.V3}`, 1, MetricLoggerUnit.None )