Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adding e2e for signature decoding api and enable it in extension #28423

Merged
merged 26 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions app/scripts/metamask-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -2054,8 +2054,7 @@ export default class MetamaskController extends EventEmitter {
decodingApiUrl: process.env.DECODING_API_URL,
isDecodeSignatureRequestEnabled: () =>
this.preferencesController.state.useExternalServices === true &&
this.preferencesController.state.useTransactionSimulations &&
process.env.ENABLE_SIGNATURE_DECODING === true,
Gudahtt marked this conversation as resolved.
Show resolved Hide resolved
this.preferencesController.state.useTransactionSimulations,
});

this.signatureController.hub.on(
Expand Down
4 changes: 1 addition & 3 deletions builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,8 @@ env:

# Used to enable confirmation redesigned pages
- ENABLE_CONFIRMATION_REDESIGN: ''
# Used to enable signature decoding
- ENABLE_SIGNATURE_DECODING: ''
# URL of the decoding API used to provide additional data from signature requests
- DECODING_API_URL: null
- DECODING_API_URL: 'https://qtgdj2huxh.execute-api.us-east-2.amazonaws.com/uat/v1'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are still pointing to uat, as prod is currently broken

# Determines if feature flagged Settings Page - Developer Options should be used
- ENABLE_SETTINGS_PAGE_DEV_OPTIONS: false
# Used for debugging changes to the phishing warning page.
Expand Down
2 changes: 2 additions & 0 deletions privacy-snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
"price.api.cx.metamask.io",
"proxy.api.cx.metamask.io",
"proxy.dev-api.cx.metamask.io",
"qtgdj2huxh.execute-api.us-east-2.amazonaws.com",
"https://signature-insights.api.cx.metamask.io",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this entry coming from?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are UAT and PROD url for signature decoding api.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed PROD url for now, we can add it back once we switch to prod instance

"raw.githubusercontent.com",
"registry.npmjs.org",
"responsive-rpc.test",
Expand Down
36 changes: 36 additions & 0 deletions test/e2e/tests/confirmations/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import { SMART_CONTRACTS } from '../../seeder/smart-contracts';
import { Driver } from '../../webdriver/driver';
import Confirmation from '../../page-objects/pages/confirmations/redesign/confirmation';

export const DECODING_E2E_API_URL =
'https://qtgdj2huxh.execute-api.us-east-2.amazonaws.com/uat/v1';

export async function scrollAndConfirmAndAssertConfirm(driver: Driver) {
const confirmation = new Confirmation(driver);
await confirmation.clickScrollToBottomButton();
Expand Down Expand Up @@ -61,6 +64,33 @@ async function createMockSegmentEvent(mockServer: Mockttp, eventName: string) {
}));
}

async function createMockSignatureDecodingEvent(mockServer: Mockttp) {
return await mockServer
.forPost(`${DECODING_E2E_API_URL}/signature`)
.thenCallback(() => ({
statusCode: 200,
json: {
stateChanges: [
{
assetType: 'NATIVE',
changeType: 'RECEIVE',
address: '',
amount: '900000000000000000',
contractAddress: '',
},
{
assetType: 'ERC721',
changeType: 'LISTING',
address: '',
amount: '',
contractAddress: '0xafd4896984CA60d2feF66136e57f958dCe9482d5',
tokenID: '2101',
},
],
},
}));
}

export async function mockSignatureApproved(
mockServer: Mockttp,
withAnonEvents = false,
Expand All @@ -77,6 +107,7 @@ export async function mockSignatureApproved(
await createMockSegmentEvent(mockServer, 'Account Details Opened'),
...anonEvents,
await createMockSegmentEvent(mockServer, 'Signature Approved'),
await createMockSignatureDecodingEvent(mockServer),
];
}

Expand All @@ -94,6 +125,11 @@ export async function mockSignatureRejected(
return [
await createMockSegmentEvent(mockServer, 'Signature Requested'),
await createMockSegmentEvent(mockServer, 'Signature Rejected'),
await createMockSignatureDecodingEvent(mockServer),
...anonEvents,
];
}

export async function mockPermitDecoding(mockServer: Mockttp) {
return [await createMockSignatureDecodingEvent(mockServer)];
}
4 changes: 4 additions & 0 deletions test/e2e/tests/confirmations/signatures/nft-permit.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ describe('Confirmation Signature - NFT Permit @no-mmi', function (this: Suite) {
signatureType: 'eth_signTypedData_v4',
primaryType: 'Permit',
uiCustomizations: ['redesigned_confirmation', 'permit'],
decodingChangeTypes: ['RECEIVE', 'LISTING'],
decodingResponse: 'CHANGE',
});

