UNPKG

@uniswap/smart-order-router

Version:
259 lines (258 loc) 12.5 kB
import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; import { BytesLike } from '@ethersproject/bytes'; import { BaseProvider } from '@ethersproject/providers'; import { Protocol } from '@uniswap/router-sdk'; import { ChainId } from '@uniswap/sdk-core'; import { Options as RetryOptions } from 'async-retry'; import { SupportedRoutes, V3Route, V4Route } from '../routers/router'; import { CurrencyAmount } from '../util/amounts'; import { Result } from './multicall-provider'; import { UniswapMulticallProvider } from './multicall-uniswap-provider'; import { ProviderConfig } from './provider'; /** * Emulate on-chain [PathKey](https://github.com/Uniswap/v4-periphery/blob/main/src/libraries/PathKey.sol#L8) struct */ export declare type PathKey = { intermediateCurrency: string; fee: BigNumberish; tickSpacing: BigNumberish; hooks: string; hookData: BytesLike; }; export declare type SupportedPath = string | PathKey[]; /** * Emulate on-chain [QuoteExactParams](https://github.com/Uniswap/v4-periphery/blob/main/src/interfaces/IQuoter.sol#L34) struct */ export declare type QuoteExactParams = { exactCurrency: string; path: PathKey[]; exactAmount: BigNumberish; }; /** * Emulate on-chain [ExtraQuoteExactInputParams](https://github.com/Uniswap/mixed-quoter/blob/main/src/interfaces/IMixedRouteQuoterV2.sol#L44C12-L44C38) struct */ declare type NonEncodableData = { hookData: BytesLike; }; export declare type ExtraQuoteExactInputParams = { nonEncodableData: NonEncodableData[]; }; export declare type QuoteInputType = QuoteExactParams[] | [string, string] | [string, ExtraQuoteExactInputParams, string]; /** * An on chain quote for a swap. */ export declare type AmountQuote = { amount: CurrencyAmount; /** * Quotes can be null (e.g. pool did not have enough liquidity). */ quote: BigNumber | null; /** * For each pool in the route, the sqrtPriceX96 after the swap. */ sqrtPriceX96AfterList: BigNumber[] | null; /** * For each pool in the route, the number of ticks crossed. */ initializedTicksCrossedList: number[] | null; /** * An estimate of the gas used by the swap. This is returned by the multicall * and is not necessarily accurate due to EIP-2929 causing gas costs to vary * depending on if the slot has already been loaded in the call. */ gasEstimate: BigNumber | null; /** * Final attempted gas limit set by the on-chain quote provider */ gasLimit: BigNumber | null; }; export declare class BlockConflictError extends Error { name: string; } export declare class SuccessRateError extends Error { name: string; } export declare class ProviderBlockHeaderError extends Error { name: string; } export declare class ProviderTimeoutError extends Error { name: string; } /** * This error typically means that the gas used by the multicall has * exceeded the total call gas limit set by the node provider. * * This can be resolved by modifying BatchParams to request fewer * quotes per call, or to set a lower gas limit per quote. * * @export * @class ProviderGasError */ export declare class ProviderGasError extends Error { name: string; } export declare type QuoteRetryOptions = RetryOptions; /** * The V3 route and a list of quotes for that route. */ export declare type RouteWithQuotes<TRoute extends SupportedRoutes> = [ TRoute, AmountQuote[] ]; /** * Final consolidated return type of all on-chain quotes. */ export declare type OnChainQuotes<TRoute extends SupportedRoutes> = { routesWithQuotes: RouteWithQuotes<TRoute>[]; blockNumber: BigNumber; }; export declare type SupportedExactOutRoutes = V4Route | V3Route; /** * Provider for getting on chain quotes using routes containing V3 pools or V2 pools. * * @export * @interface IOnChainQuoteProvider */ export interface IOnChainQuoteProvider { /** * For every route, gets an exactIn quotes for every amount provided. * @notice While passing in exactIn V2Routes is supported, we recommend using the V2QuoteProvider to compute off chain quotes for V2 whenever possible * * @param amountIns The amounts to get quotes for. * @param routes The routes to get quotes for. * @param [providerConfig] The provider config. * @returns For each route returns a RouteWithQuotes object that contains all the quotes. * @returns The blockNumber used when generating the quotes. */ getQuotesManyExactIn<TRoute extends SupportedRoutes>(amountIns: CurrencyAmount[], routes: TRoute[], providerConfig?: ProviderConfig): Promise<OnChainQuotes<TRoute>>; /** * For every route, gets ane exactOut quote for every amount provided. * @notice This does not support quotes for MixedRoutes (routes with both V3 and V2 pools/pairs) or pure V2 routes * * @param amountOuts The amounts to get quotes for. * @param routes The routes to get quotes for. * @param [providerConfig] The provider config. * @returns For each route returns a RouteWithQuotes object that contains all the quotes. * @returns The blockNumber used when generating the quotes. */ getQuotesManyExactOut<TRoute extends SupportedExactOutRoutes>(amountOuts: CurrencyAmount[], routes: TRoute[], providerConfig?: ProviderConfig): Promise<OnChainQuotes<TRoute>>; } /** * The parameters for the multicalls we make. * * It is important to ensure that (gasLimitPerCall * multicallChunk) < providers gas limit per call. * * On chain quotes can consume a lot of gas (if the swap is so large that it swaps through a large * number of ticks), so there is a risk of exceeded gas limits in these multicalls. */ export declare type BatchParams = { /** * The number of quotes to fetch in each multicall. */ multicallChunk: number; /** * The maximum call to consume for each quote in the multicall. */ gasLimitPerCall: number; /** * The minimum success rate for all quotes across all multicalls. * If we set our gasLimitPerCall too low it could result in a large number of * quotes failing due to out of gas. This parameters will fail the overall request * in this case. */ quoteMinSuccessRate: number; }; /** * The fallback values for gasLimit and multicallChunk if any failures occur. * */ export declare type FailureOverrides = { multicallChunk: number; gasLimitOverride: number; }; export declare type BlockHeaderFailureOverridesDisabled = { enabled: false; }; export declare type BlockHeaderFailureOverridesEnabled = { enabled: true; rollbackBlockOffset: number; attemptsBeforeRollback: number; }; export declare type BlockHeaderFailureOverrides = BlockHeaderFailureOverridesDisabled | BlockHeaderFailureOverridesEnabled; /** * Config around what block number to query and how to handle failures due to block header errors. */ export declare type BlockNumberConfig = { baseBlockOffset: number; rollback: BlockHeaderFailureOverrides; }; /** * Computes on chain quotes for swaps. For pure V3 routes, quotes are computed on-chain using * the 'QuoterV2' smart contract. For exactIn mixed and V2 routes, quotes are computed using the 'MixedRouteQuoterV1' contract * This is because computing quotes off-chain would require fetching all the tick data for each pool, which is a lot of data. * * To minimize the number of requests for quotes we use a Multicall contract. Generally * the number of quotes to fetch exceeds the maximum we can fit in a single multicall * while staying under gas limits, so we also batch these quotes across multiple multicalls. * * The biggest challenge with the quote provider is dealing with various gas limits. * Each provider sets a limit on the amount of gas a call can consume (on Infura this * is approximately 10x the block max size), so we must ensure each multicall does not * exceed this limit. Additionally, each quote on V3 can consume a large number of gas if * the pool lacks liquidity and the swap would cause all the ticks to be traversed. * * To ensure we don't exceed the node's call limit, we limit the gas used by each quote to * a specific value, and we limit the number of quotes in each multicall request. Users of this * class should set BatchParams such that multicallChunk * gasLimitPerCall is less than their node * providers total gas limit per call. * * @export * @class OnChainQuoteProvider */ export declare class OnChainQuoteProvider implements IOnChainQuoteProvider { protected chainId: ChainId; protected provider: BaseProvider; protected multicall2Provider: UniswapMulticallProvider; protected retryOptions: QuoteRetryOptions; protected batchParams: (optimisticCachedRoutes: boolean, protocol: Protocol) => BatchParams; protected gasErrorFailureOverride: (protocol: Protocol) => FailureOverrides; protected successRateFailureOverrides: (protocol: Protocol) => FailureOverrides; protected blockNumberConfig: (protocol: Protocol) => BlockNumberConfig; protected quoterAddressOverride?: ((useMixedRouteQuoter: boolean, mixedRouteContainsV4Pool: boolean, protocol: Protocol) => string | undefined) | undefined; protected metricsPrefix: (chainId: ChainId, useMixedRouteQuoter: boolean, mixedRouteContainsV4Pool: boolean, protocol: Protocol, optimisticCachedRoutes: boolean) => string; /** * Creates an instance of OnChainQuoteProvider. * * @param chainId The chain to get quotes for. * @param provider The web 3 provider. * @param multicall2Provider The multicall provider to use to get the quotes on-chain. * Only supports the Uniswap Multicall contract as it needs the gas limitting functionality. * @param retryOptions The retry options for each call to the multicall. * @param batchParams The parameters for each batched call to the multicall. * @param gasErrorFailureOverride The gas and chunk parameters to use when retrying a batch that failed due to out of gas. * @param successRateFailureOverrides The parameters for retries when we fail to get quotes. * @param blockNumberConfig Parameters for adjusting which block we get quotes from, and how to handle block header not found errors. * @param [quoterAddressOverride] Overrides the address of the quoter contract to use. * @param metricsPrefix metrics prefix to differentiate between different instances of the quote provider. */ constructor(chainId: ChainId, provider: BaseProvider, multicall2Provider: UniswapMulticallProvider, retryOptions?: QuoteRetryOptions, batchParams?: (optimisticCachedRoutes: boolean, protocol: Protocol) => BatchParams, gasErrorFailureOverride?: (protocol: Protocol) => FailureOverrides, successRateFailureOverrides?: (protocol: Protocol) => FailureOverrides, blockNumberConfig?: (protocol: Protocol) => BlockNumberConfig, quoterAddressOverride?: ((useMixedRouteQuoter: boolean, mixedRouteContainsV4Pool: boolean, protocol: Protocol) => string | undefined) | undefined, metricsPrefix?: (chainId: ChainId, useMixedRouteQuoter: boolean, mixedRouteContainsV4Pool: boolean, protocol: Protocol, optimisticCachedRoutes: boolean) => string); private getQuoterAddress; getQuotesManyExactIn<TRoute extends SupportedRoutes>(amountIns: CurrencyAmount[], routes: TRoute[], providerConfig?: ProviderConfig): Promise<OnChainQuotes<TRoute>>; getQuotesManyExactOut<TRoute extends SupportedExactOutRoutes>(amountOuts: CurrencyAmount[], routes: TRoute[], providerConfig?: ProviderConfig): Promise<OnChainQuotes<TRoute>>; private encodeRouteToPath; private getContractInterface; private consolidateResults; private getQuotesManyData; private partitionQuotes; private processQuoteResults; private validateBlockNumbers; protected validateSuccessRate(allResults: Result<[BigNumber, BigNumber[], number[], BigNumber]>[], haveRetriedForSuccessRate: boolean, useMixedRouteQuoter: boolean, mixedRouteContainsV4Pool: boolean, protocol: Protocol, optimisticCachedRoutes: boolean): void | SuccessRateError; /** * Throw an error for incorrect routes / function combinations * @param routes Any combination of V3, V2, and Mixed routes. * @param functionName * @param useMixedRouteQuoter true if there are ANY V2Routes or MixedRoutes in the routes parameter */ protected validateRoutes(routes: SupportedRoutes[], functionName: string, useMixedRouteQuoter: boolean): void; } export {};