Skip to content

Commit 8d9a914

Browse files
committed
fix: only add failover to infura monad rpc
1 parent 1551eb8 commit 8d9a914

File tree

2 files changed

+157
-10
lines changed

2 files changed

+157
-10
lines changed

app/scripts/migrations/186.test.ts

Lines changed: 111 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ describe(`migration #${VERSION}`, () => {
8585
});
8686

8787
it('does not add failover URL if QUICKNODE_MONAD_URL env variable is not set', async () => {
88+
process.env.INFURA_PROJECT_ID = 'test-infura-project-id';
89+
8890
const oldStorage = {
8991
meta: { version: oldVersion },
9092
data: {
@@ -93,8 +95,8 @@ describe(`migration #${VERSION}`, () => {
9395
[MONAD_CHAIN_ID]: {
9496
rpcEndpoints: [
9597
{
96-
type: RpcEndpointType.Custom,
97-
url: `https://monad-mainnet.infura.io/v3/`,
98+
type: RpcEndpointType.Infura,
99+
url: `https://monad-mainnet.infura.io/v3/test-infura-project-id`,
98100
},
99101
],
100102
},
@@ -114,6 +116,7 @@ describe(`migration #${VERSION}`, () => {
114116

115117
it('does not add failover URL if there is already a failover URL', async () => {
116118
process.env.QUICKNODE_MONAD_URL = QUICKNODE_MONAD_URL;
119+
process.env.INFURA_PROJECT_ID = 'test-infura-project-id';
117120

118121
const existingFailoverUrl = 'https://existing-failover.com';
119122

@@ -125,8 +128,8 @@ describe(`migration #${VERSION}`, () => {
125128
[MONAD_CHAIN_ID]: {
126129
rpcEndpoints: [
127130
{
128-
type: RpcEndpointType.Custom,
129-
url: `https://monad-mainnet.infura.io/v3/`,
131+
type: RpcEndpointType.Infura,
132+
url: `https://monad-mainnet.infura.io/v3/test-infura-project-id`,
130133
failoverUrls: [existingFailoverUrl],
131134
},
132135
],
@@ -144,8 +147,9 @@ describe(`migration #${VERSION}`, () => {
144147
expect(changedControllers.has('NetworkController')).toBe(true);
145148
});
146149

147-
it('adds QuickNode failover URL to all Monad RPC endpoints when no failover URLs exist', async () => {
150+
it('adds QuickNode failover URL to Monad Infura RPC endpoints when no failover URLs exist', async () => {
148151
process.env.QUICKNODE_MONAD_URL = QUICKNODE_MONAD_URL;
152+
process.env.INFURA_PROJECT_ID = 'test-infura-project-id';
149153

150154
const oldStorage = {
151155
meta: { version: oldVersion },
@@ -156,7 +160,7 @@ describe(`migration #${VERSION}`, () => {
156160
rpcEndpoints: [
157161
{
158162
type: RpcEndpointType.Infura,
159-
url: `https://monad-mainnet.infura.io/v3/`,
163+
url: `https://monad-mainnet.infura.io/v3/test-infura-project-id`,
160164
},
161165
{
162166
type: RpcEndpointType.Custom,
@@ -168,7 +172,7 @@ describe(`migration #${VERSION}`, () => {
168172
rpcEndpoints: [
169173
{
170174
type: RpcEndpointType.Custom,
171-
url: `https://ethereum-mainnet.infura.io/v3/`,
175+
url: `https://ethereum-mainnet.infura.io/v3/test-infura-project-id`,
172176
},
173177
],
174178
},
@@ -186,21 +190,117 @@ describe(`migration #${VERSION}`, () => {
186190
rpcEndpoints: [
187191
{
188192
type: RpcEndpointType.Infura,
189-
url: `https://monad-mainnet.infura.io/v3/`,
193+
url: `https://monad-mainnet.infura.io/v3/test-infura-project-id`,
190194
failoverUrls: [QUICKNODE_MONAD_URL],
191195
},
192196
{
193197
type: RpcEndpointType.Custom,
194198
url: `https://some-monad-rpc.com`,
195-
failoverUrls: [QUICKNODE_MONAD_URL],
199+
// Custom endpoint should NOT get failover URL
196200
},
197201
],
198202
},
199203
'0x1': {
200204
rpcEndpoints: [
201205
{
202206
type: RpcEndpointType.Custom,
203-
url: `https://ethereum-mainnet.infura.io/v3/`,
207+
url: `https://ethereum-mainnet.infura.io/v3/test-infura-project-id`,
208+
},
209+
],
210+
},
211+
},
212+
},
213+
},
214+
};
215+
216+
const versionedData = cloneDeep(oldStorage);
217+
const changedControllers = new Set<string>();
218+
await migrate(versionedData, changedControllers);
219+
220+
expect(versionedData).toStrictEqual(expectedStorage);
221+
expect(changedControllers.has('NetworkController')).toBe(true);
222+
});
223+
224+
it('adds QuickNode failover URL to Monad Infura-like endpoints (custom type with Infura URL pattern)', async () => {
225+
process.env.QUICKNODE_MONAD_URL = QUICKNODE_MONAD_URL;
226+
process.env.INFURA_PROJECT_ID = 'test-infura-project-id';
227+
228+
const oldStorage = {
229+
meta: { version: oldVersion },
230+
data: {
231+
NetworkController: {
232+
networkConfigurationsByChainId: {
233+
[MONAD_CHAIN_ID]: {
234+
rpcEndpoints: [
235+
{
236+
type: RpcEndpointType.Custom,
237+
url: `https://monad-mainnet.infura.io/v3/test-infura-project-id`,
238+
},
239+
],
240+
},
241+
},
242+
},
243+
},
244+
};
245+
246+
const expectedStorage = {
247+
meta: { version: VERSION },
248+
data: {
249+
NetworkController: {
250+
networkConfigurationsByChainId: {
251+
[MONAD_CHAIN_ID]: {
252+
rpcEndpoints: [
253+
{
254+
type: RpcEndpointType.Custom,
255+
url: `https://monad-mainnet.infura.io/v3/test-infura-project-id`,
256+
failoverUrls: [QUICKNODE_MONAD_URL],
257+
},
258+
],
259+
},
260+
},
261+
},
262+
},
263+
};
264+
265+
const versionedData = cloneDeep(oldStorage);
266+
const changedControllers = new Set<string>();
267+
await migrate(versionedData, changedControllers);
268+
269+
expect(versionedData).toStrictEqual(expectedStorage);
270+
expect(changedControllers.has('NetworkController')).toBe(true);
271+
});
272+
273+
it('does not add QuickNode failover URL to non-Infura Monad endpoints', async () => {
274+
process.env.QUICKNODE_MONAD_URL = QUICKNODE_MONAD_URL;
275+
276+
const oldStorage = {
277+
meta: { version: oldVersion },
278+
data: {
279+
NetworkController: {
280+
networkConfigurationsByChainId: {
281+
[MONAD_CHAIN_ID]: {
282+
rpcEndpoints: [
283+
{
284+
type: RpcEndpointType.Custom,
285+
url: `https://some-monad-rpc.com`,
286+
},
287+
],
288+
},
289+
},
290+
},
291+
},
292+
};
293+
294+
const expectedStorage = {
295+
meta: { version: VERSION },
296+
data: {
297+
NetworkController: {
298+
networkConfigurationsByChainId: {
299+
[MONAD_CHAIN_ID]: {
300+
rpcEndpoints: [
301+
{
302+
type: RpcEndpointType.Custom,
303+
url: `https://some-monad-rpc.com`,
204304
},
205305
],
206306
},
@@ -213,6 +313,7 @@ describe(`migration #${VERSION}`, () => {
213313
const changedControllers = new Set<string>();
214314
await migrate(versionedData, changedControllers);
215315

316+
// Custom non-Infura endpoint should NOT get failover URL
216317
expect(versionedData).toStrictEqual(expectedStorage);
217318
expect(changedControllers.has('NetworkController')).toBe(true);
218319
});

app/scripts/migrations/186.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import { RpcEndpointType } from '@metamask/network-controller';
12
import { getErrorMessage, hasProperty, Hex, isObject } from '@metamask/utils';
3+
import { escapeRegExp } from 'lodash';
24
import { captureException } from '../../../shared/lib/sentry';
35
import { CHAIN_IDS } from '../../../shared/constants/network';
46

@@ -19,6 +21,7 @@ const MONAD_CHAIN_ID: Hex = CHAIN_IDS.MONAD;
1921
*/
2022
function isValidRpcEndpoint(object: unknown): object is {
2123
url: string;
24+
type?: RpcEndpointType;
2225
failoverUrls?: string[];
2326
[key: string]: unknown;
2427
} {
@@ -33,6 +36,44 @@ function isValidRpcEndpoint(object: unknown): object is {
3336
);
3437
}
3538

39+
/**
40+
* Checks if an RPC endpoint is an Infura endpoint.
41+
*
42+
* @param rpcEndpoint - The RPC endpoint to check.
43+
* @returns True if the endpoint is an Infura endpoint.
44+
*/
45+
function isInfuraEndpoint(rpcEndpoint: {
46+
url: string;
47+
type?: RpcEndpointType;
48+
[key: string]: unknown;
49+
}): boolean {
50+
// Check if type is explicitly Infura
51+
if (rpcEndpoint.type === RpcEndpointType.Infura) {
52+
return true;
53+
}
54+
55+
// Check if URL matches Infura pattern
56+
// All featured networks that use Infura get added as custom RPC
57+
// endpoints, not Infura RPC endpoints, so we need to check the URL pattern
58+
const infuraUrlPattern = /^https:\/\/(.+?)\.infura\.io\/v3\//u;
59+
const match = rpcEndpoint.url.match(infuraUrlPattern);
60+
61+
if (!match) {
62+
return false;
63+
}
64+
65+
// If INFURA_PROJECT_ID is set, verify it matches for more precise detection
66+
if (process.env.INFURA_PROJECT_ID) {
67+
const expectedUrl = `https://${match[1]}.infura.io/v3/${escapeRegExp(
68+
process.env.INFURA_PROJECT_ID,
69+
)}`;
70+
return rpcEndpoint.url.startsWith(expectedUrl);
71+
}
72+
73+
// If INFURA_PROJECT_ID is not set, just check if it matches the Infura pattern
74+
return true;
75+
}
76+
3677
/**
3778
* Type guard to validate if an object has a valid network configuration with rpcEndpoints.
3879
*
@@ -147,6 +188,11 @@ function transformState(
147188
return rpcEndpoint;
148189
}
149190

191+
// Only add failover URL to Infura endpoints
192+
if (!isInfuraEndpoint(rpcEndpoint)) {
193+
return rpcEndpoint;
194+
}
195+
150196
// Add QuickNode failover URL
151197
const quickNodeUrl = process.env.QUICKNODE_MONAD_URL;
152198
if (quickNodeUrl) {

0 commit comments

Comments
 (0)