diff --git a/.github/workflows/rain-ci.yml b/.github/workflows/rain-ci.yml index aaa7e6dc03..f55884d649 100644 --- a/.github/workflows/rain-ci.yml +++ b/.github/workflows/rain-ci.yml @@ -23,4 +23,6 @@ jobs: run: nix develop -c pnpm exec turbo run check --filter=./packages/sushi - name: Test ./packages/sushi - run: nix develop -c pnpm exec turbo run test --filter=./packages/sushi \ No newline at end of file + run: | + nix develop -c pnpm exec turbo run test --filter=./packages/sushi + nix develop -c pnpm exec turbo run test --filter=./protocols/route-processor \ No newline at end of file diff --git a/.gitignore b/.gitignore index a3f851728c..756ce12afc 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,7 @@ exports # cache cache mem-cache +test-cache # generated generated diff --git a/packages/sushi/src/router/data-fetcher.ts b/packages/sushi/src/router/data-fetcher.ts index 7f5e56294b..e5c76bcbd9 100644 --- a/packages/sushi/src/router/data-fetcher.ts +++ b/packages/sushi/src/router/data-fetcher.ts @@ -3,31 +3,54 @@ import { ChainId, TestnetChainId } from '../chain/index.js' import { publicClientConfig } from '../config/index.js' import { Type } from '../currency/index.js' import { ApeSwapProvider } from './liquidity-providers/ApeSwap.js' +import { BaseSwapProvider } from './liquidity-providers/BaseSwap.js' import { BiswapProvider } from './liquidity-providers/Biswap.js' +import { BlastDEXProvider } from './liquidity-providers/BlastDEX.js' +import { BlazeSwapProvider } from './liquidity-providers/BlazeSwap.js' +import { CamelotProvider } from './liquidity-providers/Camelot.js' import { CurveProvider } from './liquidity-providers/CurveProvider.js' import { DfynProvider } from './liquidity-providers/Dfyn.js' import { DovishV3Provider } from './liquidity-providers/DovishV3.js' +import { DyorV2Provider } from './liquidity-providers/DyorV2.js' import { ElkProvider } from './liquidity-providers/Elk.js' +import { EnosysProvider } from './liquidity-providers/Enosys.js' import { HoneySwapProvider } from './liquidity-providers/HoneySwap.js' +import { HyperBlastProvider } from './liquidity-providers/HyperBlast.js' import { JetSwapProvider } from './liquidity-providers/JetSwap.js' +import { KinetixV2Provider } from './liquidity-providers/KinetixV2.js' +import { KinetixV3Provider } from './liquidity-providers/KinetixV3.js' import { LaserSwapV2Provider } from './liquidity-providers/LaserSwap.js' import { LiquidityProvider, LiquidityProviders, } from './liquidity-providers/LiquidityProvider.js' +import { MonoswapV2Provider } from './liquidity-providers/MonoSwapV2.js' +import { MonoswapV3Provider } from './liquidity-providers/MonoSwapV3.js' import { NativeWrapProvider } from './liquidity-providers/NativeWrapProvider.js' import { NetSwapProvider } from './liquidity-providers/NetSwap.js' -import { PancakeSwapProvider } from './liquidity-providers/PancakeSwap.js' +import { PancakeSwapV2Provider } from './liquidity-providers/PancakeSwapV2.js' +import { PancakeSwapV3Provider } from './liquidity-providers/PancakeSwapV3.js' import { QuickSwapProvider } from './liquidity-providers/QuickSwap.js' -import { SpookySwapProvider } from './liquidity-providers/SpookySwap.js' +import { SolarbeamProvider } from './liquidity-providers/Solarbeam.js' +import { SpookySwapV2Provider } from './liquidity-providers/SpookySwapV2.js' +import { SpookySwapV3Provider } from './liquidity-providers/SpookySwapV3.js' import { SushiSwapV2Provider } from './liquidity-providers/SushiSwapV2.js' import { SushiSwapV3Provider } from './liquidity-providers/SushiSwapV3.js' +import { SwapBlastProvider } from './liquidity-providers/SwapBlast.js' +import { + ThrusterV2_1Provider, + ThrusterV2_3Provider, +} from './liquidity-providers/ThrusterV2.js' +import { ThrusterV3Provider } from './liquidity-providers/ThrusterV3.js' import { TraderJoeProvider } from './liquidity-providers/TraderJoe.js' import { TridentProvider } from './liquidity-providers/Trident.js' import { UbeSwapProvider } from './liquidity-providers/UbeSwap.js' import { UniswapV2Provider } from './liquidity-providers/UniswapV2.js' import { UniswapV3Provider } from './liquidity-providers/UniswapV3.js' +import { VVSStandardProvider } from './liquidity-providers/VVSStandard.js' +import { WagmiProvider } from './liquidity-providers/Wagmi.js' import type { PoolCode } from './pool-codes/index.js' +import { promiseTimeout } from './timeout.js' // options for data fetching, such as pinning block number and memoize export type DataFetcherOptions = { @@ -39,6 +62,8 @@ export type DataFetcherOptions = { blockNumber?: bigint /** Determines if memoizer should be used or not */ memoize?: boolean + /** Determines a timeout (in ms) for fetching pools for a token pair */ + fetchPoolsTimeout?: number } // TODO: Should be a mode on the config for DataFetcher @@ -123,25 +148,45 @@ export class DataFetcher { this.providers = [new NativeWrapProvider(this.chainId, this.web3Client)] ;[ ApeSwapProvider, + BaseSwapProvider, BiswapProvider, + BlastDEXProvider, + BlazeSwapProvider, + CamelotProvider, CurveProvider, DfynProvider, DovishV3Provider, + DyorV2Provider, ElkProvider, + EnosysProvider, HoneySwapProvider, + HyperBlastProvider, JetSwapProvider, + KinetixV2Provider, + KinetixV3Provider, LaserSwapV2Provider, + MonoswapV2Provider, + MonoswapV3Provider, NetSwapProvider, - PancakeSwapProvider, - SpookySwapProvider, + PancakeSwapV2Provider, + PancakeSwapV3Provider, + QuickSwapProvider, + SolarbeamProvider, + SpookySwapV2Provider, + SpookySwapV3Provider, SushiSwapV2Provider, SushiSwapV3Provider, + SwapBlastProvider, + ThrusterV2_1Provider, + ThrusterV2_3Provider, + ThrusterV3Provider, TraderJoeProvider, - QuickSwapProvider, TridentProvider, UbeSwapProvider, UniswapV2Provider, UniswapV3Provider, + VVSStandardProvider, + WagmiProvider, ].forEach((p) => { try { const provider = new p(this.chainId, this.web3Client) @@ -191,12 +236,22 @@ export class DataFetcher { ) if (provider) { try { - await provider.fetchPoolsForToken( - currency0.wrapped, - currency1.wrapped, - excludePools, - options, - ) + options?.fetchPoolsTimeout + ? await promiseTimeout( + provider.fetchPoolsForToken( + currency0.wrapped, + currency1.wrapped, + excludePools, + options, + ), + options.fetchPoolsTimeout, + ) + : await provider.fetchPoolsForToken( + currency0.wrapped, + currency1.wrapped, + excludePools, + options, + ) } catch { /**/ } @@ -207,11 +262,24 @@ export class DataFetcher { currency0.wrapped.sortsBefore(currency1.wrapped) ? [currency0.wrapped, currency1.wrapped] : [currency1.wrapped, currency0.wrapped] - await Promise.allSettled( - this.providers.map((p) => - p.fetchPoolsForToken(token0, token1, excludePools, options), - ), - ) + try { + options?.fetchPoolsTimeout + ? await promiseTimeout( + Promise.allSettled( + this.providers.map((p) => + p.fetchPoolsForToken(token0, token1, excludePools, options), + ), + ), + options.fetchPoolsTimeout, + ) + : await Promise.allSettled( + this.providers.map((p) => + p.fetchPoolsForToken(token0, token1, excludePools, options), + ), + ) + } catch { + /**/ + } } } diff --git a/packages/sushi/src/router/liquidity-providers/PancakeSwap.ts b/packages/sushi/src/router/liquidity-providers/BaseSwap.ts similarity index 51% rename from packages/sushi/src/router/liquidity-providers/PancakeSwap.ts rename to packages/sushi/src/router/liquidity-providers/BaseSwap.ts index e12d78af9d..3f3ce6591c 100644 --- a/packages/sushi/src/router/liquidity-providers/PancakeSwap.ts +++ b/packages/sushi/src/router/liquidity-providers/BaseSwap.ts @@ -3,25 +3,22 @@ import { ChainId } from '../../chain/index.js' import { LiquidityProviders } from './LiquidityProvider.js' import { UniswapV2BaseProvider } from './UniswapV2Base.js' -export class PancakeSwapProvider extends UniswapV2BaseProvider { +export class BaseSwapProvider extends UniswapV2BaseProvider { override fee = 0.0025 constructor(chainId: ChainId, web3Client: PublicClient) { const factory = { - [ChainId.ETHEREUM]: '0x1097053Fd2ea711dad45caCcc45EfF7548fCB362', - [ChainId.BSC]: '0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73', + [ChainId.BASE]: '0xFDa619b6d20975be80A10332cD39b9a4b0FAa8BB', } as const const initCodeHash = { - [ChainId.ETHEREUM]: - '0x57224589c67f3f30a6b0d7a1b54cf3153ab84563bc609ef41dfb34f8b2974d2d', - [ChainId.BSC]: - '0x00fb7f630766e6a796048ea87d01acd3068e8ff67d078148a3fa3f4a84f69bd5', + [ChainId.BASE]: + '0xb618a2730fae167f5f8ac7bd659dd8436d571872655bcb6fd11f2158c8a64a3b', } as const super(chainId, web3Client, factory, initCodeHash) } getType(): LiquidityProviders { - return LiquidityProviders.PancakeSwap + return LiquidityProviders.BaseSwap } getPoolProviderName(): string { - return 'PancakeSwap' + return 'BaseSwap' } } diff --git a/packages/sushi/src/router/liquidity-providers/Biswap.ts b/packages/sushi/src/router/liquidity-providers/Biswap.ts index 94291d30a0..55f89fd348 100644 --- a/packages/sushi/src/router/liquidity-providers/Biswap.ts +++ b/packages/sushi/src/router/liquidity-providers/Biswap.ts @@ -1,6 +1,5 @@ import { PublicClient } from 'viem' import { ChainId } from '../../chain/index.js' - import { LiquidityProviders } from './LiquidityProvider.js' import { UniswapV2BaseProvider } from './UniswapV2Base.js' diff --git a/packages/sushi/src/router/liquidity-providers/BlastDEX.ts b/packages/sushi/src/router/liquidity-providers/BlastDEX.ts new file mode 100644 index 0000000000..b8742e1324 --- /dev/null +++ b/packages/sushi/src/router/liquidity-providers/BlastDEX.ts @@ -0,0 +1,24 @@ +import { PublicClient } from 'viem' +import { ChainId } from '../../chain/index.js' +import { LiquidityProviders } from './LiquidityProvider.js' +import { UniswapV2BaseProvider } from './UniswapV2Base.js' + +export class BlastDEXProvider extends UniswapV2BaseProvider { + override fee = 0.002 + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.BLAST]: '0x66346aac17d0e61156AC5F2A934ccF2a9BDe4c65', + } as const + const initCodeHash = { + [ChainId.BLAST]: + '0x376acff9b60b853f5ccc9f1caecb8dcf722793593330ac58aac8a880a3eb8b9e', + } as const + super(chainId, web3Client, factory, initCodeHash) + } + getType(): LiquidityProviders { + return LiquidityProviders.BlastDEX + } + getPoolProviderName(): string { + return 'BlastDEX' + } +} diff --git a/packages/sushi/src/router/liquidity-providers/BlazeSwap.ts b/packages/sushi/src/router/liquidity-providers/BlazeSwap.ts new file mode 100644 index 0000000000..1b2237bcab --- /dev/null +++ b/packages/sushi/src/router/liquidity-providers/BlazeSwap.ts @@ -0,0 +1,23 @@ +import { PublicClient } from 'viem' +import { ChainId } from '../../chain/index.js' +import { LiquidityProviders } from './LiquidityProvider.js' +import { UniswapV2BaseProvider } from './UniswapV2Base.js' + +export class BlazeSwapProvider extends UniswapV2BaseProvider { + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.FLARE]: '0x440602f459D7Dd500a74528003e6A20A46d6e2A6', + } as const + const initCodeHash = { + [ChainId.FLARE]: + '0xbf4c1c435583a2bb8d763765a34a46e376071c3b3d80e5bbac0950aeecdf31cb', + } as const + super(chainId, web3Client, factory, initCodeHash) + } + getType(): LiquidityProviders { + return LiquidityProviders.BlazeSwap + } + getPoolProviderName(): string { + return 'BlazeSwap' + } +} diff --git a/packages/sushi/src/router/liquidity-providers/Camelot.ts b/packages/sushi/src/router/liquidity-providers/Camelot.ts new file mode 100644 index 0000000000..a70e4ac029 --- /dev/null +++ b/packages/sushi/src/router/liquidity-providers/Camelot.ts @@ -0,0 +1,28 @@ +import { PublicClient, parseAbi } from 'viem' +import { ChainId } from '../../chain/index.js' +import { LiquidityProviders } from './LiquidityProvider.js' +import { UniswapV2BaseProvider } from './UniswapV2Base.js' + +export class CamelotProvider extends UniswapV2BaseProvider { + // Camelot has a slightly different getReserves() abi + // so needs to be overriden + override getReservesAbi = parseAbi([ + 'function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint16 _token0FeePercent, uint16 _token1FeePercent)', + ]) + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.ARBITRUM]: '0x6EcCab422D763aC031210895C81787E87B43A652', + } as const + const initCodeHash = { + [ChainId.ARBITRUM]: + '0xa856464ae65f7619087bc369daaf7e387dae1e5af69cfa7935850ebf754b04c1', + } as const + super(chainId, web3Client, factory, initCodeHash) + } + getType(): LiquidityProviders { + return LiquidityProviders.Camelot + } + getPoolProviderName(): string { + return 'Camelot' + } +} diff --git a/packages/sushi/src/router/liquidity-providers/DyorV2.ts b/packages/sushi/src/router/liquidity-providers/DyorV2.ts new file mode 100644 index 0000000000..e5ef032432 --- /dev/null +++ b/packages/sushi/src/router/liquidity-providers/DyorV2.ts @@ -0,0 +1,27 @@ +import { PublicClient } from 'viem' +import { ChainId } from '../../chain/index.js' +import { LiquidityProviders } from './LiquidityProvider.js' +import { UniswapV2BaseProvider } from './UniswapV2Base.js' + +export class DyorV2Provider extends UniswapV2BaseProvider { + override fee = 0.003 + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.BLAST]: '0xA1da7a7eB5A858da410dE8FBC5092c2079B58413', + [ChainId.ZETACHAIN]: '0xA1da7a7eB5A858da410dE8FBC5092c2079B58413', + } as const + const initCodeHash = { + [ChainId.BLAST]: + '0xda2f1a903916d7de88d9357d27d763f123502a5d48e3b229d5fa049b3ffdeeb5', + [ChainId.ZETACHAIN]: + '0xda2f1a903916d7de88d9357d27d763f123502a5d48e3b229d5fa049b3ffdeeb5', + } as const + super(chainId, web3Client, factory, initCodeHash) + } + getType(): LiquidityProviders { + return LiquidityProviders.DyorV2 + } + getPoolProviderName(): string { + return 'DyorV2' + } +} diff --git a/packages/sushi/src/router/liquidity-providers/Enosys.ts b/packages/sushi/src/router/liquidity-providers/Enosys.ts new file mode 100644 index 0000000000..b35e10e000 --- /dev/null +++ b/packages/sushi/src/router/liquidity-providers/Enosys.ts @@ -0,0 +1,77 @@ +import { getCreate2Address } from '@ethersproject/address' +import { Address, PublicClient, encodePacked, keccak256 } from 'viem' +import { ChainId } from '../../chain/index.js' + +import { Token } from '../../currency/Token.js' +import { getCurrencyCombinations } from '../get-currency-combinations.js' +import { LiquidityProviders } from './LiquidityProvider.js' +import { StaticPool, UniswapV2BaseProvider } from './UniswapV2Base.js' + +// Enosys has multiple initCodeHashes, so it is required to override the pool address +// calculations methods to use all the available initCodeHashes to generate multiple +// pool addresses for a pair and then the wrong ones will be filtered out automatically +// on multicall, just the same as any other non existant calculated pool addresses +export class EnosysProvider extends UniswapV2BaseProvider { + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.FLARE]: '0x28b70f6Ed97429E40FE9a9CD3EB8E86BCBA11dd4', + } as const + const initCodeHash = { + [ChainId.FLARE]: [ + '0x99e82d1f1ab2914f983fb7f2b987a3e30a55ad1fa8c38239d1f7c1a24fb93e3d', + '0xa1ab3f6a293fb82d68afb63ad2a5352fc49d5f3dfa28b151a85c382a91dd574b', + ], + } as const + super(chainId, web3Client, factory, initCodeHash as any) + } + getType(): LiquidityProviders { + return LiquidityProviders.Enosys + } + getPoolProviderName(): string { + return 'Enosys' + } + + // same as _getPoolAddress() in UniswapV2BaseProvider, but instead of + // returning only 1 pool address, it returns array of calculated pool + // addressses by using all available initCodeHashes + _getPoolAddresses(t1: Token, t2: Token): Address[] { + return (this.initCodeHash[this.chainId] as any as string[]).map( + (initCodeHash) => { + return getCreate2Address( + this.factory[this.chainId as keyof typeof this.factory]!, + keccak256( + encodePacked( + ['address', 'address'], + [t1.address as Address, t2.address as Address], + ), + ), + initCodeHash, + ) as Address + }, + ) + } + + // same as original getStaticPools() in UniswapV2BaseProvider, but + // just overriden to do flatMap() to flatten array of pool addresses + // per token pair, since there will be multiple calculated pool addresses + // per token pair as a result of having multiple initCodeHashes + override getStaticPools(t1: Token, t2: Token): StaticPool[] { + const currencyCombination = getCurrencyCombinations( + this.chainId, + t1, + t2, + ).map(([c0, c1]) => (c0.sortsBefore(c1) ? [c0, c1] : [c1, c0])) + return currencyCombination.flatMap((combination) => { + const poolAddresses = this._getPoolAddresses( + combination[0]!, + combination[1]!, + ) + return poolAddresses.map((poolAddress) => ({ + address: poolAddress, + token0: combination[0]!, + token1: combination[1]!, + fee: this.fee, + })) + }) + } +} diff --git a/packages/sushi/src/router/liquidity-providers/HyperBlast.ts b/packages/sushi/src/router/liquidity-providers/HyperBlast.ts new file mode 100644 index 0000000000..e4460650a0 --- /dev/null +++ b/packages/sushi/src/router/liquidity-providers/HyperBlast.ts @@ -0,0 +1,24 @@ +import { PublicClient } from 'viem' +import { ChainId } from '../../chain/index.js' +import { LiquidityProviders } from './LiquidityProvider.js' +import { UniswapV2BaseProvider } from './UniswapV2Base.js' + +export class HyperBlastProvider extends UniswapV2BaseProvider { + override fee = 0.003 + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.BLAST]: '0xD97fFc2041a8aB8f6bc4aeE7eE8ECA485381D088', + } as const + const initCodeHash = { + [ChainId.BLAST]: + '0x2e6ab686c26cf8ecf0a8c01a9fb0ef96dbd4631c04b03005350fa49e8f2f32f8', + } as const + super(chainId, web3Client, factory, initCodeHash) + } + getType(): LiquidityProviders { + return LiquidityProviders.HyperBlast + } + getPoolProviderName(): string { + return 'HyperBlast' + } +} diff --git a/packages/sushi/src/router/liquidity-providers/KinetixV2.ts b/packages/sushi/src/router/liquidity-providers/KinetixV2.ts new file mode 100644 index 0000000000..1cf407d8b2 --- /dev/null +++ b/packages/sushi/src/router/liquidity-providers/KinetixV2.ts @@ -0,0 +1,24 @@ +import { PublicClient } from 'viem' +import { ChainId } from '../../chain/index.js' +import { LiquidityProviders } from './LiquidityProvider.js' +import { UniswapV2BaseProvider } from './UniswapV2Base.js' + +export class KinetixV2Provider extends UniswapV2BaseProvider { + override fee = 0.003 + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.KAVA]: '0xE8E917BC80A26CDacc9aA42C0F4965d2E1Fa52da', + } as const + const initCodeHash = { + [ChainId.KAVA]: + '0x4b61b80b5bcfca0f9202f2aba1955b0cfda155e379cb36e0ab38598337c4c79a', + } as const + super(chainId, web3Client, factory, initCodeHash) + } + getType(): LiquidityProviders { + return LiquidityProviders.KinetixV2 + } + getPoolProviderName(): string { + return 'KinetixV2' + } +} diff --git a/packages/sushi/src/router/liquidity-providers/KinetixV3.ts b/packages/sushi/src/router/liquidity-providers/KinetixV3.ts new file mode 100644 index 0000000000..b7591e9e68 --- /dev/null +++ b/packages/sushi/src/router/liquidity-providers/KinetixV3.ts @@ -0,0 +1,26 @@ +import { PublicClient } from 'viem' +import { ChainId } from '../../chain/index.js' +import { LiquidityProviders } from './LiquidityProvider.js' +import { UniswapV3BaseProvider } from './UniswapV3Base.js' + +export class KinetixV3Provider extends UniswapV3BaseProvider { + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.KAVA]: '0x2dBB6254231C5569B6A4313c6C1F5Fe1340b35C2', + } as const + const initCodeHash = { + [ChainId.KAVA]: + '0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54', + } as const + const tickLens = { + [ChainId.KAVA]: '0xdc7A5276aB4C6cd25e16b6118B230109945D2426', + } as const + super(chainId, web3Client, factory, initCodeHash, tickLens) + } + getType(): LiquidityProviders { + return LiquidityProviders.KinetixV3 + } + getPoolProviderName(): string { + return 'KinetixV3' + } +} diff --git a/packages/sushi/src/router/liquidity-providers/LiquidityProvider.ts b/packages/sushi/src/router/liquidity-providers/LiquidityProvider.ts index 289465fb94..9037bdbd08 100644 --- a/packages/sushi/src/router/liquidity-providers/LiquidityProvider.ts +++ b/packages/sushi/src/router/liquidity-providers/LiquidityProvider.ts @@ -12,13 +12,14 @@ export enum LiquidityProviders { Trident = 'Trident', QuickSwap = 'QuickSwap', ApeSwap = 'ApeSwap', - PancakeSwap = 'PancakeSwap', + PancakeSwapV2 = 'PancakeSwapV2', PancakeSwapV3 = 'PancakeSwapV3', TraderJoe = 'TraderJoe', Dfyn = 'Dfyn', Elk = 'Elk', JetSwap = 'JetSwap', - SpookySwap = 'SpookySwap', + SpookySwapV2 = 'SpookySwapV2', + SpookySwapV3 = 'SpookySwapV3', NetSwap = 'NetSwap', NativeWrap = 'NativeWrap', HoneySwap = 'HoneySwap', @@ -42,7 +43,11 @@ export enum LiquidityProviders { ThrusterV3 = 'ThrusterV3', DyorV2 = 'DyorV2', HyperBlast = 'HyperBlast', + KinetixV2 = 'KinetixV2', KinetixV3 = 'KinetixV3', + Camelot = 'Camelot', + Enosys = 'Enosys', + BlazeSwap = 'BlazeSwap', } export abstract class LiquidityProvider { diff --git a/packages/sushi/src/router/liquidity-providers/MonoSwapV2.ts b/packages/sushi/src/router/liquidity-providers/MonoSwapV2.ts new file mode 100644 index 0000000000..c59c7f9731 --- /dev/null +++ b/packages/sushi/src/router/liquidity-providers/MonoSwapV2.ts @@ -0,0 +1,24 @@ +import { PublicClient } from 'viem' +import { ChainId } from '../../chain/index.js' +import { LiquidityProviders } from './LiquidityProvider.js' +import { UniswapV2BaseProvider } from './UniswapV2Base.js' + +export class MonoswapV2Provider extends UniswapV2BaseProvider { + override fee = 0.003 + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.BLAST]: '0xE27cb06A15230A7480d02956a3521E78C5bFD2D0', + } as const + const initCodeHash = { + [ChainId.BLAST]: + '0xd1a99f7339108abbcc2eaa6478ee4a0394e2a63f04de08793721fb2f3eff5a38', + } as const + super(chainId, web3Client, factory, initCodeHash) + } + getType(): LiquidityProviders { + return LiquidityProviders.MonoswapV2 + } + getPoolProviderName(): string { + return 'MonoswapV2' + } +} diff --git a/packages/sushi/src/router/liquidity-providers/MonoSwapV3.ts b/packages/sushi/src/router/liquidity-providers/MonoSwapV3.ts new file mode 100644 index 0000000000..6ebf4d9855 --- /dev/null +++ b/packages/sushi/src/router/liquidity-providers/MonoSwapV3.ts @@ -0,0 +1,26 @@ +import { PublicClient } from 'viem' +import { ChainId } from '../../chain/index.js' +import { LiquidityProviders } from './LiquidityProvider.js' +import { UniswapV3BaseProvider } from './UniswapV3Base.js' + +export class MonoswapV3Provider extends UniswapV3BaseProvider { + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.BLAST]: '0x48d0F09710794313f33619c95147F34458BF7C3b', + } as const + const initCodeHash = { + [ChainId.BLAST]: + '0x7ea070216c7d9135010a36147394687bab92df4695e924000eed7c4b33eb922f', + } as const + const tickLens = { + [ChainId.BLAST]: '0x4a3930837f6E721A6Da5DE4E400A7e90f907fb54', + } as const + super(chainId, web3Client, factory, initCodeHash, tickLens) + } + getType(): LiquidityProviders { + return LiquidityProviders.MonoswapV3 + } + getPoolProviderName(): string { + return 'MonoswapV3' + } +} diff --git a/packages/sushi/src/router/liquidity-providers/PancakeSwapV2.ts b/packages/sushi/src/router/liquidity-providers/PancakeSwapV2.ts new file mode 100644 index 0000000000..932153c887 --- /dev/null +++ b/packages/sushi/src/router/liquidity-providers/PancakeSwapV2.ts @@ -0,0 +1,42 @@ +import { PublicClient } from 'viem' +import { ChainId } from '../../chain/index.js' +import { LiquidityProviders } from './LiquidityProvider.js' +import { UniswapV2BaseProvider } from './UniswapV2Base.js' + +export class PancakeSwapV2Provider extends UniswapV2BaseProvider { + override fee = 0.0025 + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.ETHEREUM]: '0x1097053Fd2ea711dad45caCcc45EfF7548fCB362', + [ChainId.BSC]: '0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73', + [ChainId.POLYGON_ZKEVM]: '0x02a84c1b3BBD7401a5f7fa98a384EBC70bB5749E', + [ChainId.ZKSYNC_ERA]: '0xd03D8D566183F0086d8D09A84E1e30b58Dd5619d', + [ChainId.ARBITRUM]: '0x02a84c1b3BBD7401a5f7fa98a384EBC70bB5749E', + [ChainId.LINEA]: '0x02a84c1b3BBD7401a5f7fa98a384EBC70bB5749E', + [ChainId.BASE]: '0x02a84c1b3BBD7401a5f7fa98a384EBC70bB5749E', + } as const + const initCodeHash = { + [ChainId.ETHEREUM]: + '0x57224589c67f3f30a6b0d7a1b54cf3153ab84563bc609ef41dfb34f8b2974d2d', + [ChainId.BSC]: + '0x00fb7f630766e6a796048ea87d01acd3068e8ff67d078148a3fa3f4a84f69bd5', + [ChainId.POLYGON_ZKEVM]: + '0x57224589c67f3f30a6b0d7a1b54cf3153ab84563bc609ef41dfb34f8b2974d2d', + [ChainId.ZKSYNC_ERA]: + '0x1cb011040b91cd937ddff2327f17c9690653b05b6506e830baadf2493468d657', + [ChainId.ARBITRUM]: + '0x57224589c67f3f30a6b0d7a1b54cf3153ab84563bc609ef41dfb34f8b2974d2d', + [ChainId.LINEA]: + '0x57224589c67f3f30a6b0d7a1b54cf3153ab84563bc609ef41dfb34f8b2974d2d', + [ChainId.BASE]: + '0x57224589c67f3f30a6b0d7a1b54cf3153ab84563bc609ef41dfb34f8b2974d2d', + } as const + super(chainId, web3Client, factory, initCodeHash) + } + getType(): LiquidityProviders { + return LiquidityProviders.PancakeSwapV2 + } + getPoolProviderName(): string { + return 'PancakeSwapV2' + } +} diff --git a/packages/sushi/src/router/liquidity-providers/PancakeSwapV3.ts b/packages/sushi/src/router/liquidity-providers/PancakeSwapV3.ts new file mode 100644 index 0000000000..a252c0d7c6 --- /dev/null +++ b/packages/sushi/src/router/liquidity-providers/PancakeSwapV3.ts @@ -0,0 +1,50 @@ +import { PublicClient } from 'viem' +import { ChainId } from '../../chain/index.js' +import { LiquidityProviders } from './LiquidityProvider.js' +import { UniswapV3BaseProvider } from './UniswapV3Base.js' + +export class PancakeSwapV3Provider extends UniswapV3BaseProvider { + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.ARBITRUM]: '0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865', + [ChainId.BASE]: '0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865', + [ChainId.BSC]: '0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865', + [ChainId.ETHEREUM]: '0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865', + [ChainId.LINEA]: '0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865', + [ChainId.POLYGON_ZKEVM]: '0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865', + [ChainId.ZKSYNC_ERA]: '0x1BB72E0CbbEA93c08f535fc7856E0338D7F7a8aB', + } as const + const initCodeHash = { + [ChainId.ARBITRUM]: + '0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2', + [ChainId.BASE]: + '0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2', + [ChainId.BSC]: + '0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2', + [ChainId.ETHEREUM]: + '0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2', + [ChainId.LINEA]: + '0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2', + [ChainId.POLYGON_ZKEVM]: + '0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2', + [ChainId.ZKSYNC_ERA]: + '0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2', + } as const + const tickLens = { + [ChainId.ARBITRUM]: '0x9a489505a00cE272eAa5e07Dba6491314CaE3796', + [ChainId.BASE]: '0x9a489505a00cE272eAa5e07Dba6491314CaE3796', + [ChainId.BSC]: '0x9a489505a00cE272eAa5e07Dba6491314CaE3796', + [ChainId.ETHEREUM]: '0x9a489505a00cE272eAa5e07Dba6491314CaE3796', + [ChainId.LINEA]: '0x9a489505a00cE272eAa5e07Dba6491314CaE3796', + [ChainId.POLYGON_ZKEVM]: '0x9a489505a00cE272eAa5e07Dba6491314CaE3796', + [ChainId.ZKSYNC_ERA]: '0x7b08978FA77910f77d273c353C62b5BFB9E6D17B', + } as const + super(chainId, web3Client, factory, initCodeHash, tickLens) + } + getType(): LiquidityProviders { + return LiquidityProviders.PancakeSwapV3 + } + getPoolProviderName(): string { + return 'PancackeSwapV3' + } +} diff --git a/packages/sushi/src/router/liquidity-providers/Solarbeam.ts b/packages/sushi/src/router/liquidity-providers/Solarbeam.ts new file mode 100644 index 0000000000..3382b209e2 --- /dev/null +++ b/packages/sushi/src/router/liquidity-providers/Solarbeam.ts @@ -0,0 +1,23 @@ +import { PublicClient } from 'viem' +import { ChainId } from '../../chain/index.js' +import { LiquidityProviders } from './LiquidityProvider.js' +import { UniswapV2BaseProvider } from './UniswapV2Base.js' + +export class SolarbeamProvider extends UniswapV2BaseProvider { + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.MOONBEAM]: '0x19B85ae92947E0725d5265fFB3389e7E4F191FDa', + } as const + const initCodeHash = { + [ChainId.MOONBEAM]: + '0x9a100ded5f254443fbd264cb7e87831e398a8b642e061670a9bc35ba27293dbf', + } as const + super(chainId, web3Client, factory, initCodeHash) + } + getType(): LiquidityProviders { + return LiquidityProviders.Solarbeam + } + getPoolProviderName(): string { + return 'Solarbeam' + } +} diff --git a/packages/sushi/src/router/liquidity-providers/SpookySwap.ts b/packages/sushi/src/router/liquidity-providers/SpookySwapV2.ts similarity index 82% rename from packages/sushi/src/router/liquidity-providers/SpookySwap.ts rename to packages/sushi/src/router/liquidity-providers/SpookySwapV2.ts index 66fbcbb760..0c94b57638 100644 --- a/packages/sushi/src/router/liquidity-providers/SpookySwap.ts +++ b/packages/sushi/src/router/liquidity-providers/SpookySwapV2.ts @@ -3,7 +3,7 @@ import { ChainId } from '../../chain/index.js' import { LiquidityProviders } from './LiquidityProvider.js' import { UniswapV2BaseProvider } from './UniswapV2Base.js' -export class SpookySwapProvider extends UniswapV2BaseProvider { +export class SpookySwapV2Provider extends UniswapV2BaseProvider { constructor(chainId: ChainId, web3Client: PublicClient) { const factory = { [ChainId.FANTOM]: '0x152eE697f2E276fA89E96742e9bB9aB1F2E61bE3', @@ -15,9 +15,9 @@ export class SpookySwapProvider extends UniswapV2BaseProvider { super(chainId, web3Client, factory, initCodeHash) } getType(): LiquidityProviders { - return LiquidityProviders.SpookySwap + return LiquidityProviders.SpookySwapV2 } getPoolProviderName(): string { - return 'SpookySwap' + return 'SpookySwapV2' } } diff --git a/packages/sushi/src/router/liquidity-providers/SpookySwapV3.ts b/packages/sushi/src/router/liquidity-providers/SpookySwapV3.ts new file mode 100644 index 0000000000..69d1f34c0e --- /dev/null +++ b/packages/sushi/src/router/liquidity-providers/SpookySwapV3.ts @@ -0,0 +1,26 @@ +import { PublicClient } from 'viem' +import { ChainId } from '../../chain/index.js' +import { LiquidityProviders } from './LiquidityProvider.js' +import { UniswapV3BaseProvider } from './UniswapV3Base.js' + +export class SpookySwapV3Provider extends UniswapV3BaseProvider { + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.FANTOM]: '0x7928a2c48754501f3a8064765ECaE541daE5c3E6', + } as const + const initCodeHash = { + [ChainId.FANTOM]: + '0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54', + } as const + const tickLens = { + [ChainId.FANTOM]: '0xbaA8353CC9d02733eF12f9556ed999521f6E554c', + } as const + super(chainId, web3Client, factory, initCodeHash, tickLens) + } + getType(): LiquidityProviders { + return LiquidityProviders.SpookySwapV3 + } + getPoolProviderName(): string { + return 'SpookySwapV3' + } +} diff --git a/packages/sushi/src/router/liquidity-providers/SwapBlast.ts b/packages/sushi/src/router/liquidity-providers/SwapBlast.ts new file mode 100644 index 0000000000..4f04bd000b --- /dev/null +++ b/packages/sushi/src/router/liquidity-providers/SwapBlast.ts @@ -0,0 +1,24 @@ +import { PublicClient } from 'viem' +import { ChainId } from '../../chain/index.js' +import { LiquidityProviders } from './LiquidityProvider.js' +import { UniswapV2BaseProvider } from './UniswapV2Base.js' + +export class SwapBlastProvider extends UniswapV2BaseProvider { + override fee = 0.001 + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.BLAST]: '0x04C9f118d21e8B767D2e50C946f0cC9F6C367300', + } as const + const initCodeHash = { + [ChainId.BLAST]: + '0x89f2ba5c4e1e84307b0efac8ff56efab2786d9becd741ff83b1b6397de76dafc', + } as const + super(chainId, web3Client, factory, initCodeHash) + } + getType(): LiquidityProviders { + return LiquidityProviders.SwapBlast + } + getPoolProviderName(): string { + return 'SwapBlast' + } +} diff --git a/packages/sushi/src/router/liquidity-providers/ThrusterV2.ts b/packages/sushi/src/router/liquidity-providers/ThrusterV2.ts new file mode 100644 index 0000000000..b1cfad438b --- /dev/null +++ b/packages/sushi/src/router/liquidity-providers/ThrusterV2.ts @@ -0,0 +1,44 @@ +import { PublicClient } from 'viem' +import { ChainId } from '../../chain/index.js' +import { LiquidityProviders } from './LiquidityProvider.js' +import { UniswapV2BaseProvider } from './UniswapV2Base.js' + +export class ThrusterV2_3Provider extends UniswapV2BaseProvider { + override fee = 0.003 + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.BLAST]: '0xb4A7D971D0ADea1c73198C97d7ab3f9CE4aaFA13', + } as const + const initCodeHash = { + [ChainId.BLAST]: + '0x6f0346418750a1a53597a51ceff4f294b5f0e87f09715525b519d38ad3fab2cb', + } as const + super(chainId, web3Client, factory, initCodeHash) + } + getType(): LiquidityProviders { + return LiquidityProviders.ThrusterV2 + } + getPoolProviderName(): string { + return 'ThrusterV2' + } +} + +export class ThrusterV2_1Provider extends UniswapV2BaseProvider { + override fee = 0.01 + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.BLAST]: '0x37836821a2c03c171fB1a595767f4a16e2b93Fc4', + } as const + const initCodeHash = { + [ChainId.BLAST]: + '0x32a9ff5a51b653cbafe88e38c4da86b859135750d3ca435f0ce732c8e3bb8335', + } as const + super(chainId, web3Client, factory, initCodeHash) + } + getType(): LiquidityProviders { + return LiquidityProviders.ThrusterV2 + } + getPoolProviderName(): string { + return 'ThrusterV2' + } +} diff --git a/packages/sushi/src/router/liquidity-providers/ThrusterV3.ts b/packages/sushi/src/router/liquidity-providers/ThrusterV3.ts new file mode 100644 index 0000000000..d1d7dffd0b --- /dev/null +++ b/packages/sushi/src/router/liquidity-providers/ThrusterV3.ts @@ -0,0 +1,26 @@ +import { PublicClient } from 'viem' +import { ChainId } from '../../chain/index.js' +import { LiquidityProviders } from './LiquidityProvider.js' +import { UniswapV3BaseProvider } from './UniswapV3Base.js' + +export class ThrusterV3Provider extends UniswapV3BaseProvider { + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.BLAST]: '0x71b08f13B3c3aF35aAdEb3949AFEb1ded1016127', + } as const + const initCodeHash = { + [ChainId.BLAST]: + '0xd0c3a51b16dbc778f000c620eaabeecd33b33a80bd145e1f7cbc0d4de335193d', + } as const + const tickLens = { + [ChainId.BLAST]: '0x796B39328b92472b2Bd950AEB20D950611e02EF6', + } as const + super(chainId, web3Client, factory, initCodeHash, tickLens) + } + getType(): LiquidityProviders { + return LiquidityProviders.ThrusterV3 + } + getPoolProviderName(): string { + return 'ThrusterV3' + } +} diff --git a/packages/sushi/src/router/liquidity-providers/TraderJoe.ts b/packages/sushi/src/router/liquidity-providers/TraderJoe.ts index bac9b35ce8..3e215bf7cf 100644 --- a/packages/sushi/src/router/liquidity-providers/TraderJoe.ts +++ b/packages/sushi/src/router/liquidity-providers/TraderJoe.ts @@ -7,10 +7,16 @@ export class TraderJoeProvider extends UniswapV2BaseProvider { constructor(chainId: ChainId, web3Client: PublicClient) { const factory = { [ChainId.AVALANCHE]: '0x9Ad6C38BE94206cA50bb0d90783181662f0Cfa10', + [ChainId.ARBITRUM]: '0xaE4EC9901c3076D0DdBe76A520F9E90a6227aCB7', + [ChainId.BSC]: '0x4f8bdc85E3eec5b9dE67097c3f59B6Db025d9986', } as const const initCodeHash = { [ChainId.AVALANCHE]: '0x0bbca9af0511ad1a1da383135cf3a8d2ac620e549ef9f6ae3a4c33c2fed0af91', + [ChainId.ARBITRUM]: + '0x6c67ac67d0dad54be7b066edd9b4154fb5a0ab7d01232259b9ff26ebc1739ba2', + [ChainId.BSC]: + '0x5c9d12e487d245c53fb0b8dd1ba2ccc48810e6b9671311502b8632e88b0d605b', } as const super(chainId, web3Client, factory, initCodeHash) } diff --git a/packages/sushi/src/router/liquidity-providers/Trident.ts b/packages/sushi/src/router/liquidity-providers/Trident.ts index c8620ff678..267b3ecb2c 100644 --- a/packages/sushi/src/router/liquidity-providers/Trident.ts +++ b/packages/sushi/src/router/liquidity-providers/Trident.ts @@ -1138,23 +1138,23 @@ export class TridentProvider extends LiquidityProvider { this.topStablePools = new Map() this.bridges = new Map() - this.unwatchBlockNumber = this.client.watchBlockNumber({ - onBlockNumber: (blockNumber) => { - this.lastUpdateBlock = Number(blockNumber) - if (!this.isInitialized) { - this.initialize() - } else { - this.updatePools() - } - }, - onError: (error) => { - console.error( - `${this.getLogPrefix()} - Error watching block number: ${ - error.message - }`, - ) - }, - }) + // this.unwatchBlockNumber = this.client.watchBlockNumber({ + // onBlockNumber: (blockNumber) => { + // this.lastUpdateBlock = Number(blockNumber) + // if (!this.isInitialized) { + // this.initialize() + // } else { + // this.updatePools() + // } + // }, + // onError: (error) => { + // console.error( + // `${this.getLogPrefix()} - Error watching block number: ${ + // error.message + // }`, + // ) + // }, + // }) } private removeStalePools() { diff --git a/packages/sushi/src/router/liquidity-providers/UniswapV2.ts b/packages/sushi/src/router/liquidity-providers/UniswapV2.ts index 21a10b0871..782cef3a46 100644 --- a/packages/sushi/src/router/liquidity-providers/UniswapV2.ts +++ b/packages/sushi/src/router/liquidity-providers/UniswapV2.ts @@ -7,10 +7,31 @@ export class UniswapV2Provider extends UniswapV2BaseProvider { constructor(chainId: ChainId, web3Client: PublicClient) { const factory = { [ChainId.ETHEREUM]: '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f', + [ChainId.ARBITRUM]: '0xf1D7CC64Fb4452F05c498126312eBE29f30Fbcf9', + [ChainId.AVALANCHE]: '0x9e5A52f57b3038F1B8EeE45F28b3C1967e22799C', + [ChainId.BSC]: '0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6', + [ChainId.OPTIMISM]: '0x0c3c1c532F1e39EdF36BE9Fe0bE1410313E074Bf', + [ChainId.POLYGON]: '0x9e5A52f57b3038F1B8EeE45F28b3C1967e22799C', + [ChainId.BLAST]: '0x5C346464d33F90bABaf70dB6388507CC889C1070', + [ChainId.BASE]: '0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6', } as const const initCodeHash = { [ChainId.ETHEREUM]: '0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f', + [ChainId.ARBITRUM]: + '0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f', + [ChainId.AVALANCHE]: + '0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f', + [ChainId.BSC]: + '0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f', + [ChainId.OPTIMISM]: + '0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f', + [ChainId.POLYGON]: + '0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f', + [ChainId.BLAST]: + '0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f', + [ChainId.BASE]: + '0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f', } as const super(chainId, web3Client, factory, initCodeHash) } diff --git a/packages/sushi/src/router/liquidity-providers/UniswapV2Base.ts b/packages/sushi/src/router/liquidity-providers/UniswapV2Base.ts index e46987fb8d..2c532e5b67 100644 --- a/packages/sushi/src/router/liquidity-providers/UniswapV2Base.ts +++ b/packages/sushi/src/router/liquidity-providers/UniswapV2Base.ts @@ -1,7 +1,7 @@ import { getCreate2Address } from '@ethersproject/address' import { add, getUnixTime } from 'date-fns' import { Address, Hex, PublicClient, encodePacked, keccak256 } from 'viem' -import { getReservesAbi } from '../../abi/index.js' +import { getReservesAbi as abi } from '../../abi/index.js' import { ChainId } from '../../chain/index.js' import { ADDITIONAL_BASES, @@ -26,7 +26,7 @@ interface PoolInfo { validUntilTimestamp: number } -interface StaticPool { +export interface StaticPool { address: Address token0: Token token1: Token @@ -59,6 +59,7 @@ export abstract class UniswapV2BaseProvider extends LiquidityProvider { refreshAvailablePoolsTimestamp = getUnixTime( add(Date.now(), { seconds: this.FETCH_AVAILABLE_POOLS_AFTER_SECONDS }), ) + getReservesAbi: any = abi constructor( chainId: ChainId, @@ -107,7 +108,7 @@ export abstract class UniswapV2BaseProvider extends LiquidityProvider { ({ address: pool.address as Address, chainId: this.chainId, - abi: getReservesAbi, + abi, functionName: 'getReserves', }) as const, ), @@ -234,7 +235,7 @@ export abstract class UniswapV2BaseProvider extends LiquidityProvider { ({ address: poolCode.pool.address as Address, chainId: this.chainId, - abi: getReservesAbi, + abi: this.getReservesAbi, functionName: 'getReserves', }) as const, ), @@ -307,7 +308,7 @@ export abstract class UniswapV2BaseProvider extends LiquidityProvider { ({ address: poolCode.pool.address as Address, chainId: this.chainId, - abi: getReservesAbi, + abi, functionName: 'getReserves', }) as const, ), @@ -330,7 +331,7 @@ export abstract class UniswapV2BaseProvider extends LiquidityProvider { ({ address: poolCode.pool.address as Address, chainId: this.chainId, - abi: getReservesAbi, + abi, functionName: 'getReserves', }) as const, ), @@ -513,23 +514,23 @@ export abstract class UniswapV2BaseProvider extends LiquidityProvider { startFetchPoolsData() { this.stopFetchPoolsData() this.topPools = new Map() - this.unwatchBlockNumber = this.client.watchBlockNumber({ - onBlockNumber: (blockNumber) => { - this.lastUpdateBlock = Number(blockNumber) - if (!this.isInitialized) { - this.initialize() - } else { - this.updatePools() - } - }, - onError: (error) => { - console.error( - `${this.getLogPrefix()} - Error watching block number: ${ - error.message - }`, - ) - }, - }) + // this.unwatchBlockNumber = this.client.watchBlockNumber({ + // onBlockNumber: (blockNumber) => { + // this.lastUpdateBlock = Number(blockNumber) + // if (!this.isInitialized) { + // this.initialize() + // } else { + // this.updatePools() + // } + // }, + // onError: (error) => { + // console.error( + // `${this.getLogPrefix()} - Error watching block number: ${ + // error.message + // }`, + // ) + // }, + // }) } private removeStalePools() { diff --git a/packages/sushi/src/router/liquidity-providers/UniswapV3Base.ts b/packages/sushi/src/router/liquidity-providers/UniswapV3Base.ts index 334f8328ab..fa356b5436 100644 --- a/packages/sushi/src/router/liquidity-providers/UniswapV3Base.ts +++ b/packages/sushi/src/router/liquidity-providers/UniswapV3Base.ts @@ -487,23 +487,23 @@ export abstract class UniswapV3BaseProvider extends LiquidityProvider { startFetchPoolsData() { this.stopFetchPoolsData() // this.topPools = new Map() - this.unwatchBlockNumber = this.client.watchBlockNumber({ - onBlockNumber: (blockNumber) => { - this.lastUpdateBlock = Number(blockNumber) - // if (!this.isInitialized) { - // this.initialize() - // } else { - // this.updatePools() - // } - }, - onError: (error) => { - console.error( - `${this.getLogPrefix()} - Error watching block number: ${ - error.message - }`, - ) - }, - }) + // this.unwatchBlockNumber = this.client.watchBlockNumber({ + // onBlockNumber: (blockNumber) => { + // this.lastUpdateBlock = Number(blockNumber) + // // if (!this.isInitialized) { + // // this.initialize() + // // } else { + // // this.updatePools() + // // } + // }, + // onError: (error) => { + // console.error( + // `${this.getLogPrefix()} - Error watching block number: ${ + // error.message + // }`, + // ) + // }, + // }) } getCurrentPoolList(): PoolCode[] { diff --git a/packages/sushi/src/router/liquidity-providers/VVSStandard.ts b/packages/sushi/src/router/liquidity-providers/VVSStandard.ts new file mode 100644 index 0000000000..a25d5eb3f3 --- /dev/null +++ b/packages/sushi/src/router/liquidity-providers/VVSStandard.ts @@ -0,0 +1,23 @@ +import { PublicClient } from 'viem' +import { ChainId } from '../../chain/index.js' +import { LiquidityProviders } from './LiquidityProvider.js' +import { UniswapV2BaseProvider } from './UniswapV2Base.js' + +export class VVSStandardProvider extends UniswapV2BaseProvider { + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.CRONOS]: '0x3B44B2a187a7b3824131F8db5a74194D0a42Fc15', + } as const + const initCodeHash = { + [ChainId.CRONOS]: + '0xa77ee1cc0f39570ddde947459e293d7ebc2c30ff4e8fc45860afdcb2c2d3dc17', + } as const + super(chainId, web3Client, factory, initCodeHash) + } + getType(): LiquidityProviders { + return LiquidityProviders.VVSStandard + } + getPoolProviderName(): string { + return 'VVSStandard' + } +} diff --git a/packages/sushi/src/router/liquidity-providers/Wagmi.ts b/packages/sushi/src/router/liquidity-providers/Wagmi.ts new file mode 100644 index 0000000000..1ec5b38959 --- /dev/null +++ b/packages/sushi/src/router/liquidity-providers/Wagmi.ts @@ -0,0 +1,42 @@ +import { PublicClient } from 'viem' +import { ChainId } from '../../chain/index.js' +import { LiquidityProviders } from './LiquidityProvider.js' +import { UniswapV3BaseProvider } from './UniswapV3Base.js' + +export class WagmiProvider extends UniswapV3BaseProvider { + constructor(chainId: ChainId, web3Client: PublicClient) { + const factory = { + [ChainId.ETHEREUM]: '0xB9a14EE1cd3417f3AcC988F61650895151abde24', + [ChainId.FANTOM]: '0xaf20f5f19698f1D19351028cd7103B63D30DE7d7', + [ChainId.KAVA]: '0x0e0Ce4D450c705F8a0B6Dd9d5123e3df2787D16B', + [ChainId.ZKSYNC_ERA]: '0x31be61CE896e8770B21e7A1CAFA28402Dd701995', + [ChainId.METIS]: '0x8112E18a34b63964388a3B2984037d6a2EFE5B8A', + } as const + const initCodeHash = { + [ChainId.ETHEREUM]: + '0x30146866f3a846fe3c636beb2756dbd24cf321bc52c9113c837c21f47470dfeb', + [ChainId.FANTOM]: + '0x30146866f3a846fe3c636beb2756dbd24cf321bc52c9113c837c21f47470dfeb', + [ChainId.KAVA]: + '0x30146866f3a846fe3c636beb2756dbd24cf321bc52c9113c837c21f47470dfeb', + [ChainId.ZKSYNC_ERA]: + '0x30146866f3a846fe3c636beb2756dbd24cf321bc52c9113c837c21f47470dfeb', + [ChainId.METIS]: + '0x30146866f3a846fe3c636beb2756dbd24cf321bc52c9113c837c21f47470dfeb', + } as const + const tickLens = { + [ChainId.ETHEREUM]: '0xb1F795776cB9DdAC6E7e162f31C7419Dd3d48297', + [ChainId.FANTOM]: '0x209050d81Aad536Ca2092466B221013B8de7AC6c', + [ChainId.KAVA]: '0xf914e1329e4588783Ee68f06B2b900adDC97f966', + [ChainId.ZKSYNC_ERA]: '0x09Cbf436DE2273dAC3f0971fB905aCBe41b1CC81', + [ChainId.METIS]: '0x428065998a96F82bf66A0A427A157429A6Fdd649', + } as const + super(chainId, web3Client, factory, initCodeHash, tickLens) + } + getType(): LiquidityProviders { + return LiquidityProviders.Wagmi + } + getPoolProviderName(): string { + return 'Wagmi' + } +} diff --git a/packages/sushi/src/router/memoizer.test.ts b/packages/sushi/src/router/memoizer.test.ts index d1f9a07eaa..4e9d1da9f7 100644 --- a/packages/sushi/src/router/memoizer.test.ts +++ b/packages/sushi/src/router/memoizer.test.ts @@ -1,6 +1,7 @@ import fs from 'fs' +import memoize from 'memoize-fs' import { describe, expect, it } from 'vitest' -import { memoizer } from './memoizer.js' +import { deserialize, serialize } from './memoizer.js' describe('Memoizer', async () => { it('should serialize, memoize, read from cache, deserialize', async () => { @@ -12,6 +13,11 @@ describe('Memoizer', async () => { someOtherValue: 'some data', } } + const memoizer = memoize({ + cachePath: './test-cache', + serialize, + deserialize, + }) const testMemoizer = await memoizer.fn(testFn) const testValue = { @@ -42,12 +48,15 @@ describe('Memoizer', async () => { // read cached file content const cacheFileContent = fs.readFileSync( - `./mem-cache/${fs.readdirSync('./mem-cache')[0]}`, + `./test-cache/${fs.readdirSync('./test-cache')[0]}`, { encoding: 'utf-8' }, ) const expectedCachedContent = '{"data":{"bigint":"12345n","string":"some text","number":123,"bool":true,"obj":{"prop":"some prop"},"someOtherValue":"some data"}}' expect(cacheFileContent).toEqual(expectedCachedContent) + + // remove the cached data + fs.rmSync('./test-cache', { recursive: true, force: true }) }) }) diff --git a/packages/sushi/src/router/memoizer.ts b/packages/sushi/src/router/memoizer.ts index a8810d85f4..bd0b5d8c3c 100644 --- a/packages/sushi/src/router/memoizer.ts +++ b/packages/sushi/src/router/memoizer.ts @@ -1,6 +1,6 @@ import memoize from 'memoize-fs' -const serialize = (val: any) => { +export const serialize = (val: any) => { const circRefColl: any[] = [] return JSON.stringify(val, (_name, value) => { if (typeof value === 'function') { @@ -19,7 +19,7 @@ const serialize = (val: any) => { }) } -const deserialize = (val: string) => { +export const deserialize = (val: string) => { return JSON.parse(val, (_key, value) => { if (typeof value === 'string' && /^\d+n$/.test(value)) { return BigInt(value.slice(0, -1)) diff --git a/packages/sushi/src/router/timeout.test.ts b/packages/sushi/src/router/timeout.test.ts new file mode 100644 index 0000000000..611eb6d650 --- /dev/null +++ b/packages/sushi/src/router/timeout.test.ts @@ -0,0 +1,33 @@ +import { describe, it } from 'vitest' +import { promiseTimeout } from './timeout.js' + +const sleep = async (ms: number, msg = '') => { + let _timeoutReference + return new Promise((resolve) => { + _timeoutReference = setTimeout(() => resolve(msg), ms) + return _timeoutReference + }).finally(() => clearTimeout(_timeoutReference)) +} + +describe('Promise Timeout', async () => { + it('should timeout', async () => { + const mainPromise = sleep(1000) + await promiseTimeout(mainPromise, 500) + .then(() => { + throw 'expected to reject, but resolved' + }) + .catch(() => { + /**/ + }) + }) + it('should NOT timeout', async () => { + const mainPromise = sleep(1000) + await promiseTimeout(mainPromise, 1500) + .then(() => { + /**/ + }) + .catch(() => { + throw 'expected to resolve, but rejected' + }) + }) +}) diff --git a/packages/sushi/src/router/timeout.ts b/packages/sushi/src/router/timeout.ts new file mode 100644 index 0000000000..f05d41fd89 --- /dev/null +++ b/packages/sushi/src/router/timeout.ts @@ -0,0 +1,14 @@ +export async function promiseTimeout( + promise: Promise, + time: number, + exception?: any, +) { + let timer: any + return Promise.race([ + promise, + new Promise((_res, _rej) => { + timer = setTimeout(_rej, time, exception) + return timer + }), + ]).finally(() => clearTimeout(timer)) +} diff --git a/protocols/route-processor/test/DataFetcher.test.ts b/protocols/route-processor/test/DataFetcher.test.ts index 750bb633f5..779dca0aaa 100644 --- a/protocols/route-processor/test/DataFetcher.test.ts +++ b/protocols/route-processor/test/DataFetcher.test.ts @@ -12,7 +12,9 @@ async function testDF( ) { if (!t0 || !t1) return const start = performance.now() - await dataFetcher.fetchPoolsForToken(t0, t1) + await dataFetcher.fetchPoolsForToken(t0, t1, undefined, { + fetchPoolsTimeout: 3000, + }) const pools = dataFetcher.getCurrentPoolCodeMap(t0, t1) const time = Math.round(performance.now() - start) console.log( @@ -27,31 +29,10 @@ async function testDF( }) } -const chainIds = [ - ChainId.ARBITRUM_NOVA, - ChainId.ARBITRUM, - ChainId.AVALANCHE, - ChainId.BOBA, - ChainId.BOBA_AVAX, - ChainId.BOBA_BNB, - ChainId.BSC, - ChainId.BTTC, - ChainId.CELO, - ChainId.ETHEREUM, - ChainId.FANTOM, - ChainId.FUSE, - ChainId.GNOSIS, - ChainId.HARMONY, - ChainId.KAVA, - ChainId.METIS, - ChainId.MOONBEAM, - ChainId.MOONRIVER, - ChainId.OPTIMISM, - ChainId.POLYGON, -] +const chainIds = Object.values(ChainId) async function runTest() { - describe('DataFetcher Pools/Time check', async () => { + describe.only('DataFetcher Pools/Time check', async () => { chainIds.forEach((chainId) => { //if (chainId !== ChainId.OPTIMISM) return const chName = chainName[chainId] @@ -85,6 +66,14 @@ async function runTest() { 'SUSHI', 'USDT', ) + await testDF( + chName, + dataFetcher, + WNATIVE[chainId], + USDT[chainId as keyof typeof USDT], + 'WNATIVE', + 'USDT', + ) dataFetcher.stopDataFetching() }) })