await assertVerifiedResults(driver, publicAddress);
Expand Down Expand Up @@ -113,6 +115,8 @@ describe('Confirmation Signature - NFT Permit @no-mmi', function (this: Suite) {
primaryType: 'Permit',
uiCustomizations: ['redesigned_confirmation', 'permit'],
location: 'confirmation',
decodingChangeTypes: ['RECEIVE', 'LISTING'],
decodingResponse: 'CHANGE',
});
},
mockSignatureRejected,
Expand Down
33 changes: 33 additions & 0 deletions test/e2e/tests/confirmations/signatures/permit.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { strict as assert } from 'assert';
import { TransactionEnvelopeType } from '@metamask/transaction-controller';
import { Suite } from 'mocha';
import { MockedEndpoint } from 'mockttp';
import { openDapp, unlockWallet, WINDOW_TITLES } from '../../../helpers';
import { Ganache } from '../../../seeder/ganache';
import { Driver } from '../../../webdriver/driver';
import {
mockPermitDecoding,
mockSignatureApproved,
mockSignatureRejected,
scrollAndConfirmAndAssertConfirm,
Expand Down Expand Up @@ -67,6 +69,8 @@ describe('Confirmation Signature - Permit @no-mmi', function (this: Suite) {
signatureType: 'eth_signTypedData_v4',
primaryType: 'Permit',
uiCustomizations: ['redesigned_confirmation', 'permit'],
decodingChangeTypes: ['RECEIVE', 'LISTING'],
decodingResponse: 'CHANGE',
});

await assertVerifiedResults(driver, publicAddress);
Expand Down Expand Up @@ -103,11 +107,40 @@ describe('Confirmation Signature - Permit @no-mmi', function (this: Suite) {
primaryType: 'Permit',
uiCustomizations: ['redesigned_confirmation', 'permit'],
location: 'confirmation',
decodingChangeTypes: ['RECEIVE', 'LISTING'],
decodingResponse: 'CHANGE',
});
},
mockSignatureRejected,
);
});

it('display decoding information if available', async function () {
await withTransactionEnvelopeTypeFixtures(
this.test?.fullTitle(),
TransactionEnvelopeType.legacy,
async ({ driver }: TestSuiteArguments) => {
await unlockWallet(driver);
await openDapp(driver);
await driver.clickElement('#signPermit');
matthewwalsh0 marked this conversation as resolved.
Show resolved Hide resolved
await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);
const simulationSection = driver.findElement({
text: 'Estimated changes',
});
const receiveChange = driver.findElement({ text: 'You receive' });
const listChange = driver.findElement({ text: 'You list' });
const listChangeValue = driver.findElement({ text: '#2101' });

assert.ok(await simulationSection, 'Estimated changes');
assert.ok(await receiveChange, 'You receive');
assert.ok(await listChange, 'You list');
assert.ok(await listChangeValue, '#2101');

await driver.delay(10000);
},
mockPermitDecoding,
);
});
});

