Skip to content

Commit cd593b0

Browse files
FrederikBoldingPatrykLucka
authored andcommitted
fix: Skip unnecesary provider initialization (#2967)
Since we only expose the `request` function from the provider and don't allow listening to events or using `provider.chainId` etc we can initialize the provider without making the `metamask_getProviderState` request. This saves us a potential network request that may add overhead to booting the Snap. Specifically the clients call `net_version` since this property is required in the `MetaMaskInpageProvider`. Closes #2968
1 parent fabe009 commit cd593b0

File tree

11 files changed

+22
-199
lines changed

11 files changed

+22
-199
lines changed

packages/snaps-controllers/src/snaps/SnapController.test.tsx

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1652,14 +1652,7 @@ describe('SnapController', () => {
16521652
const stream = mux.createStream('metamask-provider');
16531653
const engine = new JsonRpcEngine();
16541654
const middleware = createAsyncMiddleware(async (req, res, _next) => {
1655-
if (req.method === 'metamask_getProviderState') {
1656-
res.result = {
1657-
isUnlocked: false,
1658-
accounts: [],
1659-
chainId: '0x1',
1660-
networkVersion: '1',
1661-
};
1662-
} else if (req.method === 'eth_blockNumber') {
1655+
if (req.method === 'eth_blockNumber') {
16631656
await sleep(100);
16641657
res.result = MOCK_BLOCK_NUMBER;
16651658
}
@@ -1737,14 +1730,7 @@ describe('SnapController', () => {
17371730
const stream = mux.createStream('metamask-provider');
17381731
const engine = new JsonRpcEngine();
17391732
const middleware = createAsyncMiddleware(async (req, res, _next) => {
1740-
if (req.method === 'metamask_getProviderState') {
1741-
res.result = {
1742-
isUnlocked: false,
1743-
accounts: [],
1744-
chainId: '0x1',
1745-
networkVersion: '1',
1746-
};
1747-
} else if (req.method === 'eth_blockNumber') {
1733+
if (req.method === 'eth_blockNumber') {
17481734
await sleep(100);
17491735
res.result = MOCK_BLOCK_NUMBER;
17501736
}

packages/snaps-controllers/src/test-utils/execution-environment.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,7 @@ export const getNodeEES = (messenger: ReturnType<typeof getNodeEESMessenger>) =>
4343
const stream = mux.createStream('metamask-provider');
4444
const engine = new JsonRpcEngine();
4545
engine.push((req, res, next, end) => {
46-
if (req.method === 'metamask_getProviderState') {
47-
res.result = {
48-
isUnlocked: false,
49-
accounts: [],
50-
chainId: '0x1',
51-
networkVersion: '1',
52-
};
53-
return end();
54-
} else if (req.method === 'eth_blockNumber') {
46+
if (req.method === 'eth_blockNumber') {
5547
res.result = MOCK_BLOCK_NUMBER;
5648
return end();
5749
}

packages/snaps-controllers/src/test-utils/service.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,6 @@ export const createService = <
3939
const stream = mux.createStream('metamask-provider');
4040
const engine = new JsonRpcEngine();
4141
engine.push((req, res, next, end) => {
42-
if (req.method === 'metamask_getProviderState') {
43-
res.result = {
44-
isUnlocked: false,
45-
accounts: [],
46-
chainId: '0x1',
47-
networkVersion: '1',
48-
};
49-
return end();
50-
}
51-
5242
if (req.method === 'eth_blockNumber') {
5343
res.result = MOCK_BLOCK_NUMBER;
5444
return end();
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"branches": 80.68,
3-
"functions": 89.26,
4-
"lines": 90.67,
5-
"statements": 90.06
3+
"functions": 89.33,
4+
"lines": 90.68,
5+
"statements": 90.08
66
}

packages/snaps-execution-environments/src/common/BaseSnapExecutor.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
// eslint-disable-next-line @typescript-eslint/triple-slash-reference, spaced-comment
22
/// <reference path="../../../../node_modules/ses/types.d.ts" />
33
import { createIdRemapMiddleware } from '@metamask/json-rpc-engine';
4-
import type { RequestArguments } from '@metamask/providers';
5-
import { StreamProvider } from '@metamask/providers/stream-provider';
4+
import type { RequestArguments, StreamProvider } from '@metamask/providers';
65
import { errorCodes, rpcErrors, serializeError } from '@metamask/rpc-errors';
76
import type { SnapsEthereumProvider, SnapsProvider } from '@metamask/snaps-sdk';
87
import { getErrorData } from '@metamask/snaps-sdk';
@@ -40,6 +39,7 @@ import type { CommandMethodsMapping } from './commands';
4039
import { getCommandMethodImplementations } from './commands';
4140
import { createEndowments } from './endowments';
4241
import { addEventListener, removeEventListener } from './globalEvents';
42+
import { SnapProvider } from './SnapProvider';
4343
import { sortParamKeys } from './sortParams';
4444
import {
4545
assertEthereumOutboundRequest,
@@ -369,12 +369,12 @@ export class BaseSnapExecutor {
369369
});
370370
};
371371

372-
const provider = new StreamProvider(this.rpcStream, {
372+
const provider = new SnapProvider(this.rpcStream, {
373373
jsonRpcStreamName: 'metamask-provider',
374374
rpcMiddleware: [createIdRemapMiddleware()],
375375
});
376376

377-
await provider.initialize();
377+
provider.initializeSync();
378378

379379
const snap = this.createSnapGlobal(provider);
380380
const ethereum = this.createEIP1193Provider(provider);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { StreamProvider } from '@metamask/providers/stream-provider';
2+
3+
export class SnapProvider extends StreamProvider {
4+
// Since only the request function is exposed to the Snap, we can initialize the provider
5+
// without making the metamask_getProviderState request, saving us a
6+
// potential network request before boot.
7+
initializeSync() {
8+
this._initializeState();
9+
}
10+
}

packages/snaps-execution-environments/src/common/test-utils/executor.ts

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ export class TestSnapExecutor extends BaseSnapExecutor {
111111
code: string,
112112
endowments: string[],
113113
) {
114-
const providerRequestPromise = this.readRpc();
115114
await this.writeCommand({
116115
jsonrpc: '2.0',
117116
id,
@@ -124,26 +123,6 @@ export class TestSnapExecutor extends BaseSnapExecutor {
124123
if ('clock' in setTimeout) {
125124
jest.advanceTimersByTime(1);
126125
}
127-
128-
const providerRequest = await providerRequestPromise;
129-
await this.writeRpc({
130-
name: 'metamask-provider',
131-
data: {
132-
jsonrpc: '2.0',
133-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
134-
id: providerRequest.data.id!,
135-
result: {
136-
isUnlocked: false,
137-
accounts: [],
138-
chainId: '0x1',
139-
networkVersion: '1',
140-
},
141-
},
142-
});
143-
144-
if ('clock' in setTimeout) {
145-
jest.advanceTimersByTime(1);
146-
}
147126
}
148127

149128
public async writeCommand(message: JsonRpcRequest): Promise<void> {

packages/snaps-execution-environments/src/iframe/IFrameSnapExecutor.test.browser.ts

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
MOCK_SNAP_ID,
77
MockWindowPostMessageStream,
88
} from '@metamask/snaps-utils/test-utils';
9-
import type { JsonRpcRequest } from '@metamask/utils';
109

1110
import { IFrameSnapExecutor } from './IFrameSnapExecutor';
1211

@@ -39,22 +38,6 @@ async function getResponse(
3938
});
4039
}
4140

42-
/**
43-
* Wait for a outbound request from the stream.
44-
*
45-
* @param stream - The stream to wait for a response on.
46-
* @returns The raw JSON-RPC response object.
47-
*/
48-
async function getOutboundRequest(
49-
stream: MockWindowPostMessageStream,
50-
): Promise<JsonRpcRequest> {
51-
return new Promise((resolve) => {
52-
stream.once('outbound', (data) => {
53-
resolve(data.data);
54-
});
55-
});
56-
}
57-
5841
describe('IFrameSnapExecutor', () => {
5942
before(() => {
6043
// @ts-expect-error - `globalThis.process` is not optional.
@@ -104,26 +87,6 @@ describe('IFrameSnapExecutor', () => {
10487
},
10588
});
10689

107-
const outboundRequest = await getOutboundRequest(mockStream);
108-
expect(outboundRequest.method).toBe('metamask_getProviderState');
109-
110-
writeMessage(mockStream, {
111-
name: 'jsonRpc',
112-
data: {
113-
name: 'metamask-provider',
114-
data: {
115-
jsonrpc: '2.0',
116-
id: outboundRequest.id,
117-
result: {
118-
isUnlocked: false,
119-
accounts: [],
120-
chainId: '0x1',
121-
networkVersion: '1',
122-
},
123-
},
124-
},
125-
});
126-
12790
expect(await getResponse(mockStream)).toStrictEqual({
12891
jsonrpc: '2.0',
12992
id: 2,

packages/snaps-execution-environments/src/node-process/ChildProcessSnapExecutor.test.ts

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import 'ses';
33
import { HandlerType, SNAP_STREAM_NAMES } from '@metamask/snaps-utils';
44
import { MOCK_ORIGIN, MOCK_SNAP_ID } from '@metamask/snaps-utils/test-utils';
5-
import type { Json, JsonRpcRequest, JsonRpcSuccess } from '@metamask/utils';
5+
import type { Json, JsonRpcSuccess } from '@metamask/utils';
66
import { EventEmitter } from 'stream';
77

88
import { ChildProcessSnapExecutor } from './ChildProcessSnapExecutor';
@@ -34,18 +34,6 @@ describe('ChildProcessSnapExecutor', () => {
3434
// Utility functions
3535
const emit = (data: Json) => parentEmitter.emit('message', { data });
3636
const emitChunk = (name: string, data: Json) => emit({ name, data });
37-
const waitForOutbound = (request: Partial<JsonRpcRequest<any>>): any =>
38-
new Promise((resolve) => {
39-
childEmitter.on('message', ({ data: { name, data } }) => {
40-
if (
41-
name === SNAP_STREAM_NAMES.JSON_RPC &&
42-
data.name === 'metamask-provider' &&
43-
data.data.method === request.method
44-
) {
45-
resolve(data.data);
46-
}
47-
});
48-
});
4937

5038
const waitForResponse = async (response: JsonRpcSuccess<string>) =>
5139
new Promise((resolve) => {
@@ -72,24 +60,6 @@ describe('ChildProcessSnapExecutor', () => {
7260
params: [MOCK_SNAP_ID, CODE, []],
7361
});
7462

75-
const providerRequest = await waitForOutbound({
76-
method: 'metamask_getProviderState',
77-
});
78-
79-
emitChunk(SNAP_STREAM_NAMES.JSON_RPC, {
80-
name: 'metamask-provider',
81-
data: {
82-
jsonrpc: '2.0',
83-
id: providerRequest.id,
84-
result: {
85-
isUnlocked: false,
86-
accounts: [],
87-
chainId: '0x1',
88-
networkVersion: '1',
89-
},
90-
},
91-
});
92-
9363
expect(
9464
await waitForResponse({ result: 'OK', id: 1, jsonrpc: '2.0' }),
9565
).not.toBeNull();

packages/snaps-execution-environments/src/node-thread/ThreadSnapExecutor.test.ts

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// eslint-disable-next-line import/no-unassigned-import
22
import 'ses';
33
import { SNAP_STREAM_NAMES, HandlerType } from '@metamask/snaps-utils';
4-
import type { Json, JsonRpcRequest, JsonRpcSuccess } from '@metamask/utils';
4+
import type { Json, JsonRpcSuccess } from '@metamask/utils';
55
import { EventEmitter } from 'stream';
66
import { parentPort } from 'worker_threads';
77

@@ -48,18 +48,6 @@ describe('ThreadSnapExecutor', () => {
4848
// Utility functions
4949
const emit = (data: Json) => parentEmitter.emit('message', { data });
5050
const emitChunk = (name: string, data: Json) => emit({ name, data });
51-
const waitForOutbound = (request: Partial<JsonRpcRequest<any>>): any =>
52-
new Promise((resolve) => {
53-
childEmitter.on('message', ({ data: { name, data } }) => {
54-
if (
55-
name === SNAP_STREAM_NAMES.JSON_RPC &&
56-
data.name === 'metamask-provider' &&
57-
data.data.method === request.method
58-
) {
59-
resolve(data.data);
60-
}
61-
});
62-
});
6351

6452
const waitForResponse = async (response: JsonRpcSuccess<string>) =>
6553
new Promise((resolve) => {
@@ -86,24 +74,6 @@ describe('ThreadSnapExecutor', () => {
8674
params: [FAKE_SNAP_NAME, CODE, []],
8775
});
8876

89-
const providerRequest = await waitForOutbound({
90-
method: 'metamask_getProviderState',
91-
});
92-
93-
emitChunk(SNAP_STREAM_NAMES.JSON_RPC, {
94-
name: 'metamask-provider',
95-
data: {
96-
jsonrpc: '2.0',
97-
id: providerRequest.id,
98-
result: {
99-
isUnlocked: false,
100-
accounts: [],
101-
chainId: '0x1',
102-
networkVersion: '1',
103-
},
104-
},
105-
});
106-
10777
expect(
10878
await waitForResponse({ result: 'OK', id: 1, jsonrpc: '2.0' }),
10979
).not.toBeNull();

0 commit comments

Comments
 (0)