diff --git a/package.json b/package.json index ba36c41e6..0bc0cfba9 100644 --- a/package.json +++ b/package.json @@ -166,7 +166,7 @@ "@types/wcag-contrast": "^3.0.0", "@typescript-eslint/eslint-plugin": "^5.21.0", "@typescript-eslint/parser": "^5.21.0", - "@uniswap/default-token-list": "^4.1.0", + "@uniswap/default-token-list": "^9.0.0", "@uniswap/v2-core": "1.0.0", "@uniswap/v3-core": "1.0.0", "@uniswap/v3-periphery": "^1.1.1", diff --git a/src/assets/svg/bnb-logo.svg b/src/assets/svg/bnb-logo.svg new file mode 100644 index 000000000..c5b47602a --- /dev/null +++ b/src/assets/svg/bnb-logo.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + diff --git a/src/components/Logo/hooks.ts b/src/components/Logo/hooks.ts index 9367de474..e4ee50030 100644 --- a/src/components/Logo/hooks.ts +++ b/src/components/Logo/hooks.ts @@ -33,7 +33,7 @@ export function useLogo(currency: LogoTableInput | undefined) { const invalidateSrc = useCallback(() => { const nextSrc = entry?.invalidateSrc() - nextSrc && setSrc(nextSrc.getUri()) + setSrc(nextSrc?.getUri()) }, [entry]) return { src, invalidateSrc } diff --git a/src/components/Logo/util.ts b/src/components/Logo/util.ts index 1705d7989..2b761310f 100644 --- a/src/components/Logo/util.ts +++ b/src/components/Logo/util.ts @@ -2,11 +2,12 @@ import { SupportedChainId } from 'constants/chains' import { isAddress } from 'utils' import EthereumLogo from '../../assets/images/ethereum-logo.png' +import BnbLogo from '../../assets/svg/bnb-logo.svg' import CeloLogo from '../../assets/svg/celo_logo.svg' import MaticLogo from '../../assets/svg/matic-token-icon.svg' import { LogoTableInput } from './LogoTable' -type Network = 'ethereum' | 'arbitrum' | 'optimism' | 'polygon' | 'celo' +type Network = 'ethereum' | 'arbitrum' | 'optimism' | 'polygon' | 'celo' | 'binance' function chainIdToNetworkName(networkId: SupportedChainId): Network | undefined { switch (networkId) { @@ -20,6 +21,8 @@ function chainIdToNetworkName(networkId: SupportedChainId): Network | undefined return 'polygon' case SupportedChainId.CELO: return 'celo' + case SupportedChainId.BNB: + return 'binance' default: return 'ethereum' } @@ -46,6 +49,8 @@ export function getNativeLogoURI(chainId: SupportedChainId = SupportedChainId.MA case SupportedChainId.CELO: case SupportedChainId.CELO_ALFAJORES: return CeloLogo + case SupportedChainId.BNB: + return BnbLogo default: return EthereumLogo } diff --git a/src/constants/chainInfo.ts b/src/constants/chainInfo.ts index b32bec0b3..d98069641 100644 --- a/src/constants/chainInfo.ts +++ b/src/constants/chainInfo.ts @@ -1,5 +1,6 @@ import ethereumLogoUrl from 'assets/images/ethereum-logo.png' import arbitrumLogoUrl from 'assets/svg/arbitrum_logo.svg' +import bnbLogo from 'assets/svg/bnb-logo.svg' import celoLogo from 'assets/svg/celo_logo.svg' import optimismLogoUrl from 'assets/svg/optimism_logo.svg' import polygonMaticLogo from 'assets/svg/polygon-matic-logo.svg' @@ -223,6 +224,19 @@ const CHAIN_INFO: ChainInfoMap = { color: '#35D07F', backgroundColor: '#34d07f1f', }, + [SupportedChainId.BNB]: { + networkType: NetworkType.L1, + blockWaitMsBeforeWarning: ms`10m`, + bridge: 'https://cbridge.celer.network/1/56', + docs: 'https://docs.bnbchain.org/', + explorer: 'https://bscscan.com/', + infoLink: 'https://info.uniswap.org/#/bnb/', + label: 'BNB Chain', + logoUrl: bnbLogo, + nativeCurrency: { name: 'BNB', symbol: 'BNB', decimals: 18 }, + color: '#F0B90B', + backgroundColor: '#F0B90B', + }, } export function getChainInfo(chainId: SupportedL1ChainId): L1ChainInfo diff --git a/src/constants/chains.ts b/src/constants/chains.ts index b36a673b8..cf530f941 100644 --- a/src/constants/chains.ts +++ b/src/constants/chains.ts @@ -19,6 +19,8 @@ export enum SupportedChainId { CELO = 42220, CELO_ALFAJORES = 44787, + + BNB = 56, } export enum ChainName { @@ -35,6 +37,7 @@ export enum ChainName { POLYGON_MUMBAI = 'polygon-mumbai', CELO = 'celo', CELO_ALFAJORES = 'celo-alfajores', + BNB = 'bnb', } export const CHAIN_NAMES_TO_IDS: { [chainName: string]: SupportedChainId } = { @@ -51,6 +54,7 @@ export const CHAIN_NAMES_TO_IDS: { [chainName: string]: SupportedChainId } = { [ChainName.OPTIMISM_GOERLI]: SupportedChainId.OPTIMISM_GOERLI, [ChainName.CELO]: SupportedChainId.CELO, [ChainName.CELO_ALFAJORES]: SupportedChainId.CELO_ALFAJORES, + [ChainName.BNB]: SupportedChainId.BNB, } /** @@ -66,6 +70,7 @@ export const SUPPORTED_GAS_ESTIMATE_CHAIN_IDS = [ SupportedChainId.OPTIMISM, SupportedChainId.ARBITRUM_ONE, SupportedChainId.CELO, + SupportedChainId.BNB, ] /** diff --git a/src/constants/jsonRpcEndpoints.ts b/src/constants/jsonRpcEndpoints.ts index 143c32798..7c7e97561 100644 --- a/src/constants/jsonRpcEndpoints.ts +++ b/src/constants/jsonRpcEndpoints.ts @@ -74,4 +74,16 @@ export const JSON_RPC_FALLBACK_ENDPOINTS: Record = { // "Safe" URLs 'https://alfajores-forno.celo-testnet.org', ], + [SupportedChainId.BNB]: [ + // "Safe" URLs + 'https://endpoints.omniatech.io/v1/bsc/mainnet/public', + 'https://bsc-mainnet.gateway.pokt.network/v1/lb/6136201a7bad1500343e248d', + 'https://1rpc.io/bnb', + 'https://bsc-dataseed3.binance.org', + 'https://bsc-dataseed2.defibit.io', + 'https://bsc-dataseed1.ninicoin.io', + 'https://binance.nodereal.io', + 'https://bsc-dataseed4.defibit.io', + 'https://rpc.ankr.com/bsc', + ], } diff --git a/src/constants/routing.ts b/src/constants/routing.ts index 02192581b..1336fe771 100644 --- a/src/constants/routing.ts +++ b/src/constants/routing.ts @@ -23,10 +23,12 @@ import { sETH2, SWISE, TRIBE, + USDC_BNB_CHAIN, USDC_MAINNET, USDC_POLYGON, USDT, USDT_ARBITRUM_ONE, + USDT_BNB_CHAIN, USDT_OPTIMISM, USDT_POLYGON, WBTC, @@ -84,6 +86,12 @@ export const BASES_TO_CHECK_TRADES_AGAINST: ChainTokenList = { PORTAL_USDC_CELO, PORTAL_ETH_CELO, ], + [SupportedChainId.BNB]: [ + nativeOnChain(SupportedChainId.BNB), + USDC_BNB_CHAIN, + USDT_BNB_CHAIN, + ...WRAPPED_NATIVE_CURRENCIES_ONLY[SupportedChainId.BNB], + ], } export const ADDITIONAL_BASES: { [chainId: number]: { [tokenAddress: string]: Token[] } } = { [SupportedChainId.MAINNET]: { diff --git a/src/constants/tokens.ts b/src/constants/tokens.ts index 615e5b3b3..df853c490 100644 --- a/src/constants/tokens.ts +++ b/src/constants/tokens.ts @@ -123,6 +123,13 @@ export const DAI_OPTIMISM = new Token( 'DAI', 'Dai stable coin' ) +export const USDC_BNB_CHAIN = new Token( + SupportedChainId.BNB, + '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d', + 18, + 'USDC', + 'USDC' +) export const USDC: { [chainId in SupportedChainId]: Token } = { [SupportedChainId.MAINNET]: USDC_MAINNET, [SupportedChainId.ARBITRUM_ONE]: USDC_ARBITRUM, @@ -137,6 +144,7 @@ export const USDC: { [chainId in SupportedChainId]: Token } = { [SupportedChainId.RINKEBY]: USDC_RINKEBY, [SupportedChainId.KOVAN]: USDC_KOVAN, [SupportedChainId.ROPSTEN]: USDC_ROPSTEN, + [SupportedChainId.BNB]: USDC_BNB_CHAIN, } export const DAI_POLYGON = new Token( SupportedChainId.POLYGON, @@ -335,6 +343,91 @@ export const CEUR_CELO_ALFAJORES = new Token( 'CEUR', 'Celo Euro Stablecoin' ) +export const USDT_BNB_CHAIN = new Token( + SupportedChainId.BNB, + '0x55d398326f99059fF775485246999027B3197955', + 18, + 'USDT', + 'USDT' +) + +export const ETH_BNB_CHAIN = new Token( + SupportedChainId.BNB, + '0x2170Ed0880ac9A755fd29B2688956BD959F933F8', + 18, + 'ETH', + 'Ethereum' +) + +export const MATIC_BNB_CHAIN = new Token( + SupportedChainId.BNB, + '0xCC42724C6683B7E57334c4E856f4c9965ED682bD', + 18, + 'MATIC', + 'Matic' +) + +export const FRAX_BNB_CHAIN = new Token( + SupportedChainId.BNB, + '0x90C97F71E18723b0Cf0dfa30ee176Ab653E89F40', + 18, + 'FRAX', + 'FRAX' +) + +export const BTC_BNB_CHAIN = new Token( + SupportedChainId.BNB, + '0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c', + 18, + 'BTCB', + 'BTCB' +) + +export const CAKE_BNB_CHAIN = new Token( + SupportedChainId.BNB, + '0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82', + 18, + 'CAKE', + 'Cake' +) + +export const BUSD_BNB_CHAIN = new Token( + SupportedChainId.BNB, + '0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56', + 18, + 'BUSD', + 'BUSD' +) + +export const DAI_BNB_CHAIN = new Token( + SupportedChainId.BNB, + '0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3', + 18, + 'DAI', + 'DAI' +) + +function isBnbChain(chainId: number): chainId is SupportedChainId.BNB { + return chainId === SupportedChainId.BNB +} + +class BnbChainNativeCurrency extends NativeCurrency { + equals(other: Currency): boolean { + return other.isNative && other.chainId === this.chainId + } + + get wrapped(): Token { + if (!isBnbChain(this.chainId)) throw new Error('Not BNB Chain') + const wrapped = WRAPPED_NATIVE_CURRENCY[this.chainId] + invariant(wrapped instanceof Token) + return wrapped + } + + public constructor(chainId: number) { + if (!isBnbChain(chainId)) throw new Error('Not BNB Chain') + super(chainId, 18, 'BNB', 'BNB') + } +} export const UNI: { [chainId: number]: Token } = { [SupportedChainId.MAINNET]: new Token(SupportedChainId.MAINNET, UNI_ADDRESS[1], 18, 'UNI', 'Uniswap'), @@ -390,6 +483,13 @@ export const WRAPPED_NATIVE_CURRENCY: { [chainId: number]: Token | undefined } = 'WMATIC', 'Wrapped MATIC' ), + [SupportedChainId.BNB]: new Token( + SupportedChainId.BNB, + '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c', + 18, + 'WBNB', + 'Wrapped BNB' + ), } export function isCelo(chainId: number): chainId is SupportedChainId.CELO | SupportedChainId.CELO_ALFAJORES { @@ -451,6 +551,8 @@ export function nativeOnChain(chainId: number): NativeCurrency | Token { nativeCurrency = new MaticNativeCurrency(chainId) } else if (isCelo(chainId)) { nativeCurrency = getCeloNativeCurrency(chainId) + } else if (isBnbChain(chainId)) { + nativeCurrency = new BnbChainNativeCurrency(chainId) } else { nativeCurrency = ExtendedEther.onChain(chainId) } diff --git a/src/hooks/web3/useJsonRpcUrlsMap.tsx b/src/hooks/web3/useJsonRpcUrlsMap.tsx index 43cb31392..3cea0ce7d 100644 --- a/src/hooks/web3/useJsonRpcUrlsMap.tsx +++ b/src/hooks/web3/useJsonRpcUrlsMap.tsx @@ -31,6 +31,7 @@ function toJsonRpcMap(getChainConnections: (chainId: SupportedChainId) => T): [SupportedChainId.OPTIMISM_GOERLI]: getChainConnections(SupportedChainId.OPTIMISM_GOERLI), [SupportedChainId.CELO]: getChainConnections(SupportedChainId.CELO), [SupportedChainId.CELO_ALFAJORES]: getChainConnections(SupportedChainId.CELO_ALFAJORES), + [SupportedChainId.BNB]: getChainConnections(SupportedChainId.BNB), } } diff --git a/src/state/routing/slice.ts b/src/state/routing/slice.ts index ae6e64e9b..c53d62c3b 100644 --- a/src/state/routing/slice.ts +++ b/src/state/routing/slice.ts @@ -82,7 +82,6 @@ export const routing = createApi({ protocols, }) if (typeof quote === 'string') return { data: quote as TradeQuoteResult } - const tradeResult = transformQuoteToTradeResult(args, quote) return { data: tradeResult } } catch (error: any) { diff --git a/src/utils/getExplorerLink.test.ts b/src/utils/getExplorerLink.test.ts index 03cfe8778..97a0da36e 100644 --- a/src/utils/getExplorerLink.test.ts +++ b/src/utils/getExplorerLink.test.ts @@ -36,4 +36,7 @@ describe('#getExplorerLink', () => { it('enum', () => { expect(getExplorerLink(4, 'abc', ExplorerDataType.ADDRESS)).toEqual('https://rinkeby.etherscan.io/address/abc') }) + it('bnb chain', () => { + expect(getExplorerLink(56, 'abc', ExplorerDataType.ADDRESS)).toEqual('https://bscscan.com/address/abc') + }) }) diff --git a/src/utils/getExplorerLink.ts b/src/utils/getExplorerLink.ts index 3f8f5e62e..4ad6ab6c4 100644 --- a/src/utils/getExplorerLink.ts +++ b/src/utils/getExplorerLink.ts @@ -12,6 +12,7 @@ const ETHERSCAN_PREFIXES: { [chainId: number]: string } = { [SupportedChainId.POLYGON]: 'https://polygonscan.com', [SupportedChainId.CELO]: 'https://celoscan.io', [SupportedChainId.CELO_ALFAJORES]: 'https://alfajores.celoscan.io', + [SupportedChainId.BNB]: 'https://bscscan.com', } export enum ExplorerDataType { diff --git a/yarn.lock b/yarn.lock index 741fd11f6..d33795d4b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3528,10 +3528,10 @@ resolved "https://registry.yarnpkg.com/@uniswap/default-token-list/-/default-token-list-2.2.0.tgz#d85a5c2520f57f4920bd989dfc9f01e1b701a567" integrity sha512-vFPWoGzDjHP4i2l7yLaober/lZMmzOZXXirVF8XNyfNzRxgmYCWKO6SzKtfEUwxpd3/KUebgdK55II4Mnak62A== -"@uniswap/default-token-list@^4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@uniswap/default-token-list/-/default-token-list-4.1.0.tgz#bbda8b946096f248b92809f71b77b4d407768796" - integrity sha512-NxFW4OhYpnAunD37CKDRadG5ujp3r6cYnfBzTD1Eq4jwdr3ULt01xGqGljq0SuGAGhTsD+bmR46vPg3TdDwW0g== +"@uniswap/default-token-list@^9.0.0": + version "9.0.0" + resolved "https://registry.yarnpkg.com/@uniswap/default-token-list/-/default-token-list-9.0.0.tgz#35e070095ac24d24ef03877842c5d46807b59c87" + integrity sha512-a62uqv5ApULDVEXCOursXIaEoxP4MtlzdNSiQikYl1x9RfsUAZXl9dBtCo2d1Ne+iS1THic1oCJMshNtT9Z0EQ== "@uniswap/lib@^4.0.1-alpha": version "4.0.1-alpha"