Skip to content

Commit

Permalink
Use metamask/json-rpc-engine and metamask/rpc-errors
Browse files Browse the repository at this point in the history
  • Loading branch information
FrederikBolding committed Jul 14, 2023
1 parent f9e3ca8 commit f3c9b47
Show file tree
Hide file tree
Showing 14 changed files with 298 additions and 94 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,15 @@
"test:watch": "jest --watch"
},
"dependencies": {
"@metamask/json-rpc-engine": "^7.0.0",
"@metamask/object-multiplex": "^1.1.0",
"@metamask/rpc-errors": "^5.1.1",
"@metamask/safe-event-emitter": "^3.0.0",
"@metamask/utils": "^6.2.0",
"detect-browser": "^5.2.0",
"eth-rpc-errors": "^4.0.2",
"extension-port-stream": "^2.0.1",
"fast-deep-equal": "^3.1.3",
"is-stream": "^2.0.0",
"json-rpc-engine": "^6.1.0",
"json-rpc-middleware-stream": "^4.2.1",
"pump": "^3.0.0",
"webextension-polyfill": "^0.10.0"
Expand Down
39 changes: 17 additions & 22 deletions src/BaseProvider.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { JsonRpcEngine, JsonRpcMiddleware } from '@metamask/json-rpc-engine';
import { rpcErrors, JsonRpcError } from '@metamask/rpc-errors';
import SafeEventEmitter from '@metamask/safe-event-emitter';
import { ethErrors, EthereumRpcError } from 'eth-rpc-errors';
import dequal from 'fast-deep-equal';
import {
JsonRpcEngine,
JsonRpcRequest,
JsonRpcId,
JsonRpcVersion,
JsonRpcVersion2,
JsonRpcSuccess,
JsonRpcMiddleware,
} from 'json-rpc-engine';
JsonRpcParams,
Json,
} from '@metamask/utils';
import dequal from 'fast-deep-equal';

