Skip to content

Commit a7aa94c

Browse files
committed
refactor: Migrate create-network-client
1 parent fbb9b00 commit a7aa94c

File tree

9 files changed

+116
-99
lines changed

9 files changed

+116
-99
lines changed

eslint-warning-thresholds.json

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -317,13 +317,6 @@
317317
"packages/name-controller/src/util.ts": {
318318
"jsdoc/require-returns": 1
319319
},
320-
"packages/network-controller/src/NetworkController.ts": {
321-
"@typescript-eslint/prefer-promise-reject-errors": 1
322-
},
323-
"packages/network-controller/tests/NetworkController.test.ts": {
324-
"@typescript-eslint/no-unused-vars": 1,
325-
"@typescript-eslint/prefer-promise-reject-errors": 1
326-
},
327320
"packages/network-controller/tests/create-network-client.test.ts": {
328321
"import-x/order": 1
329322
},

packages/eth-json-rpc-middleware/src/providerAsMiddleware.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { SafeEventEmitterProvider } from '@metamask/eth-json-rpc-provider';
1+
import type { InternalProvider } from '@metamask/eth-json-rpc-provider';
22
import { JsonRpcEngine } from '@metamask/json-rpc-engine';
33
import { JsonRpcEngineV2 } from '@metamask/json-rpc-engine/v2';
44
import type { Json } from '@metamask/utils';
@@ -10,10 +10,10 @@ import {
1010
} from './providerAsMiddleware';
1111
import { createRequest } from '../test/util/helpers';
1212

13-
const createMockProvider = (result: Json): SafeEventEmitterProvider =>
13+
const createMockProvider = (result: Json): InternalProvider =>
1414
({
1515
request: jest.fn().mockResolvedValue(result),
16-
}) as unknown as SafeEventEmitterProvider;
16+
}) as unknown as InternalProvider;
1717

