Dynamic subscription to events in the background script

In this post I’d like to share a pattern that have been proved useful in regards to subscribing to external smart contract events when their addresses are not available when the background script is initialized.

You can also see it as a guide on how to learn aragonAPI in the hard way :stuck_out_tongue_winking_eye:.

External event subscription

Many Aragon apps (Token Manager, Voting, and Finance for example) need to know what has happened in other (external) contracts and update their state in accordance to it. To do so, they usually follow the same steps:

1. Obtain the contract address with api.call

We ask to our app’s contract the address of the contract we want to follow. In this case, the TokenManager contract has a public variable called token that contains the address of the MiniMe token we want to obtain the past and future events.

2. Obtain the contract handler using api.external

When we know the address and the ABI of a contract we can obtain it’s handler.

3. Initialize api.store with options

The second parameter in the app.store function is an object with options. We can pass an external contract to it, and the reducer will receive the events of that contract as well.

An app with “special” needs

The Committees app installs new applications in order to create Committees (usually a Token Manager and a Voting app with specific permissions).

The members of a committee are the holders of the token associated to a committee. We need to listen to a specific token contract events in order to update the list of committee members.

The problem comes when a user creates new committee when the background script has already been initialized. The new token address is not available in the moment of the store initialization, so we can’t treat those events in the store reducer, can we?

Dynamically subscribing to events

We can use api.external pastEvents and events to obtain the past and future events as RxJS observables.

We denominate pastEvents$ the events occurred before than the current block number minus 100 (a constant to prevent chain reorganization errors), lastEvents$ the ones occurred between current block number minus 100 and current block number, and futureEvents$ the ones that we are receiving from now on.

We pipe them together, and use RxJS to subscribe and api.emitTrigger to send them back to the reducer, so we can treat them in a similar way to any other event received from the app’s contract or defined in the externals store options.

And thanks to getting some inspiration from the code initially contributed by 2color to the Aragon Wrapper, we can also cache events from those dynamic subscriptions.

You can see an example of this code working on the Committees app background script where we use it to cache token holders listening to the Transfer events from committees’ token contracts.

@pjcolombo and me are glad to hear about your feedback. The code has not been properly tested yet, so maybe you find some :bug:!

2 Likes