async function assertInfoValues(driver: Driver) {
Expand Down
29 changes: 29 additions & 0 deletions test/e2e/tests/confirmations/signatures/signature-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,8 @@ function assertEventPropertiesMatch(
const actualProperties = { ...event.properties };
const expectedProps = { ...expectedProperties };

compareDecodingAPIResponse(actualProperties, expectedProps, eventName);

compareSecurityAlertResponse(actualProperties, expectedProps, eventName);

assert(event, `${eventName} event not found`);
Expand Down Expand Up @@ -287,6 +289,33 @@ function compareSecurityAlertResponse(
}
}

function compareDecodingAPIResponse(
actualProperties: Record<string, unknown>,
expectedProperties: Record<string, unknown>,
eventName: string,
) {
if (
eventName === 'Signature Rejected' ||
eventName === 'Signature Approved'
) {
assert.deepStrictEqual(
actualProperties.decoding_change_types,
expectedProperties.decoding_change_types,
`${eventName} event properties do not match: decoding_change_types is ${actualProperties.decoding_change_types}`,
);
assert.equal(
actualProperties.decoding_response,
expectedProperties.decoding_response,
`${eventName} event properties do not match: decoding_response is ${actualProperties.decoding_response}`,
);
}
// Remove the property from both objects to avoid comparison
delete expectedProperties.decoding_change_types;
delete expectedProperties.decoding_response;
delete actualProperties.decoding_change_types;
delete actualProperties.decoding_response;
}

export async function clickHeaderInfoBtn(driver: Driver) {
const confirmation = new Confirmation(driver);
await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { act, screen } from '@testing-library/react';
import { act, fireEvent, screen } from '@testing-library/react';
import nock from 'nock';
import mockMetaMaskState from '../../data/integration-init-state.json';
import { integrationTestRender } from '../../../lib/render-helpers';
Expand Down Expand Up @@ -92,6 +92,8 @@ describe('Permit Seaport Tests', () => {
it('renders message details section', async () => {
await renderSeaportSignature();

fireEvent.click(screen.getByTestId('sectionCollapseButton'));

const messageDetailsSection = await screen.findByTestId(
'confirmation_message-section',
);
Expand All @@ -112,6 +114,8 @@ describe('Permit Seaport Tests', () => {
it('renders offer and consideration details', async () => {
await renderSeaportSignature();

fireEvent.click(screen.getByTestId('sectionCollapseButton'));

const offers = await screen.findByTestId('confirmation_data-offer-index-2');
const offerDetails0 = offers.querySelector(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

message section in seaport requests is not collapsed as we show simulation details.

'[data-testid="confirmation_data-0-index-0"]',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1386,30 +1386,19 @@ exports[`Info renders info section for typed sign request 1`] = `
data-testid="confirmation_message-section"
>
<div
class="mm-box confirm-info-row mm-box--margin-top-2 mm-box--margin-bottom-2 mm-box--padding-right-5 mm-box--padding-left-2 mm-box--display-flex mm-box--flex-direction-column mm-box--flex-wrap-wrap mm-box--justify-content-space-between mm-box--align-items-flex-start mm-box--color-text-default mm-box--rounded-lg"
class="mm-box confirm-info-row mm-box--margin-top-2 mm-box--margin-bottom-2 mm-box--padding-right-5 mm-box--padding-left-2 mm-box--display-flex mm-box--flex-direction-row mm-box--flex-wrap-wrap mm-box--justify-content-space-between mm-box--align-items-flex-start mm-box--color-text-default mm-box--rounded-lg"
style="overflow-wrap: anywhere; min-height: 24px; position: relative;"
>
<button
aria-label="copy-button"
class="mm-box mm-button-icon mm-button-icon--size-sm mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-icon-muted mm-box--background-color-transparent mm-box--rounded-lg"
style="cursor: pointer; position: absolute; right: 32px; top: 4px;"
style="cursor: pointer; position: absolute; right: 4px; top: 4px;"
>
<span
class="mm-box mm-icon mm-icon--size-sm mm-box--display-inline-block mm-box--color-inherit"
style="mask-image: url('./images/icons/copy.svg');"
/>
</button>
<button
aria-label="collapse-button"
class="mm-box mm-button-icon mm-button-icon--size-sm mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-icon-muted mm-box--background-color-transparent mm-box--rounded-lg"
data-testid="sectionCollapseButton"
style="cursor: pointer; position: absolute; right: 8px; top: 4px;"
>
<span
class="mm-box mm-icon mm-icon--size-sm mm-box--display-inline-block mm-box--color-inherit"
style="mask-image: url('./images/icons/collapse.svg');"
/>
</button>
<div
class="mm-box mm-box--display-flex mm-box--flex-direction-row mm-box--justify-content-center mm-box--align-items-flex-start"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1102,30 +1102,19 @@ exports[`TypedSignInfo renders origin for typed sign data request 1`] = `
data-testid="confirmation_message-section"
>
<div
class="mm-box confirm-info-row mm-box--margin-top-2 mm-box--margin-bottom-2 mm-box--padding-right-5 mm-box--padding-left-2 mm-box--display-flex mm-box--flex-direction-column mm-box--flex-wrap-wrap mm-box--justify-content-space-between mm-box--align-items-flex-start mm-box--color-text-default mm-box--rounded-lg"
class="mm-box confirm-info-row mm-box--margin-top-2 mm-box--margin-bottom-2 mm-box--padding-right-5 mm-box--padding-left-2 mm-box--display-flex mm-box--flex-direction-row mm-box--flex-wrap-wrap mm-box--justify-content-space-between mm-box--align-items-flex-start mm-box--color-text-default mm-box--rounded-lg"
style="overflow-wrap: anywhere; min-height: 24px; position: relative;"
>
<button
aria-label="copy-button"
class="mm-box mm-button-icon mm-button-icon--size-sm mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-icon-muted mm-box--background-color-transparent mm-box--rounded-lg"
style="cursor: pointer; position: absolute; right: 32px; top: 4px;"
style="cursor: pointer; position: absolute; right: 4px; top: 4px;"
>
<span
class="mm-box mm-icon mm-icon--size-sm mm-box--display-inline-block mm-box--color-inherit"
style="mask-image: url('./images/icons/copy.svg');"
/>
</button>
<button
aria-label="collapse-button"
class="mm-box mm-button-icon mm-button-icon--size-sm mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-icon-muted mm-box--background-color-transparent mm-box--rounded-lg"
data-testid="sectionCollapseButton"
style="cursor: pointer; position: absolute; right: 8px; top: 4px;"
>
<span
class="mm-box mm-icon mm-icon--size-sm mm-box--display-inline-block mm-box--color-inherit"
style="mask-image: url('./images/icons/collapse.svg');"
/>
</button>
<div
class="mm-box mm-box--display-flex mm-box--flex-direction-row mm-box--justify-content-center mm-box--align-items-flex-start"
>
Expand Down Expand Up @@ -2047,30 +2036,19 @@ exports[`TypedSignInfo should render message for typed sign v3 request 1`] = `
data-testid="confirmation_message-section"
>
<div
class="mm-box confirm-info-row mm-box--margin-top-2 mm-box--margin-bottom-2 mm-box--padding-right-5 mm-box--padding-left-2 mm-box--display-flex mm-box--flex-direction-column mm-box--flex-wrap-wrap mm-box--justify-content-space-between mm-box--align-items-flex-start mm-box--color-text-default mm-box--rounded-lg"
class="mm-box confirm-info-row mm-box--margin-top-2 mm-box--margin-bottom-2 mm-box--padding-right-5 mm-box--padding-left-2 mm-box--display-flex mm-box--flex-direction-row mm-box--flex-wrap-wrap mm-box--justify-content-space-between mm-box--align-items-flex-start mm-box--color-text-default mm-box--rounded-lg"
style="overflow-wrap: anywhere; min-height: 24px; position: relative;"
>
<button
aria-label="copy-button"
class="mm-box mm-button-icon mm-button-icon--size-sm mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-icon-muted mm-box--background-color-transparent mm-box--rounded-lg"
style="cursor: pointer; position: absolute; right: 32px; top: 4px;"
style="cursor: pointer; position: absolute; right: 4px; top: 4px;"
>
<span
class="mm-box mm-icon mm-icon--size-sm mm-box--display-inline-block mm-box--color-inherit"
style="mask-image: url('./images/icons/copy.svg');"
/>
</button>
<button
aria-label="collapse-button"
class="mm-box mm-button-icon mm-button-icon--size-sm mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-icon-muted mm-box--background-color-transparent mm-box--rounded-lg"
data-testid="sectionCollapseButton"
style="cursor: pointer; position: absolute; right: 8px; top: 4px;"
>
<span
class="mm-box mm-icon mm-icon--size-sm mm-box--display-inline-block mm-box--color-inherit"
style="mask-image: url('./images/icons/collapse.svg');"
/>
</button>
<div
class="mm-box mm-box--display-flex mm-box--flex-direction-row mm-box--justify-content-center mm-box--align-items-flex-start"
>
Expand Down Expand Up @@ -2619,30 +2597,19 @@ exports[`TypedSignInfo should render message for typed sign v4 request 1`] = `
data-testid="confirmation_message-section"
>
<div
class="mm-box confirm-info-row mm-box--margin-top-2 mm-box--margin-bottom-2 mm-box--padding-right-5 mm-box--padding-left-2 mm-box--display-flex mm-box--flex-direction-column mm-box--flex-wrap-wrap mm-box--justify-content-space-between mm-box--align-items-flex-start mm-box--color-text-default mm-box--rounded-lg"
class="mm-box confirm-info-row mm-box--margin-top-2 mm-box--margin-bottom-2 mm-box--padding-right-5 mm-box--padding-left-2 mm-box--display-flex mm-box--flex-direction-row mm-box--flex-wrap-wrap mm-box--justify-content-space-between mm-box--align-items-flex-start mm-box--color-text-default mm-box--rounded-lg"
style="overflow-wrap: anywhere; min-height: 24px; position: relative;"
>
<button
aria-label="copy-button"
class="mm-box mm-button-icon mm-button-icon--size-sm mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-icon-muted mm-box--background-color-transparent mm-box--rounded-lg"
style="cursor: pointer; position: absolute; right: 32px; top: 4px;"
style="cursor: pointer; position: absolute; right: 4px; top: 4px;"
>
<span
class="mm-box mm-icon mm-icon--size-sm mm-box--display-inline-block mm-box--color-inherit"
style="mask-image: url('./images/icons/copy.svg');"
/>
</button>
<button
aria-label="collapse-button"
class="mm-box mm-button-icon mm-button-icon--size-sm mm-box--display-inline-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-icon-muted mm-box--background-color-transparent mm-box--rounded-lg"
data-testid="sectionCollapseButton"
style="cursor: pointer; position: absolute; right: 8px; top: 4px;"
>
<span
class="mm-box mm-icon mm-icon--size-sm mm-box--display-inline-block mm-box--color-inherit"
style="mask-image: url('./images/icons/collapse.svg');"
/>
</button>
<div
class="mm-box mm-box--display-flex mm-box--flex-direction-row mm-box--justify-content-center mm-box--align-items-flex-start"
>
Expand Down
Loading
Loading