Subscribing
In the TVM-compatible blockchains, subscribing to events and messages is a crucial aspect because of the nature of how messages are handled and delivered. In particular, the delivery of deferred messages (messages that are not processed immediately) can be delayed, especially when they are sent to accounts in different shards. To handle these cases effectively and to ensure that your application receives updates in real-time, it is necessary to subscribe to the relevant events and messages.
Subscribing enables your application to receive updates whenever a particular event occurs, such as a contract state change, new transactions, network changes, or even when a delayed message is delivered or expired. This feature allows you to implement off-chain logic and stay up-to-date with the on-chain events.
There are two primary ways to subscribe to events: using the ProviderRpcClient
and through a Contract
instance. The key differences between these two approaches are as follows:
- Listener Level:
ProviderRpcClient
listens to events at the provider and blockchain level, whereas aContract
instance listens to events at the specific contract level. - Filtering: Subscribing to events through a
Contract
instance provides a narrower event filtering since it is focused on events from a specific contract. When usingProviderRpcClient
, your application might need to handle more events to track only those related to the desired contracts. - Scope: Using
ProviderRpcClient
can be helpful for monitoring network state and interaction with the extension, while aContract
instance provides deeper control over a specific contract's events.
Depending on your needs, you can use one of these approaches or combine them for optimal control over events in your application.
Overview and Significance of Events
The ProviderRpcClient
class allows you to subscribe to various events in the blockchain. This section will provide an overview of the different events and their significance, along with examples of subscribing to each event.
There are two categories of events: Provider events and Blockchain events. Provider events are related to the interaction between your application and the extension, while Blockchain events are the result of actions occurring within the network, particularly involving contracts.
Provider events
- NetworkChanged: Triggered each time the user changes the network.
- PermissionsChanged: Triggered when permissions are changed, such as when an account has been removed from the current accountInteraction permission or disconnect method was called.
- LoggedOut: Triggered when the user logs out of the extension.
- Connected: Triggered when the in-page provider connects to the extension.
- Disconnected: Triggered when the in-page provider disconnects from the extension.
Blockchain events
- TransactionsFound: Triggered on each new transactions batch, received on subscription.
- ContractStateChanged: Triggered every time a contract state changes.
- MessageStatusUpdated: Triggered every time a delayed message is delivered or expired. disconnect method is called.
Using the ProviderRpcClient
class, you can subscribe to these events to receive real-time updates and respond accordingly in your application. For example, you can listen for the 'connected' event to enable your application's features once connected to the network or handle the 'disconnected' event to prompt the user to reconnect.
With provider.Contract
methods such as transactions
, events
, waitForEvent
, and getPastEvents
, you can process Blockchain events related to contracts, like handling transaction events, decoding contract events, and waiting for events that match specific criteria.
Subscribing to Provider Events
To subscribe to events, you need to use the ProviderRpcClient.subscribe
method. This method takes the event name as an argument and returns an instance of a subscription. You can then listen to the event using the on
method and pass in a callback function to handle the event.
Using the ProviderRpcClient
class, you can subscribe to these events to receive real-time updates and respond accordingly in your application. For example, you can listen for the 'PermissionsChanged'
event to enable your application's features once connected to the network or handle the 'LoggedOut'
event to prompt the user to reconnect.
// Subscribe to provider events
const permissionsSub = await provider.subscribe('permissionsChanged');
const networkChangeSub = await provider.subscribe('networkChanged');
const loggedOutSub = await provider.subscribe('loggedOut');
// Listen to provider events
permissionsSub.on('data', data => {
console.log('permissionsChanged', data);
});
networkChangeSub.on('data', data => {
console.log('networkChanged', data);
});
loggedOutSub.on('data', data => {
console.log('loggedOut', data);
});
// Unsubscribe from provider events
permissionsSub.unsubscribe();
networkChangeSub.unsubscribe();
loggedOutSub.unsubscribe();
// Alternatively, you can unsubscribe from all events,
// but this will also remove permissions and disconnect provider.
await provider.disconnect();
Blockchain Events
Blockchain events are generated as a result of actions occurring within the network, particularly involving contracts. Events are emitted by smart contracts to provide additional information during transaction execution. They serve as a way for smart contracts to communicate with the outside world, allowing applications to monitor and react to changes within the network, such as new transactions, contract state changes, or message status updates.
Events can only exist as external outgoing messages and contain arguments to convey the necessary information. They don't have any functionality other than serving as a means to transmit data. Events are essential for implementing off-chain logic that relies on on-chain data, such as tracking the progress of a transaction or monitoring changes in contract states.
To subscribe and listen to Blockchain events, you will need to use the ProviderRpcClient
and provider.Contract
.
// Subscribe to blockchain events
const transactionsSub = await provider.subscribe('transactionsFound', { address: new Address(exampleContractAddress) });
const contractStateSub = await provider.subscribe('contractStateChanged', {
address: new Address(exampleContractAddress),
});
const msgStatusSub = await provider.subscribe('messageStatusUpdated');
// Listen to blockchain events
transactionsSub.on('data', data => {
console.log('transactionsFound', data);
// Unsubscribe
transactionsSub.unsubscribe();
});
contractStateSub.on('data', data => {
console.log('contractStateChanged', data);
});
msgStatusSub.on('data', data => {
console.log('messageStatusUpdated', data);
});
Subscribing to Contract Instance Events
Subscribing to events through a Contract
instance allows your application to listen and handle events specifically related to that contract. This can include events related to transactions, contract state changes, and other custom events defined within the contract.
const ABI = {
...,
events: [
{
name: 'StateChanged',
inputs: [
{
components: [
{ name: 'first', type: 'uint32' },
{ name: 'second', type: 'string' },
],
name: 'complexState',
type: 'tuple',
},
],
outputs: [],
},
],
};
To subscribe and listen to contract-specific events, you will need to use the provider.Contract
instance together with the provider.Subscriber
class.
// Create a contract instance
const exampleContract = new provider.Contract(exampleAddress, exampleAbi);
// Create a subscriber
const subscriber = new provider.Subscriber();
// Subscribe to contract events
const contractEvents = exampleContract.events(subscriber);
// Listen to contract events
contractEvents.on(event => {
console.log('contractEvent', event);
});
// Unsubscribe from contract events
contractEvents.unsubscribe();
Get Past Events
// Get past events
const pastEvents = await exampleContract.getPastEvents({
filter: 'StateChanged',
range: {
fromUtime: 1682651393814,
},
});
console.log('pastEvents', pastEvents);