Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Web Dapps Using Auto Sign Not Working with MWA #490

Open
Funkatronics opened this issue Jun 26, 2023 · 5 comments
Open

Web Dapps Using Auto Sign Not Working with MWA #490

Funkatronics opened this issue Jun 26, 2023 · 5 comments

Comments

@Funkatronics
Copy link
Contributor

Funkatronics commented Jun 26, 2023

Describe the bug
Some dapps attempt to do a sign in flow by automatically triggering a message sign as soon as a wallet is connected. On Chrome for Android (and most if not all other mobile browsers), both app links (eg solana-wallet://) and universal links (eg https://my.app/...) are blocked if they do not come from a direct user action. This causes these sites to not funciton with Mobile Wallet Adapter. The sign message attempt is blocked, and in most cases this causes the site to get stuck in a sort of infinite loop because a cookie is stored for the connected wallet (reload>connected wallet is saved and reconnects>triggers auto sign message again>blocked>reload>repeat).

To Reproduce
Steps to reproduce the behavior:

  1. Install Ultimate or Solflare Wallet on Android device
  2. Open mobile browser (issue confirmed on latest Play Store versions for Chrome, Edge, Firefox, Opera)
  3. Navigate to drip.haus
  4. tap on "Connect Wallet" button
  5. if a wallet disambiguation dialog is shown, select the wallet installed in step 1
  6. approve the connection in the wallet, should be returned to the web page
  7. See that the page has auto navigated to {walletUriBase}/v1/associate/...
  8. preloading the page or navigating back to drip.haus will continue to auto navigate to {walletUriBase}/v1/associate/...

Note:

  • the webpage will get stuck in this state because a cookie is stored with the connection url. clear the cookies/cached data for the site to fix/reset it.
  • this issue can be reproduced on the following websites: tensor.trade, rave3.io
  • can also be reproduced using our example web app
  • Can also be reproduced using fakewallet, and modifying this line to pass back an https url ("https:/fakewallet.com" for example)

Expected behavior
Upon returning to the webpage after approving the connection in the wallet app, subsequent requests sent to the wallet should function as expected (launch the wallet app and continue with MWA request as usual)

Screenshots
Using drip.haus and Ultimate:

Using drip.haus and Fakewallet:

Using example web app and Fakewallet:

Smartphone (please complete the following information):

  • Device: All (tested on Saga and Pixel 3, but issue is not related to the device)
  • Browser: All chrome based browsers on Android, confirmed issue on Chrome, Edge, Firefox and Opera

Additional context

I believe this issue is caused by Chrome not being able to verify wallet links that use a https scheme. Per the MWA 1.0 spec, a wallet can supply a walletUriBase field during authorization that the dapp should use to connect to for subsequent requests. Chrome is refusing to open these links as app links, and instead navigates the page to the url. I believe chrome will only open these https links in the wallet app if it can verify the app link

This was confirmed to be false. The issue is almost certainly due to mobile browsers blocking navigation (app links, universal links) that do not originate from a user action (popup blocking).

@Funkatronics
Copy link
Contributor Author

Funkatronics commented Jun 26, 2023

I think the proper fix here is for the wallets to add the app link verification stuff as described here. I have not yet confirmed this myself, but I believe this will allow chrome to open the wallet uris in the native app instead of navigating the page to that url.

Another workaround might be to modify mobile-wallet-adapter-protocol to use the custom intent: scheme IFF a valid walletUriBase is provided AND the domain cannot be verified. This will require us to implement manual verification, like we do in our digital asset links library. More info here.

Update: further investigation has revealed that even properly verified links still exhibit this behavior so its not related to app link verification.

@Funkatronics
Copy link
Contributor Author

Question: If my above theories are correct, why do some sites work but others dont? For example, Ultimate wallet does not work with drip.haus (see gif above), but it does work as expected with jup.ag. Is Jupiter using a custom implementation of mobile wallet adapter that works around this issue? Or am I incorrect in my assumptions and something else is causing some apps to navigate to the wallet url instead of launching it as an app link/android intent?

@Funkatronics Funkatronics changed the title Mobile Browsers blocking app links constructed using 'walletUriBase' field provided by wallets Mobile Browsers not properly handling app links constructed using 'walletUriBase' field provided by wallets Jun 26, 2023
@Funkatronics
Copy link
Contributor Author

Funkatronics commented Jun 26, 2023

Workaround
At this moment, wallets can work around this issue by removing the walletUriBase field that is returned during authorization. This will force wallet adapter on the website to use the solana-wallet:// uri scheme that works generically with all wallets thus circumventing the problem. The wallet could add a check to only remove this field when connecting to a web based dapp, and could continue to use the walletUriBase field for connections with natives apps. Note that this workaround has other negative impacts (wallet disambiguation dialog might be used, webpage will not have a fallback url to take the users to) so should only be used as a temporary solution.

This workaround was found to only work with some sites. Its not a reliable solution, and the solana-wallet:// uri can still be blocked by chromes popup blocker so the above info is not actually correct. Further investigation is needed to understand why some sites (like drip.haus) seem to work with this workaround. Their error logic might give us a clue on how to handle this case.

@Funkatronics Funkatronics changed the title Mobile Browsers not properly handling app links constructed using 'walletUriBase' field provided by wallets Web Dapps Using Auto Sign Not Working with MWA Jun 27, 2023
@Funkatronics
Copy link
Contributor Author

Proposed Solution:

  1. Add a sign in API to the SolanaMobileWalletAdapter plugin that combines authorize and sign message into a single transact block so that web dapps can perform this "auto" sign in flow without needing to switch back to the web between connecting the wallet and requesting a signature
  2. Add a check inside of the transact method that returns an error if transact was not initiated from a user action. This can be accomplished by adding a new event parameter to the transact method that should represent the user event that initiated the action. The transact method will check this event and verify that this event was user initiated (event.isTrusted). This would be a breaking change so if there is another way to verify that the action originated from a user event I am all ears!

CC @Michaelsulistio @sdlaver @steveluscher

@d-reader-josip
Copy link

d-reader-josip commented Jul 6, 2023

I would say that there are 2 things to implement here:

  1. from MWA side detect if the event is trusted and if not, throw a proper error so the developer understands that they need to refactor they logic
  2. from WA side we should enrich the WalletButton components to accept callbacks before and after their onClick events like so beforeConnect, afterConnect, beforeDisconnect, afterDisconnect otherwise all the developers looking to support MWA on their web apps will have to implement it on their own if they're ever looking to have support for a single button which both authorizes the app and does any other action like signing a message.

This is the naive approach, there is more to the solution proposed under the point 2. and it's implementation will probably take a lot of thought and time. The biggest issue would be the connect function from the wallet-adapter library which is not friendly enough towards the mobile-wallet-adapter library.

For example, if we want authorize a dApp and sign a message in a single wallet session on mobile web apps, our afterConnect would need to pass in the authorized account and the mobile wallet object from the transacts callback.

Roughly something like this:

await transact(async (mobileWallet) => {
  const freshAccount = await authorizeSession(mobileWallet)
  const account = selectedAccount ?? freshAccount

  if (typeof afterConnect === 'function') {
    await afterConnect(mobileWallet, account)
  }
}

can also be reproduced using our example web app

On a side note, I don't think this issue has anything to do with the example app? That could be an issue of it's own, but shouldn't be this one since the example app does not use useEffect which makes the event not trusted. Right?

cc: @Funkatronics

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants