Skip to content

Commit 7acea0e

Browse files
fix: validate EIP-5792 requests using PPOM (#31231)
## **Description** Validate security for all EIP-5792 requests. Specifically: - Use the new `validateSecurity` callback in the `addTransactionBatch` controller method. - Bump `@metamask/transaction-controller` to `^52.2.0`. - Fix E2E tests due to version change. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/31231?quickstart=1) ## **Related issues** Fixes: #31263 ## **Manual testing steps** See issue. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.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/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] 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.
1 parent b7cdc26 commit 7acea0e

12 files changed

+52
-22
lines changed

app/scripts/lib/transaction/eip5792.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ describe('EIP-5792', () => {
8686

8787
let getDisabledAccountUpgradeChainsMock: jest.MockedFn<() => Hex[]>;
8888

89+
let validateSecurityMock: jest.MockedFunction<
90+
Parameters<typeof processSendCalls>[0]['validateSecurity']
91+
>;
92+
8993
let messenger: EIP5792Messenger;
9094

9195
beforeEach(() => {
@@ -95,6 +99,7 @@ describe('EIP-5792', () => {
9599
getTransactionControllerStateMock = jest.fn();
96100
getNetworkClientByIdMock = jest.fn();
97101
getDisabledAccountUpgradeChainsMock = jest.fn();
102+
validateSecurityMock = jest.fn();
98103

99104
messenger = new Messenger();
100105

@@ -117,6 +122,7 @@ describe('EIP-5792', () => {
117122
addTransactionBatchMock.mockResolvedValue({
118123
batchId: BATCH_ID_MOCK,
119124
});
125+
120126
getDisabledAccountUpgradeChainsMock.mockReturnValue([]);
121127
});
122128

@@ -126,6 +132,7 @@ describe('EIP-5792', () => {
126132
{
127133
addTransactionBatch: addTransactionBatchMock,
128134
getDisabledAccountUpgradeChains: getDisabledAccountUpgradeChainsMock,
135+
validateSecurity: validateSecurityMock,
129136
},
130137
messenger,
131138
SEND_CALLS_MOCK,
@@ -136,7 +143,9 @@ describe('EIP-5792', () => {
136143
from: SEND_CALLS_MOCK.from,
137144
networkClientId: NETWORK_CLIENT_ID_MOCK,
138145
origin: ORIGIN_MOCK,
146+
securityAlertId: expect.any(String),
139147
transactions: [{ params: SEND_CALLS_MOCK.calls[0] }],
148+
validateSecurity: expect.any(Function),
140149
});
141150
});
142151

@@ -147,6 +156,7 @@ describe('EIP-5792', () => {
147156
addTransactionBatch: addTransactionBatchMock,
148157
getDisabledAccountUpgradeChains:
149158
getDisabledAccountUpgradeChainsMock,
159+
validateSecurity: validateSecurityMock,
150160
},
151161
messenger,
152162
SEND_CALLS_MOCK,
@@ -162,6 +172,7 @@ describe('EIP-5792', () => {
162172
addTransactionBatch: addTransactionBatchMock,
163173
getDisabledAccountUpgradeChains:
164174
getDisabledAccountUpgradeChainsMock,
175+
validateSecurity: validateSecurityMock,
165176
},
166177
messenger,
167178
{ ...SEND_CALLS_MOCK, version: '2.0' },
@@ -177,6 +188,7 @@ describe('EIP-5792', () => {
177188
addTransactionBatch: addTransactionBatchMock,
178189
getDisabledAccountUpgradeChains:
179190
getDisabledAccountUpgradeChainsMock,
191+
validateSecurity: validateSecurityMock,
180192
},
181193
messenger,
182194
{ ...SEND_CALLS_MOCK, chainId: CHAIN_ID_2_MOCK },
@@ -196,6 +208,7 @@ describe('EIP-5792', () => {
196208
addTransactionBatch: addTransactionBatchMock,
197209
getDisabledAccountUpgradeChains:
198210
getDisabledAccountUpgradeChainsMock,
211+
validateSecurity: validateSecurityMock,
199212
},
200213
messenger,
201214
SEND_CALLS_MOCK,
@@ -213,6 +226,7 @@ describe('EIP-5792', () => {
213226
addTransactionBatch: addTransactionBatchMock,
214227
getDisabledAccountUpgradeChains:
215228
getDisabledAccountUpgradeChainsMock,
229+
validateSecurity: validateSecurityMock,
216230
},
217231
messenger,
218232
{
@@ -235,6 +249,7 @@ describe('EIP-5792', () => {
235249
addTransactionBatch: addTransactionBatchMock,
236250
getDisabledAccountUpgradeChains:
237251
getDisabledAccountUpgradeChainsMock,
252+
validateSecurity: validateSecurityMock,
238253
},
239254
messenger,
240255
{

app/scripts/lib/transaction/eip5792.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
TransactionMeta,
88
TransactionReceipt,
99
TransactionStatus,
10+
ValidateSecurityRequest,
1011
} from '@metamask/transaction-controller';
1112
import { Hex, JsonRpcRequest } from '@metamask/utils';
1213
import { Messenger } from '@metamask/base-controller';
@@ -16,6 +17,7 @@ import {
1617
SendCalls,
1718
SendCallsResult,
1819
} from '@metamask/eth-json-rpc-middleware';
20+
import { generateSecurityAlertId } from '../ppom/ppom-util';
1921

2022
type Actions =
2123
| NetworkControllerGetNetworkClientByIdAction
@@ -30,12 +32,22 @@ export async function processSendCalls(
3032
hooks: {
3133
addTransactionBatch: TransactionController['addTransactionBatch'];
3234
getDisabledAccountUpgradeChains: () => Hex[];
35+
validateSecurity: (
36+
securityAlertId: string,
37+
request: ValidateSecurityRequest,
38+
chainId: Hex,
39+
) => Promise<void>;
3340
},
3441
messenger: EIP5792Messenger,
3542
params: SendCalls,
3643
req: JsonRpcRequest & { networkClientId: string; origin?: string },
3744
): Promise<SendCallsResult> {
38-
const { addTransactionBatch, getDisabledAccountUpgradeChains } = hooks;
45+
const {
46+
addTransactionBatch,
47+
getDisabledAccountUpgradeChains,
48+
validateSecurity: validateSecurityHook,
49+
} = hooks;
50+
3951
const { calls, from } = params;
4052
const { networkClientId, origin } = req;
4153
const transactions = calls.map((call) => ({ params: call }));
@@ -49,11 +61,16 @@ export async function processSendCalls(
4961

5062
validateSendCalls(params, dappChainId, disabledChains);
5163

64+
const securityAlertId = generateSecurityAlertId();
65+
const validateSecurity = validateSecurityHook.bind(null, securityAlertId);
66+
5267
const { batchId: id } = await addTransactionBatch({
5368
from,
5469
networkClientId,
5570
origin,
71+
securityAlertId,
5672
transactions,
73+
validateSecurity,
5774
});
5875

5976
return { id };

app/scripts/metamask-controller.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,10 @@ import { METAMASK_COOKIE_HANDLER } from './constants/stream';
337337

338338
// Notification controllers
339339
import { createTxVerificationMiddleware } from './lib/tx-verification/tx-verification-middleware';
340-
import { updateSecurityAlertResponse } from './lib/ppom/ppom-util';
340+
import {
341+
updateSecurityAlertResponse,
342+
validateRequestWithPPOM,
343+
} from './lib/ppom/ppom-util';
341344
import createEvmMethodsToNonEvmAccountReqFilterMiddleware from './lib/createEvmMethodsToNonEvmAccountReqFilterMiddleware';
342345
import { isEthAddress } from './lib/multichain/address';
343346

@@ -2089,6 +2092,15 @@ export default class MetamaskController extends EventEmitter {
20892092
this.preferencesController.getDisabledAccountUpgradeChains.bind(
20902093
this.preferencesController,
20912094
),
2095+
validateSecurity: (securityAlertId, request, chainId) =>
2096+
validateRequestWithPPOM({
2097+
chainId,
2098+
ppomController: this.ppomController,
2099+
request,
2100+
securityAlertId,
2101+
updateSecurityAlertResponse:
2102+
this.updateSecurityAlertResponse.bind(this),
2103+
}),
20922104
},
20932105
this.controllerMessenger,
20942106
),

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@
325325
"@metamask/snaps-sdk": "^6.19.0",
326326
"@metamask/snaps-utils": "^9.0.1",
327327
"@metamask/solana-wallet-snap": "^1.15.1",
328-
"@metamask/transaction-controller": "^52.1.0",
328+
"@metamask/transaction-controller": "^52.2.0",
329329
"@metamask/user-operation-controller": "^24.0.1",
330330
"@metamask/utils": "^11.1.0",
331331
"@ngraveio/bc-ur": "^1.1.12",

test/e2e/tests/simulation-details/mock-request-buy-erc1155.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import {
77
export const BUY_ERC1155_TRANSACTION_MOCK = {
88
data: '0xe7acab24000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000006200000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000005200000000000000000000000000000000000000000000000000000000000000580000000000000000000000000a0d884d99316d14d7727a6a9223a8266a4595468000000000000000000000000004c00500000ad104d7dbd00e3ae0a5c00560c000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000065e517b200000000000000000000000000000000000000000000000000000000660de8220000000000000000000000000000000000000000000000000000000000000000360c6ebe0000000000000000000000000000000000000000187d7f63de4580450000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000076be3b62873462d2142405439777e971754e8e77000000000000000000000000000000000000000000000000000000000000286400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000059874438570000000000000000000000000000000000000000000000000000005987443857000000000000000000000000000a0d884d99316d14d7727a6a9223a8266a4595468000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028ed6103d000000000000000000000000000000000000000000000000000000028ed6103d0000000000000000000000000000000a26b00c1f0df003000390027140000faa7190000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a3b5840f40000000000000000000000000000000000000000000000000000000a3b5840f4000000000000000000000000000157e23d3e68ac6f99334b8b0fe71f0eb844911dd0000000000000000000000000000000000000000000000000000000000000040100fc5b608d71976e87680aa0b785ae11ac8b9004316b9721222a5d6bea2c7a346d74d85776450c82d2ee3e4fa24eb8d612f5975a577789ad2b58dfc6a6e49760000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000360c6ebe',
99
from: SENDER_ADDRESS_MOCK,
10-
maxFeePerGas: '0x0',
11-
maxPriorityFeePerGas: '0x0',
1210
to: '0x00000000000000adc04c56bf30ac9d3c0aaf14dc',
1311
value: '0x19945ca262000',
1412
};

test/e2e/tests/simulation-details/mock-request-buy-erc20.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import {
77
export const BUY_ERC20_TRANSACTION = {
88
data: `0x5ae401dc0000000000000000000000000000000000000000000000000000000065fb43ab0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000124b858183f00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000${SENDER_ADDRESS_NO_0X_MOCK}00000000000000000000000000000000000000000000000000071afd498d00000000000000000000000000000000000000000000000000005d4bc0025786653d0000000000000000000000000000000000000000000000000000000000000042c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f4a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000646b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000`,
99
from: SENDER_ADDRESS_MOCK,
10-
maxFeePerGas: '0x0',
11-
maxPriorityFeePerGas: '0x0',
1210
to: '0x13f4ea83d0bd40e75c8222255bc855a974568dd4',
1311
value: '0x71afd498d0000',
1412
};

test/e2e/tests/simulation-details/mock-request-buy-erc721.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import {
77
export const BUY_ERC721_TRANSACTION_MOCK = {
88
data: '0xfbee349d00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001ccc7b6351d59f42bbb85f1fcc89cd4ac31c69cfa0681c900c46ddb7ad3f3c690f1006752ecedda5ee83902884f78ae85a3a1996bc56dc30f6aba0004ddc87699f00000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff900d7067a24874264ced8198cc87ebd7c1c53d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006669f99b0000000000000000000000000000000024081bbd5ce9458a998286f53a873a41000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000000000000000000000000000002e01f4d5d760000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000ef9c21e3ba31a74910fc7e7cb3fc814ad842ad6e00000000000000000000000000000000000000000000000000000000000002cf000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000e9ba8fa0222fc76e8bcaa13e4258f749bb92af320000000000000000000000000000000000000000000000000003baf82d03a0000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
99
from: SENDER_ADDRESS_MOCK,
10-
maxFeePerGas: '0x0',
11-
maxPriorityFeePerGas: '0x0',
1210
to: '0xdef1c0ded9bec7f1a1670819833240f027b25eff',
1311
value: '0x31bced02db0000',
1412
};

test/e2e/tests/simulation-details/mock-request-error-insuffient-gas.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import {
66

77
export const INSUFFICIENT_GAS_TRANSACTION_MOCK = {
88
from: SENDER_ADDRESS_MOCK,
9-
maxFeePerGas: '0x0',
10-
maxPriorityFeePerGas: '0x0',
119
to: RECIPIENT_ADDRESS_MOCK,
1210
value: '0x6BC75E2D63100000',
1311
};

test/e2e/tests/simulation-details/mock-request-error-malformed-transaction.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import { MockRequestResponse, SENDER_ADDRESS_MOCK } from './types';
33
export const MALFORMED_TRANSACTION_MOCK = {
44
data: '0x0323498273498729872340897234087q',
55
from: SENDER_ADDRESS_MOCK,
6-
maxFeePerGas: '0x0',
7-
maxPriorityFeePerGas: '0x0',
86
to: '0xe18035bf8712672935fdb4e5e431b1a0183d2dfc',
97
value: '0x0',
108
};

test/e2e/tests/simulation-details/mock-request-no-changes.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import { MockRequestResponse, SENDER_ADDRESS_MOCK } from './types';
22

33
export const NO_CHANGES_TRANSACTION_MOCK = {
44
from: SENDER_ADDRESS_MOCK,
5-
maxFeePerGas: '0x0',
6-
maxPriorityFeePerGas: '0x0',
75
to: SENDER_ADDRESS_MOCK,
86
value: '0x0',
97
};

0 commit comments

Comments
 (0)