1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Move "Enable Opensea API" and "NFT Autodetect" into Security & Privacy settings (#20278)

* move opensea api and nft settings to security tab

* DS techdebt; experimental tab

* rerouting the NFT tab enable autodetect to setting

* reverting vscode settings and preferences.js

* Rerouting NFT tab autodetect setting banner link

* resolving settingsRef collision
This commit is contained in:
Victor Thomas 2023-08-02 18:46:36 -04:00 committed by GitHub
parent 6947133899
commit 97073e1907
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 367 additions and 347 deletions

View File

@ -2,7 +2,7 @@ import React from 'react';
import { useHistory } from 'react-router-dom';
import { BannerAlert } from '../../component-library';
import { useI18nContext } from '../../../hooks/useI18nContext';
import { EXPERIMENTAL_ROUTE } from '../../../helpers/constants/routes';
import { SECURITY_ROUTE } from '../../../helpers/constants/routes';
export default function NftsDetectionNotice() {
const t = useI18nContext();
@ -15,7 +15,7 @@ export default function NftsDetectionNotice() {
actionButtonLabel={t('selectNFTPrivacyPreference')}
actionButtonOnClick={(e) => {
e.preventDefault();
history.push(`${EXPERIMENTAL_ROUTE}#autodetect-nfts`);
history.push(`${SECURITY_ROUTE}#autodetect-nfts`);
}}
>
{t('newNFTDetectedMessage')}

View File

@ -14,7 +14,7 @@ import {
} from '../../../helpers/constants/design-system';
import { useI18nContext } from '../../../hooks/useI18nContext';
import { getIsMainnet, getUseNftDetection } from '../../../selectors';
import { EXPERIMENTAL_ROUTE } from '../../../helpers/constants/routes';
import { SECURITY_ROUTE } from '../../../helpers/constants/routes';
import {
checkAndUpdateAllNftsOwnershipStatus,
detectNfts,
@ -36,7 +36,7 @@ export default function NftsTab() {
useNftsCollections();
const onEnableAutoDetect = () => {
history.push(EXPERIMENTAL_ROUTE);
history.push(SECURITY_ROUTE);
};
const onRefresh = () => {

View File

@ -3,7 +3,7 @@ import { fireEvent, screen } from '@testing-library/react';
import reactRouterDom from 'react-router-dom';
import configureStore from '../../../store/store';
import { renderWithProvider } from '../../../../test/jest/rendering';
import { EXPERIMENTAL_ROUTE } from '../../../helpers/constants/routes';
import { SECURITY_ROUTE } from '../../../helpers/constants/routes';
import { setBackgroundConnection } from '../../../../test/jest';
import NftsTab from '.';
@ -218,7 +218,7 @@ describe('NFT Items', () => {
fireEvent.click(screen.queryByText('Turn on NFT detection in Settings'));
expect(historyPushMock).toHaveBeenCalledTimes(1);
expect(historyPushMock).toHaveBeenCalledWith(
`${EXPERIMENTAL_ROUTE}#autodetect-nfts`,
`${SECURITY_ROUTE}#autodetect-nfts`,
);
});
it('should not render the NFTs Detection Notice when currently selected network is Mainnet and currently selected account has no NFTs but use NFT autodetection preference is set to true', () => {
@ -292,7 +292,7 @@ describe('NFT Items', () => {
expect(historyPushMock).toHaveBeenCalledTimes(0);
fireEvent.click(screen.queryByText('Enable autodetect'));
expect(historyPushMock).toHaveBeenCalledTimes(1);
expect(historyPushMock).toHaveBeenCalledWith(EXPERIMENTAL_ROUTE);
expect(historyPushMock).toHaveBeenCalledWith(SECURITY_ROUTE);
});
});
});

View File

@ -213,6 +213,20 @@ export const SETTINGS_CONSTANTS = [
route: `${SECURITY_ROUTE}#ens-domains`,
icon: 'fa fa-lock',
},
{
tabMessage: (t) => t('securityAndPrivacy'),
sectionMessage: (t) => t('enableOpenSeaAPI'),
descriptionMessage: (t) => t('enableOpenSeaAPIDescription'),
route: `${SECURITY_ROUTE}#opensea-api`,
icon: 'fa fa-lock',
},
{
tabMessage: (t) => t('securityAndPrivacy'),
sectionMessage: (t) => t('useNftDetection'),
descriptionMessage: (t) => t('useNftDetectionDescription'),
route: `${SECURITY_ROUTE}#autodetect-nfts`,
icon: 'fa fa-lock',
},
{
tabMessage: (t) => t('alerts'),
sectionMessage: (t) => t('alertSettingsUnconnectedAccount'),
@ -336,20 +350,6 @@ export const SETTINGS_CONSTANTS = [
route: `${ABOUT_US_ROUTE}#beta-terms`,
iconName: IconName.Info,
},
{
tabMessage: (t) => t('experimental'),
sectionMessage: (t) => t('enableOpenSeaAPI'),
descriptionMessage: (t) => t('enableOpenSeaAPIDescription'),
route: `${EXPERIMENTAL_ROUTE}#opensea-api`,
icon: 'fa fa-flask',
},
{
tabMessage: (t) => t('experimental'),
sectionMessage: (t) => t('useNftDetection'),
descriptionMessage: (t) => t('useNftDetectionDescription'),
route: `${EXPERIMENTAL_ROUTE}#autodetect-nfts`,
icon: 'fa fa-flask',
},
{
tabMessage: (t) => t('advanced'),
sectionMessage: (t) => t('backupUserData'),

View File

@ -165,7 +165,7 @@ describe('Settings Search Utils', () => {
it('should get good security & privacy section number', () => {
expect(
getNumberOfSettingsInSection(t, t('securityAndPrivacy')),
).toStrictEqual(10);
).toStrictEqual(12);
});
it('should get good alerts section number', () => {
@ -178,7 +178,7 @@ describe('Settings Search Utils', () => {
it('should get good experimental section number', () => {
expect(getNumberOfSettingsInSection(t, t('experimental'))).toStrictEqual(
3,
1,
);
});

View File

@ -96,7 +96,7 @@ exports[`ExperimentalTab with desktop enabled renders ExperimentalTab component
</div>
</div>
<h4
class="box box--margin-top-1 box--margin-bottom-2 box--flex-direction-row typography typography--h4 typography--weight-bold typography--style-normal typography--color-text-alternative"
class="mm-box mm-text mm-text--heading-sm mm-text--font-weight-bold mm-box--margin-bottom-2 mm-box--color-text-alternative"
>
Privacy
</h4>
@ -112,24 +112,24 @@ exports[`ExperimentalTab with desktop enabled renders ExperimentalTab component
<div
class="settings-page__content-description"
>
<h6
class="box box--margin-top-1 box--margin-bottom-1 box--flex-direction-row typography typography--h6 typography--weight-normal typography--style-normal typography--color-text-alternative"
<p
class="mm-box mm-text mm-text--body-sm mm-box--color-text-alternative"
>
We use third-party APIs to detect and display risks involved in unsigned transaction and signature requests before you sign them. These services will have access to your unsigned transaction and signature requests, your account address, and your preferred language.
</h6>
<h6
class="box box--margin-top-3 box--margin-bottom-1 box--flex-direction-row typography typography--h6 typography--weight-normal typography--style-normal typography--color-text-alternative"
</p>
<p
class="mm-box mm-text mm-text--body-sm mm-box--margin-top-3 mm-box--margin-bottom-1 mm-box--color-text-alternative"
>
Select providers:
</h6>
</p>
<div
class="settings-page__content-item-col settings-page__content-item-col-open-sea"
>
<h5
class="box box--margin-top-1 box--flex-direction-row typography typography--h5 typography--weight-medium typography--style-normal typography--color-text-default"
<p
class="mm-box mm-text mm-text--body-md mm-text--font-weight-medium mm-box--margin-bottom-0 mm-box--color-text-default"
>
OpenSea + Blockaid (Beta)
</h5>
</p>
<label
class="toggle-button toggle-button--off"
tabindex="0"
@ -172,8 +172,8 @@ exports[`ExperimentalTab with desktop enabled renders ExperimentalTab component
</div>
</label>
</div>
<h6
class="box box--margin-bottom-1 box--flex-direction-row typography typography--h6 typography--weight-normal typography--style-normal typography--color-text-alternative"
<p
class="mm-box mm-text mm-text--body-sm mm-box--margin-top-0 mm-box--color-text-alternative"
>
<span>
@ -188,172 +188,12 @@ exports[`ExperimentalTab with desktop enabled renders ExperimentalTab component
.
</span>
</h6>
<h5
class="box box--margin-top-2 box--margin-bottom-1 box--flex-direction-row typography typography--h5 typography--weight-medium typography--style-normal typography--color-text-muted"
</p>
<p
class="mm-box mm-text mm-text--body-md mm-text--font-weight-medium mm-box--margin-top-2 mm-box--color-text-muted"
>
More providers coming soon
</h5>
</div>
</div>
</div>
<div
class="settings-page__content-row"
>
<div
class="settings-page__content-item"
>
<span>
Enable OpenSea API
</span>
<div
class="settings-page__content-description"
>
Use OpenSea's API to fetch NFT data. NFT auto-detection relies on OpenSea's API, and will not be available when this is turned off.
</div>
</div>
<div
class="settings-page__content-item"
>
<div
class="settings-page__content-item-col"
>
<label
class="toggle-button toggle-button--off"
tabindex="0"
>
<div
style="display: flex; width: 52px; align-items: center; justify-content: flex-start; position: relative; cursor: pointer; background-color: transparent; border: 0px; padding: 0px; user-select: none;"
>
<div
style="width: 40px; height: 24px; padding: 0px; border-radius: 26px; display: flex; align-items: center; justify-content: center; background-color: rgb(242, 244, 246);"
>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgb(250, 250, 250); margin-top: auto; margin-bottom: auto; line-height: 0; opacity: 0; width: 26px; height: 20px; left: 4px;"
/>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgba(255, 255, 255, 0.6); bottom: 0px; margin-top: auto; margin-bottom: auto; padding-right: 5px; line-height: 0; width: 26px; height: 20px; opacity: 1;"
/>
</div>
<div
style="position: absolute; height: 100%; top: 0px; left: 0px; display: flex; flex: 1; align-self: stretch; align-items: center; justify-content: flex-start;"
>
<div
style="width: 18px; height: 18px; display: flex; align-self: center; box-shadow: none; border-radius: 50%; box-sizing: border-box; position: relative; background-color: rgb(106, 115, 125); left: 3px;"
/>
</div>
<input
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: absolute; width: 1px;"
type="checkbox"
value="false"
/>
</div>
<div
class="toggle-button__status"
>
<span
class="toggle-button__label-off"
>
Off
</span>
<span
class="toggle-button__label-on"
>
On
</span>
</div>
</label>
</div>
</div>
</div>
<div
class="settings-page__content-row"
>
<div
class="settings-page__content-item"
>
<span>
Autodetect NFTs
</span>
<div
class="settings-page__content-description"
>
<p
class="mm-box mm-text mm-text--body-md mm-box--color-text-alternative"
>
We use third-party APIs to detect NFTs in your wallet, which means your IP address may be exposed to centralized servers. There are a few things to be cautious about when enabling this feature.
</p>
<ul
class="settings-page__content-unordered-list"
>
<li>
Your account address will be viewable to third-party APIs.
</li>
<li>
NFT metadata may contain links to scams or phishing sites.
</li>
<li>
Anyone can airdrop NFTs to your account. This can include offensive content that might be automatically displayed in your wallet.
</li>
</ul>
<p
class="mm-box mm-text mm-text--body-md mm-box--padding-top-4 mm-box--color-text-alternative"
>
Leave this feature off if you don't want the app to pull data from those services.
</p>
</div>
</div>
<div
class="settings-page__content-item"
>
<div
class="settings-page__content-item-col"
>
<label
class="toggle-button toggle-button--off"
tabindex="0"
>
<div
style="display: flex; width: 52px; align-items: center; justify-content: flex-start; position: relative; cursor: pointer; background-color: transparent; border: 0px; padding: 0px; user-select: none;"
>
<div
style="width: 40px; height: 24px; padding: 0px; border-radius: 26px; display: flex; align-items: center; justify-content: center; background-color: rgb(242, 244, 246);"
>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgb(250, 250, 250); margin-top: auto; margin-bottom: auto; line-height: 0; opacity: 0; width: 26px; height: 20px; left: 4px;"
/>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgba(255, 255, 255, 0.6); bottom: 0px; margin-top: auto; margin-bottom: auto; padding-right: 5px; line-height: 0; width: 26px; height: 20px; opacity: 1;"
/>
</div>
<div
style="position: absolute; height: 100%; top: 0px; left: 0px; display: flex; flex: 1; align-self: stretch; align-items: center; justify-content: flex-start;"
>
<div
style="width: 18px; height: 18px; display: flex; align-self: center; box-shadow: none; border-radius: 50%; box-sizing: border-box; position: relative; background-color: rgb(106, 115, 125); left: 3px;"
/>
</div>
<input
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: absolute; width: 1px;"
type="checkbox"
value="false"
/>
</div>
<div
class="toggle-button__status"
>
<span
class="toggle-button__label-off"
>
Off
</span>
<span
class="toggle-button__label-on"
>
On
</span>
</div>
</label>
</div>
</div>
</div>

View File

@ -6,15 +6,11 @@ import {
handleSettingsRefs,
} from '../../../helpers/utils/settings-search';
import { MetaMetricsEventCategory } from '../../../../shared/constants/metametrics';
import Typography from '../../../components/ui/typography/typography';
import { Text } from '../../../components/component-library';
import {
FONT_WEIGHT,
FontWeight,
TextColor,
///: BEGIN:ONLY_INCLUDE_IN(blockaid)
TextVariant,
///: END:ONLY_INCLUDE_IN
TypographyVariant,
} from '../../../helpers/constants/design-system';
///: BEGIN:ONLY_INCLUDE_IN(desktop)
import DesktopEnableButton from '../../../components/app/desktop-enable-button';
@ -27,10 +23,6 @@ export default class ExperimentalTab extends PureComponent {
};
static propTypes = {
useNftDetection: PropTypes.bool,
setUseNftDetection: PropTypes.func,
setOpenSeaEnabled: PropTypes.func,
openSeaEnabled: PropTypes.bool,
transactionSecurityCheckEnabled: PropTypes.bool,
setTransactionSecurityCheckEnabled: PropTypes.func,
///: BEGIN:ONLY_INCLUDE_IN(blockaid)
@ -65,7 +57,6 @@ export default class ExperimentalTab extends PureComponent {
const { t } = this.context;
const { securityAlertsEnabled, setSecurityAlertsEnabled } = this.props;
return (
<>
<Text
@ -141,94 +132,6 @@ export default class ExperimentalTab extends PureComponent {
}
///: END:ONLY_INCLUDE_IN
renderOpenSeaEnabledToggle() {
const { t } = this.context;
const {
openSeaEnabled,
setOpenSeaEnabled,
useNftDetection,
setUseNftDetection,
} = this.props;
return (
<>
<div ref={this.settingsRefs[0]} className="settings-page__content-row">
<div className="settings-page__content-item">
<span>{t('enableOpenSeaAPI')}</span>
<div className="settings-page__content-description">
{t('enableOpenSeaAPIDescription')}
</div>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<ToggleButton
value={openSeaEnabled}
onToggle={(value) => {
this.context.trackEvent({
category: MetaMetricsEventCategory.Settings,
event: 'Enabled/Disable OpenSea',
properties: {
action: 'Enabled/Disable OpenSea',
legacy_event: true,
},
});
// value is positive when being toggled off
if (value && useNftDetection) {
setUseNftDetection(false);
}
setOpenSeaEnabled(!value);
}}
offLabel={t('off')}
onLabel={t('on')}
/>
</div>
</div>
</div>
<div ref={this.settingsRefs[1]} className="settings-page__content-row">
<div className="settings-page__content-item">
<span>{t('useNftDetection')}</span>
<div className="settings-page__content-description">
<Text color={TextColor.textAlternative}>
{t('useNftDetectionDescription')}
</Text>
<ul className="settings-page__content-unordered-list">
<li>{t('useNftDetectionDescriptionLine2')}</li>
<li>{t('useNftDetectionDescriptionLine3')}</li>
<li>{t('useNftDetectionDescriptionLine4')}</li>
</ul>
<Text color={TextColor.textAlternative} paddingTop={4}>
{t('useNftDetectionDescriptionLine5')}
</Text>
</div>
</div>
<div className="settings-page__content-item">
<div className="settings-page__content-item-col">
<ToggleButton
value={useNftDetection}
onToggle={(value) => {
this.context.trackEvent({
category: MetaMetricsEventCategory.Settings,
event: 'NFT Detected',
properties: {
action: 'NFT Detected',
legacy_event: true,
},
});
if (!value && !openSeaEnabled) {
setOpenSeaEnabled(!value);
}
setUseNftDetection(!value);
}}
offLabel={t('off')}
onLabel={t('on')}
/>
</div>
</div>
</div>
</>
);
}
renderTransactionSecurityCheckToggle() {
const { t } = this.context;
@ -239,14 +142,14 @@ export default class ExperimentalTab extends PureComponent {
return (
<>
<Typography
variant={TypographyVariant.H4}
<Text
variant={TextVariant.headingSm}
color={TextColor.textAlternative}
marginBottom={2}
fontWeight={FONT_WEIGHT.BOLD}
fontWeight={FontWeight.Bold}
>
{t('privacy')}
</Typography>
</Text>
<div
ref={this.settingsRefs[1]}
className="settings-page__content-row settings-page__content-row-experimental"
@ -254,29 +157,29 @@ export default class ExperimentalTab extends PureComponent {
<div className="settings-page__content-item">
<span>{t('transactionSecurityCheck')}</span>
<div className="settings-page__content-description">
<Typography
variant={TypographyVariant.H6}
<Text
variant={TextVariant.bodySm}
color={TextColor.textAlternative}
>
{t('transactionSecurityCheckDescription')}
</Typography>
<Typography
</Text>
<Text
marginTop={3}
marginBottom={1}
variant={TypographyVariant.H6}
variant={TextVariant.bodySm}
color={TextColor.textAlternative}
>
{t('selectProvider')}
</Typography>
</Text>
<div className="settings-page__content-item-col settings-page__content-item-col-open-sea">
<Typography
variant={TypographyVariant.H5}
<Text
variant={TextVariant.bodyMd}
color={TextColor.textDefault}
fontWeight={FONT_WEIGHT.MEDIUM}
fontWeight={FontWeight.Medium}
marginBottom={0}
>
{t('openSea')}
</Typography>
</Text>
<ToggleButton
value={transactionSecurityCheckEnabled}
onToggle={(value) => {
@ -292,8 +195,8 @@ export default class ExperimentalTab extends PureComponent {
}}
/>
</div>
<Typography
variant={TypographyVariant.H6}
<Text
variant={TextVariant.bodySm}
color={TextColor.textAlternative}
marginTop={0}
>
@ -307,15 +210,15 @@ export default class ExperimentalTab extends PureComponent {
{t('termsOfUse')}
</a>,
])}
</Typography>
<Typography
variant={TypographyVariant.H5}
</Text>
<Text
variant={TextVariant.bodyMd}
color={TextColor.textMuted}
fontWeight={FONT_WEIGHT.MEDIUM}
fontWeight={FontWeight.Medium}
marginTop={2}
>
{t('moreComingSoon')}
</Typography>
</Text>
</div>
</div>
</div>
@ -355,7 +258,6 @@ export default class ExperimentalTab extends PureComponent {
///: END:ONLY_INCLUDE_IN
}
{this.renderTransactionSecurityCheckToggle()}
{this.renderOpenSeaEnabledToggle()}
{
///: BEGIN:ONLY_INCLUDE_IN(desktop)
this.renderDesktopEnableButton()

View File

@ -2,16 +2,12 @@ import { compose } from 'redux';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import {
setUseNftDetection,
setOpenSeaEnabled,
setTransactionSecurityCheckEnabled,
///: BEGIN:ONLY_INCLUDE_IN(blockaid)
setSecurityAlertsEnabled,
///: END:ONLY_INCLUDE_IN
} from '../../../store/actions';
import {
getUseNftDetection,
getOpenSeaEnabled,
getIsTransactionSecurityCheckEnabled,
///: BEGIN:ONLY_INCLUDE_IN(blockaid)
getIsSecurityAlertsEnabled,
@ -21,8 +17,6 @@ import ExperimentalTab from './experimental-tab.component';
const mapStateToProps = (state) => {
return {
useNftDetection: getUseNftDetection(state),
openSeaEnabled: getOpenSeaEnabled(state),
transactionSecurityCheckEnabled:
getIsTransactionSecurityCheckEnabled(state),
///: BEGIN:ONLY_INCLUDE_IN(blockaid)
@ -33,8 +27,6 @@ const mapStateToProps = (state) => {
const mapDispatchToProps = (dispatch) => {
return {
setUseNftDetection: (val) => dispatch(setUseNftDetection(val)),
setOpenSeaEnabled: (val) => dispatch(setOpenSeaEnabled(val)),
setTransactionSecurityCheckEnabled: (val) =>
dispatch(setTransactionSecurityCheckEnabled(val)),
///: BEGIN:ONLY_INCLUDE_IN(blockaid)

View File

@ -714,6 +714,168 @@ exports[`Security Tab should match snapshot 1`] = `
</div>
</div>
</div>
<div
class="settings-page__content-row"
>
<div
class="settings-page__content-item"
>
<span>
Enable OpenSea API
</span>
<div
class="settings-page__content-description"
>
Use OpenSea's API to fetch NFT data. NFT auto-detection relies on OpenSea's API, and will not be available when this is turned off.
</div>
</div>
<div
class="settings-page__content-item"
>
<div
class="settings-page__content-item-col"
data-testid="enableOpenSeaAPI"
>
<label
class="toggle-button toggle-button--off"
tabindex="0"
>
<div
style="display: flex; width: 52px; align-items: center; justify-content: flex-start; position: relative; cursor: pointer; background-color: transparent; border: 0px; padding: 0px; user-select: none;"
>
<div
style="width: 40px; height: 24px; padding: 0px; border-radius: 26px; display: flex; align-items: center; justify-content: center; background-color: rgb(242, 244, 246);"
>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgb(250, 250, 250); margin-top: auto; margin-bottom: auto; line-height: 0; opacity: 0; width: 26px; height: 20px; left: 4px;"
/>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgba(255, 255, 255, 0.6); bottom: 0px; margin-top: auto; margin-bottom: auto; padding-right: 5px; line-height: 0; width: 26px; height: 20px; opacity: 1;"
/>
</div>
<div
style="position: absolute; height: 100%; top: 0px; left: 0px; display: flex; flex: 1; align-self: stretch; align-items: center; justify-content: flex-start;"
>
<div
style="width: 18px; height: 18px; display: flex; align-self: center; box-shadow: none; border-radius: 50%; box-sizing: border-box; position: relative; background-color: rgb(106, 115, 125); left: 3px;"
/>
</div>
<input
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: absolute; width: 1px;"
type="checkbox"
value="false"
/>
</div>
<div
class="toggle-button__status"
>
<span
class="toggle-button__label-off"
>
Off
</span>
<span
class="toggle-button__label-on"
>
On
</span>
</div>
</label>
</div>
</div>
</div>
<div
class="settings-page__content-row"
>
<div
class="settings-page__content-item"
>
<span>
Autodetect NFTs
</span>
<div
class="settings-page__content-description"
>
<p
class="mm-box mm-text mm-text--body-md mm-box--color-text-alternative"
>
We use third-party APIs to detect NFTs in your wallet, which means your IP address may be exposed to centralized servers. There are a few things to be cautious about when enabling this feature.
</p>
<ul
class="settings-page__content-unordered-list"
>
<li>
Your account address will be viewable to third-party APIs.
</li>
<li>
NFT metadata may contain links to scams or phishing sites.
</li>
<li>
Anyone can airdrop NFTs to your account. This can include offensive content that might be automatically displayed in your wallet.
</li>
</ul>
<p
class="mm-box mm-text mm-text--body-md mm-box--padding-top-4 mm-box--color-text-alternative"
>
Leave this feature off if you don't want the app to pull data from those services.
</p>
</div>
</div>
<div
class="settings-page__content-item"
>
<div
class="settings-page__content-item-col"
data-testid="useNftDetection"
>
<label
class="toggle-button toggle-button--off"
tabindex="0"
>
<div
style="display: flex; width: 52px; align-items: center; justify-content: flex-start; position: relative; cursor: pointer; background-color: transparent; border: 0px; padding: 0px; user-select: none;"
>
<div
style="width: 40px; height: 24px; padding: 0px; border-radius: 26px; display: flex; align-items: center; justify-content: center; background-color: rgb(242, 244, 246);"
>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgb(250, 250, 250); margin-top: auto; margin-bottom: auto; line-height: 0; opacity: 0; width: 26px; height: 20px; left: 4px;"
/>
<div
style="font-size: 11px; display: flex; align-items: center; justify-content: center; font-family: 'Helvetica Neue', Helvetica, sans-serif; position: relative; color: rgba(255, 255, 255, 0.6); bottom: 0px; margin-top: auto; margin-bottom: auto; padding-right: 5px; line-height: 0; width: 26px; height: 20px; opacity: 1;"
/>
</div>
<div
style="position: absolute; height: 100%; top: 0px; left: 0px; display: flex; flex: 1; align-self: stretch; align-items: center; justify-content: flex-start;"
>
<div
style="width: 18px; height: 18px; display: flex; align-self: center; box-shadow: none; border-radius: 50%; box-sizing: border-box; position: relative; background-color: rgb(106, 115, 125); left: 3px;"
/>
</div>
<input
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: absolute; width: 1px;"
type="checkbox"
value="false"
/>
</div>
<div
class="toggle-button__status"
>
<span
class="toggle-button__label-off"
>
Off
</span>
<span
class="toggle-button__label-on"
>
On
</span>
</div>
</label>
</div>
</div>
</div>
</div>
<span
class="settings-page__security-tab-sub-header"

View File

@ -47,6 +47,10 @@ export default class SecurityTab extends PureComponent {
static propTypes = {
warning: PropTypes.string,
history: PropTypes.object,
openSeaEnabled: PropTypes.bool,
setOpenSeaEnabled: PropTypes.func,
useNftDetection: PropTypes.bool,
setUseNftDetection: PropTypes.func,
participateInMetaMetrics: PropTypes.bool.isRequired,
setParticipateInMetaMetrics: PropTypes.func.isRequired,
showIncomingTransactions: PropTypes.bool.isRequired,
@ -603,6 +607,110 @@ export default class SecurityTab extends PureComponent {
);
}
renderOpenSeaEnabledToggle() {
const { t } = this.context;
const {
openSeaEnabled,
setOpenSeaEnabled,
useNftDetection,
setUseNftDetection,
} = this.props;
return (
<div ref={this.settingsRefs[10]} className="settings-page__content-row">
<div className="settings-page__content-item">
<span>{t('enableOpenSeaAPI')}</span>
<div className="settings-page__content-description">
{t('enableOpenSeaAPIDescription')}
</div>
</div>
<div className="settings-page__content-item">
<div
className="settings-page__content-item-col"
data-testid="enableOpenSeaAPI"
>
<ToggleButton
value={openSeaEnabled}
onToggle={(value) => {
this.context.trackEvent({
category: MetaMetricsEventCategory.Settings,
event: 'Enabled/Disable OpenSea',
properties: {
action: 'Enabled/Disable OpenSea',
legacy_event: true,
},
});
// value is positive when being toggled off
if (value && useNftDetection) {
setUseNftDetection(false);
}
setOpenSeaEnabled(!value);
}}
offLabel={t('off')}
onLabel={t('on')}
/>
</div>
</div>
</div>
);
}
renderNftDetectionToggle() {
const { t } = this.context;
const {
openSeaEnabled,
setOpenSeaEnabled,
useNftDetection,
setUseNftDetection,
} = this.props;
return (
<div ref={this.settingsRefs[11]} className="settings-page__content-row">
<div className="settings-page__content-item">
<span>{t('useNftDetection')}</span>
<div className="settings-page__content-description">
<Text color={TextColor.textAlternative}>
{t('useNftDetectionDescription')}
</Text>
<ul className="settings-page__content-unordered-list">
<li>{t('useNftDetectionDescriptionLine2')}</li>
<li>{t('useNftDetectionDescriptionLine3')}</li>
<li>{t('useNftDetectionDescriptionLine4')}</li>
</ul>
<Text color={TextColor.textAlternative} paddingTop={4}>
{t('useNftDetectionDescriptionLine5')}
</Text>
</div>
</div>
<div className="settings-page__content-item">
<div
className="settings-page__content-item-col"
data-testid="useNftDetection"
>
<ToggleButton
value={useNftDetection}
onToggle={(value) => {
this.context.trackEvent({
category: MetaMetricsEventCategory.Settings,
event: 'NFT Detected',
properties: {
action: 'NFT Detected',
legacy_event: true,
},
});
if (!value && !openSeaEnabled) {
setOpenSeaEnabled(!value);
}
setUseNftDetection(!value);
}}
offLabel={t('off')}
onLabel={t('on')}
/>
</div>
</div>
</div>
);
}
render() {
const { warning } = this.props;
@ -643,6 +751,8 @@ export default class SecurityTab extends PureComponent {
<div className="settings-page__content-padded">
{this.renderAutoDetectTokensToggle()}
{this.renderBatchAccountBalanceRequestsToggle()}
{this.renderOpenSeaEnabledToggle()}
{this.renderNftDetectionToggle()}
</div>
<span className="settings-page__security-tab-sub-header">
{this.context.t('metrics')}

View File

@ -10,6 +10,8 @@ import {
setUsePhishDetect,
setUseTokenDetection,
setUseAddressBarEnsResolution,
setOpenSeaEnabled,
setUseNftDetection,
} from '../../../store/actions';
import SecurityTab from './security-tab.component';
@ -27,6 +29,8 @@ const mapStateToProps = (state) => {
useMultiAccountBalanceChecker,
useCurrencyRateCheck,
useAddressBarEnsResolution,
openSeaEnabled,
useNftDetection,
} = metamask;
return {
@ -39,6 +43,8 @@ const mapStateToProps = (state) => {
useMultiAccountBalanceChecker,
useCurrencyRateCheck,
useAddressBarEnsResolution,
openSeaEnabled,
useNftDetection,
};
};
@ -61,6 +67,8 @@ const mapDispatchToProps = (dispatch) => {
},
setUseAddressBarEnsResolution: (value) =>
dispatch(setUseAddressBarEnsResolution(value)),
setOpenSeaEnabled: (val) => dispatch(setOpenSeaEnabled(val)),
setUseNftDetection: (val) => dispatch(setUseNftDetection(val)),
};
};

View File

@ -46,6 +46,14 @@ describe('Security Tab', () => {
expect(container).toMatchSnapshot();
});
it('toggles opensea api enabled', async () => {
expect(await toggleCheckbox('enableOpenSeaAPI', false)).toBe(true);
});
it('toggles nft detection', async () => {
expect(await toggleCheckbox('useNftDetection', false)).toBe(true);
});
it('toggles phishing detection', async () => {
expect(await toggleCheckbox('usePhishingDetection', true)).toBe(true);
});

View File

@ -2988,18 +2988,31 @@ export function setUseTokenDetection(
};
}
export function setOpenSeaEnabled(
val: boolean,
): ThunkAction<void, MetaMaskReduxState, unknown, AnyAction> {
return async (dispatch: MetaMaskReduxDispatch) => {
dispatch(showLoadingIndication());
log.debug(`background.setOpenSeaEnabled`);
try {
await submitRequestToBackground('setOpenSeaEnabled', [val]);
} finally {
dispatch(hideLoadingIndication());
}
};
}
export function setUseNftDetection(
val: boolean,
): ThunkAction<void, MetaMaskReduxState, unknown, AnyAction> {
return (dispatch: MetaMaskReduxDispatch) => {
return async (dispatch: MetaMaskReduxDispatch) => {
dispatch(showLoadingIndication());
log.debug(`background.setUseNftDetection`);
callBackgroundMethod('setUseNftDetection', [val], (err) => {
try {
await submitRequestToBackground('setUseNftDetection', [val]);
} finally {
dispatch(hideLoadingIndication());
if (err) {
dispatch(displayWarning(err));
}
});
}
};
}
@ -3018,21 +3031,6 @@ export function setUseCurrencyRateCheck(
};
}
export function setOpenSeaEnabled(
val: boolean,
): ThunkAction<void, MetaMaskReduxState, unknown, AnyAction> {
return (dispatch: MetaMaskReduxDispatch) => {
dispatch(showLoadingIndication());
log.debug(`background.setOpenSeaEnabled`);
callBackgroundMethod('setOpenSeaEnabled', [val], (err) => {
dispatch(hideLoadingIndication());
if (err) {
dispatch(displayWarning(err));
}
});
};
}
// DetectTokenController
export function detectNewTokens(): ThunkAction<
void,