Skip to content

Commit

Permalink
Correct and enhance documentation for subscribing to events (#6129)
Browse files Browse the repository at this point in the history
* correction and elaboration on `clearSubscriptions` at migration guide

* corrections and elaboration on Web3Eth `subscribe` documentation

* replace “, ”, and " with ' and/or ` at some files

* add clarification and section for web3.eth.subscribe Migration Guide
  • Loading branch information
Muhammad-Altabba committed Jun 1, 2023
1 parent daaaff7 commit 88ac791
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 34 deletions.
4 changes: 4 additions & 0 deletions docs/docs/guides/web3_migration_guide/index.md
Expand Up @@ -32,6 +32,10 @@ const web3 = new Web3();

Passing callbacks to functions is no longer supported, except for event listeners.

For example, the approach to subscribing-to and listening-for blockchain events has changed in version 4.x. Detailed instructions can be found in the [**`web3.eth.subscribe` Migration Guide**](/docs/guides/web3_migration_guide/subscribe_migration_guide#subscribing-to-events).

However, the approach to subscribing to Provider events remains the same, utilizing callbacks as explained in the [Providers Events Listening guide](/docs/guides/web3_providers_guide/events_listening). It is important to note that Providers have undergone some breaking changes, including the renaming of the `on('close', ...)` to `on('disconnect', ...)`.

### Not Implemented or Exported

- [extend](https://web3js.readthedocs.io/en/v1.7.3/web3.html#extend) Extending web3 modules functionality is not implemented
Expand Down
54 changes: 52 additions & 2 deletions docs/docs/guides/web3_migration_guide/subscribe_migration_guide.md
Expand Up @@ -7,6 +7,45 @@ sidebar_label: web3.eth.subscribe

## Breaking Changes

### Subscribing to events

You subscribe to blockchain events using the `web3.eth.subscribe` API.

However, in web3.js version 1.x, for example, you could subscribe to the `newBlockHeaders` event, in one step, with the following code snippet:

```typescript
var subscription = web3.eth.subscribe('newBlockHeaders', function (error, result) {
if (!error) console.log(result);
});
```

But, in web3.js Version 4.x, the function signature has changed for `web3.eth.subscribe`. In addition, the way you get notified for `data` and `error` has also changed. It is now in 2 steps: First you subscribe and then you listen to events. Here's an example of how you would subscribe to the same `newBlockHeaders` event in web3.js version 4.x:

```typescript
// in 4.x
const subscription = await web3.eth.subscribe('newHeads');

// note that in version 4.x the way you get notified for `data` and `error` has changed
subscription.on('data', async blockhead => {
console.log('New block header: ', blockhead);
});
subscription.on('error', error =>
console.log('Error when subscribing to New block header: ', error),
);
```

#### Differences

In summary, the differences you need to be aware of when subscribing to blockchain events in web3.js version 4.x are:

- The `subscribe` function signature has changed:
- It does not accept a callback function.
- It returns a subscription object that you can use to listen to `data` and `error` events.
- You should now use the `on`, or `once`, method on the newly returned subscription object to listen to `data` and `error` events, instead of passing a callback function directly.
- You can have multiple event listeners, if you have, for example multiple `on` calls. And you can get the number of listeners in you code by calling `listenerCount(event_name)` or get the listeners with `listeners(event_name)`.

Keep in mind that these differences apply to all blockchain event subscriptions, not just to the `newBlockHeaders` event.

### New Block Headers event

In 1.x, `web3.eth.subscribe('newBlockHeaders')` was used to subscribe to new block headers.
Expand All @@ -30,7 +69,18 @@ web3.eth.clearSubscriptions(function (error, success) {

// in 4.x
const subscription = await web3.eth.subscribe('newHeads');
subscription.unsubscribe().then(
console.log(), // [...] Array of subsription ids

// note that in version 4.x the way you get notified for `data` and `error` has changed
newBlocksSubscription.on('data', async blockhead => {
console.log('New block header: ', blockhead);
});
newBlocksSubscription.on('error', error =>
console.log('Error when subscribing to New block header: ', error),
);

const ids = await web3.eth.clearSubscriptions();
console.log(ids); // [...] An array of subscription ids that were cleared

// note that you can unsubscribe from a specific subscription by calling unsubscribe()
// on that subscription object: `await subscription.unsubscribe();` and this would return void if succeeded.
```
2 changes: 1 addition & 1 deletion packages/web3-core/src/web3_config.ts
Expand Up @@ -282,7 +282,7 @@ export abstract class Web3Config
}

/**
* The blockHeaderTimeout is used over socket-based connections. This option defines the amount seconds it should wait for newBlockHeaders event before falling back to polling to fetch transaction receipt.
* The blockHeaderTimeout is used over socket-based connections. This option defines the amount seconds it should wait for `'newBlockHeaders'` event before falling back to polling to fetch transaction receipt.
* Default is `10` seconds.
*/
public get blockHeaderTimeout() {
Expand Down
2 changes: 1 addition & 1 deletion packages/web3-eth-contract/src/types.ts
Expand Up @@ -70,7 +70,7 @@ export interface ContractEventOptions {
*/
fromBlock?: BlockNumberOrTag;
/**
* This allows to manually set the topics for the event filter. If given the filter property and event signature, (topic[0]) will not be set automatically. Each topic can also be a nested array of topics that behaves as “or” operation between the given nested topics.
* This allows to manually set the topics for the event filter. If given the filter property and event signature, (topic[0]) will not be set automatically. Each topic can also be a nested array of topics that behaves as `or` operation between the given nested topics.
*/
topics?: string[];
}
Expand Down
43 changes: 27 additions & 16 deletions packages/web3-eth/src/web3_eth.ts
Expand Up @@ -1244,13 +1244,13 @@ export class Web3Eth extends Web3Context<Web3EthExecutionAPI, RegisteredSubscrip
}

/**
* Gets work for miners to mine on. Returns the hash of the current block, the seedHash, and the boundary condition to be met (target).
* Gets work for miners to mine on. Returns the hash of the current block, the seedHash, and the boundary condition to be met ('target').
*
* @returns The mining work as an array of strings with the following structure:
*
* String 32 Bytes - at index 0: current block header pow-hash
* String 32 Bytes - at index 1: the seed hash used for the DAG.
* String 32 Bytes - at index 2: the boundary condition (target), 2^256 / difficulty.
* String 32 Bytes - at index 2: the boundary condition ('target'), 2^256 / difficulty.
*
* ```ts
* web3.eth.getWork().then(console.log);
Expand Down Expand Up @@ -1424,7 +1424,7 @@ export class Web3Eth extends Web3Context<Web3EthExecutionAPI, RegisteredSubscrip
/**
* @param blockCount Number of blocks in the requested range. Between `1` and `1024` blocks can be requested in a single query. Less than requested may be returned if not all blocks are available.
* @param newestBlock Highest number block of the requested range.
* @param rewardPercentiles A monotonically increasing list of percentile values to sample from each block’s effective priority fees per gas in ascending order, weighted by gas used. Example: `[“0”, “25”, “50”, “75”, “100]` or `[“0”, “0.5”, “1”, “1.5”, “3”, “80”]`
* @param rewardPercentiles A monotonically increasing list of percentile values to sample from each block’s effective priority fees per gas in ascending order, weighted by gas used. Example: `['0', '25', '50', '75', '100']` or `['0', '0.5', '1', '1.5', '3', '80']`
* @param returnFormat ({@link DataFormat} defaults to {@link DEFAULT_RETURN_FORMAT}) - Specifies how the return data from the call should be formatted.
* @returns `baseFeePerGas` and transaction effective `priorityFeePerGas` history for the requested block range if available.
* The range between `headBlock - 4` and `headBlock` is guaranteed to be available while retrieving data from the `pending` block and older history are optional to support.
Expand Down Expand Up @@ -1553,22 +1553,33 @@ export class Web3Eth extends Web3Context<Web3EthExecutionAPI, RegisteredSubscrip
* - on("error") - Fires when an error in the subscription occurs.
* - on("connected") - Fires once after the subscription successfully connected. Returns the subscription id.
*
* @example
* @example **Subscribe to Smart Contract events**
* ```ts
* const subscription = web3.eth.subscribe('logs', {
* // Subscribe to `logs`
* const logSubscription = web3.eth.subscribe('logs', {
* address: '0x1234567890123456789012345678901234567890',
* topics: ['0x033456732123ffff2342342dd12342434324234234fd234fd23fd4f23d4234']
* }, function(error, result){
* if (!error)
* console.log(result);
* });
* logSubscription.on('data', (data: any) => console.log(data));
* logSubscription.on('error', (error: any) => console.log(error));
*
* const subscription = web3.eth.subscribe('logs', {
* address: '0x1234567890123456789012345678901234567890',
* topics: ['0x033456732123ffff2342342dd12342434324234234fd234fd23fd4f23d4234']
* })
* .then(logs => console.log(logs))
* .catch(error => console.log(error));
* ```
*
* @example **Subscribe to new block headers**
* ```ts
* // Subscribe to `newBlockHeaders`
* const newBlocksSubscription = await web3.eth.subscribe('newBlockHeaders');
*
* newBlocksSubscription.on('data', async blockhead => {
* console.log('New block header: ', blockhead);
*
* // You do not need the next line, if you like to keep notified for every new block
* await newBlocksSubscription.unsubscribe();
* console.log('Unsubscribed from new block headers.');
* });
* newBlocksSubscription.on('error', error =>
* console.log('Error when subscribing to New block header: ', error),
* );
* ```
*/
public async subscribe<
Expand Down Expand Up @@ -1614,11 +1625,11 @@ export class Web3Eth extends Web3Context<Web3EthExecutionAPI, RegisteredSubscrip
* Resets subscriptions.
*
* @param notClearSyncing If `true` it keeps the `syncing` subscription.
* @returns `true` if successful, otherwise `false`.
* @returns A promise to an array of subscription ids that were cleared.
*
* ```ts
* web3.eth.clearSubscriptions().then(console.log);
* > true
* > [...] An array of subscription ids that were cleared
* ```
*/
public clearSubscriptions(notClearSyncing = false): Promise<string[]> | undefined {
Expand Down
24 changes: 12 additions & 12 deletions packages/web3-eth/src/web3_subscriptions.ts
Expand Up @@ -34,13 +34,13 @@ type CommonSubscriptionEvents = {
connected: number;
};
/**
* ## subscribe(logs)
* ## subscribe('logs')
* Subscribes to incoming logs, filtered by the given options. If a valid numerical fromBlock options property is set, web3.js will retrieve logs beginning from this point, backfilling the response as necessary.
*
* You can subscribe to logs matching a given filter object, which can take the following parameters:
* - `fromBlock`: (optional, default: latest) Integer block number, or latest for the last mined block or pending”, “earliest for not yet mined transactions.
* - `fromBlock`: (optional, default: 'latest') Integer block number, or `'latest'` for the last mined block or `'pending'`, `'earliest'` for not yet mined transactions.
* - `address`: (optional) Contract address or a list of addresses from which logs should originate.
* - `topics`: (optional) Array of 32 Bytes DATA topics. Topics are order-dependent. Each topic can also be an array of DATA with “or” options.
* - `topics`: (optional) Array of 32 Bytes DATA topics. Topics are order-dependent. Each topic can also be an array of DATA with `or` options.
*
*/
export class LogsSubscription extends Web3Subscription<
Expand Down Expand Up @@ -68,13 +68,13 @@ export class LogsSubscription extends Web3Subscription<
}

/**
* ## subscribe(pendingTransactions)
* ## subscribe('pendingTransactions')
* Subscribes to incoming pending transactions.
*
* You can subscribe to pending transactions by calling web3.eth.subscribe(pendingTransactions).
* You can subscribe to pending transactions by calling web3.eth.subscribe('pendingTransactions').
* @example
* ```ts
* web3.eth.subscribe('pendingTransactions').on("data", console.log(transaction);
* (await web3.eth.subscribe('pendingTransactions')).on('data', console.log);
* ```
*/
export class NewPendingTransactionsSubscription extends Web3Subscription<
Expand All @@ -97,15 +97,15 @@ export class NewPendingTransactionsSubscription extends Web3Subscription<
}

/**
* ## subscribe(newHeads) ( same as subscribe("newBlockHeaders"))
* ## subscribe('newHeads') ( same as subscribe('newBlockHeaders'))
*
* Subscribes to incoming block headers. This can be used as timer to check for changes on the blockchain.
*
* The structure of a returned block header is {@link BlockHeaderOutput}:
* @example
* ```ts
* (await web3.eth.subscribe("newHeads")).on( // "newBlockHeaders" would work as well
* "data",
* (await web3.eth.subscribe('newHeads')).on( // 'newBlockHeaders' would work as well
* 'data',
* console.log
* );
* >{
Expand Down Expand Up @@ -145,15 +145,15 @@ export class NewHeadsSubscription extends Web3Subscription<
}

/**
* ## subscribe(syncing)
* ## subscribe('syncing')
*
* Subscribe to syncing events. This will return `true` when the node is syncing and when it’s finished syncing will return `false`, for the `changed` event.
* @example
* ```ts
* (await web3.eth.subscribe("syncing")).on("changed", console.log);
* (await web3.eth.subscribe('syncing')).on('changed', console.log);
* > `true` // when syncing
*
* (await web3.eth.subscribe("syncing")).on("data", console.log);
* (await web3.eth.subscribe('syncing')).on('data', console.log);
* > {
* startingBlock: 0,
* currentBlock: 0,
Expand Down
4 changes: 2 additions & 2 deletions packages/web3-types/src/eth_contract_types.ts
Expand Up @@ -50,12 +50,12 @@ export interface ContractInitOptions {
export interface NonPayableCallOptions {
nonce?: HexString;
/**
* The address the call `transaction` should be made from. For calls the `from` property is optional however it is
* The address which is the call (the transaction) should be made from. For calls the `from` property is optional however it is
* highly recommended to explicitly set it or it may default to address(0) depending on your node or provider.
*/
from?: Address;
/**
* The maximum gas provided for this call “transaction” (gas limit)
* The maximum gas (gas limit) provided for this call (this transaction)
*/
gas?: string;
maxPriorityFeePerGas?: HexString;
Expand Down

0 comments on commit 88ac791

Please sign in to comment.