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

Version v12.9.3 RC #29358

Merged
merged 8 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
diff --git a/dist/multicall.cjs b/dist/multicall.cjs
index bf9aa5e86573fc1651f421cc0b64f5af121c3ab2..43a0531ed86cd3ee1774dcda3f990dd40f7f52de 100644
--- a/dist/multicall.cjs
+++ b/dist/multicall.cjs
@@ -342,9 +342,22 @@ const multicallOrFallback = async (calls, chainId, provider, maxCallsPerMultical
return [];
}
const multicallAddress = MULTICALL_CONTRACT_BY_CHAINID[chainId];
- return await (multicallAddress
- ? multicall(calls, multicallAddress, provider, maxCallsPerMulticall)
- : fallback(calls, maxCallsParallel));
+ if (multicallAddress) {
+ try {
+ return await multicall(calls, multicallAddress, provider, maxCallsPerMulticall);
+ }
+ catch (error) {
+ // Fallback only on revert
+ // https://docs.ethers.org/v5/troubleshooting/errors/#help-CALL_EXCEPTION
+ if (!error ||
+ typeof error !== 'object' ||
+ !('code' in error) ||
+ error.code !== 'CALL_EXCEPTION') {
+ throw error;
+ }
+ }
+ }
+ return await fallback(calls, maxCallsParallel);
};
exports.multicallOrFallback = multicallOrFallback;
//# sourceMappingURL=multicall.cjs.map
\ No newline at end of file
diff --git a/dist/multicall.mjs b/dist/multicall.mjs
index 8fbe0112303d5df1d868e0357a9d31e43a3b6cf9..860dfdbddd813659cb2be5f7faed5d4016db5966 100644
--- a/dist/multicall.mjs
+++ b/dist/multicall.mjs
@@ -339,8 +339,21 @@ export const multicallOrFallback = async (calls, chainId, provider, maxCallsPerM
return [];
}
const multicallAddress = MULTICALL_CONTRACT_BY_CHAINID[chainId];
- return await (multicallAddress
- ? multicall(calls, multicallAddress, provider, maxCallsPerMulticall)
- : fallback(calls, maxCallsParallel));
+ if (multicallAddress) {
+ try {
+ return await multicall(calls, multicallAddress, provider, maxCallsPerMulticall);
+ }
+ catch (error) {
+ // Fallback only on revert
+ // https://docs.ethers.org/v5/troubleshooting/errors/#help-CALL_EXCEPTION
+ if (!error ||
+ typeof error !== 'object' ||
+ !('code' in error) ||
+ error.code !== 'CALL_EXCEPTION') {
+ throw error;
+ }
+ }
+ }
+ return await fallback(calls, maxCallsParallel);
};
//# sourceMappingURL=multicall.mjs.map
\ No newline at end of file
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [12.9.3]
### Fixed
- Fix some cases where users were incorrectly seeing 0 token balances ([#29361](https://github.com/MetaMask/metamask-extension/pull/29361))
- Ensure users that opt out of smart transaction decoding don't send network requests to related APIs ([#29341](https://github.com/
MetaMask/metamask-extension/pull/29341))