import messages from './messages';
import {
Expand All @@ -20,7 +21,7 @@ import {

export type UnvalidatedJsonRpcRequest = {
id?: JsonRpcId;
jsonrpc?: JsonRpcVersion;
jsonrpc?: JsonRpcVersion2;
method: string;
params?: unknown;
};
Expand All @@ -37,10 +38,10 @@ export type BaseProviderOptions = {
maxEventListeners?: number;

/**
* `json-rpc-engine` middleware. The middleware will be inserted in the given
* `@metamask/json-rpc-engine` middleware. The middleware will be inserted in the given
* order immediately after engine initialization.
*/
rpcMiddleware?: JsonRpcMiddleware<unknown, unknown>[];
rpcMiddleware?: JsonRpcMiddleware<JsonRpcParams, Json>[];
};

export type RequestArguments = {
Expand Down Expand Up @@ -169,7 +170,7 @@ export abstract class BaseProvider extends SafeEventEmitter {
*/
async request<T>(args: RequestArguments): Promise<Maybe<T>> {
if (!args || typeof args !== 'object' || Array.isArray(args)) {
throw ethErrors.rpc.invalidRequest({
throw rpcErrors.invalidRequest({
message: messages.errors.invalidRequestArgs(),
data: args,
});
Expand All @@ -178,7 +179,7 @@ export abstract class BaseProvider extends SafeEventEmitter {
const { method, params } = args;

if (typeof method !== 'string' || method.length === 0) {
throw ethErrors.rpc.invalidRequest({
throw rpcErrors.invalidRequest({
message: messages.errors.invalidRequestMethod(),
data: args,
});
Expand All @@ -189,7 +190,7 @@ export abstract class BaseProvider extends SafeEventEmitter {
!Array.isArray(params) &&
(typeof params !== 'object' || params === null)
) {
throw ethErrors.rpc.invalidRequest({
throw rpcErrors.invalidRequest({
message: messages.errors.invalidRequestParams(),
data: args,
});
Expand Down Expand Up @@ -285,15 +286,9 @@ export abstract class BaseProvider extends SafeEventEmitter {
callback(error, response);
};
}
return this._rpcEngine.handle(
payload as JsonRpcRequest<unknown>,
callbackWrapper,
);
return this._rpcEngine.handle(payload as JsonRpcRequest, callbackWrapper);
}
return this._rpcEngine.handle(
payload as JsonRpcRequest<unknown>[],
callbackWrapper,
);
return this._rpcEngine.handle(payload as JsonRpcRequest[], callbackWrapper);
}

/**
Expand Down Expand Up @@ -331,13 +326,13 @@ export abstract class BaseProvider extends SafeEventEmitter {

let error;
if (isRecoverable) {
error = new EthereumRpcError(
error = new JsonRpcError(
1013, // Try again later
errorMessage ?? messages.errors.disconnected(),
);
this._log.debug(error);
} else {
error = new EthereumRpcError(
error = new JsonRpcError(
1011, // Internal error
errorMessage ?? messages.errors.permanentlyDisconnected(),
);
Expand Down
5 changes: 2 additions & 3 deletions src/MetaMaskInpageProvider.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { JsonRpcRequest } from 'json-rpc-engine';
import { JsonRpcRequest } from '@metamask/utils';

import messages from './messages';
import {
MetaMaskInpageProviderStreamName,
MetaMaskInpageProvider,
Expand Down Expand Up @@ -58,7 +57,7 @@ async function getInitializedProvider({
onMethodCalled?: {
substream: string;
method: string;
callback: (data: JsonRpcRequest<unknown>) => void;
callback: (data: JsonRpcRequest) => void;
}[];
} = {}): Promise<InitializedProviderDetails> {
const onWrite = jest.fn();
Expand Down
26 changes: 14 additions & 12 deletions src/MetaMaskInpageProvider.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { ethErrors } from 'eth-rpc-errors';
import type { JsonRpcRequest, JsonRpcResponse } from 'json-rpc-engine';
import { rpcErrors } from '@metamask/rpc-errors';
import type { Json, JsonRpcRequest, JsonRpcResponse } from '@metamask/utils';
import type { Duplex } from 'stream';

import type { UnvalidatedJsonRpcRequest } from './BaseProvider';
import messages from './messages';
import { sendSiteMetadata } from './siteMetadata';
import {
Expand All @@ -22,7 +21,7 @@ export type SendSyncJsonRpcRequest = {
| 'eth_coinbase'
| 'eth_uninstallFilter'
| 'net_version';
} & JsonRpcRequest<unknown>;
} & JsonRpcRequest;

type WarningEventName = keyof SentWarningsState['events'];

Expand Down Expand Up @@ -171,8 +170,8 @@ export class MetaMaskInpageProvider extends AbstractStreamProvider {
* @param callback - The callback function.
*/
sendAsync(
payload: JsonRpcRequest<unknown>,
callback: (error: Error | null, result?: JsonRpcResponse<unknown>) => void,
payload: JsonRpcRequest,
callback: (error: Error | null, result?: JsonRpcResponse<Json>) => void,
): void {
this._rpcRequest(payload, callback);
}
Expand Down Expand Up @@ -283,7 +282,10 @@ export class MetaMaskInpageProvider extends AbstractStreamProvider {
* @returns A Promise that resolves with the JSON-RPC response object for the
* request.
*/
send<T>(method: string, params?: T[]): Promise<JsonRpcResponse<T>>;
send<T extends Json>(
method: string,
params?: T[],
): Promise<JsonRpcResponse<T>>;

/**
* Submits an RPC request per the given JSON-RPC request object.
Expand All @@ -293,8 +295,8 @@ export class MetaMaskInpageProvider extends AbstractStreamProvider {
* @param callback - An error-first callback that will receive the JSON-RPC
* response object.
*/
send<T>(
payload: JsonRpcRequest<unknown>,
send<T extends Json>(
payload: JsonRpcRequest,
callback: (error: Error | null, result?: JsonRpcResponse<T>) => void,
): void;

Expand All @@ -306,7 +308,7 @@ export class MetaMaskInpageProvider extends AbstractStreamProvider {
* @param payload - A JSON-RPC request object.
* @returns A JSON-RPC response object.
*/
send<T>(payload: SendSyncJsonRpcRequest): JsonRpcResponse<T>;
send<T extends Json>(payload: SendSyncJsonRpcRequest): JsonRpcResponse<T>;

// eslint-disable-next-line @typescript-eslint/promise-function-async
send(methodOrPayload: unknown, callbackOrArgs?: unknown): unknown {
Expand Down Expand Up @@ -335,7 +337,7 @@ export class MetaMaskInpageProvider extends AbstractStreamProvider {
typeof callbackOrArgs === 'function'
) {
return this._rpcRequest(
methodOrPayload as JsonRpcRequest<unknown>,
methodOrPayload as JsonRpcRequest,
callbackOrArgs as (...args: unknown[]) => void,
);
}
Expand Down Expand Up @@ -412,7 +414,7 @@ export class MetaMaskInpageProvider extends AbstractStreamProvider {
*/
requestBatch: async (requests: UnvalidatedJsonRpcRequest[]) => {
if (!Array.isArray(requests)) {
throw ethErrors.rpc.invalidRequest({
throw rpcErrors.invalidRequest({
message:
'Batch requests must be made with an array of request objects.',
data: requests,
Expand Down
5 changes: 3 additions & 2 deletions src/StreamProvider.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { JsonRpcMiddleware } from 'json-rpc-engine';
import type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';
import { Json, JsonRpcParams } from '@metamask/utils';

import messages from './messages';
import { StreamProvider } from './StreamProvider';
Expand All @@ -15,7 +16,7 @@ const mockStreamName = 'mock-stream';
* @returns A tuple containing the StreamProvider instance and the mock stream.
*/
function getStreamProvider(
rpcMiddleware: JsonRpcMiddleware<unknown, unknown>[] = [],
rpcMiddleware: JsonRpcMiddleware<JsonRpcParams, Json>[] = [],
) {
const mockStream = new MockConnectionStream();
const streamProvider = new StreamProvider(mockStream, {
Expand Down
5 changes: 3 additions & 2 deletions src/StreamProvider.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';
import ObjectMultiplex from '@metamask/object-multiplex';
import SafeEventEmitter from '@metamask/safe-event-emitter';
import { Json, JsonRpcParams } from '@metamask/utils';
import { duplex as isDuplex } from 'is-stream';
import type { JsonRpcMiddleware } from 'json-rpc-engine';
import { createStreamMiddleware } from 'json-rpc-middleware-stream';
import pump from 'pump';
import type { Duplex } from 'stream';
Expand All @@ -23,7 +24,7 @@ export type StreamProviderOptions = {

export type JsonRpcConnection = {
events: SafeEventEmitter;
middleware: JsonRpcMiddleware<unknown, unknown>;
middleware: JsonRpcMiddleware<JsonRpcParams, Json>;
stream: Duplex;
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { JsonRpcRequest } from 'json-rpc-engine';
import type { JsonRpcRequest } from '@metamask/utils';

import { createExternalExtensionProvider } from './createExternalExtensionProvider';
import config from './external-extension-config.json';
Expand Down Expand Up @@ -49,7 +49,7 @@ async function getInitializedProvider({
onMethodCalled?: {
substream: string;
method: string;
callback: (data: JsonRpcRequest<unknown>) => void;
callback: (data: JsonRpcRequest) => void;
}[];
} = {}): Promise<InitializedExtensionProviderDetails> {
const onWrite = jest.fn();
Expand Down
7 changes: 4 additions & 3 deletions src/middleware/createRpcWarningMiddleware.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { JsonRpcEngine, JsonRpcFailure, JsonRpcSuccess } from 'json-rpc-engine';
import { JsonRpcEngine } from '@metamask/json-rpc-engine';
import { Json, JsonRpcFailure, JsonRpcSuccess } from '@metamask/utils';

import { createRpcWarningMiddleware } from './createRpcWarningMiddleware';
import messages from '../messages';
Expand Down Expand Up @@ -89,7 +90,7 @@ describe('createRpcWarningMiddleware', () => {
jsonrpc: '2.0',
id: 1,
method,
})) as JsonRpcSuccess<unknown>;
})) as JsonRpcSuccess<Json>;

expect(response.result).toBe('success!');
});
Expand Down Expand Up @@ -138,7 +139,7 @@ describe('createRpcWarningMiddleware', () => {
id: 1,
method,
params,
})) as JsonRpcSuccess<unknown>;
})) as JsonRpcSuccess<Json>;

expect(response.result).toBe('success!');
});
Expand Down
5 changes: 3 additions & 2 deletions src/middleware/createRpcWarningMiddleware.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { JsonRpcMiddleware, JsonRpcRequest } from 'json-rpc-engine';
import type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';
import type { Json, JsonRpcParams, JsonRpcRequest } from '@metamask/utils';

import { ERC1155, ERC721 } from '../constants';
import messages from '../messages';
Expand All @@ -12,7 +13,7 @@ import type { ConsoleLike } from '../utils';
*/
export function createRpcWarningMiddleware(
log: ConsoleLike,
): JsonRpcMiddleware<unknown, unknown> {
): JsonRpcMiddleware<JsonRpcParams, Json> {
const sentWarnings = {
ethDecryptDeprecation: false,
ethGetEncryptionPublicKeyDeprecation: false,
Expand Down
2 changes: 1 addition & 1 deletion src/siteMetadata.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { JsonRpcEngine } from 'json-rpc-engine';
import { JsonRpcEngine } from '@metamask/json-rpc-engine';

import messages from './messages';
import { ConsoleLike, NOOP } from './utils';
Expand Down
16 changes: 8 additions & 8 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { ethErrors } from 'eth-rpc-errors';
import {
createIdRemapMiddleware,
JsonRpcMiddleware,
PendingJsonRpcResponse,
} from 'json-rpc-engine';
} from '@metamask/json-rpc-engine';
import { rpcErrors } from '@metamask/rpc-errors';
import { Json, JsonRpcParams, PendingJsonRpcResponse } from '@metamask/utils';

import { createRpcWarningMiddleware } from './middleware/createRpcWarningMiddleware';

Expand All @@ -27,7 +27,7 @@ export const EMITTED_NOTIFICATIONS = Object.freeze([
* remapping middleware and an error middleware.
*
* @param logger - The logger to use in the error middleware.
* @returns An array of json-rpc-engine middleware functions.
* @returns An array of @metamask/json-rpc-engine middleware functions.
*/
export const getDefaultExternalMiddleware = (logger: ConsoleLike = console) => [
createIdRemapMiddleware(),
Expand All @@ -40,15 +40,15 @@ export const getDefaultExternalMiddleware = (logger: ConsoleLike = console) => [
* method.
*
* @param log - The logging API to use.
* @returns A json-rpc-engine middleware function.
* @returns A @metamask/json-rpc-engine middleware function.
*/
function createErrorMiddleware(
log: ConsoleLike,
): JsonRpcMiddleware<unknown, unknown> {
): JsonRpcMiddleware<JsonRpcParams, Json> {
return (request, response, next) => {
// json-rpc-engine will terminate the request when it notices this error
if (typeof request.method !== 'string' || !request.method) {
response.error = ethErrors.rpc.invalidRequest({
response.error = rpcErrors.invalidRequest({
message: `The request 'method' must be a non-empty string.`,
data: request,
});
Expand All @@ -72,7 +72,7 @@ export const getRpcPromiseCallback =
reject: (error?: Error) => void,
unwrapResult = true,
) =>
(error: Error, response: PendingJsonRpcResponse<unknown>): void => {
(error: Error, response: PendingJsonRpcResponse<Json>): void => {
if (error || response.error) {
reject(error || response.error);
} else {
Expand Down
Loading

0 comments on commit f3c9b47

Please sign in to comment.