1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-02 06:07:06 +01:00
metamask-extension/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js

138 lines
3.6 KiB
JavaScript
Raw Normal View History

2021-05-10 21:14:21 +02:00
import { ethErrors } from 'eth-rpc-errors';
import { omit } from 'lodash';
2023-05-10 07:36:01 +02:00
import { ApprovalType } from '@metamask/controller-utils';
2021-05-10 21:14:21 +02:00
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,
BUILT_IN_INFURA_NETWORKS,
} from '../../../../../shared/constants/network';
2021-05-10 21:14:21 +02:00
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,
},
2021-05-10 21:14:21 +02:00
};
export default switchEthereumChain;
function findExistingNetwork(chainId, findNetworkConfigurationBy) {
if (
Object.values(BUILT_IN_INFURA_NETWORKS)
.map(({ chainId: id }) => id)
.includes(chainId)
) {
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 });
}
2021-05-10 21:14:21 +02:00
async function switchEthereumChainHandler(
req,
res,
_next,
end,
{
getCurrentChainId,
findNetworkConfigurationBy,
setProviderType,
setActiveNetwork,
requestUserApproval,
},
2021-05-10 21:14:21 +02:00
) {
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) {
2021-05-10 21:14:21 +02:00
const currentChainId = getCurrentChainId();
if (currentChainId === _chainId) {
res.result = null;
return end();
}
try {
const approvedRequestData = await requestUserApproval({
origin,
2023-05-10 07:36:01 +02:00
type: ApprovalType.SwitchEthereumChain,
requestData,
});
if (
Object.values(BUILT_IN_INFURA_NETWORKS)
.map(({ chainId: id }) => id)
.includes(chainId)
) {
await setProviderType(approvedRequestData.type);
} else {
await setActiveNetwork(approvedRequestData.id);
}
2021-05-10 21:14:21 +02:00
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.`,
}),
);
2021-05-10 21:14:21 +02:00
}