diff --git a/CHANGELOG.md b/CHANGELOG.md index a8231a396..7bf0ba1fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [3.6.0](https://github.com/Uniswap/smart-order-router/compare/v3.5.0...v3.6.0) (2023-02-24) + ### [3.0.1](https://github.com/Uniswap/smart-order-router/compare/v2.10.2...v3.0.1) (2022-11-20) ### [2.10.2](https://github.com/Uniswap/smart-order-router/compare/v2.10.1...v2.10.2) (2022-11-08) @@ -10,10 +12,9 @@ All notable changes to this project will be documented in this file. See [standa ## [2.10.0](https://github.com/Uniswap/smart-order-router/compare/v2.9.3...v2.10.0) (2022-09-09) - ### Features -* add network context to logs ([#163](https://github.com/Uniswap/smart-order-router/issues/163)) ([d686a14](https://github.com/Uniswap/smart-order-router/commit/d686a14a0d0cf248caf29bc1c0384c4d84719475)) +- add network context to logs ([#163](https://github.com/Uniswap/smart-order-router/issues/163)) ([d686a14](https://github.com/Uniswap/smart-order-router/commit/d686a14a0d0cf248caf29bc1c0384c4d84719475)) ### [2.9.3](https://github.com/Uniswap/smart-order-router/compare/v2.9.2...v2.9.3) (2022-08-17) @@ -27,31 +28,27 @@ All notable changes to this project will be documented in this file. See [standa ## [2.8.0](https://github.com/Uniswap/smart-order-router/compare/v2.6.1...v2.8.0) (2022-07-20) - ### Features -* add stale config ([#116](https://github.com/Uniswap/smart-order-router/issues/116)) ([3c4a32f](https://github.com/Uniswap/smart-order-router/commit/3c4a32fc671ee1b57c48f494090caede2d5f776f)) +- add stale config ([#116](https://github.com/Uniswap/smart-order-router/issues/116)) ([3c4a32f](https://github.com/Uniswap/smart-order-router/commit/3c4a32fc671ee1b57c48f494090caede2d5f776f)) ## [2.7.0](https://github.com/Uniswap/smart-order-router/compare/v2.6.1...v2.7.0) (2022-07-14) - ### Features -* add stale config ([#116](https://github.com/Uniswap/smart-order-router/issues/116)) ([3c4a32f](https://github.com/Uniswap/smart-order-router/commit/3c4a32fc671ee1b57c48f494090caede2d5f776f)) +- add stale config ([#116](https://github.com/Uniswap/smart-order-router/issues/116)) ([3c4a32f](https://github.com/Uniswap/smart-order-router/commit/3c4a32fc671ee1b57c48f494090caede2d5f776f)) ### [2.6.1](https://github.com/Uniswap/smart-order-router/compare/v2.6.0...v2.6.1) (2022-07-12) ## [2.6.0](https://github.com/Uniswap/smart-order-router/compare/v2.5.32...v2.6.0) (2022-07-07) - ### Features -* export TokenValidatorProvider ([#110](https://github.com/Uniswap/smart-order-router/issues/110)) ([53c6bef](https://github.com/Uniswap/smart-order-router/commit/53c6befc4a78f814a80d510896e4c15da527151c)) - +- export TokenValidatorProvider ([#110](https://github.com/Uniswap/smart-order-router/issues/110)) ([53c6bef](https://github.com/Uniswap/smart-order-router/commit/53c6befc4a78f814a80d510896e4c15da527151c)) ### Bug Fixes -* update celo contract addresses ([#109](https://github.com/Uniswap/smart-order-router/issues/109)) ([121e9ba](https://github.com/Uniswap/smart-order-router/commit/121e9ba5fd37afaaeea65d0e92e9fdd599d7cbb2)) +- update celo contract addresses ([#109](https://github.com/Uniswap/smart-order-router/issues/109)) ([121e9ba](https://github.com/Uniswap/smart-order-router/commit/121e9ba5fd37afaaeea65d0e92e9fdd599d7cbb2)) ### [2.5.32](https://github.com/Uniswap/smart-order-router/compare/v2.5.31...v2.5.32) (2022-07-05) diff --git a/README.md b/README.md index 2d00c1756..553b9a5aa 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ JSON_RPC_PROVIDER_POLYGON = '' JSON_RPC_PROVIDER_POLYGON_MUMBAI = '' JSON_RPC_PROVIDER_CELO = '' JSON_RPC_PROVIDER_CELO_ALFAJORES = '' +JSON_RPC_PROVIDER_BSC = '' ``` Then from the root directory you can execute the CLI. @@ -195,6 +196,12 @@ Total ticks crossed: 7 ./bin/cli quote --tokenIn CELO --tokenOut 0x765DE816845861e75A25fCA122bb6898B8B1282a --amount 5 --exactIn --minSplits 1 --protocols v3 --router alpha --chainId 42220 ``` +## BSC Mainnet + +``` +./bin/cli quote --tokenIn 0x55d398326f99059fF775485246999027B3197955 --tokenOut 0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d --amount 1 --exactIn --minSplits 1 --protocols v3 --router alpha --chainId 56 +``` + ## Adding a new Chain The main components to complete are: diff --git a/package-lock.json b/package-lock.json index 8d453b16c..eb04a1c2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@uniswap/smart-order-router", - "version": "3.5.0", + "version": "3.6.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@uniswap/smart-order-router", - "version": "3.5.0", + "version": "3.6.0", "license": "GPL", "dependencies": { "@uniswap/default-token-list": "^2.0.0", @@ -15,7 +15,7 @@ "@uniswap/swap-router-contracts": "^1.3.0", "@uniswap/token-lists": "^1.0.0-beta.25", "@uniswap/universal-router": "^1.0.1", - "@uniswap/universal-router-sdk": "^1.3.0", + "@uniswap/universal-router-sdk": "^1.3.8", "@uniswap/v2-sdk": "^3.0.1", "@uniswap/v3-sdk": "^3.7.0", "async-retry": "^1.3.1", @@ -3244,9 +3244,9 @@ } }, "node_modules/@uniswap/universal-router-sdk": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@uniswap/universal-router-sdk/-/universal-router-sdk-1.3.0.tgz", - "integrity": "sha512-Q7/Gw059JQDO7exxV791QzghEOiWomdvxvqidozDvkiZE7paIlSWq1vDVF4H3zB2GYy5Hu7HM8krl2l0KS9X5g==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/@uniswap/universal-router-sdk/-/universal-router-sdk-1.3.8.tgz", + "integrity": "sha512-WwmcIL20DSExTNep31OxyVCMsi/JqRsZsCqZEqwYTP+Ip1qQ9P8mcR3wtGAfBmYlWFS1lcIhI6SDvXayIk6DDw==", "dependencies": { "@uniswap/permit2-sdk": "^1.2.0", "@uniswap/router-sdk": "^1.4.0", @@ -14225,9 +14225,9 @@ } }, "@uniswap/universal-router-sdk": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@uniswap/universal-router-sdk/-/universal-router-sdk-1.3.0.tgz", - "integrity": "sha512-Q7/Gw059JQDO7exxV791QzghEOiWomdvxvqidozDvkiZE7paIlSWq1vDVF4H3zB2GYy5Hu7HM8krl2l0KS9X5g==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/@uniswap/universal-router-sdk/-/universal-router-sdk-1.3.8.tgz", + "integrity": "sha512-WwmcIL20DSExTNep31OxyVCMsi/JqRsZsCqZEqwYTP+Ip1qQ9P8mcR3wtGAfBmYlWFS1lcIhI6SDvXayIk6DDw==", "requires": { "@uniswap/permit2-sdk": "^1.2.0", "@uniswap/router-sdk": "^1.4.0", diff --git a/package.json b/package.json index afcf0b3c7..b1116c303 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@uniswap/smart-order-router", - "version": "3.5.0", + "version": "3.6.0", "description": "Uniswap Smart Order Router", "main": "build/main/index.js", "typings": "build/main/index.d.ts", @@ -37,7 +37,7 @@ "@uniswap/swap-router-contracts": "^1.3.0", "@uniswap/token-lists": "^1.0.0-beta.25", "@uniswap/universal-router": "^1.0.1", - "@uniswap/universal-router-sdk": "^1.3.0", + "@uniswap/universal-router-sdk": "^1.3.8", "@uniswap/v2-sdk": "^3.0.1", "@uniswap/v3-sdk": "^3.7.0", "async-retry": "^1.3.1", diff --git a/src/providers/caching-token-list-provider.ts b/src/providers/caching-token-list-provider.ts index 84526d957..f3cfa0d75 100644 --- a/src/providers/caching-token-list-provider.ts +++ b/src/providers/caching-token-list-provider.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ import { Token } from '@uniswap/sdk-core'; import { TokenInfo, TokenList } from '@uniswap/token-lists'; import axios from 'axios'; diff --git a/src/providers/caching-token-provider.ts b/src/providers/caching-token-provider.ts index 5ccf6d3fd..5415b95f8 100644 --- a/src/providers/caching-token-provider.ts +++ b/src/providers/caching-token-provider.ts @@ -5,6 +5,8 @@ import { ChainId, log, WRAPPED_NATIVE_CURRENCY } from '../util'; import { ICache } from './cache'; import { + BTC_BSC, + BUSD_BSC, CELO, CELO_ALFAJORES, CEUR_CELO, @@ -12,6 +14,7 @@ import { CUSD_CELO_ALFAJORES, DAI_ARBITRUM, DAI_ARBITRUM_RINKEBY, + DAI_BSC, DAI_CELO, DAI_CELO_ALFAJORES, DAI_MAINNET, @@ -21,12 +24,14 @@ import { DAI_POLYGON_MUMBAI, DAI_RINKEBY_1, DAI_RINKEBY_2, + ETH_BSC, ITokenProvider, TokenAccessor, UNI_ARBITRUM_RINKEBY, USDC_ARBITRUM, USDC_ARBITRUM_GOERLI, USDC_ARBITRUM_RINKEBY, + USDC_BSC, USDC_ETHEREUM_GNOSIS, USDC_MAINNET, USDC_MOONBEAM, @@ -35,6 +40,7 @@ import { USDC_POLYGON, USDT_ARBITRUM, USDT_ARBITRUM_RINKEBY, + USDT_BSC, USDT_MAINNET, USDT_OPTIMISM, USDT_OPTIMISTIC_KOVAN, @@ -130,6 +136,15 @@ export const CACHE_SEED_TOKENS: { WBTC: WBTC_MOONBEAM, WGLMR: WRAPPED_NATIVE_CURRENCY[ChainId.MOONBEAM], }, + [ChainId.BSC]: { + USDC: USDC_BSC, + USDT: USDT_BSC, + BUSD: BUSD_BSC, + ETH: ETH_BSC, + DAI: DAI_BSC, + BTC: BTC_BSC, + WBNB: WRAPPED_NATIVE_CURRENCY[ChainId.BSC], + }, // Currently we do not have providers for Moonbeam mainnet or Gnosis testnet }; diff --git a/src/providers/simulation-provider.ts b/src/providers/simulation-provider.ts index 226c645db..a94e0d9e3 100644 --- a/src/providers/simulation-provider.ts +++ b/src/providers/simulation-provider.ts @@ -6,7 +6,12 @@ import { BigNumber } from 'ethers/lib/ethers'; import { SwapOptions, SwapRoute, SwapType } from '../routers'; import { Erc20__factory } from '../types/other/factories/Erc20__factory'; import { Permit2__factory } from '../types/other/factories/Permit2__factory'; -import { ChainId, CurrencyAmount, log, SWAP_ROUTER_02_ADDRESS } from '../util'; +import { + ChainId, + CurrencyAmount, + log, + SWAP_ROUTER_02_ADDRESSES, +} from '../util'; import { ProviderConfig } from './provider'; import { ArbitrumGasData, OptimismGasData } from './v3/gas-data-provider'; @@ -174,7 +179,7 @@ export abstract class Simulator { await permit2Contract.allowance( fromAddress, inputAmount.currency.wrapped.address, - SWAP_ROUTER_02_ADDRESS + SWAP_ROUTER_02_ADDRESSES(this.chainId) ); const nowTimestampS = Math.round(Date.now() / 1000); @@ -211,7 +216,7 @@ export abstract class Simulator { const allowance = await tokenContract.allowance( fromAddress, - SWAP_ROUTER_02_ADDRESS + SWAP_ROUTER_02_ADDRESSES(this.chainId) ); const hasAllowance = allowance.gte( BigNumber.from(inputAmount.quotient.toString()) diff --git a/src/providers/swap-router-provider.ts b/src/providers/swap-router-provider.ts index e53e57d3e..e8ead09e6 100644 --- a/src/providers/swap-router-provider.ts +++ b/src/providers/swap-router-provider.ts @@ -2,7 +2,7 @@ import { ApprovalTypes } from '@uniswap/router-sdk'; import { Currency, CurrencyAmount } from '@uniswap/sdk-core'; import { SwapRouter02__factory } from '../types/other/factories/SwapRouter02__factory'; -import { log, SWAP_ROUTER_02_ADDRESS } from '../util'; +import { ChainId, log, SWAP_ROUTER_02_ADDRESSES } from '../util'; import { IMulticallProvider } from './multicall-provider'; @@ -32,7 +32,10 @@ export interface ISwapRouterProvider { } export class SwapRouterProvider implements ISwapRouterProvider { - constructor(protected multicall2Provider: IMulticallProvider) {} + constructor( + protected multicall2Provider: IMulticallProvider, + protected chainId: ChainId + ) {} public async getApprovalType( tokenInAmount: CurrencyAmount, @@ -54,7 +57,7 @@ export class SwapRouterProvider implements ISwapRouterProvider { [string, string], [ApprovalTypes] >({ - address: SWAP_ROUTER_02_ADDRESS, + address: SWAP_ROUTER_02_ADDRESSES(this.chainId), contractInterface: SwapRouter02__factory.createInterface(), functionName: 'getApprovalType', functionParams, diff --git a/src/providers/tenderly-simulation-provider.ts b/src/providers/tenderly-simulation-provider.ts index 51a5527b3..7329d3835 100644 --- a/src/providers/tenderly-simulation-provider.ts +++ b/src/providers/tenderly-simulation-provider.ts @@ -10,7 +10,7 @@ import { BigNumber } from 'ethers/lib/ethers'; import { SwapOptions, SwapRoute, SwapType } from '../routers'; import { Erc20__factory } from '../types/other/factories/Erc20__factory'; import { Permit2__factory } from '../types/other/factories/Permit2__factory'; -import { ChainId, log, MAX_UINT160, SWAP_ROUTER_02_ADDRESS } from '../util'; +import { ChainId, log, MAX_UINT160, SWAP_ROUTER_02_ADDRESSES } from '../util'; import { APPROVE_TOKEN_FOR_TRANSFER } from '../util/callData'; import { calculateGasUsed, @@ -316,7 +316,7 @@ export class TenderlySimulator extends Simulator { const swap = { network_id: chainId, input: calldata, - to: SWAP_ROUTER_02_ADDRESS, + to: SWAP_ROUTER_02_ADDRESSES(chainId), gas_estimate: true, value: currencyIn.isNative ? swapRoute.methodParameters.value : '0', from: fromAddress, diff --git a/src/providers/token-provider.ts b/src/providers/token-provider.ts index 27a86e63d..4f00ed5a3 100644 --- a/src/providers/token-provider.ts +++ b/src/providers/token-provider.ts @@ -404,6 +404,55 @@ export const WETH_POLYGON_MUMBAI = new Token( 'Wrapped Ether' ); +// BNB chain Tokens +export const BTC_BSC = new Token( + ChainId.BSC, + '0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c', + 18, + 'BTCB', + 'Binance BTC' +); + +export const BUSD_BSC = new Token( + ChainId.BSC, + '0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56', + 18, + 'BUSD', + 'BUSD' +); + +export const DAI_BSC = new Token( + ChainId.BSC, + '0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3', + 18, + 'DAI', + 'DAI' +); + +export const ETH_BSC = new Token( + ChainId.BSC, + '0x2170Ed0880ac9A755fd29B2688956BD959F933F8', + 18, + 'ETH', + 'ETH' +); + +export const USDC_BSC = new Token( + ChainId.BSC, + '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d', + 18, + 'USDC', + 'USDC' +); + +export const USDT_BSC = new Token( + ChainId.BSC, + '0x55d398326f99059fF775485246999027B3197955', + 18, + 'USDT', + 'USDT' +); + // Celo Tokens export const CELO = new Token( ChainId.CELO, @@ -655,6 +704,8 @@ export const DAI_ON = (chainId: ChainId): Token => { return DAI_CELO_ALFAJORES; case ChainId.MOONBEAM: return DAI_MOONBEAM; + case ChainId.BSC: + return DAI_BSC; default: throw new Error(`Chain id: ${chainId} not supported`); } @@ -680,6 +731,8 @@ export const USDT_ON = (chainId: ChainId): Token => { return USDT_ARBITRUM; case ChainId.ARBITRUM_RINKEBY: return USDT_ARBITRUM_RINKEBY; + case ChainId.BSC: + return USDT_BSC; default: throw new Error(`Chain id: ${chainId} not supported`); } @@ -715,6 +768,8 @@ export const USDC_ON = (chainId: ChainId): Token => { return USDC_ETHEREUM_GNOSIS; case ChainId.MOONBEAM: return USDC_MOONBEAM; + case ChainId.BSC: + return USDC_BSC; default: throw new Error(`Chain id: ${chainId} not supported`); } diff --git a/src/providers/v2/static-subgraph-provider.ts b/src/providers/v2/static-subgraph-provider.ts index b321ece65..65b80a00a 100644 --- a/src/providers/v2/static-subgraph-provider.ts +++ b/src/providers/v2/static-subgraph-provider.ts @@ -47,6 +47,7 @@ const BASES_TO_CHECK_TRADES_AGAINST: ChainTokenList = { [ChainId.CELO_ALFAJORES]: [], [ChainId.GNOSIS]: [], [ChainId.MOONBEAM]: [], + [ChainId.BSC]: [], }; /** diff --git a/src/providers/v3/static-subgraph-provider.ts b/src/providers/v3/static-subgraph-provider.ts index f173b25df..db14f3ece 100644 --- a/src/providers/v3/static-subgraph-provider.ts +++ b/src/providers/v3/static-subgraph-provider.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ import { Token } from '@uniswap/sdk-core'; import { FeeAmount, Pool } from '@uniswap/v3-sdk'; import JSBI from 'jsbi'; @@ -7,6 +8,8 @@ import { unparseFeeAmount } from '../../util/amounts'; import { ChainId, WRAPPED_NATIVE_CURRENCY } from '../../util/chains'; import { log } from '../../util/log'; import { + BTC_BSC, + BUSD_BSC, CELO, CELO_ALFAJORES, CEUR_CELO, @@ -15,6 +18,7 @@ import { CUSD_CELO_ALFAJORES, DAI_ARBITRUM, DAI_ARBITRUM_RINKEBY, + DAI_BSC, DAI_CELO, DAI_CELO_ALFAJORES, DAI_GÖRLI, @@ -27,9 +31,11 @@ import { DAI_RINKEBY_1, DAI_RINKEBY_2, DAI_ROPSTEN, + ETH_BSC, UNI_ARBITRUM_RINKEBY, USDC_ARBITRUM, USDC_ARBITRUM_GOERLI, + USDC_BSC, USDC_ETHEREUM_GNOSIS, USDC_GÖRLI, USDC_KOVAN, @@ -42,6 +48,7 @@ import { USDC_ROPSTEN, USDT_ARBITRUM, USDT_ARBITRUM_RINKEBY, + USDT_BSC, USDT_GÖRLI, USDT_KOVAN, USDT_MAINNET, @@ -155,6 +162,15 @@ const BASES_TO_CHECK_TRADES_AGAINST: ChainTokenList = { WXDAI_GNOSIS, USDC_ETHEREUM_GNOSIS, ], + [ChainId.BSC]: [ + WRAPPED_NATIVE_CURRENCY[ChainId.BSC], + BUSD_BSC, + DAI_BSC, + USDC_BSC, + USDT_BSC, + BTC_BSC, + ETH_BSC, + ], [ChainId.MOONBEAM]: [ WRAPPED_NATIVE_CURRENCY[ChainId.MOONBEAM], DAI_MOONBEAM, diff --git a/src/providers/v3/subgraph-provider.ts b/src/providers/v3/subgraph-provider.ts index e8a016350..00f58368d 100644 --- a/src/providers/v3/subgraph-provider.ts +++ b/src/providers/v3/subgraph-provider.ts @@ -59,6 +59,8 @@ const SUBGRAPH_URL_BY_CHAIN: { [chainId in ChainId]?: string } = { 'https://api.thegraph.com/subgraphs/name/jesse-sawa/uniswap-celo', [ChainId.GÖRLI]: 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v3-gorli', + [ChainId.BSC]: + 'https://api.thegraph.com/subgraphs/name/ilyamk/uniswap-v3---bnb-chain', }; const PAGE_SIZE = 1000; // 1k is max possible query size from subgraph. diff --git a/src/routers/alpha-router/alpha-router.ts b/src/routers/alpha-router/alpha-router.ts index 5e5913de0..241bd9ece 100644 --- a/src/routers/alpha-router/alpha-router.ts +++ b/src/routers/alpha-router/alpha-router.ts @@ -69,7 +69,7 @@ import { } from '../../providers/v3/pool-provider'; import { IV3SubgraphProvider } from '../../providers/v3/subgraph-provider'; import { Erc20__factory } from '../../types/other/factories/Erc20__factory'; -import { SWAP_ROUTER_02_ADDRESS } from '../../util'; +import { SWAP_ROUTER_02_ADDRESSES } from '../../util'; import { CurrencyAmount } from '../../util/amounts'; import { ChainId, @@ -600,7 +600,8 @@ export class AlphaRouter mixedRouteGasModelFactory ?? new MixedRouteHeuristicGasModelFactory(); this.swapRouterProvider = - swapRouterProvider ?? new SwapRouterProvider(this.multicall2Provider); + swapRouterProvider ?? + new SwapRouterProvider(this.multicall2Provider, this.chainId); if (chainId == ChainId.OPTIMISM || chainId == ChainId.OPTIMISTIC_KOVAN) { this.l2GasDataProvider = @@ -1724,7 +1725,7 @@ export class AlphaRouter approvalTypes.approvalTokenIn, approvalTypes.approvalTokenOut ), - to: SWAP_ROUTER_02_ADDRESS, + to: SWAP_ROUTER_02_ADDRESSES(this.chainId), }; } diff --git a/src/routers/alpha-router/functions/get-candidate-pools.ts b/src/routers/alpha-router/functions/get-candidate-pools.ts index efe9a6ece..3b2300315 100644 --- a/src/routers/alpha-router/functions/get-candidate-pools.ts +++ b/src/routers/alpha-router/functions/get-candidate-pools.ts @@ -17,6 +17,7 @@ import { CUSD_CELO_ALFAJORES, DAI_ARBITRUM, DAI_ARBITRUM_RINKEBY, + DAI_BSC, DAI_MAINNET, DAI_MOONBEAM, DAI_OPTIMISM, @@ -28,6 +29,7 @@ import { ITokenProvider, USDC_ARBITRUM, USDC_ARBITRUM_GOERLI, + USDC_BSC, USDC_ETHEREUM_GNOSIS, USDC_MAINNET, USDC_MOONBEAM, @@ -36,6 +38,7 @@ import { USDC_POLYGON, USDT_ARBITRUM, USDT_ARBITRUM_RINKEBY, + USDT_BSC, USDT_MAINNET, USDT_OPTIMISM, USDT_OPTIMISTIC_KOVAN, @@ -170,6 +173,11 @@ const baseTokensByChain: { [chainId in ChainId]?: Token[] } = { WBTC_MOONBEAM, WGLMR_MOONBEAM, ], + [ChainId.BSC]: [ + DAI_BSC, + USDC_BSC, + USDT_BSC, + ], }; export async function getV3CandidatePools({ diff --git a/src/routers/alpha-router/gas-models/gas-model.ts b/src/routers/alpha-router/gas-models/gas-model.ts index 2afe267ea..436b1b1d6 100644 --- a/src/routers/alpha-router/gas-models/gas-model.ts +++ b/src/routers/alpha-router/gas-models/gas-model.ts @@ -6,6 +6,7 @@ import { CUSD_CELO_ALFAJORES, DAI_ARBITRUM, DAI_ARBITRUM_RINKEBY, + DAI_BSC, DAI_GÖRLI, DAI_KOVAN, DAI_MAINNET, @@ -17,6 +18,7 @@ import { DAI_ROPSTEN, USDC_ARBITRUM, USDC_ARBITRUM_GOERLI, + USDC_BSC, USDC_ETHEREUM_GNOSIS, USDC_GÖRLI, USDC_KOVAN, @@ -28,6 +30,7 @@ import { USDC_ROPSTEN, USDT_ARBITRUM, USDT_ARBITRUM_RINKEBY, + USDT_BSC, USDT_GÖRLI, USDT_KOVAN, USDT_MAINNET, @@ -73,6 +76,7 @@ export const usdGasTokensByChain: { [chainId in ChainId]?: Token[] } = { [ChainId.CELO_ALFAJORES]: [CUSD_CELO_ALFAJORES], [ChainId.GNOSIS]: [USDC_ETHEREUM_GNOSIS], [ChainId.MOONBEAM]: [USDC_MOONBEAM], + [ChainId.BSC]: [USDT_BSC, USDC_BSC, DAI_BSC], }; export type L1ToL2GasCosts = { diff --git a/src/routers/alpha-router/gas-models/v3/gas-costs.ts b/src/routers/alpha-router/gas-models/v3/gas-costs.ts index 7b8ec8132..708a0c002 100644 --- a/src/routers/alpha-router/gas-models/v3/gas-costs.ts +++ b/src/routers/alpha-router/gas-models/v3/gas-costs.ts @@ -14,6 +14,7 @@ export const BASE_SWAP_COST = (id: ChainId): BigNumber => { case ChainId.GÖRLI: case ChainId.OPTIMISM: case ChainId.OPTIMISTIC_KOVAN: + case ChainId.BSC: case ChainId.KOVAN: return BigNumber.from(2000); case ChainId.ARBITRUM_ONE: @@ -41,6 +42,7 @@ export const COST_PER_INIT_TICK = (id: ChainId): BigNumber => { case ChainId.ROPSTEN: case ChainId.RINKEBY: case ChainId.GÖRLI: + case ChainId.BSC: case ChainId.KOVAN: return BigNumber.from(31000); case ChainId.OPTIMISM: @@ -70,6 +72,7 @@ export const COST_PER_HOP = (id: ChainId): BigNumber => { case ChainId.RINKEBY: case ChainId.GÖRLI: case ChainId.KOVAN: + case ChainId.BSC: case ChainId.OPTIMISM: case ChainId.OPTIMISTIC_KOVAN: return BigNumber.from(80000); diff --git a/src/routers/legacy-router/bases.ts b/src/routers/legacy-router/bases.ts index 60fa86e55..5aed125b0 100644 --- a/src/routers/legacy-router/bases.ts +++ b/src/routers/legacy-router/bases.ts @@ -1,13 +1,20 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ import { Token } from '@uniswap/sdk-core'; import { + BTC_BSC, + BUSD_BSC, + DAI_BSC, DAI_MAINNET, ITokenProvider, + USDC_BSC, USDC_MAINNET, + USDT_BSC, USDT_MAINNET, WBTC_MAINNET, WMATIC_POLYGON, WMATIC_POLYGON_MUMBAI, + } from '../../providers/token-provider'; import { ChainId, WRAPPED_NATIVE_CURRENCY } from '../../util/chains'; @@ -47,6 +54,14 @@ export const BASES_TO_CHECK_TRADES_AGAINST = ( [ChainId.CELO_ALFAJORES]: [WRAPPED_NATIVE_CURRENCY[ChainId.CELO_ALFAJORES]], [ChainId.GNOSIS]: [WRAPPED_NATIVE_CURRENCY[ChainId.GNOSIS]], [ChainId.MOONBEAM]: [WRAPPED_NATIVE_CURRENCY[ChainId.MOONBEAM]], + [ChainId.BSC]: [ + WRAPPED_NATIVE_CURRENCY[ChainId.BSC]!, + BUSD_BSC, + DAI_BSC, + USDC_BSC, + USDT_BSC, + BTC_BSC, + ], }; }; diff --git a/src/routers/legacy-router/legacy-router.ts b/src/routers/legacy-router/legacy-router.ts index dc31c376a..87b18663c 100644 --- a/src/routers/legacy-router/legacy-router.ts +++ b/src/routers/legacy-router/legacy-router.ts @@ -13,7 +13,7 @@ import { USDC_MAINNET, } from '../../providers/token-provider'; import { IV3PoolProvider } from '../../providers/v3/pool-provider'; -import { SWAP_ROUTER_02_ADDRESS } from '../../util'; +import { SWAP_ROUTER_02_ADDRESSES } from '../../util'; import { CurrencyAmount } from '../../util/amounts'; import { ChainId } from '../../util/chains'; import { log } from '../../util/log'; @@ -141,7 +141,7 @@ export class LegacyRouter { methodParameters: swapConfig ? { ...this.buildMethodParameters(trade, swapConfig), - to: SWAP_ROUTER_02_ADDRESS, + to: SWAP_ROUTER_02_ADDRESSES(this.chainId), } : undefined, blockNumber: BigNumber.from(0), @@ -196,7 +196,7 @@ export class LegacyRouter { methodParameters: swapConfig ? { ...this.buildMethodParameters(trade, swapConfig), - to: SWAP_ROUTER_02_ADDRESS, + to: SWAP_ROUTER_02_ADDRESSES(this.chainId), } : undefined, blockNumber: BigNumber.from(0), diff --git a/src/util/addresses.ts b/src/util/addresses.ts index 689ff659f..90e6f9315 100644 --- a/src/util/addresses.ts +++ b/src/util/addresses.ts @@ -15,12 +15,26 @@ const ARBITRUM_GOERLI_QUOTER_ADDRESSES = const ARBITRUM_GOERLI_MULTICALL_ADDRESS = '0x8260CB40247290317a4c062F3542622367F206Ee'; +const BSC_V3_CORE_FACTORY_ADDRESSES = + '0x128Ce3A3D48f27CE35A3F810cF2cddD2f6879b13'; +const BSC_QUOTER_ADDRESSES = '0xD00bD441CEF3623dC59B5D9b5EF96ee87b42Db42'; +const BSC_MULTICALL_ADDRESS = '0x581e2A6eF5e2032ACD1Eb0263ac8087fa2aEF41f'; + +export const BSC_TICK_LENS_ADDRESS = + '0xf5F4496219F31CDCBa6130B5402873624585615a'; +export const BSC_NONFUNGIBLE_POSITION_MANAGER_ADDRESS = + '0x71479Cf279BC2Fcf5b8faA8C9eeD2Ab59127aB95'; +export const BSC_SWAP_ROUTER_02_ADDRESS = + '0xa64Dd3A63fEed608660226112E748F93B87E650F'; +export const BSC_V3_MIGRATOR_ADDRESS = + '0xB3Abf5790a6F6706F16CBdE1e7de893F3C5746fC'; + export const V3_CORE_FACTORY_ADDRESSES: AddressMap = { ...constructSameAddressMap(FACTORY_ADDRESS), [ChainId.CELO]: CELO_V3_CORE_FACTORY_ADDRESSES, [ChainId.CELO_ALFAJORES]: CELO_V3_CORE_FACTORY_ADDRESSES, - [ChainId.ARBITRUM_GOERLI]: ARBITRUM_GOERLI_V3_CORE_FACTORY_ADDRESSES, + [ChainId.BSC]: BSC_V3_CORE_FACTORY_ADDRESSES, // TODO: Gnosis + Moonbeam contracts to be deployed }; @@ -28,8 +42,8 @@ export const QUOTER_V2_ADDRESSES: AddressMap = { ...constructSameAddressMap('0x61fFE014bA17989E743c5F6cB21bF9697530B21e'), [ChainId.CELO]: CELO_QUOTER_ADDRESSES, [ChainId.CELO_ALFAJORES]: CELO_QUOTER_ADDRESSES, - [ChainId.ARBITRUM_GOERLI]: ARBITRUM_GOERLI_QUOTER_ADDRESSES, + [ChainId.BSC]: BSC_QUOTER_ADDRESSES, // TODO: Gnosis + Moonbeam contracts to be deployed }; @@ -44,20 +58,33 @@ export const UNISWAP_MULTICALL_ADDRESSES: AddressMap = { ...constructSameAddressMap('0x1F98415757620B543A52E61c46B32eB19261F984'), [ChainId.CELO]: CELO_MULTICALL_ADDRESS, [ChainId.CELO_ALFAJORES]: CELO_MULTICALL_ADDRESS, - [ChainId.ARBITRUM_GOERLI]: ARBITRUM_GOERLI_MULTICALL_ADDRESS, + [ChainId.BSC]: BSC_MULTICALL_ADDRESS, // TODO: Gnosis + Moonbeam contracts to be deployed }; +// export const SWAP_ROUTER_02_ADDRESSES: AddressMap = { +// ...constructSameAddressMap('0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45'), +// // TODO: not sure if swapRouter02 is deployed on Celo, Alfajores, and Arb Goerli +// [ChainId.CELO]: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45', +// [ChainId.CELO_ALFAJORES]: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45', +// [ChainId.ARBITRUM_GOERLI]: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45', +// [ChainId.BSC]: BSC_SWAP_ROUTER_02_ADDRESS, +// }; + +export const SWAP_ROUTER_02_ADDRESSES = (chainId: number) => { + if (chainId == ChainId.BSC) { + return BSC_SWAP_ROUTER_02_ADDRESS; + } + return '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45'; +}; + export const OVM_GASPRICE_ADDRESS = '0x420000000000000000000000000000000000000F'; export const ARB_GASINFO_ADDRESS = '0x000000000000000000000000000000000000006C'; - export const TICK_LENS_ADDRESS = '0xbfd8137f7d1516D3ea5cA83523914859ec47F573'; export const NONFUNGIBLE_POSITION_MANAGER_ADDRESS = '0xC36442b4a4522E871399CD717aBDD847Ab11FE88'; -export const SWAP_ROUTER_02_ADDRESS = - '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45'; export const V3_MIGRATOR_ADDRESS = '0xA5644E29708357803b5A882D272c41cC0dF92B34'; export const MULTICALL2_ADDRESS = '0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696'; @@ -86,6 +113,7 @@ export const WETH9: { | ChainId.CELO_ALFAJORES | ChainId.GNOSIS | ChainId.MOONBEAM + | ChainId.BSC >]: Token; } = { [ChainId.MAINNET]: new Token( diff --git a/src/util/chains.ts b/src/util/chains.ts index 140770b47..7ebcc97ed 100644 --- a/src/util/chains.ts +++ b/src/util/chains.ts @@ -1,5 +1,6 @@ import { Currency, Ether, NativeCurrency, Token } from '@uniswap/sdk-core'; + export enum ChainId { MAINNET = 1, ROPSTEN = 3, @@ -17,6 +18,7 @@ export enum ChainId { CELO_ALFAJORES = 44787, GNOSIS = 100, MOONBEAM = 1284, + BSC = 56, } // WIP: Gnosis, Moonbeam @@ -35,6 +37,7 @@ export const SUPPORTED_CHAINS: ChainId[] = [ ChainId.GÖRLI, ChainId.CELO_ALFAJORES, ChainId.CELO, + ChainId.BSC, // Gnosis and Moonbeam don't yet have contracts deployed yet ]; @@ -80,6 +83,8 @@ export const ID_TO_CHAIN_ID = (id: number): ChainId => { return ChainId.GÖRLI; case 42: return ChainId.KOVAN; + case 56: + return ChainId.BSC; case 10: return ChainId.OPTIMISM; case 69: @@ -124,8 +129,10 @@ export enum ChainName { CELO_ALFAJORES = 'celo-alfajores', GNOSIS = 'gnosis-mainnet', MOONBEAM = 'moonbeam-mainnet', + BSC = 'bsc-mainnet', } + export enum NativeCurrencyName { // Strings match input for CLI ETHER = 'ETH', @@ -133,6 +140,7 @@ export enum NativeCurrencyName { CELO = 'CELO', GNOSIS = 'XDAI', MOONBEAM = 'GLMR', + BNB = "BNB", } export const NATIVE_NAMES_BY_ID: { [chainId: number]: string[] } = { [ChainId.MAINNET]: [ @@ -185,7 +193,9 @@ export const NATIVE_NAMES_BY_ID: { [chainId: number]: string[] } = { 'ETHER', '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', ], - [ChainId.POLYGON]: ['MATIC', '0x0000000000000000000000000000000000001010'], + [ChainId.POLYGON]: [ + 'MATIC', '0x0000000000000000000000000000000000001010' + ], [ChainId.POLYGON_MUMBAI]: [ 'MATIC', '0x0000000000000000000000000000000000001010', @@ -194,6 +204,11 @@ export const NATIVE_NAMES_BY_ID: { [chainId: number]: string[] } = { [ChainId.CELO_ALFAJORES]: ['CELO'], [ChainId.GNOSIS]: ['XDAI'], [ChainId.MOONBEAM]: ['GLMR'], + [ChainId.BSC]: [ + 'BNB', + 'BNB', + '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + ], }; export const NATIVE_CURRENCY: { [chainId: number]: NativeCurrencyName } = { @@ -213,6 +228,7 @@ export const NATIVE_CURRENCY: { [chainId: number]: NativeCurrencyName } = { [ChainId.CELO_ALFAJORES]: NativeCurrencyName.CELO, [ChainId.GNOSIS]: NativeCurrencyName.GNOSIS, [ChainId.MOONBEAM]: NativeCurrencyName.MOONBEAM, + [ChainId.BSC]: NativeCurrencyName.BNB, }; export const ID_TO_NETWORK_NAME = (id: number): ChainName => { @@ -227,6 +243,8 @@ export const ID_TO_NETWORK_NAME = (id: number): ChainName => { return ChainName.GÖRLI; case 42: return ChainName.KOVAN; + case 56: + return ChainName.BSC; case 10: return ChainName.OPTIMISM; case 69: @@ -288,6 +306,8 @@ export const ID_TO_PROVIDER = (id: ChainId): string => { return process.env.JSON_RPC_PROVIDER_CELO!; case ChainId.CELO_ALFAJORES: return process.env.JSON_RPC_PROVIDER_CELO_ALFAJORES!; + case ChainId.BSC: + return process.env.JSON_RPC_PROVIDER_BSC!; default: throw new Error(`Chain id: ${id} not supported`); } @@ -329,6 +349,13 @@ export const WRAPPED_NATIVE_CURRENCY: { [chainId in ChainId]: Token } = { 'WETH', 'Wrapped Ether' ), + [ChainId.BSC]: new Token( + 56, + '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c', + 18, + 'WBNB', + 'Wrapped BNB' + ), [ChainId.OPTIMISM]: new Token( ChainId.OPTIMISM, '0x4200000000000000000000000000000000000006', @@ -486,6 +513,30 @@ class GnosisNativeCurrency extends NativeCurrency { } } +function isBsc(chainId: number): chainId is ChainId.BSC { + return chainId === ChainId.BSC; +} + +class BscNativeCurrency extends NativeCurrency { + equals(other: Currency): boolean { + return other.isNative && other.chainId === this.chainId; + } + + get wrapped(): Token { + if (!isBsc(this.chainId)) throw new Error('Not bnb'); + 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 (!isBsc(chainId)) throw new Error('Not bnb'); + super(chainId, 18, 'BNB', 'BNB'); + } +} + function isMoonbeam(chainId: number): chainId is ChainId.MOONBEAM { return chainId === ChainId.MOONBEAM; } @@ -540,6 +591,8 @@ export function nativeOnChain(chainId: number): NativeCurrency { cachedNativeCurrency[chainId] = new GnosisNativeCurrency(chainId); else if (isMoonbeam(chainId)) cachedNativeCurrency[chainId] = new MoonbeamNativeCurrency(chainId); + else if (isBsc(chainId)) + cachedNativeCurrency[chainId] = new BscNativeCurrency(chainId); else cachedNativeCurrency[chainId] = ExtendedEther.onChain(chainId); return cachedNativeCurrency[chainId]!; diff --git a/src/util/methodParameters.ts b/src/util/methodParameters.ts index 402e38cba..3dde054a2 100644 --- a/src/util/methodParameters.ts +++ b/src/util/methodParameters.ts @@ -19,9 +19,9 @@ import { MethodParameters, MixedRouteWithValidQuote, RouteWithValidQuote, - SWAP_ROUTER_02_ADDRESS, SwapOptions, SwapType, + SWAP_ROUTER_02_ADDRESSES, V2RouteWithValidQuote, V3RouteWithValidQuote, } from '..'; @@ -250,7 +250,7 @@ export function buildSwapMethodParameters( deadlineOrPreviousBlockhash: deadline, inputTokenPermit, }), - to: SWAP_ROUTER_02_ADDRESS, + to: SWAP_ROUTER_02_ADDRESSES(chainId), }; } diff --git a/test/integ/routers/alpha-router/alpha-router.integration.test.ts b/test/integ/routers/alpha-router/alpha-router.integration.test.ts index 91f31ace7..6ff4ddbcc 100644 --- a/test/integ/routers/alpha-router/alpha-router.integration.test.ts +++ b/test/integ/routers/alpha-router/alpha-router.integration.test.ts @@ -36,16 +36,19 @@ import { SimulationStatus, StaticGasPriceProvider, SUPPORTED_CHAINS, + // SUPPORTED_CHAINS, SwapOptions, SwapType, - SWAP_ROUTER_02_ADDRESS, + SWAP_ROUTER_02_ADDRESSES, TenderlySimulator, UniswapMulticallProvider, UNI_GÖRLI, UNI_MAINNET, + USDC_BSC, USDC_ETHEREUM_GNOSIS, USDC_MAINNET, USDC_ON, + USDT_BSC, USDT_MAINNET, V2PoolProvider, V2Route, @@ -245,7 +248,7 @@ describe('alpha router integration', () => { } else { tokenInBefore = await getBalanceAndApprove( alice, - SWAP_ROUTER_02_ADDRESS, + SWAP_ROUTER_02_ADDRESSES(tokenIn.chainId), tokenIn ); tokenOutBefore = await hardhat.getBalance(alice._address, tokenOut); @@ -2530,6 +2533,7 @@ describe('quote for other networks', () => { [ChainId.CELO_ALFAJORES]: CUSD_CELO_ALFAJORES, [ChainId.GNOSIS]: WBTC_GNOSIS, [ChainId.MOONBEAM]: WBTC_MOONBEAM, + [ChainId.BSC]: USDC_BSC, }; const TEST_ERC20_2: { [chainId in ChainId]: Token } = { [ChainId.MAINNET]: DAI_ON(1), @@ -2548,6 +2552,7 @@ describe('quote for other networks', () => { [ChainId.CELO_ALFAJORES]: CEUR_CELO_ALFAJORES, [ChainId.GNOSIS]: USDC_ETHEREUM_GNOSIS, [ChainId.MOONBEAM]: WBTC_MOONBEAM, + [ChainId.BSC]: USDT_BSC, }; // TODO: Find valid pools/tokens on optimistic kovan and polygon mumbai. We skip those tests for now. @@ -2563,7 +2568,9 @@ describe('quote for other networks', () => { c != ChainId.ARBITRUM_GOERLI && c != ChainId.OPTIMISM && /// @dev infura has been having issues with optimism lately // Tests are failing https://github.com/Uniswap/smart-order-router/issues/104 - c != ChainId.CELO_ALFAJORES + c != ChainId.CELO_ALFAJORES && + // TODO: re-add BSC tests here once there is liquidity + c != ChainId.BSC )) { for (const tradeType of [TradeType.EXACT_INPUT, TradeType.EXACT_OUTPUT]) { const erc1 = TEST_ERC20_1[chain]; @@ -2687,8 +2694,8 @@ describe('quote for other networks', () => { ? parseAmount('10', tokenIn) : parseAmount('10', tokenOut) : tradeType == TradeType.EXACT_INPUT - ? parseAmount('100', tokenIn) - : parseAmount('100', tokenOut); + ? parseAmount('1', tokenIn) + : parseAmount('1', tokenOut); const swap = await alphaRouter.route( amount, @@ -2959,4 +2966,105 @@ describe('quote for other networks', () => { }); } } + + describe('BSC', () => { + const chain = ChainId.BSC; + for (const tradeType of [TradeType.EXACT_INPUT, TradeType.EXACT_OUTPUT]) { + describe(`${ID_TO_NETWORK_NAME(chain)} ${tradeType} 2xx`, function () { + const wrappedNative = WNATIVE_ON(chain); + + let alphaRouter: AlphaRouter; + + beforeAll(async () => { + const chainProvider = ID_TO_PROVIDER(chain); + const provider = new JsonRpcProvider(chainProvider, chain); + + const multicall2Provider = new UniswapMulticallProvider( + chain, + provider + ); + + alphaRouter = new AlphaRouter({ + chainId: chain, + provider, + multicall2Provider, + }); + }); + + it(`${wrappedNative.symbol} -> USDT`, async () => { + const tokenIn = wrappedNative; + const tokenOut = USDT_BSC; + const amount = + tradeType == TradeType.EXACT_INPUT + ? parseAmount('1', tokenIn) + : parseAmount('1', tokenOut); + + const swap = await alphaRouter.route( + amount, + getQuoteToken(tokenIn, tokenOut, tradeType), + tradeType, + undefined, + { + // @ts-ignore[TS7053] - complaining about switch being non exhaustive + ...DEFAULT_ROUTING_CONFIG_BY_CHAIN[chain], + protocols: [Protocol.V3, Protocol.V2], + } + ); + expect(swap).toBeDefined(); + expect(swap).not.toBeNull(); + + // Scope limited for non mainnet network tests to validating the swap + }); + + it(`USDC -> USDT`, async () => { + const tokenIn = USDC_BSC; + const tokenOut = USDT_BSC; + const amount = + tradeType == TradeType.EXACT_INPUT + ? parseAmount('100', tokenIn) + : parseAmount('100', tokenOut); + + const swap = await alphaRouter.route( + amount, + getQuoteToken(tokenIn, tokenOut, tradeType), + tradeType, + undefined, + { + // @ts-ignore[TS7053] - complaining about switch being non exhaustive + ...DEFAULT_ROUTING_CONFIG_BY_CHAIN[chain], + protocols: [Protocol.V3, Protocol.V2], + } + ); + expect(swap).toBeDefined(); + expect(swap).not.toBeNull(); + }); + + const native = NATIVE_CURRENCY[chain]; + + it(`${native} -> USDT`, async () => { + const tokenIn = nativeOnChain(chain); + const tokenOut = USDT_BSC; + + const amount = + tradeType == TradeType.EXACT_INPUT + ? parseAmount('1', tokenIn) + : parseAmount('1', tokenOut); + + const swap = await alphaRouter.route( + amount, + getQuoteToken(tokenIn, tokenOut, tradeType), + tradeType, + undefined, + { + // @ts-ignore[TS7053] - complaining about switch being non exhaustive + ...DEFAULT_ROUTING_CONFIG_BY_CHAIN[chain], + protocols: [Protocol.V3, Protocol.V2], + } + ); + expect(swap).toBeDefined(); + expect(swap).not.toBeNull(); + }); + }); + } + }); });