## [12.9.2]
### Changed
- Display the "Amount" row within the advanced view of contract interaction confirmations, and whenever the amount being sent differs from the "You Send" row of the transaction simulation information by more than 5% ([#29131](https://github.com/MetaMask/metamask-extension/pull/29131))
Expand Down Expand Up @@ -5487,7 +5493,8 @@ Update styles and spacing on the critical error page ([#20350](https://github.c
- Added the ability to restore accounts from seed words.


[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v12.9.2...HEAD
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v12.9.3...HEAD
[12.9.3]: https://github.com/MetaMask/metamask-extension/compare/v12.9.2...v12.9.3
[12.9.2]: https://github.com/MetaMask/metamask-extension/compare/v12.9.1...v12.9.2
[12.9.1]: https://github.com/MetaMask/metamask-extension/compare/v12.9.0...v12.9.1
[12.9.0]: https://github.com/MetaMask/metamask-extension/compare/v12.8.1...v12.9.0
Expand Down
2 changes: 1 addition & 1 deletion app/scripts/controllers/permissions/background-api.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import nanoid from 'nanoid';
import { nanoid } from 'nanoid';
import {
CaveatTypes,
RestrictedMethods,
Expand Down
24 changes: 24 additions & 0 deletions app/scripts/lib/createMainFrameOriginMiddleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Request and responses are currently untyped.
/* eslint-disable @typescript-eslint/no-explicit-any */

/**
* Returns a middleware that appends the mainFrameOrigin to request
*
* @param {{ mainFrameOrigin: string }} opts - The middleware options
* @returns {Function}
*/

export default function createMainFrameOriginMiddleware({
mainFrameOrigin,
}: {
mainFrameOrigin: string;
}) {
return function mainFrameOriginMiddleware(
req: any,
_res: any,
next: () => void,
) {
req.mainFrameOrigin = mainFrameOrigin;
next();
};
}
50 changes: 49 additions & 1 deletion app/scripts/lib/ppom/ppom-util.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
SignatureController,
SignatureRequest,
} from '@metamask/signature-controller';
import { Hex } from '@metamask/utils';
import { Hex, JsonRpcRequest } from '@metamask/utils';
import {
BlockaidReason,
BlockaidResultType,
Expand All @@ -22,6 +22,8 @@ import { AppStateController } from '../../controllers/app-state-controller';
import {
generateSecurityAlertId,
isChainSupported,
METHOD_SIGN_TYPED_DATA_V3,
METHOD_SIGN_TYPED_DATA_V4,
updateSecurityAlertResponse,
validateRequestWithPPOM,
} from './ppom-util';
Expand Down Expand Up @@ -57,6 +59,10 @@ const TRANSACTION_PARAMS_MOCK_1: TransactionParams = {
value: '0x123',
};

const SIGN_TYPED_DATA_PARAMS_MOCK_1 = '0x123';
const SIGN_TYPED_DATA_PARAMS_MOCK_2 =
'{"primaryType":"Permit","domain":{},"types":{}}';

const TRANSACTION_PARAMS_MOCK_2: TransactionParams = {
...TRANSACTION_PARAMS_MOCK_1,
to: '0x456',
Expand Down Expand Up @@ -259,6 +265,48 @@ describe('PPOM Utils', () => {
);
});

// @ts-expect-error This is missing from the Mocha type definitions
it.each([METHOD_SIGN_TYPED_DATA_V3, METHOD_SIGN_TYPED_DATA_V4])(
'sanitizes request params if method is %s',
async (method: string) => {
const ppom = createPPOMMock();
const ppomController = createPPOMControllerMock();

ppomController.usePPOM.mockImplementation(
(callback) =>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
callback(ppom as any) as any,
);

const firstTwoParams = [
SIGN_TYPED_DATA_PARAMS_MOCK_1,
SIGN_TYPED_DATA_PARAMS_MOCK_2,
];

const unwantedParams = [{}, undefined, 1, null];

const params = [...firstTwoParams, ...unwantedParams];

const request = {
...REQUEST_MOCK,
method,
params,
} as unknown as JsonRpcRequest;

await validateRequestWithPPOM({
...validateRequestWithPPOMOptionsBase,
ppomController,
request,
});

expect(ppom.validateJsonRpc).toHaveBeenCalledTimes(1);
expect(ppom.validateJsonRpc).toHaveBeenCalledWith({
...request,
params: firstTwoParams,
});
},
);

it('updates response indicating chain is not supported', async () => {
const ppomController = {} as PPOMController;
const CHAIN_ID_UNSUPPORTED_MOCK = '0x2';
Expand Down
20 changes: 19 additions & 1 deletion app/scripts/lib/ppom/ppom-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import {
const { sentry } = global;

const METHOD_SEND_TRANSACTION = 'eth_sendTransaction';
export const METHOD_SIGN_TYPED_DATA_V3 = 'eth_signTypedData_v3';
export const METHOD_SIGN_TYPED_DATA_V4 = 'eth_signTypedData_v4';

const SECURITY_ALERT_RESPONSE_ERROR = {
result_type: BlockaidResultType.Errored,
Expand Down Expand Up @@ -169,7 +171,7 @@ function normalizePPOMRequest(
request,
)
) {
return request;
return sanitizeRequest(request);
}

const transactionParams = request.params[0];
Expand All @@ -181,6 +183,22 @@ function normalizePPOMRequest(
};
}

function sanitizeRequest(request: JsonRpcRequest): JsonRpcRequest {
// This is a temporary fix to prevent a PPOM bypass
if (
request.method === METHOD_SIGN_TYPED_DATA_V4 ||
request.method === METHOD_SIGN_TYPED_DATA_V3
) {
if (Array.isArray(request.params)) {
return {
...request,
params: request.params.slice(0, 2),
};
}
}
return request;
}

function getErrorMessage(error: unknown) {
if (error instanceof Error) {
return `${error.name}: ${error.message}`;
Expand Down
24 changes: 22 additions & 2 deletions app/scripts/metamask-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import { rawChainData } from 'eth-chainlist';
import { MetaMaskKeyring as QRHardwareKeyring } from '@keystonehq/metamask-airgapped-keyring';
import EthQuery from '@metamask/eth-query';
import EthJSQuery from '@metamask/ethjs-query';
import nanoid from 'nanoid';
import { nanoid } from 'nanoid';
import { captureException } from '@sentry/browser';
import { AddressBookController } from '@metamask/address-book-controller';
import {
Expand Down Expand Up @@ -296,6 +296,7 @@ import {
createUnsupportedMethodMiddleware,
} from './lib/rpc-method-middleware';
import createOriginMiddleware from './lib/createOriginMiddleware';
import createMainFrameOriginMiddleware from './lib/createMainFrameOriginMiddleware';
import createTabIdMiddleware from './lib/createTabIdMiddleware';
import { NetworkOrderController } from './controllers/network-order';
import { AccountOrderController } from './controllers/account-order';
Expand Down Expand Up @@ -5669,11 +5670,18 @@ export default class MetamaskController extends EventEmitter {
tabId = sender.tab.id;
}

let mainFrameOrigin = origin;
if (sender.tab && sender.tab.url) {
// If sender origin is an iframe, then get the top-level frame's origin
mainFrameOrigin = new URL(sender.tab.url).origin;
}

const engine = this.setupProviderEngineEip1193({
origin,
sender,
subjectType,
tabId,
mainFrameOrigin,
});

const dupeReqFilterStream = createDupeReqFilterStream();
Expand Down Expand Up @@ -5794,13 +5802,25 @@ export default class MetamaskController extends EventEmitter {
* @param {MessageSender | SnapSender} options.sender - The sender object.
* @param {string} options.subjectType - The type of the sender subject.
* @param {tabId} [options.tabId] - The tab ID of the sender - if the sender is within a tab
* @param {mainFrameOrigin} [options.mainFrameOrigin] - The origin of the main frame if the sender is an iframe
*/
setupProviderEngineEip1193({ origin, subjectType, sender, tabId }) {
setupProviderEngineEip1193({
origin,
subjectType,
sender,
tabId,
mainFrameOrigin,
}) {
const engine = new JsonRpcEngine();

// Append origin to each request
engine.push(createOriginMiddleware({ origin }));

// Append mainFrameOrigin to each request if present
if (mainFrameOrigin) {
engine.push(createMainFrameOriginMiddleware({ mainFrameOrigin }));
}

// Append selectedNetworkClientId to each request
engine.push(createSelectedNetworkMiddleware(this.controllerMessenger));

Expand Down
Loading
Loading