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 6 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
83 changes: 83 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,83 @@
/*
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, Web3APISpec } from 'web3-types';
import { HttpProviderOptions } from 'web3-providers-http';
import { Network, SocketOptions, Transport } from './types.js';
import { Web3ExternalProvider } from './web3_provider.js';

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

export class InfuraProvider<
API extends Web3APISpec = EthExecutionAPI,
> extends Web3ExternalProvider<API> {
// 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 static readonly networkHostMap: { [key: string]: string } = {
[Network.PALM_MAINNET]: 'palm-mainnet.infura.io',
[Network.PALM_TESTNET]: 'palm-testnet.infura.io',
[Network.BLAST_MAINNET]: 'blast-mainnet.infura.io',
[Network.BLAST_SEPOLIA]: 'blast-sepolia.infura.io',
[Network.AVALANCHE_MAINNET]: 'avalanche-mainnet.infura.io',
[Network.AVALANCHE_FUJI]: 'avalanche-fuji.infura.io',
[Network.STARKNET_MAINNET]: 'starknet-mainnet.infura.io',
[Network.STARKNET_SEPOLIA]: 'starknet-sepolia.infura.io',
[Network.ZKSYNC_MAINNET]: 'zksync-mainnet.infura.io',
[Network.ZKSYNC_SEPOLIA]: 'zksync-sepolia.infura.io',
[Network.CELO_MAINNET]: 'celo-mainnet.infura.io',
[Network.CELO_ALFAJORES]: 'celo-alfajores.infura.io',
[Network.BSC_MAINNET]: 'bsc-mainnet.infura.io',
[Network.BSC_TESTNET]: 'bsc-testnet.infura.io',
[Network.MANTLE_MAINNET]: 'mantle-mainnet.infura.io',
[Network.MANTLE_SEPOLIA]: 'mantle-sepolia.infura.io',
[Network.ETH_MAINNET]: 'mainnet.infura.io',
[Network.ETH_HOLESKY]: 'holesky.infura.io',
[Network.ETH_SEPOLIA]: 'sepolia.infura.io',
[Network.ARBITRUM_MAINNET]: 'arbitrum-mainnet.infura.io',
[Network.ARBITRUM_SEPOLIA]: 'arbitrum-sepolia.infura.io',
[Network.BASE_MAINNET]: 'base-mainnet.infura.io',
[Network.BASE_SEPOLIA]: 'base-sepolia.infura.io',
[Network.BNB_MAINNET]: 'opbnb-mainnet.infura.io',
[Network.BNB_TESTNET]: 'opbnb-testnet.infura.io',
[Network.LINEA_MAINNET]: 'linea-mainnet.infura.io',
[Network.LINEA_SEPOLIA]: 'linea-sepolia.infura.io',
[Network.POLYGON_MAINNET]: 'polygon-mainnet.infura.io',
[Network.POLYGON_AMONY]: 'polygon-amoy.infura.io',
[Network.OPTIMISM_MAINNET]: 'optimism-mainnet.infura.io',
[Network.OPTIMISM_SEPOLIA]: 'optimism-sepolia.infura.io',
};
// eslint-disable-next-line class-methods-use-this
public getRPCURL(network: Network, transport: Transport, token: string, _host: string) {
const defaultHost = InfuraProvider.networkHostMap[network];
if (!defaultHost) {
throw new Error('Network info not avalible.');
}
const host = isValid(_host) ? _host : defaultHost;

return `${transport}://${host}/${
transport === Transport.WebSocket ? 'ws/' : ''
}v3/${token}`;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { Web3ExternalProvider } from '../../src/web3_provider';
import { Network, SocketOptions, Transport } from '../../src/types';
import { ProviderConfigOptionsError } from '../../src/errors';

// Mock implementation so ws doesnt have openhandle after test exits as it attempts to connects at start
// Mock implementation so ws doesnt have openhandle after test exits as it attempts to connect at start
jest.mock('isomorphic-ws', () => {
return {
__esModule: true,
Expand Down
2 changes: 1 addition & 1 deletion packages/web3-rpc-providers/test/unit/request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,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

This file was deleted.

87 changes: 84 additions & 3 deletions packages/web3/test/integration/web3RPCProviders.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ 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 { mainnet, Network, QuickNodeProvider, Transport } from 'web3-rpc-providers';
import { mainnet, Network, QuickNodeProvider, InfuraProvider, Transport } from 'web3-rpc-providers';
import { Web3 } from '../../src/index';

jest.setTimeout(10000);
describe('Web3 RPC Provider Integration tests', () => {
const transports = Object.values(Transport);
const networks = [
const quickNodeNetworks = [
Network.ETH_MAINNET,
Network.ETH_HOLESKY,
Network.ETH_SEPOLIA,
Expand All @@ -33,7 +34,7 @@ describe('Web3 RPC Provider Integration tests', () => {
];

transports.forEach(transport => {
networks.forEach(network => {
quickNodeNetworks.forEach(network => {
it(`QuickNodeProvider should work with ${transport} transport and ${network} network`, async () => {
const provider = new QuickNodeProvider(network, transport);
const web3 = new Web3(provider);
Expand All @@ -48,6 +49,86 @@ describe('Web3 RPC Provider Integration tests', () => {
});
});
});

const infuraNetworks = [
Network.PALM_MAINNET,
Network.PALM_TESTNET,
Network.BLAST_MAINNET,
Network.BLAST_SEPOLIA,
Network.AVALANCHE_MAINNET,
Network.AVALANCHE_FUJI,
Network.STARKNET_MAINNET,
Network.STARKNET_SEPOLIA,
Network.ZKSYNC_MAINNET,
Network.ZKSYNC_SEPOLIA,
Network.CELO_MAINNET,
Network.CELO_ALFAJORES,
Network.BSC_MAINNET,
Network.BSC_TESTNET,
Network.MANTLE_MAINNET,
Network.MANTLE_SEPOLIA,
Network.ETH_MAINNET,
Network.ETH_HOLESKY,
Network.ETH_SEPOLIA,
Network.ARBITRUM_MAINNET,
Network.ARBITRUM_SEPOLIA,
Network.BASE_MAINNET,
Network.BASE_SEPOLIA,
Network.BNB_MAINNET,
Network.BNB_TESTNET,
Network.LINEA_MAINNET,
Network.LINEA_SEPOLIA,
Network.POLYGON_MAINNET,
Network.POLYGON_AMONY,
Network.OPTIMISM_MAINNET,
Network.OPTIMISM_SEPOLIA,
];
transports.forEach(transport => {
infuraNetworks.forEach(network => {
// skip not exists endpoints
if (
!(
[
Network.PALM_MAINNET,
Network.PALM_TESTNET,
Network.BLAST_SEPOLIA,
Network.STARKNET_MAINNET,
Network.STARKNET_SEPOLIA,
Network.ZKSYNC_SEPOLIA,
Network.BSC_TESTNET,
Network.MANTLE_SEPOLIA,
Network.BNB_TESTNET,
].includes(network) && transport === Transport.WebSocket
)
) {
it.skip(`InfuraProvider should work with ${transport} transport and ${network} network`, async () => {
const provider = new InfuraProvider(
network,
transport,
process.env.INFURA_PROVIDER_KEY,
);

const web3 = new Web3(provider);
const result =
network === Network.STARKNET_MAINNET || network === Network.STARKNET_SEPOLIA
? BigInt(
await web3.requestManager.send({
method: 'starknet_blockNumber',
params: [],
}),
)
: await web3.eth.getBlockNumber();

expect(typeof result).toBe('bigint');
expect(result > 0).toBe(true);

if (transport === Transport.WebSocket) {
web3.provider?.disconnect();
}
});
}
});
});
it(`should work with mainnet provider`, async () => {
const web3 = new Web3(mainnet);
const result = await web3.eth.getBlockNumber();
Expand Down
Loading