@reach-sh/stdlib: Make it possible to reset the Algorand provider during the application lifecycle
flyingleafe opened this issue · 3 comments
We have two use cases which we would like to support in our Algorand application:
-
Allow the user to disconnect his current wallet and connect another one (e.g. if the user has both MyAlgo and Pera wallet)
1.1. This would also help with automatic reconnection of the previously connected wallet without blocking the user from changing the wallet at some point in the future. -
Fetch the contract's global views when the user has not yet connected the wallet (e.g., displaying some TVLs and other parameters of a contract for everybody on the front page).
Currently, both of those use cases are blocked by the behaviour of the Reach stdlib, specifically by the definition of getProvider
and setProvider
functions
export const [getProvider, setProvider] = replaceableThunk(async () => {
if ( window.algorand ) {
// @ts-ignore
return await makeProviderByWallet(window.algorand, process.env);
} else {
debug(`making default provider based on process.env`);
return await makeProviderByEnv(process.env);
}
});
Using the replaceableThunk
function here in its current implementation leads to the fact that the value of the first call to getProvider()
gets remembered forever, and there is no way to reset the memorized provider. In turn, this leads to:
reach.setWalletFallback()
andreach.getDefaultAccount()
do nothing if called in the second time of the application lifecycle, since the result ofgetDefaultAccount()
is derived fromgetProvider()
, and therefore it always stays the same no matter what- Using some default randomly generated account to create a contract handle (
ctc = account.contract(bin, id)
) and then doingctc.views.someGlobalView()
causesgetProvider()
function to get called internally, the wallet-less provider value gets memorized and afterwards it is impossible to change it to a wallet-based provider, so the user cannot connect the wallet usingsetWalletFallback
anymore.
Both of this issues could be mitigated easily if e.g. setProvider
function could be actually called more than once. Are there some fundamental concerns which dictate that it should not be possible? I understand that allowing this will open the door to many possibilities for a developer to do weird bugs when resetting the provider at the wrong time, but providing some function like unsafeSetProvider
which emits warnings rather than errors would be better than prohibiting the use cases I present altogether. I think that those are pretty common among all Web3 apps, not only our one.
NB: For the second use case (reading the global contract views without having an account connected), it would be nice to provide some function like reach.contractPublicView(bin, id)
, which does not require an account to be created, and which only contains views which do not touch the local state. I anticipate that it should not be very hard to do in principle (the current code already understands which views touch local state and which don't, otherwise it wouldn't work), but probably hard to do in practice (requires extensive refactoring or something). Anyway, just allowing the provider to be set allows the workaround with a default account and it seems to be easy to do.
We'll work on doing this fully. Before then, let me try to help with what we have today...
- You can make multiple instances of the standard library
- If you use
stdlib.createAccount
, you will by-pass the wallet'senableAccounts
call, so for wallets that don't provide node access, you'll just connect directly.
It is now possible to load independent instances of the standard library easily...
https://docs.reach.sh/frontend/#ref-frontends-js-loader
And we've added a discussion about how to use setWalletFallback
multiple times effectively....
When Jay says "it is now possible", he means, it will be possible starting with @reach-sh/stdlib@0.1.11-rc.6
, which will be released next week.