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 .
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 !