1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00
metamask-extension/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js
Mark Stacey b87c1b8526
Make setProviderType async (#18604)
The network controller method `setProviderType` is now async, and the
async operation `_setProviderConfig` called at the end of the method is
now awaited.

Because the only async operation was the last step, this should have no
impact upon the flow of execution. The only functional change is that
now any callers have the option of waiting until the network switch
operation has completed.

One such change was made, in the `switch-ethereum-chain` middleware. As
a result, an error thrown while the network is switching will now
be thrown in this middleware and returned to the dapp as an internal
error.

Relates to https://github.com/MetaMask/metamask-extension/issues/18587
2023-04-17 15:45:01 -02:30

133 lines
3.5 KiB
JavaScript

import { ethErrors } from 'eth-rpc-errors';
import { omit } from 'lodash';
import { MESSAGE_TYPE } from '../../../../../shared/constants/app';
import {
CHAIN_ID_TO_TYPE_MAP,
NETWORK_TO_NAME_MAP,
CHAIN_ID_TO_RPC_URL_MAP,
CURRENCY_SYMBOLS,
NETWORK_TYPES,
} from '../../../../../shared/constants/network';
import {
isPrefixedFormattedHexString,
isSafeChainId,
} from '../../../../../shared/modules/network.utils';
const switchEthereumChain = {
methodNames: [MESSAGE_TYPE.SWITCH_ETHEREUM_CHAIN],
implementation: switchEthereumChainHandler,
hookNames: {
getCurrentChainId: true,
findNetworkConfigurationBy: true,
setProviderType: true,
setActiveNetwork: true,
requestUserApproval: true,
},
};
export default switchEthereumChain;
function findExistingNetwork(chainId, findNetworkConfigurationBy) {
if (chainId in CHAIN_ID_TO_TYPE_MAP) {
return {
chainId,
ticker: CURRENCY_SYMBOLS.ETH,
nickname: NETWORK_TO_NAME_MAP[chainId],
rpcUrl: CHAIN_ID_TO_RPC_URL_MAP[chainId],
type: CHAIN_ID_TO_TYPE_MAP[chainId],
};
}
return findNetworkConfigurationBy({ chainId });
}
async function switchEthereumChainHandler(
req,
res,
_next,
end,
{
getCurrentChainId,
findNetworkConfigurationBy,
setProviderType,
setActiveNetwork,
requestUserApproval,
},
) {
if (!req.params?.[0] || typeof req.params[0] !== 'object') {
return end(
ethErrors.rpc.invalidParams({
message: `Expected single, object parameter. Received:\n${JSON.stringify(
req.params,
)}`,
}),
);
}
const { origin } = req;
const { chainId } = req.params[0];
const otherKeys = Object.keys(omit(req.params[0], ['chainId']));
if (otherKeys.length > 0) {
return end(
ethErrors.rpc.invalidParams({
message: `Received unexpected keys on object parameter. Unsupported keys:\n${otherKeys}`,
}),
);
}
const _chainId = typeof chainId === 'string' && chainId.toLowerCase();
if (!isPrefixedFormattedHexString(_chainId)) {
return end(
ethErrors.rpc.invalidParams({
message: `Expected 0x-prefixed, unpadded, non-zero hexadecimal string 'chainId'. Received:\n${chainId}`,
}),
);
}
if (!isSafeChainId(parseInt(_chainId, 16))) {
return end(
ethErrors.rpc.invalidParams({
message: `Invalid chain ID "${_chainId}": numerical value greater than max safe value. Received:\n${chainId}`,
}),
);
}
const requestData = findExistingNetwork(_chainId, findNetworkConfigurationBy);
if (requestData) {
const currentChainId = getCurrentChainId();
if (currentChainId === _chainId) {
res.result = null;
return end();
}
try {
const approvedRequestData = await requestUserApproval({
origin,
type: MESSAGE_TYPE.SWITCH_ETHEREUM_CHAIN,
requestData,
});
if (
chainId in CHAIN_ID_TO_TYPE_MAP &&
approvedRequestData.type !== NETWORK_TYPES.LOCALHOST &&
approvedRequestData.type !== NETWORK_TYPES.LINEA_TESTNET
) {
await setProviderType(approvedRequestData.type);
} else {
await setActiveNetwork(approvedRequestData.id);
}
res.result = null;
} catch (error) {
return end(error);
}
return end();
}
return end(
ethErrors.provider.custom({
code: 4902, // To-be-standardized "unrecognized chain ID" error
message: `Unrecognized chain ID "${chainId}". Try adding the chain using ${MESSAGE_TYPE.ADD_ETHEREUM_CHAIN} first.`,
}),
);
}