Skip to content

Commit

Permalink
Add documentation for catching provider events (#5886)
Browse files Browse the repository at this point in the history
* show Ipc and WebSocket providers in the documentation

* add guides for providers and their events

* move the generic section of the providers guide from the migration guide

* edit some texts in the guides
  • Loading branch information
Muhammad-Altabba authored Mar 6, 2023
1 parent 69768a4 commit 2332c5f
Show file tree
Hide file tree
Showing 8 changed files with 319 additions and 94 deletions.
124 changes: 38 additions & 86 deletions docs/docs/guides/web3_migration_guide/providers_migration_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,99 +4,32 @@ sidebar_position: 2
sidebar_label: web3.providers
---

There are multiple ways to set the provider.
For full description about the providers, their priorities and their types, you can check [web3.js Providers Guide](/docs/guides/web3_providers_guide/).

```ts title='Setting a provider'
web3.setProvider(myProvider);
web3.eth.setProvider(myProvider);
web3.Contract.setProvider(myProvider);
contractInstance.setProvider(myProvider);
```

The key rule for setting provider is as follows:

1. Any provider set on the higher level will be applied to all lower levels. e.g. Any provider set using `web3.setProvider` will also be applied to `web3.eth` object.
2. For contracts `web3.Contract.setProvider` can be used to set provider for **all instances** of contracts created by `web3.eth.Contract`.

:::tip
A provider can be either type `string` or [`SupportedProviders`](/api/web3-core#SupportedProviders).
:::

## Examples

### Local Geth Node

```ts
const Web3 = require('web3');
const web3 = new Web3('http://localhost:8545');
// or
const web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'));

// change provider
web3.setProvider('ws://localhost:8546');
// or
web3.setProvider(new Web3.providers.WebsocketProvider('ws://localhost:8546'));

// Using the IPC provider in node.js
const net = require('net');
const web3 = new Web3('/Users/myuser/Library/Ethereum/geth.ipc', net); // mac os path
// or
const web3 = new Web3(
new Web3.providers.IpcProvider('/Users/myuser/Library/Ethereum/geth.ipc', net),
); // mac os path
// on windows the path is: "\\\\.\\pipe\\geth.ipc"
// on linux the path is: "/users/myuser/.ethereum/geth.ipc"
```
### Provider Options Changes

### Remote Node Provider

```ts
// Using a remote node provider, like Alchemy (https://www.alchemyapi.io/supernode), is simple.
const Web3 = require('web3');
const web3 = new Web3('https://eth-mainnet.alchemyapi.io/v2/your-api-key');
```

### Injected providers

The Injected provider should be in compliance with [EIP1193](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1193.md).

The web3.js 4.x Provider specifications are defined in [web3 base provider](https://github.com/ChainSafe/web3.js/blob/4.x/packages/web3-types/src/web3_base_provider.ts) for Injected Providers.

```ts
const Web3 = require('web3');
// Using an EIP1193 provider like MetaMask can be injected

if (window.ethereum) {
// Check if ethereum object exists
await window.ethereum.request();
window.web3 = new Web3(window.ethereum); // inject provider
}
```

### Provider Options

There are differences in the objects that could be passed in the Provider constructors.
There are differences in the objects that could be passed in the Provider constructors between version 1.x and 4.x. Below, you will find the difference for every Provider object type.

#### HttpProvider

In 1.x, options passed in the constructor should be of type [`HttpProviderOptions`](https://github.com/web3/web3.js/blob/1.x/packages/web3-core-helpers/types/index.d.ts#L173). The `HttpProviderOptions` interface consists of:

```ts
export interface HttpProviderOptions {
interface HttpProviderOptions {
keepAlive?: boolean;
timeout?: number;
headers?: HttpHeader[];
withCredentials?: boolean;
agent?: HttpAgent;
}

export interface HttpAgent {
interface HttpAgent {
http?: http.Agent;
https?: https.Agent;
baseUrl?: string;
}

export interface HttpHeader {
interface HttpHeader {
name: string;
value: string;
}
Expand Down Expand Up @@ -147,12 +80,12 @@ let httpOptions = {
};
```

#### WebsocketProvider
#### WebSocketProvider

In 1.x, options passed in the constructor should be of type [`WebsocketProviderOptions`](https://github.com/web3/web3.js/blob/1.x/packages/web3-core-helpers/types/index.d.ts#L192). The `WebsocketProviderOptions` interface consists of:

```ts
export interface WebsocketProviderOptions {
interface WebsocketProviderOptions {
host?: string;
timeout?: number;
reconnectDelay?: number;
Expand All @@ -164,30 +97,29 @@ export interface WebsocketProviderOptions {
reconnect?: ReconnectOptions;
}

export interface ReconnectOptions {
interface ReconnectOptions {
auto?: boolean;
delay?: number;
maxAttempts?: number;
onTimeout?: boolean;
}
```

In 4.x, the options object is of type `ClientRequestArgs` or of `ClientOptions`. See
Regarding `RequestInit` see [here](https://microsoft.github.io/PowerBI-JavaScript/interfaces/_node_modules__types_node_http_d_._http_.clientrequestargs.html) for `ClientRequestArgs` and [here](https://github.com/websockets/ws) for `ClientOptions`.

In 4.x a second option parameter can be given regarding reconnecting.
In 4.x, the options object is of type `ClientRequestArgs` or of `ClientOptions`. See [here](https://microsoft.github.io/PowerBI-JavaScript/interfaces/_node_modules__types_node_http_d_._http_.clientrequestargs.html) for `ClientRequestArgs` and [here](https://github.com/websockets/ws) for `ClientOptions`.

The interface:
In 4.x a second option parameter can be given regarding auto-reconnecting, delay and max tries attempts. And here is its type:

```ts
export type ReconnectOptions = {
autoReconnect: boolean;
delay: number;
maxAttempts: number;
type ReconnectOptions = {
autoReconnect: boolean; // default: `true`
delay: number; // default: `5000`
maxAttempts: number; // default: `5`
};
```

For example:
##### Options examples

Below is an example for the passed options for each version:

```ts
// in 1.x
Expand Down Expand Up @@ -232,3 +164,23 @@ const reconnectOptions: ReconnectOptions = {
maxAttempts: 5,
};
```

##### Error message for reconnect attempts

The error in, version 1.x, was an Error object that contains the message:
`'Maximum number of reconnect attempts reached!'`

However, the error, in version 4.x, is just an error message (not wrapped in an Error object). And the error message will contain the value of the variable `maxAttempts` as follows:

`` `Max connection attempts exceeded (${maxAttempts})` ``

And here is how to catch the error, in version 4.x, if max attempts reached when there is auto reconnecting:

```ts
provider.on('error', errorMessage => {
if (errorMessage.startsWith('Max connection attempts exceeded')) {
// the `errorMessage` will be `Max connection attempts exceeded (${maxAttempts})`
// the `maxAttempts` is equal to the provided value by the user, or the default value `5`.
}
});
```
2 changes: 1 addition & 1 deletion docs/docs/guides/web3_plugin_guide/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 1
sidebar_position: 2
sidebar_label: 'web3 Plugins'
---

Expand Down
68 changes: 68 additions & 0 deletions docs/docs/guides/web3_providers_guide/events_listening.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
sidebar_position: 0
sidebar_label: 'Providers Events Listening'
---

# Providers Events Listening

Some providers are, by design, always connected. Therefor, they can communicate changes with the user through events. Actually, among the 3 providers, `HttpProvider` is the only one that does not support event. And the other 2:
[WebSocketProvider](/api/web3-providers-ws/class/WebSocketProvider) and [IpcProvider](/api/web3-providers-ipc/class/IpcProvider) enable the user to listen to emitted events.

Actually, the events can be categorized as follows ([according to EIP 1193](https://eips.ethereum.org/EIPS/eip-1193#rationale)):

- Communicate arbitrary messages: `message`
- Changes to the Provider’s ability to make RPC requests;
- `connect`
- `disconnect`
- Common Client and/or Wallet state changes that any non-trivial application must handle:
- `chainChanged`
- `accountsChanged`

Below a sample code for listening and remove listening to EIP 1193 events:

```ts
import { Web3 } from `web3`

const web3 = new Web3(/* PROVIDER*/);

web3.provider.on('message',()=>{
// ...
})

web3.provider.on('connect',()=>{
// ...
})

web3.provider.on('disconnect',()=>{
// ...
})

web3.provider.on('accountsChanged',()=>{
// ...
})

web3.provider.on('chainChanged',()=>{
// ...
})

// it is possible to catch errors that could happen in the underlying connection Socket with the `error` event
// and it is also used to catch the error when max connection attempts exceeded
// as in section: /docs/guides/web3_providers_guide/#error-message
web3.provider.on('error',()=>{
// ...
}

// ...

// for every event above `once` could be used to register to the event only once
web3.provider.once('SUPPORTED_EVENT_NAME',()=>{
// ...
})

// And to unregister a listener `removeListener` could be called
web3.provider.removeListener('SUPPORTED_EVENT_NAME',()=>{
// ...
})
```
However, the underlying `SocketConnection` of both `WebSocketProvider` and `IpcProvider` could be accessed. This enables the user to access any special properties of the used Socket. As well as, registering to the custom server events directly. Actually the Socket used at `WebSocketProvider` is [isomorphic-ws](https://github.com/heineiuo/isomorphic-ws). And the Socket used at `IpcProvider` is [net.Server](https://nodejs.org/api/net.html#class-netserver)
Loading

0 comments on commit 2332c5f

Please sign in to comment.