mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-25 11:28:51 +01:00
Toggle option to enable/disable balance and Token rate checking for using third-party API (#16772)
This commit is contained in:
parent
554939cc66
commit
a0bb4a6c5a
@ -1225,6 +1225,7 @@ const state = {
|
||||
useNonceField: false,
|
||||
usePhishDetect: true,
|
||||
useTokenDetection: true,
|
||||
useCurrencyRateCheck: true,
|
||||
lostIdentities: {},
|
||||
forgottenPassword: false,
|
||||
ipfsGateway: 'dweb.link',
|
||||
|
13
app/_locales/en/messages.json
generated
13
app/_locales/en/messages.json
generated
@ -682,6 +682,9 @@
|
||||
"close": {
|
||||
"message": "Close"
|
||||
},
|
||||
"coingecko": {
|
||||
"message": "CoinGecko"
|
||||
},
|
||||
"collectibleAddFailedMessage": {
|
||||
"message": "NFT can’t be added as the ownership details do not match. Make sure you have entered correct information."
|
||||
},
|
||||
@ -894,9 +897,19 @@
|
||||
"createPassword": {
|
||||
"message": "Create password"
|
||||
},
|
||||
"cryptoCompare": {
|
||||
"message": "CryptoCompare"
|
||||
},
|
||||
"currencyConversion": {
|
||||
"message": "Currency conversion"
|
||||
},
|
||||
"currencyRateCheckToggle": {
|
||||
"message": "Show balance and token price checker"
|
||||
},
|
||||
"currencyRateCheckToggleDescription": {
|
||||
"message": "We use $1 and $2 APIs to display your balance and token price. $3",
|
||||
"description": "$1 represents Coingecko, $2 represents CryptoCompare and $3 represents Privacy Policy"
|
||||
},
|
||||
"currencySymbol": {
|
||||
"message": "Currency symbol"
|
||||
},
|
||||
|
@ -116,7 +116,7 @@ export default class DetectTokensController {
|
||||
const tokensToDetect = [];
|
||||
for (const tokenAddress in tokenListUsed) {
|
||||
if (
|
||||
!this.tokenAddresses.find(({ address }) =>
|
||||
!this.tokenAddresses.find((address) =>
|
||||
isEqualCaseInsensitive(address, tokenAddress),
|
||||
) &&
|
||||
!this.hiddenTokens.find((address) =>
|
||||
|
@ -11,8 +11,9 @@ import {
|
||||
} from '@metamask/assets-controllers';
|
||||
import { NETWORK_TYPES } from '../../../shared/constants/network';
|
||||
import { toChecksumHexAddress } from '../../../shared/modules/hexstring-utils';
|
||||
import { hexToDecimal } from '../../../shared/lib/metamask-controller-utils';
|
||||
import DetectTokensController from './detect-tokens';
|
||||
import NetworkController from './network';
|
||||
import NetworkController, { NETWORK_EVENTS } from './network';
|
||||
import PreferencesController from './preferences';
|
||||
|
||||
describe('DetectTokensController', function () {
|
||||
@ -64,14 +65,34 @@ describe('DetectTokensController', function () {
|
||||
onPreferencesStateChange: preferences.store.subscribe.bind(
|
||||
preferences.store,
|
||||
),
|
||||
onNetworkStateChange: network.store.subscribe.bind(network.store),
|
||||
onNetworkStateChange: (cb) =>
|
||||
network.store.subscribe((networkState) => {
|
||||
const modifiedNetworkState = {
|
||||
...networkState,
|
||||
providerConfig: {
|
||||
...networkState.provider,
|
||||
},
|
||||
};
|
||||
return cb(modifiedNetworkState);
|
||||
}),
|
||||
});
|
||||
|
||||
assetsContractController = new AssetsContractController({
|
||||
onPreferencesStateChange: preferences.store.subscribe.bind(
|
||||
preferences.store,
|
||||
),
|
||||
onNetworkStateChange: network.store.subscribe.bind(network.store),
|
||||
onNetworkStateChange: (cb) =>
|
||||
network.on(NETWORK_EVENTS.NETWORK_DID_CHANGE, () => {
|
||||
const networkState = network.store.getState();
|
||||
const modifiedNetworkState = {
|
||||
...networkState,
|
||||
providerConfig: {
|
||||
...networkState.provider,
|
||||
chainId: hexToDecimal(networkState.provider.chainId),
|
||||
},
|
||||
};
|
||||
return cb(modifiedNetworkState);
|
||||
}),
|
||||
});
|
||||
|
||||
sandbox
|
||||
|
@ -37,6 +37,7 @@ export default class PreferencesController {
|
||||
// set to false will be using the static list from contract-metadata
|
||||
useTokenDetection: false,
|
||||
useNftDetection: false,
|
||||
useCurrencyRateCheck: true,
|
||||
openSeaEnabled: false,
|
||||
advancedGasFee: null,
|
||||
|
||||
@ -156,6 +157,15 @@ export default class PreferencesController {
|
||||
this.store.updateState({ useNftDetection });
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the `useCurrencyRateCheck` property
|
||||
*
|
||||
* @param {boolean} val - Whether or not the user prefers to use currency rate check for ETH and tokens.
|
||||
*/
|
||||
setUseCurrencyRateCheck(val) {
|
||||
this.store.updateState({ useCurrencyRateCheck: val });
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the `openSeaEnabled` property
|
||||
*
|
||||
|
@ -367,4 +367,23 @@ describe('preferences controller', function () {
|
||||
assert.equal(preferencesController.store.getState().theme, 'dark');
|
||||
});
|
||||
});
|
||||
|
||||
describe('setUseCurrencyRateCheck', function () {
|
||||
it('should default to false', function () {
|
||||
const state = preferencesController.store.getState();
|
||||
assert.equal(state.useCurrencyRateCheck, true);
|
||||
});
|
||||
|
||||
it('should set the useCurrencyRateCheck property in state', function () {
|
||||
assert.equal(
|
||||
preferencesController.store.getState().useCurrencyRateCheck,
|
||||
true,
|
||||
);
|
||||
preferencesController.setUseCurrencyRateCheck(false);
|
||||
assert.equal(
|
||||
preferencesController.store.getState().useCurrencyRateCheck,
|
||||
false,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -266,7 +266,7 @@ export default class MetamaskController extends EventEmitter {
|
||||
this.networkController.store.subscribe((networkState) => {
|
||||
const modifiedNetworkState = {
|
||||
...networkState,
|
||||
provider: {
|
||||
providerConfig: {
|
||||
...networkState.provider,
|
||||
chainId: hexToDecimal(networkState.provider.chainId),
|
||||
},
|
||||
@ -291,9 +291,16 @@ export default class MetamaskController extends EventEmitter {
|
||||
onPreferencesStateChange: this.preferencesController.store.subscribe.bind(
|
||||
this.preferencesController.store,
|
||||
),
|
||||
onNetworkStateChange: this.networkController.store.subscribe.bind(
|
||||
this.networkController.store,
|
||||
),
|
||||
onNetworkStateChange: (cb) =>
|
||||
this.networkController.store.subscribe((networkState) => {
|
||||
const modifiedNetworkState = {
|
||||
...networkState,
|
||||
providerConfig: {
|
||||
...networkState.provider,
|
||||
},
|
||||
};
|
||||
return cb(modifiedNetworkState);
|
||||
}),
|
||||
config: { provider: this.provider },
|
||||
state: initState.TokensController,
|
||||
});
|
||||
@ -307,7 +314,7 @@ export default class MetamaskController extends EventEmitter {
|
||||
const networkState = this.networkController.store.getState();
|
||||
const modifiedNetworkState = {
|
||||
...networkState,
|
||||
provider: {
|
||||
providerConfig: {
|
||||
...networkState.provider,
|
||||
chainId: hexToDecimal(networkState.provider.chainId),
|
||||
},
|
||||
@ -327,9 +334,16 @@ export default class MetamaskController extends EventEmitter {
|
||||
this.preferencesController.store.subscribe.bind(
|
||||
this.preferencesController.store,
|
||||
),
|
||||
onNetworkStateChange: this.networkController.store.subscribe.bind(
|
||||
this.networkController.store,
|
||||
),
|
||||
onNetworkStateChange: (cb) =>
|
||||
this.networkController.store.subscribe((networkState) => {
|
||||
const modifiedNetworkState = {
|
||||
...networkState,
|
||||
providerConfig: {
|
||||
...networkState.provider,
|
||||
},
|
||||
};
|
||||
return cb(modifiedNetworkState);
|
||||
}),
|
||||
getERC721AssetName:
|
||||
this.assetsContractController.getERC721AssetName.bind(
|
||||
this.assetsContractController,
|
||||
@ -504,7 +518,7 @@ export default class MetamaskController extends EventEmitter {
|
||||
this.networkController.store.subscribe((networkState) => {
|
||||
const modifiedNetworkState = {
|
||||
...networkState,
|
||||
provider: {
|
||||
providerConfig: {
|
||||
...networkState.provider,
|
||||
chainId: hexToDecimal(networkState.provider.chainId),
|
||||
},
|
||||
@ -512,9 +526,29 @@ export default class MetamaskController extends EventEmitter {
|
||||
return cb(modifiedNetworkState);
|
||||
}),
|
||||
},
|
||||
undefined,
|
||||
{
|
||||
disabled:
|
||||
!this.preferencesController.store.getState().useCurrencyRateCheck,
|
||||
},
|
||||
initState.TokenRatesController,
|
||||
);
|
||||
this.preferencesController.store.subscribe(
|
||||
previousValueComparator((prevState, currState) => {
|
||||
const { useCurrencyRateCheck: prevUseCurrencyRateCheck } = prevState;
|
||||
const { useCurrencyRateCheck: currUseCurrencyRateCheck } = currState;
|
||||
if (currUseCurrencyRateCheck && !prevUseCurrencyRateCheck) {
|
||||
this.currencyRateController.start();
|
||||
this.tokenRatesController.configure(
|
||||
{ disabled: false },
|
||||
false,
|
||||
false,
|
||||
);
|
||||
} else if (!currUseCurrencyRateCheck && prevUseCurrencyRateCheck) {
|
||||
this.currencyRateController.stop();
|
||||
this.tokenRatesController.configure({ disabled: true }, false, false);
|
||||
}
|
||||
}, this.preferencesController.store.getState()),
|
||||
);
|
||||
|
||||
this.ensController = new EnsController({
|
||||
provider: this.provider,
|
||||
@ -1245,7 +1279,9 @@ export default class MetamaskController extends EventEmitter {
|
||||
triggerNetworkrequests() {
|
||||
this.accountTracker.start();
|
||||
this.incomingTransactionsController.start();
|
||||
if (this.preferencesController.store.getState().useCurrencyRateCheck) {
|
||||
this.currencyRateController.start();
|
||||
}
|
||||
if (this.preferencesController.store.getState().useTokenDetection) {
|
||||
this.tokenListController.start();
|
||||
}
|
||||
@ -1254,7 +1290,9 @@ export default class MetamaskController extends EventEmitter {
|
||||
stopNetworkRequests() {
|
||||
this.accountTracker.stop();
|
||||
this.incomingTransactionsController.stop();
|
||||
if (this.preferencesController.store.getState().useCurrencyRateCheck) {
|
||||
this.currencyRateController.stop();
|
||||
}
|
||||
if (this.preferencesController.store.getState().useTokenDetection) {
|
||||
this.tokenListController.stop();
|
||||
}
|
||||
@ -1633,6 +1671,10 @@ export default class MetamaskController extends EventEmitter {
|
||||
setUseNftDetection: preferencesController.setUseNftDetection.bind(
|
||||
preferencesController,
|
||||
),
|
||||
setUseCurrencyRateCheck:
|
||||
preferencesController.setUseCurrencyRateCheck.bind(
|
||||
preferencesController,
|
||||
),
|
||||
setOpenSeaEnabled: preferencesController.setOpenSeaEnabled.bind(
|
||||
preferencesController,
|
||||
),
|
||||
|
@ -501,6 +501,7 @@
|
||||
"URL": true,
|
||||
"clearInterval": true,
|
||||
"clearTimeout": true,
|
||||
"console.info": true,
|
||||
"console.log": true,
|
||||
"setInterval": true,
|
||||
"setTimeout": true
|
||||
@ -508,10 +509,10 @@
|
||||
"packages": {
|
||||
"@ethersproject/contracts": true,
|
||||
"@ethersproject/providers": true,
|
||||
"@metamask/assets-controllers>@metamask/contract-metadata": true,
|
||||
"@metamask/assets-controllers>abort-controller": true,
|
||||
"@metamask/assets-controllers>multiformats": true,
|
||||
"@metamask/base-controller": true,
|
||||
"@metamask/contract-metadata": true,
|
||||
"@metamask/controller-utils": true,
|
||||
"@metamask/metamask-eth-abis": true,
|
||||
"browserify>events": true,
|
||||
|
@ -501,6 +501,7 @@
|
||||
"URL": true,
|
||||
"clearInterval": true,
|
||||
"clearTimeout": true,
|
||||
"console.info": true,
|
||||
"console.log": true,
|
||||
"setInterval": true,
|
||||
"setTimeout": true
|
||||
@ -508,10 +509,10 @@
|
||||
"packages": {
|
||||
"@ethersproject/contracts": true,
|
||||
"@ethersproject/providers": true,
|
||||
"@metamask/assets-controllers>@metamask/contract-metadata": true,
|
||||
"@metamask/assets-controllers>abort-controller": true,
|
||||
"@metamask/assets-controllers>multiformats": true,
|
||||
"@metamask/base-controller": true,
|
||||
"@metamask/contract-metadata": true,
|
||||
"@metamask/controller-utils": true,
|
||||
"@metamask/metamask-eth-abis": true,
|
||||
"browserify>events": true,
|
||||
|
@ -501,6 +501,7 @@
|
||||
"URL": true,
|
||||
"clearInterval": true,
|
||||
"clearTimeout": true,
|
||||
"console.info": true,
|
||||
"console.log": true,
|
||||
"setInterval": true,
|
||||
"setTimeout": true
|
||||
@ -508,10 +509,10 @@
|
||||
"packages": {
|
||||
"@ethersproject/contracts": true,
|
||||
"@ethersproject/providers": true,
|
||||
"@metamask/assets-controllers>@metamask/contract-metadata": true,
|
||||
"@metamask/assets-controllers>abort-controller": true,
|
||||
"@metamask/assets-controllers>multiformats": true,
|
||||
"@metamask/base-controller": true,
|
||||
"@metamask/contract-metadata": true,
|
||||
"@metamask/controller-utils": true,
|
||||
"@metamask/metamask-eth-abis": true,
|
||||
"browserify>events": true,
|
||||
|
@ -209,7 +209,7 @@
|
||||
"@metamask/address-book-controller": "^1.0.0",
|
||||
"@metamask/announcement-controller": "^1.0.0",
|
||||
"@metamask/approval-controller": "^1.0.0",
|
||||
"@metamask/assets-controllers": "^1.0.1",
|
||||
"@metamask/assets-controllers": "^3.0.1",
|
||||
"@metamask/base-controller": "^1.0.0",
|
||||
"@metamask/contract-metadata": "^2.1.0",
|
||||
"@metamask/controller-utils": "^1.0.0",
|
||||
|
@ -5,6 +5,11 @@ _supportLink = 'https://metamask-flask.zendesk.com/hc';
|
||||
///: END:ONLY_INCLUDE_IN
|
||||
|
||||
export const SUPPORT_LINK = _supportLink;
|
||||
|
||||
export const COINGECKO_LINK = 'https://www.coingecko.com/';
|
||||
export const CRYPTOCOMPARE_LINK = 'https://www.cryptocompare.com/';
|
||||
export const PRIVACY_POLICY_LINK = 'https://consensys.net/privacy-policy/';
|
||||
|
||||
// TODO make sure these links are correct
|
||||
export const ETHERSCAN_PRIVACY_LINK = 'https://etherscan.io/privacyPolicy';
|
||||
export const CONSENSYS_PRIVACY_LINK = 'https://consensys.net/privacy-policy/';
|
||||
|
@ -252,6 +252,7 @@
|
||||
"unapprovedTypedMessages": {},
|
||||
"unapprovedTypedMessagesCount": 0,
|
||||
"useTokenDetection": true,
|
||||
"useCurrencyRateCheck": true,
|
||||
"advancedGasFee": {
|
||||
"maxBaseFee": "75",
|
||||
"priorityFee": "2"
|
||||
|
@ -239,6 +239,7 @@ function defaultFixture() {
|
||||
useNonceField: false,
|
||||
usePhishDetect: true,
|
||||
useTokenDetection: false,
|
||||
useCurrencyRateCheck: true,
|
||||
useMultiAccountBalanceChecker: true,
|
||||
},
|
||||
SmartTransactionsController: {
|
||||
@ -352,6 +353,7 @@ function onboardingFixture() {
|
||||
useNonceField: false,
|
||||
usePhishDetect: true,
|
||||
useTokenDetection: false,
|
||||
useCurrencyRateCheck: true,
|
||||
useMultiAccountBalanceChecker: true,
|
||||
},
|
||||
SmartTransactionsController: {
|
||||
|
@ -46,6 +46,7 @@
|
||||
"useNonceField": false,
|
||||
"usePhishDetect": true,
|
||||
"useTokenDetection": false,
|
||||
"useCurrencyRateCheck": true,
|
||||
"useMultiAccountBalanceChecker": true
|
||||
}
|
||||
}
|
||||
|
@ -218,6 +218,7 @@ export const createSwapsMockStore = () => {
|
||||
postTxBalance: '19a61aaaf06e4bd1',
|
||||
},
|
||||
],
|
||||
useCurrencyRateCheck: true,
|
||||
conversionRate: 1,
|
||||
contractExchangeRates: {
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48': 2,
|
||||
|
@ -16,6 +16,7 @@ describe('CurrencyInput Component', () => {
|
||||
preferences: {
|
||||
showFiatInTestnets: true,
|
||||
},
|
||||
useCurrencyRateCheck: true,
|
||||
},
|
||||
};
|
||||
describe('rendering', () => {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import Box from '../../../ui/box';
|
||||
import Typography from '../../../ui/typography';
|
||||
@ -12,6 +13,7 @@ import {
|
||||
} from '../../../../helpers/constants/design-system';
|
||||
import { useTokenTracker } from '../../../../hooks/useTokenTracker';
|
||||
import { useTokenFiatAmount } from '../../../../hooks/useTokenFiatAmount';
|
||||
import { getUseCurrencyRateCheck } from '../../../../selectors';
|
||||
|
||||
const DetectedTokenValues = ({
|
||||
token,
|
||||
@ -30,6 +32,8 @@ const DetectedTokenValues = ({
|
||||
token.symbol,
|
||||
);
|
||||
|
||||
const useCurrencyRateCheck = useSelector(getUseCurrencyRateCheck);
|
||||
|
||||
useEffect(() => {
|
||||
setTokenSelection(tokensListDetected[token.address]?.selected);
|
||||
}, [tokensListDetected, token.address, tokenSelection, setTokenSelection]);
|
||||
@ -46,7 +50,9 @@ const DetectedTokenValues = ({
|
||||
{`${balanceString || '0'} ${token.symbol}`}
|
||||
</Typography>
|
||||
<Typography variant={TYPOGRAPHY.H7} color={COLORS.TEXT_ALTERNATIVE}>
|
||||
{formattedFiatBalance || '$0'}
|
||||
{useCurrencyRateCheck
|
||||
? formattedFiatBalance || '$0' // since formattedFiatBalance will be when teh conversion rate is not obtained, should be replace the `$0` with `N/A`
|
||||
: formattedFiatBalance}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box className="detected-token-values__checkbox">
|
||||
|
@ -5,7 +5,7 @@ import { useSelector } from 'react-redux';
|
||||
|
||||
import { COLORS } from '../../../helpers/constants/design-system';
|
||||
import { PRIMARY, SECONDARY } from '../../../helpers/constants/common';
|
||||
import { getPreferences } from '../../../selectors';
|
||||
import { getPreferences, getUseCurrencyRateCheck } from '../../../selectors';
|
||||
import { useGasFeeContext } from '../../../contexts/gasFee';
|
||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||
|
||||
@ -29,6 +29,8 @@ const GasDetailsItem = ({ userAcknowledgedGasMissing = false }) => {
|
||||
|
||||
const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences);
|
||||
|
||||
const useCurrencyRateCheck = useSelector(getUseCurrencyRateCheck);
|
||||
|
||||
if (hasSimulationError && !userAcknowledgedGasMissing) {
|
||||
return null;
|
||||
}
|
||||
@ -39,6 +41,7 @@ const GasDetailsItem = ({ userAcknowledgedGasMissing = false }) => {
|
||||
detailTitle={<GasDetailsItemTitle />}
|
||||
detailTitleColor={COLORS.TEXT_DEFAULT}
|
||||
detailText={
|
||||
useCurrencyRateCheck && (
|
||||
<div className="gas-details-item__currency-container">
|
||||
<LoadingHeartBeat estimateUsed={estimateUsed} />
|
||||
<UserPreferencedCurrencyDisplay
|
||||
@ -47,6 +50,7 @@ const GasDetailsItem = ({ userAcknowledgedGasMissing = false }) => {
|
||||
hideLabel={Boolean(useNativeCurrencyAsPrimaryCurrency)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
detailTotal={
|
||||
<div className="gas-details-item__currency-container">
|
||||
|
@ -3,7 +3,7 @@
|
||||
exports[`Token Cell should match snapshot 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="list-item asset-list-item token-cell"
|
||||
class="list-item asset-list-item token-cell list-item--single-content-row"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
@ -77,15 +77,6 @@ exports[`Token Cell should match snapshot 1`] = `
|
||||
</h2>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="list-item__subheading"
|
||||
>
|
||||
<h3
|
||||
title="$0.52 USD"
|
||||
>
|
||||
$0.52 USD
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="list-item__right-content"
|
||||
>
|
||||
|
@ -219,6 +219,13 @@ export const SETTINGS_CONSTANTS = [
|
||||
icon: 'fa fa-flask',
|
||||
featureFlag: 'NFTS_V1',
|
||||
},
|
||||
{
|
||||
tabMessage: (t) => t('securityAndPrivacy'),
|
||||
sectionMessage: (t) => t('currencyRateCheckToggle'),
|
||||
descriptionMessage: (t) => t('currencyRateCheckToggleDescription'),
|
||||
route: `${SECURITY_ROUTE}#price-checker`,
|
||||
icon: 'fa fa-lock',
|
||||
},
|
||||
{
|
||||
tabMessage: (t) => t('alerts'),
|
||||
sectionMessage: (t) => t('alertSettingsUnconnectedAccount'),
|
||||
|
@ -137,6 +137,10 @@ const t = (key) => {
|
||||
return 'Contact us';
|
||||
case 'snaps':
|
||||
return 'Snaps';
|
||||
case 'currencyRateCheckToggle':
|
||||
return 'Show balance and token price checker';
|
||||
case 'currencyRateCheckToggleDescription':
|
||||
return 'We use Coingecko and CryptoCompare APIs to display your balance and token price. Privacy Policy';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
@ -165,7 +169,7 @@ describe('Settings Search Utils', () => {
|
||||
it('should get good security & privacy section number', () => {
|
||||
expect(
|
||||
getNumberOfSettingsInSection(t, t('securityAndPrivacy')),
|
||||
).toStrictEqual(9);
|
||||
).toStrictEqual(10);
|
||||
});
|
||||
|
||||
it('should get good alerts section number', () => {
|
||||
|
@ -160,6 +160,7 @@ export default class ConfirmTransactionBase extends Component {
|
||||
insightSnaps: PropTypes.arrayOf(PropTypes.object),
|
||||
///: END:ONLY_INCLUDE_IN
|
||||
assetStandard: PropTypes.string,
|
||||
useCurrencyRateCheck: PropTypes.bool,
|
||||
};
|
||||
|
||||
state = {
|
||||
@ -349,6 +350,7 @@ export default class ConfirmTransactionBase extends Component {
|
||||
isMultiLayerFeeNetwork,
|
||||
nativeCurrency,
|
||||
isBuyableChain,
|
||||
useCurrencyRateCheck,
|
||||
} = this.props;
|
||||
const { t } = this.context;
|
||||
const { userAcknowledgedGasMissing } = this.state;
|
||||
@ -511,6 +513,7 @@ export default class ConfirmTransactionBase extends Component {
|
||||
)
|
||||
}
|
||||
detailText={
|
||||
useCurrencyRateCheck && (
|
||||
<div className="confirm-page-container-content__currency-container test">
|
||||
{renderHeartBeatIfNotInTest()}
|
||||
<UserPreferencedCurrencyDisplay
|
||||
@ -519,6 +522,7 @@ export default class ConfirmTransactionBase extends Component {
|
||||
hideLabel={Boolean(useNativeCurrencyAsPrimaryCurrency)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
detailTotal={
|
||||
<div className="confirm-page-container-content__currency-container">
|
||||
@ -637,7 +641,7 @@ export default class ConfirmTransactionBase extends Component {
|
||||
<TransactionDetailItem
|
||||
key="total-item"
|
||||
detailTitle={t('total')}
|
||||
detailText={renderTotalDetailText()}
|
||||
detailText={useCurrencyRateCheck && renderTotalDetailText()}
|
||||
detailTotal={renderTotalDetailTotal()}
|
||||
subTitle={t('transactionDetailGasTotalSubtitle')}
|
||||
subText={
|
||||
|
@ -36,6 +36,7 @@ import {
|
||||
getEnsResolutionByAddress,
|
||||
getUnapprovedTransaction,
|
||||
getFullTxData,
|
||||
getUseCurrencyRateCheck,
|
||||
///: BEGIN:ONLY_INCLUDE_IN(flask)
|
||||
getInsightSnaps,
|
||||
///: END:ONLY_INCLUDE_IN
|
||||
@ -251,6 +252,7 @@ const mapStateToProps = (state, ownProps) => {
|
||||
///: BEGIN:ONLY_INCLUDE_IN(flask)
|
||||
insightSnaps,
|
||||
///: END:ONLY_INCLUDE_IN
|
||||
useCurrencyRateCheck: getUseCurrencyRateCheck(state),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -22,13 +22,20 @@ import {
|
||||
showModal,
|
||||
setIpfsGateway,
|
||||
showNetworkDropdown,
|
||||
setUseCurrencyRateCheck,
|
||||
} from '../../../store/actions';
|
||||
import { ONBOARDING_PIN_EXTENSION_ROUTE } from '../../../helpers/constants/routes';
|
||||
import { Icon, TextField } from '../../../components/component-library';
|
||||
import NetworkDropdown from '../../../components/app/dropdowns/network-dropdown';
|
||||
import NetworkDisplay from '../../../components/app/network-display/network-display';
|
||||
import {
|
||||
COINGECKO_LINK,
|
||||
CRYPTOCOMPARE_LINK,
|
||||
PRIVACY_POLICY_LINK,
|
||||
} from '../../../../shared/lib/ui-utils';
|
||||
import { MetaMetricsContext } from '../../../contexts/metametrics';
|
||||
import { EVENT_NAMES, EVENT } from '../../../../shared/constants/metametrics';
|
||||
|
||||
import { Setting } from './setting';
|
||||
|
||||
export default function PrivacySettings() {
|
||||
@ -37,6 +44,7 @@ export default function PrivacySettings() {
|
||||
const history = useHistory();
|
||||
const [usePhishingDetection, setUsePhishingDetection] = useState(true);
|
||||
const [turnOnTokenDetection, setTurnOnTokenDetection] = useState(true);
|
||||
const [turnOnCurrencyRateCheck, setTurnOnCurrencyRateCheck] = useState(true);
|
||||
const [showIncomingTransactions, setShowIncomingTransactions] =
|
||||
useState(true);
|
||||
const [
|
||||
@ -60,6 +68,7 @@ export default function PrivacySettings() {
|
||||
dispatch(
|
||||
setUseMultiAccountBalanceChecker(isMultiAccountBalanceCheckerEnabled),
|
||||
);
|
||||
dispatch(setUseCurrencyRateCheck(turnOnCurrencyRateCheck));
|
||||
dispatch(setCompletedOnboarding());
|
||||
|
||||
if (ipfsURL && !ipfsError) {
|
||||
@ -254,6 +263,37 @@ export default function PrivacySettings() {
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<Setting
|
||||
value={turnOnCurrencyRateCheck}
|
||||
setValue={setTurnOnCurrencyRateCheck}
|
||||
title={t('currencyRateCheckToggle')}
|
||||
description={t('currencyRateCheckToggleDescription', [
|
||||
<a
|
||||
key="coingecko_link"
|
||||
href={COINGECKO_LINK}
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
{t('coingecko')}
|
||||
</a>,
|
||||
<a
|
||||
key="cryptocompare_link"
|
||||
href={CRYPTOCOMPARE_LINK}
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
{t('cryptoCompare')}
|
||||
</a>,
|
||||
<a
|
||||
key="privacy_policy_link"
|
||||
href={PRIVACY_POLICY_LINK}
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
{t('privacyMsg')}
|
||||
</a>,
|
||||
])}
|
||||
/>
|
||||
</div>
|
||||
<Button type="primary" rounded onClick={handleSubmit}>
|
||||
{t('done')}
|
||||
|
@ -22,6 +22,7 @@ describe('Privacy Settings Onboarding View', () => {
|
||||
const setFeatureFlagStub = jest.fn();
|
||||
const setUsePhishDetectStub = jest.fn();
|
||||
const setUseTokenDetectionStub = jest.fn();
|
||||
const setUseCurrencyRateCheckStub = jest.fn();
|
||||
const completeOnboardingStub = jest
|
||||
.fn()
|
||||
.mockImplementation(() => Promise.resolve());
|
||||
@ -31,6 +32,7 @@ describe('Privacy Settings Onboarding View', () => {
|
||||
setFeatureFlag: setFeatureFlagStub,
|
||||
setUsePhishDetect: setUsePhishDetectStub,
|
||||
setUseTokenDetection: setUseTokenDetectionStub,
|
||||
setUseCurrencyRateCheck: setUseCurrencyRateCheckStub,
|
||||
completeOnboarding: completeOnboardingStub,
|
||||
setUseMultiAccountBalanceChecker: setUseMultiAccountBalanceCheckerStub,
|
||||
});
|
||||
@ -45,6 +47,7 @@ describe('Privacy Settings Onboarding View', () => {
|
||||
expect(setUsePhishDetectStub).toHaveBeenCalledTimes(0);
|
||||
expect(setUseTokenDetectionStub).toHaveBeenCalledTimes(0);
|
||||
expect(setUseMultiAccountBalanceCheckerStub).toHaveBeenCalledTimes(0);
|
||||
expect(setUseCurrencyRateCheckStub).toHaveBeenCalledTimes(0);
|
||||
|
||||
const toggles = container.querySelectorAll('input[type=checkbox]');
|
||||
const submitButton = getByText('Done');
|
||||
@ -54,34 +57,42 @@ describe('Privacy Settings Onboarding View', () => {
|
||||
fireEvent.click(toggles[1]);
|
||||
fireEvent.click(toggles[2]);
|
||||
fireEvent.click(toggles[3]);
|
||||
fireEvent.click(toggles[4]);
|
||||
fireEvent.click(submitButton);
|
||||
|
||||
expect(setFeatureFlagStub).toHaveBeenCalledTimes(1);
|
||||
expect(setUsePhishDetectStub).toHaveBeenCalledTimes(1);
|
||||
expect(setUseTokenDetectionStub).toHaveBeenCalledTimes(1);
|
||||
expect(setUseMultiAccountBalanceCheckerStub).toHaveBeenCalledTimes(1);
|
||||
expect(setUseCurrencyRateCheckStub).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(setFeatureFlagStub.mock.calls[0][1]).toStrictEqual(false);
|
||||
expect(setUsePhishDetectStub.mock.calls[0][0]).toStrictEqual(false);
|
||||
expect(setUseTokenDetectionStub.mock.calls[0][0]).toStrictEqual(false);
|
||||
expect(setUseMultiAccountBalanceCheckerStub.mock.calls[0][0]).toStrictEqual(
|
||||
false,
|
||||
);
|
||||
expect(setUseCurrencyRateCheckStub.mock.calls[0][0]).toStrictEqual(false);
|
||||
|
||||
// toggle back to true
|
||||
fireEvent.click(toggles[0]);
|
||||
fireEvent.click(toggles[1]);
|
||||
fireEvent.click(toggles[2]);
|
||||
fireEvent.click(toggles[3]);
|
||||
fireEvent.click(toggles[4]);
|
||||
fireEvent.click(submitButton);
|
||||
expect(setFeatureFlagStub).toHaveBeenCalledTimes(2);
|
||||
expect(setUsePhishDetectStub).toHaveBeenCalledTimes(2);
|
||||
expect(setUseTokenDetectionStub).toHaveBeenCalledTimes(2);
|
||||
expect(setUseMultiAccountBalanceCheckerStub).toHaveBeenCalledTimes(2);
|
||||
expect(setUseCurrencyRateCheckStub).toHaveBeenCalledTimes(2);
|
||||
|
||||
expect(setFeatureFlagStub.mock.calls[1][1]).toStrictEqual(true);
|
||||
expect(setUsePhishDetectStub.mock.calls[1][0]).toStrictEqual(true);
|
||||
expect(setUseTokenDetectionStub.mock.calls[1][0]).toStrictEqual(true);
|
||||
expect(setUseMultiAccountBalanceCheckerStub.mock.calls[1][0]).toStrictEqual(
|
||||
true,
|
||||
);
|
||||
expect(setUseCurrencyRateCheckStub.mock.calls[1][0]).toStrictEqual(true);
|
||||
});
|
||||
});
|
||||
|
@ -38,6 +38,7 @@ import {
|
||||
getIsBuyableChain,
|
||||
transactionFeeSelector,
|
||||
getIsMainnet,
|
||||
getUseCurrencyRateCheck,
|
||||
} from '../../../selectors';
|
||||
|
||||
import {
|
||||
@ -57,6 +58,7 @@ export default function GasDisplay({ gasError }) {
|
||||
const isMainnet = useSelector(getIsMainnet);
|
||||
const isBuyableChain = useSelector(getIsBuyableChain);
|
||||
const draftTransaction = useSelector(getCurrentDraftTransaction);
|
||||
const useCurrencyRateCheck = useSelector(getUseCurrencyRateCheck);
|
||||
const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences);
|
||||
const { nativeCurrency, provider, unapprovedTxs } = useSelector(
|
||||
(state) => state.metamask,
|
||||
@ -197,6 +199,7 @@ export default function GasDisplay({ gasError }) {
|
||||
}
|
||||
detailTitleColor={COLORS.TEXT_DEFAULT}
|
||||
detailText={
|
||||
useCurrencyRateCheck && (
|
||||
<Box className="gas-display__currency-container">
|
||||
<LoadingHeartBeat estimateUsed={estimateUsed} />
|
||||
<UserPreferencedCurrencyDisplay
|
||||
@ -205,6 +208,7 @@ export default function GasDisplay({ gasError }) {
|
||||
hideLabel={Boolean(useNativeCurrencyAsPrimaryCurrency)}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
detailTotal={
|
||||
<Box className="gas-display__currency-container">
|
||||
@ -263,6 +267,7 @@ export default function GasDisplay({ gasError }) {
|
||||
key="total-item"
|
||||
detailTitle={t('total')}
|
||||
detailText={
|
||||
useCurrencyRateCheck && (
|
||||
<Box
|
||||
height={BLOCK_SIZES.MAX}
|
||||
display={DISPLAY.FLEX}
|
||||
@ -279,6 +284,7 @@ export default function GasDisplay({ gasError }) {
|
||||
hideLabel={Boolean(useNativeCurrencyAsPrimaryCurrency)}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
detailTotal={detailTotal}
|
||||
subTitle={t('transactionDetailGasTotalSubtitle')}
|
||||
|
@ -236,27 +236,6 @@ exports[`SendContent Component render should match snapshot 1`] = `
|
||||
<div
|
||||
class="transaction-detail-item__detail-values"
|
||||
>
|
||||
<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"
|
||||
>
|
||||
<div
|
||||
class="box gas-display__currency-container box--flex-direction-row"
|
||||
>
|
||||
<div
|
||||
class="currency-display-component"
|
||||
title="0.0000315"
|
||||
>
|
||||
<span
|
||||
class="currency-display-component__prefix"
|
||||
/>
|
||||
<span
|
||||
class="currency-display-component__text"
|
||||
>
|
||||
0.0000315
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</h6>
|
||||
<h6
|
||||
class="box box--margin-top-1 box--margin-bottom-1 box--margin-left-1 box--flex-direction-row box--text-align-right typography typography--h6 typography--weight-bold typography--style-normal typography--color-text-default"
|
||||
>
|
||||
|
@ -134,6 +134,103 @@ exports[`Security Tab should match snapshot 1`] = `
|
||||
<div
|
||||
class="settings-page__content-padded"
|
||||
>
|
||||
<div
|
||||
class="settings-page__content-row"
|
||||
>
|
||||
<div
|
||||
class="settings-page__content-item"
|
||||
>
|
||||
<span>
|
||||
Show balance and token price checker
|
||||
</span>
|
||||
<div
|
||||
class="settings-page__content-description"
|
||||
>
|
||||
<span>
|
||||
|
||||
We use
|
||||
<a
|
||||
href="https://www.coingecko.com/"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
CoinGecko
|
||||
</a>
|
||||
and
|
||||
<a
|
||||
href="https://www.cryptocompare.com/"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
CryptoCompare
|
||||
</a>
|
||||
APIs to display your balance and token price.
|
||||
<a
|
||||
href="https://consensys.net/privacy-policy/"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Privacy policy
|
||||
</a>
|
||||
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="settings-page__content-item"
|
||||
>
|
||||
<div
|
||||
class="settings-page__content-item-col"
|
||||
>
|
||||
<label
|
||||
class="toggle-button toggle-button--on"
|
||||
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: 1; 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: 0;"
|
||||
/>
|
||||
</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(3, 125, 214); left: 18px;"
|
||||
/>
|
||||
</div>
|
||||
<input
|
||||
style="border: 0px; height: 1px; margin: -1px; overflow: hidden; padding: 0px; position: absolute; width: 1px;"
|
||||
type="checkbox"
|
||||
value="true"
|
||||
/>
|
||||
</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"
|
||||
>
|
||||
|
@ -14,6 +14,9 @@ import {
|
||||
} from '../../../helpers/utils/settings-search';
|
||||
import { EVENT, EVENT_NAMES } from '../../../../shared/constants/metametrics';
|
||||
import {
|
||||
COINGECKO_LINK,
|
||||
CRYPTOCOMPARE_LINK,
|
||||
PRIVACY_POLICY_LINK,
|
||||
AUTO_DETECT_TOKEN_LEARN_MORE_LINK,
|
||||
CONSENSYS_PRIVACY_LINK,
|
||||
ETHERSCAN_PRIVACY_LINK,
|
||||
@ -45,6 +48,8 @@ export default class SecurityTab extends PureComponent {
|
||||
ipfsGateway: PropTypes.string.isRequired,
|
||||
useMultiAccountBalanceChecker: PropTypes.bool.isRequired,
|
||||
setUseMultiAccountBalanceChecker: PropTypes.func.isRequired,
|
||||
useCurrencyRateCheck: PropTypes.bool.isRequired,
|
||||
setUseCurrencyRateCheck: PropTypes.func.isRequired,
|
||||
useNftDetection: PropTypes.bool,
|
||||
setUseNftDetection: PropTypes.func,
|
||||
setOpenSeaEnabled: PropTypes.func,
|
||||
@ -348,7 +353,7 @@ export default class SecurityTab extends PureComponent {
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={this.settingsRefs[7]}
|
||||
ref={this.settingsRefs[4]}
|
||||
className="settings-page__content-row"
|
||||
data-testid="advanced-setting-gas-fee-estimation"
|
||||
>
|
||||
@ -395,7 +400,7 @@ export default class SecurityTab extends PureComponent {
|
||||
this.props;
|
||||
|
||||
return (
|
||||
<div ref={this.settingsRefs[4]} className="settings-page__content-row">
|
||||
<div ref={this.settingsRefs[8]} className="settings-page__content-row">
|
||||
<div className="settings-page__content-item">
|
||||
<span>{t('useMultiAccountBalanceChecker')}</span>
|
||||
<div className="settings-page__content-description">
|
||||
@ -437,7 +442,7 @@ export default class SecurityTab extends PureComponent {
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div ref={this.settingsRefs[9]} className="settings-page__content-row">
|
||||
<div ref={this.settingsRefs[7]} className="settings-page__content-row">
|
||||
<div className="settings-page__content-item">
|
||||
<span>{t('useCollectibleDetection')}</span>
|
||||
<div className="settings-page__content-description">
|
||||
@ -477,6 +482,57 @@ export default class SecurityTab extends PureComponent {
|
||||
);
|
||||
}
|
||||
|
||||
renderCurrencyRateCheckToggle() {
|
||||
const { t } = this.context;
|
||||
const { useCurrencyRateCheck, setUseCurrencyRateCheck } = this.props;
|
||||
|
||||
return (
|
||||
<div ref={this.settingsRefs[9]} className="settings-page__content-row">
|
||||
<div className="settings-page__content-item">
|
||||
<span>{t('currencyRateCheckToggle')}</span>
|
||||
<div className="settings-page__content-description">
|
||||
{t('currencyRateCheckToggleDescription', [
|
||||
<a
|
||||
key="coingecko_link"
|
||||
href={COINGECKO_LINK}
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
{t('coingecko')}
|
||||
</a>,
|
||||
<a
|
||||
key="cryptocompare_link"
|
||||
href={CRYPTOCOMPARE_LINK}
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
{t('cryptoCompare')}
|
||||
</a>,
|
||||
<a
|
||||
key="privacy_policy_link"
|
||||
href={PRIVACY_POLICY_LINK}
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
{t('privacyMsg')}
|
||||
</a>,
|
||||
])}
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-page__content-item">
|
||||
<div className="settings-page__content-item-col">
|
||||
<ToggleButton
|
||||
value={useCurrencyRateCheck}
|
||||
onToggle={(value) => setUseCurrencyRateCheck(!value)}
|
||||
offLabel={t('off')}
|
||||
onLabel={t('on')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { warning } = this.props;
|
||||
|
||||
@ -503,6 +559,7 @@ export default class SecurityTab extends PureComponent {
|
||||
{this.context.t('transactions')}
|
||||
</span>
|
||||
<div className="settings-page__content-padded">
|
||||
{this.renderCurrencyRateCheckToggle()}
|
||||
{this.renderIncomingTransactionsOptIn()}
|
||||
</div>
|
||||
<span className="settings-page__security-tab-sub-header">
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
setUseTokenDetection,
|
||||
setIpfsGateway,
|
||||
setUseMultiAccountBalanceChecker,
|
||||
setUseCurrencyRateCheck,
|
||||
setUseNftDetection,
|
||||
setOpenSeaEnabled,
|
||||
} from '../../../store/actions';
|
||||
@ -26,6 +27,7 @@ const mapStateToProps = (state) => {
|
||||
useTokenDetection,
|
||||
ipfsGateway,
|
||||
useMultiAccountBalanceChecker,
|
||||
useCurrencyRateCheck,
|
||||
} = metamask;
|
||||
|
||||
return {
|
||||
@ -36,6 +38,7 @@ const mapStateToProps = (state) => {
|
||||
useTokenDetection,
|
||||
ipfsGateway,
|
||||
useMultiAccountBalanceChecker,
|
||||
useCurrencyRateCheck,
|
||||
useNftDetection: getUseNftDetection(state),
|
||||
openSeaEnabled: getOpenSeaEnabled(state),
|
||||
};
|
||||
@ -48,6 +51,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
setShowIncomingTransactionsFeatureFlag: (shouldShow) =>
|
||||
dispatch(setFeatureFlag('showIncomingTransactions', shouldShow)),
|
||||
setUsePhishDetect: (val) => dispatch(setUsePhishDetect(val)),
|
||||
setUseCurrencyRateCheck: (val) => dispatch(setUseCurrencyRateCheck(val)),
|
||||
setUseTokenDetection: (value) => {
|
||||
return dispatch(setUseTokenDetection(value));
|
||||
},
|
||||
|
@ -8,12 +8,14 @@ import SecurityTab from './security-tab.container';
|
||||
const mockSetFeatureFlag = jest.fn();
|
||||
const mockSetParticipateInMetaMetrics = jest.fn();
|
||||
const mockSetUsePhishDetect = jest.fn();
|
||||
const mockSetUseCurrencyRateCheck = jest.fn();
|
||||
|
||||
jest.mock('../../../store/actions.js', () => {
|
||||
return {
|
||||
setFeatureFlag: () => mockSetFeatureFlag,
|
||||
setParticipateInMetaMetrics: () => mockSetParticipateInMetaMetrics,
|
||||
setUsePhishDetect: () => mockSetUsePhishDetect,
|
||||
setUseCurrencyRateCheck: () => mockSetUseCurrencyRateCheck,
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -69,6 +69,7 @@ import {
|
||||
getTokenList,
|
||||
isHardwareWallet,
|
||||
getHardwareWalletType,
|
||||
getUseCurrencyRateCheck,
|
||||
} from '../../../selectors';
|
||||
|
||||
import { getValueFromWeiHex } from '../../../helpers/utils/conversions.util';
|
||||
@ -154,6 +155,7 @@ export default function BuildQuote({
|
||||
|
||||
const tokenConversionRates = useSelector(getTokenExchangeRates, isEqual);
|
||||
const conversionRate = useSelector(getConversionRate);
|
||||
const useCurrencyRateCheck = useSelector(getUseCurrencyRateCheck);
|
||||
const hardwareWalletUsed = useSelector(isHardwareWallet);
|
||||
const hardwareWalletType = useSelector(getHardwareWalletType);
|
||||
const smartTransactionsOptInStatus = useSelector(
|
||||
@ -255,13 +257,13 @@ export default function BuildQuote({
|
||||
fromTokenInputValue || 0,
|
||||
fromTokenSymbol,
|
||||
{
|
||||
showFiat: true,
|
||||
showFiat: useCurrencyRateCheck,
|
||||
},
|
||||
true,
|
||||
);
|
||||
const swapFromEthFiatValue = useEthFiatAmount(
|
||||
fromTokenInputValue || 0,
|
||||
{ showFiat: true },
|
||||
{ showFiat: useCurrencyRateCheck },
|
||||
true,
|
||||
);
|
||||
const swapFromFiatValue = isSwapsDefaultTokenSymbol(fromTokenSymbol, chainId)
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import { I18nContext } from '../../../contexts/i18n';
|
||||
import InfoTooltip from '../../../components/ui/info-tooltip';
|
||||
@ -13,6 +14,7 @@ import {
|
||||
} from '../../../helpers/constants/design-system';
|
||||
import { MetaMetricsContext } from '../../../contexts/metametrics';
|
||||
import { EVENT } from '../../../../shared/constants/metametrics';
|
||||
import { getUseCurrencyRateCheck } from '../../../selectors';
|
||||
|
||||
const GAS_FEES_LEARN_MORE_URL =
|
||||
'https://community.metamask.io/t/what-is-gas-why-do-transactions-take-so-long/3172';
|
||||
@ -30,6 +32,7 @@ export default function FeeCard({
|
||||
isBestQuote,
|
||||
}) {
|
||||
const t = useContext(I18nContext);
|
||||
const useCurrencyRateCheck = useSelector(getUseCurrencyRateCheck);
|
||||
|
||||
/* istanbul ignore next */
|
||||
const getTranslatedNetworkName = () => {
|
||||
@ -112,9 +115,10 @@ export default function FeeCard({
|
||||
</>
|
||||
}
|
||||
detailText={primaryFee.fee}
|
||||
detailTotal={secondaryFee.fee}
|
||||
detailTotal={useCurrencyRateCheck && secondaryFee.fee}
|
||||
subText={
|
||||
secondaryFee?.maxFee !== undefined && (
|
||||
(secondaryFee?.maxFee !== undefined ||
|
||||
primaryFee?.maxFee !== undefined) && (
|
||||
<>
|
||||
<Typography
|
||||
as="span"
|
||||
@ -124,7 +128,9 @@ export default function FeeCard({
|
||||
>
|
||||
{t('maxFee')}
|
||||
</Typography>
|
||||
{`: ${secondaryFee.maxFee}`}
|
||||
{useCurrencyRateCheck
|
||||
? `: ${secondaryFee.maxFee}`
|
||||
: `: ${primaryFee.maxFee}`}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
import React from 'react';
|
||||
import configureMockStore from 'redux-mock-store';
|
||||
import thunk from 'redux-thunk';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import {
|
||||
renderWithProvider,
|
||||
createSwapsMockStore,
|
||||
setBackgroundConnection,
|
||||
MOCKS,
|
||||
fireEvent,
|
||||
} from '../../../../test/jest';
|
||||
import { CHAIN_IDS } from '../../../../shared/constants/network';
|
||||
|
||||
import { checkNetworkAndAccountSupports1559 } from '../../../selectors';
|
||||
import {
|
||||
checkNetworkAndAccountSupports1559,
|
||||
getUseCurrencyRateCheck,
|
||||
} from '../../../selectors';
|
||||
import {
|
||||
getGasEstimateType,
|
||||
getGasFeeEstimates,
|
||||
@ -22,8 +22,6 @@ import { TRANSACTION_ENVELOPE_TYPE_NAMES } from '../../../helpers/constants/tran
|
||||
|
||||
import FeeCard from '.';
|
||||
|
||||
const middleware = [thunk];
|
||||
|
||||
jest.mock('../../../hooks/useGasFeeEstimates', () => ({
|
||||
useGasFeeEstimates: jest.fn(),
|
||||
}));
|
||||
@ -50,6 +48,9 @@ const generateUseSelectorRouter = () => (selector) => {
|
||||
if (selector === getIsGasEstimatesLoading) {
|
||||
return false;
|
||||
}
|
||||
if (selector === getUseCurrencyRateCheck) {
|
||||
return true;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
@ -109,13 +110,12 @@ describe('FeeCard', () => {
|
||||
});
|
||||
|
||||
it('renders the component with EIP-1559 enabled', () => {
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
const props = createProps({
|
||||
networkAndAccountSupports1559: true,
|
||||
maxPriorityFeePerGasDecGWEI: '3',
|
||||
maxFeePerGasDecGWEI: '4',
|
||||
});
|
||||
const { getByText } = renderWithProvider(<FeeCard {...props} />, store);
|
||||
const { getByText } = renderWithProvider(<FeeCard {...props} />);
|
||||
expect(getByText('Best of 6 quotes.')).toBeInTheDocument();
|
||||
expect(getByText('Estimated gas fee')).toBeInTheDocument();
|
||||
expect(getByText('Max fee')).toBeInTheDocument();
|
||||
@ -129,7 +129,6 @@ describe('FeeCard', () => {
|
||||
});
|
||||
|
||||
it('renders the component with smart transactions enabled and user opted in', () => {
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
const props = createProps({
|
||||
smartTransactionsOptInStatus: true,
|
||||
smartTransactionsEnabled: true,
|
||||
@ -138,7 +137,6 @@ describe('FeeCard', () => {
|
||||
});
|
||||
const { getByText, queryByTestId } = renderWithProvider(
|
||||
<FeeCard {...props} />,
|
||||
store,
|
||||
);
|
||||
expect(getByText('Best of 6 quotes.')).toBeInTheDocument();
|
||||
expect(getByText('Estimated gas fee')).toBeInTheDocument();
|
||||
@ -149,20 +147,18 @@ describe('FeeCard', () => {
|
||||
});
|
||||
|
||||
it('renders the component with hidden token approval row', () => {
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
const props = createProps({
|
||||
hideTokenApprovalRow: true,
|
||||
});
|
||||
const { queryByText } = renderWithProvider(<FeeCard {...props} />, store);
|
||||
const { queryByText } = renderWithProvider(<FeeCard {...props} />);
|
||||
expect(queryByText('Edit limit')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('approves a token', () => {
|
||||
const store = configureMockStore(middleware)(createSwapsMockStore());
|
||||
const props = createProps({
|
||||
onTokenApprovalClick: jest.fn(),
|
||||
});
|
||||
const { queryByText } = renderWithProvider(<FeeCard {...props} />, store);
|
||||
const { queryByText } = renderWithProvider(<FeeCard {...props} />);
|
||||
fireEvent.click(queryByText('Edit limit'));
|
||||
expect(props.onTokenApprovalClick).toHaveBeenCalled();
|
||||
});
|
||||
|
@ -10,6 +10,7 @@ import { I18nContext } from '../../../../contexts/i18n';
|
||||
import {
|
||||
getCurrentChainId,
|
||||
getRpcPrefsForCurrentProvider,
|
||||
getUseCurrencyRateCheck,
|
||||
} from '../../../../selectors';
|
||||
import { EVENT } from '../../../../../shared/constants/metametrics';
|
||||
import { SWAPS_CHAINID_DEFAULT_BLOCK_EXPLORER_URL_MAP } from '../../../../../shared/constants/swaps';
|
||||
@ -36,7 +37,7 @@ export default function ItemList({
|
||||
rpcPrefs.blockExplorerUrl ??
|
||||
SWAPS_CHAINID_DEFAULT_BLOCK_EXPLORER_URL_MAP[chainId] ??
|
||||
null;
|
||||
|
||||
const useCurrencyRateCheck = useSelector(getUseCurrencyRateCheck);
|
||||
const blockExplorerHostName = getURLHostName(blockExplorerLink);
|
||||
const trackEvent = useContext(MetaMetricsContext);
|
||||
|
||||
@ -124,7 +125,7 @@ export default function ItemList({
|
||||
{rightPrimaryLabel}
|
||||
</span>
|
||||
) : null}
|
||||
{rightSecondaryLabel ? (
|
||||
{rightSecondaryLabel && useCurrencyRateCheck ? (
|
||||
<span className="searchable-item-list__right-secondary-label">
|
||||
{rightSecondaryLabel}
|
||||
</span>
|
||||
|
@ -1,8 +1,10 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import { I18nContext } from '../../../../contexts/i18n';
|
||||
import InfoTooltip from '../../../../components/ui/info-tooltip';
|
||||
import ExchangeRateDisplay from '../../exchange-rate-display';
|
||||
import { getUseCurrencyRateCheck } from '../../../../selectors';
|
||||
|
||||
const QuoteDetails = ({
|
||||
slippage,
|
||||
@ -18,6 +20,8 @@ const QuoteDetails = ({
|
||||
hideEstimatedGasFee,
|
||||
}) => {
|
||||
const t = useContext(I18nContext);
|
||||
const useCurrencyRateCheck = useSelector(getUseCurrencyRateCheck);
|
||||
|
||||
return (
|
||||
<div className="quote-details">
|
||||
<div className="quote-details__row">
|
||||
@ -67,7 +71,9 @@ const QuoteDetails = ({
|
||||
</div>
|
||||
<div className="quote-details__detail-content">
|
||||
<span>{feeInEth}</span>
|
||||
<span className="quote-details__light-grey">{` (${networkFees})`}</span>
|
||||
<span className="quote-details__light-grey">
|
||||
{useCurrencyRateCheck && ` (${networkFees})`}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
@ -1,6 +1,8 @@
|
||||
import React from 'react';
|
||||
|
||||
import { renderWithProvider } from '../../../../test/jest';
|
||||
import configureStore from '../../../store/store';
|
||||
import mockState from '../../../../test/data/mock-state.json';
|
||||
import SelectQuotePopover from '.';
|
||||
|
||||
const createProps = (customProps = {}) => {
|
||||
@ -14,11 +16,13 @@ const createProps = (customProps = {}) => {
|
||||
...customProps,
|
||||
};
|
||||
};
|
||||
const store = configureStore(mockState);
|
||||
|
||||
describe('SelectQuotePopover', () => {
|
||||
it('renders the component with initial props', () => {
|
||||
const { container } = renderWithProvider(
|
||||
<SelectQuotePopover {...createProps()} />,
|
||||
store,
|
||||
);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, { useState, useContext, useMemo } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
import BigNumber from 'bignumber.js';
|
||||
@ -6,6 +7,7 @@ import SunCheckIcon from '../../../../components/ui/icon/sun-check-icon.componen
|
||||
import { I18nContext } from '../../../../contexts/i18n';
|
||||
import { QUOTE_DATA_ROWS_PROPTYPES_SHAPE } from '../select-quote-popover-constants';
|
||||
import InfoTooltip from '../../../../components/ui/info-tooltip';
|
||||
import { getUseCurrencyRateCheck } from '../../../../selectors';
|
||||
|
||||
const ToggleArrows = () => (
|
||||
<svg
|
||||
@ -36,6 +38,7 @@ export default function SortList({
|
||||
}) {
|
||||
const t = useContext(I18nContext);
|
||||
const [noRowHover, setRowNowHover] = useState(false);
|
||||
const useCurrencyRateCheck = useSelector(getUseCurrencyRateCheck);
|
||||
|
||||
const onColumnHeaderClick = (nextSortColumn) => {
|
||||
if (nextSortColumn === sortColumn) {
|
||||
@ -100,7 +103,7 @@ export default function SortList({
|
||||
data-testid="select-quote-popover__network-fees-header"
|
||||
onClick={() => onColumnHeaderClick('rawNetworkFees')}
|
||||
>
|
||||
{!hideEstimatedGasFee && (
|
||||
{!hideEstimatedGasFee && useCurrencyRateCheck && (
|
||||
<>
|
||||
<span>{t('swapEstimatedNetworkFees')}</span>
|
||||
<InfoTooltip
|
||||
@ -161,7 +164,7 @@ export default function SortList({
|
||||
)}
|
||||
</div>
|
||||
<div className="select-quote-popover__network-fees">
|
||||
{!hideEstimatedGasFee && networkFees}
|
||||
{!hideEstimatedGasFee && useCurrencyRateCheck && networkFees}
|
||||
</div>
|
||||
<div className="select-quote-popover__quote-source">
|
||||
<div
|
||||
|
@ -1,6 +1,8 @@
|
||||
import React from 'react';
|
||||
|
||||
import { renderWithProvider, fireEvent } from '../../../../../test/jest';
|
||||
import MockState from '../../../../../test/data/mock-state.json';
|
||||
import configureStore from '../../../../store/store';
|
||||
import SortList from './sort-list';
|
||||
|
||||
jest.mock(
|
||||
@ -71,8 +73,12 @@ const createProps = (customProps = {}) => {
|
||||
};
|
||||
|
||||
describe('SortList', () => {
|
||||
const store = configureStore(MockState);
|
||||
it('renders the component with initial props', () => {
|
||||
const { getByText } = renderWithProvider(<SortList {...createProps()} />);
|
||||
const { getByText } = renderWithProvider(
|
||||
<SortList {...createProps()} />,
|
||||
store,
|
||||
);
|
||||
expect(getByText('$15.25')).toBeInTheDocument();
|
||||
expect(getByText('$14.26')).toBeInTheDocument();
|
||||
expect(getByText('$13.27')).toBeInTheDocument();
|
||||
@ -89,28 +95,28 @@ describe('SortList', () => {
|
||||
|
||||
it('clicks on the "destinationTokenValue" header', () => {
|
||||
const props = createProps();
|
||||
const { getByTestId } = renderWithProvider(<SortList {...props} />);
|
||||
const { getByTestId } = renderWithProvider(<SortList {...props} />, store);
|
||||
fireEvent.click(getByTestId('select-quote-popover__receiving'));
|
||||
expect(props.setSortColumn).toHaveBeenCalledWith('destinationTokenValue');
|
||||
});
|
||||
|
||||
it('clicks on the "rawNetworkFees" header', () => {
|
||||
const props = createProps();
|
||||
const { getByTestId } = renderWithProvider(<SortList {...props} />);
|
||||
const { getByTestId } = renderWithProvider(<SortList {...props} />, store);
|
||||
fireEvent.click(getByTestId('select-quote-popover__network-fees-header'));
|
||||
expect(props.setSortColumn).toHaveBeenCalledWith('rawNetworkFees');
|
||||
});
|
||||
|
||||
it('clicks on the first aggregator', () => {
|
||||
const props = createProps();
|
||||
const { getByTestId } = renderWithProvider(<SortList {...props} />);
|
||||
const { getByTestId } = renderWithProvider(<SortList {...props} />, store);
|
||||
fireEvent.click(getByTestId('select-quote-popover-row-0'));
|
||||
expect(props.onSelect).toHaveBeenCalledWith('Agg1');
|
||||
});
|
||||
|
||||
it('clicks on a caret for the first aggregator', () => {
|
||||
const props = createProps();
|
||||
const { getByTestId } = renderWithProvider(<SortList {...props} />);
|
||||
const { getByTestId } = renderWithProvider(<SortList {...props} />, store);
|
||||
fireEvent.click(getByTestId('select-quote-popover__caret-right-0'));
|
||||
expect(props.onCaretClick).toHaveBeenCalledWith('Agg1');
|
||||
});
|
||||
|
@ -586,9 +586,12 @@ export function getShouldShowFiat(state) {
|
||||
const isMainNet = getIsMainnet(state);
|
||||
const isCustomNetwork = getIsCustomNetwork(state);
|
||||
const conversionRate = getConversionRate(state);
|
||||
const useCurrencyRateCheck = getUseCurrencyRateCheck(state);
|
||||
const { showFiatInTestnets } = getPreferences(state);
|
||||
return Boolean(
|
||||
(isMainNet || isCustomNetwork || showFiatInTestnets) && conversionRate,
|
||||
(isMainNet || isCustomNetwork || showFiatInTestnets) &&
|
||||
useCurrencyRateCheck &&
|
||||
conversionRate,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1388,3 +1391,13 @@ export function getShouldShowSeedPhraseReminder(state) {
|
||||
export function getCustomTokenAmount(state) {
|
||||
return state.appState.customTokenAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* To get the useCurrencyRateCheck flag which to check if the user prefers currency conversion
|
||||
*
|
||||
* @param {*} state
|
||||
* @returns Boolean
|
||||
*/
|
||||
export function getUseCurrencyRateCheck(state) {
|
||||
return Boolean(state.metamask.useCurrencyRateCheck);
|
||||
}
|
||||
|
@ -263,4 +263,9 @@ describe('Selectors', () => {
|
||||
mockState.metamask.notifications.test,
|
||||
]);
|
||||
});
|
||||
|
||||
it('#getUseCurrencyRateCheck', () => {
|
||||
const useCurrencyRateCheck = selectors.getUseCurrencyRateCheck(mockState);
|
||||
expect(useCurrencyRateCheck).toStrictEqual(true);
|
||||
});
|
||||
});
|
||||
|
@ -2748,6 +2748,19 @@ export function setUseNftDetection(val) {
|
||||
};
|
||||
}
|
||||
|
||||
export function setUseCurrencyRateCheck(val) {
|
||||
return (dispatch) => {
|
||||
dispatch(showLoadingIndication());
|
||||
log.debug(`background.setUseCurrencyRateCheck`);
|
||||
callBackgroundMethod('setUseCurrencyRateCheck', [val], (err) => {
|
||||
dispatch(hideLoadingIndication());
|
||||
if (err) {
|
||||
dispatch(displayWarning(err.message));
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function setOpenSeaEnabled(val) {
|
||||
return (dispatch) => {
|
||||
dispatch(showLoadingIndication());
|
||||
|
43
yarn.lock
43
yarn.lock
@ -3293,20 +3293,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@metamask/assets-controllers@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "@metamask/assets-controllers@npm:1.0.1"
|
||||
"@metamask/assets-controllers@npm:^3.0.1":
|
||||
version: 3.0.1
|
||||
resolution: "@metamask/assets-controllers@npm:3.0.1"
|
||||
dependencies:
|
||||
"@ethersproject/abi": ^5.7.0
|
||||
"@ethersproject/bignumber": ^5.7.0
|
||||
"@ethersproject/contracts": ^5.7.0
|
||||
"@ethersproject/providers": ^5.7.0
|
||||
"@metamask/base-controller": ~1.1.0
|
||||
"@metamask/contract-metadata": ^1.35.0
|
||||
"@metamask/controller-utils": ~1.0.0
|
||||
"@metamask/base-controller": ^1.1.1
|
||||
"@metamask/contract-metadata": ^2.1.0
|
||||
"@metamask/controller-utils": ^1.0.0
|
||||
"@metamask/metamask-eth-abis": 3.0.0
|
||||
"@metamask/network-controller": ~1.0.0
|
||||
"@metamask/preferences-controller": ~1.0.0
|
||||
"@metamask/network-controller": ^2.0.0
|
||||
"@metamask/preferences-controller": ^1.0.1
|
||||
"@types/uuid": ^8.3.0
|
||||
abort-controller: ^3.0.0
|
||||
async-mutex: ^0.2.6
|
||||
@ -3318,7 +3318,9 @@ __metadata:
|
||||
multiformats: ^9.5.2
|
||||
single-call-balance-checker-abi: ^1.0.0
|
||||
uuid: ^8.3.2
|
||||
checksum: 678f32126aa84de769065581661218a247166ef2e4918290a8e082dd9c7b175d84c5a4d4f431c884dc83201b183f324c2b5047bc69a2ea7825d710470cae5f87
|
||||
peerDependencies:
|
||||
"@metamask/network-controller": ^2.0.0
|
||||
checksum: c356a820929738e3ad83a5cfe20993a1e7c4dac6835b308d8cb32efe8542c339664ae3046a1dedce6ee2a4c45cec5528015309366fa96674837dca7ea001998f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -3336,7 +3338,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@metamask/base-controller@npm:^1.0.0, @metamask/base-controller@npm:^1.1.1, @metamask/base-controller@npm:~1.1.0":
|
||||
"@metamask/base-controller@npm:^1.0.0, @metamask/base-controller@npm:^1.1.1":
|
||||
version: 1.1.1
|
||||
resolution: "@metamask/base-controller@npm:1.1.1"
|
||||
dependencies:
|
||||
@ -3375,13 +3377,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@metamask/contract-metadata@npm:^1.35.0":
|
||||
version: 1.36.0
|
||||
resolution: "@metamask/contract-metadata@npm:1.36.0"
|
||||
checksum: 6b1bc0927536a7ed235f896dcb0dabbce1f7853eef5e58efdd6cc8294c2ef10dd0c46572d20df9df31563fb466a0a162101169d9e1595dd931c7eabb9fa5a7e9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@metamask/contract-metadata@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "@metamask/contract-metadata@npm:2.1.0"
|
||||
@ -3767,13 +3762,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@metamask/preferences-controller@npm:~1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "@metamask/preferences-controller@npm:1.0.0"
|
||||
"@metamask/preferences-controller@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "@metamask/preferences-controller@npm:1.0.1"
|
||||
dependencies:
|
||||
"@metamask/base-controller": ~1.0.0
|
||||
"@metamask/controller-utils": ~1.0.0
|
||||
checksum: dad15bf468031df470ebeb18fa71c8181f247f9c9fd2eac52f6ee71f77bda61d8b0b7f8dc492d4f4f1602e249dedc38360b5e90ca2902adbcbd7c56bbaec8282
|
||||
"@metamask/base-controller": ^1.1.1
|
||||
"@metamask/controller-utils": ^1.0.0
|
||||
checksum: 3ad7dcf40cc1dc6679d37f705418d4d18da2acce120ce6bd09b0e6755484d193139fd85cf2c0b7374d867ab8a03d7f5bc74ebc8c2cdc003d5872f33d34c1e965
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -22758,7 +22753,7 @@ __metadata:
|
||||
"@metamask/address-book-controller": ^1.0.0
|
||||
"@metamask/announcement-controller": ^1.0.0
|
||||
"@metamask/approval-controller": ^1.0.0
|
||||
"@metamask/assets-controllers": ^1.0.1
|
||||
"@metamask/assets-controllers": ^3.0.1
|
||||
"@metamask/auto-changelog": ^2.1.0
|
||||
"@metamask/base-controller": ^1.0.0
|
||||
"@metamask/contract-metadata": ^2.1.0
|
||||
|
Loading…
Reference in New Issue
Block a user