@metamask/snaps-rpc-methods
Version:
MetaMask Snaps JSON-RPC method implementations
152 lines • 5.76 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.providerRequestHandler = void 0;
const rpc_errors_1 = require("@metamask/rpc-errors");
const superstruct_1 = require("@metamask/superstruct");
const utils_1 = require("@metamask/utils");
const endowments_1 = require("../endowments/index.cjs");
// Read-only methods that are currently allowed for this RPC method.
const METHOD_ALLOWLIST = Object.freeze([
'eth_blockNumber',
'eth_call',
'eth_chainId',
'eth_coinbase',
'eth_estimateGas',
'eth_feeHistory',
'eth_gasPrice',
'eth_getBalance',
'eth_getBlockByHash',
'eth_getBlockByNumber',
'eth_getBlockTransactionCountByHash',
'eth_getBlockTransactionCountByNumber',
'eth_getCode',
'eth_getFilterChanges',
'eth_getFilterLogs',
'eth_getLogs',
'eth_getProof',
'eth_getStorageAt',
'eth_getTransactionByBlockHashAndIndex',
'eth_getTransactionByBlockNumberAndIndex',
'eth_getTransactionByHash',
'eth_getTransactionCount',
'eth_getTransactionReceipt',
'eth_getUncleByBlockHashAndIndex',
'eth_getUncleByBlockNumberAndIndex',
'eth_getUncleCountByBlockHash',
'eth_getUncleCountByBlockNumber',
'eth_getWork',
'eth_hashrate',
'eth_mining',
'eth_newBlockFilter',
'eth_newFilter',
'eth_newPendingTransactionFilter',
'eth_protocolVersion',
'eth_sendRawTransaction',
'eth_submitHashrate',
'eth_submitWork',
'eth_syncing',
'eth_uninstallFilter',
'net_listening',
'net_peerCount',
'net_version',
'web3_clientVersion',
'web3_sha3',
]);
const hookNames = {
hasPermission: true,
getNetworkConfigurationByChainId: true,
getNetworkClientById: true,
};
exports.providerRequestHandler = {
methodNames: ['snap_experimentalProviderRequest'],
implementation: providerRequestImplementation,
hookNames,
};
const ProviderRequestParametersStruct = (0, superstruct_1.object)({
chainId: utils_1.CaipChainIdStruct,
request: (0, superstruct_1.type)({
method: (0, superstruct_1.string)(),
params: (0, superstruct_1.optional)(utils_1.JsonRpcParamsStruct),
}),
});
/**
* The `snap_experimentalProviderRequest` method implementation.
*
* This RPC method lets Snaps make requests to MetaMask networks that are not currently selected in the UI.
*
* The RPC method requires the caller to have the endowment:ethereum-provider permission.
*
* NOTE: This implementation is experimental and may be removed or changed without warning.
*
* @param req - The JSON-RPC request object.
* @param res - The JSON-RPC response object.
* @param _next - The `json-rpc-engine` "next" callback. Not used by this
* function.
* @param end - The `json-rpc-engine` "end" callback.
* @param hooks - The RPC method hooks.
* @param hooks.hasPermission - Checks whether a given origin has a given permission.
* @param hooks.getNetworkConfigurationByChainId - Get a network configuration for a given chain ID.
* @param hooks.getNetworkClientById - Get a network client for a given ID.
* @returns Nothing.
*/
async function providerRequestImplementation(req,
// `ProviderRequestResult` is an alias for `Json` (which is the default type
// argument for `PendingJsonRpcResponse`), but that may not be the case in the
// future. We use `ProviderRequestResult` here to make it clear that this is
// the expected type of the result.
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-arguments
res, _next, end, { hasPermission, getNetworkConfigurationByChainId, getNetworkClientById, }) {
if (!hasPermission(endowments_1.SnapEndowments.EthereumProvider)) {
return end(rpc_errors_1.rpcErrors.methodNotFound());
}
const { params } = req;
try {
const { chainId, request } = getValidatedParams(params);
if (!METHOD_ALLOWLIST.includes(request.method)) {
return end(rpc_errors_1.rpcErrors.methodNotFound());
}
const parsedChainId = (0, utils_1.parseCaipChainId)(chainId);
if (parsedChainId.namespace !== 'eip155') {
return end(rpc_errors_1.rpcErrors.invalidParams({
message: 'Only EVM networks are currently supported.',
}));
}
const numericalChainId = BigInt(parsedChainId.reference);
const networkConfiguration = getNetworkConfigurationByChainId((0, utils_1.bigIntToHex)(numericalChainId));
if (!networkConfiguration) {
return end(rpc_errors_1.rpcErrors.invalidParams({
message: 'The requested network is not available.',
}));
}
const rpc = networkConfiguration.rpcEndpoints[networkConfiguration.defaultRpcEndpointIndex];
const networkClient = getNetworkClientById(rpc.networkClientId);
const { provider } = networkClient;
res.result = await provider.request(request);
}
catch (error) {
return end(error);
}
return end();
}
/**
* Validate the method `params` and returns them cast to the correct
* type. Throws if validation fails.
*
* @param params - The unvalidated params object from the method request.
* @returns The validated updateInterface method parameter object.
*/
function getValidatedParams(params) {
try {
return (0, superstruct_1.create)(params, ProviderRequestParametersStruct);
}
catch (error) {
if (error instanceof superstruct_1.StructError) {
throw rpc_errors_1.rpcErrors.invalidParams({
message: `Invalid params: ${error.message}.`,
});
}
/* istanbul ignore next */
throw rpc_errors_1.rpcErrors.internal();
}
}
//# sourceMappingURL=experimentalProviderRequest.cjs.map