diff --git a/public/icons/tokens/wxtz.svg b/public/icons/tokens/wxtz.svg index ea1bbeb8..84e23b56 100644 --- a/public/icons/tokens/wxtz.svg +++ b/public/icons/tokens/wxtz.svg @@ -1,4 +1,9 @@ - +tezos-logo-01 + + + + + diff --git a/src/components/MarketSwitcher.tsx b/src/components/MarketSwitcher.tsx index 1fe9f756..90717c2c 100644 --- a/src/components/MarketSwitcher.tsx +++ b/src/components/MarketSwitcher.tsx @@ -59,7 +59,7 @@ type MarketLogoProps = { export const MarketLogo = ({ size, logo, testChainName }: MarketLogoProps) => { return ( - + {testChainName && ( @@ -173,35 +173,36 @@ export const MarketSwitcher = () => { - {availableMarkets.map((marketId: CustomMarket) => { - const { market, network } = getMarketInfoById(marketId); - const marketNaming = getMarketHelpData(market.marketTitle); - return ( - - - - {marketNaming.name} {market.isFork ? 'Fork' : ''} - - - - {marketNaming.testChainName} - - - - ); - })} + {availableMarkets + .map((marketId: CustomMarket) => { + const { market, network } = getMarketInfoById(marketId); + const marketNaming = getMarketHelpData(market.marketTitle); + return ( + + + + {marketNaming.name} {market.isFork ? 'Fork' : ''} + + + + {marketNaming.testChainName} + + + + ); + })} ); }; diff --git a/src/components/TextWithTooltip.tsx b/src/components/TextWithTooltip.tsx index 47044578..c75f029f 100644 --- a/src/components/TextWithTooltip.tsx +++ b/src/components/TextWithTooltip.tsx @@ -27,7 +27,12 @@ export const TextWithTooltip = ({ const [open, setOpen] = useState(false); return ( - + {text && {text}} {children}} open={open} setOpen={setOpen}> diff --git a/src/components/primitives/WarningSnackbar.tsx b/src/components/primitives/WarningSnackbar.tsx new file mode 100644 index 00000000..454b14f9 --- /dev/null +++ b/src/components/primitives/WarningSnackbar.tsx @@ -0,0 +1,32 @@ +import { Alert, Snackbar } from '@mui/material' +import React from 'react' + +type TSnackbar = { + open: boolean; + message: string; +} + +type TProps = { + snackbar: TSnackbar; + handleCloseSnackbar: () => void; +} + +export default function WarningSnackbar({ snackbar, handleCloseSnackbar }: TProps) { + return ( + + + {snackbar.message} + + + ) +} diff --git a/src/components/transactions/FlowCommons/TxModalDetails.tsx b/src/components/transactions/FlowCommons/TxModalDetails.tsx index 67cb9df8..93e97177 100644 --- a/src/components/transactions/FlowCommons/TxModalDetails.tsx +++ b/src/components/transactions/FlowCommons/TxModalDetails.tsx @@ -144,8 +144,8 @@ export const DetailsNumberLineWithSub = ({ loading = false, }: DetailsNumberLineWithSubProps) => { return ( - - + + {loading ? ( <> diff --git a/src/helpers/toggle-mode.tsx b/src/helpers/toggle-mode.tsx new file mode 100644 index 00000000..ef55edef --- /dev/null +++ b/src/helpers/toggle-mode.tsx @@ -0,0 +1,10 @@ +export const toggleMode = () => { + const isTestnetEnabled = localStorage.getItem('testnetsEnabled') === 'true'; + const toggledTestnet = isTestnetEnabled ? "false" : "true"; + localStorage.setItem('testnetsEnabled', toggledTestnet); + + // Set window.location to trigger a page reload when navigating to the the dashboard + window.location.href = '/'; + + return toggledTestnet; +}; \ No newline at end of file diff --git a/src/hooks/useSnackbar.tsx b/src/hooks/useSnackbar.tsx new file mode 100644 index 00000000..c4d29950 --- /dev/null +++ b/src/hooks/useSnackbar.tsx @@ -0,0 +1,25 @@ +import { useState } from 'react'; + +const snackbarInit = { + open: false, + message: "" +} + +export default function useSnackbar() { + const [snackbar, setSnackbar] = useState(snackbarInit); + + function handleCloseSnackbar() { + setSnackbar(state => ({ ...state, open: false })); + } + + function handleOpenSnackbar({ message = "" }: { message: string }) { + setSnackbar({ open: true, message }); + } + + return { + snackbar, + setSnackbar, + handleCloseSnackbar, + handleOpenSnackbar + } +} \ No newline at end of file diff --git a/src/layouts/AppHeader.tsx b/src/layouts/AppHeader.tsx index d09fdcca..a92645da 100644 --- a/src/layouts/AppHeader.tsx +++ b/src/layouts/AppHeader.tsx @@ -21,6 +21,11 @@ import { NavItems } from './components/NavItems'; import { MobileMenu } from './MobileMenu'; import { SettingsMenu } from './SettingsMenu'; import WalletWidget from './WalletWidget'; +import { toggleMode } from 'src/helpers/toggle-mode'; +import { useWeb3Context } from 'src/libs/hooks/useWeb3Context'; +import { ChainId } from 'src/ui-config/networksConfig'; +import useSnackbar from 'src/hooks/useSnackbar'; +import WarningSnackbar from 'src/components/primitives/WarningSnackbar'; interface Props { children: React.ReactElement; @@ -40,6 +45,8 @@ export function AppHeader() { const { breakpoints } = useTheme(); const md = useMediaQuery(breakpoints.down('md')); const sm = useMediaQuery(breakpoints.down('sm')); + const { switchNetwork } = useWeb3Context(); + const { snackbar, handleCloseSnackbar, handleOpenSnackbar } = useSnackbar(); const [mobileMenuOpen, setMobileMenuOpen] = useState(false); const [walletWidgetOpen, setWalletWidgetOpen] = useState(false); @@ -56,72 +63,89 @@ export function AppHeader() { const headerHeight = 80; - const disableTestnet = () => { - localStorage.setItem('testnetsEnabled', 'false'); - // Set window.location to trigger a page reload when navigating to the the dashboard - window.location.href = '/'; + const handleNetworkSwitch = () => { + const isTestnetEnabled = localStorage.getItem('testnetsEnabled') === 'true'; + const newChainId = isTestnetEnabled ? ChainId.etherlink : ChainId.etherlink_testnet; + + switchNetwork(newChainId) + .then(toggleMode) + .catch(err => { + console.log('Switch network error => ', `"${err.code}"`) + if(err.code.toString() === "-32002") { + handleOpenSnackbar({ + message: "Resolve any pending requests from your wallet or try again!" + }); + } + }); }; const testnetTooltip = ( - Testnet mode is ON + {ENABLE_TESTNET && Testnet mode is ON} + {!ENABLE_TESTNET && Testnet mode is OFF} - The app is running in testnet mode. Learn how it works in{' '} + {ENABLE_TESTNET && + The app is running in testnet mode. Learn how it works in + } + {!ENABLE_TESTNET && + The app is running in mainnet mode. Learn how it works in + } FAQ. - ); return ( - - ({ - height: headerHeight, - position: 'sticky', - top: 0, - transition: theme.transitions.create('top'), - zIndex: theme.zIndex.appBar, - background: theme.palette.background.navbar, - padding: { - xs: mobileMenuOpen || walletWidgetOpen ? '8px 20px' : '8px 8px 8px 20px', - xsm: '8px 20px', - }, - display: 'flex', - alignItems: 'center', - flexDirection: 'space-between', - })} - > + <> + setMobileMenuOpen(false)} + component="header" + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + sx={(theme) => ({ + height: headerHeight, + position: 'sticky', + top: 0, + transition: theme.transitions.create('top'), + zIndex: theme.zIndex.appBar, + background: theme.palette.background.navbar, + padding: { + xs: mobileMenuOpen || walletWidgetOpen ? '8px 20px' : '8px 8px 8px 20px', + xsm: '8px 20px', + }, + display: 'flex', + alignItems: 'center', + flexDirection: 'space-between', + })} > - An SVG of the Superlend logo - - - {ENABLE_TESTNET && ( + setMobileMenuOpen(false)} + > + An SVG of the Superlend logo + + - )} - - - - - - - + - {!mobileMenuOpen && ( - - )} + + + - - - + - {!walletWidgetOpen && ( - - + )} + + + - )} - - + + {!walletWidgetOpen && ( + + + + )} + + + + ); } diff --git a/src/layouts/components/TestNetModeSwitcher.tsx b/src/layouts/components/TestNetModeSwitcher.tsx index 039d8fdf..6f18e1e7 100644 --- a/src/layouts/components/TestNetModeSwitcher.tsx +++ b/src/layouts/components/TestNetModeSwitcher.tsx @@ -1,29 +1,41 @@ import { Trans } from '@lingui/macro'; import { Box, FormControlLabel, ListItem, ListItemText, MenuItem, Switch } from '@mui/material'; -import React, { useState } from 'react'; +import React from 'react'; +import WarningSnackbar from 'src/components/primitives/WarningSnackbar'; +import { toggleMode } from 'src/helpers/toggle-mode'; +import useSnackbar from 'src/hooks/useSnackbar'; +import { useWeb3Context } from 'src/libs/hooks/useWeb3Context'; +import { ChainId } from 'src/ui-config/networksConfig'; + interface TestNetModeSwitcherProps { component?: typeof MenuItem | typeof ListItem; } export const TestNetModeSwitcher = ({ component = ListItem }: TestNetModeSwitcherProps) => { - // const testnetsEnabledId = 'testnetsEnabled'; - const testnetsEnabledLocalstorage = true; - // localStorage.getItem(testnetsEnabledId) === 'true' || false; - const [testnetsEnabled] = useState(testnetsEnabledLocalstorage); + const testnetEnabled = localStorage.getItem("testnetsEnabled") === 'true'; + const { snackbar, handleCloseSnackbar, handleOpenSnackbar } = useSnackbar(); + const { switchNetwork } = useWeb3Context(); + + const handleNetworkSwitch = () => { + const newChainId = testnetEnabled ? ChainId.etherlink : ChainId.etherlink_testnet; - const toggleTestnetsEnabled = () => { - // const newState = !testnetsEnabled; - // setTestnetsMode(!testnetsEnabled); - // localStorage.setItem(testnetsEnabledId, newState ? 'true' : 'false'); - // // Set window.location to trigger a page reload when navigating to the the dashboard - // window.location.href = '/'; + switchNetwork(newChainId) + .then(toggleMode) + .catch(err => { + console.log('Switch network error => ', `"${err.message}"`) + if (err.code.toString() === "-32002") { + handleOpenSnackbar({ + message: "Resolve any pending requests from your wallet or try again!" + }); + } + }); }; return ( } - label={testnetsEnabled ? 'On' : 'Off'} + label={testnetEnabled ? 'On' : 'Off'} labelPlacement="start" /> + ); }; diff --git a/src/libs/web3-data-provider/Web3Provider.tsx b/src/libs/web3-data-provider/Web3Provider.tsx index 0e73794b..b190dfc5 100644 --- a/src/libs/web3-data-provider/Web3Provider.tsx +++ b/src/libs/web3-data-provider/Web3Provider.tsx @@ -366,8 +366,10 @@ export const Web3ContextProvider: React.FC<{ children: ReactElement }> = ({ chil } } else if (switchError.code === 4001) { setSwitchNetworkError(undefined); + throw switchError; } else { setSwitchNetworkError(switchError); + throw switchError; } } } diff --git a/src/modules/dashboard/lists/SupplyAssetsList/WalletEmptyInfo.tsx b/src/modules/dashboard/lists/SupplyAssetsList/WalletEmptyInfo.tsx index 1952813c..6cabd0ad 100644 --- a/src/modules/dashboard/lists/SupplyAssetsList/WalletEmptyInfo.tsx +++ b/src/modules/dashboard/lists/SupplyAssetsList/WalletEmptyInfo.tsx @@ -16,6 +16,8 @@ type WalletEmptyInfoProps = Pick & { export function WalletEmptyInfo({ bridge, chainId, icon, sx, symbol }: WalletEmptyInfoProps) { const network = [ChainId.avalanche].includes(chainId) ? 'Ethereum & Bitcoin' : 'Ethereum'; + const isWstEth = symbol === 'wstETH'; + return ( {bridge ? ( @@ -24,12 +26,21 @@ export function WalletEmptyInfo({ bridge, chainId, icon, sx, symbol }: WalletEmp {{bridge.name}} to transfer your {network} assets. ) : ( - - Your wallet is empty. Purchase or transfer assets.{' '} - {symbol === 'wstETH' ? ( - Wrap your Lido stETH here. - ) : null} - + <> + + Your wallet is empty. Purchase or transfer assets.{' '} + + {isWstEth && + <> +
+ + + Wrap your Lido stETH here. + + + + } + )}
); diff --git a/src/modules/reserve-overview/BorrowInfo.tsx b/src/modules/reserve-overview/BorrowInfo.tsx index 04afc1ac..6df9645a 100644 --- a/src/modules/reserve-overview/BorrowInfo.tsx +++ b/src/modules/reserve-overview/BorrowInfo.tsx @@ -44,6 +44,7 @@ export const BorrowInfo = ({ display: 'flex', alignItems: 'center', flexWrap: 'wrap', + gap: '10px' }} > {showBorrowCapStatus ? ( diff --git a/src/ui-config/marketsConfig.tsx b/src/ui-config/marketsConfig.tsx index 9b840399..0cb83f4b 100644 --- a/src/ui-config/marketsConfig.tsx +++ b/src/ui-config/marketsConfig.tsx @@ -53,6 +53,7 @@ export type MarketDataType = { export enum CustomMarket { etherlink_testnet = 'etherlink_testnet', + etherlink = 'etherlink', } export const marketsData: { @@ -77,5 +78,25 @@ export const marketsData: { COLLECTOR: '0x250fB04547404729D22Eb8f9C498Da13E9980f2D', }, faucetUrl: 'https://faucet.etherlink.com', + }, + [CustomMarket.etherlink]: { + marketTitle: 'Etherlink', + chainId: 42793, //ChainId.etherlink, + v3: true, + enabledFeatures: { + liquiditySwap: false, + collateralRepay: false, + faucet: false, + }, + addresses: { + LENDING_POOL_ADDRESS_PROVIDER: '0x33cf76bcff795d3C3522B9EF539c10877D3C32dE'.toLowerCase(), + LENDING_POOL: '0xb12Ec57a854C2D6beE878ac803d84624f525226A', + WALLET_BALANCE_PROVIDER: '0xAB6e6CbCeA13870c809B93e1134747c0239c9B75', + UI_POOL_DATA_PROVIDER: '0xa412ab4428c6E5543661e463987485121a898943', + UI_INCENTIVE_DATA_PROVIDER: '0x8d254ECDb2FF209e00771A006814D5D74fbFf28C', + WETH_GATEWAY: '0x0d2304c30Fca9781dF8a4DC06A44f3f7c475dD1A', + COLLECTOR: '0x78466b9DC7023Ad14b955dCDf8BffD2888BCfcF0', + }, + faucetUrl: 'https://faucet.etherlink.com', }, } as const; \ No newline at end of file diff --git a/src/ui-config/networksConfig.ts b/src/ui-config/networksConfig.ts index f210f5dc..9fff00d8 100644 --- a/src/ui-config/networksConfig.ts +++ b/src/ui-config/networksConfig.ts @@ -51,11 +51,13 @@ export type BaseNetworkConfig = Omit; export enum ChainId { mainnet = 1, etherlink_testnet = 128123, + etherlink = 42793, } export const ChainIdToNetwork: Record = { 1: 'mainnet', 128123: 'etherlink_testnet', + 42793: 'etherlink', }; export const networkConfigs: Record = { @@ -84,7 +86,6 @@ export const networkConfigs: Record = { name: 'Etherlink Testnet', publicJsonRPCUrl: [ 'https://node.ghostnet.etherlink.com', - 'https://etherlink-rollup-testnet-archive.zeeve.net/Rdj3r1npGPHxcDcQvOT/rpc', ], baseUniswapAdapter: '0x0', baseAssetSymbol: 'XTZ', @@ -94,4 +95,19 @@ export const networkConfigs: Record = { isTestnet: true, networkLogoPath: '/icons/networks/etherlink.svg', }, + [ChainId.etherlink]: { + name: 'Etherlink', + publicJsonRPCUrl: [ + 'https://rpc.superlend.xyz', + 'https://plend-etherlink-mainnet-djs2w.zeeve.net/TuychDxGCScIED1nCk0m/rpc', + 'https://node.mainnet.etherlink.com' + ], + baseUniswapAdapter: '0x0', + baseAssetSymbol: 'XTZ', + wrappedBaseAssetSymbol: 'WXTZ', + baseAssetDecimals: 18, + explorerLink: 'https://explorer.etherlink.com', + isTestnet: false, + networkLogoPath: '/icons/networks/etherlink.svg', + }, } as const; diff --git a/src/utils/marketsAndNetworksConfig.ts b/src/utils/marketsAndNetworksConfig.ts index a378098b..cd9aaff8 100644 --- a/src/utils/marketsAndNetworksConfig.ts +++ b/src/utils/marketsAndNetworksConfig.ts @@ -22,9 +22,8 @@ export type Pool = { }; export const STAGING_ENV = process.env.NEXT_PUBLIC_ENV === 'staging'; -export const PROD_ENV = !process.env.NEXT_PUBLIC_ENV || process.env.NEXT_PUBLIC_ENV === 'prod'; -export const ENABLE_TESTNET = - PROD_ENV || global?.window?.localStorage.getItem('testnetsEnabled') === 'true'; +export const PROD_ENV = process.env.NEXT_PUBLIC_ENV === 'prod'; +export const ENABLE_TESTNET = global?.window?.localStorage.getItem('testnetsEnabled') === 'true'; // determines if forks should be shown const FORK_ENABLED = @@ -102,7 +101,7 @@ export function getSupportedChainIds(): number[] { if (STAGING_ENV || ENABLE_TESTNET) { return isTestnet; } - + return !isTestnet; }) .reduce(