Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add documentation for catching provider events #5886

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
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.
Muhammad-Altabba marked this conversation as resolved.
Show resolved Hide resolved
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',()=>{
// ...
})

avkos marked this conversation as resolved.
Show resolved Hide resolved
// 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