From 083082f30267209155834ba834def369f30550d0 Mon Sep 17 00:00:00 2001 From: Sara Reynolds <30504811+snreynolds@users.noreply.github.com> Date: Wed, 22 Dec 2021 12:09:19 -0800 Subject: [PATCH] polygon support checkpoint (#45) * polygon support checkpoint * cleanup logs and add polygon mumbai command to readme * fix: require weth * cleanup and include subgraph * add tokens to bases * updating token addresses * some refactors * fix dependency and clean weth9 * weth to native --- README.md | 10 + cli/commands/quote-to-ratio.ts | 1 + cli/commands/quote.ts | 19 +- src/providers/caching-token-provider.ts | 4 +- src/providers/on-chain-gas-price-provider.ts | 1 + src/providers/token-provider.ts | 84 ++++++++- src/providers/v2/static-subgraph-provider.ts | 20 +- src/providers/v3/static-subgraph-provider.ts | 33 ++-- src/providers/v3/subgraph-provider.ts | 2 + .../functions/get-candidate-pools.ts | 40 ++-- .../alpha-router/gas-models/gas-model.ts | 4 + .../gas-models/v2/v2-heuristic-gas-model.ts | 22 ++- .../gas-models/v3/v3-heuristic-gas-model.ts | 100 +++++----- src/routers/legacy-router/bases.ts | 31 ++-- src/util/addresses.ts | 7 +- src/util/chains.ts | 171 ++++++++++++++++++ .../routers/alpha-router/alpha-router.test.ts | 160 ++++++++++------ .../functions/best-swap-route.test.ts | 50 +++-- .../functions/get-candidate-pools.test.ts | 22 +-- test/unit/test-util/mock-data.ts | 16 +- 20 files changed, 595 insertions(+), 202 deletions(-) diff --git a/README.md b/README.md index ee94447ad..73a3dcc83 100644 --- a/README.md +++ b/README.md @@ -123,3 +123,13 @@ Calldata: 0x414bf389000000000000000000000000dac17f958d2ee523a2206206994597c13d83 ``` ./bin/cli quote --tokenIn 0x09b98f8b2395d076514037ff7d39a091a536206c --tokenOut 0xb47e6a5f8b33b3f17603c83a0535a9dcd7e32681 --amount 200 --exactIn --minSplits 1 --router alpha --chainId 421611 ``` + +## Polygon Mumbai + +``` +./bin/cli quote --tokenIn 0x001b3b4d0f3714ca98ba10f6042daebf0b1b7b6f --tokenOut 0x9c3c9283d3e44854697cd22d3faa240cfb032889 --amount 1 --exactIn --protocols v3 --recipient 0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B --minSplits 1 --router alpha --chainId 80001 +``` + +# Polygon Mainnet + +./bin/cli quote --tokenIn 0x2791bca1f2de4661ed88a30c99a7a9449aa84174 --tokenOut 0x7ceb23fd6bc0add59e62ac25578270cff1b9f619 --amount 5 --exactIn --minSplits 1 --protocols v3 --router alpha --chainId 137 diff --git a/cli/commands/quote-to-ratio.ts b/cli/commands/quote-to-ratio.ts index 97c4edb36..ada86b81e 100644 --- a/cli/commands/quote-to-ratio.ts +++ b/cli/commands/quote-to-ratio.ts @@ -65,6 +65,7 @@ export class QuoteToRatio extends BaseCommand { const tokenAccessor = await tokenProvider.getTokens([token0Str, token1Str]); const chainId = ID_TO_CHAIN_ID(chainIdNumb); + // TODO add support for polygon const token0: Currency = token0Str == 'ETH' ? Ether.onChain(chainId) diff --git a/cli/commands/quote.ts b/cli/commands/quote.ts index f95ce5482..ba92aa15d 100644 --- a/cli/commands/quote.ts +++ b/cli/commands/quote.ts @@ -1,10 +1,16 @@ import { flags } from '@oclif/command'; import { Protocol } from '@uniswap/router-sdk'; -import { Currency, Ether, Percent, TradeType } from '@uniswap/sdk-core'; +import { Currency, Percent, TradeType } from '@uniswap/sdk-core'; import dotenv from 'dotenv'; import { ethers } from 'ethers'; import _ from 'lodash'; -import { ID_TO_CHAIN_ID, parseAmount, SwapRoute } from '../../src'; +import { + ID_TO_CHAIN_ID, + NativeCurrencyName, + nativeOnChain, + parseAmount, + SwapRoute, +} from '../../src'; import { TO_PROTOCOL } from '../../src/util/protocols'; import { BaseCommand } from '../base-command'; @@ -84,13 +90,14 @@ export class Quote extends BaseCommand { tokenOutStr, ]); + // if the tokenIn str is 'ETH' or 'MATIC' or NATIVE_CURRENCY_STRING const tokenIn: Currency = - tokenInStr == 'ETH' - ? Ether.onChain(chainId) + tokenInStr in NativeCurrencyName + ? nativeOnChain(chainId) : tokenAccessor.getTokenByAddress(tokenInStr)!; const tokenOut: Currency = - tokenOutStr == 'ETH' - ? Ether.onChain(chainId) + tokenOutStr in NativeCurrencyName + ? nativeOnChain(chainId) : tokenAccessor.getTokenByAddress(tokenOutStr)!; let swapRoutes: SwapRoute | null; diff --git a/src/providers/caching-token-provider.ts b/src/providers/caching-token-provider.ts index 926baee3b..7b836df6e 100644 --- a/src/providers/caching-token-provider.ts +++ b/src/providers/caching-token-provider.ts @@ -2,7 +2,7 @@ import { Token } from '@uniswap/sdk-core'; import _ from 'lodash'; import { ChainId, log } from '../util'; import { ICache } from './cache'; -import { ITokenProvider, TokenAccessor, TOKENS } from './token-provider'; +import { ITokenProvider, SEED_TOKENS, TokenAccessor } from './token-provider'; /** * Provider for getting token metadata that falls back to a different provider @@ -25,7 +25,7 @@ export class CachingTokenProviderWithFallback implements ITokenProvider { ) {} public async getTokens(_addresses: string[]): Promise { - const seedTokens = TOKENS[this.chainId]; + const seedTokens = SEED_TOKENS[this.chainId]; if (seedTokens) { for (const token of Object.values(seedTokens)) { diff --git a/src/providers/on-chain-gas-price-provider.ts b/src/providers/on-chain-gas-price-provider.ts index ce84bd20a..e53c44f28 100644 --- a/src/providers/on-chain-gas-price-provider.ts +++ b/src/providers/on-chain-gas-price-provider.ts @@ -8,6 +8,7 @@ const DEFAULT_EIP_1559_SUPPORTED_CHAINS = [ ChainId.RINKEBY, ChainId.ROPSTEN, ChainId.GÖRLI, + ChainId.POLYGON_MUMBAI, // infura endpoint having difficulty w/ eip-1559 on kovan // ChainId.KOVAN, ]; diff --git a/src/providers/token-provider.ts b/src/providers/token-provider.ts index a4240ba54..7cdee80bc 100644 --- a/src/providers/token-provider.ts +++ b/src/providers/token-provider.ts @@ -1,7 +1,7 @@ -import { Token, WETH9 } from '@uniswap/sdk-core'; +import { Token } from '@uniswap/sdk-core'; import _ from 'lodash'; import { IERC20Metadata__factory } from '../types/v3'; -import { ChainId, log } from '../util'; +import { ChainId, log, WRAPPED_NATIVE_CURRENCY } from '../util'; import { IMulticallProvider } from './multicall-provider'; import { ProviderConfig } from './provider'; @@ -305,18 +305,84 @@ export const UNI_ARBITRUM_RINKEBY = new Token( 'Uni token' ); -export const TOKENS: { +//polygon tokens +export const WMATIC_POLYGON = new Token( + ChainId.POLYGON, + '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270', + 18, + 'WMATIC', + 'Wrapped MATIC' +); + +export const WETH_POLYGON = new Token( + ChainId.POLYGON, + '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619', + 18, + 'WETH', + 'Wrapped Ether' +); + +export const USDC_POLYGON = new Token( + ChainId.POLYGON, + '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', + 6, + 'USDC', + 'USD//C' +); + +export const DAI_POLYGON = new Token( + ChainId.POLYGON, + '0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063', + 18, + 'DAI', + 'Dai Stablecoin' +); + +//polygon mumbai tokens +export const WMATIC_POLYGON_MUMBAI = new Token( + ChainId.POLYGON_MUMBAI, + '0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889', + 18, + 'WMATIC', + 'Wrapped MATIC' +); + +export const USDC_POLYGON_MUMBAI = new Token( + ChainId.POLYGON_MUMBAI, + '0xe11a86849d99f524cac3e7a0ec1241828e332c62', + 6, + 'USDC', + 'USD//C' +); + +export const DAI_POLYGON_MUMBAI = new Token( + ChainId.POLYGON_MUMBAI, + '0x001b3b4d0f3714ca98ba10f6042daebf0b1b7b6f', + 18, + 'DAI', + 'Dai Stablecoin' +); + +export const WETH_POLYGON_MUMBAI = new Token( + ChainId.POLYGON_MUMBAI, + '0xa6fa4fb5f76172d178d61b04b0ecd319c5d1c0aa', + 18, + 'WETH', + 'Wrapped Ether' +); + +export const SEED_TOKENS: { [chainId in ChainId]?: { [symbol: string]: Token }; } = { [ChainId.MAINNET]: { - WETH: WETH9[ChainId.MAINNET]!, + WETH: WRAPPED_NATIVE_CURRENCY[ChainId.MAINNET]!, USDC: USDC_MAINNET, USDT: USDT_MAINNET, WBTC: WBTC_MAINNET, DAI: DAI_MAINNET, }, [ChainId.RINKEBY]: { - WETH: WETH9[ChainId.RINKEBY]!, + WETH: WRAPPED_NATIVE_CURRENCY[ChainId.RINKEBY]!, DAI_1: DAI_RINKEBY_1, DAI_2: DAI_RINKEBY_2, }, @@ -344,6 +410,14 @@ export const TOKENS: { DAI: DAI_ARBITRUM_RINKEBY, USDC: USDC_ARBITRUM_RINKEBY, }, + [ChainId.POLYGON]: { + WMATIC: WMATIC_POLYGON, + USDC: USDC_POLYGON, + }, + [ChainId.POLYGON_MUMBAI]: { + WMATIC: WMATIC_POLYGON_MUMBAI, + DAI: DAI_POLYGON_MUMBAI, + }, }; export class TokenProvider implements ITokenProvider { diff --git a/src/providers/v2/static-subgraph-provider.ts b/src/providers/v2/static-subgraph-provider.ts index ddee73253..53637651c 100644 --- a/src/providers/v2/static-subgraph-provider.ts +++ b/src/providers/v2/static-subgraph-provider.ts @@ -1,7 +1,7 @@ -import { Token, WETH9 } from '@uniswap/sdk-core'; +import { Token } from '@uniswap/sdk-core'; import { Pair } from '@uniswap/v2-sdk'; import _ from 'lodash'; -import { ChainId } from '../../util/chains'; +import { ChainId, WRAPPED_NATIVE_CURRENCY } from '../../util/chains'; import { log } from '../../util/log'; import { DAI_MAINNET, @@ -19,21 +19,27 @@ type ChainTokenList = { const BASES_TO_CHECK_TRADES_AGAINST: ChainTokenList = { [ChainId.MAINNET]: [ - WETH9[ChainId.MAINNET]!, + WRAPPED_NATIVE_CURRENCY[ChainId.MAINNET]!, DAI_MAINNET, USDC_MAINNET, USDT_MAINNET, WBTC_MAINNET, ], - [ChainId.ROPSTEN]: [WETH9[ChainId.ROPSTEN]!], - [ChainId.RINKEBY]: [WETH9[ChainId.RINKEBY]!, DAI_RINKEBY_1, DAI_RINKEBY_2], - [ChainId.GÖRLI]: [WETH9[ChainId.GÖRLI]!], - [ChainId.KOVAN]: [WETH9[ChainId.KOVAN]!], + [ChainId.ROPSTEN]: [WRAPPED_NATIVE_CURRENCY[ChainId.ROPSTEN]!], + [ChainId.RINKEBY]: [ + WRAPPED_NATIVE_CURRENCY[ChainId.RINKEBY]!, + DAI_RINKEBY_1, + DAI_RINKEBY_2, + ], + [ChainId.GÖRLI]: [WRAPPED_NATIVE_CURRENCY[ChainId.GÖRLI]!], + [ChainId.KOVAN]: [WRAPPED_NATIVE_CURRENCY[ChainId.KOVAN]!], //v2 not deployed on optimism/arbitrum or their testnets [ChainId.OPTIMISM]: [], [ChainId.ARBITRUM_ONE]: [], [ChainId.ARBITRUM_RINKEBY]: [], [ChainId.OPTIMISTIC_KOVAN]: [], + [ChainId.POLYGON]: [], + [ChainId.POLYGON_MUMBAI]: [], }; /** diff --git a/src/providers/v3/static-subgraph-provider.ts b/src/providers/v3/static-subgraph-provider.ts index 8e52e9c0d..2b4a50aa5 100644 --- a/src/providers/v3/static-subgraph-provider.ts +++ b/src/providers/v3/static-subgraph-provider.ts @@ -1,9 +1,9 @@ -import { Token, WETH9 } from '@uniswap/sdk-core'; +import { Token } from '@uniswap/sdk-core'; import { FeeAmount, Pool } from '@uniswap/v3-sdk'; import JSBI from 'jsbi'; import _ from 'lodash'; import { unparseFeeAmount } from '../../util/amounts'; -import { ChainId } from '../../util/chains'; +import { ChainId, WRAPPED_NATIVE_CURRENCY } from '../../util/chains'; import { log } from '../../util/log'; import { DAI_ARBITRUM, @@ -13,6 +13,7 @@ import { DAI_MAINNET, DAI_OPTIMISM, DAI_OPTIMISTIC_KOVAN, + DAI_POLYGON_MUMBAI, DAI_RINKEBY_1, DAI_RINKEBY_2, DAI_ROPSTEN, @@ -23,6 +24,7 @@ import { USDC_MAINNET, USDC_OPTIMISM, USDC_OPTIMISTIC_KOVAN, + USDC_POLYGON, USDC_RINKEBY, USDC_ROPSTEN, USDT_ARBITRUM, @@ -40,6 +42,9 @@ import { WBTC_MAINNET, WBTC_OPTIMISM, WBTC_OPTIMISTIC_KOVAN, + WETH_POLYGON, + WMATIC_POLYGON, + WMATIC_POLYGON_MUMBAI, } from '../token-provider'; import { IV3PoolProvider } from './pool-provider'; import { IV3SubgraphProvider, V3SubgraphPool } from './subgraph-provider'; @@ -50,66 +55,72 @@ type ChainTokenList = { const BASES_TO_CHECK_TRADES_AGAINST: ChainTokenList = { [ChainId.MAINNET]: [ - WETH9[ChainId.MAINNET]!, + WRAPPED_NATIVE_CURRENCY[ChainId.MAINNET]!, DAI_MAINNET, USDC_MAINNET, USDT_MAINNET, WBTC_MAINNET, ], [ChainId.ROPSTEN]: [ - WETH9[ChainId.ROPSTEN]!, + WRAPPED_NATIVE_CURRENCY[ChainId.ROPSTEN]!, DAI_ROPSTEN, USDT_ROPSTEN, USDC_ROPSTEN, ], [ChainId.RINKEBY]: [ - WETH9[ChainId.RINKEBY]!, + WRAPPED_NATIVE_CURRENCY[ChainId.RINKEBY]!, DAI_RINKEBY_1, DAI_RINKEBY_2, USDC_RINKEBY, USDT_RINKEBY, ], [ChainId.GÖRLI]: [ - WETH9[ChainId.GÖRLI]!, + WRAPPED_NATIVE_CURRENCY[ChainId.GÖRLI]!, USDT_GÖRLI, USDC_GÖRLI, WBTC_GÖRLI, DAI_GÖRLI, ], [ChainId.KOVAN]: [ - WETH9[ChainId.KOVAN]!, + WRAPPED_NATIVE_CURRENCY[ChainId.KOVAN]!, USDC_KOVAN, USDT_KOVAN, WBTC_KOVAN, DAI_KOVAN, ], [ChainId.OPTIMISM]: [ - WETH9[ChainId.OPTIMISM]!, + WRAPPED_NATIVE_CURRENCY[ChainId.OPTIMISM]!, USDC_OPTIMISM, DAI_OPTIMISM, USDT_OPTIMISM, WBTC_OPTIMISM, ], [ChainId.ARBITRUM_ONE]: [ - WETH9[ChainId.ARBITRUM_ONE]!, + WRAPPED_NATIVE_CURRENCY[ChainId.ARBITRUM_ONE]!, WBTC_ARBITRUM, DAI_ARBITRUM, USDC_ARBITRUM, USDT_ARBITRUM, ], [ChainId.ARBITRUM_RINKEBY]: [ - WETH9[ChainId.ARBITRUM_RINKEBY]!, + WRAPPED_NATIVE_CURRENCY[ChainId.ARBITRUM_RINKEBY]!, DAI_ARBITRUM_RINKEBY, UNI_ARBITRUM_RINKEBY, USDT_ARBITRUM_RINKEBY, ], [ChainId.OPTIMISTIC_KOVAN]: [ - WETH9[ChainId.OPTIMISTIC_KOVAN]!, + WRAPPED_NATIVE_CURRENCY[ChainId.OPTIMISTIC_KOVAN]!, DAI_OPTIMISTIC_KOVAN, WBTC_OPTIMISTIC_KOVAN, USDT_OPTIMISTIC_KOVAN, USDC_OPTIMISTIC_KOVAN, ], + [ChainId.POLYGON]: [USDC_POLYGON, WETH_POLYGON, WMATIC_POLYGON], + [ChainId.POLYGON_MUMBAI]: [ + DAI_POLYGON_MUMBAI, + WRAPPED_NATIVE_CURRENCY[ChainId.POLYGON_MUMBAI]!, + WMATIC_POLYGON_MUMBAI, + ], }; /** diff --git a/src/providers/v3/subgraph-provider.ts b/src/providers/v3/subgraph-provider.ts index eb09c8aa2..6c248e9d0 100644 --- a/src/providers/v3/subgraph-provider.ts +++ b/src/providers/v3/subgraph-provider.ts @@ -53,6 +53,8 @@ const SUBGRAPH_URL_BY_CHAIN: { [chainId in ChainId]?: string } = { 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-optmism-regen', [ChainId.ARBITRUM_ONE]: 'https://api.thegraph.com/subgraphs/name/ianlapham/arbitrum-minimal', + [ChainId.POLYGON]: + 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v3-polygon', }; const PAGE_SIZE = 1000; // 1k is max possible query size from subgraph. diff --git a/src/routers/alpha-router/functions/get-candidate-pools.ts b/src/routers/alpha-router/functions/get-candidate-pools.ts index 2b6c15ee4..90bcd7477 100644 --- a/src/routers/alpha-router/functions/get-candidate-pools.ts +++ b/src/routers/alpha-router/functions/get-candidate-pools.ts @@ -1,5 +1,5 @@ import { Protocol } from '@uniswap/router-sdk'; -import { Token, TradeType, WETH9 } from '@uniswap/sdk-core'; +import { Token, TradeType } from '@uniswap/sdk-core'; import { FeeAmount } from '@uniswap/v3-sdk'; import _ from 'lodash'; import { @@ -13,6 +13,7 @@ import { DAI_MAINNET, DAI_OPTIMISM, DAI_OPTIMISTIC_KOVAN, + DAI_POLYGON_MUMBAI, DAI_RINKEBY_1, DAI_RINKEBY_2, FEI_MAINNET, @@ -21,6 +22,7 @@ import { USDC_MAINNET, USDC_OPTIMISM, USDC_OPTIMISTIC_KOVAN, + USDC_POLYGON, USDT_ARBITRUM, USDT_ARBITRUM_RINKEBY, USDT_MAINNET, @@ -30,6 +32,8 @@ import { WBTC_MAINNET, WBTC_OPTIMISM, WBTC_OPTIMISTIC_KOVAN, + WMATIC_POLYGON, + WMATIC_POLYGON_MUMBAI, } from '../../../providers/token-provider'; import { IV2PoolProvider, @@ -43,7 +47,7 @@ import { IV3SubgraphProvider, V3SubgraphPool, } from '../../../providers/v3/subgraph-provider'; -import { ChainId } from '../../../util'; +import { ChainId, WRAPPED_NATIVE_CURRENCY } from '../../../util'; import { parseFeeAmount, unparseFeeAmount } from '../../../util/amounts'; import { log } from '../../../util/log'; import { metric, MetricLoggerUnit } from '../../../util/metric'; @@ -95,7 +99,7 @@ const baseTokensByChain: { [chainId in ChainId]?: Token[] } = { USDT_MAINNET, WBTC_MAINNET, DAI_MAINNET, - WETH9[1]!, + WRAPPED_NATIVE_CURRENCY[1]!, FEI_MAINNET, ], [ChainId.RINKEBY]: [DAI_RINKEBY_1, DAI_RINKEBY_2], @@ -118,6 +122,8 @@ const baseTokensByChain: { [chainId in ChainId]?: Token[] } = { USDT_ARBITRUM, ], [ChainId.ARBITRUM_RINKEBY]: [DAI_ARBITRUM_RINKEBY, USDT_ARBITRUM_RINKEBY], + [ChainId.POLYGON]: [USDC_POLYGON, WMATIC_POLYGON], + [ChainId.POLYGON_MUMBAI]: [DAI_POLYGON_MUMBAI, WMATIC_POLYGON_MUMBAI], }; export async function getV3CandidatePools({ @@ -298,31 +304,36 @@ export async function getV3CandidatePools({ addToAddressSet(top2DirectSwapPool); - const wethAddress = WETH9[chainId]!.address; + const wrappedNativeAddress = WRAPPED_NATIVE_CURRENCY[chainId]?.address; - // Main reason we need this is for gas estimates, only needed if token out is not ETH. - // We don't check the seen address set because if we've already added pools for getting ETH quotes + // Main reason we need this is for gas estimates, only needed if token out is not native. + // We don't check the seen address set because if we've already added pools for getting native quotes // theres no need to add more. let top2EthQuoteTokenPool: V3SubgraphPool[] = []; if ( - tokenOut.symbol != 'WETH' && - tokenOut.symbol != 'WETH9' && - tokenOut.symbol != 'ETH' + (WRAPPED_NATIVE_CURRENCY[chainId]?.symbol == + WRAPPED_NATIVE_CURRENCY[ChainId.MAINNET]?.symbol && + tokenOut.symbol != 'WETH' && + tokenOut.symbol != 'WETH9' && + tokenOut.symbol != 'ETH') || + (WRAPPED_NATIVE_CURRENCY[chainId]?.symbol == WMATIC_POLYGON.symbol && + tokenOut.symbol != 'MATIC' && + tokenOut.symbol != 'WMATIC') ) { top2EthQuoteTokenPool = _(subgraphPoolsSorted) .filter((subgraphPool) => { if (routeType == TradeType.EXACT_INPUT) { return ( - (subgraphPool.token0.id == wethAddress && + (subgraphPool.token0.id == wrappedNativeAddress && subgraphPool.token1.id == tokenOutAddress) || - (subgraphPool.token1.id == wethAddress && + (subgraphPool.token1.id == wrappedNativeAddress && subgraphPool.token0.id == tokenOutAddress) ); } else { return ( - (subgraphPool.token0.id == wethAddress && + (subgraphPool.token0.id == wrappedNativeAddress && subgraphPool.token1.id == tokenInAddress) || - (subgraphPool.token1.id == wethAddress && + (subgraphPool.token1.id == wrappedNativeAddress && subgraphPool.token0.id == tokenInAddress) ); } @@ -686,11 +697,12 @@ export async function getV2CandidatePools({ addToAddressSet(topByDirectSwapPool); - const wethAddress = WETH9[chainId]!.address; + const wethAddress = WRAPPED_NATIVE_CURRENCY[chainId]!.address; // Main reason we need this is for gas estimates, only needed if token out is not ETH. // We don't check the seen address set because if we've already added pools for getting ETH quotes // theres no need to add more. + // Note: we do not need to check other native currencies for the V2 Protocol let topByEthQuoteTokenPool: V2SubgraphPool[] = []; if ( tokenOut.symbol != 'WETH' && diff --git a/src/routers/alpha-router/gas-models/gas-model.ts b/src/routers/alpha-router/gas-models/gas-model.ts index 70c5ff52f..93a4e8839 100644 --- a/src/routers/alpha-router/gas-models/gas-model.ts +++ b/src/routers/alpha-router/gas-models/gas-model.ts @@ -8,6 +8,7 @@ import { DAI_MAINNET, DAI_OPTIMISM, DAI_OPTIMISTIC_KOVAN, + DAI_POLYGON_MUMBAI, DAI_RINKEBY_1, DAI_RINKEBY_2, DAI_ROPSTEN, @@ -17,6 +18,7 @@ import { USDC_MAINNET, USDC_OPTIMISM, USDC_OPTIMISTIC_KOVAN, + USDC_POLYGON, USDC_ROPSTEN, USDT_ARBITRUM, USDT_ARBITRUM_RINKEBY, @@ -52,6 +54,8 @@ export const usdGasTokensByChain: { [chainId in ChainId]?: Token[] } = { [ChainId.KOVAN]: [DAI_KOVAN, USDC_KOVAN, USDT_KOVAN], [ChainId.GÖRLI]: [USDC_GÖRLI, USDT_GÖRLI, WBTC_GÖRLI, DAI_GÖRLI], [ChainId.ROPSTEN]: [DAI_ROPSTEN, USDC_ROPSTEN, USDT_ROPSTEN], + [ChainId.POLYGON]: [USDC_POLYGON], + [ChainId.POLYGON_MUMBAI]: [DAI_POLYGON_MUMBAI], }; /** diff --git a/src/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.ts b/src/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.ts index 5f7b5d1d5..8aabe0575 100644 --- a/src/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.ts +++ b/src/routers/alpha-router/gas-models/v2/v2-heuristic-gas-model.ts @@ -3,7 +3,7 @@ import { Token } from '@uniswap/sdk-core'; import { Pair } from '@uniswap/v2-sdk'; import _ from 'lodash'; import { IV2PoolProvider } from '../../../../providers/v2/pool-provider'; -import { ChainId, log, WETH9 } from '../../../../util'; +import { ChainId, log, WRAPPED_NATIVE_CURRENCY } from '../../../../util'; import { CurrencyAmount } from '../../../../util/amounts'; import { V2RouteWithValidQuote } from '../../entities/route-with-valid-quote'; import { @@ -46,7 +46,7 @@ export class V2HeuristicGasModelFactory extends IV2GasModelFactory { poolProvider: IV2PoolProvider, token: Token ): Promise> { - if (token.equals(WETH9[chainId]!)) { + if (token.equals(WRAPPED_NATIVE_CURRENCY[chainId]!)) { const usdPool: Pair = await this.getHighestLiquidityUSDPool( chainId, poolProvider @@ -60,7 +60,8 @@ export class V2HeuristicGasModelFactory extends IV2GasModelFactory { chainId ); - const ethToken0 = usdPool.token0.address == WETH9[chainId]!.address; + const ethToken0 = + usdPool.token0.address == WRAPPED_NATIVE_CURRENCY[chainId]!.address; const ethTokenPrice = ethToken0 ? usdPool.token0Price @@ -95,7 +96,7 @@ export class V2HeuristicGasModelFactory extends IV2GasModelFactory { return { estimateGasCost: (routeWithValidQuote: V2RouteWithValidQuote) => { const usdToken = - usdPool.token0.address == WETH9[chainId]!.address + usdPool.token0.address == WRAPPED_NATIVE_CURRENCY[chainId]!.address ? usdPool.token1 : usdPool.token0; @@ -116,7 +117,8 @@ export class V2HeuristicGasModelFactory extends IV2GasModelFactory { }; } - const ethToken0 = ethPool.token0.address == WETH9[chainId]!.address; + const ethToken0 = + ethPool.token0.address == WRAPPED_NATIVE_CURRENCY[chainId]!.address; const ethTokenPrice = ethToken0 ? ethPool.token0Price @@ -140,7 +142,7 @@ export class V2HeuristicGasModelFactory extends IV2GasModelFactory { } const ethToken0USDPool = - usdPool.token0.address == WETH9[chainId]!.address; + usdPool.token0.address == WRAPPED_NATIVE_CURRENCY[chainId]!.address; const ethTokenPriceUSDPool = ethToken0USDPool ? usdPool.token0Price @@ -182,7 +184,7 @@ export class V2HeuristicGasModelFactory extends IV2GasModelFactory { const totalGasCostWei = gasPriceWei.mul(gasUse); - const weth = WETH9[chainId]!; + const weth = WRAPPED_NATIVE_CURRENCY[chainId]!; const gasCostInEth = CurrencyAmount.fromRawAmount( weth, @@ -197,7 +199,7 @@ export class V2HeuristicGasModelFactory extends IV2GasModelFactory { token: Token, poolProvider: IV2PoolProvider ): Promise { - const weth = WETH9[chainId]!; + const weth = WRAPPED_NATIVE_CURRENCY[chainId]!; const poolAccessor = await poolProvider.getPools([[weth, token]]); const pool = poolAccessor.getPool(weth, token); @@ -228,7 +230,7 @@ export class V2HeuristicGasModelFactory extends IV2GasModelFactory { const usdPools = _.map(usdTokens, (usdToken) => [ usdToken, - WETH9[chainId]!, + WRAPPED_NATIVE_CURRENCY[chainId]!, ]); const poolAccessor = await poolProvider.getPools(usdPools); const pools = poolAccessor.getAllPools(); @@ -242,7 +244,7 @@ export class V2HeuristicGasModelFactory extends IV2GasModelFactory { } const maxPool = _.maxBy(pools, (pool) => { - if (pool.token0.equals(WETH9[chainId]!)) { + if (pool.token0.equals(WRAPPED_NATIVE_CURRENCY[chainId]!)) { return parseFloat(pool.reserve0.toSignificant(2)); } else { return parseFloat(pool.reserve1.toSignificant(2)); diff --git a/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts b/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts index 524890bfc..ffedbb99e 100644 --- a/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts +++ b/src/routers/alpha-router/gas-models/v3/v3-heuristic-gas-model.ts @@ -2,8 +2,9 @@ import { BigNumber } from '@ethersproject/bignumber'; import { Token } from '@uniswap/sdk-core'; import { FeeAmount, Pool } from '@uniswap/v3-sdk'; import _ from 'lodash'; +import { WRAPPED_NATIVE_CURRENCY } from '../../../..'; import { IV3PoolProvider } from '../../../../providers/v3/pool-provider'; -import { ChainId, WETH9 } from '../../../../util'; +import { ChainId } from '../../../../util'; import { CurrencyAmount } from '../../../../util/amounts'; import { log } from '../../../../util/log'; import { V3RouteWithValidQuote } from '../../entities/route-with-valid-quote'; @@ -53,11 +54,14 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { gasPriceWei: BigNumber, poolProvider: IV3PoolProvider, token: Token + // this is the quoteToken ): Promise> { // If our quote token is WETH, we don't need to convert our gas use to be in terms // of the quote token in order to produce a gas adjusted amount. // We do return a gas use in USD however, so we still convert to usd. - if (token.equals(WETH9[chainId]!)) { + + const nativeCurrency = WRAPPED_NATIVE_CURRENCY[chainId]!; + if (token.equals(nativeCurrency)) { const usdPool: Pool = await this.getHighestLiquidityUSDPool( chainId, poolProvider @@ -70,25 +74,25 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { gasCostInToken: CurrencyAmount; gasCostInUSD: CurrencyAmount; } => { - const { gasCostInEth, gasUse } = this.estimateGas( + const { gasCostNativeCurrency, gasUse } = this.estimateGas( routeWithValidQuote, gasPriceWei, chainId ); - const ethToken0 = usdPool.token0.address == WETH9[chainId]!.address; + const token0 = usdPool.token0.address == nativeCurrency.address; - const ethTokenPrice = ethToken0 + const nativeTokenPrice = token0 ? usdPool.token0Price : usdPool.token1Price; - const gasCostInTermsOfUSD: CurrencyAmount = ethTokenPrice.quote( - gasCostInEth + const gasCostInTermsOfUSD: CurrencyAmount = nativeTokenPrice.quote( + gasCostNativeCurrency ) as CurrencyAmount; return { gasEstimate: gasUse, - gasCostInToken: gasCostInEth, + gasCostInToken: gasCostNativeCurrency, gasCostInUSD: gasCostInTermsOfUSD, }; }; @@ -98,9 +102,9 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { }; } - // If the quote token is not WETH, we convert the gas cost to be in terms of the quote token. - // We do this by getting the highest liquidity /ETH pool. - const ethPool: Pool | null = await this.getHighestLiquidityEthPool( + // If the quote token is not in the native currency, we convert the gas cost to be in terms of the quote token. + // We do this by getting the highest liquidity / pool. eg. /ETH pool. + const nativePool: Pool | null = await this.getHighestLiquidityNativePool( chainId, token, poolProvider @@ -112,7 +116,7 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { ); const usdToken = - usdPool.token0.address == WETH9[chainId]!.address + usdPool.token0.address == nativeCurrency.address ? usdPool.token1 : usdPool.token0; @@ -123,15 +127,15 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { gasCostInToken: CurrencyAmount; gasCostInUSD: CurrencyAmount; } => { - const { gasCostInEth, gasUse } = this.estimateGas( + const { gasCostNativeCurrency, gasUse } = this.estimateGas( routeWithValidQuote, gasPriceWei, chainId ); - if (!ethPool) { + if (!nativePool) { log.info( - 'Unable to find ETH pool with the quote token to produce gas adjusted costs. Route will not account for gas.' + `Unable to find ${nativeCurrency.symbol} pool with the quote token, ${token.symbol} to produce gas adjusted costs. Route will not account for gas.` ); return { gasEstimate: gasUse, @@ -140,47 +144,50 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { }; } - const ethToken0 = ethPool.token0.address == WETH9[chainId]!.address; + const token0 = nativePool.token0.address == nativeCurrency.address; - const ethTokenPrice = ethToken0 - ? ethPool.token0Price - : ethPool.token1Price; + // returns mid price in terms of the native currency (the ratio of quoteToken/nativeToken) + const nativeTokenPrice = token0 + ? nativePool.token0Price + : nativePool.token1Price; let gasCostInTermsOfQuoteToken: CurrencyAmount; try { - gasCostInTermsOfQuoteToken = ethTokenPrice.quote( - gasCostInEth + // native token is base currency + gasCostInTermsOfQuoteToken = nativeTokenPrice.quote( + gasCostNativeCurrency ) as CurrencyAmount; } catch (err) { log.info( { - ethTokenPriceBase: ethTokenPrice.baseCurrency, - ethTokenPriceQuote: ethTokenPrice.quoteCurrency, - gasCostInEth: gasCostInEth.currency, + nativeTokenPriceBase: nativeTokenPrice.baseCurrency, + nativeTokenPriceQuote: nativeTokenPrice.quoteCurrency, + gasCostInEth: gasCostNativeCurrency.currency, }, 'Debug eth price token issue' ); throw err; } - const ethToken0USDPool = - usdPool.token0.address == WETH9[chainId]!.address; + // true if token0 is the native currency + const token0USDPool = usdPool.token0.address == nativeCurrency.address; - const ethTokenPriceUSDPool = ethToken0USDPool + // gets the mid price of the pool in terms of the native token + const nativeTokenPriceUSDPool = token0USDPool ? usdPool.token0Price : usdPool.token1Price; let gasCostInTermsOfUSD: CurrencyAmount; try { - gasCostInTermsOfUSD = ethTokenPriceUSDPool.quote( - gasCostInEth + gasCostInTermsOfUSD = nativeTokenPriceUSDPool.quote( + gasCostNativeCurrency ) as CurrencyAmount; } catch (err) { log.info( { usdT1: usdPool.token0.symbol, usdT2: usdPool.token1.symbol, - gasCostInEthToken: gasCostInEth.currency.symbol, + gasCostInNativeToken: gasCostNativeCurrency.currency.symbol, }, 'Failed to compute USD gas price' ); @@ -220,34 +227,34 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { const totalGasCostWei = gasPriceWei.mul(gasUse); - const weth = WETH9[chainId]!; + const wrappedCurrency = WRAPPED_NATIVE_CURRENCY[chainId]!; - const gasCostInEth = CurrencyAmount.fromRawAmount( - weth, + const gasCostNativeCurrency = CurrencyAmount.fromRawAmount( + wrappedCurrency, totalGasCostWei.toString() ); - return { gasCostInEth, gasUse }; + return { gasCostNativeCurrency, gasUse }; } - private async getHighestLiquidityEthPool( + private async getHighestLiquidityNativePool( chainId: ChainId, token: Token, poolProvider: IV3PoolProvider ): Promise { - const weth = WETH9[chainId]!; + const nativeCurrency = WRAPPED_NATIVE_CURRENCY[chainId]!; - const ethPools = _([FeeAmount.HIGH, FeeAmount.MEDIUM, FeeAmount.LOW]) + const nativePools = _([FeeAmount.HIGH, FeeAmount.MEDIUM, FeeAmount.LOW]) .map<[Token, Token, FeeAmount]>((feeAmount) => { - return [weth, token, feeAmount]; + return [nativeCurrency, token, feeAmount]; }) .value(); - const poolAccessor = await poolProvider.getPools(ethPools); + const poolAccessor = await poolProvider.getPools(nativePools); const pools = _([FeeAmount.HIGH, FeeAmount.MEDIUM, FeeAmount.LOW]) .map((feeAmount) => { - return poolAccessor.getPool(weth, token, feeAmount); + return poolAccessor.getPool(nativeCurrency, token, feeAmount); }) .compact() .value(); @@ -255,7 +262,7 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { if (pools.length == 0) { log.error( { pools }, - `Could not find a WETH pool with ${token.symbol} for computing gas costs.` + `Could not find a ${nativeCurrency.symbol} pool with ${token.symbol} for computing gas costs.` ); return null; @@ -271,6 +278,7 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { poolProvider: IV3PoolProvider ): Promise { const usdTokens = usdGasTokensByChain[chainId]; + const wrappedCurrency = WRAPPED_NATIVE_CURRENCY[chainId]!; if (!usdTokens) { throw new Error( @@ -287,7 +295,7 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { .flatMap((feeAmount) => { return _.map( usdTokens, - (usdToken) => [WETH9[chainId]!, usdToken, feeAmount] + (usdToken) => [wrappedCurrency, usdToken, feeAmount] ); }) .value(); @@ -305,7 +313,7 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { for (const usdToken of usdTokens) { const pool = poolAccessor.getPool( - WETH9[chainId]!, + wrappedCurrency, usdToken, feeAmount ); @@ -322,9 +330,11 @@ export class V3HeuristicGasModelFactory extends IV3GasModelFactory { if (pools.length == 0) { log.error( { pools }, - `Could not find a USD/WETH pool for computing gas costs.` + `Could not find a USD/${wrappedCurrency.symbol} pool for computing gas costs.` + ); + throw new Error( + `Can't find USD/${wrappedCurrency.symbol} pool for computing gas costs.` ); - throw new Error(`Can't find USD/WETH pool for computing gas costs.`); } const maxPool = _.maxBy(pools, (pool) => pool.liquidity) as Pool; diff --git a/src/routers/legacy-router/bases.ts b/src/routers/legacy-router/bases.ts index 36482ca90..0454ee46d 100644 --- a/src/routers/legacy-router/bases.ts +++ b/src/routers/legacy-router/bases.ts @@ -5,9 +5,10 @@ import { USDC_MAINNET, USDT_MAINNET, WBTC_MAINNET, + WMATIC_POLYGON, + WMATIC_POLYGON_MUMBAI, } from '../../providers/token-provider'; -import { WETH9 } from '../../util/addresses'; -import { ChainId } from '../../util/chains'; +import { ChainId, WRAPPED_NATIVE_CURRENCY } from '../../util/chains'; type ChainTokenList = { readonly [chainId in ChainId]: Token[]; @@ -18,20 +19,26 @@ export const BASES_TO_CHECK_TRADES_AGAINST = ( ): ChainTokenList => { return { [ChainId.MAINNET]: [ - WETH9[ChainId.MAINNET], + WRAPPED_NATIVE_CURRENCY[ChainId.MAINNET]!, DAI_MAINNET, USDC_MAINNET, USDT_MAINNET, WBTC_MAINNET, ], - [ChainId.ROPSTEN]: [WETH9[ChainId.ROPSTEN]], - [ChainId.RINKEBY]: [WETH9[ChainId.RINKEBY]], - [ChainId.GÖRLI]: [WETH9[ChainId.GÖRLI]], - [ChainId.KOVAN]: [WETH9[ChainId.KOVAN]], - [ChainId.OPTIMISM]: [WETH9[ChainId.OPTIMISM]], - [ChainId.OPTIMISTIC_KOVAN]: [WETH9[ChainId.OPTIMISTIC_KOVAN]], - [ChainId.ARBITRUM_ONE]: [WETH9[ChainId.ARBITRUM_ONE]], - [ChainId.ARBITRUM_RINKEBY]: [WETH9[ChainId.ARBITRUM_RINKEBY]], + [ChainId.ROPSTEN]: [WRAPPED_NATIVE_CURRENCY[ChainId.ROPSTEN]!], + [ChainId.RINKEBY]: [WRAPPED_NATIVE_CURRENCY[ChainId.RINKEBY]!], + [ChainId.GÖRLI]: [WRAPPED_NATIVE_CURRENCY[ChainId.GÖRLI]!], + [ChainId.KOVAN]: [WRAPPED_NATIVE_CURRENCY[ChainId.KOVAN]!], + [ChainId.OPTIMISM]: [WRAPPED_NATIVE_CURRENCY[ChainId.OPTIMISM]!], + [ChainId.OPTIMISTIC_KOVAN]: [ + WRAPPED_NATIVE_CURRENCY[ChainId.OPTIMISTIC_KOVAN]!, + ], + [ChainId.ARBITRUM_ONE]: [WRAPPED_NATIVE_CURRENCY[ChainId.ARBITRUM_ONE]!], + [ChainId.ARBITRUM_RINKEBY]: [ + WRAPPED_NATIVE_CURRENCY[ChainId.ARBITRUM_RINKEBY]!, + ], + [ChainId.POLYGON]: [WMATIC_POLYGON], + [ChainId.POLYGON_MUMBAI]: [WMATIC_POLYGON_MUMBAI], }; }; @@ -135,7 +142,7 @@ export const CUSTOM_BASES = async ( tokenProvider, ChainId.MAINNET, '0xd46ba6d942050d489dbd938a2c909a5d5039a161', - WETH9[1].address + WRAPPED_NATIVE_CURRENCY[1]!.address )), }, }; diff --git a/src/util/addresses.ts b/src/util/addresses.ts index b34f8731e..9b05ff37a 100644 --- a/src/util/addresses.ts +++ b/src/util/addresses.ts @@ -14,7 +14,12 @@ export const UNISWAP_MULTICALL_ADDRESS = '0x1F98415757620B543A52E61c46B32eB19261F984'; export const MULTICALL2_ADDRESS = '0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696'; -export const WETH9: { [chainId in ChainId]: Token } = { +export const WETH9: { + [chainId in Exclude< + ChainId, + ChainId.POLYGON | ChainId.POLYGON_MUMBAI + >]: Token; +} = { [ChainId.MAINNET]: new Token( ChainId.MAINNET, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', diff --git a/src/util/chains.ts b/src/util/chains.ts index 8fefc081e..c5c28a5b8 100644 --- a/src/util/chains.ts +++ b/src/util/chains.ts @@ -1,3 +1,4 @@ +import { Currency, Ether, NativeCurrency, Token } from '@uniswap/sdk-core'; export enum ChainId { MAINNET = 1, ROPSTEN = 3, @@ -8,6 +9,8 @@ export enum ChainId { OPTIMISTIC_KOVAN = 69, ARBITRUM_ONE = 42161, ARBITRUM_RINKEBY = 421611, + POLYGON = 137, + POLYGON_MUMBAI = 80001, } export const ID_TO_CHAIN_ID = (id: number): ChainId => { @@ -30,6 +33,10 @@ export const ID_TO_CHAIN_ID = (id: number): ChainId => { return ChainId.ARBITRUM_ONE; case 421611: return ChainId.ARBITRUM_RINKEBY; + case 137: + return ChainId.POLYGON; + case 80001: + return ChainId.POLYGON_MUMBAI; default: throw new Error(`Unknown chain id: ${id}`); } @@ -46,8 +53,30 @@ export enum ChainName { OPTIMISTIC_KOVAN = 'optimism-kovan', ARBITRUM_ONE = 'arbitrum-mainnet', ARBITRUM_RINKEBY = 'arbitrum-rinkeby', + POLYGON = 'polygon-mainnet', + POLYGON_MUMBAI = 'polygon-mumbai', } +export enum NativeCurrencyName { + // Strings match input for CLI + ETHER = 'ETH', + MATIC = 'MATIC', +} + +export const NATIVE_CURRENCY: { [chainId: number]: NativeCurrencyName } = { + [ChainId.MAINNET]: NativeCurrencyName.ETHER, + [ChainId.ROPSTEN]: NativeCurrencyName.ETHER, + [ChainId.RINKEBY]: NativeCurrencyName.ETHER, + [ChainId.GÖRLI]: NativeCurrencyName.ETHER, + [ChainId.KOVAN]: NativeCurrencyName.ETHER, + [ChainId.OPTIMISM]: NativeCurrencyName.ETHER, + [ChainId.OPTIMISTIC_KOVAN]: NativeCurrencyName.ETHER, + [ChainId.ARBITRUM_ONE]: NativeCurrencyName.ETHER, + [ChainId.ARBITRUM_RINKEBY]: NativeCurrencyName.ETHER, + [ChainId.POLYGON]: NativeCurrencyName.MATIC, + [ChainId.POLYGON_MUMBAI]: NativeCurrencyName.MATIC, +}; + export const ID_TO_NETWORK_NAME = (id: number): ChainName => { switch (id) { case 1: @@ -68,6 +97,10 @@ export const ID_TO_NETWORK_NAME = (id: number): ChainName => { return ChainName.ARBITRUM_ONE; case 421611: return ChainName.ARBITRUM_RINKEBY; + case 137: + return ChainName.POLYGON; + case 80001: + return ChainName.POLYGON_MUMBAI; default: throw new Error(`Unknown chain id: ${id}`); } @@ -97,7 +130,145 @@ export const ID_TO_PROVIDER = (id: ChainId): string => { return process.env.JSON_RPC_PROVIDER_ARBITRUM_ONE!; case ChainId.ARBITRUM_RINKEBY: return process.env.JSON_RPC_PROVIDER_ARBITRUM_RINKEBY!; + case ChainId.POLYGON: + return process.env.JSON_RPC_PROVIDER_POLYGON!; + case ChainId.POLYGON_MUMBAI: + return process.env.JSON_RPC_PROVIDER_POLYGON_MUMBAI!; default: throw new Error(`Chain id: ${id} not supported`); } }; + +export const WRAPPED_NATIVE_CURRENCY: { [chainId in ChainId]: Token } = { + [ChainId.MAINNET]: new Token( + 1, + '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + 18, + 'WETH', + 'Wrapped Ether' + ), + [ChainId.ROPSTEN]: new Token( + 3, + '0xc778417E063141139Fce010982780140Aa0cD5Ab', + 18, + 'WETH', + 'Wrapped Ether' + ), + [ChainId.RINKEBY]: new Token( + 4, + '0xc778417E063141139Fce010982780140Aa0cD5Ab', + 18, + 'WETH', + 'Wrapped Ether' + ), + [ChainId.GÖRLI]: new Token( + 5, + '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6', + 18, + 'WETH', + 'Wrapped Ether' + ), + [ChainId.KOVAN]: new Token( + 42, + '0xd0A1E359811322d97991E03f863a0C30C2cF029C', + 18, + 'WETH', + 'Wrapped Ether' + ), + [ChainId.OPTIMISM]: new Token( + ChainId.OPTIMISM, + '0x4200000000000000000000000000000000000006', + 18, + 'WETH', + 'Wrapped Ether' + ), + [ChainId.OPTIMISTIC_KOVAN]: new Token( + ChainId.OPTIMISTIC_KOVAN, + '0x4200000000000000000000000000000000000006', + 18, + 'WETH', + 'Wrapped Ether' + ), + [ChainId.ARBITRUM_ONE]: new Token( + ChainId.ARBITRUM_ONE, + '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', + 18, + 'WETH', + 'Wrapped Ether' + ), + [ChainId.ARBITRUM_RINKEBY]: new Token( + ChainId.ARBITRUM_RINKEBY, + '0xB47e6A5f8b33b3F17603C83a0535A9dcD7E32681', + 18, + 'WETH', + 'Wrapped Ether' + ), + [ChainId.POLYGON]: new Token( + ChainId.POLYGON, + '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270', + 18, + 'WMATIC', + 'Wrapped MATIC' + ), + [ChainId.POLYGON_MUMBAI]: new Token( + ChainId.POLYGON_MUMBAI, + '0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889', + 18, + 'WMATIC', + 'Wrapped MATIC' + ), +}; + +function isMatic( + chainId: number +): chainId is ChainId.POLYGON | ChainId.POLYGON_MUMBAI { + return chainId === ChainId.POLYGON_MUMBAI || chainId === ChainId.POLYGON; +} + +class MaticNativeCurrency extends NativeCurrency { + equals(other: Currency): boolean { + return other.isNative && other.chainId === this.chainId; + } + + get wrapped(): Token { + if (!isMatic(this.chainId)) throw new Error('Not matic'); + const nativeCurrency = WRAPPED_NATIVE_CURRENCY[this.chainId]; + if (nativeCurrency) { + return nativeCurrency; + } + throw new Error(`Does not support this chain ${this.chainId}`); + } + + public constructor(chainId: number) { + if (!isMatic(chainId)) throw new Error('Not matic'); + super(chainId, 18, 'MATIC', 'Polygon Matic'); + } +} + +export class ExtendedEther extends Ether { + public get wrapped(): Token { + if (this.chainId in WRAPPED_NATIVE_CURRENCY) + return WRAPPED_NATIVE_CURRENCY[this.chainId as ChainId]; + throw new Error('Unsupported chain ID'); + } + + private static _cachedExtendedEther: { [chainId: number]: NativeCurrency } = + {}; + + public static onChain(chainId: number): ExtendedEther { + return ( + this._cachedExtendedEther[chainId] ?? + (this._cachedExtendedEther[chainId] = new ExtendedEther(chainId)) + ); + } +} + +const cachedNativeCurrency: { [chainId: number]: NativeCurrency } = {}; +export function nativeOnChain(chainId: number): NativeCurrency { + return ( + cachedNativeCurrency[chainId] ?? + (cachedNativeCurrency[chainId] = isMatic(chainId) + ? new MaticNativeCurrency(chainId) + : ExtendedEther.onChain(chainId)) + ); +} diff --git a/test/unit/routers/alpha-router/alpha-router.test.ts b/test/unit/routers/alpha-router/alpha-router.test.ts index aff7579b2..b980ac89c 100644 --- a/test/unit/routers/alpha-router/alpha-router.test.ts +++ b/test/unit/routers/alpha-router/alpha-router.test.ts @@ -38,7 +38,7 @@ import { V3RouteWithValidQuote, V3SubgraphPool, V3SubgraphProvider, - WETH9, + WRAPPED_NATIVE_CURRENCY, } from '../../../../src'; import { ProviderConfig } from '../../../../src/providers/provider'; import { V2PoolProvider } from '../../../../src/providers/v2/pool-provider'; @@ -144,7 +144,7 @@ describe('alpha router', () => { mockMulticallProvider = sinon.createStubInstance(UniswapMulticallProvider); mockTokenProvider = sinon.createStubInstance(TokenProvider); - const mockTokens = [USDC, DAI, WETH9[1], USDT]; + const mockTokens = [USDC, DAI, WRAPPED_NATIVE_CURRENCY[1], USDT]; mockTokenProvider.getTokens.resolves(buildMockTokenAccessor(mockTokens)); mockV3PoolProvider = sinon.createStubInstance(V3PoolProvider); @@ -400,7 +400,7 @@ describe('alpha router', () => { const swap = await alphaRouter.route( amount, - WETH9[1]!, + WRAPPED_NATIVE_CURRENCY[1], TradeType.EXACT_INPUT, undefined, { ...ROUTING_CONFIG } @@ -414,7 +414,7 @@ describe('alpha router', () => { 1, mockGasPriceWeiBN, sinon.match.any, - WETH9[1]! + WRAPPED_NATIVE_CURRENCY[1] ) ).toBeTruthy(); expect( @@ -422,7 +422,7 @@ describe('alpha router', () => { 1, mockGasPriceWeiBN, sinon.match.any, - WETH9[1]! + WRAPPED_NATIVE_CURRENCY[1] ) ).toBeTruthy(); @@ -444,15 +444,23 @@ describe('alpha router', () => { for (const r of swap!.route) { expect(r.route.input.equals(USDC)).toBeTruthy(); - expect(r.route.output.equals(WETH9[1]!.wrapped)).toBeTruthy(); + expect( + r.route.output.equals(WRAPPED_NATIVE_CURRENCY[1].wrapped) + ).toBeTruthy(); } - expect(swap!.quote.currency.equals(WETH9[1]!)).toBeTruthy(); - expect(swap!.quoteGasAdjusted.currency.equals(WETH9[1]!)).toBeTruthy(); + expect( + swap!.quote.currency.equals(WRAPPED_NATIVE_CURRENCY[1]) + ).toBeTruthy(); + expect( + swap!.quoteGasAdjusted.currency.equals(WRAPPED_NATIVE_CURRENCY[1]) + ).toBeTruthy(); expect(swap!.quote.greaterThan(swap!.quoteGasAdjusted)).toBeTruthy(); expect(swap!.estimatedGasUsed.toString()).toEqual('20000'); expect( - swap!.estimatedGasUsedQuoteToken.currency.equals(WETH9[1]!) + swap!.estimatedGasUsedQuoteToken.currency.equals( + WRAPPED_NATIVE_CURRENCY[1] + ) ).toBeTruthy(); expect( swap!.estimatedGasUsedUSD.currency.equals(USDC) || @@ -551,7 +559,7 @@ describe('alpha router', () => { const swap = await alphaRouter.route( amount, - WETH9[1]!, + WRAPPED_NATIVE_CURRENCY[1], TradeType.EXACT_INPUT, undefined, { ...ROUTING_CONFIG, protocols: [Protocol.V2, Protocol.V3] } @@ -565,7 +573,7 @@ describe('alpha router', () => { 1, mockGasPriceWeiBN, sinon.match.any, - WETH9[1]! + WRAPPED_NATIVE_CURRENCY[1] ) ).toBeTruthy(); expect( @@ -573,7 +581,7 @@ describe('alpha router', () => { 1, mockGasPriceWeiBN, sinon.match.any, - WETH9[1]! + WRAPPED_NATIVE_CURRENCY[1] ) ).toBeTruthy(); @@ -595,15 +603,23 @@ describe('alpha router', () => { for (const r of swap!.route) { expect(r.route.input.equals(USDC)).toBeTruthy(); - expect(r.route.output.equals(WETH9[1]!.wrapped)).toBeTruthy(); + expect( + r.route.output.equals(WRAPPED_NATIVE_CURRENCY[1].wrapped) + ).toBeTruthy(); } - expect(swap!.quote.currency.equals(WETH9[1]!)).toBeTruthy(); - expect(swap!.quoteGasAdjusted.currency.equals(WETH9[1]!)).toBeTruthy(); + expect( + swap!.quote.currency.equals(WRAPPED_NATIVE_CURRENCY[1]) + ).toBeTruthy(); + expect( + swap!.quoteGasAdjusted.currency.equals(WRAPPED_NATIVE_CURRENCY[1]) + ).toBeTruthy(); expect(swap!.quote.greaterThan(swap!.quoteGasAdjusted)).toBeTruthy(); expect(swap!.estimatedGasUsed.toString()).toEqual('20000'); expect( - swap!.estimatedGasUsedQuoteToken.currency.equals(WETH9[1]!) + swap!.estimatedGasUsedQuoteToken.currency.equals( + WRAPPED_NATIVE_CURRENCY[1] + ) ).toBeTruthy(); expect( swap!.estimatedGasUsedUSD.currency.equals(USDC) || @@ -638,7 +654,7 @@ describe('alpha router', () => { test('succeeds to route on v3 only', async () => { const swap = await alphaRouter.route( CurrencyAmount.fromRawAmount(USDC, 10000), - WETH9[1]!, + WRAPPED_NATIVE_CURRENCY[1], TradeType.EXACT_INPUT, undefined, { ...ROUTING_CONFIG, protocols: [Protocol.V3] } @@ -652,7 +668,7 @@ describe('alpha router', () => { 1, mockGasPriceWeiBN, sinon.match.any, - WETH9[1]! + WRAPPED_NATIVE_CURRENCY[1] ) ).toBeTruthy(); @@ -665,18 +681,26 @@ describe('alpha router', () => { sinon.match({ blockNumber: sinon.match.defined }) ); - expect(swap!.quote.currency.equals(WETH9[1]!)).toBeTruthy(); - expect(swap!.quoteGasAdjusted.currency.equals(WETH9[1]!)).toBeTruthy(); + expect( + swap!.quote.currency.equals(WRAPPED_NATIVE_CURRENCY[1]) + ).toBeTruthy(); + expect( + swap!.quoteGasAdjusted.currency.equals(WRAPPED_NATIVE_CURRENCY[1]) + ).toBeTruthy(); for (const r of swap!.route) { expect(r.route.input.equals(USDC)).toBeTruthy(); - expect(r.route.output.equals(WETH9[1]!.wrapped)).toBeTruthy(); + expect( + r.route.output.equals(WRAPPED_NATIVE_CURRENCY[1].wrapped) + ).toBeTruthy(); } expect(swap!.quote.greaterThan(swap!.quoteGasAdjusted)).toBeTruthy(); expect(swap!.estimatedGasUsed.toString()).toEqual('10000'); expect( - swap!.estimatedGasUsedQuoteToken.currency.equals(WETH9[1]!) + swap!.estimatedGasUsedQuoteToken.currency.equals( + WRAPPED_NATIVE_CURRENCY[1] + ) ).toBeTruthy(); expect( swap!.estimatedGasUsedUSD.currency.equals(USDC) || @@ -695,7 +719,7 @@ describe('alpha router', () => { test('succeeds to route on v2 only', async () => { const swap = await alphaRouter.route( CurrencyAmount.fromRawAmount(USDC, 10000), - WETH9[1]!, + WRAPPED_NATIVE_CURRENCY[1], TradeType.EXACT_INPUT, undefined, { ...ROUTING_CONFIG, protocols: [Protocol.V2] } @@ -709,7 +733,7 @@ describe('alpha router', () => { 1, mockGasPriceWeiBN, sinon.match.any, - WETH9[1]! + WRAPPED_NATIVE_CURRENCY[1] ) ).toBeTruthy(); @@ -721,18 +745,26 @@ describe('alpha router', () => { sinon.match.array ); - expect(swap!.quote.currency.equals(WETH9[1]!)).toBeTruthy(); - expect(swap!.quoteGasAdjusted.currency.equals(WETH9[1]!)).toBeTruthy(); + expect( + swap!.quote.currency.equals(WRAPPED_NATIVE_CURRENCY[1]) + ).toBeTruthy(); + expect( + swap!.quoteGasAdjusted.currency.equals(WRAPPED_NATIVE_CURRENCY[1]) + ).toBeTruthy(); for (const r of swap!.route) { expect(r.route.input.equals(USDC)).toBeTruthy(); - expect(r.route.output.equals(WETH9[1]!.wrapped)).toBeTruthy(); + expect( + r.route.output.equals(WRAPPED_NATIVE_CURRENCY[1].wrapped) + ).toBeTruthy(); } expect(swap!.quote.greaterThan(swap!.quoteGasAdjusted)).toBeTruthy(); expect(swap!.estimatedGasUsed.toString()).toEqual('10000'); expect( - swap!.estimatedGasUsedQuoteToken.currency.equals(WETH9[1]!) + swap!.estimatedGasUsedQuoteToken.currency.equals( + WRAPPED_NATIVE_CURRENCY[1] + ) ).toBeTruthy(); expect( swap!.estimatedGasUsedUSD.currency.equals(USDC) || @@ -757,7 +789,7 @@ describe('alpha router', () => { const swap = await alphaRouter.route( CurrencyAmount.fromRawAmount(USDC, 10000), - WETH9[1]!, + WRAPPED_NATIVE_CURRENCY[1], TradeType.EXACT_INPUT, swapParams, { ...ROUTING_CONFIG, protocols: [Protocol.V3] } @@ -771,7 +803,7 @@ describe('alpha router', () => { 1, mockGasPriceWeiBN, sinon.match.any, - WETH9[1]! + WRAPPED_NATIVE_CURRENCY[1] ) ).toBeTruthy(); @@ -784,18 +816,26 @@ describe('alpha router', () => { sinon.match({ blockNumber: sinon.match.defined }) ); - expect(swap!.quote.currency.equals(WETH9[1]!)).toBeTruthy(); - expect(swap!.quoteGasAdjusted.currency.equals(WETH9[1]!)).toBeTruthy(); + expect( + swap!.quote.currency.equals(WRAPPED_NATIVE_CURRENCY[1]) + ).toBeTruthy(); + expect( + swap!.quoteGasAdjusted.currency.equals(WRAPPED_NATIVE_CURRENCY[1]) + ).toBeTruthy(); for (const r of swap!.route) { expect(r.route.input.equals(USDC)).toBeTruthy(); - expect(r.route.output.equals(WETH9[1]!.wrapped)).toBeTruthy(); + expect( + r.route.output.equals(WRAPPED_NATIVE_CURRENCY[1].wrapped) + ).toBeTruthy(); } expect(swap!.quote.greaterThan(swap!.quoteGasAdjusted)).toBeTruthy(); expect(swap!.estimatedGasUsed.toString()).toEqual('10000'); expect( - swap!.estimatedGasUsedQuoteToken.currency.equals(WETH9[1]!) + swap!.estimatedGasUsedQuoteToken.currency.equals( + WRAPPED_NATIVE_CURRENCY[1] + ) ).toBeTruthy(); expect( swap!.estimatedGasUsedUSD.currency.equals(USDC) || @@ -820,7 +860,7 @@ describe('alpha router', () => { const swap = await alphaRouter.route( CurrencyAmount.fromRawAmount(USDC, 10000), - WETH9[1]!, + WRAPPED_NATIVE_CURRENCY[1], TradeType.EXACT_INPUT, swapParams, { ...ROUTING_CONFIG, protocols: [Protocol.V2] } @@ -834,7 +874,7 @@ describe('alpha router', () => { 1, mockGasPriceWeiBN, sinon.match.any, - WETH9[1]! + WRAPPED_NATIVE_CURRENCY[1] ) ).toBeTruthy(); @@ -846,18 +886,26 @@ describe('alpha router', () => { sinon.match.array ); - expect(swap!.quote.currency.equals(WETH9[1]!)).toBeTruthy(); - expect(swap!.quoteGasAdjusted.currency.equals(WETH9[1]!)).toBeTruthy(); + expect( + swap!.quote.currency.equals(WRAPPED_NATIVE_CURRENCY[1]) + ).toBeTruthy(); + expect( + swap!.quoteGasAdjusted.currency.equals(WRAPPED_NATIVE_CURRENCY[1]) + ).toBeTruthy(); for (const r of swap!.route) { expect(r.route.input.equals(USDC)).toBeTruthy(); - expect(r.route.output.equals(WETH9[1]!.wrapped)).toBeTruthy(); + expect( + r.route.output.equals(WRAPPED_NATIVE_CURRENCY[1].wrapped) + ).toBeTruthy(); } expect(swap!.quote.greaterThan(swap!.quoteGasAdjusted)).toBeTruthy(); expect(swap!.estimatedGasUsed.toString()).toEqual('10000'); expect( - swap!.estimatedGasUsedQuoteToken.currency.equals(WETH9[1]!) + swap!.estimatedGasUsedQuoteToken.currency.equals( + WRAPPED_NATIVE_CURRENCY[1] + ) ).toBeTruthy(); expect( swap!.estimatedGasUsedUSD.currency.equals(USDC) || @@ -941,7 +989,7 @@ describe('alpha router', () => { const amount = CurrencyAmount.fromRawAmount(USDC, 10000); const swap = await alphaRouter.route( - CurrencyAmount.fromRawAmount(WETH9[1]!, 10000), + CurrencyAmount.fromRawAmount(WRAPPED_NATIVE_CURRENCY[1], 10000), USDC, TradeType.EXACT_OUTPUT, undefined, @@ -989,7 +1037,9 @@ describe('alpha router', () => { for (const r of swap!.route) { expect(r.route.input.equals(USDC)).toBeTruthy(); - expect(r.route.output.equals(WETH9[1]!.wrapped)).toBeTruthy(); + expect( + r.route.output.equals(WRAPPED_NATIVE_CURRENCY[1].wrapped) + ).toBeTruthy(); } expect(swap!.quote.lessThan(swap!.quoteGasAdjusted)).toBeTruthy(); @@ -1029,7 +1079,7 @@ describe('alpha router', () => { test('succeeds to route on v3 only', async () => { const swap = await alphaRouter.route( - CurrencyAmount.fromRawAmount(WETH9[1]!, 10000), + CurrencyAmount.fromRawAmount(WRAPPED_NATIVE_CURRENCY[1], 10000), USDC, TradeType.EXACT_OUTPUT, undefined, @@ -1062,7 +1112,9 @@ describe('alpha router', () => { for (const r of swap!.route) { expect(r.route.input.equals(USDC)).toBeTruthy(); - expect(r.route.output.equals(WETH9[1]!.wrapped)).toBeTruthy(); + expect( + r.route.output.equals(WRAPPED_NATIVE_CURRENCY[1].wrapped) + ).toBeTruthy(); } expect(swap!.quote.lessThan(swap!.quoteGasAdjusted)).toBeTruthy(); @@ -1086,7 +1138,7 @@ describe('alpha router', () => { test('succeeds to route on v2 only', async () => { const swap = await alphaRouter.route( - CurrencyAmount.fromRawAmount(WETH9[1]!, 10000), + CurrencyAmount.fromRawAmount(WRAPPED_NATIVE_CURRENCY[1], 10000), USDC, TradeType.EXACT_OUTPUT, undefined, @@ -1118,7 +1170,9 @@ describe('alpha router', () => { for (const r of swap!.route) { expect(r.route.input.equals(USDC)).toBeTruthy(); - expect(r.route.output.equals(WETH9[1]!.wrapped)).toBeTruthy(); + expect( + r.route.output.equals(WRAPPED_NATIVE_CURRENCY[1].wrapped) + ).toBeTruthy(); } expect(swap!.quote.lessThan(swap!.quoteGasAdjusted)).toBeTruthy(); @@ -1148,7 +1202,7 @@ describe('alpha router', () => { }; const swap = await alphaRouter.route( - CurrencyAmount.fromRawAmount(WETH9[1]!, 10000), + CurrencyAmount.fromRawAmount(WRAPPED_NATIVE_CURRENCY[1], 10000), USDC, TradeType.EXACT_OUTPUT, swapParams, @@ -1182,7 +1236,9 @@ describe('alpha router', () => { for (const r of swap!.route) { expect(r.route.input.equals(USDC)).toBeTruthy(); - expect(r.route.output.equals(WETH9[1]!.wrapped)).toBeTruthy(); + expect( + r.route.output.equals(WRAPPED_NATIVE_CURRENCY[1].wrapped) + ).toBeTruthy(); } expect(swap!.quote.lessThan(swap!.quoteGasAdjusted)).toBeTruthy(); @@ -1212,7 +1268,7 @@ describe('alpha router', () => { }; const swap = await alphaRouter.route( - CurrencyAmount.fromRawAmount(WETH9[1]!, 10000), + CurrencyAmount.fromRawAmount(WRAPPED_NATIVE_CURRENCY[1], 10000), USDC, TradeType.EXACT_OUTPUT, swapParams, @@ -1245,7 +1301,9 @@ describe('alpha router', () => { for (const r of swap!.route) { expect(r.route.input.equals(USDC)).toBeTruthy(); - expect(r.route.output.equals(WETH9[1]!.wrapped)).toBeTruthy(); + expect( + r.route.output.equals(WRAPPED_NATIVE_CURRENCY[1].wrapped) + ).toBeTruthy(); } expect(swap!.quote.lessThan(swap!.quoteGasAdjusted)).toBeTruthy(); @@ -1431,7 +1489,7 @@ describe('alpha router', () => { describe('when token1 has more decimal places than token0', () => { test('calls routeExactIn with correct parameters', async () => { const token0Balance = parseAmount('20' + '0'.repeat(12), USDC); - const token1Balance = parseAmount('5', WETH9[1]); + const token1Balance = parseAmount('5', WRAPPED_NATIVE_CURRENCY[1]); const position = new Position({ pool: USDC_WETH_LOW, diff --git a/test/unit/routers/alpha-router/functions/best-swap-route.test.ts b/test/unit/routers/alpha-router/functions/best-swap-route.test.ts index ab82cf71f..7286669ae 100644 --- a/test/unit/routers/alpha-router/functions/best-swap-route.test.ts +++ b/test/unit/routers/alpha-router/functions/best-swap-route.test.ts @@ -17,7 +17,7 @@ import { V3PoolProvider, V3Route, V3RouteWithValidQuote, - WETH9, + WRAPPED_NATIVE_CURRENCY, } from '../../../../../src'; import { V2PoolProvider } from '../../../../../src/providers/v2/pool-provider'; import { getBestSwapRoute } from '../../../../../src/routers/alpha-router/functions/best-swap-route'; @@ -44,22 +44,30 @@ import { const v3Route1 = new V3Route( [USDC_DAI_LOW, DAI_USDT_LOW, WETH9_USDT_LOW], USDC, - WETH9[1] + WRAPPED_NATIVE_CURRENCY[1] ); -const v3Route2 = new V3Route([USDC_WETH_LOW], USDC, WETH9[1]); +const v3Route2 = new V3Route([USDC_WETH_LOW], USDC, WRAPPED_NATIVE_CURRENCY[1]); const v3Route3 = new V3Route( [USDC_DAI_MEDIUM, DAI_USDT_MEDIUM, WBTC_USDT_MEDIUM, WBTC_WETH_MEDIUM], USDC, - WETH9[1]! + WRAPPED_NATIVE_CURRENCY[1] +); +const v3Route4 = new V3Route( + [USDC_WETH_MEDIUM], + USDC, + WRAPPED_NATIVE_CURRENCY[1] ); -const v3Route4 = new V3Route([USDC_WETH_MEDIUM], USDC, WETH9[1]!); -const v2Route1 = new V2Route([USDC_DAI, DAI_USDT, WETH_USDT], USDC, WETH9[1]); -const v2Route2 = new V2Route([USDC_WETH], USDC, WETH9[1]); +const v2Route1 = new V2Route( + [USDC_DAI, DAI_USDT, WETH_USDT], + USDC, + WRAPPED_NATIVE_CURRENCY[1] +); +const v2Route2 = new V2Route([USDC_WETH], USDC, WRAPPED_NATIVE_CURRENCY[1]); const v2Route3 = new V2Route( [USDC_DAI, DAI_USDT, WETH_USDT, WBTC_WETH], USDC, - WETH9[1] + WRAPPED_NATIVE_CURRENCY[1]! ); const mockPools = [ @@ -273,7 +281,7 @@ describe('get best swap route', () => { ).toBeTruthy(); expect( estimatedGasUsedQuoteToken.equalTo( - CurrencyAmount.fromRawAmount(WETH9[1], 0) + CurrencyAmount.fromRawAmount(WRAPPED_NATIVE_CURRENCY[1]!, 0) ) ).toBeTruthy(); expect(routes).toHaveLength(1); @@ -331,7 +339,7 @@ describe('get best swap route', () => { ).toBeTruthy(); expect( estimatedGasUsedQuoteToken.equalTo( - CurrencyAmount.fromRawAmount(WETH9[1], 0) + CurrencyAmount.fromRawAmount(WRAPPED_NATIVE_CURRENCY[1]!, 0) ) ).toBeTruthy(); expect(routes).toHaveLength(2); @@ -389,7 +397,7 @@ describe('get best swap route', () => { ).toBeTruthy(); expect( estimatedGasUsedQuoteToken.equalTo( - CurrencyAmount.fromRawAmount(WETH9[1], 0) + CurrencyAmount.fromRawAmount(WRAPPED_NATIVE_CURRENCY[1]!, 0) ) ).toBeTruthy(); expect(routes).toHaveLength(3); @@ -454,7 +462,7 @@ describe('get best swap route', () => { ).toBeTruthy(); expect( estimatedGasUsedQuoteToken.equalTo( - CurrencyAmount.fromRawAmount(WETH9[1], 0) + CurrencyAmount.fromRawAmount(WRAPPED_NATIVE_CURRENCY[1]!, 0) ) ).toBeTruthy(); expect(routes).toHaveLength(4); @@ -466,8 +474,12 @@ describe('get best swap route', () => { // Check that even though the pools in these routes use the same tokens, // since they are on different protocols we are fine to route in them. - const v2Route = new V2Route([USDC_WETH], USDC, WETH9[1]); - const v3Route = new V3Route([USDC_WETH_LOW], USDC, WETH9[1]); + const v2Route = new V2Route([USDC_WETH], USDC, WRAPPED_NATIVE_CURRENCY[1]!); + const v3Route = new V3Route( + [USDC_WETH_LOW], + USDC, + WRAPPED_NATIVE_CURRENCY[1]! + ); const routesWithQuotes: RouteWithValidQuote[] = [ ...buildV2RouteWithValidQuotes( @@ -517,7 +529,7 @@ describe('get best swap route', () => { ).toBeTruthy(); expect( estimatedGasUsedQuoteToken.equalTo( - CurrencyAmount.fromRawAmount(WETH9[1], 0) + CurrencyAmount.fromRawAmount(WRAPPED_NATIVE_CURRENCY[1]!, 0) ) ).toBeTruthy(); expect(routes).toHaveLength(2); @@ -583,7 +595,7 @@ describe('get best swap route', () => { ).toBeTruthy(); expect( estimatedGasUsedQuoteToken.equalTo( - CurrencyAmount.fromRawAmount(WETH9[1], 0) + CurrencyAmount.fromRawAmount(WRAPPED_NATIVE_CURRENCY[1]!, 0) ) ).toBeTruthy(); expect(routes).toHaveLength(3); @@ -654,7 +666,7 @@ describe('get best swap route', () => { ).toBeTruthy(); expect( estimatedGasUsedQuoteToken.equalTo( - CurrencyAmount.fromRawAmount(WETH9[1], 0) + CurrencyAmount.fromRawAmount(WRAPPED_NATIVE_CURRENCY[1]!, 0) ) ).toBeTruthy(); expect(routes).toHaveLength(3); @@ -723,7 +735,7 @@ describe('get best swap route', () => { expect(estimatedGasUsedUSD.quotient.toString()).toEqual('10000000000000'); expect( estimatedGasUsedQuoteToken.equalTo( - CurrencyAmount.fromRawAmount(WETH9[1], 10) + CurrencyAmount.fromRawAmount(WRAPPED_NATIVE_CURRENCY[1]!, 10) ) ).toBeTruthy(); expect(routes).toHaveLength(1); @@ -792,7 +804,7 @@ describe('get best swap route', () => { expect(estimatedGasUsedUSD.quotient.toString()).toEqual('10'); expect( estimatedGasUsedQuoteToken.equalTo( - CurrencyAmount.fromRawAmount(WETH9[1], 10) + CurrencyAmount.fromRawAmount(WRAPPED_NATIVE_CURRENCY[1]!, 10) ) ).toBeTruthy(); expect(routes).toHaveLength(1); diff --git a/test/unit/routers/alpha-router/functions/get-candidate-pools.test.ts b/test/unit/routers/alpha-router/functions/get-candidate-pools.test.ts index 662739164..7839d4fc9 100644 --- a/test/unit/routers/alpha-router/functions/get-candidate-pools.test.ts +++ b/test/unit/routers/alpha-router/functions/get-candidate-pools.test.ts @@ -13,7 +13,7 @@ import { V3PoolProvider, V3SubgraphPool, V3SubgraphProvider, - WETH9, + WRAPPED_NATIVE_CURRENCY, } from '../../../../../src'; import { getV3CandidatePools } from '../../../../../src/routers/alpha-router/functions/get-candidate-pools'; import { @@ -57,7 +57,7 @@ describe('get candidate pools', () => { forceCrossProtocol: false, }; - const mockTokens = [USDC, DAI, WETH9[1], USDT]; + const mockTokens = [USDC, DAI, WRAPPED_NATIVE_CURRENCY[1]!, USDT]; const mockPools = [ USDC_DAI_LOW, USDC_DAI_MEDIUM, @@ -114,8 +114,8 @@ describe('get candidate pools', () => { expect( mockV3PoolProvider.getPools.calledWithExactly([ - [USDC, WETH9[1], FeeAmount.LOW], - [WETH9[1], USDT, FeeAmount.LOW], + [USDC, WRAPPED_NATIVE_CURRENCY[1]!, FeeAmount.LOW], + [WRAPPED_NATIVE_CURRENCY[1]!, USDT, FeeAmount.LOW], ]) ).toBeTruthy(); }); @@ -168,7 +168,7 @@ describe('get candidate pools', () => { expect( mockV3PoolProvider.getPools.calledWithExactly([ - [USDC, WETH9[1], FeeAmount.LOW], + [USDC, WRAPPED_NATIVE_CURRENCY[1]!, FeeAmount.LOW], [DAI, USDC, FeeAmount.LOW], ]) ).toBeTruthy(); @@ -193,7 +193,7 @@ describe('get candidate pools', () => { const DAI_WETH_LOW = new Pool( DAI, - WETH9[1], + WRAPPED_NATIVE_CURRENCY[1]!, FeeAmount.LOW, encodeSqrtRatioX96(1, 1), 10, @@ -204,7 +204,7 @@ describe('get candidate pools', () => { ); await getV3CandidatePools({ - tokenIn: WETH9[1], + tokenIn: WRAPPED_NATIVE_CURRENCY[1]!, tokenOut: DAI, routeType: TradeType.EXACT_INPUT, routingConfig: { @@ -223,10 +223,10 @@ describe('get candidate pools', () => { expect( mockV3PoolProvider.getPools.calledWithExactly([ - [DAI, WETH9[1], FeeAmount.HIGH], - [DAI, WETH9[1], FeeAmount.MEDIUM], - [DAI, WETH9[1], FeeAmount.LOW], - [DAI, WETH9[1], FeeAmount.LOWEST], + [DAI, WRAPPED_NATIVE_CURRENCY[1]!, FeeAmount.HIGH], + [DAI, WRAPPED_NATIVE_CURRENCY[1]!, FeeAmount.MEDIUM], + [DAI, WRAPPED_NATIVE_CURRENCY[1]!, FeeAmount.LOW], + [DAI, WRAPPED_NATIVE_CURRENCY[1]!, FeeAmount.LOWEST], ]) ).toBeTruthy(); }); diff --git a/test/unit/test-util/mock-data.ts b/test/unit/test-util/mock-data.ts index ff1c61df1..9480d2bfc 100644 --- a/test/unit/test-util/mock-data.ts +++ b/test/unit/test-util/mock-data.ts @@ -15,7 +15,7 @@ import { V3PoolAccessor, V3SubgraphPool, WBTC_MAINNET as WBTC, - WETH9, + WRAPPED_NATIVE_CURRENCY, } from '../../../src'; import { V2PoolAccessor } from '../../../src/providers/v2/pool-provider'; @@ -50,7 +50,7 @@ export const mockRoutingConfig: AlphaRouterConfig = { // Mock V3 Pools export const USDC_WETH_LOW = new Pool( USDC, - WETH9[1], + WRAPPED_NATIVE_CURRENCY[1]!, FeeAmount.LOW, encodeSqrtRatioX96(1, 1), 500, @@ -59,7 +59,7 @@ export const USDC_WETH_LOW = new Pool( export const USDC_WETH_MEDIUM = new Pool( USDC, - WETH9[1], + WRAPPED_NATIVE_CURRENCY[1]!, FeeAmount.MEDIUM, encodeSqrtRatioX96(1, 1), 500, @@ -67,7 +67,7 @@ export const USDC_WETH_MEDIUM = new Pool( ); export const WETH9_USDT_LOW = new Pool( - WETH9[1], + WRAPPED_NATIVE_CURRENCY[1]!, USDT, FeeAmount.LOW, encodeSqrtRatioX96(1, 1), @@ -124,7 +124,7 @@ export const WBTC_USDT_MEDIUM = new Pool( 0 ); export const WBTC_WETH_MEDIUM = new Pool( - WETH9[1], + WRAPPED_NATIVE_CURRENCY[1]!, WBTC, FeeAmount.MEDIUM, encodeSqrtRatioX96(1, 1), @@ -140,12 +140,12 @@ export const DAI_USDT = new Pair( export const USDC_WETH = new Pair( CurrencyAmount.fromRawAmount(USDC, 10000000000), - CurrencyAmount.fromRawAmount(WETH9[1]!, 10000000000) + CurrencyAmount.fromRawAmount(WRAPPED_NATIVE_CURRENCY[1]!, 10000000000) ); export const WETH_USDT = new Pair( CurrencyAmount.fromRawAmount(USDT, 10000000000), - CurrencyAmount.fromRawAmount(WETH9[1]!, 10000000000) + CurrencyAmount.fromRawAmount(WRAPPED_NATIVE_CURRENCY[1]!, 10000000000) ); export const USDC_DAI = new Pair( @@ -155,7 +155,7 @@ export const USDC_DAI = new Pair( export const WBTC_WETH = new Pair( CurrencyAmount.fromRawAmount(WBTC, 10000000000), - CurrencyAmount.fromRawAmount(WETH9[1]!, 10000000000) + CurrencyAmount.fromRawAmount(WRAPPED_NATIVE_CURRENCY[1]!, 10000000000) ); export const poolToV3SubgraphPool = (