Skip to content
Closed
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
6 changes: 3 additions & 3 deletions app/core/BackgroundBridge/BackgroundBridge.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable import/no-commonjs */
import URL from 'url-parse';
import { JsonRpcEngine } from 'json-rpc-engine';
import { JsonRpcEngine } from '@metamask/json-rpc-engine';
import {
createSelectedNetworkMiddleware,
METAMASK_DOMAIN,
Expand All @@ -26,8 +26,8 @@ import snapMethodMiddlewareBuilder from '../Snaps/SnapsMethodMiddleware';
import { SubjectType } from '@metamask/permission-controller';
///: END:ONLY_INCLUDE_IF

const createFilterMiddleware = require('eth-json-rpc-filters');
const createSubscriptionManager = require('eth-json-rpc-filters/subscriptionManager');
const createFilterMiddleware = require('@metamask/eth-json-rpc-filters');
const createSubscriptionManager = require('@metamask/eth-json-rpc-filters/subscriptionManager');
const providerAsMiddleware = require('eth-json-rpc-middleware/providerAsMiddleware');
const pump = require('pump');
// eslint-disable-next-line import/no-nodejs-modules
Expand Down
43 changes: 28 additions & 15 deletions app/core/RPCMethods/RPCMethodMiddleware.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import {
JsonRpcEngine,
import { JsonRpcEngine, JsonRpcMiddleware } from '@metamask/json-rpc-engine';
import type {
Json,
JsonRpcFailure,
JsonRpcMiddleware,
JsonRpcParams,
JsonRpcRequest,
JsonRpcResponse,
JsonRpcSuccess,
} from 'json-rpc-engine';
} from '@metamask/utils';
import type { TransactionParams } from '@metamask/transaction-controller';
import { providerErrors, rpcErrors } from '@metamask/rpc-errors';
import Engine from '../Engine';
Expand Down Expand Up @@ -106,8 +107,8 @@ const jsonrpc = '2.0' as const;
* @throws If the given value is not a valid {@link JsonRpcSuccess} object.
*/
function assertIsJsonRpcSuccess(
response: JsonRpcResponse<unknown>,
): asserts response is JsonRpcSuccess<unknown> {
response: JsonRpcResponse<Json>,
): asserts response is JsonRpcSuccess<Json> {
if ('error' in response) {
throw new Error(`Response failed with error '${JSON.stringify('error')}'`);
} else if (!('result' in response)) {
Expand Down Expand Up @@ -208,8 +209,8 @@ async function callMiddleware({
middleware,
request,
}: {
middleware: JsonRpcMiddleware<unknown, unknown>;
request: JsonRpcRequest<unknown>;
middleware: JsonRpcMiddleware<JsonRpcParams, Json>;
request: JsonRpcRequest<JsonRpcParams>;
}) {
const engine = new JsonRpcEngine();
engine.push(middleware);
Expand Down Expand Up @@ -1097,7 +1098,8 @@ describe('getRpcMethodMiddleware', () => {
it('returns a JSON-RPC error if an error is thrown when adding this transaction', async () => {
// Omit `from` and `chainId` here to skip validation for simplicity
// Downcast needed here because `from` is required by this type
const mockTransactionParameters = {} as TransactionParams;
const mockTransactionParameters = {} as (TransactionParams &
JsonRpcParams)[];
// Transaction fails before returning a result
mockAddTransaction.mockImplementation(async () => {
throw new Error('Failed to add transaction');
Expand All @@ -1112,20 +1114,26 @@ describe('getRpcMethodMiddleware', () => {
method: 'eth_sendTransaction',
params: [mockTransactionParameters],
};
const expectedError = rpcErrors.internal('Failed to add transaction');
const expectedError = rpcErrors.internal('Internal JSON-RPC error.');
const expectedErrorCauseMessage = 'Failed to add transaction';

const response = await callMiddleware({ middleware, request });

expect((response as JsonRpcFailure).error.code).toBe(expectedError.code);
expect((response as JsonRpcFailure).error.message).toBe(
expectedError.message,
);
// @ts-expect-error - TODO: This should type
expect((response as JsonRpcFailure).error.data.cause.message).toBe(
expectedErrorCauseMessage,
);
});

it('returns a JSON-RPC error if an error is thrown after approval', async () => {
// Omit `from` and `chainId` here to skip validation for simplicity
// Downcast needed here because `from` is required by this type
const mockTransactionParameters = {} as TransactionParams;
const mockTransactionParameters = {} as (TransactionParams &
JsonRpcParams)[];
setupGlobalState({
addTransactionResult: Promise.reject(
new Error('Failed to process transaction'),
Expand All @@ -1142,14 +1150,19 @@ describe('getRpcMethodMiddleware', () => {
method: 'eth_sendTransaction',
params: [mockTransactionParameters],
};
const expectedError = rpcErrors.internal('Failed to process transaction');
const expectedError = rpcErrors.internal('Internal JSON-RPC error.');
const expectedErrorCauseMessage = 'Failed to process transaction';

const response = await callMiddleware({ middleware, request });

expect((response as JsonRpcFailure).error.code).toBe(expectedError.code);
expect((response as JsonRpcFailure).error.message).toBe(
expectedError.message,
);
// @ts-expect-error - TODO: This should type
expect((response as JsonRpcFailure).error.data.cause.message).toBe(
expectedErrorCauseMessage,
);
});
});

Expand Down Expand Up @@ -1215,7 +1228,7 @@ describe('getRpcMethodMiddleware', () => {
method: 'personal_ecRecover',
params: [helloWorldMessage],
};
const expectedError = rpcErrors.internal('Missing signature parameter');
const expectedError = rpcErrors.internal('Internal JSON-RPC error.');

const response = await callMiddleware({ middleware, request });

Expand All @@ -1234,9 +1247,9 @@ describe('getRpcMethodMiddleware', () => {
jsonrpc,
id: 1,
method: 'personal_ecRecover',
params: [undefined, helloWorldSignature],
params: [undefined, helloWorldSignature] as JsonRpcParams,
};
const expectedError = rpcErrors.internal('Missing data parameter');
const expectedError = rpcErrors.internal('Internal JSON-RPC error.');

const response = await callMiddleware({ middleware, request });

Expand Down
9 changes: 5 additions & 4 deletions app/core/RPCMethods/RPCMethodMiddleware.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Alert } from 'react-native';
import { getVersion } from 'react-native-device-info';
import { createAsyncMiddleware } from 'json-rpc-engine';
import { createAsyncMiddleware } from '@metamask/json-rpc-engine';
import { providerErrors, rpcErrors } from '@metamask/rpc-errors';
import {
EndFlowOptions,
Expand All @@ -15,6 +15,7 @@ import {
PermissionController,
permissionRpcMethods,
} from '@metamask/permission-controller';
import type { Hex } from '@metamask/utils';
import { blockTagParamIndex, getAllNetworks } from '../../util/networks';
import { polyfillGasPrice } from './utils';
import {
Expand Down Expand Up @@ -112,7 +113,7 @@ export const checkActiveAccountAndChainId = async ({
isWalletConnect,
}: {
address?: string;
chainId?: number;
chainId?: Hex;
channelId?: string;
hostname: string;
isWalletConnect: boolean;
Expand Down Expand Up @@ -224,7 +225,7 @@ const generateRawSignature = async ({
title: { current: string };
icon: { current: string | undefined };
analytics: { [key: string]: string | boolean };
chainId: number;
chainId: Hex;
isMMSDK: boolean;
channelId?: string;
getSource: () => string;
Expand Down Expand Up @@ -521,7 +522,7 @@ export const getRpcMethodMiddleware = ({
chainId,
}: {
from?: string;
chainId?: number;
chainId?: Hex;
}) => {
// TODO this needs to be modified for per dapp selected network
await checkActiveAccountAndChainId({
Expand Down
35 changes: 25 additions & 10 deletions app/core/RPCMethods/eth_sendTransaction.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
// eslint-disable-next-line import/no-nodejs-modules
import { inspect } from 'util';
import type { JsonRpcRequest, PendingJsonRpcResponse } from 'json-rpc-engine';
import type {
Json,
JsonRpcParams,
JsonRpcRequest,
PendingJsonRpcResponse,
} from '@metamask/utils';
import type {
TransactionParams,
TransactionController,
Expand Down Expand Up @@ -47,14 +52,16 @@ jest.mock('../../util/transaction-controller', () => ({
* @param params - The request parameters.
* @returns The JSON-RPC request.
*/
function constructSendTransactionRequest(
params: unknown,
): JsonRpcRequest<unknown> & { method: 'eth_sendTransaction' } {
function constructSendTransactionRequest(params: Json[]): JsonRpcRequest<
[TransactionParams & JsonRpcParams]
> & {
method: 'eth_sendTransaction';
} {
return {
jsonrpc: '2.0',
id: 1,
method: 'eth_sendTransaction',
params,
params: params as any,
};
}

Expand All @@ -63,7 +70,7 @@ function constructSendTransactionRequest(
*
* @returns A pending JSON-RPC response.
*/
function constructPendingJsonRpcResponse(): PendingJsonRpcResponse<unknown> {
function constructPendingJsonRpcResponse(): PendingJsonRpcResponse<Json> {
return {
jsonrpc: '2.0',
id: 1,
Expand Down Expand Up @@ -144,13 +151,17 @@ function getMockAddTransaction({
describe('eth_sendTransaction', () => {
it('sends the transaction and returns the resulting hash', async () => {
const mockAddress = '0x0000000000000000000000000000000000000001';
const mockTransactionParameters = { from: mockAddress };
const mockTransactionParameters = {
from: mockAddress,
} as TransactionParams;
const expectedResult = 'fake-hash';
const pendingResult = constructPendingJsonRpcResponse();

await eth_sendTransaction({
hostname: 'example.metamask.io',
req: constructSendTransactionRequest([mockTransactionParameters]),
req: constructSendTransactionRequest([
mockTransactionParameters as unknown as JsonRpcParams,
]) as any,
res: pendingResult,
sendTransaction: getMockAddTransaction({
expectedTransaction: mockTransactionParameters,
Expand All @@ -172,7 +183,9 @@ describe('eth_sendTransaction', () => {
async () =>
await eth_sendTransaction({
hostname: 'example.metamask.io',
req: constructSendTransactionRequest(invalidParameter),
req: constructSendTransactionRequest(
invalidParameter as unknown as Json[],
),
res: constructPendingJsonRpcResponse(),
sendTransaction: getMockAddTransaction({
returnValue: 'fake-hash',
Expand All @@ -194,7 +207,9 @@ describe('eth_sendTransaction', () => {
async () =>
await eth_sendTransaction({
hostname: 'example.metamask.io',
req: constructSendTransactionRequest(invalidParameter),
req: constructSendTransactionRequest(
invalidParameter as unknown as Json[],
),
res: constructPendingJsonRpcResponse(),
sendTransaction: getMockAddTransaction({
returnValue: 'fake-hash',
Expand Down
25 changes: 18 additions & 7 deletions app/core/RPCMethods/eth_sendTransaction.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import type { JsonRpcRequest, PendingJsonRpcResponse } from 'json-rpc-engine';
import type {
Hex,
Json,
JsonRpcParams,
JsonRpcRequest,
PendingJsonRpcResponse,
} from '@metamask/utils';
import {
TransactionController,
TransactionParams,
WalletDevice,
} from '@metamask/transaction-controller';
import { rpcErrors } from '@metamask/rpc-errors';
Expand Down Expand Up @@ -46,6 +53,11 @@ const hasProperty = <
): objectToCheck is ObjectToCheck & Record<Property, unknown> =>
Object.hasOwnProperty.call(objectToCheck, name);

interface SendArgs {
from: string;
chainId?: Hex;
}

/**
* Handle a `eth_sendTransaction` request.
*
Expand All @@ -66,13 +78,12 @@ async function eth_sendTransaction({
validateAccountAndChainId,
}: {
hostname: string;
req: JsonRpcRequest<unknown> & { method: 'eth_sendTransaction' };
res: PendingJsonRpcResponse<unknown>;
req: JsonRpcRequest<[TransactionParams & JsonRpcParams]> & {
method: 'eth_sendTransaction';
};
res: PendingJsonRpcResponse<Json>;
sendTransaction: TransactionController['addTransaction'];
validateAccountAndChainId: (args: {
from: string;
chainId?: number;
}) => Promise<void>;
validateAccountAndChainId: (args: SendArgs) => Promise<void>;
}) {
if (
!Array.isArray(req.params) &&
Expand Down
2 changes: 1 addition & 1 deletion app/core/RPCMethods/wallet_watchAsset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from '../../constants/error';
import { selectChainId } from '../../selectors/networkController';
import { isValidAddress } from 'ethereumjs-util';
import { JsonRpcRequest, PendingJsonRpcResponse } from 'json-rpc-engine';
import { JsonRpcRequest, PendingJsonRpcResponse } from '@metamask/utils';
import { toChecksumHexAddress } from '@metamask/controller-utils';

const wallet_watchAsset = async ({
Expand Down
21 changes: 12 additions & 9 deletions app/core/SanitizationMiddleware.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { JsonRpcMiddleware, JsonRpcRequest } from 'json-rpc-engine';
import { JsonRpcMiddleware } from '@metamask/json-rpc-engine';
import type { Json, JsonRpcParams, JsonRpcRequest } from '@metamask/utils';
import { addHexPrefix } from 'ethereumjs-util';

// We use this to clean any custom params from the txParams
Expand Down Expand Up @@ -39,18 +40,20 @@ export const permittedKeys = [
* @param parameter - The parameter to sanitize.
* @returns The given parameter containing just permitted keys.
*/
function sanitizeRpcParameter(parameter: Record<PropertyKey, unknown>) {
return permittedKeys.reduce<Record<string, unknown>>((copy, permitted) => {
function sanitizeRpcParameter(
parameter: Record<PropertyKey, unknown>,
): Record<string, Json> {
return permittedKeys.reduce<Record<string, Json>>((copy, permitted) => {
if (permitted in parameter) {
const value = parameter[permitted];
if (Array.isArray(value)) {
copy[permitted] = value.map(sanitize);
copy[permitted] = value.map(sanitize) as Json;
} else {
copy[permitted] = sanitize(value);
copy[permitted] = sanitize(value) as Json;
}
}
return copy;
}, {});
}, {} as Record<string, Json>);
}

/**
Expand Down Expand Up @@ -80,12 +83,12 @@ function sanitize(value: unknown) {
* request along.
*/
export function createSanitizationMiddleware(): JsonRpcMiddleware<
unknown,
unknown
JsonRpcParams,
Json
> {
// TODO: Replace "any" with type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (req: JsonRpcRequest<unknown>, _: any, next: () => any) => {
return (req: JsonRpcRequest<JsonRpcParams>, _: any, next: () => any) => {
if (!Array.isArray(req.params)) {
next();
return;
Expand Down
6 changes: 3 additions & 3 deletions app/core/Snaps/SnapBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
createSwappableProxy,
createEventEmitterProxy,
} from '@metamask/swappable-obj-proxy';
import { JsonRpcEngine } from 'json-rpc-engine';
import { JsonRpcEngine } from '@metamask/json-rpc-engine';
import { createEngineStream } from 'json-rpc-middleware-stream';
import { NetworksChainId } from '@metamask/controller-utils';

Expand All @@ -22,8 +22,8 @@ import snapMethodMiddlewareBuilder from './SnapsMethodMiddleware';
import { SubjectType } from '@metamask/permission-controller';

const ObjectMultiplex = require('@metamask/object-multiplex');
const createFilterMiddleware = require('eth-json-rpc-filters');
const createSubscriptionManager = require('eth-json-rpc-filters/subscriptionManager');
const createFilterMiddleware = require('@metamask/eth-json-rpc-filters');
const createSubscriptionManager = require('@metamask/eth-json-rpc-filters/subscriptionManager');
const providerAsMiddleware = require('eth-json-rpc-middleware/providerAsMiddleware');
const pump = require('pump');

Expand Down
2 changes: 1 addition & 1 deletion app/core/WalletConnect/extractApprovedAccounts.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Caveat, ValidPermission } from '@metamask/permission-controller';
import { Json } from 'json-rpc-engine';
import { Json } from '@metamask/utils';

export const extractApprovedAccounts = (
accountPermission: // TODO: Replace "any" with type
Expand Down
Loading
Loading