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

Commit 2ef694c

Browse files
authored
Web3 RPC Providers support of configuration of selected transport (#7205)
* SocketOptions type * ProviderConfigOptionsError * providerConfigOptions * tests * changelog
1 parent d9d0391 commit 2ef694c

File tree

6 files changed

+132
-27
lines changed

6 files changed

+132
-27
lines changed

packages/web3-rpc-providers/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5555

5656
### Added
5757

58-
- Updated rate limit error of QuickNode provider for HTTP transport
58+
- Updated rate limit error of QuickNode provider for HTTP transport
59+
- Added optional `HttpProviderOptions | SocketOptions` in `Web3ExternalProvider` and `QuickNodeProvider` for provider configs

packages/web3-rpc-providers/src/errors.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ You should have received a copy of the GNU Lesser General Public License
1515
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
1616
*/
1717

18+
/* eslint-disable max-classes-per-file */
19+
1820
import { BaseWeb3Error } from 'web3-errors';
1921

2022
const ERR_QUICK_NODE_RATE_LIMIT = 1300;
@@ -24,4 +26,14 @@ export class QuickNodeRateLimitError extends BaseWeb3Error {
2426
public constructor(error?: Error) {
2527
super(`You've reach the rate limit of free RPC calls from our Partner Quick Nodes. There are two options you can either create a paid Quick Nodes account and get 20% off for 2 months using WEB3JS referral code, or use Free public RPC endpoint.`, error);
2628
}
27-
}
29+
}
30+
31+
const ERR_PROVIDER_CONFIG_OPTIONS = 1301;
32+
export class ProviderConfigOptionsError extends BaseWeb3Error {
33+
public code = ERR_PROVIDER_CONFIG_OPTIONS;
34+
35+
public constructor(msg: string) {
36+
super(`Invalid provider config options given for ${msg}`);
37+
}
38+
}
39+
/* eslint-enable max-classes-per-file */

packages/web3-rpc-providers/src/types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ You should have received a copy of the GNU Lesser General Public License
1515
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
1616
*/
1717

