Skip to content

Commit

Permalink
feat: Adds opensea to blockaid migration BannerAlert (#23743)
Browse files Browse the repository at this point in the history
## **Description**

This adds a notice to transaction and signature confirmations for users
who have been automatically migrated from the security alerts by Open
Sea to security alerts by Blockaid (see #23460) and are on networks that
are not supported by Blockaid. The notice can be dismissed and is not
shown again once that happens.

The PR adds e2e tests to verify the change for simple send, token
approval, personal signature, and contract interaction.

We intend to remove this notice after a few releases.

[![Open in GitHub
Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/23743?quickstart=1)

## **Related issues**

Fixes:
[#2134](https://app.zenhub.com/workspaces/-confirmations-secure-ux-6245e6e2348677001213b8d2/issues/gh/metamask/metamask-planning/2134)

Related:
[#23546](#23546) and
#23460

## **Manual testing steps**

1. Checkout the extension on a commit prior to #23546 (for example,
`112b155d59`)
2. Build the app and open metamask
3. Select security alerts by open sea

<img width="577" alt="Screenshot 2024-03-27 at 11 01 38"
src="https://github.com/MetaMask/metamask-extension/assets/13814744/7f732e93-d772-432a-85b5-87c95ccbdc53">


4. Checkout this branch, build and reload on the managing extensions
page
5. Switch to Linea Goerli, or another network that is not currently
supported by blockaid
6. Open the testdApp and trigger a new confirmation
7. The Banner Alert should show up

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **After**

#### Simple Send
<img width="472" alt="Screenshot 2024-03-26 at 19 04 56"
src="https://github.com/MetaMask/metamask-extension/assets/13814744/96466bd3-4d5b-4071-8bad-a7c205bbec6f">

#### Token Approval
<img width="472" alt="Screenshot 2024-03-26 at 19 02 11"
src="https://github.com/MetaMask/metamask-extension/assets/13814744/2ebc2ff8-2cc7-4479-8379-236dddd447bf">

#### Personal Signature
<img width="472" alt="Screenshot 2024-03-26 at 19 00 04"
src="https://github.com/MetaMask/metamask-extension/assets/13814744/f6259f01-5c4e-4c81-87ff-98e4db3dec91">

#### Contract Interaction
<img width="472" alt="Screenshot 2024-03-26 at 19 07 44"
src="https://github.com/MetaMask/metamask-extension/assets/13814744/d81deb5c-c379-4556-a818-2428a4951366">

## **Pre-merge author checklist**

- [x] I’ve followed [MetaMask Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
  • Loading branch information
pedronfigueiredo committed Mar 27, 2024
1 parent 1eeaf82 commit de76c52
Show file tree
Hide file tree
Showing 18 changed files with 398 additions and 2 deletions.
9 changes: 9 additions & 0 deletions app/_locales/en/messages.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions app/scripts/controllers/preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export default class PreferencesController {
eth_sign: false,
},
useMultiAccountBalanceChecker: true,
hasDismissedOpenSeaToBlockaidBanner: false,
useSafeChainsListValidation: true,
// set to true means the dynamic list from the API is being used
// set to false will be using the static list from contract-metadata
Expand Down Expand Up @@ -192,6 +193,14 @@ export default class PreferencesController {
this.store.updateState({ useMultiAccountBalanceChecker: val });
}

/**
* Setter for the `dismissOpenSeaToBlockaidBanner` property
*
*/
dismissOpenSeaToBlockaidBanner() {
this.store.updateState({ hasDismissedOpenSeaToBlockaidBanner: true });
}

/**
* Setter for the `useSafeChainsListValidation` property
*
Expand Down
17 changes: 17 additions & 0 deletions app/scripts/controllers/preferences.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,23 @@ describe('preferences controller', () => {
});
});

describe('dismissOpenSeaToBlockaidBanner', () => {
it('hasDismissedOpenSeaToBlockaidBanner should default to false', () => {
expect(
preferencesController.store.getState()
.hasDismissedOpenSeaToBlockaidBanner,
).toStrictEqual(false);
});

it('should set the hasDismissedOpenSeaToBlockaidBanner property in state', () => {
preferencesController.dismissOpenSeaToBlockaidBanner();
expect(
preferencesController.store.getState()
.hasDismissedOpenSeaToBlockaidBanner,
).toStrictEqual(true);
});
});

describe('setUseSafeChainsListValidation', function () {
it('should default to true', function () {
const state = preferencesController.store.getState();
Expand Down
1 change: 1 addition & 0 deletions app/scripts/lib/setupSentry.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ export const SENTRY_BACKGROUND_STATE = {
useTokenDetection: true,
useRequestQueue: true,
useTransactionSimulations: true,
hasDismissedOpenSeaToBlockaidBanner: true,
},
SelectedNetworkController: { domains: false },
SignatureController: {
Expand Down
4 changes: 4 additions & 0 deletions app/scripts/metamask-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -2879,6 +2879,10 @@ export default class MetamaskController extends EventEmitter {
preferencesController.setUseMultiAccountBalanceChecker.bind(
preferencesController,
),
dismissOpenSeaToBlockaidBanner:
preferencesController.dismissOpenSeaToBlockaidBanner.bind(
preferencesController,
),
setUseSafeChainsListValidation:
preferencesController.setUseSafeChainsListValidation.bind(
preferencesController,
Expand Down
3 changes: 2 additions & 1 deletion app/scripts/migrations/114.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('migration #114', () => {
});

describe('deprecates transactionSecurityCheckEnabled in PreferencesController', () => {
it('sets securityAlertsEnabled to true if transactionSecurityCheckEnabled is true', async () => {
it('sets securityAlertsEnabled and hasMigratedFromOpenSeaToBlockaid to true if transactionSecurityCheckEnabled is true', async () => {
const oldStorage = {
PreferencesController: {
transactionSecurityCheckEnabled: true,
Expand All @@ -32,6 +32,7 @@ describe('migration #114', () => {
const expectedState = {
PreferencesController: {
securityAlertsEnabled: true,
hasMigratedFromOpenSeaToBlockaid: true,
},
};

Expand Down
1 change: 1 addition & 0 deletions app/scripts/migrations/114.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ function transformState(state: Record<string, any>) {
) {
if (state.PreferencesController.transactionSecurityCheckEnabled) {
state.PreferencesController.securityAlertsEnabled = true;
state.PreferencesController.hasMigratedFromOpenSeaToBlockaid = true;
}

delete state.PreferencesController.transactionSecurityCheckEnabled;
Expand Down
135 changes: 135 additions & 0 deletions test/e2e/tests/ppom/migrate-opensea-to-blockaid-banner.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
const { connectAccountToTestDapp } = require('../../accounts/common');
const FixtureBuilder = require('../../fixture-builder');
const {
defaultGanacheOptions,
unlockWallet,
withFixtures,
openDapp,
WINDOW_TITLES,
} = require('../../helpers');

describe('Migrate Opensea to Blockaid Banner @no-mmi', function () {
it('Shows up on simple send transaction', async function () {
await withFixtures(
{
dapp: true,
fixtures: new FixtureBuilder()
.withPreferencesController({ hasMigratedFromOpenSeaToBlockaid: true })
.build(),
ganacheOptions: defaultGanacheOptions,
title: this.test.fullTitle(),
},
async ({ driver }) => {
await driver.navigate();
await unlockWallet(driver);
await openDapp(driver);

await connectAccountToTestDapp(driver);

await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp);
await driver.clickElement('#sendButton');
await driver.delay(2000);

await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);
await driver.waitForSelector({ text: 'Heads up!', tag: 'p' });
},
);
});

it('Shows up on token approval', async function () {
await withFixtures(
{
dapp: true,
fixtures: new FixtureBuilder()
.withPreferencesController({ hasMigratedFromOpenSeaToBlockaid: true })
.build(),
ganacheOptions: defaultGanacheOptions,
title: this.test.fullTitle(),
},
async ({ driver }) => {
await driver.navigate();
await unlockWallet(driver);
await openDapp(driver);

await connectAccountToTestDapp(driver);

await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp);
await driver.findClickableElement('#createToken');
await driver.clickElement('#createToken');
await driver.delay(2000);

await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);
await driver.findClickableElements({
text: 'Confirm',
tag: 'button',
});
await driver.clickElement({
text: 'Confirm',
tag: 'button',
});

await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp);
await driver.clickElement({ text: 'Approve Tokens', tag: 'button' });
await driver.delay(2000);

await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);
await driver.waitForSelector({ text: 'Heads up!', tag: 'p' });
},
);
});

it('Shows up on personal signature', async function () {
await withFixtures(
{
dapp: true,
fixtures: new FixtureBuilder()
.withPreferencesController({ hasMigratedFromOpenSeaToBlockaid: true })
.build(),
ganacheOptions: defaultGanacheOptions,
title: this.test.fullTitle(),
},
async ({ driver }) => {
await driver.navigate();
await unlockWallet(driver);
await openDapp(driver);

await connectAccountToTestDapp(driver);

await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp);
await driver.clickElement('#personalSign');
await driver.delay(2000);

await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);
await driver.waitForSelector({ text: 'Heads up!', tag: 'p' });
},
);
});

it('Shows up on contract interaction', async function () {
await withFixtures(
{
dapp: true,
fixtures: new FixtureBuilder()
.withPreferencesController({ hasMigratedFromOpenSeaToBlockaid: true })
.build(),
ganacheOptions: defaultGanacheOptions,
title: this.test.fullTitle(),
},
async ({ driver }) => {
await driver.navigate();
await unlockWallet(driver);
await openDapp(driver);

await connectAccountToTestDapp(driver);

await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp);

await driver.clickElement('#deployMultisigButton');
await driver.delay(2000);

await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);
await driver.waitForSelector({ text: 'Heads up!', tag: 'p' });
},
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@
"addSnapAccountEnabled": "boolean",
"advancedGasFee": {},
"featureFlags": {},
"hasDismissedOpenSeaToBlockaidBanner": false,
"incomingTransactionsPreferences": {},
"knownMethodData": "object",
"currentLocale": "en",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"showAccountBanner": true,
"trezorModel": null,
"hadAdvancedGasFeesSetPriorToMigration92_3": false,
"hasDismissedOpenSeaToBlockaidBanner": false,
"nftsDropdownState": {},
"termsOfUseLastAgreed": "number",
"qrHardware": {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
TextAlign,
TextColor,
Size,
Severity,
///: BEGIN:ONLY_INCLUDE_IF(build-mmi)
IconColor,
Display,
Expand All @@ -36,6 +37,7 @@ import {
} from '../../../../helpers/constants/design-system';
import {
ButtonLink,
BannerAlert,
///: BEGIN:ONLY_INCLUDE_IF(build-mmi)
Box,
Icon,
Expand Down Expand Up @@ -85,6 +87,10 @@ export default class SignatureRequestOriginal extends Component {
mostRecentOverviewPage: PropTypes.string.isRequired,
resolvePendingApproval: PropTypes.func.isRequired,
completedTx: PropTypes.func.isRequired,
hasMigratedFromOpenSeaToBlockaid: PropTypes.bool.isRequired,
isNetworkSupportedByBlockaid: PropTypes.bool.isRequired,
hasDismissedOpenSeaToBlockaidBanner: PropTypes.bool.isRequired,
dismissOpenSeaToBlockaidBanner: PropTypes.func.isRequired,
///: BEGIN:ONLY_INCLUDE_IF(build-mmi)
// Used to show a warning if the signing account is not the selected account
// Largely relevant for contract wallet custodians
Expand Down Expand Up @@ -129,6 +135,8 @@ export default class SignatureRequestOriginal extends Component {
};

renderBody = () => {
const { t } = this.context;

let rows;
const notice = `${this.context.t('youSign')}:`;

Expand All @@ -150,6 +158,20 @@ export default class SignatureRequestOriginal extends Component {
? subjectMetadata?.[txData.msgParams.origin]
: null;

const {
hasMigratedFromOpenSeaToBlockaid,
isNetworkSupportedByBlockaid,
hasDismissedOpenSeaToBlockaidBanner,
dismissOpenSeaToBlockaidBanner,
} = this.props;
const showOpenSeaToBlockaidBannerAlert =
hasMigratedFromOpenSeaToBlockaid &&
!isNetworkSupportedByBlockaid &&
!hasDismissedOpenSeaToBlockaidBanner;
const handleCloseOpenSeaToBlockaidBannerAlert = () => {
dismissOpenSeaToBlockaidBanner();
};

return (
<div className="request-signature__body">
{
Expand All @@ -162,6 +184,23 @@ export default class SignatureRequestOriginal extends Component {
securityProviderResponse={txData.securityProviderResponse}
/>
)}
{showOpenSeaToBlockaidBannerAlert ? (
<BannerAlert
severity={Severity.Info}
title={t('openSeaToBlockaidTitle')}
description={t('openSeaToBlockaidDescription')}
actionButtonLabel={t('openSeaToBlockaidBtnLabel')}
actionButtonProps={{
href: 'https://snaps.metamask.io/transaction-insights',
externalLink: true,
}}
marginBottom={4}
marginLeft={4}
marginTop={4}
marginRight={4}
onClose={handleCloseOpenSeaToBlockaidBannerAlert}
/>
) : null}
{
///: BEGIN:ONLY_INCLUDE_IF(build-mmi)
this.props.selectedAccount.address ===
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
rejectPendingApproval,
rejectAllMessages,
completedTx,
dismissOpenSeaToBlockaidBanner,
} from '../../../../store/actions';
///: BEGIN:ONLY_INCLUDE_IF(build-mmi)
// eslint-disable-next-line import/order
Expand All @@ -22,6 +23,9 @@ import {
doesAddressRequireLedgerHidConnection,
unconfirmedMessagesHashSelector,
getTotalUnapprovedMessagesCount,
getIsNetworkSupportedByBlockaid,
getHasDismissedOpenSeaToBlockaidBanner,
getHasMigratedFromOpenSeaToBlockaid,
///: BEGIN:ONLY_INCLUDE_IF(build-mmi)
getAccountType,
getSelectedInternalAccount,
Expand All @@ -44,6 +48,12 @@ function mapStateToProps(state, ownProps) {
const messagesList = unconfirmedMessagesHashSelector(state);
const messagesCount = getTotalUnapprovedMessagesCount(state);

const hasMigratedFromOpenSeaToBlockaid =
getHasMigratedFromOpenSeaToBlockaid(state);
const hasDismissedOpenSeaToBlockaidBanner =
getHasDismissedOpenSeaToBlockaidBanner(state);
const isNetworkSupportedByBlockaid = getIsNetworkSupportedByBlockaid(state);

return {
requester: null,
requesterAddress: null,
Expand All @@ -55,6 +65,9 @@ function mapStateToProps(state, ownProps) {
subjectMetadata: getSubjectMetadata(state),
messagesList,
messagesCount,
hasMigratedFromOpenSeaToBlockaid,
hasDismissedOpenSeaToBlockaidBanner,
isNetworkSupportedByBlockaid,
///: BEGIN:ONLY_INCLUDE_IF(build-mmi)
accountType: getAccountType(state),
selectedAccount: getSelectedInternalAccount(state),
Expand Down Expand Up @@ -90,6 +103,8 @@ mapDispatchToProps = function (dispatch) {
cancelAllApprovals: (messagesList) => {
dispatch(rejectAllMessages(messagesList));
},
dismissOpenSeaToBlockaidBanner: () =>
dispatch(dismissOpenSeaToBlockaidBanner()),
};
};

Expand Down
Loading

0 comments on commit de76c52

Please sign in to comment.