From 2fc0d9378902fe7c3abf7393a443b82cff067f84 Mon Sep 17 00:00:00 2001
From: micaelae <100321200+micaelae@users.noreply.github.com>
Date: Thu, 23 Mar 2023 10:24:10 -0700
Subject: [PATCH] Disable Bridge button on unsupported networks (#18268)
---
shared/constants/bridge.ts | 10 ++++
.../app/wallet-overview/eth-overview.js | 43 +++++++++++------
.../app/wallet-overview/eth-overview.test.js | 46 +++++++++++++++++--
ui/components/ui/icon-button/icon-button.scss | 1 +
ui/selectors/selectors.js | 7 +++
ui/selectors/selectors.test.js | 10 ++++
6 files changed, 101 insertions(+), 16 deletions(-)
create mode 100644 shared/constants/bridge.ts
diff --git a/shared/constants/bridge.ts b/shared/constants/bridge.ts
new file mode 100644
index 000000000..a70c0a62a
--- /dev/null
+++ b/shared/constants/bridge.ts
@@ -0,0 +1,10 @@
+import { CHAIN_IDS } from './network';
+
+export const ALLOWED_BRIDGE_CHAIN_IDS = [
+ CHAIN_IDS.MAINNET,
+ CHAIN_IDS.BSC,
+ CHAIN_IDS.POLYGON,
+ CHAIN_IDS.AVALANCHE,
+ CHAIN_IDS.OPTIMISM,
+ CHAIN_IDS.ARBITRUM,
+];
diff --git a/ui/components/app/wallet-overview/eth-overview.js b/ui/components/app/wallet-overview/eth-overview.js
index a02c8459d..12e69b59b 100644
--- a/ui/components/app/wallet-overview/eth-overview.js
+++ b/ui/components/app/wallet-overview/eth-overview.js
@@ -19,6 +19,7 @@ import {
getCurrentKeyring,
getSwapsDefaultToken,
getIsSwapsChain,
+ getIsBridgeChain,
getIsBuyableChain,
getNativeCurrencyImage,
getSelectedAccountCachedBalance,
@@ -56,6 +57,7 @@ const EthOverview = ({ className }) => {
const showFiat = useSelector(getShouldShowFiat);
const balance = useSelector(getSelectedAccountCachedBalance);
const isSwapsChain = useSelector(getIsSwapsChain);
+ const isBridgeChain = useSelector(getIsBridgeChain);
const isBuyableChain = useSelector(getIsBuyableChain);
const primaryTokenImage = useSelector(getNativeCurrencyImage);
const defaultSwapsToken = useSelector(getSwapsDefaultToken);
@@ -232,26 +234,41 @@ const EthOverview = ({ className }) => {
/>
}
label={t('bridge')}
onClick={() => {
- const portfolioUrl = process.env.PORTFOLIO_URL;
- const bridgeUrl = `${portfolioUrl}/bridge`;
- global.platform.openTab({
- url: `${bridgeUrl}?metamaskEntry=ext`,
- });
- trackEvent({
- category: EVENT.CATEGORIES.NAVIGATION,
- event: EVENT_NAMES.BRIDGE_LINK_CLICKED,
- properties: {
- location: 'Home',
- text: 'Bridge',
- },
- });
+ if (isBridgeChain) {
+ const portfolioUrl = process.env.PORTFOLIO_URL;
+ const bridgeUrl = `${portfolioUrl}/bridge`;
+ global.platform.openTab({
+ url: `${bridgeUrl}?metamaskEntry=ext`,
+ });
+ trackEvent({
+ category: EVENT.CATEGORIES.NAVIGATION,
+ event: EVENT_NAMES.BRIDGE_LINK_CLICKED,
+ properties: {
+ location: 'Home',
+ text: 'Bridge',
+ },
+ });
+ }
}}
+ tooltipRender={
+ isBridgeChain
+ ? null
+ : (contents) => (
+
+ {contents}
+
+ )
+ }
/>
>
}
diff --git a/ui/components/app/wallet-overview/eth-overview.test.js b/ui/components/app/wallet-overview/eth-overview.test.js
index c73377199..3d4f459c1 100644
--- a/ui/components/app/wallet-overview/eth-overview.test.js
+++ b/ui/components/app/wallet-overview/eth-overview.test.js
@@ -145,13 +145,30 @@ describe('EthOverview', () => {
expect(secondaryBalance).toHaveTextContent('0');
});
- it('should always show the Bridge button', () => {
- const { queryByTestId } = renderWithProvider(, store);
+ it('should have the Bridge button enabled if chain id is part of supported chains', () => {
+ const mockedAvalancheStore = {
+ ...mockStore,
+ metamask: {
+ ...mockStore.metamask,
+ provider: { ...mockStore.metamask.provider, chainId: '0xa86a' },
+ },
+ };
+ const mockedStore = configureMockStore([thunk])(mockedAvalancheStore);
+
+ const { queryByTestId, queryByText } = renderWithProvider(
+ ,
+ mockedStore,
+ );
const bridgeButton = queryByTestId(ETH_OVERVIEW_BRIDGE);
expect(bridgeButton).toBeInTheDocument();
+ expect(bridgeButton).toBeEnabled();
+ expect(queryByText('Bridge').parentElement).not.toHaveAttribute(
+ 'data-original-title',
+ 'Unavailable on this network',
+ );
});
- it('should open the Bridge URI when clicking on Bridge button', async () => {
+ it('should open the Bridge URI when clicking on Bridge button on supported network', async () => {
const { queryByTestId } = renderWithProvider(, store);
const bridgeButton = queryByTestId(ETH_OVERVIEW_BRIDGE);
@@ -169,6 +186,29 @@ describe('EthOverview', () => {
);
});
+ it('should have the Bridge button disabled if chain id is not part of supported chains', () => {
+ const mockedFantomStore = {
+ ...mockStore,
+ metamask: {
+ ...mockStore.metamask,
+ provider: { ...mockStore.metamask.provider, chainId: '0xfa' },
+ },
+ };
+ const mockedStore = configureMockStore([thunk])(mockedFantomStore);
+
+ const { queryByTestId, queryByText } = renderWithProvider(
+ ,
+ mockedStore,
+ );
+ const bridgeButton = queryByTestId(ETH_OVERVIEW_BRIDGE);
+ expect(bridgeButton).toBeInTheDocument();
+ expect(bridgeButton).toBeDisabled();
+ expect(queryByText('Bridge').parentElement).toHaveAttribute(
+ 'data-original-title',
+ 'Unavailable on this network',
+ );
+ });
+
it('should always show the Portfolio button', () => {
const { queryByTestId } = renderWithProvider(, store);
const portfolioButton = queryByTestId(ETH_OVERVIEW_PORTFOLIO);
diff --git a/ui/components/ui/icon-button/icon-button.scss b/ui/components/ui/icon-button/icon-button.scss
index 4ce70027c..8769d532c 100644
--- a/ui/components/ui/icon-button/icon-button.scss
+++ b/ui/components/ui/icon-button/icon-button.scss
@@ -22,6 +22,7 @@
border-radius: 18px;
margin-top: 6px;
margin-bottom: 5px;
+ margin-inline: auto;
}
&--disabled {
diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js
index dea043e15..425107475 100644
--- a/ui/selectors/selectors.js
+++ b/ui/selectors/selectors.js
@@ -41,6 +41,8 @@ import {
ALLOWED_DEV_SWAPS_CHAIN_IDS,
} from '../../shared/constants/swaps';
+import { ALLOWED_BRIDGE_CHAIN_IDS } from '../../shared/constants/bridge';
+
import {
shortenAddress,
getAccountByAddress,
@@ -750,6 +752,11 @@ export function getIsSwapsChain(state) {
: ALLOWED_DEV_SWAPS_CHAIN_IDS.includes(chainId);
}
+export function getIsBridgeChain(state) {
+ const chainId = getCurrentChainId(state);
+ return ALLOWED_BRIDGE_CHAIN_IDS.includes(chainId);
+}
+
export function getIsBuyableChain(state) {
const chainId = getCurrentChainId(state);
return Object.keys(BUYABLE_CHAINS_MAP).includes(chainId);
diff --git a/ui/selectors/selectors.test.js b/ui/selectors/selectors.test.js
index f3593f937..f1f7bfe5e 100644
--- a/ui/selectors/selectors.test.js
+++ b/ui/selectors/selectors.test.js
@@ -390,4 +390,14 @@ describe('Selectors', () => {
const isDesktopEnabled = selectors.getIsDesktopEnabled(mockState);
expect(isDesktopEnabled).toBeFalsy();
});
+
+ it('#getIsBridgeChain', () => {
+ mockState.metamask.provider.chainId = '0xa';
+ const isOptimismSupported = selectors.getIsBridgeChain(mockState);
+ expect(isOptimismSupported).toBeTruthy();
+
+ mockState.metamask.provider.chainId = '0xfa';
+ const isFantomSupported = selectors.getIsBridgeChain(mockState);
+ expect(isFantomSupported).toBeFalsy();
+ });
});