Skip to content

Commit

Permalink
Adding e2e for signature decoding
Browse files Browse the repository at this point in the history
  • Loading branch information
jpuri committed Nov 27, 2024
1 parent 65be533 commit 8698533
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 11 deletions.
3 changes: 1 addition & 2 deletions app/scripts/metamask-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -2046,8 +2046,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,
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'
# 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",
"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 @@ -9,6 +9,9 @@ import { MockedEndpoint, Mockttp } from '../../mock-e2e';
import { SMART_CONTRACTS } from '../../seeder/smart-contracts';
import { Driver } from '../../webdriver/driver';

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

export async function scrollAndConfirmAndAssertConfirm(driver: Driver) {
await driver.clickElementSafe('.confirm-scroll-to-bottom__button');
await driver.clickElement('[data-testid="confirm-footer-button"]');
Expand Down Expand Up @@ -59,6 +62,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 @@ -75,6 +105,7 @@ export async function mockSignatureApproved(
await createMockSegmentEvent(mockServer, 'Account Details Opened'),
...anonEvents,
await createMockSegmentEvent(mockServer, 'Signature Approved'),
await createMockSignatureDecodingEvent(mockServer),
];
}

Expand All @@ -92,6 +123,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)];
}
32 changes: 32 additions & 0 deletions test/e2e/tests/confirmations/signatures/permit.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import { Ganache } from '../../../seeder/ganache';
import { Driver } from '../../../webdriver/driver';
import {
mockPermitDecoding,
mockSignatureApproved,
mockSignatureRejected,
scrollAndConfirmAndAssertConfirm,
Expand Down Expand Up @@ -67,6 +68,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 @@ -106,11 +109,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');
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 @@ -243,6 +243,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 @@ -277,6 +279,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) {
await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ jest.mock('../../../../../../../store/actions', () => {
getTokenStandardAndDetails: jest
.fn()
.mockResolvedValue({ decimals: 2, standard: 'ERC20' }),
updateEventFragment: jest.fn(),
};
});

Expand Down Expand Up @@ -113,7 +114,6 @@ describe('PermitSimulation', () => {

await waitFor(() => {
expect(queryByTestId('30')).not.toBeInTheDocument();
expect(queryByTestId('Estimated changes')).toBeInTheDocument();
expect(
queryByTestId(
"You're giving the spender permission to spend this many tokens from your account.",
Expand All @@ -132,18 +132,17 @@ describe('PermitSimulation', () => {
const mockStore = configureMockStore([])(state);

await act(async () => {
const { findByText } = renderWithConfirmContextProvider(
const { container, findByText } = renderWithConfirmContextProvider(
<TypedSignV4Simulation />,
mockStore,
);

expect(await findByText('Estimated changes')).toBeInTheDocument();
expect(await findByText('Spending cap')).toBeInTheDocument();
expect(await findByText('1,461,501,637,3...')).toBeInTheDocument();
});
});

it.only('should render decoding simulation for seaport request', async () => {
it('should render decoding simulation for seaport request', async () => {
const state = getMockTypedSignConfirmStateForRequest(seaportSignatureMsg);
const mockStore = configureMockStore([])(state);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ const decodingData: DecodingData = {
};

describe('useDecodedSignatureMetrics', () => {
process.env.ENABLE_SIGNATURE_DECODING = 'true';
it('should not call updateSignatureEventFragment if decodingLoading is true', async () => {
const state = getMockTypedSignConfirmStateForRequest({
...permitSignatureMsg,
Expand Down
2 changes: 1 addition & 1 deletion ui/pages/confirmations/hooks/useDecodedSignatureMetrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function useDecodedSignatureMetrics() {
: DecodingResponseType.NoChange);

useEffect(() => {
if (decodingLoading || !process.env.ENABLE_SIGNATURE_DECODING) {
if (decodingLoading) {
return;
}

Expand Down

0 comments on commit 8698533

Please sign in to comment.