18+
import {ClientOptions, ClientRequestArgs} from "web3-providers-ws";
19+
import { ReconnectOptions } from 'web3-utils';
20+
1821
export enum Transport {
1922
HTTPS = "https",
2023
WebSocket = "wss"
@@ -41,4 +44,10 @@ export enum Network {
4144

4245
BNB_MAINNET = "bnb_mainnet",
4346
BNB_TESTNET = "bnb_testnet"
47+
};
48+
49+
// Combining the ws types
50+
export type SocketOptions = {
51+
socketOptions?: ClientOptions | ClientRequestArgs;
52+
reconnectOptions?: Partial<ReconnectOptions>;
4453
};

packages/web3-rpc-providers/src/web3_provider.ts

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ You should have received a copy of the GNU Lesser General Public License
1515
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
1616
*/
1717

18-
import HttpProvider from "web3-providers-http";
18+
import HttpProvider, { HttpProviderOptions } from "web3-providers-http";
1919
import WebSocketProvider from "web3-providers-ws";
2020
import {
2121
EthExecutionAPI, JsonRpcResult, ProviderConnectInfo, ProviderMessage,
@@ -27,7 +27,8 @@ import {
2727
JsonRpcResponseWithResult,
2828
} from "web3-types";
2929
import { Eip1193Provider } from "web3-utils";
30-
import { Transport, Network } from "./types.js";
30+
import { Transport, Network, SocketOptions } from "./types.js";
31+
import { ProviderConfigOptionsError } from "./errors.js";
3132

3233
/*
3334
This class can be used to create new providers only when there is custom logic required in each Request method like
@@ -50,16 +51,36 @@ export abstract class Web3ExternalProvider<
5051
network: Network,
5152
transport: Transport,
5253
token: string,
53-
host: string) {
54+
host: string,
55+
providerConfigOptions?: HttpProviderOptions | SocketOptions) {
5456

5557
super();
5658

59+
if(providerConfigOptions!== undefined &&
60+
transport === Transport.HTTPS &&
61+
!('providerOptions' in providerConfigOptions)){
62+
63+
throw new ProviderConfigOptionsError("HTTP Provider");
64+
}
65+
else if(providerConfigOptions!== undefined &&
66+
transport === Transport.WebSocket &&
67+
!( 'socketOptions' in providerConfigOptions ||
68+
'reconnectOptions' in providerConfigOptions
69+
)){
70+
throw new ProviderConfigOptionsError("Websocket Provider");
71+
}
72+
5773
this.transport = transport;
5874
if (transport === Transport.HTTPS) {
59-
this.provider = new HttpProvider(this.getRPCURL(network, transport, token, host));
75+
this.provider = new HttpProvider(
76+
this.getRPCURL(network, transport, token, host),
77+
providerConfigOptions as HttpProviderOptions);
6078
}
6179
else if (transport === Transport.WebSocket) {
62-
this.provider = new WebSocketProvider(this.getRPCURL(network, transport, token, host));
80+
this.provider = new WebSocketProvider(
81+
this.getRPCURL(network, transport, token, host),
82+
(providerConfigOptions as SocketOptions)?.socketOptions,
83+
(providerConfigOptions as SocketOptions)?.reconnectOptions);
6384
}
6485
}
6586

@@ -133,4 +154,5 @@ export abstract class Web3ExternalProvider<
133154
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
134155
this.provider.removeListener(_type as any, _listener as any);
135156
}
136-
}
157+
}
158+

packages/web3-rpc-providers/src/web3_provider_quicknode.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ along with web3.js. If not, see <http://www.gnu.org/licenses/>.
1717

1818
import { EthExecutionAPI, JsonRpcResponseWithResult, Web3APIMethod, Web3APIPayload, Web3APIReturnType, Web3APISpec } from "web3-types";
1919
import { ResponseError } from "web3-errors";
20-
import { Transport, Network } from "./types.js";
20+
import { HttpProviderOptions } from "web3-providers-http";
21+
import { Transport, Network, SocketOptions } from "./types.js";
2122
import { Web3ExternalProvider } from "./web3_provider.js";
2223
import { QuickNodeRateLimitError } from "./errors.js";
2324

@@ -27,13 +28,10 @@ export class QuickNodeProvider<
2728
API extends Web3APISpec = EthExecutionAPI,
2829
> extends Web3ExternalProvider {
2930

30-
public constructor(
31-
network: Network = Network.ETH_MAINNET,
32-
transport: Transport = Transport.HTTPS,
33-
token = "",
34-
host = "") {
31+
// eslint-disable-next-line default-param-last
32+
public constructor( network: Network = Network.ETH_MAINNET, transport: Transport = Transport.HTTPS, token = "", host = "", providerConfigOptions?: HttpProviderOptions | SocketOptions) {
3533

36-
super(network, transport, token, host);
34+
super(network, transport, token, host, providerConfigOptions);
3735

3836
}
3937

packages/web3-rpc-providers/test/unit/constructor.test.ts

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ along with web3.js. If not, see <http://www.gnu.org/licenses/>.
1616
*/
1717

1818

19-
import HttpProvider from 'web3-providers-http';
19+
import HttpProvider, { HttpProviderOptions } from 'web3-providers-http';
2020
import WebSocketProvider from 'web3-providers-ws';
2121
import WebSocket from 'isomorphic-ws';
2222

2323
import { Web3ExternalProvider } from '../../src/web3_provider';
24-
import { Network, Transport } from '../../src/types';
24+
import { Network, SocketOptions, Transport } from '../../src/types';
25+
import { ProviderConfigOptionsError } from '../../src/errors';
2526

2627
// Mock implementation so ws doesnt have openhandle after test exits as it attempts to connects at start
2728
jest.mock('isomorphic-ws', () => {
@@ -60,11 +61,11 @@ jest.mock('isomorphic-ws', () => {
6061
});
6162

6263
class MockWeb3ExternalProviderA extends Web3ExternalProvider {
63-
public constructor(network: Network, transport: Transport, token: string){
64-
super(network, transport, token, "");
64+
public constructor(network: Network, transport: Transport, token: string, host?: string, providerConfigOptions?: HttpProviderOptions | SocketOptions) {
65+
super(network, transport, token, host ?? "", providerConfigOptions);
6566
}
6667
// eslint-disable-next-line class-methods-use-this
67-
public getRPCURL(_network: Network, _transport: Transport, _token: string, _host=""): string {
68+
public getRPCURL(_network: Network, _transport: Transport, _token: string, _host = ""): string {
6869
let transport = "";
6970
if (_transport === Transport.HTTPS)
7071
transport = "http://";
@@ -76,23 +77,85 @@ class MockWeb3ExternalProviderA extends Web3ExternalProvider {
7677
}
7778

7879
describe('Web3ExternalProvider', () => {
80+
const network: Network = Network.ETH_MAINNET;
81+
const transport: Transport = Transport.HTTPS;
82+
const token = 'test-token';
83+
const host = 'test-host';
84+
7985
it('should initialize the provider correctly', () => {
80-
const network: Network = Network.ETH_MAINNET;
81-
const transport: Transport = Transport.HTTPS;
82-
const token = 'your-token';
8386

8487
const provider = new MockWeb3ExternalProviderA(network, transport, token);
8588

8689
expect(provider.provider).toBeInstanceOf(HttpProvider);
8790
});
8891

8992
it('should initialize the provider with WebSocketProvider for WebSocket transport', () => {
90-
const network: Network = Network.ETH_MAINNET;
91-
const transport: Transport = Transport.WebSocket;
92-
const token = 'your-token';
93+
const transport1: Transport = Transport.WebSocket;
9394

94-
const provider = new MockWeb3ExternalProviderA(network, transport, token);
95+
const provider = new MockWeb3ExternalProviderA(network, transport1, token);
9596
expect(provider.provider).toBeInstanceOf(WebSocketProvider);
9697
});
9798

99+
it('should throw ProviderConfigOptionsError for HTTP provider with missing providerOptions', () => {
100+
const providerConfigOptions: HttpProviderOptions | SocketOptions = { /* missing providerOptions */ };
101+
expect(() => new MockWeb3ExternalProviderA(network, transport, token, host, providerConfigOptions)).toThrow(ProviderConfigOptionsError);
102+
});
103+
104+
it('should throw ProviderConfigOptionsError for HTTP provider with WS providerOptions', () => {
105+
const providerConfigOptions: SocketOptions = {
106+
socketOptions: { /* options */ },
107+
reconnectOptions: { /* options */ },
108+
};
109+
expect(() => new MockWeb3ExternalProviderA(network, transport, token, host, providerConfigOptions)).toThrow(ProviderConfigOptionsError);
110+
});
111+
112+
it('should throw ProviderConfigOptionsError for WebSocket provider with missing socketOptions and reconnectOptions', () => {
113+
const providerConfigOptions: HttpProviderOptions | SocketOptions = { /* missing socketOptions and reconnectOptions */ };
114+
expect(() => new MockWeb3ExternalProviderA(network, Transport.WebSocket, token, host, providerConfigOptions)).toThrow(ProviderConfigOptionsError);
115+
});
116+
117+
it('should throw ProviderConfigOptionsError for WebSocket provider with HTTP options', () => {
118+
const providerConfigOptions: HttpProviderOptions = { providerOptions: { /* options */ } };
119+
expect(() => new MockWeb3ExternalProviderA(network, Transport.WebSocket, token, host, providerConfigOptions)).toThrow(ProviderConfigOptionsError);
120+
});
121+
122+
it('should create provider instance and not throw ProviderConfigOptionsError for WebSocket provider with missing reconnectOptions', () => {
123+
const providerConfigOptions: SocketOptions = {
124+
socketOptions: { /* options */ },
125+
};
126+
127+
// Create an instance of the MockWeb3ExternalProviderA
128+
const provider = new MockWeb3ExternalProviderA(network, Transport.WebSocket, token, host, providerConfigOptions);
129+
130+
// Expect that the provider is created successfully
131+
expect(provider).toBeInstanceOf(MockWeb3ExternalProviderA);
132+
});
133+
134+
it('should create provider instance and not throw ProviderConfigOptionsError for WebSocket provider with missing socketOptions', () => {
135+
const providerConfigOptions: SocketOptions = {
136+
reconnectOptions: { /* options */ },
137+
};
138+
139+
// Create an instance of the MockWeb3ExternalProviderA
140+
const provider = new MockWeb3ExternalProviderA(network, Transport.WebSocket, token, host, providerConfigOptions);
141+
142+
// Expect that the provider is created successfully
143+
expect(provider).toBeInstanceOf(MockWeb3ExternalProviderA);
144+
});
145+
146+
it('should create an HttpProvider with providerOptions', () => {
147+
const providerConfigOptions: HttpProviderOptions = { providerOptions: { /* options */ } };
148+
const provider = new MockWeb3ExternalProviderA(network, transport, token, host, providerConfigOptions);
149+
expect(provider.provider).toBeInstanceOf(HttpProvider);
150+
});
151+
152+
it('should create a WebSocketProvider with socketOptions and reconnectOptions', () => {
153+
const providerConfigOptions: SocketOptions = {
154+
socketOptions: { /* options */ },
155+
reconnectOptions: { /* options */ },
156+
};
157+
const provider = new MockWeb3ExternalProviderA(network, Transport.WebSocket, token, host, providerConfigOptions);
158+
expect(provider.provider).toBeInstanceOf(WebSocketProvider);
159+
});
98160
});
161+

0 commit comments

Comments
 (0)