1818
describe('providerAsMiddleware', () => {
1919
it('forwards requests to the provider and returns the result', async () => {

packages/eth-json-rpc-provider/src/internal-provider.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,28 @@ type Eip1193Request<Params extends JsonRpcParams> = {
2626
params?: Params;
2727
};
2828

29-
type Options =
29+
/**
30+
* The {@link JsonRpcMiddleware} constraint and default type for the {@link InternalProvider}.
31+
* We care that the middleware can handle JSON-RPC requests, but do not care about the context,
32+
* the validity of which is enforced by the {@link JsonRpcServer}.
33+
*/
34+
export type InternalProviderMiddleware = JsonRpcMiddleware<
35+
JsonRpcRequest,
36+
Json,
37+
// Non-polluting `any` constraint.
38+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
39+
any
40+
>;
41+
42+
type Options<Middleware extends InternalProviderMiddleware> =
3043
| {
3144
/**
3245
* @deprecated Use `rpcHandler` instead.
3346
*/
3447
engine: JsonRpcEngine;
3548
}
3649
| {
37-
rpcHandler:
38-
| JsonRpcEngine
39-
| JsonRpcServer<JsonRpcMiddleware<JsonRpcRequest>>;
50+
rpcHandler: JsonRpcEngine | JsonRpcServer<Middleware>;
4051
};
4152

4253
/**
@@ -45,10 +56,10 @@ type Options =
4556
* This provider loosely follows conventions that pre-date EIP-1193.
4657
* It is not compliant with any Ethereum provider standard.
4758
*/
48-
export class InternalProvider {
49-
readonly #rpcHandler:
50-
| JsonRpcEngine
51-
| JsonRpcServer<JsonRpcMiddleware<JsonRpcRequest>>;
59+
export class InternalProvider<
60+
Middleware extends InternalProviderMiddleware = InternalProviderMiddleware,
61+
> {
62+
readonly #rpcHandler: JsonRpcEngine | JsonRpcServer<Middleware>;
5263

5364
/**
5465
* Construct a InternalProvider from a JSON-RPC server or legacy engine.
@@ -57,7 +68,7 @@ export class InternalProvider {
5768
* @param options.rpcHandler - The JSON-RPC server or engine used to process requests. Mutually exclusive with `engine`.
5869
* @param options.engine - The JSON-RPC engine used to process requests. Mutually exclusive with `rpcHandler`.
5970
*/
60-
constructor(options: Options) {
71+
constructor(options: Options<Middleware>) {
6172
this.#rpcHandler =
6273
'rpcHandler' in options ? options.rpcHandler : options.engine;
6374
}

packages/eth-json-rpc-provider/src/provider-from-middleware.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { JsonRpcEngine } from '@metamask/json-rpc-engine';
22
import type { JsonRpcMiddleware as LegacyJsonRpcMiddleware } from '@metamask/json-rpc-engine';
33
import { JsonRpcServer } from '@metamask/json-rpc-engine/v2';
4-
import type { JsonRpcMiddleware } from '@metamask/json-rpc-engine/v2';
5-
import type { Json, JsonRpcParams, JsonRpcRequest } from '@metamask/utils';
4+
import type { Json, JsonRpcParams } from '@metamask/utils';
65

6+
import type { InternalProviderMiddleware } from './internal-provider';
77
import { InternalProvider } from './internal-provider';
88
import { providerFromEngine } from './provider-from-engine';
99

@@ -31,7 +31,7 @@ export function providerFromMiddleware<
3131
* @returns An Ethereum provider.
3232
*/
3333
export function providerFromMiddlewareV2<
34-
Middleware extends JsonRpcMiddleware<JsonRpcRequest, Json>,
34+
Middleware extends InternalProviderMiddleware,
3535
>(middleware: Middleware): InternalProvider {
3636
return new InternalProvider({
3737
rpcHandler: new JsonRpcServer({ middleware: [middleware] }),

packages/json-rpc-engine/src/v2/JsonRpcEngineV2.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,16 @@ type ContextOf<Middleware> =
9191
? C
9292
: never;
9393

94-
export type MergedContextOf<
95-
// Non-polluting `any` constraint.
96-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
97-
Middleware extends JsonRpcMiddleware<any, any, any>,
98-
> = MergeContexts<ContextOf<Middleware>>;
94+
// Non-polluting `any` constraint.
95+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
96+
export type MiddlewareConstraint = JsonRpcMiddleware<
97+
any,
98+
ResultConstraint<any>,
99+
MiddlewareContext<any>
100+
>;
101+
102+
export type MergedContextOf<Middleware extends MiddlewareConstraint> =
103+
MergeContexts<ContextOf<Middleware>>;
99104

100105
const INVALID_ENGINE = Symbol('Invalid engine');
101106

packages/json-rpc-engine/src/v2/JsonRpcServer.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ import { hasProperty, isObject } from '@metamask/utils';
1111
import type {
1212
JsonRpcMiddleware,
1313
MergedContextOf,
14+
MiddlewareConstraint,
1415
RequestOf,
15-
ResultConstraint,
1616
} from './JsonRpcEngineV2';
1717
import { JsonRpcEngineV2 } from './JsonRpcEngineV2';
1818
import type { JsonRpcCall } from './utils';
1919
import { getUniqueId } from '../getUniqueId';
2020

2121
type OnError = (error: unknown) => void;
2222

23-
type Options<Middleware extends JsonRpcMiddleware> = {
23+
type Options<Middleware extends MiddlewareConstraint> = {
2424
onError?: OnError;
2525
} & (
2626
| {
@@ -58,14 +58,7 @@ const jsonrpc = '2.0' as const;
5858
* ```
5959
*/
6060
export class JsonRpcServer<
61-
Middleware extends JsonRpcMiddleware<
62-
// Non-polluting `any` constraint.
63-
/* eslint-disable @typescript-eslint/no-explicit-any */
64-
any,
65-
ResultConstraint<any>,
66-
any
67-
/* eslint-enable @typescript-eslint/no-explicit-any */
68-
> = JsonRpcMiddleware,
61+
Middleware extends MiddlewareConstraint = JsonRpcMiddleware,
6962
> {
7063
readonly #engine: JsonRpcEngineV2<
7164
RequestOf<Middleware>,
@@ -202,7 +195,7 @@ export class JsonRpcServer<
202195
}
203196

204197
if (isRequest) {
205-
(request as JsonRpcRequest).id = getUniqueId();
198+
(request as JsonRpcRequest).id = String(getUniqueId());
206199
}
207200

208201
return request;

packages/network-controller/src/NetworkController.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -705,8 +705,6 @@ function getDefaultInfuraNetworkConfigurationsByChainId(): Record<
705705
}
706706

707707
const rpcEndpointUrl =
708-
// False positive - this is a string.
709-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
710708
`https://${infuraNetworkType}.infura.io/v3/{infuraProjectId}` as const;
711709

712710
const networkConfiguration: NetworkConfiguration = {
@@ -1893,6 +1891,8 @@ export class NetworkController extends BaseController<
18931891
{ method: 'eth_getBlockByNumber', params: ['latest', false] },
18941892
(error: unknown, block?: unknown) => {
18951893
if (error) {
1894+
// We have no good reason to do this except long precedent.
1895+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
18961896
reject(error);
18971897
} else {
18981898
// TODO: Validate this type
@@ -2423,6 +2423,8 @@ export class NetworkController extends BaseController<
24232423
*
24242424
* In-progress requests will not be aborted.
24252425
*/
2426+
// We're intentionally changing the signature of an extended method.
2427+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
24262428
async destroy() {
24272429
await this.#blockTrackerProxy?.destroy();
24282430
}

packages/network-controller/src/create-network-client.ts

Lines changed: 70 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,19 @@ import {
1212
createFetchMiddleware,
1313
createRetryOnEmptyMiddleware,
1414
} from '@metamask/eth-json-rpc-middleware';
15-
import type { InternalProvider } from '@metamask/eth-json-rpc-provider';
15+
import { InternalProvider } from '@metamask/eth-json-rpc-provider';
16+
import { providerFromMiddlewareV2 } from '@metamask/eth-json-rpc-provider';
17+
import { asV2Middleware } from '@metamask/json-rpc-engine';
1618
import {
17-
providerFromEngine,
18-
providerFromMiddleware,
19-
} from '@metamask/eth-json-rpc-provider';
20-
import {
21-
createAsyncMiddleware,
2219
createScaffoldMiddleware,
23-
JsonRpcEngine,
24-
mergeMiddleware,
25-
} from '@metamask/json-rpc-engine';
26-
import type { JsonRpcMiddleware } from '@metamask/json-rpc-engine';
27-
import type { Hex, Json, JsonRpcParams } from '@metamask/utils';
20+
JsonRpcEngineV2,
21+
JsonRpcServer,
22+
} from '@metamask/json-rpc-engine/v2';
23+
import type {
24+
JsonRpcMiddleware,
25+
MiddlewareContext,
26+
} from '@metamask/json-rpc-engine/v2';
27+
import type { Hex, Json, JsonRpcRequest } from '@metamask/utils';
2828
import type { Logger } from 'loglevel';
2929

3030
import type { NetworkControllerMessenger } from './NetworkController';
@@ -50,6 +50,12 @@ export type NetworkClient = {
5050
destroy: () => void;
5151
};
5252

53+
type RpcApiMiddleware = JsonRpcMiddleware<
54+
JsonRpcRequest,
55+
Json,
56+
MiddlewareContext<{ origin: string }>
57+
>;
58+
5359
/**
5460
* Create a JSON RPC network client for a specific network.
5561
*
@@ -137,17 +143,21 @@ export function createNetworkClient({
137143
});
138144
});
139145

140-
const rpcApiMiddleware =
141-
configuration.type === NetworkClientType.Infura
142-
? createInfuraMiddleware({
143-
rpcService: rpcServiceChain,
144-
options: {
145-
source: 'metamask',
146-
},
147-
})
148-
: createFetchMiddleware({ rpcService: rpcServiceChain });
146+
let rpcApiMiddleware: RpcApiMiddleware;
147+
if (configuration.type === NetworkClientType.Infura) {
148+
rpcApiMiddleware = asV2Middleware(
149+
createInfuraMiddleware({
150+
rpcService: rpcServiceChain,
151+
options: {
152+
source: 'metamask',
153+
},
154+
}),
155+
) as unknown as RpcApiMiddleware;
156+
} else {
157+
rpcApiMiddleware = createFetchMiddleware({ rpcService: rpcServiceChain });
158+
}
149159

150-
const rpcProvider = providerFromMiddleware(rpcApiMiddleware);
160+
const rpcProvider = providerFromMiddlewareV2(rpcApiMiddleware);
151161

152162
const blockTracker = createBlockTracker({
153163
networkClientType: configuration.type,
@@ -170,11 +180,9 @@ export function createNetworkClient({
170180
rpcApiMiddleware,
171181
});
172182

173-
const engine = new JsonRpcEngine();
174-
175-
engine.push(networkMiddleware);
176-
177-
const provider = providerFromEngine(engine);
183+
const provider = new InternalProvider({
184+
rpcHandler: new JsonRpcServer({ middleware: [networkMiddleware] }),
185+
});
178186

179187
const destroy = () => {
180188
// TODO: Either fix this lint violation or explain why it's necessary to ignore.
@@ -241,17 +249,19 @@ function createInfuraNetworkMiddleware({
241249
blockTracker: PollingBlockTracker;
242250
network: InfuraNetworkType;
243251
rpcProvider: InternalProvider;
244-
rpcApiMiddleware: JsonRpcMiddleware<JsonRpcParams, Json>;
252+
rpcApiMiddleware: RpcApiMiddleware;
245253
}) {
246-
return mergeMiddleware([
247-
createNetworkAndChainIdMiddleware({ network }),
248-
createBlockCacheMiddleware({ blockTracker }),
249-
createInflightCacheMiddleware(),
250-
createBlockRefMiddleware({ blockTracker, provider: rpcProvider }),
251-
createRetryOnEmptyMiddleware({ blockTracker, provider: rpcProvider }),
252-
createBlockTrackerInspectorMiddleware({ blockTracker }),
253-
rpcApiMiddleware,
254-
]);
254+
return JsonRpcEngineV2.create({
255+
middleware: [
256+
createNetworkAndChainIdMiddleware({ network }),
257+
createBlockCacheMiddleware({ blockTracker }),
258+
createInflightCacheMiddleware(),
259+
createBlockRefMiddleware({ blockTracker, provider: rpcProvider }),
260+
createRetryOnEmptyMiddleware({ blockTracker, provider: rpcProvider }),
261+
createBlockTrackerInspectorMiddleware({ blockTracker }),
262+
rpcApiMiddleware,
263+
],
264+
}).asMiddleware();
255265
}
256266

257267
/**
@@ -273,11 +283,10 @@ function createNetworkAndChainIdMiddleware({
273283

274284
const createChainIdMiddleware = (
275285
chainId: Hex,
276-
): JsonRpcMiddleware<JsonRpcParams, Json> => {
277-
return (req, res, next, end) => {
278-
if (req.method === 'eth_chainId') {
279-
res.result = chainId;
280-
return end();
286+
): JsonRpcMiddleware<JsonRpcRequest, Json> => {
287+
return ({ request, next }) => {
288+
if (request.method === 'eth_chainId') {
289+
return chainId;
281290
}
282291
return next();
283292
};
@@ -299,21 +308,23 @@ function createCustomNetworkMiddleware({
299308
}: {
300309
blockTracker: PollingBlockTracker;
301310
chainId: Hex;
302-
rpcApiMiddleware: JsonRpcMiddleware<JsonRpcParams, Json>;
303-
}): JsonRpcMiddleware<JsonRpcParams, Json> {
311+
rpcApiMiddleware: RpcApiMiddleware;
312+
}) {
304313
const testMiddlewares = process.env.IN_TEST
305314
? [createEstimateGasDelayTestMiddleware()]
306315
: [];
307316

308-
return mergeMiddleware([
309-
...testMiddlewares,
310-
createChainIdMiddleware(chainId),
311-
createBlockRefRewriteMiddleware({ blockTracker }),
312-
createBlockCacheMiddleware({ blockTracker }),
313-
createInflightCacheMiddleware(),
314-
createBlockTrackerInspectorMiddleware({ blockTracker }),
315-
rpcApiMiddleware,
316-
]);
317+
return JsonRpcEngineV2.create({
318+
middleware: [
319+
...testMiddlewares,
320+
createChainIdMiddleware(chainId),
321+
createBlockRefRewriteMiddleware({ blockTracker }),
322+
createBlockCacheMiddleware({ blockTracker }),
323+
createInflightCacheMiddleware(),
324+
createBlockTrackerInspectorMiddleware({ blockTracker }),
325+
rpcApiMiddleware,
326+
],
327+
}).asMiddleware();
317328
}
318329

319330
/**
@@ -322,11 +333,14 @@ function createCustomNetworkMiddleware({
322333
*
323334
* @returns The middleware for delaying gas estimation calls by 2 seconds when in test.
324335
*/
325-
function createEstimateGasDelayTestMiddleware() {
326-
return createAsyncMiddleware(async (req, _, next) => {
327-
if (req.method === 'eth_estimateGas') {
336+
function createEstimateGasDelayTestMiddleware(): JsonRpcMiddleware<
337+
JsonRpcRequest,
338+
Json
339+
> {
340+
return async ({ request, next }) => {
341+
if (request.method === 'eth_estimateGas') {
328342
await new Promise((resolve) => setTimeout(resolve, SECOND * 2));
329343
}
330344
return next();
331-
});
345+
};
332346
}

0 commit comments

Comments
 (0)