polkadot-js / extension

Simple browser extension for managing Polkadot and Substrate network accounts in a browser. Allows the signing of extrinsics using these accounts. Also provides a simple interface for compliant extensions for dapps.
Apache License 2.0
977 stars 414 forks source link

No way to determine whether `web3Enable` was fired or not in case of rejected authorization #1431

Closed nikitayutanov closed 2 months ago

nikitayutanov commented 3 months ago

It seems there was a significant gap in Chrome/Firefox store releases, and recent updates have negatively impacted our application's UX.

1068 introduced a new approach to handling authorization requests, which I certainly appreciate as an improvement. However, our team has encountered a drawback.

Before the 0.44.2 release, if an authorization request was rejected or skipped, web3Enable would return an empty array, signaling to developers that a request for extensions was made but no working extensions were found. As a result, the entire subsequent UI logic (for example, determining if there is any wallet present or not) should not be executed.

Currently, if a user skips the authorization request, web3Enable neither resolves nor rejects, leaving no way to determine the outcome of the authorization attempt. window.injectedWeb3['polkadot-js'].enable call behaves the same way.

Simplified code snippet to elaborate on the above:

  const [extensions, setExtensions] = useState<InjectedExtension[]>();
  const [accounts, setAccounts] = useState<InjectedAccountWithMeta[]>();
  const [account, setAccount] = useState<InjectedAccountWithMeta>();

  const isAuthReady = ![extensions, accounts].includes(undefined); // responsible for a loading UI state, for example

  useEffect(() => {
    const init = async () => {
      const _extensions = await web3Enable('dApp'); // right now is stale if user skipped auth request, but before was resolved with an empty array
      const _accounts = await web3Accounts();

      const loggedInAccount = _accounts.find(({ address }) => localStorage[LOCAL_STORAGE.ACCOUNT] === address);

      setExtensions(_extensions);
      setAccounts(_accounts);
      setAccount(loggedInAccount);
    };

    init();
  }, []);

I would be thankful if there's a way to come up with a straightforward fix for this kind of behaviour, as I believe it really affects both developers' and users' experiences.

nikitayutanov commented 3 months ago

@TarikGul are you able to provide any insight on this, please? Seems like PR linked above is not related to described issue.

Tbaut commented 3 months ago

Hello,

(for example, determining if there is any wallet present or not) should not be executed.

You probably found out as I see you know about the window object. You can determine simply if there's any wallet or not by inspecting the window.injectedWeb3 object. It contains the entries of the injected extensions.

All in all, I would advise to migrate to a lib or a logic with a wallet selection mechanism since web3Enable fires all installed extensions, and users with several of them have a bad experience. This is the case for https://github.com/tien/dot-connect for instance. Or to see how a manual account selection is performed you can inspect the code of the https://github.com/GMorDIE/gmordie repo.

nikitayutanov commented 3 months ago

Thanks for your reply, @Tbaut! There are no issues with the tasks you described.

The main problem I'm experiencing is that the window.injectedWeb3['polkadot-js'].enable promise remains stale if the authorization popup is closed, which prevents me from determining the result of the requested authentication.

This problem only exists with the Polkadot-js extension. Subwallet and others don't have this issue because they simply throw an error if the authorization popup is rejected or closed.

I believe this is currently a code oversight and an inconvenience. window.injectedWeb3['polkadot-js'] should be settled (either resolved or rejected), as the stale promise can block the execution of the subsequent code that depends on it.

Tbaut commented 2 months ago

Sorry for the delay. Just like with transaction signing, if the user closes the popup (and doesn't click on "reject"), then the signing remains stale, and users can always go back to the popup, by clicking on the extension's icon, and see the request there. I understand it's an issue though, let me see if we can fix this.

Tbaut commented 2 months ago

BTW, the reason I talked about using a proper extension selection mechanism is because:

Hence, my PR above should help, also an extension selector should be the way to do.

polkadot-js-bot commented 2 months ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue if you think you have a related problem or query.