mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 01:47:00 +01:00
Add Opt-out Settings toggle for 4byte contract method names resolution (#20098)
* Adding 4byte toggle to settings UI and preferences * Adding 4byte toggle to advanced settings tab * adding use4ByteResolution privacy logic to getContractMethodData & getMethodDataAsync, removing unused useMethodData hook, adding clearKnownMethodData * add 4byte setting to onboarding advanced option * more test changes * adding e2e for 4byte setting toggle * test and copy changes, snap updates * removing 4byte from advanced section * adding settings constant and fixing refs * removing clearKnownMethodData, adding flag to selector, test fixes * e2e refactor, selectors refactor * adding tests * Fix jest tests, remove unwanted forceUpdateMetamaskState * Fix jest tests * lint:fix * settingsRefs fixes --------- Co-authored-by: David Walsh <davidwalsh83@gmail.com>
This commit is contained in:
parent
658ceb90d1
commit
2ff289e271
9
app/_locales/en/messages.json
generated
9
app/_locales/en/messages.json
generated
@ -3914,6 +3914,9 @@
|
|||||||
"skipAccountSecurityDetails": {
|
"skipAccountSecurityDetails": {
|
||||||
"message": "I understand that until I back up my Secret Recovery Phrase, I may lose my accounts and all of their assets."
|
"message": "I understand that until I back up my Secret Recovery Phrase, I may lose my accounts and all of their assets."
|
||||||
},
|
},
|
||||||
|
"smartContracts": {
|
||||||
|
"message": "Smart contracts"
|
||||||
|
},
|
||||||
"smartSwap": {
|
"smartSwap": {
|
||||||
"message": "Smart swap"
|
"message": "Smart swap"
|
||||||
},
|
},
|
||||||
@ -5207,6 +5210,12 @@
|
|||||||
"urlExistsErrorMsg": {
|
"urlExistsErrorMsg": {
|
||||||
"message": "This URL is currently used by the $1 network."
|
"message": "This URL is currently used by the $1 network."
|
||||||
},
|
},
|
||||||
|
"use4ByteResolution": {
|
||||||
|
"message": "Decode smart contracts"
|
||||||
|
},
|
||||||
|
"use4ByteResolutionDescription": {
|
||||||
|
"message": "To improve user experience, we customize the activity tab with messages based on the smart contracts you interact with. MetaMask uses a service called 4byte.directory to decode data and show you a version of a smart contact that's easier to read. This helps reduce your chances of approving malicious smart contract actions, but can result in your IP address being shared."
|
||||||
|
},
|
||||||
"useMultiAccountBalanceChecker": {
|
"useMultiAccountBalanceChecker": {
|
||||||
"message": "Batch account balance requests"
|
"message": "Batch account balance requests"
|
||||||
},
|
},
|
||||||
|
@ -39,6 +39,7 @@ export default class PreferencesController {
|
|||||||
// set to false will be using the static list from contract-metadata
|
// set to false will be using the static list from contract-metadata
|
||||||
useTokenDetection: false,
|
useTokenDetection: false,
|
||||||
useNftDetection: false,
|
useNftDetection: false,
|
||||||
|
use4ByteResolution: true,
|
||||||
useCurrencyRateCheck: true,
|
useCurrencyRateCheck: true,
|
||||||
openSeaEnabled: false,
|
openSeaEnabled: false,
|
||||||
///: BEGIN:ONLY_INCLUDE_IN(blockaid)
|
///: BEGIN:ONLY_INCLUDE_IN(blockaid)
|
||||||
@ -169,6 +170,15 @@ export default class PreferencesController {
|
|||||||
this.store.updateState({ useNftDetection });
|
this.store.updateState({ useNftDetection });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter for the `use4ByteResolution` property
|
||||||
|
*
|
||||||
|
* @param {boolean} use4ByteResolution - (Privacy) Whether or not the user prefers to have smart contract name details resolved with 4byte.directory
|
||||||
|
*/
|
||||||
|
setUse4ByteResolution(use4ByteResolution) {
|
||||||
|
this.store.updateState({ use4ByteResolution });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setter for the `useCurrencyRateCheck` property
|
* Setter for the `useCurrencyRateCheck` property
|
||||||
*
|
*
|
||||||
|
@ -233,6 +233,25 @@ describe('preferences controller', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('setUse4ByteResolution', function () {
|
||||||
|
it('should default to true', function () {
|
||||||
|
const state = preferencesController.store.getState();
|
||||||
|
assert.equal(state.use4ByteResolution, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the use4ByteResolution property in state', function () {
|
||||||
|
assert.equal(
|
||||||
|
preferencesController.store.getState().use4ByteResolution,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
preferencesController.setUse4ByteResolution(false);
|
||||||
|
assert.equal(
|
||||||
|
preferencesController.store.getState().use4ByteResolution,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('setOpenSeaEnabled', function () {
|
describe('setOpenSeaEnabled', function () {
|
||||||
it('should default to false', function () {
|
it('should default to false', function () {
|
||||||
const state = preferencesController.store.getState();
|
const state = preferencesController.store.getState();
|
||||||
|
@ -2230,6 +2230,9 @@ export default class MetamaskController extends EventEmitter {
|
|||||||
setUseNftDetection: preferencesController.setUseNftDetection.bind(
|
setUseNftDetection: preferencesController.setUseNftDetection.bind(
|
||||||
preferencesController,
|
preferencesController,
|
||||||
),
|
),
|
||||||
|
setUse4ByteResolution: preferencesController.setUse4ByteResolution.bind(
|
||||||
|
preferencesController,
|
||||||
|
),
|
||||||
setUseCurrencyRateCheck:
|
setUseCurrencyRateCheck:
|
||||||
preferencesController.setUseCurrencyRateCheck.bind(
|
preferencesController.setUseCurrencyRateCheck.bind(
|
||||||
preferencesController,
|
preferencesController,
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
"mostRecentOverviewPage": "/mostRecentOverviewPage"
|
"mostRecentOverviewPage": "/mostRecentOverviewPage"
|
||||||
},
|
},
|
||||||
"metamask": {
|
"metamask": {
|
||||||
|
"use4ByteResolution": true,
|
||||||
"ipfsGateway": "dweb.link",
|
"ipfsGateway": "dweb.link",
|
||||||
"dismissSeedBackUpReminder": false,
|
"dismissSeedBackUpReminder": false,
|
||||||
"usePhishDetect": true,
|
"usePhishDetect": true,
|
||||||
|
114
test/e2e/tests/4byte-directory.spec.js
Normal file
114
test/e2e/tests/4byte-directory.spec.js
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
const { strict: assert } = require('assert');
|
||||||
|
const FixtureBuilder = require('../fixture-builder');
|
||||||
|
const {
|
||||||
|
withFixtures,
|
||||||
|
openDapp,
|
||||||
|
unlockWallet,
|
||||||
|
largeDelayMs,
|
||||||
|
veryLargeDelayMs,
|
||||||
|
WINDOW_TITLES,
|
||||||
|
} = require('../helpers');
|
||||||
|
const { SMART_CONTRACTS } = require('../seeder/smart-contracts');
|
||||||
|
|
||||||
|
describe('4byte setting', function () {
|
||||||
|
it('makes a call to 4byte when the setting is on', async function () {
|
||||||
|
const smartContract = SMART_CONTRACTS.PIGGYBANK;
|
||||||
|
await withFixtures(
|
||||||
|
{
|
||||||
|
dapp: true,
|
||||||
|
fixtures: new FixtureBuilder()
|
||||||
|
.withPermissionControllerConnectedToTestDapp()
|
||||||
|
.build(),
|
||||||
|
smartContract,
|
||||||
|
title: this.test.title,
|
||||||
|
},
|
||||||
|
async ({ driver, contractRegistry }) => {
|
||||||
|
const contractAddress = await contractRegistry.getContractAddress(
|
||||||
|
smartContract,
|
||||||
|
);
|
||||||
|
await driver.navigate();
|
||||||
|
await unlockWallet(driver);
|
||||||
|
|
||||||
|
// deploy contract
|
||||||
|
await openDapp(driver, contractAddress);
|
||||||
|
|
||||||
|
// wait for deployed contract, calls and confirms a contract method where ETH is sent
|
||||||
|
await driver.delay(largeDelayMs);
|
||||||
|
await driver.clickElement('#depositButton');
|
||||||
|
|
||||||
|
await driver.waitForSelector({
|
||||||
|
css: 'span',
|
||||||
|
text: 'Deposit initiated',
|
||||||
|
});
|
||||||
|
|
||||||
|
await driver.waitUntilXWindowHandles(3);
|
||||||
|
await driver.switchToWindowWithTitle(WINDOW_TITLES.Notification);
|
||||||
|
const actionElement = await driver.waitForSelector({
|
||||||
|
css: '.confirm-page-container-summary__action__name',
|
||||||
|
text: 'Deposit',
|
||||||
|
});
|
||||||
|
assert.equal(await actionElement.getText(), 'DEPOSIT');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not try to get contract method name from 4byte when the setting is off', async function () {
|
||||||
|
const smartContract = SMART_CONTRACTS.PIGGYBANK;
|
||||||
|
await withFixtures(
|
||||||
|
{
|
||||||
|
dapp: true,
|
||||||
|
fixtures: new FixtureBuilder()
|
||||||
|
.withPermissionControllerConnectedToTestDapp()
|
||||||
|
.build(),
|
||||||
|
smartContract,
|
||||||
|
title: this.test.title,
|
||||||
|
},
|
||||||
|
async ({ driver, contractRegistry }) => {
|
||||||
|
const contractAddress = await contractRegistry.getContractAddress(
|
||||||
|
smartContract,
|
||||||
|
);
|
||||||
|
await driver.navigate();
|
||||||
|
await unlockWallet(driver);
|
||||||
|
|
||||||
|
// goes to the settings screen
|
||||||
|
await driver.clickElement(
|
||||||
|
'[data-testid="account-options-menu-button"]',
|
||||||
|
);
|
||||||
|
await driver.clickElement({ text: 'Settings', tag: 'div' });
|
||||||
|
await driver.clickElement({ text: 'Security & privacy', tag: 'div' });
|
||||||
|
|
||||||
|
// turns off 4Byte Directory contract method name resolution
|
||||||
|
await driver.clickElement(
|
||||||
|
'[data-testid="4byte-resolution-container"] .toggle-button',
|
||||||
|
);
|
||||||
|
|
||||||
|
// deploy contract
|
||||||
|
await openDapp(driver, contractAddress);
|
||||||
|
|
||||||
|
// wait for deployed contract, calls and confirms a contract method where ETH is sent
|
||||||
|
await driver.findClickableElement('#depositButton');
|
||||||
|
await driver.clickElement('#depositButton');
|
||||||
|
|
||||||
|
await driver.waitForSelector({
|
||||||
|
css: 'span',
|
||||||
|
text: 'Deposit initiated',
|
||||||
|
});
|
||||||
|
|
||||||
|
await driver.waitUntilXWindowHandles(3);
|
||||||
|
await driver.switchToWindowWithTitle(WINDOW_TITLES.Notification);
|
||||||
|
const contractInteraction = 'Contract interaction';
|
||||||
|
const actionElement = await driver.waitForSelector({
|
||||||
|
css: '.confirm-page-container-summary__action__name',
|
||||||
|
text: contractInteraction,
|
||||||
|
});
|
||||||
|
// We add a delay here to wait for any potential UI changes
|
||||||
|
await driver.delay(veryLargeDelayMs);
|
||||||
|
// css text-transform: uppercase is applied to the text
|
||||||
|
assert.equal(
|
||||||
|
await actionElement.getText(),
|
||||||
|
contractInteraction.toUpperCase(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
@ -47,6 +47,7 @@ const initialState = {
|
|||||||
firstTimeFlowType: null,
|
firstTimeFlowType: null,
|
||||||
completedOnboarding: false,
|
completedOnboarding: false,
|
||||||
knownMethodData: {},
|
knownMethodData: {},
|
||||||
|
use4ByteResolution: true,
|
||||||
participateInMetaMetrics: null,
|
participateInMetaMetrics: null,
|
||||||
nextNonce: null,
|
nextNonce: null,
|
||||||
conversionRate: null,
|
conversionRate: null,
|
||||||
|
@ -163,6 +163,13 @@ export const SETTINGS_CONSTANTS = [
|
|||||||
route: `${SECURITY_ROUTE}#phishing-detection`,
|
route: `${SECURITY_ROUTE}#phishing-detection`,
|
||||||
icon: 'fa fa-lock',
|
icon: 'fa fa-lock',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
tabMessage: (t) => t('securityAndPrivacy'),
|
||||||
|
sectionMessage: (t) => t('use4ByteResolution'),
|
||||||
|
descriptionMessage: (t) => t('use4ByteResolutionDescription'),
|
||||||
|
route: `${SECURITY_ROUTE}#decode-smart-contracts`,
|
||||||
|
icon: 'fa fa-lock',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
tabMessage: (t) => t('securityAndPrivacy'),
|
tabMessage: (t) => t('securityAndPrivacy'),
|
||||||
sectionMessage: (t) => t('participateInMetaMetrics'),
|
sectionMessage: (t) => t('participateInMetaMetrics'),
|
||||||
|
@ -165,7 +165,7 @@ describe('Settings Search Utils', () => {
|
|||||||
it('should get good security & privacy section number', () => {
|
it('should get good security & privacy section number', () => {
|
||||||
expect(
|
expect(
|
||||||
getNumberOfSettingsInSection(t, t('securityAndPrivacy')),
|
getNumberOfSettingsInSection(t, t('securityAndPrivacy')),
|
||||||
).toStrictEqual(12);
|
).toStrictEqual(13);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get good alerts section number', () => {
|
it('should get good alerts section number', () => {
|
||||||
|
@ -49,14 +49,18 @@ let registry;
|
|||||||
* Attempts to return the method data from the MethodRegistry library, the message registry library and the token abi, in that order of preference
|
* Attempts to return the method data from the MethodRegistry library, the message registry library and the token abi, in that order of preference
|
||||||
*
|
*
|
||||||
* @param {string} fourBytePrefix - The prefix from the method code associated with the data
|
* @param {string} fourBytePrefix - The prefix from the method code associated with the data
|
||||||
|
* @param {boolean} allow4ByteRequests - Whether or not to allow 4byte.directory requests, toggled by the user in privacy settings
|
||||||
* @returns {object}
|
* @returns {object}
|
||||||
*/
|
*/
|
||||||
export async function getMethodDataAsync(fourBytePrefix) {
|
export async function getMethodDataAsync(fourBytePrefix, allow4ByteRequests) {
|
||||||
try {
|
try {
|
||||||
const fourByteSig = await getMethodFrom4Byte(fourBytePrefix).catch((e) => {
|
let fourByteSig = null;
|
||||||
log.error(e);
|
if (allow4ByteRequests) {
|
||||||
return null;
|
fourByteSig = await getMethodFrom4Byte(fourBytePrefix).catch((e) => {
|
||||||
});
|
log.error(e);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!registry) {
|
if (!registry) {
|
||||||
registry = new MethodRegistry({ provider: global.ethereumProvider });
|
registry = new MethodRegistry({ provider: global.ethereumProvider });
|
||||||
|
@ -62,7 +62,7 @@ describe('Transactions utils', () => {
|
|||||||
global.ethereumProvider = new HttpProvider(
|
global.ethereumProvider = new HttpProvider(
|
||||||
'https://mainnet.infura.io/v3/341eacb578dd44a1a049cbc5f6fd4035',
|
'https://mainnet.infura.io/v3/341eacb578dd44a1a049cbc5f6fd4035',
|
||||||
);
|
);
|
||||||
it('returns a valid signature for setApprovalForAll', async () => {
|
it('returns a valid signature for setApprovalForAll when use4ByteResolution privacy setting is ON', async () => {
|
||||||
nock('https://www.4byte.directory:443', { encodedQueryParams: true })
|
nock('https://www.4byte.directory:443', { encodedQueryParams: true })
|
||||||
.get('/api/v1/signatures/')
|
.get('/api/v1/signatures/')
|
||||||
.query({ hex_signature: '0xa22cb465' })
|
.query({ hex_signature: '0xa22cb465' })
|
||||||
@ -87,7 +87,7 @@ describe('Transactions utils', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
expect(await utils.getMethodDataAsync('0xa22cb465')).toStrictEqual({
|
expect(await utils.getMethodDataAsync('0xa22cb465', true)).toStrictEqual({
|
||||||
name: 'Set Approval For All',
|
name: 'Set Approval For All',
|
||||||
params: [{ type: 'address' }, { type: 'bool' }],
|
params: [{ type: 'address' }, { type: 'bool' }],
|
||||||
});
|
});
|
||||||
|
@ -33,6 +33,7 @@ import { usePrevious } from '../../hooks/usePrevious';
|
|||||||
import {
|
import {
|
||||||
unconfirmedTransactionsListSelector,
|
unconfirmedTransactionsListSelector,
|
||||||
unconfirmedTransactionsHashSelector,
|
unconfirmedTransactionsHashSelector,
|
||||||
|
use4ByteResolutionSelector,
|
||||||
} from '../../selectors';
|
} from '../../selectors';
|
||||||
import {
|
import {
|
||||||
disconnectGasFeeEstimatePoller,
|
disconnectGasFeeEstimatePoller,
|
||||||
@ -71,6 +72,7 @@ const ConfirmTransaction = () => {
|
|||||||
unconfirmedTxsSorted,
|
unconfirmedTxsSorted,
|
||||||
]);
|
]);
|
||||||
const [transaction, setTransaction] = useState(getTransaction);
|
const [transaction, setTransaction] = useState(getTransaction);
|
||||||
|
const use4ByteResolution = useSelector(use4ByteResolutionSelector);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const tx = getTransaction();
|
const tx = getTransaction();
|
||||||
@ -127,7 +129,7 @@ const ConfirmTransaction = () => {
|
|||||||
const { txParams: { data } = {}, origin } = transaction;
|
const { txParams: { data } = {}, origin } = transaction;
|
||||||
|
|
||||||
if (origin !== ORIGIN_METAMASK) {
|
if (origin !== ORIGIN_METAMASK) {
|
||||||
dispatch(getContractMethodData(data));
|
dispatch(getContractMethodData(data, use4ByteResolution));
|
||||||
}
|
}
|
||||||
|
|
||||||
const txId = transactionId || paramsTransactionId;
|
const txId = transactionId || paramsTransactionId;
|
||||||
@ -154,7 +156,7 @@ const ConfirmTransaction = () => {
|
|||||||
dispatch(clearConfirmTransaction());
|
dispatch(clearConfirmTransaction());
|
||||||
dispatch(setTransactionToConfirm(paramsTransactionId));
|
dispatch(setTransactionToConfirm(paramsTransactionId));
|
||||||
if (origin !== ORIGIN_METAMASK) {
|
if (origin !== ORIGIN_METAMASK) {
|
||||||
dispatch(getContractMethodData(data));
|
dispatch(getContractMethodData(data, use4ByteResolution));
|
||||||
}
|
}
|
||||||
} else if (prevTransactionId && !transactionId && !totalUnapproved) {
|
} else if (prevTransactionId && !transactionId && !totalUnapproved) {
|
||||||
dispatch(setDefaultHomeActiveTabName('activity')).then(() => {
|
dispatch(setDefaultHomeActiveTabName('activity')).then(() => {
|
||||||
@ -178,6 +180,7 @@ const ConfirmTransaction = () => {
|
|||||||
totalUnapproved,
|
totalUnapproved,
|
||||||
transaction,
|
transaction,
|
||||||
transactionId,
|
transactionId,
|
||||||
|
use4ByteResolution,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (isValidTokenMethod && isValidTransactionId) {
|
if (isValidTokenMethod && isValidTransactionId) {
|
||||||
|
@ -36,6 +36,7 @@ import {
|
|||||||
setUseCurrencyRateCheck,
|
setUseCurrencyRateCheck,
|
||||||
setUseMultiAccountBalanceChecker,
|
setUseMultiAccountBalanceChecker,
|
||||||
setUsePhishDetect,
|
setUsePhishDetect,
|
||||||
|
setUse4ByteResolution,
|
||||||
setUseTokenDetection,
|
setUseTokenDetection,
|
||||||
setUseAddressBarEnsResolution,
|
setUseAddressBarEnsResolution,
|
||||||
showModal,
|
showModal,
|
||||||
@ -48,6 +49,7 @@ export default function PrivacySettings() {
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const [usePhishingDetection, setUsePhishingDetection] = useState(true);
|
const [usePhishingDetection, setUsePhishingDetection] = useState(true);
|
||||||
|
const [turnOn4ByteResolution, setTurnOn4ByteResolution] = useState(true);
|
||||||
const [turnOnTokenDetection, setTurnOnTokenDetection] = useState(true);
|
const [turnOnTokenDetection, setTurnOnTokenDetection] = useState(true);
|
||||||
const [turnOnCurrencyRateCheck, setTurnOnCurrencyRateCheck] = useState(true);
|
const [turnOnCurrencyRateCheck, setTurnOnCurrencyRateCheck] = useState(true);
|
||||||
const [showIncomingTransactions, setShowIncomingTransactions] =
|
const [showIncomingTransactions, setShowIncomingTransactions] =
|
||||||
@ -68,6 +70,7 @@ export default function PrivacySettings() {
|
|||||||
setFeatureFlag('showIncomingTransactions', showIncomingTransactions),
|
setFeatureFlag('showIncomingTransactions', showIncomingTransactions),
|
||||||
);
|
);
|
||||||
dispatch(setUsePhishDetect(usePhishingDetection));
|
dispatch(setUsePhishDetect(usePhishingDetection));
|
||||||
|
dispatch(setUse4ByteResolution(turnOn4ByteResolution));
|
||||||
dispatch(setUseTokenDetection(turnOnTokenDetection));
|
dispatch(setUseTokenDetection(turnOnTokenDetection));
|
||||||
dispatch(
|
dispatch(
|
||||||
setUseMultiAccountBalanceChecker(isMultiAccountBalanceCheckerEnabled),
|
setUseMultiAccountBalanceChecker(isMultiAccountBalanceCheckerEnabled),
|
||||||
@ -171,6 +174,12 @@ export default function PrivacySettings() {
|
|||||||
</a>,
|
</a>,
|
||||||
])}
|
])}
|
||||||
/>
|
/>
|
||||||
|
<Setting
|
||||||
|
value={turnOn4ByteResolution}
|
||||||
|
setValue={setTurnOn4ByteResolution}
|
||||||
|
title={t('use4ByteResolution')}
|
||||||
|
description={t('use4ByteResolutionDescription')}
|
||||||
|
/>
|
||||||
<Setting
|
<Setting
|
||||||
value={turnOnTokenDetection}
|
value={turnOnTokenDetection}
|
||||||
setValue={setTurnOnTokenDetection}
|
setValue={setTurnOnTokenDetection}
|
||||||
|
@ -21,6 +21,7 @@ describe('Privacy Settings Onboarding View', () => {
|
|||||||
const store = configureMockStore([thunk])(mockStore);
|
const store = configureMockStore([thunk])(mockStore);
|
||||||
const setFeatureFlagStub = jest.fn();
|
const setFeatureFlagStub = jest.fn();
|
||||||
const setUsePhishDetectStub = jest.fn();
|
const setUsePhishDetectStub = jest.fn();
|
||||||
|
const setUse4ByteResolutionStub = jest.fn();
|
||||||
const setUseTokenDetectionStub = jest.fn();
|
const setUseTokenDetectionStub = jest.fn();
|
||||||
const setUseCurrencyRateCheckStub = jest.fn();
|
const setUseCurrencyRateCheckStub = jest.fn();
|
||||||
const setIpfsGatewayStub = jest.fn();
|
const setIpfsGatewayStub = jest.fn();
|
||||||
@ -33,6 +34,7 @@ describe('Privacy Settings Onboarding View', () => {
|
|||||||
setBackgroundConnection({
|
setBackgroundConnection({
|
||||||
setFeatureFlag: setFeatureFlagStub,
|
setFeatureFlag: setFeatureFlagStub,
|
||||||
setUsePhishDetect: setUsePhishDetectStub,
|
setUsePhishDetect: setUsePhishDetectStub,
|
||||||
|
setUse4ByteResolution: setUse4ByteResolutionStub,
|
||||||
setUseTokenDetection: setUseTokenDetectionStub,
|
setUseTokenDetection: setUseTokenDetectionStub,
|
||||||
setUseCurrencyRateCheck: setUseCurrencyRateCheckStub,
|
setUseCurrencyRateCheck: setUseCurrencyRateCheckStub,
|
||||||
setIpfsGateway: setIpfsGatewayStub,
|
setIpfsGateway: setIpfsGatewayStub,
|
||||||
@ -49,6 +51,7 @@ describe('Privacy Settings Onboarding View', () => {
|
|||||||
// All settings are initialized toggled to true
|
// All settings are initialized toggled to true
|
||||||
expect(setFeatureFlagStub).toHaveBeenCalledTimes(0);
|
expect(setFeatureFlagStub).toHaveBeenCalledTimes(0);
|
||||||
expect(setUsePhishDetectStub).toHaveBeenCalledTimes(0);
|
expect(setUsePhishDetectStub).toHaveBeenCalledTimes(0);
|
||||||
|
expect(setUse4ByteResolutionStub).toHaveBeenCalledTimes(0);
|
||||||
expect(setUseTokenDetectionStub).toHaveBeenCalledTimes(0);
|
expect(setUseTokenDetectionStub).toHaveBeenCalledTimes(0);
|
||||||
expect(setUseMultiAccountBalanceCheckerStub).toHaveBeenCalledTimes(0);
|
expect(setUseMultiAccountBalanceCheckerStub).toHaveBeenCalledTimes(0);
|
||||||
expect(setUseCurrencyRateCheckStub).toHaveBeenCalledTimes(0);
|
expect(setUseCurrencyRateCheckStub).toHaveBeenCalledTimes(0);
|
||||||
@ -64,10 +67,12 @@ describe('Privacy Settings Onboarding View', () => {
|
|||||||
fireEvent.click(toggles[3]);
|
fireEvent.click(toggles[3]);
|
||||||
fireEvent.click(toggles[4]);
|
fireEvent.click(toggles[4]);
|
||||||
fireEvent.click(toggles[5]);
|
fireEvent.click(toggles[5]);
|
||||||
|
fireEvent.click(toggles[6]);
|
||||||
fireEvent.click(submitButton);
|
fireEvent.click(submitButton);
|
||||||
|
|
||||||
expect(setFeatureFlagStub).toHaveBeenCalledTimes(1);
|
expect(setFeatureFlagStub).toHaveBeenCalledTimes(1);
|
||||||
expect(setUsePhishDetectStub).toHaveBeenCalledTimes(1);
|
expect(setUsePhishDetectStub).toHaveBeenCalledTimes(1);
|
||||||
|
expect(setUse4ByteResolutionStub).toHaveBeenCalledTimes(1);
|
||||||
expect(setUseTokenDetectionStub).toHaveBeenCalledTimes(1);
|
expect(setUseTokenDetectionStub).toHaveBeenCalledTimes(1);
|
||||||
expect(setUseMultiAccountBalanceCheckerStub).toHaveBeenCalledTimes(1);
|
expect(setUseMultiAccountBalanceCheckerStub).toHaveBeenCalledTimes(1);
|
||||||
expect(setUseCurrencyRateCheckStub).toHaveBeenCalledTimes(1);
|
expect(setUseCurrencyRateCheckStub).toHaveBeenCalledTimes(1);
|
||||||
@ -75,6 +80,7 @@ describe('Privacy Settings Onboarding View', () => {
|
|||||||
|
|
||||||
expect(setFeatureFlagStub.mock.calls[0][1]).toStrictEqual(false);
|
expect(setFeatureFlagStub.mock.calls[0][1]).toStrictEqual(false);
|
||||||
expect(setUsePhishDetectStub.mock.calls[0][0]).toStrictEqual(false);
|
expect(setUsePhishDetectStub.mock.calls[0][0]).toStrictEqual(false);
|
||||||
|
expect(setUse4ByteResolutionStub.mock.calls[0][0]).toStrictEqual(false);
|
||||||
expect(setUseTokenDetectionStub.mock.calls[0][0]).toStrictEqual(false);
|
expect(setUseTokenDetectionStub.mock.calls[0][0]).toStrictEqual(false);
|
||||||
expect(setUseMultiAccountBalanceCheckerStub.mock.calls[0][0]).toStrictEqual(
|
expect(setUseMultiAccountBalanceCheckerStub.mock.calls[0][0]).toStrictEqual(
|
||||||
false,
|
false,
|
||||||
@ -91,9 +97,11 @@ describe('Privacy Settings Onboarding View', () => {
|
|||||||
fireEvent.click(toggles[3]);
|
fireEvent.click(toggles[3]);
|
||||||
fireEvent.click(toggles[4]);
|
fireEvent.click(toggles[4]);
|
||||||
fireEvent.click(toggles[5]);
|
fireEvent.click(toggles[5]);
|
||||||
|
fireEvent.click(toggles[6]);
|
||||||
fireEvent.click(submitButton);
|
fireEvent.click(submitButton);
|
||||||
expect(setFeatureFlagStub).toHaveBeenCalledTimes(2);
|
expect(setFeatureFlagStub).toHaveBeenCalledTimes(2);
|
||||||
expect(setUsePhishDetectStub).toHaveBeenCalledTimes(2);
|
expect(setUsePhishDetectStub).toHaveBeenCalledTimes(2);
|
||||||
|
expect(setUse4ByteResolutionStub).toHaveBeenCalledTimes(2);
|
||||||
expect(setUseTokenDetectionStub).toHaveBeenCalledTimes(2);
|
expect(setUseTokenDetectionStub).toHaveBeenCalledTimes(2);
|
||||||
expect(setUseMultiAccountBalanceCheckerStub).toHaveBeenCalledTimes(2);
|
expect(setUseMultiAccountBalanceCheckerStub).toHaveBeenCalledTimes(2);
|
||||||
expect(setUseCurrencyRateCheckStub).toHaveBeenCalledTimes(2);
|
expect(setUseCurrencyRateCheckStub).toHaveBeenCalledTimes(2);
|
||||||
@ -101,6 +109,7 @@ describe('Privacy Settings Onboarding View', () => {
|
|||||||
|
|
||||||
expect(setFeatureFlagStub.mock.calls[1][1]).toStrictEqual(true);
|
expect(setFeatureFlagStub.mock.calls[1][1]).toStrictEqual(true);
|
||||||
expect(setUsePhishDetectStub.mock.calls[1][0]).toStrictEqual(true);
|
expect(setUsePhishDetectStub.mock.calls[1][0]).toStrictEqual(true);
|
||||||
|
expect(setUse4ByteResolutionStub.mock.calls[1][0]).toStrictEqual(true);
|
||||||
expect(setUseTokenDetectionStub.mock.calls[1][0]).toStrictEqual(true);
|
expect(setUseTokenDetectionStub.mock.calls[1][0]).toStrictEqual(true);
|
||||||
expect(setUseMultiAccountBalanceCheckerStub.mock.calls[1][0]).toStrictEqual(
|
expect(setUseMultiAccountBalanceCheckerStub.mock.calls[1][0]).toStrictEqual(
|
||||||
true,
|
true,
|
||||||
|
@ -113,6 +113,87 @@ exports[`Security Tab should match snapshot 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
class="settings-page__security-tab-sub-header"
|
||||||
|
>
|
||||||
|
Smart contracts
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="settings-page__content-padded"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="settings-page__content-row"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="settings-page__content-item"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Decode smart contracts
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
class="settings-page__content-description"
|
||||||
|
>
|
||||||
|
To improve user experience, we customize the activity tab with messages based on the smart contracts you interact with. MetaMask uses a service called 4byte.directory to decode data and show you a version of a smart contact that's easier to read. This helps reduce your chances of approving malicious smart contract actions, but can result in your IP address being shared.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="settings-page__content-item"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="settings-page__content-item-col"
|
||||||
|
data-testid="4byte-resolution-container"
|
||||||
|
>
|
||||||
|
<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>
|
||||||
<span
|
<span
|
||||||
class="settings-page__security-tab-sub-header"
|
class="settings-page__security-tab-sub-header"
|
||||||
>
|
>
|
||||||
|
@ -61,6 +61,8 @@ export default class SecurityTab extends PureComponent {
|
|||||||
setShowIncomingTransactionsFeatureFlag: PropTypes.func.isRequired,
|
setShowIncomingTransactionsFeatureFlag: PropTypes.func.isRequired,
|
||||||
setUsePhishDetect: PropTypes.func.isRequired,
|
setUsePhishDetect: PropTypes.func.isRequired,
|
||||||
usePhishDetect: PropTypes.bool.isRequired,
|
usePhishDetect: PropTypes.bool.isRequired,
|
||||||
|
setUse4ByteResolution: PropTypes.func.isRequired,
|
||||||
|
use4ByteResolution: PropTypes.bool.isRequired,
|
||||||
useTokenDetection: PropTypes.bool.isRequired,
|
useTokenDetection: PropTypes.bool.isRequired,
|
||||||
setUseTokenDetection: PropTypes.func.isRequired,
|
setUseTokenDetection: PropTypes.func.isRequired,
|
||||||
setIpfsGateway: PropTypes.func.isRequired,
|
setIpfsGateway: PropTypes.func.isRequired,
|
||||||
@ -254,6 +256,34 @@ export default class SecurityTab extends PureComponent {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderUse4ByteResolutionToggle() {
|
||||||
|
const { t } = this.context;
|
||||||
|
const { use4ByteResolution, setUse4ByteResolution } = this.props;
|
||||||
|
return (
|
||||||
|
<div ref={this.settingsRefs[3]} className="settings-page__content-row">
|
||||||
|
<div className="settings-page__content-item">
|
||||||
|
<span>{t('use4ByteResolution')}</span>
|
||||||
|
<div className="settings-page__content-description">
|
||||||
|
{t('use4ByteResolutionDescription')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="settings-page__content-item">
|
||||||
|
<div
|
||||||
|
className="settings-page__content-item-col"
|
||||||
|
data-testid="4byte-resolution-container"
|
||||||
|
>
|
||||||
|
<ToggleButton
|
||||||
|
value={use4ByteResolution}
|
||||||
|
onToggle={(value) => setUse4ByteResolution(!value)}
|
||||||
|
offLabel={t('off')}
|
||||||
|
onLabel={t('on')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
renderMetaMetricsOptIn() {
|
renderMetaMetricsOptIn() {
|
||||||
const { t } = this.context;
|
const { t } = this.context;
|
||||||
const { participateInMetaMetrics, setParticipateInMetaMetrics } =
|
const { participateInMetaMetrics, setParticipateInMetaMetrics } =
|
||||||
@ -261,7 +291,7 @@ export default class SecurityTab extends PureComponent {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
ref={this.settingsRefs[3]}
|
ref={this.settingsRefs[4]}
|
||||||
className="settings-page__content-row"
|
className="settings-page__content-row"
|
||||||
display={Display.Flex}
|
display={Display.Flex}
|
||||||
flexDirection={FlexDirection.Row}
|
flexDirection={FlexDirection.Row}
|
||||||
@ -294,7 +324,7 @@ export default class SecurityTab extends PureComponent {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
ref={this.settingsRefs[4]}
|
ref={this.settingsRefs[5]}
|
||||||
className="settings-page__content-row"
|
className="settings-page__content-row"
|
||||||
data-testid="advanced-setting-choose-your-network"
|
data-testid="advanced-setting-choose-your-network"
|
||||||
display={Display.Flex}
|
display={Display.Flex}
|
||||||
@ -384,7 +414,7 @@ export default class SecurityTab extends PureComponent {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
ref={this.settingsRefs[5]}
|
ref={this.settingsRefs[6]}
|
||||||
className="settings-page__content-row"
|
className="settings-page__content-row"
|
||||||
data-testid="setting-ipfs-gateway"
|
data-testid="setting-ipfs-gateway"
|
||||||
display={Display.Flex}
|
display={Display.Flex}
|
||||||
@ -428,7 +458,7 @@ export default class SecurityTab extends PureComponent {
|
|||||||
display={Display.Flex}
|
display={Display.Flex}
|
||||||
flexDirection={FlexDirection.Row}
|
flexDirection={FlexDirection.Row}
|
||||||
justifyContent={JustifyContent.spaceBetween}
|
justifyContent={JustifyContent.spaceBetween}
|
||||||
ref={this.settingsRefs[9]}
|
ref={this.settingsRefs[10]}
|
||||||
marginTop={3}
|
marginTop={3}
|
||||||
id="ens-domains"
|
id="ens-domains"
|
||||||
>
|
>
|
||||||
@ -495,7 +525,7 @@ export default class SecurityTab extends PureComponent {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
ref={this.settingsRefs[6]}
|
ref={this.settingsRefs[7]}
|
||||||
className="settings-page__content-row"
|
className="settings-page__content-row"
|
||||||
data-testid="advanced-setting-gas-fee-estimation"
|
data-testid="advanced-setting-gas-fee-estimation"
|
||||||
display={Display.Flex}
|
display={Display.Flex}
|
||||||
@ -548,7 +578,7 @@ export default class SecurityTab extends PureComponent {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
ref={this.settingsRefs[7]}
|
ref={this.settingsRefs[8]}
|
||||||
className="settings-page__content-row"
|
className="settings-page__content-row"
|
||||||
display={Display.Flex}
|
display={Display.Flex}
|
||||||
flexDirection={FlexDirection.Row}
|
flexDirection={FlexDirection.Row}
|
||||||
@ -589,7 +619,7 @@ export default class SecurityTab extends PureComponent {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
ref={this.settingsRefs[8]}
|
ref={this.settingsRefs[9]}
|
||||||
className="settings-page__content-row"
|
className="settings-page__content-row"
|
||||||
display={Display.Flex}
|
display={Display.Flex}
|
||||||
flexDirection={FlexDirection.Row}
|
flexDirection={FlexDirection.Row}
|
||||||
@ -653,7 +683,7 @@ export default class SecurityTab extends PureComponent {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
ref={this.settingsRefs[10]}
|
ref={this.settingsRefs[11]}
|
||||||
className="settings-page__content-row"
|
className="settings-page__content-row"
|
||||||
display={Display.Flex}
|
display={Display.Flex}
|
||||||
flexDirection={FlexDirection.Row}
|
flexDirection={FlexDirection.Row}
|
||||||
@ -705,7 +735,7 @@ export default class SecurityTab extends PureComponent {
|
|||||||
} = this.props;
|
} = this.props;
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
ref={this.settingsRefs[11]}
|
ref={this.settingsRefs[12]}
|
||||||
className="settings-page__content-row"
|
className="settings-page__content-row"
|
||||||
display={Display.Flex}
|
display={Display.Flex}
|
||||||
flexDirection={FlexDirection.Row}
|
flexDirection={FlexDirection.Row}
|
||||||
@ -770,12 +800,21 @@ export default class SecurityTab extends PureComponent {
|
|||||||
{this.context.t('privacy')}
|
{this.context.t('privacy')}
|
||||||
</span>
|
</span>
|
||||||
<div>
|
<div>
|
||||||
<span className="settings-page__security-tab-sub-header">Alerts</span>
|
<span className="settings-page__security-tab-sub-header">
|
||||||
|
{this.context.t('alerts')}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="settings-page__content-padded">
|
<div className="settings-page__content-padded">
|
||||||
{this.renderPhishingDetectionToggle()}
|
{this.renderPhishingDetectionToggle()}
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<span className="settings-page__security-tab-sub-header">
|
||||||
|
{this.context.t('smartContracts')}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="settings-page__content-padded">
|
||||||
|
{this.renderUse4ByteResolutionToggle()}
|
||||||
|
</div>
|
||||||
<span className="settings-page__security-tab-sub-header">
|
<span className="settings-page__security-tab-sub-header">
|
||||||
{this.context.t('transactions')}
|
{this.context.t('transactions')}
|
||||||
</span>
|
</span>
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
setUseAddressBarEnsResolution,
|
setUseAddressBarEnsResolution,
|
||||||
setOpenSeaEnabled,
|
setOpenSeaEnabled,
|
||||||
setUseNftDetection,
|
setUseNftDetection,
|
||||||
|
setUse4ByteResolution,
|
||||||
} from '../../../store/actions';
|
} from '../../../store/actions';
|
||||||
import SecurityTab from './security-tab.component';
|
import SecurityTab from './security-tab.component';
|
||||||
|
|
||||||
@ -31,6 +32,7 @@ const mapStateToProps = (state) => {
|
|||||||
useAddressBarEnsResolution,
|
useAddressBarEnsResolution,
|
||||||
openSeaEnabled,
|
openSeaEnabled,
|
||||||
useNftDetection,
|
useNftDetection,
|
||||||
|
use4ByteResolution,
|
||||||
} = metamask;
|
} = metamask;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -45,6 +47,7 @@ const mapStateToProps = (state) => {
|
|||||||
useAddressBarEnsResolution,
|
useAddressBarEnsResolution,
|
||||||
openSeaEnabled,
|
openSeaEnabled,
|
||||||
useNftDetection,
|
useNftDetection,
|
||||||
|
use4ByteResolution,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -69,6 +72,9 @@ const mapDispatchToProps = (dispatch) => {
|
|||||||
dispatch(setUseAddressBarEnsResolution(value)),
|
dispatch(setUseAddressBarEnsResolution(value)),
|
||||||
setOpenSeaEnabled: (val) => dispatch(setOpenSeaEnabled(val)),
|
setOpenSeaEnabled: (val) => dispatch(setOpenSeaEnabled(val)),
|
||||||
setUseNftDetection: (val) => dispatch(setUseNftDetection(val)),
|
setUseNftDetection: (val) => dispatch(setUseNftDetection(val)),
|
||||||
|
setUse4ByteResolution: (value) => {
|
||||||
|
return dispatch(setUse4ByteResolution(value));
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -58,6 +58,10 @@ describe('Security Tab', () => {
|
|||||||
expect(await toggleCheckbox('usePhishingDetection', true)).toBe(true);
|
expect(await toggleCheckbox('usePhishingDetection', true)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('toggles 4byte resolution', async () => {
|
||||||
|
expect(await toggleCheckbox('4byte-resolution-container', true)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it('toggles balance and token price checker', async () => {
|
it('toggles balance and token price checker', async () => {
|
||||||
expect(await toggleCheckbox('currencyRateCheckToggle', true)).toBe(true);
|
expect(await toggleCheckbox('currencyRateCheckToggle', true)).toBe(true);
|
||||||
});
|
});
|
||||||
|
@ -141,7 +141,8 @@ export const unconfirmedMessagesHashSelector = createSelector(
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
export const use4ByteResolutionSelector = (state) =>
|
||||||
|
state.metamask.use4ByteResolution;
|
||||||
export const currentCurrencySelector = (state) =>
|
export const currentCurrencySelector = (state) =>
|
||||||
state.metamask.currentCurrency;
|
state.metamask.currentCurrency;
|
||||||
export const conversionRateSelector = (state) => state.metamask.conversionRate;
|
export const conversionRateSelector = (state) => state.metamask.conversionRate;
|
||||||
|
@ -698,9 +698,9 @@ export function getKnownMethodData(state, data) {
|
|||||||
}
|
}
|
||||||
const prefixedData = addHexPrefix(data);
|
const prefixedData = addHexPrefix(data);
|
||||||
const fourBytePrefix = prefixedData.slice(0, 10);
|
const fourBytePrefix = prefixedData.slice(0, 10);
|
||||||
const { knownMethodData } = state.metamask;
|
const { knownMethodData, use4ByteResolution } = state.metamask;
|
||||||
|
// If 4byte setting is off, we do not want to return the knownMethodData
|
||||||
return knownMethodData && knownMethodData[fourBytePrefix];
|
return use4ByteResolution && knownMethodData?.[fourBytePrefix];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFeatureFlags(state) {
|
export function getFeatureFlags(state) {
|
||||||
|
@ -1756,6 +1756,44 @@ describe('Actions', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#setUse4ByteResolution', () => {
|
||||||
|
afterEach(() => {
|
||||||
|
sinon.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls setUse4ByteResolution in background', async () => {
|
||||||
|
const store = mockStore();
|
||||||
|
const setUse4ByteResolutionStub = sinon.stub().callsFake((_, cb) => cb());
|
||||||
|
_setBackgroundConnection({
|
||||||
|
setUse4ByteResolution: setUse4ByteResolutionStub,
|
||||||
|
});
|
||||||
|
|
||||||
|
await store.dispatch(actions.setUse4ByteResolution());
|
||||||
|
expect(setUse4ByteResolutionStub.callCount).toStrictEqual(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('errors when setUse4ByteResolution in background throws', async () => {
|
||||||
|
const store = mockStore();
|
||||||
|
const setUse4ByteResolutionStub = sinon.stub().callsFake((_, cb) => {
|
||||||
|
cb(new Error('error'));
|
||||||
|
});
|
||||||
|
|
||||||
|
_setBackgroundConnection({
|
||||||
|
setUse4ByteResolution: setUse4ByteResolutionStub,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'SHOW_LOADING_INDICATION', payload: undefined },
|
||||||
|
{ type: 'DISPLAY_WARNING', payload: 'error' },
|
||||||
|
{ type: 'HIDE_LOADING_INDICATION' },
|
||||||
|
];
|
||||||
|
|
||||||
|
await store.dispatch(actions.setUse4ByteResolution());
|
||||||
|
|
||||||
|
expect(store.getActions()).toStrictEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('#updateCurrentLocale', () => {
|
describe('#updateCurrentLocale', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
sinon.stub(window, 'fetch').resolves({
|
sinon.stub(window, 'fetch').resolves({
|
||||||
|
@ -2997,6 +2997,22 @@ export function setUseNftDetection(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setUse4ByteResolution(
|
||||||
|
val: boolean,
|
||||||
|
): ThunkAction<void, MetaMaskReduxState, unknown, AnyAction> {
|
||||||
|
return async (dispatch: MetaMaskReduxDispatch) => {
|
||||||
|
dispatch(showLoadingIndication());
|
||||||
|
log.debug(`background.setUse4ByteResolution`);
|
||||||
|
try {
|
||||||
|
await submitRequestToBackground('setUse4ByteResolution', [val]);
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(displayWarning(error));
|
||||||
|
} finally {
|
||||||
|
dispatch(hideLoadingIndication());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function setUseCurrencyRateCheck(
|
export function setUseCurrencyRateCheck(
|
||||||
val: boolean,
|
val: boolean,
|
||||||
): ThunkAction<void, MetaMaskReduxState, unknown, AnyAction> {
|
): ThunkAction<void, MetaMaskReduxState, unknown, AnyAction> {
|
||||||
@ -3775,7 +3791,7 @@ export function getContractMethodData(
|
|||||||
if (fourBytePrefix.length < 10) {
|
if (fourBytePrefix.length < 10) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
const { knownMethodData } = getState().metamask;
|
const { knownMethodData, use4ByteResolution } = getState().metamask;
|
||||||
if (
|
if (
|
||||||
knownMethodData?.[fourBytePrefix] &&
|
knownMethodData?.[fourBytePrefix] &&
|
||||||
Object.keys(knownMethodData[fourBytePrefix]).length !== 0
|
Object.keys(knownMethodData[fourBytePrefix]).length !== 0
|
||||||
@ -3785,7 +3801,10 @@ export function getContractMethodData(
|
|||||||
|
|
||||||
log.debug(`loadingMethodData`);
|
log.debug(`loadingMethodData`);
|
||||||
|
|
||||||
const { name, params } = (await getMethodDataAsync(fourBytePrefix)) as {
|
const { name, params } = (await getMethodDataAsync(
|
||||||
|
fourBytePrefix,
|
||||||
|
use4ByteResolution,
|
||||||
|
)) as {
|
||||||
name: string;
|
name: string;
|
||||||
params: unknown;
|
params: unknown;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user