Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.

Add RPC provider: Infura #7286

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions packages/web3-rpc-providers/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { QuickNodeProvider } from './web3_provider_quicknode.js';

export * from './types.js';
export * from './web3_provider_quicknode.js';
export * from './web3_provider_infura.js';
export * from './web3_provider.js';
export * from './errors.js';

Expand Down
33 changes: 32 additions & 1 deletion packages/web3-rpc-providers/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,56 @@ export enum Transport {

export enum Network {
ETH_MAINNET = 'eth_mainnet',
ETH_GOERLI = 'eth_goerli',
ETH_SEPOLIA = 'eth_sepolia',
ETH_GOERLI = 'eth_goerli',
ETH_HOLESKY = 'eth_holesky',

PALM_MAINNET = 'palm_mainnet',
PALM_TESTNET = 'palm_testnet',

BLAST_MAINNET = 'blast_mainnet',
BLAST_SEPOLIA = 'blast_sepolia',

STARKNET_MAINNET = 'starknet_mainnet',
STARKNET_SEPOLIA = 'starknet_sepolia',

ZKSYNC_MAINNET = 'zksync_mainnet',
ZKSYNC_SEPOLIA = 'zksync_sepolia',

CELO_MAINNET = 'celo_mainnet',
CELO_ALFAJORES = 'celo_alfajores',

AVALANCHE_MAINNET = 'avalanche_mainnet',
AVALANCHE_FUJI = 'avalanche_fuji',

POLYGON_MAINNET = 'polygon_mainnet',
POLYGON_MUMBAI = 'polygon_mumbai',
POLYGON_AMONY = 'polygon_amony',

ARBITRUM_MAINNET = 'arbitrum_mainnet',
ARBITRUM_SEPOLIA = 'arbitrum_sepolia',
ARBITRUM_GOERLI = 'arbitrum_goerli',

BASE_MAINNET = 'base_mainnet',
BASE_SEPOLIA = 'base_sepolia',
BASE_GOERLI = 'base_foerli',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
BASE_GOERLI = 'base_foerli',
BASE_GOERLI = 'base_goerli',


OPTIMISM_MAINNET = 'optimism_mainnet',
OPTIMISM_SEPOLIA = 'optimism_sepolia',
OPTIMISM_GOERLI = 'optimism_goerli',

BNB_MAINNET = 'bnb_mainnet',
BNB_TESTNET = 'bnb_testnet',

BSC_MAINNET = 'bsc_mainnet',
BSC_TESTNET = 'bsc_testnet',

MANTLE_MAINNET = 'mantle_mainnet',
MANTLE_SEPOLIA = 'mantle_sepolia',

LINEA_MAINNET = 'linea_mainnet',
LINEA_SEPOLIA = 'linea_sepolia',
LINEA_GOERLI = 'linea_goerli',
}

// Combining the ws types
Expand Down
169 changes: 169 additions & 0 deletions packages/web3-rpc-providers/src/web3_provider_infura.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/*
This file is part of web3.js.

web3.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

web3.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/

import {
EthExecutionAPI,
JsonRpcResponseWithResult,
Web3APIMethod,
Web3APIPayload,
Web3APIReturnType,
Web3APISpec,
} from 'web3-types';
import { ResponseError } from 'web3-errors';
import { HttpProviderOptions } from 'web3-providers-http';
import { Transport, Network, SocketOptions } from './types.js';
import { Web3ExternalProvider } from './web3_provider.js';
import { QuickNodeRateLimitError } from './errors.js';

const isValid = (str: string) => str !== undefined && str.trim().length > 0;

export class InfuraProvider<
API extends Web3APISpec = EthExecutionAPI,
> extends Web3ExternalProvider {
// eslint-disable-next-line default-param-last
public constructor(
network: Network = Network.ETH_MAINNET,
transport: Transport = Transport.HTTPS,
token = '',
host = '',
providerConfigOptions?: HttpProviderOptions | SocketOptions,
) {
super(network, transport, token, host, providerConfigOptions);
}

public async request<
Method extends Web3APIMethod<API>,
ResultType = Web3APIReturnType<API, Method>,
>(
payload: Web3APIPayload<EthExecutionAPI, Method>,
requestOptions?: RequestInit,
): Promise<JsonRpcResponseWithResult<ResultType>> {
try {
return await super.request(payload, requestOptions);
} catch (error) {
if (error instanceof ResponseError && error.statusCode === 429) {
throw new QuickNodeRateLimitError(error);
}
throw error;
}
}

// eslint-disable-next-line class-methods-use-this
public getRPCURL(network: Network, transport: Transport, token: string, _host: string) {
let host = '';

switch (network) {
case Network.PALM_MAINNET:
host = isValid(_host) ? _host : 'palm-mainnet.infura.io';
break;
case Network.PALM_TESTNET:
host = isValid(_host) ? _host : 'palm-testnet.infura.io';
break;
case Network.BLAST_MAINNET:
host = isValid(_host) ? _host : 'blast-mainnet.infura.io';
break;
case Network.BLAST_SEPOLIA:
host = isValid(_host) ? _host : 'blast-sepolia.infura.io';
break;
case Network.AVALANCHE_MAINNET:
host = isValid(_host) ? _host : 'avalanche-mainnet.infura.io';
break;
case Network.AVALANCHE_FUJI:
host = isValid(_host) ? _host : 'avalanche-fuji.infura.io';
break;
case Network.STARKNET_MAINNET:
host = isValid(_host) ? _host : 'starknet-mainnet.infura.io';
break;
case Network.STARKNET_SEPOLIA:
host = isValid(_host) ? _host : 'starknet-sepolia.infura.io';
break;
case Network.ZKSYNC_MAINNET:
host = isValid(_host) ? _host : 'zksync-mainnet.infura.io';
break;
case Network.ZKSYNC_SEPOLIA:
host = isValid(_host) ? _host : 'zksync-sepolia.infura.io';
break;
case Network.CELO_MAINNET:
host = isValid(_host) ? _host : 'celo-mainnet.infura.io';
break;
case Network.CELO_ALFAJORES:
host = isValid(_host) ? _host : 'celo-alfajores.infura.io';
break;
case Network.BSC_MAINNET:
host = isValid(_host) ? _host : 'bsc-mainnet.infura.io';
break;
case Network.BSC_TESTNET:
host = isValid(_host) ? _host : 'bsc-testnet.infura.io';
break;
case Network.MANTLE_MAINNET:
host = isValid(_host) ? _host : 'mantle-mainnet.infura.io';
break;
case Network.MANTLE_SEPOLIA:
host = isValid(_host) ? _host : 'mantle-sepolia.infura.io';
break;
case Network.ETH_MAINNET:
host = isValid(_host) ? _host : 'mainnet.infura.io';
break;
case Network.ETH_HOLESKY:
host = isValid(_host) ? _host : 'holesky.infura.io';
break;
case Network.ETH_SEPOLIA:
host = isValid(_host) ? _host : 'sepolia.infura.io';
break;
case Network.ARBITRUM_MAINNET:
host = isValid(_host) ? _host : 'arbitrum-mainnet.infura.io';
break;
case Network.ARBITRUM_SEPOLIA:
host = isValid(_host) ? _host : 'arbitrum-sepolia.infura.io';
break;
case Network.BASE_MAINNET:
host = isValid(_host) ? _host : 'base-mainnet.infura.io';
break;
case Network.BASE_SEPOLIA:
host = isValid(_host) ? _host : 'base-sepolia.infura.io';
break;
case Network.BNB_MAINNET:
host = isValid(_host) ? _host : 'opbnb-mainnet.infura.io';
break;
case Network.BNB_TESTNET:
host = isValid(_host) ? _host : 'opbnb-testnet.infura.io';
break;
case Network.LINEA_MAINNET:
host = isValid(_host) ? _host : 'linea-mainnet.infura.io';
break;
case Network.LINEA_SEPOLIA:
host = isValid(_host) ? _host : 'linea-sepolia.infura.io';
break;
case Network.POLYGON_MAINNET:
host = isValid(_host) ? _host : 'polygon-mainnet.infura.io';
break;
case Network.POLYGON_AMONY:
host = isValid(_host) ? _host : 'polygon-amoy.infura.io';
break;
case Network.OPTIMISM_MAINNET:
host = isValid(_host) ? _host : 'optimism-mainnet.infura.io';
break;
case Network.OPTIMISM_SEPOLIA:
host = isValid(_host) ? _host : 'optimism-sepolia.infura.io';
break;
default:
throw new Error('Network info not avalible.');
}

return `${transport}://${host}/v3/${token}`;
}
}
43 changes: 42 additions & 1 deletion packages/web3-rpc-providers/test/unit/request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { Network, Transport } from '../../src/types';
import { Web3ExternalProvider } from '../../src/web3_provider';
import { QuickNodeRateLimitError } from '../../src/errors';
import { QuickNodeProvider } from '../../src/web3_provider_quicknode';
import { InfuraProvider } from '../../src/web3_provider_infura';

jest.mock('web3-providers-ws', () => {
return {
Expand Down Expand Up @@ -82,7 +83,7 @@ describe('Web3ExternalProvider', () => {
expect(result).toEqual({ result: 'mock-result' });
});

it('should throw a rate limiting error when status code is 429', async () => {
it('QuickNodeProvider: should throw a rate limiting error when status code is 429', async () => {
const network: Network = Network.ETH_MAINNET;
const transport: Transport = Transport.HTTPS;
const token = 'your-token';
Expand Down Expand Up @@ -116,6 +117,46 @@ describe('Web3ExternalProvider', () => {
const provider = new QuickNodeProvider(network, transport, token);
(provider as any).provider = mockHttpProvider;

const payload: Web3APIPayload<EthExecutionAPI, Web3APIMethod<EthExecutionAPI>> = {
method: 'eth_getBalance',
params: ['0x0123456789012345678901234567890123456789', 'latest'],
};
await expect(provider.request(payload)).rejects.toThrow(QuickNodeRateLimitError);
});
it('InfuraProvider: should throw a rate limiting error when status code is 429', async () => {
const network: Network = Network.ETH_MAINNET;
const transport: Transport = Transport.HTTPS;
const token = 'your-token';

const mockHttpProvider = {
request: jest.fn(),
};

// Create a mock ResponseError with status code 429
// Create a mock JsonRpcResponse to pass to ResponseError
const mockJsonRpcResponse: JsonRpcResponse = {
jsonrpc: '2.0',
id: '458408f4-7e2c-43f1-b61d-1fe09a9ee25a',
error: {
code: 429,
message: 'Rate limit exceeded',
},
};

// Create a mock ResponseError with status code 429
const mockError = new ResponseError(
mockJsonRpcResponse,
undefined,
undefined, // request can be undefined
429, // statusCode
);

// Mock the request method to throw the ResponseError
mockHttpProvider.request.mockRejectedValue(mockError);

const provider = new InfuraProvider(network, transport, token);
(provider as any).provider = mockHttpProvider;

const payload: Web3APIPayload<EthExecutionAPI, Web3APIMethod<EthExecutionAPI>> = {
method: 'eth_getBalance',
params: ['0x0123456789012345678901234567890123456789', 'latest'],
Expand Down

This file was deleted.

Loading
Loading